This commit was generated by cvs2svn to compensate for changes in r4,
[kai/samba.git] / source3 / client / client.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-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 BOOL got_pass = False;
42 BOOL connect_as_printer = False;
43 BOOL connect_as_ipc = False;
44 extern struct in_addr bcast_ip;
45 static BOOL got_bcast=False;
46
47 char cryptkey[8];
48 BOOL doencrypt=False;
49
50 extern pstring user_socket_options;
51
52 /* 30 second timeout on most commands */
53 #define CLIENT_TIMEOUT (30*1000)
54 #define SHORT_TIMEOUT (5*1000)
55
56 /* value for unused fid field in trans2 secondary request */
57 #define FID_UNUSED (0xFFFF)
58
59 int name_type = 0x20;
60
61 int max_protocol = PROTOCOL_NT1;
62
63
64 time_t newer_than = 0;
65 int archive_level = 0;
66
67 extern struct in_addr myip;
68
69 extern pstring debugf;
70 extern int DEBUGLEVEL;
71
72 BOOL translation = False;
73
74 /* clitar bits insert */
75 extern void cmd_tar();
76 extern void cmd_block();
77 extern void cmd_tarmode();
78 extern void cmd_setmode();
79 extern int blocksize;
80 extern BOOL tar_inc;
81 extern BOOL tar_reset;
82 extern int process_tar();
83 extern int tar_parseargs();
84 /* clitar bits end */
85  
86
87 int cnum = 0;
88 int pid = 0;
89 int gid = 0;
90 int uid = 0;
91 int mid = 0;
92 int myumask = 0755;
93
94 int max_xmit = BUFFER_SIZE;
95
96 extern pstring scope;
97
98 BOOL prompt = True;
99
100 int printmode = 1;
101
102 BOOL recurse = False;
103 BOOL lowercase = False;
104
105 BOOL have_ip = False;
106
107 struct in_addr dest_ip;
108
109 #define SEPARATORS " \t\n\r"
110
111 BOOL abort_mget = True;
112
113 extern int Protocol;
114
115 BOOL readbraw_supported = False;
116 BOOL writebraw_supported = False;
117
118 pstring fileselection = "";
119
120 extern file_info def_finfo;
121
122 /* timing globals */
123 int get_total_size = 0;
124 int get_total_time_ms = 0;
125 int put_total_size = 0;
126 int put_total_time_ms = 0;
127
128
129 extern int Client;
130
131 #define USENMB
132
133 #ifdef KANJI
134 extern int coding_system;
135 #define CNV_LANG(s) (coding_system == DOSV_CODE?s:dos_to_unix(s, False))
136 #define CNV_INPUT(s) (coding_system == DOSV_CODE?s:unix_to_dos(s, True))
137 static BOOL
138 setup_term_code (char *code)
139 {
140     int new;
141     new = interpret_coding_system (code, UNKNOWN_CODE);
142     if (new != UNKNOWN_CODE) {
143         coding_system = new;
144         return True;
145     }
146     return False;
147 }
148 #else
149 #define CNV_LANG(s) dos2unix_format(s,False)
150 #define CNV_INPUT(s) unix2dos_format(s,True)
151 #endif
152
153 static void send_logout(void );
154 BOOL reopen_connection(char *inbuf,char *outbuf);
155 static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
156 static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
157 static BOOL call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,
158                      int *rprcnt,int *rdrcnt,char *param,char *data,
159                      char **rparam,char **rdata);
160 static BOOL send_trans_request(char *outbuf,int trans,
161                                char *name,int fid,int flags,
162                                char *data,char *param,uint16 *setup,
163                                int ldata,int lparam,int lsetup,
164                                int mdata,int mparam,int msetup);
165
166
167 /****************************************************************************
168 setup basics in a outgoing packet
169 ****************************************************************************/
170 void setup_pkt(char *outbuf)
171 {
172   SSVAL(outbuf,smb_pid,pid);
173   SSVAL(outbuf,smb_uid,uid);
174   SSVAL(outbuf,smb_mid,mid);
175   if (Protocol > PROTOCOL_CORE)
176     {
177       SCVAL(outbuf,smb_flg,0x8);
178       SSVAL(outbuf,smb_flg2,0x1);
179     }
180 }
181
182 /****************************************************************************
183 write to a local file with CR/LF->LF translation if appropriate. return the 
184 number taken from the buffer. This may not equal the number written.
185 ****************************************************************************/
186 static int writefile(int f, char *b, int n)
187 {
188   int i;
189
190   if (!translation)
191     return(write(f,b,n));
192   
193   i = 0;
194   while (i < n)
195     {
196       if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n')
197         {
198           b++;i++;
199         }
200       if (write(f, b, 1) != 1)
201         {
202           break;
203         }
204       b++;
205       i++;
206     }
207   
208   return(i);
209 }
210
211 /****************************************************************************
212   read from a file with LF->CR/LF translation if appropriate. return the 
213   number read. read approx n bytes.
214 ****************************************************************************/
215 static int readfile(char *b, int size, int n, FILE *f)
216 {
217   int i;
218   int c;
219
220   if (!translation || (size != 1))
221     return(fread(b,size,n,f));
222   
223   i = 0;
224   while (i < n)
225     {
226       if ((c = getc(f)) == EOF)
227         {
228           break;
229         }
230       
231       if (c == '\n') /* change all LFs to CR/LF */
232         {
233           b[i++] = '\r';
234           n++;
235         }
236       
237       b[i++] = c;
238     }
239   
240   return(i);
241 }
242  
243
244 /****************************************************************************
245 read from a file with print translation. return the number read. read approx n
246 bytes.
247 ****************************************************************************/
248 static int printread(FILE *f,char *b,int n)
249 {
250   int i;
251
252   i = readfile(b,1, n-1,f);
253 #if FORMFEED
254   if (feof(f) && i>0)
255     b[i++] = '\014';
256 #endif
257
258   return(i);
259 }
260
261 /****************************************************************************
262 check for existance of a dir
263 ****************************************************************************/
264 static BOOL chkpath(char *path,BOOL report)
265 {
266   fstring path2;
267   pstring inbuf,outbuf;
268   char *p;
269
270   strcpy(path2,path);
271   trim_string(path2,NULL,"\\");
272   if (!*path2) *path2 = '\\';
273
274   bzero(outbuf,smb_size);
275   set_message(outbuf,0,4 + strlen(path2),True);
276   SCVAL(outbuf,smb_com,SMBchkpth);
277   SSVAL(outbuf,smb_tid,cnum);
278   setup_pkt(outbuf);
279
280   p = smb_buf(outbuf);
281   *p++ = 4;
282   strcpy(p,path2);
283
284   send_smb(Client,outbuf);
285   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
286
287   if (report && CVAL(inbuf,smb_rcls) != 0)
288     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
289
290   return(CVAL(inbuf,smb_rcls) == 0);
291 }
292
293
294 /****************************************************************************
295 send a message
296 ****************************************************************************/
297 static void send_message(char *inbuf,char *outbuf)
298 {
299   int total_len = 0;
300
301   char *p;
302   int grp_id;
303
304   /* send a SMBsendstrt command */
305   bzero(outbuf,smb_size);
306   set_message(outbuf,0,0,True);
307   CVAL(outbuf,smb_com) = SMBsendstrt;
308   SSVAL(outbuf,smb_tid,cnum);
309
310   p = smb_buf(outbuf);
311   *p++ = 4;
312   strcpy(p,username);
313   p = skip_string(p,1);
314   *p++ = 4;
315   strcpy(p,desthost);
316   p = skip_string(p,1);
317
318   set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
319
320   send_smb(Client,outbuf);
321   
322
323   if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
324     {
325       printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
326       return;
327     }
328
329   grp_id = SVAL(inbuf,smb_vwv0);
330
331   printf("Connected. Type your message, ending it with a Control-D\n");
332
333   while (!feof(stdin) && total_len < 1600)
334     {
335       int maxlen = MIN(1600 - total_len,127);
336       pstring msg;
337       int l=0;
338       int c;
339
340       bzero(msg,smb_size);
341
342       for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++)
343         {
344           if (c == '\n')
345             msg[l++] = '\r';
346           msg[l] = c;   
347         }
348
349       CVAL(outbuf,smb_com) = SMBsendtxt;
350
351       set_message(outbuf,1,l+3,True);
352
353       SSVAL(outbuf,smb_vwv0,grp_id);
354
355       p = smb_buf(outbuf);
356       *p = 1;
357       SSVAL(p,1,l);
358       memcpy(p+3,msg,l);
359
360       send_smb(Client,outbuf);
361       
362
363       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
364         {
365           printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
366           return;
367         }      
368
369       total_len += l;
370     }
371
372   if (total_len >= 1600)
373     printf("the message was truncated to 1600 bytes ");
374   else
375     printf("sent %d bytes ",total_len);
376
377   printf("(status was %d-%d)\n",CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err));
378
379   CVAL(outbuf,smb_com) = SMBsendend;
380   set_message(outbuf,1,0,False);
381   SSVAL(outbuf,smb_vwv0,grp_id);
382
383   send_smb(Client,outbuf);
384   
385
386   if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
387     {
388       printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
389       return;
390     }      
391 }
392
393
394
395 /****************************************************************************
396 check the space on a device
397 ****************************************************************************/
398 static void do_dskattr(void)
399 {
400   pstring inbuf,outbuf;
401
402   bzero(outbuf,smb_size);
403   set_message(outbuf,0,0,True);
404   CVAL(outbuf,smb_com) = SMBdskattr;
405   SSVAL(outbuf,smb_tid,cnum);
406   setup_pkt(outbuf);
407
408   send_smb(Client,outbuf);
409   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
410
411   if (CVAL(inbuf,smb_rcls) != 0) 
412     DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));      
413
414   DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n",
415         SVAL(inbuf,smb_vwv0),
416         SVAL(inbuf,smb_vwv1)*SVAL(inbuf,smb_vwv2),
417         SVAL(inbuf,smb_vwv3)));
418 }
419
420 /****************************************************************************
421 show cd/pwd
422 ****************************************************************************/
423 static void cmd_pwd(void)
424 {
425   DEBUG(0,("Current directory is %s",CNV_LANG(service)));
426   DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
427 }
428
429
430 /****************************************************************************
431 change directory - inner section
432 ****************************************************************************/
433 static void do_cd(char *newdir)
434 {
435   char *p = newdir;
436   pstring saved_dir;
437   pstring dname;
438       
439   /* Save the current directory in case the
440      new directory is invalid */
441   strcpy(saved_dir, cur_dir);
442   if (*p == '\\')
443     strcpy(cur_dir,p);
444   else
445     strcat(cur_dir,p);
446   if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
447     strcat(cur_dir, "\\");
448   }
449   dos_clean_name(cur_dir);
450   strcpy(dname,cur_dir);
451   strcat(cur_dir,"\\");
452   dos_clean_name(cur_dir);
453
454   if (!strequal(cur_dir,"\\"))
455     if (!chkpath(dname,True))
456       strcpy(cur_dir,saved_dir);
457
458   strcpy(cd_path,cur_dir);
459 }
460
461 /****************************************************************************
462 change directory
463 ****************************************************************************/
464 static void cmd_cd(char *inbuf,char *outbuf)
465 {
466   fstring buf;
467
468   if (next_token(NULL,buf,NULL))
469     do_cd(buf);
470   else
471     DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
472 }
473
474
475 /****************************************************************************
476   display info about a file
477   ****************************************************************************/
478 static void display_finfo(file_info *finfo)
479 {
480   time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
481   DEBUG(0,("  %-30s%7.7s%10d  %s",
482            CNV_LANG(finfo->name),
483            attrib_string(finfo->mode),
484            finfo->size,
485            asctime(LocalTime(&t,GMT_TO_LOCAL))));
486 }
487
488 /****************************************************************************
489   do a directory listing, calling fn on each file found
490   ****************************************************************************/
491 void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
492 {
493   DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
494   if (Protocol >= PROTOCOL_LANMAN2)
495     {
496       if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
497         return;
498     }
499
500   expand_mask(Mask,False);
501   do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
502   return;
503 }
504
505 /*******************************************************************
506   decide if a file should be operated on
507   ********************************************************************/
508 static BOOL do_this_one(file_info *finfo)
509 {
510   if (finfo->mode & aDIR) return(True);
511
512   if (newer_than && finfo->mtime < newer_than)
513     return(False);
514
515   if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
516     return(False);
517
518   return(True);
519 }
520
521 /****************************************************************************
522 interpret a short filename structure
523 The length of the structure is returned
524 ****************************************************************************/
525 static int interpret_short_filename(char *p,file_info *finfo)
526 {
527   finfo->mode = CVAL(p,21);
528
529   /* this date is converted to GMT by make_unix_date */
530   finfo->ctime = make_unix_date(p+22);
531   finfo->mtime = finfo->atime = finfo->ctime;
532   finfo->size = IVAL(p,26);
533   strcpy(finfo->name,p+30);
534   
535   return(DIR_STRUCT_SIZE);
536 }
537
538 /****************************************************************************
539 interpret a long filename structure - this is mostly guesses at the moment
540 The length of the structure is returned
541 The structure of a long filename depends on the info level. 260 is used
542 by NT and 2 is used by OS/2
543 ****************************************************************************/
544 static int interpret_long_filename(int level,char *p,file_info *finfo)
545 {
546   if (finfo)
547     memcpy(finfo,&def_finfo,sizeof(*finfo));
548
549   switch (level)
550     {
551     case 1: /* OS/2 understands this */
552       if (finfo)
553         {
554           /* these dates are converted to GMT by make_unix_date */
555           finfo->ctime = make_unix_date2(p+4);
556           finfo->atime = make_unix_date2(p+8);
557           finfo->mtime = make_unix_date2(p+12);
558           finfo->size = IVAL(p,16);
559           finfo->mode = CVAL(p,24);
560           strcpy(finfo->name,p+27);
561         }
562       return(28 + CVAL(p,26));
563
564     case 2: /* this is what OS/2 uses mostly */
565       if (finfo)
566         {
567           /* these dates are converted to GMT by make_unix_date */
568           finfo->ctime = make_unix_date2(p+4);
569           finfo->atime = make_unix_date2(p+8);
570           finfo->mtime = make_unix_date2(p+12);
571           finfo->size = IVAL(p,16);
572           finfo->mode = CVAL(p,24);
573           strcpy(finfo->name,p+31);
574         }
575       return(32 + CVAL(p,30));
576
577       /* levels 3 and 4 are untested */
578     case 3:
579       if (finfo)
580         {
581           /* these dates are probably like the other ones */
582           finfo->ctime = make_unix_date2(p+8);
583           finfo->atime = make_unix_date2(p+12);
584           finfo->mtime = make_unix_date2(p+16);
585           finfo->size = IVAL(p,20);
586           finfo->mode = CVAL(p,28);
587           strcpy(finfo->name,p+33);
588         }
589       return(SVAL(p,4)+4);
590
591     case 4:
592       if (finfo)
593         {
594           /* these dates are probably like the other ones */
595           finfo->ctime = make_unix_date2(p+8);
596           finfo->atime = make_unix_date2(p+12);
597           finfo->mtime = make_unix_date2(p+16);
598           finfo->size = IVAL(p,20);
599           finfo->mode = CVAL(p,28);
600           strcpy(finfo->name,p+37);
601         }
602       return(SVAL(p,4)+4);
603
604     case 260: /* NT uses this, but also accepts 2 */
605       if (finfo)
606         {
607           int ret = SVAL(p,0);
608           int namelen;
609           p += 4; /* next entry offset */
610           p += 4; /* fileindex */
611
612           /* these dates appear to arrive in a weird way. It seems to
613              be localtime plus the serverzone given in the initial
614              connect. This is GMT when DST is not in effect and one
615              hour from GMT otherwise. Can this really be right??
616
617              I suppose this could be called kludge-GMT. Is is the GMT
618              you get by using the current DST setting on a different
619              localtime. It will be cheap to calculate, I suppose, as
620              no DST tables will be needed */
621
622           finfo->ctime = interpret_long_date(p); p += 8;
623           finfo->atime = interpret_long_date(p); p += 8;
624           finfo->mtime = interpret_long_date(p); p += 8; p += 8;
625           finfo->size = IVAL(p,0); p += 8;
626           p += 8; /* alloc size */
627           finfo->mode = CVAL(p,0); p += 4;
628           namelen = IVAL(p,0); p += 4;
629           p += 4; /* EA size */
630           p += 2; /* short name len? */
631           p += 24; /* short name? */      
632           StrnCpy(finfo->name,p,namelen);
633           return(ret);
634         }
635       return(SVAL(p,0));
636     }
637
638   DEBUG(1,("Unknown long filename format %d\n",level));
639   return(SVAL(p,0));
640 }
641
642
643
644
645 /****************************************************************************
646   act on the files in a dir listing
647   ****************************************************************************/
648 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
649 {
650
651   if (!((finfo->mode & aDIR) == 0 && *fileselection && 
652         !mask_match(finfo->name,fileselection,False,False)) &&
653       !(recurse_dir && (strequal(finfo->name,".") || 
654                         strequal(finfo->name,".."))))
655     {
656       if (recurse_dir && (finfo->mode & aDIR))
657         {
658           pstring mask2;
659           pstring sav_dir;
660           strcpy(sav_dir,cur_dir);
661           strcat(cur_dir,finfo->name);
662           strcat(cur_dir,"\\");
663           strcpy(mask2,cur_dir);
664
665           if (!fn)
666             DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
667
668           strcat(mask2,"*");
669
670           if (longdir)
671             do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);      
672           else
673             do_dir(inbuf,outbuf,mask2,attribute,fn,True);
674
675           strcpy(cur_dir,sav_dir);
676         }
677       else
678         {
679           if (fn && do_this_one(finfo))
680             fn(finfo);
681         }
682     }
683 }
684
685
686 /****************************************************************************
687   do a directory listing, calling fn on each file found
688   ****************************************************************************/
689 static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
690 {
691   char *p;
692   int received = 0;
693   BOOL first = True;
694   char status[21];
695   int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
696   int num_received = 0;
697   int i;
698   char *dirlist = NULL;
699   pstring mask;
700   file_info finfo;
701
702   finfo = def_finfo;
703
704   bzero(status,21);
705
706   strcpy(mask,Mask);
707   
708   while (1)
709     {
710       bzero(outbuf,smb_size);
711       if (first)        
712         set_message(outbuf,2,5 + strlen(mask),True);
713       else
714         set_message(outbuf,2,5 + 21,True);
715
716 #if FFIRST
717       if (Protocol >= PROTOCOL_LANMAN1)
718         CVAL(outbuf,smb_com) = SMBffirst;
719       else
720 #endif
721         CVAL(outbuf,smb_com) = SMBsearch;
722
723       SSVAL(outbuf,smb_tid,cnum);
724       setup_pkt(outbuf);
725
726       SSVAL(outbuf,smb_vwv0,num_asked);
727       SSVAL(outbuf,smb_vwv1,attribute);
728   
729       p = smb_buf(outbuf);
730       *p++ = 4;
731       
732       if (first)
733         strcpy(p,mask);
734       else
735         strcpy(p,"");
736       p += strlen(p) + 1;
737       
738       *p++ = 5;
739       if (first)
740         SSVAL(p,0,0);
741       else
742         {
743           SSVAL(p,0,21);
744           p += 2;
745           memcpy(p,status,21);
746         }
747
748       send_smb(Client,outbuf);
749       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
750
751       received = SVAL(inbuf,smb_vwv0);
752
753       DEBUG(5,("dir received %d\n",received));
754
755       DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
756
757       if (received <= 0) break;
758
759       first = False;
760
761       dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
762
763       if (!dirlist) 
764         return 0;
765
766       p = smb_buf(inbuf) + 3;
767
768       memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
769              p,received*DIR_STRUCT_SIZE);
770
771       memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
772
773       num_received += received;
774
775       if (CVAL(inbuf,smb_rcls) != 0) break;
776     }
777
778 #if FFIRST
779   if (!first && Protocol >= PROTOCOL_LANMAN1)
780     {
781       bzero(outbuf,smb_size);
782       CVAL(outbuf,smb_com) = SMBfclose;
783
784       SSVAL(outbuf,smb_tid,cnum);
785       setup_pkt(outbuf);
786
787       p = smb_buf(outbuf);
788       *p++ = 4;
789       
790       strcpy(p,"");
791       p += strlen(p) + 1;
792       
793       *p++ = 5;
794       SSVAL(p,0,21);
795       p += 2;
796       memcpy(p,status,21);
797
798       send_smb(Client,outbuf);
799       receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
800
801       if (CVAL(inbuf,smb_rcls) != 0) 
802         DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));      
803     }
804 #endif
805
806   if (!fn)
807     for (p=dirlist,i=0;i<num_received;i++)
808       {
809         p += interpret_short_filename(p,&finfo);
810         display_finfo(&finfo);
811       }
812
813   for (p=dirlist,i=0;i<num_received;i++)
814     {
815       p += interpret_short_filename(p,&finfo);
816       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False);
817     }
818
819   if (dirlist) free(dirlist);
820   return(num_received);
821 }
822
823 /****************************************************************************
824   receive a SMB trans or trans2 response allocating the necessary memory
825   ****************************************************************************/
826 static BOOL receive_trans_response(char *inbuf,int trans,
827                                    int *data_len,int *param_len,
828                                       char **data,char **param)
829 {
830   int total_data=0;
831   int total_param=0;
832   int this_data,this_param;
833
834   *data_len = *param_len = 0;
835
836   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
837   show_msg(inbuf);
838
839   /* sanity check */
840   if (CVAL(inbuf,smb_com) != trans)
841     {
842       DEBUG(0,("Expected %s response, got command 0x%02x\n",
843                trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
844       return(False);
845     }
846   if (CVAL(inbuf,smb_rcls) != 0)
847     return(False);
848
849   /* parse out the lengths */
850   total_data = SVAL(inbuf,smb_tdrcnt);
851   total_param = SVAL(inbuf,smb_tprcnt);
852
853   /* allocate it */
854   *data = Realloc(*data,total_data);
855   *param = Realloc(*param,total_param);
856
857   while (1)
858     {
859       this_data = SVAL(inbuf,smb_drcnt);
860       this_param = SVAL(inbuf,smb_prcnt);
861       if (this_data)
862         memcpy(*data + SVAL(inbuf,smb_drdisp),
863                smb_base(inbuf) + SVAL(inbuf,smb_droff),
864                this_data);
865       if (this_param)
866         memcpy(*param + SVAL(inbuf,smb_prdisp),
867                smb_base(inbuf) + SVAL(inbuf,smb_proff),
868                this_param);
869       *data_len += this_data;
870       *param_len += this_param;
871
872       /* parse out the total lengths again - they can shrink! */
873       total_data = SVAL(inbuf,smb_tdrcnt);
874       total_param = SVAL(inbuf,smb_tprcnt);
875
876       if (total_data <= *data_len && total_param <= *param_len)
877         break;
878
879       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
880       show_msg(inbuf);
881
882       /* sanity check */
883       if (CVAL(inbuf,smb_com) != trans)
884         {
885           DEBUG(0,("Expected %s response, got command 0x%02x\n",
886                    trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
887           return(False);
888         }
889       if (CVAL(inbuf,smb_rcls) != 0)
890           return(False);
891     }
892   
893   return(True);
894 }
895
896 /****************************************************************************
897   do a directory listing, calling fn on each file found. Use the TRANSACT2
898   call for long filenames
899   ****************************************************************************/
900 static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
901 {
902   int max_matches = 512;
903   int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
904   char *p;
905   pstring mask;
906   file_info finfo;
907   int i;
908   char *dirlist = NULL;
909   int dirlist_len = 0;
910   int total_received = 0;
911   BOOL First = True;
912   char *resp_data=NULL;
913   char *resp_param=NULL;
914   int resp_data_len = 0;
915   int resp_param_len=0;
916
917   int ff_resume_key = 0;
918   int ff_searchcount=0;
919   int ff_eos=0;
920   int ff_lastname=0;
921   int ff_dir_handle=0;
922   int loop_count = 0;
923
924   uint16 setup;
925   pstring param;
926
927   strcpy(mask,Mask);
928
929   while (ff_eos == 0)
930     {
931       loop_count++;
932       if (loop_count > 200)
933         {
934           DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
935           break;
936         }
937
938       if (First)
939         {
940           setup = TRANSACT2_FINDFIRST;
941           SSVAL(param,0,attribute); /* attribute */
942           SSVAL(param,2,max_matches); /* max count */
943           SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
944           SSVAL(param,6,info_level); 
945           SIVAL(param,8,0);
946           strcpy(param+12,mask);
947         }
948       else
949         {
950           setup = TRANSACT2_FINDNEXT;
951           SSVAL(param,0,ff_dir_handle);
952           SSVAL(param,2,max_matches); /* max count */
953           SSVAL(param,4,info_level); 
954           SIVAL(param,6,ff_resume_key); /* ff_resume_key */
955           SSVAL(param,10,8+4+2);        /* resume required + close on end + continue */
956           strcpy(param+12,mask);
957
958           DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
959                    ff_dir_handle,ff_resume_key,ff_lastname,mask));
960         }
961       /* ??? original code added 1 pad byte after param */
962
963       send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
964                          NULL,param,&setup,
965                          0,12+strlen(mask)+1,1,
966                          BUFFER_SIZE,10,0);
967
968       if (!receive_trans_response(inbuf,SMBtrans2,
969                               &resp_data_len,&resp_param_len,
970                                   &resp_data,&resp_param))
971         {
972           DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
973           break;
974         }
975
976       /* parse out some important return info */
977       p = resp_param;
978       if (First)
979         {
980           ff_dir_handle = SVAL(p,0);
981           ff_searchcount = SVAL(p,2);
982           ff_eos = SVAL(p,4);
983           ff_lastname = SVAL(p,8);
984         }
985       else
986         {
987           ff_searchcount = SVAL(p,0);
988           ff_eos = SVAL(p,2);
989           ff_lastname = SVAL(p,6);
990         }
991
992       if (ff_searchcount == 0) 
993         break;
994
995       /* point to the data bytes */
996       p = resp_data;
997
998       /* we might need the lastname for continuations */
999       if (ff_lastname > 0)
1000         {
1001           switch(info_level)
1002             {
1003             case 260:
1004               ff_resume_key =0;
1005               StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
1006               /* strcpy(mask,p+ff_lastname+94); */
1007               break;
1008             case 1:
1009               strcpy(mask,p + ff_lastname + 1);
1010               ff_resume_key = 0;
1011               break;
1012             }
1013         }
1014       else
1015         strcpy(mask,"");
1016   
1017       /* and add them to the dirlist pool */
1018       dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
1019
1020       if (!dirlist)
1021         {
1022           DEBUG(0,("Failed to expand dirlist\n"));
1023           break;
1024         }
1025
1026       /* put in a length for the last entry, to ensure we can chain entries 
1027          into the next packet */
1028       {
1029         char *p2;
1030         for (p2=p,i=0;i<(ff_searchcount-1);i++)
1031           p2 += interpret_long_filename(info_level,p2,NULL);
1032         SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
1033       }
1034
1035       /* grab the data for later use */
1036       memcpy(dirlist+dirlist_len,p,resp_data_len);
1037       dirlist_len += resp_data_len;
1038
1039       total_received += ff_searchcount;
1040
1041       if (resp_data) free(resp_data); resp_data = NULL;
1042       if (resp_param) free(resp_param); resp_param = NULL;
1043
1044       DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
1045                ff_searchcount,ff_eos,ff_resume_key));
1046
1047       First = False;
1048     }
1049
1050   if (!fn)
1051     for (p=dirlist,i=0;i<total_received;i++)
1052       {
1053         p += interpret_long_filename(info_level,p,&finfo);
1054         display_finfo(&finfo);
1055       }
1056
1057   for (p=dirlist,i=0;i<total_received;i++)
1058     {
1059       p += interpret_long_filename(info_level,p,&finfo);
1060       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
1061     }
1062
1063   /* free up the dirlist buffer */
1064   if (dirlist) free(dirlist);
1065   return(total_received);
1066 }
1067
1068
1069 /****************************************************************************
1070   get a directory listing
1071   ****************************************************************************/
1072 static void cmd_dir(char *inbuf,char *outbuf)
1073 {
1074   int attribute = aDIR | aSYSTEM | aHIDDEN;
1075   pstring mask;
1076   fstring buf;
1077   char *p=buf;
1078
1079   strcpy(mask,cur_dir);
1080   if(mask[strlen(mask)-1]!='\\')
1081     strcat(mask,"\\");
1082
1083   if (next_token(NULL,buf,NULL))
1084     {
1085       if (*p == '\\')
1086         strcpy(mask,p);
1087       else
1088         strcat(mask,p);
1089     }
1090   else {
1091     strcat(mask,"*");
1092   }
1093
1094   do_dir(inbuf,outbuf,mask,attribute,NULL,recurse);
1095
1096   do_dskattr();
1097 }
1098
1099
1100
1101 /****************************************************************************
1102   get a file from rname to lname
1103   ****************************************************************************/
1104 static void do_get(char *rname,char *lname,file_info *finfo1)
1105 {  
1106   int handle=0,fnum;
1107   uint32 nread=0;
1108   char *p;
1109   BOOL newhandle = False;
1110   char *inbuf,*outbuf;
1111   file_info finfo;
1112   BOOL close_done = False;
1113   BOOL ignore_close_error = False;
1114   char *dataptr=NULL;
1115   int datalen=0;
1116
1117   struct timeval tp_start;
1118   GetTimeOfDay(&tp_start);
1119
1120   if (finfo1) 
1121     finfo = *finfo1;
1122   else
1123     finfo = def_finfo;
1124
1125   if (lowercase)
1126     strlower(lname);
1127
1128
1129   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1130   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1131
1132   if (!inbuf || !outbuf)
1133     {
1134       DEBUG(0,("out of memory\n"));
1135       return;
1136     }
1137
1138   bzero(outbuf,smb_size);
1139   set_message(outbuf,15,1 + strlen(rname),True);
1140
1141   CVAL(outbuf,smb_com) = SMBopenX;
1142   SSVAL(outbuf,smb_tid,cnum);
1143   setup_pkt(outbuf);
1144
1145   SSVAL(outbuf,smb_vwv0,0xFF);
1146   SSVAL(outbuf,smb_vwv2,1);
1147   SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1148   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1149   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1150   SSVAL(outbuf,smb_vwv8,1);
1151   
1152   p = smb_buf(outbuf);
1153   strcpy(p,rname);
1154   p = skip_string(p,1);
1155
1156   /* do a chained openX with a readX? */
1157 #if 1
1158   if (finfo.size > 0)
1159     {
1160       DEBUG(3,("Chaining readX wth openX\n"));
1161       SSVAL(outbuf,smb_vwv0,SMBreadX);
1162       SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
1163       bzero(p,200);
1164       p -= smb_wct;
1165       SSVAL(p,smb_wct,10);
1166       SSVAL(p,smb_vwv0,0xFF);
1167       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1168       SSVAL(p,smb_vwv9,MIN(BUFFER_SIZE,finfo.size));
1169       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
1170     }
1171 #endif
1172
1173   if(!strcmp(lname,"-"))
1174     handle = fileno(stdout);
1175   else 
1176     {
1177       handle = creat(lname,0644);
1178       newhandle = True;
1179     }
1180   if (handle < 0)
1181     {
1182       DEBUG(0,("Error opening local file %s\n",lname));
1183       free(inbuf);free(outbuf);
1184       return;
1185     }
1186
1187   send_smb(Client,outbuf);
1188   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1189
1190   if (CVAL(inbuf,smb_rcls) != 0)
1191     {
1192       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1193           SVAL(inbuf,smb_err) == ERRnoresource &&
1194           reopen_connection(inbuf,outbuf))
1195         {
1196           do_get(rname,lname,finfo1);
1197           return;
1198         }
1199       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1200       if(newhandle)
1201         close(handle);
1202       free(inbuf);free(outbuf);
1203       return;
1204     }
1205
1206   strcpy(finfo.name,rname);
1207
1208   if (!finfo1)
1209     {
1210       finfo.mode = SVAL(inbuf,smb_vwv3);
1211       /* these times arrive as LOCAL time, using the DST offset 
1212          corresponding to that time, we convert them to GMT */
1213       finfo.mtime = make_unix_date3(inbuf+smb_vwv4);
1214       finfo.atime = finfo.ctime = finfo.mtime;
1215       finfo.size = IVAL(inbuf,smb_vwv6);
1216     }
1217
1218   DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode));
1219
1220   fnum = SVAL(inbuf,smb_vwv2);
1221
1222   /* we might have got some data from a chained readX */
1223   if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1224     {
1225       p = (smb_base(inbuf)+SVAL(inbuf,smb_vwv1)) - smb_wct;
1226       datalen = SVAL(p,smb_vwv5);
1227       dataptr = smb_base(inbuf) + SVAL(p,smb_vwv6);
1228     }
1229   else
1230     {
1231       dataptr = NULL;
1232       datalen = 0;
1233     }
1234
1235
1236   DEBUG(2,("getting file %s of size %d bytes as %s ",
1237            CNV_LANG(finfo.name),
1238            finfo.size,
1239            lname));
1240
1241   while (nread < finfo.size && !close_done)
1242     {
1243       int method = -1;
1244       static BOOL can_chain_close = True;
1245
1246       p=NULL;
1247       
1248       DEBUG(3,("nread=%d max_xmit=%d fsize=%d\n",nread,max_xmit,finfo.size));
1249
1250       /* 3 possible read types. readbraw if a large block is required.
1251          readX + close if not much left and read if neither is supported */
1252
1253       /* we might have already read some data from a chained readX */
1254       if (dataptr && datalen>0)
1255         method=3;
1256
1257       /* if we can finish now then readX+close */
1258       if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
1259           ((finfo.size - nread) < 
1260            (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1261         method = 0;
1262
1263       /* if we support readraw then use that */
1264       if (method<0 && readbraw_supported)
1265         method = 1;
1266
1267       /* if we can then use readX */
1268       if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1269         method = 2;
1270
1271       switch (method)
1272         {
1273           /* use readX */
1274         case 0:
1275         case 2:
1276           if (method == 0)
1277             close_done = True;
1278             
1279           /* use readX + close */
1280           bzero(outbuf,smb_size);
1281           set_message(outbuf,10,0,True);
1282           CVAL(outbuf,smb_com) = SMBreadX;
1283           SSVAL(outbuf,smb_tid,cnum);
1284           setup_pkt(outbuf);
1285           
1286           if (close_done)
1287             {
1288               CVAL(outbuf,smb_vwv0) = SMBclose;
1289               SSVAL(outbuf,smb_vwv1,smb_offset(smb_buf(outbuf),outbuf));
1290             }
1291           else
1292             CVAL(outbuf,smb_vwv0) = 0xFF;             
1293           
1294           SSVAL(outbuf,smb_vwv2,fnum);
1295           SIVAL(outbuf,smb_vwv3,nread);
1296           SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1297           SSVAL(outbuf,smb_vwv6,0);
1298           SIVAL(outbuf,smb_vwv7,0);
1299           SSVAL(outbuf,smb_vwv9,MIN(BUFFER_SIZE,finfo.size-nread));
1300           
1301           if (close_done)
1302             {
1303               p = smb_buf(outbuf);
1304               bzero(p,9);
1305               
1306               CVAL(p,0) = 3;
1307               SSVAL(p,1,fnum);
1308               SIVALS(p,3,-1);
1309               
1310               /* now set the total packet length */
1311               smb_setlen(outbuf,smb_len(outbuf)+9);
1312             }
1313           
1314           send_smb(Client,outbuf);
1315           receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1316           
1317           if (CVAL(inbuf,smb_rcls) != 0)
1318             {
1319               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1320               break;
1321             }
1322           
1323           if (close_done &&
1324               SVAL(inbuf,smb_vwv0) != SMBclose)
1325             {
1326               /* NOTE: WfWg sometimes just ignores the chained
1327                  command! This seems to break the spec? */
1328               DEBUG(3,("Rejected chained close?\n"));
1329               close_done = False;
1330               can_chain_close = False;
1331               ignore_close_error = True;
1332             }
1333           
1334           datalen = SVAL(inbuf,smb_vwv5);
1335           dataptr = smb_base(inbuf) + SVAL(inbuf,smb_vwv6);
1336           break;
1337
1338           /* use readbraw */
1339         case 1:
1340           {
1341             static int readbraw_size = BUFFER_SIZE;
1342           
1343             extern int Client;
1344             bzero(outbuf,smb_size);
1345             set_message(outbuf,8,0,True);
1346             CVAL(outbuf,smb_com) = SMBreadbraw;
1347             SSVAL(outbuf,smb_tid,cnum);
1348             setup_pkt(outbuf);
1349             SSVAL(outbuf,smb_vwv0,fnum);
1350             SIVAL(outbuf,smb_vwv1,nread);
1351             SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1352             SSVAL(outbuf,smb_vwv4,0);
1353             SIVALS(outbuf,smb_vwv5,-1);
1354             send_smb(Client,outbuf);
1355
1356             /* Now read the raw data into the buffer and write it */      
1357             if(read_smb_length(Client,inbuf,0) == -1) {
1358               DEBUG(0,("Failed to read length in readbraw\n"));     
1359               exit(1);
1360             }
1361             
1362             /* Even though this is not an smb message, smb_len
1363                returns the generic length of an smb message */
1364             datalen = smb_len(inbuf);
1365
1366             if (datalen == 0)
1367               {
1368                 /* we got a readbraw error */
1369                 DEBUG(4,("readbraw error - reducing size\n"));
1370                 readbraw_size = (readbraw_size * 9) / 10;
1371                 
1372                 if (readbraw_size < max_xmit)
1373                   {
1374                     DEBUG(0,("disabling readbraw\n"));
1375                     readbraw_supported = False;
1376                   }
1377                 
1378                 dataptr=NULL;
1379                 continue;
1380               }
1381
1382             if(read_data(Client,inbuf,datalen) != datalen) {
1383               DEBUG(0,("Failed to read data in readbraw\n"));
1384               exit(1);
1385             }
1386             dataptr = inbuf;
1387           }
1388           break;
1389
1390         case 3:
1391           /* we've already read some data with a chained readX */
1392           break;
1393
1394         default:
1395           /* use plain read */
1396           bzero(outbuf,smb_size);
1397           set_message(outbuf,5,0,True);
1398           CVAL(outbuf,smb_com) = SMBread;
1399           SSVAL(outbuf,smb_tid,cnum);
1400           setup_pkt(outbuf);
1401
1402           SSVAL(outbuf,smb_vwv0,fnum);
1403           SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1404           SIVAL(outbuf,smb_vwv2,nread);
1405           SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1406
1407           send_smb(Client,outbuf);
1408           receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1409
1410           if (CVAL(inbuf,smb_rcls) != 0)
1411             {
1412               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1413               break;
1414             }
1415
1416           datalen = SVAL(inbuf,smb_vwv0);
1417           dataptr = smb_buf(inbuf) + 3;
1418           break;
1419         }
1420  
1421       if (writefile(handle,dataptr,datalen) != datalen)
1422         {
1423           DEBUG(0,("Error writing local file\n"));
1424           break;
1425         }
1426       
1427       nread += datalen;
1428       if (datalen == 0) 
1429         {
1430           DEBUG(0,("Error reading file %s. Got %d bytes\n",CNV_LANG(rname),nread));
1431           break;
1432         }
1433
1434       dataptr=NULL;
1435       datalen=0;
1436     }
1437
1438
1439
1440   if (!close_done)
1441     {
1442       bzero(outbuf,smb_size);
1443       set_message(outbuf,3,0,True);
1444       CVAL(outbuf,smb_com) = SMBclose;
1445       SSVAL(outbuf,smb_tid,cnum);
1446       setup_pkt(outbuf);
1447       
1448       SSVAL(outbuf,smb_vwv0,fnum);
1449       SIVALS(outbuf,smb_vwv1,-1);
1450       
1451       send_smb(Client,outbuf);
1452       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1453       
1454       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1455         {
1456           DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1457           if(newhandle)
1458             close(handle);
1459           free(inbuf);free(outbuf);
1460           return;
1461         }
1462     }
1463
1464   if(newhandle)
1465     close(handle);
1466
1467   if (archive_level >= 2 && (finfo.mode & aARCH)) {
1468     bzero(outbuf,smb_size);
1469     set_message(outbuf,8,strlen(rname)+4,True);
1470     CVAL(outbuf,smb_com) = SMBsetatr;
1471     SSVAL(outbuf,smb_tid,cnum);
1472     setup_pkt(outbuf);
1473     SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
1474     SIVALS(outbuf,smb_vwv1,0);
1475     p = smb_buf(outbuf);
1476     *p++ = 4;
1477     strcpy(p,rname);
1478     p += strlen(p)+1;
1479     *p++ = 4;
1480     *p = 0;
1481     send_smb(Client,outbuf);
1482     receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1483   }
1484
1485   {
1486     struct timeval tp_end;
1487     int this_time;
1488
1489     GetTimeOfDay(&tp_end);
1490     this_time = 
1491       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1492         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1493     get_total_time_ms += this_time;
1494     get_total_size += finfo.size;
1495
1496     DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
1497              finfo.size / (1.024*this_time + 1.0e-4),
1498              get_total_size / (1.024*get_total_time_ms)));
1499   }
1500
1501   free(inbuf);free(outbuf);
1502 }
1503
1504
1505 /****************************************************************************
1506   get a file
1507   ****************************************************************************/
1508 static void cmd_get(void)
1509 {
1510   pstring lname;
1511   pstring rname;
1512   char *p;
1513
1514   strcpy(rname,cur_dir);
1515   strcat(rname,"\\");
1516
1517   p = rname + strlen(rname);
1518
1519   if (!next_token(NULL,p,NULL)) {
1520     DEBUG(0,("get <filename>\n"));
1521     return;
1522   }
1523   strcpy(lname,p);
1524   dos_clean_name(rname);
1525     
1526   next_token(NULL,lname,NULL);
1527
1528   do_get(rname,lname,NULL);
1529 }
1530
1531
1532 /****************************************************************************
1533   do a mget operation on one file
1534   ****************************************************************************/
1535 static void do_mget(file_info *finfo)
1536 {
1537   pstring rname;
1538   pstring quest;
1539
1540   if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1541     return;
1542
1543   if (abort_mget)
1544     {
1545       DEBUG(0,("mget aborted\n"));
1546       return;
1547     }
1548
1549   if (finfo->mode & aDIR)
1550     sprintf(quest,"Get directory %s? ",CNV_LANG(finfo->name));
1551   else
1552     sprintf(quest,"Get file %s? ",CNV_LANG(finfo->name));
1553
1554   if (prompt && !yesno(quest)) return;
1555
1556   if (finfo->mode & aDIR)
1557     {
1558       pstring saved_curdir;
1559       pstring mget_mask;
1560       char *inbuf,*outbuf;
1561
1562       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1563       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1564
1565       if (!inbuf || !outbuf)
1566         {
1567           DEBUG(0,("out of memory\n"));
1568           return;
1569         }
1570
1571       strcpy(saved_curdir,cur_dir);
1572
1573       strcat(cur_dir,finfo->name);
1574       strcat(cur_dir,"\\");
1575
1576       unix_format(finfo->name);
1577       {
1578         if (lowercase)
1579           strlower(finfo->name);
1580
1581         if (!directory_exist(finfo->name,NULL) && 
1582             sys_mkdir(finfo->name,0777) != 0) 
1583           {
1584             DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
1585             strcpy(cur_dir,saved_curdir);
1586             free(inbuf);free(outbuf);
1587             return;
1588           }
1589
1590         if (sys_chdir(finfo->name) != 0)
1591           {
1592             DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
1593             strcpy(cur_dir,saved_curdir);
1594             free(inbuf);free(outbuf);
1595             return;
1596           }
1597       }       
1598
1599       strcpy(mget_mask,cur_dir);
1600       strcat(mget_mask,"*");
1601       
1602       do_dir((char *)inbuf,(char *)outbuf,
1603              mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False);
1604       chdir("..");
1605       strcpy(cur_dir,saved_curdir);
1606       free(inbuf);free(outbuf);
1607     }
1608   else
1609     {
1610       strcpy(rname,cur_dir);
1611       strcat(rname,finfo->name);
1612       do_get(rname,finfo->name,finfo);
1613     }
1614 }
1615
1616 /****************************************************************************
1617 view the file using the pager
1618 ****************************************************************************/
1619 static void cmd_more(void)
1620 {
1621   fstring rname,lname,tmpname,pager_cmd;
1622   char *pager;
1623
1624   strcpy(rname,cur_dir);
1625   strcat(rname,"\\");
1626   sprintf(tmpname,"/tmp/smbmore.%d",getpid());
1627   strcpy(lname,tmpname);
1628
1629   if (!next_token(NULL,rname+strlen(rname),NULL)) {
1630     DEBUG(0,("more <filename>\n"));
1631     return;
1632   }
1633   dos_clean_name(rname);
1634
1635   do_get(rname,lname,NULL);
1636
1637   pager=getenv("PAGER");
1638   sprintf(pager_cmd,"%s %s",(pager? pager:PAGER), tmpname);
1639   system(pager_cmd);
1640   unlink(tmpname);
1641 }
1642
1643
1644
1645 /****************************************************************************
1646 do a mget command
1647 ****************************************************************************/
1648 static void cmd_mget(char *inbuf,char *outbuf)
1649 {
1650   int attribute = aSYSTEM | aHIDDEN;
1651   pstring mget_mask;
1652   fstring buf;
1653   char *p=buf;
1654
1655   *mget_mask = 0;
1656
1657   if (recurse)
1658     attribute |= aDIR;
1659
1660   abort_mget = False;
1661
1662   while (next_token(NULL,p,NULL))
1663     {
1664       strcpy(mget_mask,cur_dir);
1665       if(mget_mask[strlen(mget_mask)-1]!='\\')
1666         strcat(mget_mask,"\\");
1667
1668       if (*p == '\\')
1669         strcpy(mget_mask,p);
1670       else
1671         strcat(mget_mask,p);
1672       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
1673     }
1674
1675   if (! *mget_mask)
1676     {
1677       strcpy(mget_mask,cur_dir);
1678       if(mget_mask[strlen(mget_mask)-1]!='\\')
1679         strcat(mget_mask,"\\");
1680       strcat(mget_mask,"*");
1681       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
1682     }
1683 }
1684
1685 /****************************************************************************
1686 make a directory of name "name"
1687 ****************************************************************************/
1688 static BOOL do_mkdir(char *name)
1689 {
1690   char *p;
1691   char *inbuf,*outbuf;
1692
1693   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1694   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1695
1696   if (!inbuf || !outbuf)
1697     {
1698       DEBUG(0,("out of memory\n"));
1699       return False;
1700     }
1701
1702   bzero(outbuf,smb_size);
1703   set_message(outbuf,0,2 + strlen(name),True);
1704   
1705   CVAL(outbuf,smb_com) = SMBmkdir;
1706   SSVAL(outbuf,smb_tid,cnum);
1707   setup_pkt(outbuf);
1708
1709   
1710   p = smb_buf(outbuf);
1711   *p++ = 4;      
1712   strcpy(p,name);
1713   
1714   send_smb(Client,outbuf);
1715   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1716   
1717   if (CVAL(inbuf,smb_rcls) != 0)
1718     {
1719       DEBUG(0,("%s making remote directory %s\n",
1720                smb_errstr(inbuf),CNV_LANG(name)));
1721
1722       free(inbuf);free(outbuf);
1723       return(False);
1724     }
1725
1726   free(inbuf);free(outbuf);
1727   return(True);
1728 }
1729
1730
1731 /****************************************************************************
1732   make a directory
1733   ****************************************************************************/
1734 static void cmd_mkdir(char *inbuf,char *outbuf)
1735 {
1736   pstring mask;
1737   fstring buf;
1738   char *p=buf;
1739   
1740   strcpy(mask,cur_dir);
1741
1742   if (!next_token(NULL,p,NULL))
1743     {
1744       if (!recurse)
1745         DEBUG(0,("mkdir <dirname>\n"));
1746       return;
1747     }
1748   strcat(mask,p);
1749
1750   if (recurse)
1751     {
1752       pstring ddir;
1753       pstring ddir2;
1754       *ddir2 = 0;
1755
1756       strcpy(ddir,mask);
1757       trim_string(ddir,".",NULL);
1758       p = strtok(ddir,"/\\");
1759       while (p)
1760         {
1761           strcat(ddir2,p);
1762           if (!chkpath(ddir2,False))
1763             {             
1764               do_mkdir(ddir2);
1765             }
1766           strcat(ddir2,"\\");
1767           p = strtok(NULL,"/\\");
1768         }        
1769     }
1770   else
1771     do_mkdir(mask);
1772 }
1773
1774
1775 /*******************************************************************
1776   write to a file using writebraw
1777   ********************************************************************/
1778 static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
1779 {
1780   extern int Client;
1781   pstring inbuf;
1782
1783   bzero(outbuf,smb_size);
1784   bzero(inbuf,smb_size);  
1785   set_message(outbuf,Protocol>PROTOCOL_COREPLUS?12:10,0,True);
1786
1787   CVAL(outbuf,smb_com) = SMBwritebraw;
1788   SSVAL(outbuf,smb_tid,cnum);
1789   setup_pkt(outbuf);
1790
1791   SSVAL(outbuf,smb_vwv0,fnum);
1792   SSVAL(outbuf,smb_vwv1,n);
1793   SIVAL(outbuf,smb_vwv3,pos);
1794   SSVAL(outbuf,smb_vwv7,1);
1795
1796   send_smb(Client,outbuf);
1797   
1798   if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
1799     return(0);
1800
1801   _smb_setlen(buf-4,n);         /* HACK! XXXX */
1802
1803   if (write_socket(Client,buf-4,n+4) != n+4)
1804     return(0);
1805
1806   if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
1807     DEBUG(0,("Error writing remote file (2)\n"));
1808     return(0);
1809   }
1810   return(SVAL(inbuf,smb_vwv0));
1811 }
1812       
1813
1814
1815 /*******************************************************************
1816   write to a file
1817   ********************************************************************/
1818 static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
1819 {
1820   pstring inbuf;
1821
1822   if (writebraw_supported && n > (max_xmit-200)) 
1823     return(smb_writeraw(outbuf,fnum,pos,buf,n));
1824
1825   bzero(outbuf,smb_size);
1826   bzero(inbuf,smb_size);
1827   set_message(outbuf,5,n + 3,True);
1828
1829   CVAL(outbuf,smb_com) = SMBwrite;
1830   SSVAL(outbuf,smb_tid,cnum);
1831   setup_pkt(outbuf);
1832
1833   SSVAL(outbuf,smb_vwv0,fnum);
1834   SSVAL(outbuf,smb_vwv1,n);
1835   SIVAL(outbuf,smb_vwv2,pos);
1836   SSVAL(outbuf,smb_vwv4,0);
1837   CVAL(smb_buf(outbuf),0) = 1;
1838   SSVAL(smb_buf(outbuf),1,n);
1839
1840   memcpy(smb_buf(outbuf)+3,buf,n);
1841
1842   send_smb(Client,outbuf);
1843   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1844
1845   if (CVAL(inbuf,smb_rcls) != 0) {
1846     DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
1847     return(0);
1848   }
1849   return(SVAL(inbuf,smb_vwv0));
1850 }
1851       
1852
1853
1854 /****************************************************************************
1855   put a single file
1856   ****************************************************************************/
1857 static void do_put(char *rname,char *lname,file_info *finfo)
1858 {
1859   int fnum;
1860   FILE *f;
1861   int nread=0;
1862   char *p;
1863   char *inbuf,*outbuf; 
1864   time_t close_time = finfo->mtime;
1865   char *buf=NULL;
1866   static int maxwrite=0;
1867
1868   struct timeval tp_start;
1869   GetTimeOfDay(&tp_start);
1870
1871   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1872   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1873
1874   if (!inbuf || !outbuf)
1875     {
1876       DEBUG(0,("out of memory\n"));
1877       return;
1878     }
1879
1880   bzero(outbuf,smb_size);
1881   set_message(outbuf,3,2 + strlen(rname),True);
1882
1883   if (finfo->mtime == 0 || finfo->mtime == -1)
1884     finfo->mtime = finfo->atime = finfo->ctime = time(NULL);
1885
1886   CVAL(outbuf,smb_com) = SMBcreate;
1887   SSVAL(outbuf,smb_tid,cnum);
1888   setup_pkt(outbuf);
1889
1890   SSVAL(outbuf,smb_vwv0,finfo->mode);
1891   put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
1892   
1893   p = smb_buf(outbuf);
1894   *p++ = 4;      
1895   strcpy(p,rname);
1896   
1897   send_smb(Client,outbuf);
1898   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1899   
1900   if (CVAL(inbuf,smb_rcls) != 0)
1901     {
1902       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1903
1904       free(inbuf);free(outbuf);if (buf) free(buf);
1905       return;
1906     }
1907
1908   f = fopen(lname,"r");
1909
1910   if (!f)
1911     {
1912       DEBUG(0,("Error opening local file %s\n",lname));
1913       free(inbuf);free(outbuf);
1914       return;
1915     }
1916
1917   
1918   fnum = SVAL(inbuf,smb_vwv0);
1919   if (finfo->size < 0)
1920     finfo->size = file_size(lname);
1921   
1922   DEBUG(1,("putting file %s of size %d bytes as %s ",lname,finfo->size,CNV_LANG(rname)));
1923   
1924   if (!maxwrite)
1925     maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
1926
1927   while (nread < finfo->size)
1928     {
1929       int n = maxwrite;
1930       int ret;
1931
1932       n = MIN(n,finfo->size - nread);
1933
1934       buf = (char *)Realloc(buf,n+4);
1935   
1936       fseek(f,nread,SEEK_SET);
1937       if ((n = readfile(buf+4,1,n,f)) < 1)
1938         {
1939           DEBUG(0,("Error reading local file\n"));
1940           break;
1941         }         
1942
1943       ret = smb_writefile(outbuf,fnum,nread,buf+4,n);
1944
1945       if (n != ret) {
1946         if (!maxwrite) {
1947           DEBUG(0,("Error writing file\n"));
1948           break;
1949         } else {
1950           maxwrite /= 2;
1951           continue;
1952         }
1953       }
1954
1955       nread += n;
1956     }
1957
1958
1959
1960   bzero(outbuf,smb_size);
1961   set_message(outbuf,3,0,True);
1962   CVAL(outbuf,smb_com) = SMBclose;
1963   SSVAL(outbuf,smb_tid,cnum);
1964   setup_pkt(outbuf);
1965
1966   SSVAL(outbuf,smb_vwv0,fnum);  
1967   put_dos_date3(outbuf,smb_vwv1,close_time);
1968
1969   send_smb(Client,outbuf);
1970   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1971   
1972   if (CVAL(inbuf,smb_rcls) != 0)
1973     {
1974       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1975       fclose(f);
1976       free(inbuf);free(outbuf);
1977       if (buf) free(buf);
1978       return;
1979     }
1980
1981   
1982   fclose(f);
1983   free(inbuf);free(outbuf);
1984   if (buf) free(buf);
1985
1986   {
1987     struct timeval tp_end;
1988     int this_time;
1989
1990     GetTimeOfDay(&tp_end);
1991     this_time = 
1992       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1993         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1994     put_total_time_ms += this_time;
1995     put_total_size += finfo->size;
1996
1997     DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
1998              finfo->size / (1.024*this_time + 1.0e-4),
1999              put_total_size / (1.024*put_total_time_ms)));
2000   }
2001
2002
2003  
2004
2005 /****************************************************************************
2006   put a file
2007   ****************************************************************************/
2008 static void cmd_put(void)
2009 {
2010   pstring lname;
2011   pstring rname;
2012   fstring buf;
2013   char *p=buf;
2014   file_info finfo;
2015   finfo = def_finfo;
2016   
2017   strcpy(rname,cur_dir);
2018   strcat(rname,"\\");
2019   
2020   
2021   if (!next_token(NULL,p,NULL))
2022     {
2023       DEBUG(0,("put <filename>\n"));
2024       return;
2025     }
2026   strcpy(lname,p);
2027   
2028   if (next_token(NULL,p,NULL))
2029     strcat(rname,p);      
2030   else
2031     strcat(rname,lname);
2032
2033   dos_clean_name(rname);
2034
2035   {
2036     struct stat st;
2037     if (!file_exist(lname,&st)) {
2038       DEBUG(0,("%s does not exist\n",lname));
2039       return;
2040     }
2041     finfo.mtime = st.st_mtime;
2042   }
2043
2044   do_put(rname,lname,&finfo);
2045 }
2046
2047 /****************************************************************************
2048   seek in a directory/file list until you get something that doesn't start with
2049   the specified name
2050   ****************************************************************************/
2051 static BOOL seek_list(FILE *f,char *name)
2052 {
2053   pstring s;
2054   while (!feof(f))
2055     {
2056       if (fscanf(f,"%s",s) != 1) return(False);
2057       trim_string(s,"./",NULL);
2058       if (strncmp(s,name,strlen(name)) != 0)
2059         {
2060           strcpy(name,s);
2061           return(True);
2062         }
2063     }
2064       
2065   return(False);
2066 }
2067
2068
2069 /****************************************************************************
2070   set the file selection mask
2071   ****************************************************************************/
2072 static void cmd_select(void)
2073 {
2074   strcpy(fileselection,"");
2075   next_token(NULL,fileselection,NULL);
2076 }
2077
2078
2079 /****************************************************************************
2080   mput some files
2081   ****************************************************************************/
2082 static void cmd_mput(void)
2083 {
2084   pstring lname;
2085   pstring rname;
2086   file_info finfo;
2087   fstring buf;
2088   char *p=buf;
2089
2090   finfo = def_finfo;
2091
2092   
2093   while (next_token(NULL,p,NULL))
2094     {
2095       struct stat st;
2096       pstring cmd;
2097       pstring tmpname;
2098       FILE *f;
2099       
2100       sprintf(tmpname,"/tmp/ls.smb.%d",(int)getpid());
2101       if (recurse)
2102         sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpname);
2103       else
2104         sprintf(cmd,"/bin/ls %s > %s",p,tmpname);
2105       system(cmd);
2106
2107       f = fopen(tmpname,"r");
2108       if (!f) continue;
2109
2110       while (!feof(f))
2111         {
2112           pstring quest;
2113
2114           if (fscanf(f,"%s",lname) != 1) break;
2115           trim_string(lname,"./",NULL);
2116
2117         again1:
2118
2119           /* check if it's a directory */
2120           if (directory_exist(lname,&st))
2121             {
2122               if (!recurse) continue;
2123               sprintf(quest,"Put directory %s? ",lname);
2124               if (prompt && !yesno(quest)) 
2125                 {
2126                   strcat(lname,"/");
2127                   if (!seek_list(f,lname))
2128                     break;
2129                   goto again1;              
2130                 }
2131               
2132               strcpy(rname,cur_dir);
2133               strcat(rname,lname);
2134               if (!do_mkdir(rname))
2135                 {
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,GMT_TO_LOCAL))));
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,GMT_TO_LOCAL)),
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     set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
3186     CVAL(outbuf,smb_com) = SMBtconX;
3187     setup_pkt(outbuf);
3188
3189     SSVAL(outbuf,smb_vwv0,0xFF);
3190     SSVAL(outbuf,smb_vwv3,passlen);
3191
3192     p = smb_buf(outbuf);
3193     memcpy(p,pword,passlen);
3194     p += passlen;
3195     strcpy(p,service);
3196     p = skip_string(p,1);
3197     strcpy(p,dev);
3198   }
3199
3200   send_smb(Client,outbuf);
3201   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3202
3203   /* trying again with a blank password */
3204   if (CVAL(inbuf,smb_rcls) != 0 && 
3205       (int)strlen(pass) > 0 && 
3206       !doencrypt &&
3207       Protocol >= PROTOCOL_LANMAN1)
3208     {
3209       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
3210       strcpy(pass,"");
3211       goto again2;
3212     }  
3213
3214   if (CVAL(inbuf,smb_rcls) != 0)
3215     {
3216       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
3217       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
3218       DEBUG(0,("Some servers insist that these be in uppercase\n"));
3219       if (was_null)
3220         {
3221           free(inbuf);
3222           free(outbuf);
3223         }
3224       return(False);
3225     }
3226   
3227
3228   max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
3229   if (max_xmit <= 0)
3230     max_xmit = BUFFER_SIZE - 4;
3231
3232   cnum = SVAL(inbuf,smb_tid);
3233
3234   DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
3235
3236   if (was_null)
3237     {
3238       free(inbuf);
3239       free(outbuf);
3240     }
3241   return True;
3242 }
3243
3244
3245 /****************************************************************************
3246 send a logout command
3247 ****************************************************************************/
3248 static void send_logout(void )
3249 {
3250   pstring inbuf,outbuf;
3251
3252   bzero(outbuf,smb_size);
3253   set_message(outbuf,0,0,True);
3254   CVAL(outbuf,smb_com) = SMBtdis;
3255   SSVAL(outbuf,smb_tid,cnum);
3256   setup_pkt(outbuf);
3257
3258   send_smb(Client,outbuf);
3259   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3260
3261   if (CVAL(inbuf,smb_rcls) != 0)
3262     {
3263       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
3264     }
3265
3266   
3267 #ifdef STATS
3268   stats_report();
3269 #endif
3270   exit(0);
3271 }
3272
3273
3274
3275 /****************************************************************************
3276 call a remote api
3277 ****************************************************************************/
3278 static BOOL call_api(int prcnt,int drcnt,
3279                      int mprcnt,int mdrcnt,
3280                      int *rprcnt,int *rdrcnt,
3281                      char *param,char *data,
3282                      char **rparam,char **rdata)
3283 {
3284   static char *inbuf=NULL;
3285   static char *outbuf=NULL;
3286
3287   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3288   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3289
3290   send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
3291                      data,param,NULL,
3292                      drcnt,prcnt,0,
3293                      mdrcnt,mprcnt,0);
3294
3295   return (receive_trans_response(inbuf,SMBtrans,
3296                                  rdrcnt,rprcnt,
3297                                  rdata,rparam));
3298 }
3299
3300 /****************************************************************************
3301   send a SMB trans or trans2 request
3302   ****************************************************************************/
3303 static BOOL send_trans_request(char *outbuf,int trans,
3304                                char *name,int fid,int flags,
3305                                char *data,char *param,uint16 *setup,
3306                                int ldata,int lparam,int lsetup,
3307                                int mdata,int mparam,int msetup)
3308 {
3309   int i;
3310   int this_ldata,this_lparam;
3311   int tot_data=0,tot_param=0;
3312   char *outdata,*outparam;
3313   pstring inbuf;
3314   char *p;
3315
3316   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
3317   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
3318
3319   bzero(outbuf,smb_size);
3320   set_message(outbuf,14+lsetup,0,True);
3321   CVAL(outbuf,smb_com) = trans;
3322   SSVAL(outbuf,smb_tid,cnum);
3323   setup_pkt(outbuf);
3324
3325   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
3326   outdata = outparam+this_lparam;
3327
3328   /* primary request */
3329   SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3330   SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3331   SSVAL(outbuf,smb_mprcnt,mparam);      /* mprcnt */
3332   SSVAL(outbuf,smb_mdrcnt,mdata);       /* mdrcnt */
3333   SCVAL(outbuf,smb_msrcnt,msetup);      /* msrcnt */
3334   SSVAL(outbuf,smb_flags,flags);        /* flags */
3335   SIVAL(outbuf,smb_timeout,0);          /* timeout */
3336   SSVAL(outbuf,smb_pscnt,this_lparam);  /* pscnt */
3337   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
3338   SSVAL(outbuf,smb_dscnt,this_ldata);   /* dscnt */
3339   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
3340   SCVAL(outbuf,smb_suwcnt,lsetup);      /* suwcnt */
3341   for (i=0;i<lsetup;i++)                /* setup[] */
3342     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
3343   p = smb_buf(outbuf);
3344   if (trans==SMBtrans)
3345     strcpy(p,name);                     /* name[] */
3346   else
3347     {
3348       *p++ = 0;                         /* put in a null smb_name */
3349       *p++ = 'D'; *p++ = ' ';           /* this was added because OS/2 does it */
3350     }
3351   if (this_lparam)                      /* param[] */
3352     memcpy(outparam,param,this_lparam);
3353   if (this_ldata)                       /* data[] */
3354     memcpy(outdata,data,this_ldata);
3355   set_message(outbuf,14+lsetup,         /* wcnt, bcc */
3356               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3357
3358   show_msg(outbuf);
3359   send_smb(Client,outbuf);
3360
3361   if (this_ldata < ldata || this_lparam < lparam)
3362     {
3363       /* receive interim response */
3364       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
3365         {
3366           DEBUG(0,("%s request failed (%s)\n",
3367                    trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
3368           return(False);
3369         }      
3370
3371       tot_data = this_ldata;
3372       tot_param = this_lparam;
3373
3374       while (tot_data < ldata || tot_param < lparam)
3375     {
3376           this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
3377           this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
3378
3379           set_message(outbuf,trans==SMBtrans?8:9,0,True);
3380           CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
3381
3382           outparam = smb_buf(outbuf);
3383           outdata = outparam+this_lparam;
3384
3385           /* secondary request */
3386           SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3387           SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3388           SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
3389           SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
3390           SSVAL(outbuf,smb_spsdisp,tot_param);  /* psdisp */
3391           SSVAL(outbuf,smb_sdscnt,this_ldata);  /* dscnt */
3392           SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
3393           SSVAL(outbuf,smb_sdsdisp,tot_data);   /* dsdisp */
3394           if (trans==SMBtrans2)
3395             SSVAL(outbuf,smb_sfid,fid);         /* fid */
3396           if (this_lparam)                      /* param[] */
3397             memcpy(outparam,param,this_lparam);
3398           if (this_ldata)                       /* data[] */
3399             memcpy(outdata,data,this_ldata);
3400           set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
3401                       PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3402
3403           show_msg(outbuf);
3404           send_smb(Client,outbuf);
3405
3406           tot_data += this_ldata;
3407           tot_param += this_lparam;
3408         }
3409     }
3410
3411     return(True);
3412 }
3413
3414 /****************************************************************************
3415 try and browse available connections on a host
3416 ****************************************************************************/
3417 static BOOL browse_host(BOOL sort)
3418 {
3419 #ifdef NOSTRCASECMP
3420 #define strcasecmp StrCaseCmp
3421 #endif
3422   extern int strcasecmp();
3423
3424   char *rparam = NULL;
3425   char *rdata = NULL;
3426   char *p;
3427   int rdrcnt,rprcnt;
3428   pstring param;
3429   int count = -1;
3430
3431   /* now send a SMBtrans command with api RNetShareEnum */
3432   p = param;
3433   SSVAL(p,0,0); /* api number */
3434   p += 2;
3435   strcpy(p,"WrLeh");
3436   p = skip_string(p,1);
3437   strcpy(p,"B13BWz");
3438   p = skip_string(p,1);
3439   SSVAL(p,0,1);
3440   SSVAL(p,2,BUFFER_SIZE);
3441   p += 4;
3442
3443   if (call_api(PTR_DIFF(p,param),0,
3444                1024,BUFFER_SIZE,
3445                &rprcnt,&rdrcnt,
3446                param,NULL,
3447                &rparam,&rdata))
3448     {
3449       int res = SVAL(rparam,0);
3450       int converter=SVAL(rparam,2);
3451       int i;
3452       BOOL long_share_name=False;
3453       
3454       if (res == 0)
3455         {
3456           count=SVAL(rparam,4);
3457           p = rdata;
3458
3459           if (count > 0)
3460             {
3461               printf("\n\tSharename      Type      Comment\n");
3462               printf("\t---------      ----      -------\n");
3463             }
3464
3465           if (sort)
3466             qsort(p,count,20,QSORT_CAST strcasecmp);
3467
3468           for (i=0;i<count;i++)
3469             {
3470               char *sname = p;
3471               int type = SVAL(p,14);
3472               int comment_offset = IVAL(p,16) & 0xFFFF;
3473               fstring typestr;
3474               *typestr=0;
3475
3476               switch (type)
3477                 {
3478                 case STYPE_DISKTREE:
3479                   strcpy(typestr,"Disk"); break;
3480                 case STYPE_PRINTQ:
3481                   strcpy(typestr,"Printer"); break;           
3482                 case STYPE_DEVICE:
3483                   strcpy(typestr,"Device"); break;
3484                 case STYPE_IPC:
3485                   strcpy(typestr,"IPC"); break;      
3486                 }
3487
3488               printf("\t%-15.15s%-10.10s%s\n",
3489                      sname,
3490                      typestr,
3491                      comment_offset?rdata+comment_offset-converter:"");
3492           
3493               if (strlen(sname)>8) long_share_name=True;
3494           
3495               p += 20;
3496             }
3497
3498           if (long_share_name) {
3499             printf("\nNOTE: There were share names longer than 8 chars.\nOn older clients these may not be accessible or may give browsing errors\n");
3500           }
3501         }
3502     }
3503   
3504   if (rparam) free(rparam);
3505   if (rdata) free(rdata);
3506
3507   return(count>0);
3508 }
3509
3510
3511 /****************************************************************************
3512 get some server info
3513 ****************************************************************************/
3514 static void server_info()
3515 {
3516   char *rparam = NULL;
3517   char *rdata = NULL;
3518   char *p;
3519   int rdrcnt,rprcnt;
3520   pstring param;
3521
3522   bzero(param,sizeof(param));
3523
3524   p = param;
3525   SSVAL(p,0,63); /* api number */
3526   p += 2;
3527   strcpy(p,"WrLh");
3528   p = skip_string(p,1);
3529   strcpy(p,"zzzBBzz");
3530   p = skip_string(p,1);
3531   SSVAL(p,0,10); /* level 10 */
3532   SSVAL(p,2,1000);
3533   p += 6;
3534
3535   if (call_api(PTR_DIFF(p,param),0,
3536                6,1000,
3537                &rprcnt,&rdrcnt,
3538                param,NULL,
3539                &rparam,&rdata))
3540     {
3541       int res = SVAL(rparam,0);
3542       int converter=SVAL(rparam,2);
3543
3544       if (res == 0)
3545         {
3546       p = rdata;
3547
3548       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3549              rdata+SVAL(p,0)-converter,
3550              rdata+SVAL(p,4)-converter,
3551              rdata+SVAL(p,8)-converter,
3552              rdata+SVAL(p,14)-converter);
3553     }
3554     }
3555
3556   if (rparam) free(rparam);
3557   if (rdata) free(rdata);
3558
3559   return;
3560 }
3561
3562
3563 /****************************************************************************
3564 try and browse available connections on a host
3565 ****************************************************************************/
3566 static BOOL list_servers()
3567 {
3568   char *rparam = NULL;
3569   char *rdata = NULL;
3570   int rdrcnt,rprcnt;
3571   char *p;
3572   pstring param;
3573   int uLevel = 1;
3574   int count = 0;
3575
3576   /* now send a SMBtrans command with api ServerEnum? */
3577   p = param;
3578   SSVAL(p,0,0x68); /* api number */
3579   p += 2;
3580   strcpy(p,"WrLehDO");
3581   p = skip_string(p,1);
3582
3583   strcpy(p,"B16BBDz");
3584 #if 0
3585   strcpy(p,getenv("XX_STR2"));
3586 #endif
3587
3588   p = skip_string(p,1);
3589   SSVAL(p,0,uLevel);
3590   SSVAL(p,2,0x2000); /* buf length */
3591   p += 4;
3592
3593   SIVAL(p,0,SV_TYPE_ALL);
3594
3595   if (call_api(PTR_DIFF(p+4,param),0,
3596                8,10000,
3597                &rprcnt,&rdrcnt,
3598                param,NULL,
3599                &rparam,&rdata))
3600     {
3601       int res = SVAL(rparam,0);
3602       int converter=SVAL(rparam,2);
3603       int i;
3604
3605       if (res == 0) {   
3606         char *p2 = rdata;
3607         count=SVAL(rparam,4);
3608
3609         if (count > 0) {
3610           printf("\n\nThis machine has a browse list:\n");
3611           printf("\n\tServer               Comment\n");
3612           printf("\t---------            -------\n");
3613         }
3614         
3615         for (i=0;i<count;i++) {
3616           char *sname = p2;
3617           int comment_offset = IVAL(p2,22) & 0xFFFF;
3618           printf("\t%-16.16s     %s\n",
3619                  sname,
3620                  comment_offset?rdata+comment_offset-converter:"");
3621           
3622           p2 += 26;
3623         }
3624       }
3625     }
3626
3627   if (rparam) {free(rparam); rparam = NULL;}
3628   if (rdata) {free(rdata); rdata = NULL;}
3629
3630   SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
3631
3632   if (call_api(PTR_DIFF(p+4,param),0,
3633                8,10000,
3634                &rprcnt,&rdrcnt,
3635                param,NULL,
3636                &rparam,&rdata))
3637     {
3638       int res = SVAL(rparam,0);
3639       int converter=SVAL(rparam,2);
3640       int i;
3641
3642       if (res == 0) {
3643         char *p2 = rdata;
3644         count=SVAL(rparam,4);
3645
3646         if (count > 0) {
3647           printf("\n\nThis machine has a workgroup list:\n");
3648           printf("\n\tWorkgroup            Master\n");
3649           printf("\t---------            -------\n");
3650         }
3651         
3652         for (i=0;i<count;i++) {
3653           char *sname = p2;
3654           int comment_offset = IVAL(p2,22) & 0xFFFF;
3655           printf("\t%-16.16s     %s\n",
3656                  sname,
3657                  comment_offset?rdata+comment_offset-converter:"");
3658           
3659           p2 += 26;
3660         }
3661       }
3662     }
3663
3664   if (rparam) free(rparam);
3665   if (rdata) free(rdata);
3666
3667   return(count>0);
3668 }
3669
3670
3671
3672
3673 void cmd_help();
3674
3675 /* This defines the commands supported by this client */
3676 struct
3677 {
3678   char *name;
3679   void (*fn)();
3680   char *description;
3681 } commands[] = 
3682 {
3683   {"ls",cmd_dir,"<mask> list the contents of the current directory"},
3684   {"dir",cmd_dir,"<mask> list the contents of the current directory"},
3685   {"lcd",cmd_lcd,"[directory] change/report the local current working directory"},
3686   {"cd",cmd_cd,"[directory] change/report the remote directory"},
3687   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
3688   {"get",cmd_get,"<remote name> [local name] get a file"},
3689   {"mget",cmd_mget,"<mask> get all the matching files"},
3690   {"put",cmd_put,"<local name> [remote name] put a file"},
3691   {"mput",cmd_mput,"<mask> put all matching files"},
3692   {"rename",cmd_rename,"<src> <dest> rename some files"},
3693   {"more",cmd_more,"<remote name> view a remote file with your pager"},  
3694   {"mask",cmd_select,"<mask> mask all filenames against this"},
3695   {"del",cmd_del,"<mask> delete all matching files"},
3696   {"rm",cmd_del,"<mask> delete all matching files"},
3697   {"mkdir",cmd_mkdir,"<directory> make a directory"},
3698   {"md",cmd_mkdir,"<directory> make a directory"},
3699   {"rmdir",cmd_rmdir,"<directory> remove a directory"},
3700   {"rd",cmd_rmdir,"<directory> remove a directory"},
3701   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},  
3702   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},  
3703   {"translate",cmd_translate,"toggle text translation for printing"},  
3704   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},  
3705   {"print",cmd_print,"<file name> print a file"},
3706   {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
3707   {"queue",cmd_queue,"show the print queue"},
3708   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
3709   {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
3710   {"quit",send_logout,"logoff the server"},
3711   {"q",send_logout,"logoff the server"},
3712   {"exit",send_logout,"logoff the server"},
3713   {"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
3714   {"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"},
3715   {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
3716   {"blocksize",cmd_block,"blocksize <number> (default 20)" },
3717   {"tarmode",cmd_tarmode,
3718      "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
3719   {"setmode",cmd_setmode,"filename <setmode string> change modes of file"},
3720   {"help",cmd_help,"[command] give help on a command"},
3721   {"?",cmd_help,"[command] give help on a command"},
3722   {"!",NULL,"run a shell command on the local system"},
3723   {"",NULL,NULL}
3724 };
3725
3726
3727 /*******************************************************************
3728   lookup a command string in the list of commands, including 
3729   abbreviations
3730   ******************************************************************/
3731 static int process_tok(fstring tok)
3732 {
3733   int i = 0, matches = 0;
3734   int cmd=0;
3735   int tok_len = strlen(tok);
3736   
3737   while (commands[i].fn != NULL)
3738     {
3739       if (strequal(commands[i].name,tok))
3740         {
3741           matches = 1;
3742           cmd = i;
3743           break;
3744         }
3745       else if (strnequal(commands[i].name, tok, tok_len+1))
3746         {
3747           matches++;
3748           cmd = i;
3749         }
3750       i++;
3751     }
3752   
3753   if (matches == 0)
3754     return(-1);
3755   else if (matches == 1)
3756     return(cmd);
3757   else
3758     return(-2);
3759 }
3760
3761 /****************************************************************************
3762 help
3763 ****************************************************************************/
3764 void cmd_help(void)
3765 {
3766   int i=0,j;
3767   fstring buf;
3768
3769   if (next_token(NULL,buf,NULL))
3770     {
3771       if ((i = process_tok(buf)) >= 0)
3772         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
3773     }
3774   else
3775     while (commands[i].description)
3776       {
3777         for (j=0; commands[i].description && (j<5); j++) {
3778           DEBUG(0,("%-15s",commands[i].name));
3779           i++;
3780         }
3781         DEBUG(0,("\n"));
3782       }
3783 }
3784
3785 /****************************************************************************
3786 open the client sockets
3787 ****************************************************************************/
3788 static BOOL open_sockets(int port )
3789 {
3790   static int last_port;
3791   char *host;
3792   pstring service2;
3793   extern int Client;
3794 #ifdef USENMB
3795   BOOL failed = True;
3796 #endif
3797
3798   if (port == 0) port=last_port;
3799   last_port=port;
3800
3801   strupper(service);
3802
3803   if (*desthost)
3804     {
3805       host = desthost;
3806     }
3807   else
3808     {
3809       strcpy(service2,service);
3810       host = strtok(service2,"\\/");
3811       if (!host) {
3812         DEBUG(0,("Badly formed host name\n"));
3813         return(False);
3814       }
3815       strcpy(desthost,host);
3816     }
3817
3818   DEBUG(3,("Opening sockets\n"));
3819
3820   if (*myname == 0)
3821     {
3822       get_myname(myname,NULL);
3823       strupper(myname);
3824     }
3825
3826   if (!have_ip)
3827     {
3828       struct hostent *hp;
3829
3830       if ((hp = Get_Hostbyname(host))) {
3831         putip((char *)&dest_ip,(char *)hp->h_addr);
3832         failed = False;
3833       } else {
3834 #ifdef USENMB
3835         /* Try and resolve the name with the netbios server */
3836         int             bcast;
3837         pstring         hs;
3838         struct in_addr  ip1, ip2;
3839         
3840         if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
3841           set_socket_options (bcast, "SO_BROADCAST");
3842
3843           if (!got_bcast && get_myname(hs, &ip1)) {
3844             get_broadcast(&ip1, &bcast_ip, &ip2);
3845           }
3846
3847           if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
3848             failed = False;
3849           }
3850           close (bcast);
3851         }
3852 #endif
3853         if (failed) {
3854           DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
3855           return False;
3856         }
3857       }
3858     }
3859
3860   Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
3861   if (Client == -1)
3862     return False;
3863
3864   DEBUG(3,("Connected\n"));
3865   
3866   set_socket_options(Client,user_socket_options);  
3867   
3868   return True;
3869 }
3870
3871 /****************************************************************************
3872 wait for keyboard activity, swallowing network packets
3873 ****************************************************************************/
3874 #ifdef CLIX
3875 static char wait_keyboard(char *buffer)
3876 #else
3877 static void wait_keyboard(char *buffer)
3878 #endif
3879 {
3880   fd_set fds;
3881   int selrtn;
3882   struct timeval timeout;
3883   
3884 #ifdef CLIX
3885   int delay = 0;
3886 #endif
3887   
3888   while (1) 
3889     {
3890       extern int Client;
3891       FD_ZERO(&fds);
3892       FD_SET(Client,&fds);
3893 #ifndef CLIX
3894       FD_SET(fileno(stdin),&fds);
3895 #endif
3896
3897       timeout.tv_sec = 20;
3898       timeout.tv_usec = 0;
3899 #ifdef CLIX
3900       timeout.tv_sec = 0;
3901 #endif
3902       selrtn = sys_select(&fds,&timeout);
3903       
3904 #ifndef CLIX
3905       if (FD_ISSET(fileno(stdin),&fds))
3906         return;
3907 #else
3908       {
3909         char ch;
3910         int f_flags;
3911         int readret;
3912         
3913         f_flags = fcntl(fileno(stdin), F_GETFL, 0);
3914         fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
3915         readret = read_data( fileno(stdin), &ch, 1);
3916         fcntl(fileno(stdin), F_SETFL, f_flags);
3917         if (readret == -1)
3918           {
3919             if (errno != EAGAIN)
3920               {
3921                 /* should crash here */
3922                 DEBUG(1,("readchar stdin failed\n"));
3923               }
3924           }
3925         else if (readret != 0)
3926           {
3927             return ch;
3928           }
3929       }
3930 #endif
3931       if (FD_ISSET(Client,&fds))
3932         receive_smb(Client,buffer,0);
3933       
3934 #ifdef CLIX
3935       delay++;
3936       if (delay > 100000)
3937         {
3938           delay = 0;
3939           chkpath("\\",False);
3940         }
3941 #else
3942       chkpath("\\",False);
3943 #endif
3944     }  
3945 }
3946
3947
3948 /****************************************************************************
3949 close and open the connection again
3950 ****************************************************************************/
3951 BOOL reopen_connection(char *inbuf,char *outbuf)
3952 {
3953   static int open_count=0;
3954
3955   open_count++;
3956
3957   if (open_count>5) return(False);
3958
3959   DEBUG(1,("Trying to re-open connection\n"));
3960
3961   set_message(outbuf,0,0,True);
3962   SCVAL(outbuf,smb_com,SMBtdis);
3963   SSVAL(outbuf,smb_tid,cnum);
3964   setup_pkt(outbuf);
3965
3966   send_smb(Client,outbuf);
3967   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3968
3969   close_sockets();
3970   if (!open_sockets(0)) return(False);
3971
3972   return(send_login(inbuf,outbuf,True,True));
3973 }
3974
3975 /****************************************************************************
3976   process commands from the client
3977 ****************************************************************************/
3978 BOOL process(char *base_directory)
3979 {
3980   extern FILE *dbf;
3981   pstring line;
3982
3983   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3984   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3985
3986   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3987     return(False);
3988   
3989   bzero(OutBuffer,smb_size);
3990
3991   if (!send_login(InBuffer,OutBuffer,True,True))
3992     return(False);
3993
3994   if (*base_directory) do_cd(base_directory);
3995
3996   while (!feof(stdin))
3997     {
3998       fstring tok;
3999       int i;
4000
4001       bzero(OutBuffer,smb_size);
4002
4003       /* display a prompt */
4004       DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
4005       fflush(dbf);
4006
4007 #ifdef CLIX
4008       line[0] = wait_keyboard(InBuffer);
4009       /* this might not be such a good idea... */
4010       if ( line[0] == EOF)
4011         break;
4012 #else
4013       wait_keyboard(InBuffer);
4014 #endif
4015   
4016       /* and get a response */
4017 #ifdef CLIX
4018       fgets( &line[1],999, stdin);
4019 #else
4020       if (!fgets(line,1000,stdin))
4021         break;
4022 #endif
4023
4024       /* input language code to internal one */
4025       CNV_INPUT (line);
4026
4027       /* special case - first char is ! */
4028       if (*line == '!')
4029         {
4030           system(line + 1);
4031           continue;
4032         }
4033       
4034       /* and get the first part of the command */
4035       {
4036         char *ptr = line;
4037         if (!next_token(&ptr,tok,NULL)) continue;
4038       }
4039
4040       if ((i = process_tok(tok)) >= 0)
4041         commands[i].fn(InBuffer,OutBuffer);
4042       else if (i == -2)
4043         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4044       else
4045         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4046     }
4047   
4048   send_logout();
4049   return(True);
4050 }
4051
4052
4053 /****************************************************************************
4054 usage on the program
4055 ****************************************************************************/
4056 void usage(char *pname)
4057 {
4058   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
4059            pname));
4060
4061 #ifdef KANJI
4062   DEBUG(0,("[-t termcode] "));
4063 #endif /* KANJI */
4064
4065   DEBUG(0,("\nVersion %s\n",VERSION));
4066   DEBUG(0,("\t-p port               listen on the specified port\n"));
4067   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
4068   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
4069   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
4070   DEBUG(0,("\t-N                    don't ask for a password\n"));
4071   DEBUG(0,("\t-P                    connect to service as a printer\n"));
4072   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
4073   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
4074   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
4075   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
4076   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
4077   DEBUG(0,("\t-U username           set the network username\n"));
4078   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
4079 #ifdef KANJI
4080   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
4081 #endif /* KANJI */
4082   DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
4083   DEBUG(0,("\t-D directory          start from directory\n"));
4084   DEBUG(0,("\n"));
4085 }
4086
4087
4088
4089 /****************************************************************************
4090   main program
4091 ****************************************************************************/
4092 int main(int argc,char *argv[])
4093 {
4094   fstring base_directory;
4095   char *pname = argv[0];
4096   int port = 139;
4097   int opt;
4098   extern FILE *dbf;
4099   extern char *optarg;
4100   extern int optind;
4101   pstring query_host;
4102   BOOL message = False;
4103   extern char tar_type;
4104
4105   *query_host = 0;
4106   *base_directory = 0;
4107
4108   DEBUGLEVEL = 2;
4109
4110   setup_logging(pname,True);
4111
4112   TimeInit();
4113   charset_initialise();
4114
4115   pid = getpid();
4116   uid = getuid();
4117   gid = getgid();
4118   mid = pid + 100;
4119   myumask = umask(0);
4120   umask(myumask);
4121
4122   if (getenv("USER"))
4123     {
4124       strcpy(username,getenv("USER"));
4125       strupper(username);
4126     }
4127
4128   if (*username == 0 && getenv("LOGNAME"))
4129     {
4130       strcpy(username,getenv("LOGNAME"));
4131       strupper(username);
4132     }
4133
4134   if (argc < 2)
4135     {
4136       usage(pname);
4137       exit(1);
4138     }
4139   
4140   if (*argv[1] != '-')
4141     {
4142
4143       strcpy(service,argv[1]);  
4144       argc--;
4145       argv++;
4146
4147       if (count_chars(service,'\\') < 3)
4148         {
4149           usage(pname);
4150           printf("\n%s: Not enough '\\' characters in service\n",service);
4151           exit(1);
4152         }
4153
4154 /*
4155       if (count_chars(service,'\\') > 3)
4156         {
4157           usage(pname);
4158           printf("\n%s: Too many '\\' characters in service\n",service);
4159           exit(1);
4160         }
4161         */
4162
4163       if (argc > 1 && (*argv[1] != '-'))
4164         {
4165           got_pass = True;
4166           strcpy(password,argv[1]);  
4167           memset(argv[1],'X',strlen(argv[1]));
4168           argc--;
4169           argv++;
4170         }
4171     }
4172
4173 #ifdef KANJI
4174   setup_term_code (KANJI);
4175   while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:")) != EOF)
4176 #else
4177   while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:m:W:T:D:")) != EOF)
4178 #endif /* KANJI */
4179     switch (opt)
4180       {
4181       case 'm':
4182         max_protocol = interpret_protocol(optarg,max_protocol);
4183         break;
4184       case 'O':
4185         strcpy(user_socket_options,optarg);
4186         break;  
4187       case 'M':
4188         name_type = 3;
4189         strcpy(desthost,optarg);
4190         strupper(desthost);
4191         message = True;
4192         break;
4193       case 'B':
4194         bcast_ip = *interpret_addr2(optarg);
4195         got_bcast = True;
4196         break;
4197       case 'D':
4198         strcpy(base_directory,optarg);
4199         break;
4200       case 'T':
4201         if (!tar_parseargs(argc, argv, optarg, optind)) {
4202           usage(pname);
4203           exit(1);
4204         }
4205         break;
4206       case 'i':
4207         strcpy(scope,optarg);
4208         break;
4209       case 'L':
4210         got_pass = True;
4211         strcpy(query_host,optarg);
4212         break;
4213       case 'U':
4214         {
4215           char *p;
4216         strcpy(username,optarg);
4217         if ((p=strchr(username,'%')))
4218           {
4219             *p = 0;
4220             strcpy(password,p+1);
4221             got_pass = True;
4222             memset(strchr(optarg,'%')+1,'X',strlen(password));
4223           }
4224         }
4225             
4226         break;
4227       case 'W':
4228         strcpy(workgroup,optarg);
4229         break;
4230       case 'E':
4231         dbf = stderr;
4232         break;
4233       case 'I':
4234         {
4235           dest_ip = *interpret_addr2(optarg);
4236           if (zero_ip(dest_ip)) exit(1);
4237           have_ip = True;
4238         }
4239         break;
4240       case 'n':
4241         strcpy(myname,optarg);
4242         break;
4243       case 'N':
4244         got_pass = True;
4245         break;
4246       case 'P':
4247         connect_as_printer = True;
4248         break;
4249       case 'd':
4250         if (*optarg == 'A')
4251           DEBUGLEVEL = 10000;
4252         else
4253           DEBUGLEVEL = atoi(optarg);
4254         break;
4255       case 'l':
4256         sprintf(debugf,"%s.client",optarg);
4257         break;
4258       case 'p':
4259         port = atoi(optarg);
4260         break;
4261       case 'h':
4262         usage(pname);
4263         exit(0);
4264         break;
4265 #ifdef KANJI
4266       case 't':
4267         if (!setup_term_code (optarg)) {
4268             DEBUG(0, ("%s: unknown terminal code name\n", optarg));
4269             usage (pname);
4270             exit (1);
4271         }
4272         break;
4273 #endif /* KANJI */
4274       default:
4275         usage(pname);
4276         exit(1);
4277       }
4278
4279   if (!tar_type && !*query_host && !*service && !message)
4280     {
4281       usage(pname);
4282       exit(1);
4283     }
4284
4285
4286   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
4287
4288   get_myname(*myname?NULL:myname,&myip);  
4289   strupper(myname);
4290
4291   if (tar_type) {
4292     recurse=True;
4293
4294     if (open_sockets(port)) {
4295         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4296         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4297         int ret;
4298
4299         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4300           return(1);
4301
4302         bzero(OutBuffer,smb_size);
4303         if (!send_login(InBuffer,OutBuffer,True,True))
4304           return(False);
4305
4306         if (*base_directory) do_cd(base_directory);
4307
4308         ret=process_tar(InBuffer, OutBuffer);
4309
4310         send_logout();
4311         close_sockets();
4312         return(ret);
4313     } else
4314       return(1);
4315   }
4316   
4317   if (*query_host)
4318     {
4319       int ret = 0;
4320       sprintf(service,"\\\\%s\\IPC$",query_host);
4321       strupper(service);
4322       connect_as_ipc = True;
4323       if (open_sockets(port))
4324         {
4325 #if 0
4326           *username = 0;
4327 #endif
4328           if (!send_login(NULL,NULL,True,True))
4329             return(1);
4330
4331           server_info();
4332           if (!browse_host(True)) {
4333             sleep(1);
4334             browse_host(True);
4335           }
4336           if (!list_servers()) {
4337             sleep(1);
4338             list_servers();
4339           }
4340
4341           send_logout();
4342           close_sockets();
4343         }
4344
4345       return(ret);
4346     }
4347
4348   if (message)
4349     {
4350       int ret = 0;
4351       if (open_sockets(port))
4352         {
4353           pstring inbuf,outbuf;
4354           bzero(outbuf,smb_size);
4355           if (!send_session_request(inbuf,outbuf))
4356             return(1);
4357
4358           send_message(inbuf,outbuf);
4359
4360           close_sockets();
4361         }
4362
4363       return(ret);
4364     }
4365
4366   if (open_sockets(port))
4367     {
4368       if (!process(base_directory))
4369         {
4370           close_sockets();
4371           return(1);
4372         }
4373       close_sockets();
4374     }
4375   else
4376     return(1);
4377
4378   return(0);
4379 }
4380
4381
4382 /* error code stuff - put together by Merik Karman
4383    merik@blackadder.dsh.oz.au */
4384
4385 typedef struct
4386 {
4387   char *name;
4388   int code;
4389   char *message;
4390 } err_code_struct;
4391
4392 /* Dos Error Messages */
4393 err_code_struct dos_msgs[] = {
4394   {"ERRbadfunc",1,"Invalid function."},
4395   {"ERRbadfile",2,"File not found."},
4396   {"ERRbadpath",3,"Directory invalid."},
4397   {"ERRnofids",4,"No file descriptors available"},
4398   {"ERRnoaccess",5,"Access denied."},
4399   {"ERRbadfid",6,"Invalid file handle."},
4400   {"ERRbadmcb",7,"Memory control blocks destroyed."},
4401   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
4402   {"ERRbadmem",9,"Invalid memory block address."},
4403   {"ERRbadenv",10,"Invalid environment."},
4404   {"ERRbadformat",11,"Invalid format."},
4405   {"ERRbadaccess",12,"Invalid open mode."},
4406   {"ERRbaddata",13,"Invalid data."},
4407   {"ERR",14,"reserved."},
4408   {"ERRbaddrive",15,"Invalid drive specified."},
4409   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
4410   {"ERRdiffdevice",17,"Not same device."},
4411   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
4412   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
4413   {"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."},
4414   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
4415   {"ERRbadpipe",230,"Pipe invalid."},
4416   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
4417   {"ERRpipeclosing",232,"Pipe close in progress."},
4418   {"ERRnotconnected",233,"No process on other end of pipe."},
4419   {"ERRmoredata",234,"There is more data to be returned."},
4420   {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
4421   {NULL,-1,NULL}};
4422
4423 /* Server Error Messages */
4424 err_code_struct server_msgs[] = {
4425   {"ERRerror",1,"Non-specific error code."},
4426   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
4427   {"ERRbadtype",3,"reserved."},
4428   {"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."},
4429   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
4430   {"ERRinvnetname",6,"Invalid network name in tree connect."},
4431   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
4432   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
4433   {"ERRqtoobig",50,"Print queue full -- no space."},
4434   {"ERRqeof",51,"EOF on print queue dump."},
4435   {"ERRinvpfid",52,"Invalid print file FID."},
4436   {"ERRsmbcmd",64,"The server did not recognize the command received."},
4437   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
4438   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
4439   {"ERRreserved",68,"reserved."},
4440   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
4441   {"ERRreserved",70,"reserved."},
4442   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
4443   {"ERRpaused",81,"Server is paused."},
4444   {"ERRmsgoff",82,"Not receiving messages."},
4445   {"ERRnoroom",83,"No room to buffer message."},
4446   {"ERRrmuns",87,"Too many remote user names."},
4447   {"ERRtimeout",88,"Operation timed out."},
4448   {"ERRnoresource",89,"No resources currently available for request."},
4449   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
4450   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
4451   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
4452   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
4453   {"ERRcontmpx",252,"Continue in MPX mode."},
4454   {"ERRreserved",253,"reserved."},
4455   {"ERRreserved",254,"reserved."},
4456   {"ERRnosupport",0xFFFF,"Function not supported."},
4457   {NULL,-1,NULL}};
4458
4459 /* Hard Error Messages */
4460 err_code_struct hard_msgs[] = {
4461   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
4462   {"ERRbadunit",20,"Unknown unit."},
4463   {"ERRnotready",21,"Drive not ready."},
4464   {"ERRbadcmd",22,"Unknown command."},
4465   {"ERRdata",23,"Data error (CRC)."},
4466   {"ERRbadreq",24,"Bad request structure length."},
4467   {"ERRseek",25 ,"Seek error."},
4468   {"ERRbadmedia",26,"Unknown media type."},
4469   {"ERRbadsector",27,"Sector not found."},
4470   {"ERRnopaper",28,"Printer out of paper."},
4471   {"ERRwrite",29,"Write fault."},
4472   {"ERRread",30,"Read fault."},
4473   {"ERRgeneral",31,"General failure."},
4474   {"ERRbadshare",32,"A open conflicts with an existing open."},
4475   {"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."},
4476   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
4477   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
4478   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
4479   {NULL,-1,NULL}};
4480
4481
4482 struct
4483 {
4484   int code;
4485   char *class;
4486   err_code_struct *err_msgs;
4487 } err_classes[] = { 
4488   {0,"SUCCESS",NULL},
4489   {0x01,"ERRDOS",dos_msgs},
4490   {0x02,"ERRSRV",server_msgs},
4491   {0x03,"ERRHRD",hard_msgs},
4492   {0x04,"ERRXOS",NULL},
4493   {0xE1,"ERRRMX1",NULL},
4494   {0xE2,"ERRRMX2",NULL},
4495   {0xE3,"ERRRMX3",NULL},
4496   {0xFF,"ERRCMD",NULL},
4497   {-1,NULL,NULL}};
4498
4499
4500 /****************************************************************************
4501 return a SMB error string from a SMB buffer
4502 ****************************************************************************/
4503 char *smb_errstr(char *inbuf)
4504 {
4505   static pstring ret;
4506   int class = CVAL(inbuf,smb_rcls);
4507   int num = SVAL(inbuf,smb_err);
4508   int i,j;
4509
4510   for (i=0;err_classes[i].class;i++)
4511     if (err_classes[i].code == class)
4512       {
4513         if (err_classes[i].err_msgs)
4514           {
4515             err_code_struct *err = err_classes[i].err_msgs;
4516             for (j=0;err[j].name;j++)
4517               if (num == err[j].code)
4518                 {
4519                   if (DEBUGLEVEL > 0)
4520                     sprintf(ret,"%s - %s (%s)",err_classes[i].class,
4521                             err[j].name,err[j].message);
4522                   else
4523                     sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
4524                   return ret;
4525                 }
4526           }
4527
4528         sprintf(ret,"%s - %d",err_classes[i].class,num);
4529         return ret;
4530       }
4531   
4532   sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
4533   return(ret);
4534 }