- handle CORE protocol better
[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 (!chkpath(rname,False) && !do_mkdir(rname)) {
2135                 strcat(lname,"/");
2136                 if (!seek_list(f,lname))
2137                   break;
2138                 goto again1;                              
2139               }
2140
2141               continue;
2142             }
2143           else
2144             {
2145               sprintf(quest,"Put file %s? ",lname);
2146               if (prompt && !yesno(quest)) continue;
2147
2148               strcpy(rname,cur_dir);
2149               strcat(rname,lname);
2150             }
2151           dos_format(rname);
2152
2153           /* null size so do_put knows to ignore it */
2154           finfo.size = -1;
2155
2156           /* set the date on the file */
2157           finfo.mtime = st.st_mtime;
2158
2159           do_put(rname,lname,&finfo);
2160         }
2161       fclose(f);
2162       unlink(tmpname);
2163     }
2164 }
2165
2166 /****************************************************************************
2167   cancel a print job
2168   ****************************************************************************/
2169 static void do_cancel(int job)
2170 {
2171   char *rparam = NULL;
2172   char *rdata = NULL;
2173   char *p;
2174   int rdrcnt,rprcnt;
2175   pstring param;
2176
2177   bzero(param,sizeof(param));
2178
2179   p = param;
2180   SSVAL(p,0,81);                /* api number */
2181   p += 2;
2182   strcpy(p,"W");
2183   p = skip_string(p,1);
2184   strcpy(p,"");
2185   p = skip_string(p,1);
2186   SSVAL(p,0,job);     
2187   p += 2;
2188
2189   if (call_api(PTR_DIFF(p,param),0,
2190                6,1000,
2191                &rprcnt,&rdrcnt,
2192                param,NULL,
2193                &rparam,&rdata))
2194     {
2195       int res = SVAL(rparam,0);
2196
2197       if (!res)
2198         printf("Job %d cancelled\n",job);
2199       else
2200         printf("Error %d calcelling job %d\n",res,job);
2201       return;
2202     }
2203   else
2204   printf("Server refused cancel request\n");
2205
2206   if (rparam) free(rparam);
2207   if (rdata) free(rdata);
2208
2209   return;
2210 }
2211
2212
2213 /****************************************************************************
2214   cancel a print job
2215   ****************************************************************************/
2216 static void cmd_cancel(char *inbuf,char *outbuf )
2217 {
2218   fstring buf;
2219   int job; 
2220
2221   if (!connect_as_printer)
2222     {
2223       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2224       DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
2225     }
2226
2227   if (!next_token(NULL,buf,NULL)) {
2228     printf("cancel <jobid> ...\n");
2229     return;
2230   }
2231   do {
2232     job = atoi(buf);
2233     do_cancel(job);
2234   } while (next_token(NULL,buf,NULL));
2235 }
2236
2237
2238 /****************************************************************************
2239   get info on a file
2240   ****************************************************************************/
2241 static void cmd_stat(char *inbuf,char *outbuf)
2242 {
2243   fstring buf;
2244   pstring param;
2245   char *resp_data=NULL;
2246   char *resp_param=NULL;
2247   int resp_data_len = 0;
2248   int resp_param_len=0;
2249   char *p;
2250   uint16 setup = TRANSACT2_QPATHINFO;
2251
2252   if (!next_token(NULL,buf,NULL)) {
2253     printf("stat <file>\n");
2254     return;
2255   }
2256
2257   bzero(param,6);
2258   SSVAL(param,0,4); /* level */
2259   p = param+6;
2260   strcpy(p,cur_dir);
2261   strcat(p,buf);
2262
2263   send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
2264                      NULL,param,&setup,
2265                      0,6 + strlen(p)+1,1,
2266                      BUFFER_SIZE,2,0);
2267
2268   receive_trans_response(inbuf,SMBtrans2,
2269                           &resp_data_len,&resp_param_len,
2270                           &resp_data,&resp_param);
2271
2272   if (resp_data) free(resp_data); resp_data = NULL;
2273   if (resp_param) free(resp_param); resp_param = NULL;
2274 }
2275
2276
2277 /****************************************************************************
2278   print a file
2279   ****************************************************************************/
2280 static void cmd_print(char *inbuf,char *outbuf )
2281 {
2282   int fnum;
2283   FILE *f = NULL;
2284   uint32 nread=0;
2285   pstring lname;
2286   pstring rname;
2287   char *p;
2288
2289   if (!connect_as_printer)
2290     {
2291       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2292       DEBUG(0,("Trying to print without -P may fail\n"));
2293     }
2294
2295   if (!next_token(NULL,lname,NULL))
2296     {
2297       DEBUG(0,("print <filename>\n"));
2298       return;
2299     }
2300
2301   strcpy(rname,lname);
2302   p = strrchr(rname,'/');
2303   if (p)
2304     {
2305       pstring tname;
2306       strcpy(tname,p+1);
2307       strcpy(rname,tname);
2308     }
2309
2310   if ((int)strlen(rname) > 14)
2311     rname[14] = 0;
2312
2313   if (strequal(lname,"-"))
2314     {
2315       f = stdin;
2316       strcpy(rname,"stdin");
2317     }
2318   
2319   dos_clean_name(rname);
2320
2321   bzero(outbuf,smb_size);
2322   set_message(outbuf,2,2 + strlen(rname),True);
2323   
2324   CVAL(outbuf,smb_com) = SMBsplopen;
2325   SSVAL(outbuf,smb_tid,cnum);
2326   setup_pkt(outbuf);
2327
2328   SSVAL(outbuf,smb_vwv0,0);
2329   SSVAL(outbuf,smb_vwv1,printmode);
2330   
2331   p = smb_buf(outbuf);
2332   *p++ = 4;      
2333   strcpy(p,rname);
2334   
2335   send_smb(Client,outbuf);
2336   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2337   
2338   if (CVAL(inbuf,smb_rcls) != 0)
2339     {
2340       DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
2341       return;
2342     }
2343   
2344   if (!f)
2345     f = fopen(lname,"r");
2346   if (!f)
2347     {
2348       DEBUG(0,("Error opening local file %s\n",lname));
2349       return;
2350     }
2351
2352   
2353   fnum = SVAL(inbuf,smb_vwv0);
2354   
2355   DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname)));
2356   
2357   while (!feof(f))
2358     {
2359       int n;
2360   
2361       bzero(outbuf,smb_size);
2362       set_message(outbuf,1,3,True);
2363
2364       /* for some strange reason the OS/2 print server can't handle large
2365          packets when printing. weird */
2366       n = MIN(1024,max_xmit-(smb_len(outbuf)+4));
2367
2368       if (translation)
2369         n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n));
2370       else
2371         n = readfile(smb_buf(outbuf)+3,1,n,f);
2372       if (n <= 0) 
2373         {
2374           DEBUG(0,("read gave %d\n",n));
2375           break;
2376         }
2377
2378       smb_setlen(outbuf,smb_len(outbuf) + n);
2379
2380       CVAL(outbuf,smb_com) = SMBsplwr;
2381       SSVAL(outbuf,smb_tid,cnum);
2382       setup_pkt(outbuf);
2383
2384       SSVAL(outbuf,smb_vwv0,fnum);
2385       SSVAL(outbuf,smb_vwv1,n+3);
2386       CVAL(smb_buf(outbuf),0) = 1;
2387       SSVAL(smb_buf(outbuf),1,n);
2388
2389       send_smb(Client,outbuf);
2390       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2391
2392       if (CVAL(inbuf,smb_rcls) != 0)
2393         {
2394           DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf)));
2395           break;
2396         }
2397
2398       nread += n;
2399     }
2400
2401   DEBUG(2,("%d bytes printed\n",nread));
2402
2403   bzero(outbuf,smb_size);
2404   set_message(outbuf,1,0,True);
2405   CVAL(outbuf,smb_com) = SMBsplclose;
2406   SSVAL(outbuf,smb_tid,cnum);
2407   setup_pkt(outbuf);
2408
2409   SSVAL(outbuf,smb_vwv0,fnum);
2410
2411   send_smb(Client,outbuf);
2412   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2413   
2414   if (CVAL(inbuf,smb_rcls) != 0)
2415     {
2416       DEBUG(0,("%s closing print file\n",smb_errstr(inbuf)));
2417       if (f != stdin)
2418         fclose(f);
2419       return;
2420     }
2421
2422   if (f != stdin)
2423     fclose(f);
2424 }
2425
2426 /****************************************************************************
2427 print a file
2428 ****************************************************************************/
2429 static void cmd_queue(char *inbuf,char *outbuf )
2430 {
2431   int count;
2432   char *p;
2433
2434   bzero(outbuf,smb_size);
2435   set_message(outbuf,2,0,True);
2436   
2437   CVAL(outbuf,smb_com) = SMBsplretq;
2438   SSVAL(outbuf,smb_tid,cnum);
2439   setup_pkt(outbuf);
2440
2441   SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
2442   SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
2443   
2444   send_smb(Client,outbuf);
2445   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2446   
2447   if (CVAL(inbuf,smb_rcls) != 0)
2448     {
2449       DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf)));
2450       return;
2451     }
2452
2453   count = SVAL(inbuf,smb_vwv0);
2454   p = smb_buf(inbuf) + 3;
2455   if (count <= 0)
2456     {
2457       DEBUG(0,("No entries in the print queue\n"));
2458       return;
2459     }  
2460
2461   {
2462     char status[20];
2463
2464     DEBUG(0,("Job      Name              Size         Status\n"));
2465
2466     while (count--)
2467       {
2468         switch (CVAL(p,4))
2469           {
2470           case 0x01: sprintf(status,"held or stopped"); break;
2471           case 0x02: sprintf(status,"printing"); break;
2472           case 0x03: sprintf(status,"awaiting print"); break;
2473           case 0x04: sprintf(status,"in intercept"); break;
2474           case 0x05: sprintf(status,"file had error"); break;
2475           case 0x06: sprintf(status,"printer error"); break;
2476           default: sprintf(status,"unknown"); break;
2477           }
2478
2479         DEBUG(0,("%-6d   %-16.16s  %-9d    %s\n",
2480                  SVAL(p,5),p+12,IVAL(p,7),status));
2481         p += 28;
2482       }
2483   }
2484   
2485 }
2486
2487
2488 /****************************************************************************
2489 delete some files
2490 ****************************************************************************/
2491 static void do_del(file_info *finfo)
2492 {
2493   char *p;
2494   char *inbuf,*outbuf;
2495   pstring mask;
2496
2497   strcpy(mask,cur_dir);
2498   strcat(mask,finfo->name);
2499
2500   if (finfo->mode & aDIR) 
2501     return;
2502
2503   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2504   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2505   
2506   if (!inbuf || !outbuf)
2507     {
2508       DEBUG(0,("out of memory\n"));
2509       return;
2510     }
2511
2512   bzero(outbuf,smb_size);
2513   set_message(outbuf,1,2 + strlen(mask),True);
2514   
2515   CVAL(outbuf,smb_com) = SMBunlink;
2516   SSVAL(outbuf,smb_tid,cnum);
2517   setup_pkt(outbuf);
2518
2519   SSVAL(outbuf,smb_vwv0,0);
2520   
2521   p = smb_buf(outbuf);
2522   *p++ = 4;      
2523   strcpy(p,mask);
2524   
2525   send_smb(Client,outbuf);
2526   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2527   
2528   if (CVAL(inbuf,smb_rcls) != 0)
2529     DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2530
2531   free(inbuf);free(outbuf);
2532   
2533 }
2534
2535 /****************************************************************************
2536 delete some files
2537 ****************************************************************************/
2538 static void cmd_del(char *inbuf,char *outbuf )
2539 {
2540   pstring mask;
2541   fstring buf;
2542   int attribute = aSYSTEM | aHIDDEN;
2543
2544   if (recurse)
2545     attribute |= aDIR;
2546   
2547   strcpy(mask,cur_dir);
2548     
2549   if (!next_token(NULL,buf,NULL))
2550     {
2551       DEBUG(0,("del <filename>\n"));
2552       return;
2553     }
2554   strcat(mask,buf);
2555
2556   do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False);
2557 }
2558
2559
2560 /****************************************************************************
2561 remove a directory
2562 ****************************************************************************/
2563 static void cmd_rmdir(char *inbuf,char *outbuf )
2564 {
2565   pstring mask;
2566   fstring buf;
2567   char *p;
2568   
2569   strcpy(mask,cur_dir);
2570   
2571   if (!next_token(NULL,buf,NULL))
2572     {
2573       DEBUG(0,("rmdir <dirname>\n"));
2574       return;
2575     }
2576   strcat(mask,buf);
2577
2578   bzero(outbuf,smb_size);
2579   set_message(outbuf,0,2 + strlen(mask),True);
2580   
2581   CVAL(outbuf,smb_com) = SMBrmdir;
2582   SSVAL(outbuf,smb_tid,cnum);
2583   setup_pkt(outbuf);
2584
2585   
2586   p = smb_buf(outbuf);
2587   *p++ = 4;      
2588   strcpy(p,mask);
2589   
2590   send_smb(Client,outbuf);
2591   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2592   
2593   if (CVAL(inbuf,smb_rcls) != 0)
2594     {
2595       DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2596       return;
2597     }
2598   
2599 }
2600
2601 /****************************************************************************
2602 rename some files
2603 ****************************************************************************/
2604 static void cmd_rename(char *inbuf,char *outbuf )
2605 {
2606   pstring src,dest;
2607   fstring buf,buf2;
2608   char *p;
2609   
2610   strcpy(src,cur_dir);
2611   strcpy(dest,cur_dir);
2612   
2613   if (!next_token(NULL,buf,NULL) || !next_token(NULL,buf2,NULL))
2614     {
2615       DEBUG(0,("rename <src> <dest>\n"));
2616       return;
2617     }
2618   strcat(src,buf);
2619   strcat(dest,buf2);
2620
2621   bzero(outbuf,smb_size);
2622   set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
2623   
2624   CVAL(outbuf,smb_com) = SMBmv;
2625   SSVAL(outbuf,smb_tid,cnum);
2626   SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
2627   setup_pkt(outbuf);
2628   
2629   p = smb_buf(outbuf);
2630   *p++ = 4;      
2631   strcpy(p,src);
2632   p = skip_string(p,1);
2633   *p++ = 4;      
2634   strcpy(p,dest);
2635   
2636   send_smb(Client,outbuf);
2637   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2638   
2639   if (CVAL(inbuf,smb_rcls) != 0)
2640     {
2641       DEBUG(0,("%s renaming files\n",smb_errstr(inbuf)));
2642       return;
2643     }
2644   
2645 }
2646
2647
2648 /****************************************************************************
2649 toggle the prompt flag
2650 ****************************************************************************/
2651 static void cmd_prompt(void)
2652 {
2653   prompt = !prompt;
2654   DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2655 }
2656
2657
2658 /****************************************************************************
2659 set the newer than time
2660 ****************************************************************************/
2661 static void cmd_newer(void)
2662 {
2663   fstring buf;
2664   BOOL ok;
2665   struct stat sbuf;
2666
2667   ok = next_token(NULL,buf,NULL);
2668   if (ok && (sys_stat(buf,&sbuf) == 0))
2669     {
2670       newer_than = sbuf.st_mtime;
2671       DEBUG(1,("Getting files newer than %s",
2672                asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
2673     }
2674   else
2675     newer_than = 0;
2676
2677   if (ok && newer_than == 0)
2678     DEBUG(0,("Error setting newer-than time\n"));
2679 }
2680
2681 /****************************************************************************
2682 set the archive level
2683 ****************************************************************************/
2684 static void cmd_archive(void)
2685 {
2686   fstring buf;
2687
2688   if (next_token(NULL,buf,NULL)) {
2689     archive_level = atoi(buf);
2690   } else
2691     DEBUG(0,("Archive level is %d\n",archive_level));
2692 }
2693
2694 /****************************************************************************
2695 toggle the lowercaseflag
2696 ****************************************************************************/
2697 static void cmd_lowercase(void)
2698 {
2699   lowercase = !lowercase;
2700   DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2701 }
2702
2703
2704
2705
2706 /****************************************************************************
2707 toggle the recurse flag
2708 ****************************************************************************/
2709 static void cmd_recurse(void)
2710 {
2711   recurse = !recurse;
2712   DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2713 }
2714
2715 /****************************************************************************
2716 toggle the translate flag
2717 ****************************************************************************/
2718 static void cmd_translate(void)
2719 {
2720   translation = !translation;
2721   DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2722         translation?"on":"off"));
2723 }
2724
2725
2726 /****************************************************************************
2727 do a printmode command
2728 ****************************************************************************/
2729 static void cmd_printmode(void)
2730 {
2731   fstring buf;
2732   fstring mode;
2733
2734   if (next_token(NULL,buf,NULL))
2735     {
2736       if (strequal(buf,"text"))
2737         printmode = 0;      
2738       else
2739         {
2740           if (strequal(buf,"graphics"))
2741             printmode = 1;
2742           else
2743             printmode = atoi(buf);
2744         }
2745     }
2746
2747   switch(printmode)
2748     {
2749     case 0: 
2750       strcpy(mode,"text");
2751       break;
2752     case 1: 
2753       strcpy(mode,"graphics");
2754       break;
2755     default: 
2756       sprintf(mode,"%d",printmode);
2757       break;
2758     }
2759
2760   DEBUG(2,("the printmode is now %s\n",mode));
2761 }
2762
2763 /****************************************************************************
2764 do the lcd command
2765 ****************************************************************************/
2766 static void cmd_lcd(void)
2767 {
2768   fstring buf;
2769   pstring d;
2770
2771   if (next_token(NULL,buf,NULL))
2772     sys_chdir(buf);
2773   DEBUG(2,("the local directory is now %s\n",GetWd(d)));
2774 }
2775
2776
2777 /****************************************************************************
2778 send a session request
2779 ****************************************************************************/
2780 static BOOL send_session_request(char *inbuf,char *outbuf)
2781 {
2782   fstring dest;
2783   char *p;
2784   int len = 4;
2785   /* send a session request (RFC 8002) */
2786
2787   strcpy(dest,desthost);
2788   p = strchr(dest,'.');
2789   if (p) *p = 0;
2790
2791   /* put in the destination name */
2792   p = outbuf+len;
2793   name_mangle(dest,p,name_type);
2794   len += name_len(p);
2795
2796   /* and my name */
2797   p = outbuf+len;
2798   name_mangle(myname,p,0);
2799   len += name_len(p);
2800
2801   /* setup the packet length */
2802   _smb_setlen(outbuf,len);
2803   CVAL(outbuf,0) = 0x81;
2804
2805   send_smb(Client,outbuf);
2806   DEBUG(5,("Sent session request\n"));
2807
2808   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2809
2810   if (CVAL(inbuf,0) == 0x84) /* C. Hoch  9/14/95 Start */
2811     {
2812       /* For information, here is the response structure.
2813        * We do the byte-twiddling to for portability.
2814        struct RetargetResponse{
2815        unsigned char type;
2816        unsigned char flags;
2817        int16 length;
2818        int32 ip_addr;
2819        int16 port;
2820        };
2821        */
2822       extern int Client;
2823       int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
2824       /* SESSION RETARGET */
2825       putip((char *)&dest_ip,inbuf+4);
2826
2827       close_sockets();
2828       Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
2829       if (Client == -1)
2830         return False;
2831
2832       DEBUG(3,("Retargeted\n"));
2833
2834       set_socket_options(Client,user_socket_options);
2835
2836       /* Try again */
2837       return send_session_request(inbuf,outbuf);
2838     } /* C. Hoch 9/14/95 End */
2839
2840
2841   if (CVAL(inbuf,0) != 0x82)
2842     {
2843       int ecode = CVAL(inbuf,4);
2844       DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n",
2845                CVAL(inbuf,0),ecode,myname,desthost));
2846       switch (ecode)
2847         {
2848         case 0x80: 
2849           DEBUG(0,("Not listening on called name\n")); 
2850           DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
2851           DEBUG(0,("You may find the -I option useful for this\n"));
2852           break;
2853         case 0x81: 
2854           DEBUG(0,("Not listening for calling name\n")); 
2855           DEBUG(0,("Try to connect as another name (instead of %s)\n",myname));
2856           DEBUG(0,("You may find the -n option useful for this\n"));
2857           break;
2858         case 0x82: 
2859           DEBUG(0,("Called name not present\n")); 
2860           DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
2861           DEBUG(0,("You may find the -I option useful for this\n"));
2862           break;
2863         case 0x83: 
2864           DEBUG(0,("Called name present, but insufficient resources\n")); 
2865           DEBUG(0,("Perhaps you should try again later?\n")); 
2866           break;
2867         default:
2868           DEBUG(0,("Unspecified error 0x%X\n",ecode)); 
2869           DEBUG(0,("Your server software is being unfriendly\n"));
2870           break;          
2871         }
2872       return(False);
2873     }
2874   return(True);
2875 }
2876
2877
2878 /****************************************************************************
2879 send a login command
2880 ****************************************************************************/
2881 static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup)
2882 {
2883   BOOL was_null = (!inbuf && !outbuf);
2884   int sesskey=0;
2885   time_t servertime = 0;
2886   extern int serverzone;
2887   int sec_mode=0;
2888   int crypt_len;
2889   int max_vcs=0;
2890   struct {
2891     int prot;
2892     char *name;
2893   }
2894   prots[] = 
2895     {
2896       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
2897       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
2898       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
2899       {PROTOCOL_LANMAN1,"LANMAN1.0"},
2900       {PROTOCOL_LANMAN2,"LM1.2X002"},
2901       {PROTOCOL_LANMAN2,"Samba"},
2902       {PROTOCOL_NT1,"NT LM 0.12"},
2903       {PROTOCOL_NT1,"NT LANMAN 1.0"},
2904       {-1,NULL}
2905     };
2906   char *pass = NULL;  
2907   pstring dev;
2908   char *p;
2909   int numprots;
2910
2911   if (was_null)
2912     {
2913       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2914       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2915     }
2916
2917 #if AJT
2918   if (strstr(service,"IPC$")) connect_as_ipc = True;
2919 #endif
2920
2921   strcpy(dev,"A:");
2922   if (connect_as_printer)
2923     strcpy(dev,"LPT1:");
2924   if (connect_as_ipc)
2925     strcpy(dev,"IPC");
2926
2927
2928   if (start_session && !send_session_request(inbuf,outbuf))
2929     {
2930       if (was_null)
2931         {
2932           free(inbuf);
2933           free(outbuf);
2934         }      
2935       return(False);
2936     }
2937
2938   bzero(outbuf,smb_size);
2939
2940   /* setup the protocol strings */
2941   {
2942     int plength;
2943
2944     for (plength=0,numprots=0;
2945          prots[numprots].name && prots[numprots].prot<=max_protocol;
2946          numprots++)
2947       plength += strlen(prots[numprots].name)+2;
2948     
2949     set_message(outbuf,0,plength,True);
2950
2951     p = smb_buf(outbuf);
2952     for (numprots=0;
2953          prots[numprots].name && prots[numprots].prot<=max_protocol;
2954          numprots++)
2955       {
2956         *p++ = 2;
2957         strcpy(p,prots[numprots].name);
2958         p += strlen(p) + 1;
2959       }
2960   }
2961
2962   CVAL(outbuf,smb_com) = SMBnegprot;
2963   setup_pkt(outbuf);
2964
2965   CVAL(smb_buf(outbuf),0) = 2;
2966
2967   send_smb(Client,outbuf);
2968   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2969
2970   show_msg(inbuf);
2971
2972   if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
2973     {
2974       DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
2975             myname,desthost,smb_errstr(inbuf)));
2976       if (was_null)
2977         {
2978           free(inbuf);
2979           free(outbuf);
2980         }
2981       return(False);
2982     }
2983
2984   Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
2985
2986
2987   if (Protocol < PROTOCOL_NT1) {    
2988     sec_mode = SVAL(inbuf,smb_vwv1);
2989     max_xmit = SVAL(inbuf,smb_vwv2);
2990     sesskey = IVAL(inbuf,smb_vwv6);
2991     serverzone = SVALS(inbuf,smb_vwv10)*60;
2992     /* this time is converted to GMT by make_unix_date */
2993     servertime = make_unix_date(inbuf+smb_vwv8);
2994     if (Protocol >= PROTOCOL_COREPLUS) {
2995       readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
2996       writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
2997     }
2998     crypt_len = smb_buflen(inbuf);
2999     memcpy(cryptkey,smb_buf(inbuf),8);
3000     DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
3001     max_vcs = SVAL(inbuf,smb_vwv4); 
3002     DEBUG(3,("max vcs %d\n",max_vcs)); 
3003     DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
3004   } else {
3005     /* NT protocol */
3006     sec_mode = CVAL(inbuf,smb_vwv1);
3007     max_xmit = IVAL(inbuf,smb_vwv3+1);
3008     sesskey = IVAL(inbuf,smb_vwv7+1);
3009     serverzone = SVALS(inbuf,smb_vwv15+1)*60;
3010     /* this time arrives in real GMT */
3011     servertime = interpret_long_date(inbuf+smb_vwv11+1);
3012     crypt_len = CVAL(inbuf,smb_vwv16+1);
3013     memcpy(cryptkey,smb_buf(inbuf),8);
3014     if (IVAL(inbuf,smb_vwv9+1) & 1)
3015       readbraw_supported = writebraw_supported = True;      
3016     DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
3017     max_vcs = SVAL(inbuf,smb_vwv2+1); 
3018     DEBUG(3,("max vcs %d\n",max_vcs));
3019     DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
3020     DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
3021   }
3022
3023   DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
3024   DEBUG(3,("max xmt %d\n",max_xmit));
3025   DEBUG(3,("Got %d byte crypt key\n",crypt_len));
3026   DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
3027
3028   doencrypt = ((sec_mode & 2) != 0);
3029
3030   if (servertime) {
3031     static BOOL done_time = False;
3032     if (!done_time) {
3033       DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
3034                asctime(LocalTime(&servertime,GMT_TO_LOCAL)),
3035                -(double)(serverzone/3600.0)));
3036       done_time = True;
3037     }
3038   }
3039
3040  get_pass:
3041
3042   if (got_pass)
3043     pass = password;
3044   else
3045     pass = (char *)getpass("Password: ");
3046
3047   if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
3048     {
3049       fstring pword;
3050       int passlen = strlen(pass)+1;
3051       strcpy(pword,pass);      
3052
3053 #ifdef SMB_PASSWD
3054       if (doencrypt && *pass) {
3055         DEBUG(3,("Using encrypted passwords\n"));
3056         passlen = 24;
3057         SMBencrypt(pass,cryptkey,pword);
3058       }
3059 #else
3060       doencrypt = False;
3061 #endif
3062
3063       /* if in share level security then don't send a password now */
3064       if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} 
3065
3066       /* send a session setup command */
3067       bzero(outbuf,smb_size);
3068
3069       if (Protocol < PROTOCOL_NT1) {
3070         set_message(outbuf,10,1 + strlen(username) + passlen,True);
3071         CVAL(outbuf,smb_com) = SMBsesssetupX;
3072         setup_pkt(outbuf);
3073
3074         CVAL(outbuf,smb_vwv0) = 0xFF;
3075         SSVAL(outbuf,smb_vwv2,max_xmit);
3076         SSVAL(outbuf,smb_vwv3,2);
3077         SSVAL(outbuf,smb_vwv4,max_vcs-1);
3078         SIVAL(outbuf,smb_vwv5,sesskey);
3079         SSVAL(outbuf,smb_vwv7,passlen);
3080         p = smb_buf(outbuf);
3081         memcpy(p,pword,passlen);
3082         p += passlen;
3083         strcpy(p,username);
3084       } else {
3085         if (!doencrypt) passlen--;
3086         /* for Win95 */
3087         set_message(outbuf,13,0,True);
3088         CVAL(outbuf,smb_com) = SMBsesssetupX;
3089         setup_pkt(outbuf);
3090
3091         CVAL(outbuf,smb_vwv0) = 0xFF;
3092         SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
3093         SSVAL(outbuf,smb_vwv3,2);
3094         SSVAL(outbuf,smb_vwv4,getpid());
3095         SIVAL(outbuf,smb_vwv5,sesskey);
3096         SSVAL(outbuf,smb_vwv7,passlen);
3097         SSVAL(outbuf,smb_vwv8,0);
3098         p = smb_buf(outbuf);
3099         memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
3100         strcpy(p,username);p = skip_string(p,1);
3101         strcpy(p,workgroup);p = skip_string(p,1);
3102         strcpy(p,"Unix");p = skip_string(p,1);
3103         strcpy(p,"Samba");p = skip_string(p,1);
3104         set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
3105       }
3106
3107       send_smb(Client,outbuf);
3108       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3109
3110       show_msg(inbuf);
3111
3112       if (CVAL(inbuf,smb_rcls) != 0)
3113         {
3114           if (! *pass &&
3115               ((CVAL(inbuf,smb_rcls) == ERRDOS && 
3116                 SVAL(inbuf,smb_err) == ERRnoaccess) ||
3117                (CVAL(inbuf,smb_rcls) == ERRSRV && 
3118                 SVAL(inbuf,smb_err) == ERRbadpw)))
3119             {
3120               got_pass = False;
3121               DEBUG(3,("resending login\n"));
3122               goto get_pass;
3123             }
3124               
3125           DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s   %s\n",
3126                 username,myname,desthost,smb_errstr(inbuf)));
3127           DEBUG(0,("You might find the -U, -W or -n options useful\n"));
3128           DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
3129           DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
3130           if (was_null)
3131             {
3132               free(inbuf);
3133               free(outbuf);
3134             }
3135           return(False);
3136         }
3137
3138       if (Protocol >= PROTOCOL_NT1) {
3139         char *domain,*os,*lanman;
3140         p = smb_buf(inbuf);
3141         os = p;
3142         lanman = skip_string(os,1);
3143         domain = skip_string(lanman,1);
3144         if (*domain || *os || *lanman)
3145           DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
3146       }
3147
3148       /* use the returned uid from now on */
3149       if (SVAL(inbuf,smb_uid) != uid)
3150         DEBUG(3,("Server gave us a UID of %d. We gave %d\n",
3151               SVAL(inbuf,smb_uid),uid));
3152       uid = SVAL(inbuf,smb_uid);
3153     }
3154
3155   /* now we've got a connection - send a tcon message */
3156   bzero(outbuf,smb_size);
3157
3158   if (strncmp(service,"\\\\",2) != 0)
3159     {
3160       DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
3161       DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
3162     }
3163
3164
3165  again2:
3166
3167   {
3168     int passlen = strlen(pass)+1;
3169     fstring pword;
3170     strcpy(pword,pass);
3171
3172 #ifdef SMB_PASSWD
3173     if (doencrypt && *pass) {
3174       passlen=24;
3175       SMBencrypt(pass,cryptkey,pword);      
3176     }
3177 #endif
3178
3179     /* if in user level security then don't send a password now */
3180     if ((sec_mode & 1)) {
3181       strcpy(pword, ""); passlen=1; 
3182     }
3183
3184     if (Protocol <= PROTOCOL_CORE) {
3185       set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
3186       CVAL(outbuf,smb_com) = SMBtcon;
3187       setup_pkt(outbuf);
3188
3189       p = smb_buf(outbuf);
3190       *p++ = 0x04;
3191       strcpy(p, service);
3192       p = skip_string(p,1);
3193       *p++ = 0x04;
3194       memcpy(p,pword,passlen);
3195       p += passlen;
3196       *p++ = 0x04;
3197       strcpy(p, dev);
3198     }
3199     else {
3200       set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
3201       CVAL(outbuf,smb_com) = SMBtconX;
3202       setup_pkt(outbuf);
3203   
3204       SSVAL(outbuf,smb_vwv0,0xFF);
3205       SSVAL(outbuf,smb_vwv3,passlen);
3206   
3207       p = smb_buf(outbuf);
3208       memcpy(p,pword,passlen);
3209       p += passlen;
3210       strcpy(p,service);
3211       p = skip_string(p,1);
3212       strcpy(p,dev);
3213     }
3214   }
3215
3216   send_smb(Client,outbuf);
3217   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3218
3219   /* trying again with a blank password */
3220   if (CVAL(inbuf,smb_rcls) != 0 && 
3221       (int)strlen(pass) > 0 && 
3222       !doencrypt &&
3223       Protocol >= PROTOCOL_LANMAN1)
3224     {
3225       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
3226       strcpy(pass,"");
3227       goto again2;
3228     }  
3229
3230   if (CVAL(inbuf,smb_rcls) != 0)
3231     {
3232       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
3233       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
3234       DEBUG(0,("Some servers insist that these be in uppercase\n"));
3235       if (was_null)
3236         {
3237           free(inbuf);
3238           free(outbuf);
3239         }
3240       return(False);
3241     }
3242   
3243
3244   if (Protocol <= PROTOCOL_CORE) {
3245     max_xmit = SVAL(inbuf,smb_vwv0);
3246
3247     cnum = SVAL(inbuf,smb_vwv1);
3248   }
3249   else {
3250     max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
3251     if (max_xmit <= 0)
3252       max_xmit = BUFFER_SIZE - 4;
3253
3254     cnum = SVAL(inbuf,smb_tid);
3255   }
3256
3257   DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
3258
3259   if (was_null)
3260     {
3261       free(inbuf);
3262       free(outbuf);
3263     }
3264   return True;
3265 }
3266
3267
3268 /****************************************************************************
3269 send a logout command
3270 ****************************************************************************/
3271 static void send_logout(void )
3272 {
3273   pstring inbuf,outbuf;
3274
3275   bzero(outbuf,smb_size);
3276   set_message(outbuf,0,0,True);
3277   CVAL(outbuf,smb_com) = SMBtdis;
3278   SSVAL(outbuf,smb_tid,cnum);
3279   setup_pkt(outbuf);
3280
3281   send_smb(Client,outbuf);
3282   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3283
3284   if (CVAL(inbuf,smb_rcls) != 0)
3285     {
3286       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
3287     }
3288
3289   
3290 #ifdef STATS
3291   stats_report();
3292 #endif
3293   exit(0);
3294 }
3295
3296
3297
3298 /****************************************************************************
3299 call a remote api
3300 ****************************************************************************/
3301 static BOOL call_api(int prcnt,int drcnt,
3302                      int mprcnt,int mdrcnt,
3303                      int *rprcnt,int *rdrcnt,
3304                      char *param,char *data,
3305                      char **rparam,char **rdata)
3306 {
3307   static char *inbuf=NULL;
3308   static char *outbuf=NULL;
3309
3310   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3311   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3312
3313   send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
3314                      data,param,NULL,
3315                      drcnt,prcnt,0,
3316                      mdrcnt,mprcnt,0);
3317
3318   return (receive_trans_response(inbuf,SMBtrans,
3319                                  rdrcnt,rprcnt,
3320                                  rdata,rparam));
3321 }
3322
3323 /****************************************************************************
3324   send a SMB trans or trans2 request
3325   ****************************************************************************/
3326 static BOOL send_trans_request(char *outbuf,int trans,
3327                                char *name,int fid,int flags,
3328                                char *data,char *param,uint16 *setup,
3329                                int ldata,int lparam,int lsetup,
3330                                int mdata,int mparam,int msetup)
3331 {
3332   int i;
3333   int this_ldata,this_lparam;
3334   int tot_data=0,tot_param=0;
3335   char *outdata,*outparam;
3336   pstring inbuf;
3337   char *p;
3338
3339   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
3340   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
3341
3342   bzero(outbuf,smb_size);
3343   set_message(outbuf,14+lsetup,0,True);
3344   CVAL(outbuf,smb_com) = trans;
3345   SSVAL(outbuf,smb_tid,cnum);
3346   setup_pkt(outbuf);
3347
3348   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
3349   outdata = outparam+this_lparam;
3350
3351   /* primary request */
3352   SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3353   SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3354   SSVAL(outbuf,smb_mprcnt,mparam);      /* mprcnt */
3355   SSVAL(outbuf,smb_mdrcnt,mdata);       /* mdrcnt */
3356   SCVAL(outbuf,smb_msrcnt,msetup);      /* msrcnt */
3357   SSVAL(outbuf,smb_flags,flags);        /* flags */
3358   SIVAL(outbuf,smb_timeout,0);          /* timeout */
3359   SSVAL(outbuf,smb_pscnt,this_lparam);  /* pscnt */
3360   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
3361   SSVAL(outbuf,smb_dscnt,this_ldata);   /* dscnt */
3362   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
3363   SCVAL(outbuf,smb_suwcnt,lsetup);      /* suwcnt */
3364   for (i=0;i<lsetup;i++)                /* setup[] */
3365     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
3366   p = smb_buf(outbuf);
3367   if (trans==SMBtrans)
3368     strcpy(p,name);                     /* name[] */
3369   else
3370     {
3371       *p++ = 0;                         /* put in a null smb_name */
3372       *p++ = 'D'; *p++ = ' ';           /* this was added because OS/2 does it */
3373     }
3374   if (this_lparam)                      /* param[] */
3375     memcpy(outparam,param,this_lparam);
3376   if (this_ldata)                       /* data[] */
3377     memcpy(outdata,data,this_ldata);
3378   set_message(outbuf,14+lsetup,         /* wcnt, bcc */
3379               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3380
3381   show_msg(outbuf);
3382   send_smb(Client,outbuf);
3383
3384   if (this_ldata < ldata || this_lparam < lparam)
3385     {
3386       /* receive interim response */
3387       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
3388         {
3389           DEBUG(0,("%s request failed (%s)\n",
3390                    trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
3391           return(False);
3392         }      
3393
3394       tot_data = this_ldata;
3395       tot_param = this_lparam;
3396
3397       while (tot_data < ldata || tot_param < lparam)
3398     {
3399           this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
3400           this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
3401
3402           set_message(outbuf,trans==SMBtrans?8:9,0,True);
3403           CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
3404
3405           outparam = smb_buf(outbuf);
3406           outdata = outparam+this_lparam;
3407
3408           /* secondary request */
3409           SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3410           SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3411           SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
3412           SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
3413           SSVAL(outbuf,smb_spsdisp,tot_param);  /* psdisp */
3414           SSVAL(outbuf,smb_sdscnt,this_ldata);  /* dscnt */
3415           SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
3416           SSVAL(outbuf,smb_sdsdisp,tot_data);   /* dsdisp */
3417           if (trans==SMBtrans2)
3418             SSVAL(outbuf,smb_sfid,fid);         /* fid */
3419           if (this_lparam)                      /* param[] */
3420             memcpy(outparam,param,this_lparam);
3421           if (this_ldata)                       /* data[] */
3422             memcpy(outdata,data,this_ldata);
3423           set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
3424                       PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3425
3426           show_msg(outbuf);
3427           send_smb(Client,outbuf);
3428
3429           tot_data += this_ldata;
3430           tot_param += this_lparam;
3431         }
3432     }
3433
3434     return(True);
3435 }
3436
3437 /****************************************************************************
3438 try and browse available connections on a host
3439 ****************************************************************************/
3440 static BOOL browse_host(BOOL sort)
3441 {
3442 #ifdef NOSTRCASECMP
3443 #define strcasecmp StrCaseCmp
3444 #endif
3445   extern int strcasecmp();
3446
3447   char *rparam = NULL;
3448   char *rdata = NULL;
3449   char *p;
3450   int rdrcnt,rprcnt;
3451   pstring param;
3452   int count = -1;
3453
3454   /* now send a SMBtrans command with api RNetShareEnum */
3455   p = param;
3456   SSVAL(p,0,0); /* api number */
3457   p += 2;
3458   strcpy(p,"WrLeh");
3459   p = skip_string(p,1);
3460   strcpy(p,"B13BWz");
3461   p = skip_string(p,1);
3462   SSVAL(p,0,1);
3463   SSVAL(p,2,BUFFER_SIZE);
3464   p += 4;
3465
3466   if (call_api(PTR_DIFF(p,param),0,
3467                1024,BUFFER_SIZE,
3468                &rprcnt,&rdrcnt,
3469                param,NULL,
3470                &rparam,&rdata))
3471     {
3472       int res = SVAL(rparam,0);
3473       int converter=SVAL(rparam,2);
3474       int i;
3475       BOOL long_share_name=False;
3476       
3477       if (res == 0)
3478         {
3479           count=SVAL(rparam,4);
3480           p = rdata;
3481
3482           if (count > 0)
3483             {
3484               printf("\n\tSharename      Type      Comment\n");
3485               printf("\t---------      ----      -------\n");
3486             }
3487
3488           if (sort)
3489             qsort(p,count,20,QSORT_CAST strcasecmp);
3490
3491           for (i=0;i<count;i++)
3492             {
3493               char *sname = p;
3494               int type = SVAL(p,14);
3495               int comment_offset = IVAL(p,16) & 0xFFFF;
3496               fstring typestr;
3497               *typestr=0;
3498
3499               switch (type)
3500                 {
3501                 case STYPE_DISKTREE:
3502                   strcpy(typestr,"Disk"); break;
3503                 case STYPE_PRINTQ:
3504                   strcpy(typestr,"Printer"); break;           
3505                 case STYPE_DEVICE:
3506                   strcpy(typestr,"Device"); break;
3507                 case STYPE_IPC:
3508                   strcpy(typestr,"IPC"); break;      
3509                 }
3510
3511               printf("\t%-15.15s%-10.10s%s\n",
3512                      sname,
3513                      typestr,
3514                      comment_offset?rdata+comment_offset-converter:"");
3515           
3516               if (strlen(sname)>8) long_share_name=True;
3517           
3518               p += 20;
3519             }
3520
3521           if (long_share_name) {
3522             printf("\nNOTE: There were share names longer than 8 chars.\nOn older clients these may not be accessible or may give browsing errors\n");
3523           }
3524         }
3525     }
3526   
3527   if (rparam) free(rparam);
3528   if (rdata) free(rdata);
3529
3530   return(count>0);
3531 }
3532
3533
3534 /****************************************************************************
3535 get some server info
3536 ****************************************************************************/
3537 static void server_info()
3538 {
3539   char *rparam = NULL;
3540   char *rdata = NULL;
3541   char *p;
3542   int rdrcnt,rprcnt;
3543   pstring param;
3544
3545   bzero(param,sizeof(param));
3546
3547   p = param;
3548   SSVAL(p,0,63); /* api number */
3549   p += 2;
3550   strcpy(p,"WrLh");
3551   p = skip_string(p,1);
3552   strcpy(p,"zzzBBzz");
3553   p = skip_string(p,1);
3554   SSVAL(p,0,10); /* level 10 */
3555   SSVAL(p,2,1000);
3556   p += 6;
3557
3558   if (call_api(PTR_DIFF(p,param),0,
3559                6,1000,
3560                &rprcnt,&rdrcnt,
3561                param,NULL,
3562                &rparam,&rdata))
3563     {
3564       int res = SVAL(rparam,0);
3565       int converter=SVAL(rparam,2);
3566
3567       if (res == 0)
3568         {
3569       p = rdata;
3570
3571       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3572              rdata+SVAL(p,0)-converter,
3573              rdata+SVAL(p,4)-converter,
3574              rdata+SVAL(p,8)-converter,
3575              rdata+SVAL(p,14)-converter);
3576     }
3577     }
3578
3579   if (rparam) free(rparam);
3580   if (rdata) free(rdata);
3581
3582   return;
3583 }
3584
3585
3586 /****************************************************************************
3587 try and browse available connections on a host
3588 ****************************************************************************/
3589 static BOOL list_servers()
3590 {
3591   char *rparam = NULL;
3592   char *rdata = NULL;
3593   int rdrcnt,rprcnt;
3594   char *p;
3595   pstring param;
3596   int uLevel = 1;
3597   int count = 0;
3598
3599   /* now send a SMBtrans command with api ServerEnum? */
3600   p = param;
3601   SSVAL(p,0,0x68); /* api number */
3602   p += 2;
3603   strcpy(p,"WrLehDO");
3604   p = skip_string(p,1);
3605
3606   strcpy(p,"B16BBDz");
3607 #if 0
3608   strcpy(p,getenv("XX_STR2"));
3609 #endif
3610
3611   p = skip_string(p,1);
3612   SSVAL(p,0,uLevel);
3613   SSVAL(p,2,0x2000); /* buf length */
3614   p += 4;
3615
3616   SIVAL(p,0,SV_TYPE_ALL);
3617
3618   if (call_api(PTR_DIFF(p+4,param),0,
3619                8,10000,
3620                &rprcnt,&rdrcnt,
3621                param,NULL,
3622                &rparam,&rdata))
3623     {
3624       int res = SVAL(rparam,0);
3625       int converter=SVAL(rparam,2);
3626       int i;
3627
3628       if (res == 0) {   
3629         char *p2 = rdata;
3630         count=SVAL(rparam,4);
3631
3632         if (count > 0) {
3633           printf("\n\nThis machine has a browse list:\n");
3634           printf("\n\tServer               Comment\n");
3635           printf("\t---------            -------\n");
3636         }
3637         
3638         for (i=0;i<count;i++) {
3639           char *sname = p2;
3640           int comment_offset = IVAL(p2,22) & 0xFFFF;
3641           printf("\t%-16.16s     %s\n",
3642                  sname,
3643                  comment_offset?rdata+comment_offset-converter:"");
3644           
3645           p2 += 26;
3646         }
3647       }
3648     }
3649
3650   if (rparam) {free(rparam); rparam = NULL;}
3651   if (rdata) {free(rdata); rdata = NULL;}
3652
3653   SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
3654
3655   if (call_api(PTR_DIFF(p+4,param),0,
3656                8,10000,
3657                &rprcnt,&rdrcnt,
3658                param,NULL,
3659                &rparam,&rdata))
3660     {
3661       int res = SVAL(rparam,0);
3662       int converter=SVAL(rparam,2);
3663       int i;
3664
3665       if (res == 0) {
3666         char *p2 = rdata;
3667         count=SVAL(rparam,4);
3668
3669         if (count > 0) {
3670           printf("\n\nThis machine has a workgroup list:\n");
3671           printf("\n\tWorkgroup            Master\n");
3672           printf("\t---------            -------\n");
3673         }
3674         
3675         for (i=0;i<count;i++) {
3676           char *sname = p2;
3677           int comment_offset = IVAL(p2,22) & 0xFFFF;
3678           printf("\t%-16.16s     %s\n",
3679                  sname,
3680                  comment_offset?rdata+comment_offset-converter:"");
3681           
3682           p2 += 26;
3683         }
3684       }
3685     }
3686
3687   if (rparam) free(rparam);
3688   if (rdata) free(rdata);
3689
3690   return(count>0);
3691 }
3692
3693
3694
3695
3696 void cmd_help();
3697
3698 /* This defines the commands supported by this client */
3699 struct
3700 {
3701   char *name;
3702   void (*fn)();
3703   char *description;
3704 } commands[] = 
3705 {
3706   {"ls",cmd_dir,"<mask> list the contents of the current directory"},
3707   {"dir",cmd_dir,"<mask> list the contents of the current directory"},
3708   {"lcd",cmd_lcd,"[directory] change/report the local current working directory"},
3709   {"cd",cmd_cd,"[directory] change/report the remote directory"},
3710   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
3711   {"get",cmd_get,"<remote name> [local name] get a file"},
3712   {"mget",cmd_mget,"<mask> get all the matching files"},
3713   {"put",cmd_put,"<local name> [remote name] put a file"},
3714   {"mput",cmd_mput,"<mask> put all matching files"},
3715   {"rename",cmd_rename,"<src> <dest> rename some files"},
3716   {"more",cmd_more,"<remote name> view a remote file with your pager"},  
3717   {"mask",cmd_select,"<mask> mask all filenames against this"},
3718   {"del",cmd_del,"<mask> delete all matching files"},
3719   {"rm",cmd_del,"<mask> delete all matching files"},
3720   {"mkdir",cmd_mkdir,"<directory> make a directory"},
3721   {"md",cmd_mkdir,"<directory> make a directory"},
3722   {"rmdir",cmd_rmdir,"<directory> remove a directory"},
3723   {"rd",cmd_rmdir,"<directory> remove a directory"},
3724   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},  
3725   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},  
3726   {"translate",cmd_translate,"toggle text translation for printing"},  
3727   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},  
3728   {"print",cmd_print,"<file name> print a file"},
3729   {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
3730   {"queue",cmd_queue,"show the print queue"},
3731   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
3732   {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
3733   {"quit",send_logout,"logoff the server"},
3734   {"q",send_logout,"logoff the server"},
3735   {"exit",send_logout,"logoff the server"},
3736   {"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
3737   {"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"},
3738   {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
3739   {"blocksize",cmd_block,"blocksize <number> (default 20)" },
3740   {"tarmode",cmd_tarmode,
3741      "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
3742   {"setmode",cmd_setmode,"filename <setmode string> change modes of file"},
3743   {"help",cmd_help,"[command] give help on a command"},
3744   {"?",cmd_help,"[command] give help on a command"},
3745   {"!",NULL,"run a shell command on the local system"},
3746   {"",NULL,NULL}
3747 };
3748
3749
3750 /*******************************************************************
3751   lookup a command string in the list of commands, including 
3752   abbreviations
3753   ******************************************************************/
3754 static int process_tok(fstring tok)
3755 {
3756   int i = 0, matches = 0;
3757   int cmd=0;
3758   int tok_len = strlen(tok);
3759   
3760   while (commands[i].fn != NULL)
3761     {
3762       if (strequal(commands[i].name,tok))
3763         {
3764           matches = 1;
3765           cmd = i;
3766           break;
3767         }
3768       else if (strnequal(commands[i].name, tok, tok_len+1))
3769         {
3770           matches++;
3771           cmd = i;
3772         }
3773       i++;
3774     }
3775   
3776   if (matches == 0)
3777     return(-1);
3778   else if (matches == 1)
3779     return(cmd);
3780   else
3781     return(-2);
3782 }
3783
3784 /****************************************************************************
3785 help
3786 ****************************************************************************/
3787 void cmd_help(void)
3788 {
3789   int i=0,j;
3790   fstring buf;
3791
3792   if (next_token(NULL,buf,NULL))
3793     {
3794       if ((i = process_tok(buf)) >= 0)
3795         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
3796     }
3797   else
3798     while (commands[i].description)
3799       {
3800         for (j=0; commands[i].description && (j<5); j++) {
3801           DEBUG(0,("%-15s",commands[i].name));
3802           i++;
3803         }
3804         DEBUG(0,("\n"));
3805       }
3806 }
3807
3808 /****************************************************************************
3809 open the client sockets
3810 ****************************************************************************/
3811 static BOOL open_sockets(int port )
3812 {
3813   static int last_port;
3814   char *host;
3815   pstring service2;
3816   extern int Client;
3817 #ifdef USENMB
3818   BOOL failed = True;
3819 #endif
3820
3821   if (port == 0) port=last_port;
3822   last_port=port;
3823
3824   strupper(service);
3825
3826   if (*desthost)
3827     {
3828       host = desthost;
3829     }
3830   else
3831     {
3832       strcpy(service2,service);
3833       host = strtok(service2,"\\/");
3834       if (!host) {
3835         DEBUG(0,("Badly formed host name\n"));
3836         return(False);
3837       }
3838       strcpy(desthost,host);
3839     }
3840
3841   DEBUG(3,("Opening sockets\n"));
3842
3843   if (*myname == 0)
3844     {
3845       get_myname(myname,NULL);
3846       strupper(myname);
3847     }
3848
3849   if (!have_ip)
3850     {
3851       struct hostent *hp;
3852
3853       if ((hp = Get_Hostbyname(host))) {
3854         putip((char *)&dest_ip,(char *)hp->h_addr);
3855         failed = False;
3856       } else {
3857 #ifdef USENMB
3858         /* Try and resolve the name with the netbios server */
3859         int             bcast;
3860         pstring         hs;
3861         struct in_addr  ip1, ip2;
3862         
3863         if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
3864           set_socket_options (bcast, "SO_BROADCAST");
3865
3866           if (!got_bcast && get_myname(hs, &ip1)) {
3867             get_broadcast(&ip1, &bcast_ip, &ip2);
3868           }
3869
3870           if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
3871             failed = False;
3872           }
3873           close (bcast);
3874         }
3875 #endif
3876         if (failed) {
3877           DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
3878           return False;
3879         }
3880       }
3881     }
3882
3883   Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
3884   if (Client == -1)
3885     return False;
3886
3887   DEBUG(3,("Connected\n"));
3888   
3889   set_socket_options(Client,user_socket_options);  
3890   
3891   return True;
3892 }
3893
3894 /****************************************************************************
3895 wait for keyboard activity, swallowing network packets
3896 ****************************************************************************/
3897 #ifdef CLIX
3898 static char wait_keyboard(char *buffer)
3899 #else
3900 static void wait_keyboard(char *buffer)
3901 #endif
3902 {
3903   fd_set fds;
3904   int selrtn;
3905   struct timeval timeout;
3906   
3907 #ifdef CLIX
3908   int delay = 0;
3909 #endif
3910   
3911   while (1) 
3912     {
3913       extern int Client;
3914       FD_ZERO(&fds);
3915       FD_SET(Client,&fds);
3916 #ifndef CLIX
3917       FD_SET(fileno(stdin),&fds);
3918 #endif
3919
3920       timeout.tv_sec = 20;
3921       timeout.tv_usec = 0;
3922 #ifdef CLIX
3923       timeout.tv_sec = 0;
3924 #endif
3925       selrtn = sys_select(&fds,&timeout);
3926       
3927 #ifndef CLIX
3928       if (FD_ISSET(fileno(stdin),&fds))
3929         return;
3930 #else
3931       {
3932         char ch;
3933         int f_flags;
3934         int readret;
3935         
3936         f_flags = fcntl(fileno(stdin), F_GETFL, 0);
3937         fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
3938         readret = read_data( fileno(stdin), &ch, 1);
3939         fcntl(fileno(stdin), F_SETFL, f_flags);
3940         if (readret == -1)
3941           {
3942             if (errno != EAGAIN)
3943               {
3944                 /* should crash here */
3945                 DEBUG(1,("readchar stdin failed\n"));
3946               }
3947           }
3948         else if (readret != 0)
3949           {
3950             return ch;
3951           }
3952       }
3953 #endif
3954       if (FD_ISSET(Client,&fds))
3955         receive_smb(Client,buffer,0);
3956       
3957 #ifdef CLIX
3958       delay++;
3959       if (delay > 100000)
3960         {
3961           delay = 0;
3962           chkpath("\\",False);
3963         }
3964 #else
3965       chkpath("\\",False);
3966 #endif
3967     }  
3968 }
3969
3970
3971 /****************************************************************************
3972 close and open the connection again
3973 ****************************************************************************/
3974 BOOL reopen_connection(char *inbuf,char *outbuf)
3975 {
3976   static int open_count=0;
3977
3978   open_count++;
3979
3980   if (open_count>5) return(False);
3981
3982   DEBUG(1,("Trying to re-open connection\n"));
3983
3984   set_message(outbuf,0,0,True);
3985   SCVAL(outbuf,smb_com,SMBtdis);
3986   SSVAL(outbuf,smb_tid,cnum);
3987   setup_pkt(outbuf);
3988
3989   send_smb(Client,outbuf);
3990   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3991
3992   close_sockets();
3993   if (!open_sockets(0)) return(False);
3994
3995   return(send_login(inbuf,outbuf,True,True));
3996 }
3997
3998 /****************************************************************************
3999   process commands from the client
4000 ****************************************************************************/
4001 BOOL process(char *base_directory)
4002 {
4003   extern FILE *dbf;
4004   pstring line;
4005
4006   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4007   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4008
4009   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4010     return(False);
4011   
4012   bzero(OutBuffer,smb_size);
4013
4014   if (!send_login(InBuffer,OutBuffer,True,True))
4015     return(False);
4016
4017   if (*base_directory) do_cd(base_directory);
4018
4019   while (!feof(stdin))
4020     {
4021       fstring tok;
4022       int i;
4023
4024       bzero(OutBuffer,smb_size);
4025
4026       /* display a prompt */
4027       DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
4028       fflush(dbf);
4029
4030 #ifdef CLIX
4031       line[0] = wait_keyboard(InBuffer);
4032       /* this might not be such a good idea... */
4033       if ( line[0] == EOF)
4034         break;
4035 #else
4036       wait_keyboard(InBuffer);
4037 #endif
4038   
4039       /* and get a response */
4040 #ifdef CLIX
4041       fgets( &line[1],999, stdin);
4042 #else
4043       if (!fgets(line,1000,stdin))
4044         break;
4045 #endif
4046
4047       /* input language code to internal one */
4048       CNV_INPUT (line);
4049
4050       /* special case - first char is ! */
4051       if (*line == '!')
4052         {
4053           system(line + 1);
4054           continue;
4055         }
4056       
4057       /* and get the first part of the command */
4058       {
4059         char *ptr = line;
4060         if (!next_token(&ptr,tok,NULL)) continue;
4061       }
4062
4063       if ((i = process_tok(tok)) >= 0)
4064         commands[i].fn(InBuffer,OutBuffer);
4065       else if (i == -2)
4066         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4067       else
4068         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4069     }
4070   
4071   send_logout();
4072   return(True);
4073 }
4074
4075
4076 /****************************************************************************
4077 usage on the program
4078 ****************************************************************************/
4079 void usage(char *pname)
4080 {
4081   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
4082            pname));
4083
4084 #ifdef KANJI
4085   DEBUG(0,("[-t termcode] "));
4086 #endif /* KANJI */
4087
4088   DEBUG(0,("\nVersion %s\n",VERSION));
4089   DEBUG(0,("\t-p port               listen on the specified port\n"));
4090   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
4091   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
4092   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
4093   DEBUG(0,("\t-N                    don't ask for a password\n"));
4094   DEBUG(0,("\t-P                    connect to service as a printer\n"));
4095   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
4096   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
4097   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
4098   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
4099   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
4100   DEBUG(0,("\t-U username           set the network username\n"));
4101   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
4102 #ifdef KANJI
4103   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
4104 #endif /* KANJI */
4105   DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
4106   DEBUG(0,("\t-D directory          start from directory\n"));
4107   DEBUG(0,("\n"));
4108 }
4109
4110
4111
4112 /****************************************************************************
4113   main program
4114 ****************************************************************************/
4115 int main(int argc,char *argv[])
4116 {
4117   fstring base_directory;
4118   char *pname = argv[0];
4119   int port = 139;
4120   int opt;
4121   extern FILE *dbf;
4122   extern char *optarg;
4123   extern int optind;
4124   pstring query_host;
4125   BOOL message = False;
4126   extern char tar_type;
4127
4128   *query_host = 0;
4129   *base_directory = 0;
4130
4131   DEBUGLEVEL = 2;
4132
4133   setup_logging(pname,True);
4134
4135   TimeInit();
4136   charset_initialise();
4137
4138   pid = getpid();
4139   uid = getuid();
4140   gid = getgid();
4141   mid = pid + 100;
4142   myumask = umask(0);
4143   umask(myumask);
4144
4145   if (getenv("USER"))
4146     {
4147       strcpy(username,getenv("USER"));
4148       strupper(username);
4149     }
4150
4151   if (*username == 0 && getenv("LOGNAME"))
4152     {
4153       strcpy(username,getenv("LOGNAME"));
4154       strupper(username);
4155     }
4156
4157   if (argc < 2)
4158     {
4159       usage(pname);
4160       exit(1);
4161     }
4162   
4163   if (*argv[1] != '-')
4164     {
4165
4166       strcpy(service,argv[1]);  
4167       argc--;
4168       argv++;
4169
4170       if (count_chars(service,'\\') < 3)
4171         {
4172           usage(pname);
4173           printf("\n%s: Not enough '\\' characters in service\n",service);
4174           exit(1);
4175         }
4176
4177 /*
4178       if (count_chars(service,'\\') > 3)
4179         {
4180           usage(pname);
4181           printf("\n%s: Too many '\\' characters in service\n",service);
4182           exit(1);
4183         }
4184         */
4185
4186       if (argc > 1 && (*argv[1] != '-'))
4187         {
4188           got_pass = True;
4189           strcpy(password,argv[1]);  
4190           memset(argv[1],'X',strlen(argv[1]));
4191           argc--;
4192           argv++;
4193         }
4194     }
4195
4196 #ifdef KANJI
4197   setup_term_code (KANJI);
4198   while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:")) != EOF)
4199 #else
4200   while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:m:W:T:D:")) != EOF)
4201 #endif /* KANJI */
4202     switch (opt)
4203       {
4204       case 'm':
4205         max_protocol = interpret_protocol(optarg,max_protocol);
4206         break;
4207       case 'O':
4208         strcpy(user_socket_options,optarg);
4209         break;  
4210       case 'M':
4211         name_type = 3;
4212         strcpy(desthost,optarg);
4213         strupper(desthost);
4214         message = True;
4215         break;
4216       case 'B':
4217         bcast_ip = *interpret_addr2(optarg);
4218         got_bcast = True;
4219         break;
4220       case 'D':
4221         strcpy(base_directory,optarg);
4222         break;
4223       case 'T':
4224         if (!tar_parseargs(argc, argv, optarg, optind)) {
4225           usage(pname);
4226           exit(1);
4227         }
4228         break;
4229       case 'i':
4230         strcpy(scope,optarg);
4231         break;
4232       case 'L':
4233         got_pass = True;
4234         strcpy(query_host,optarg);
4235         break;
4236       case 'U':
4237         {
4238           char *p;
4239         strcpy(username,optarg);
4240         if ((p=strchr(username,'%')))
4241           {
4242             *p = 0;
4243             strcpy(password,p+1);
4244             got_pass = True;
4245             memset(strchr(optarg,'%')+1,'X',strlen(password));
4246           }
4247         }
4248             
4249         break;
4250       case 'W':
4251         strcpy(workgroup,optarg);
4252         break;
4253       case 'E':
4254         dbf = stderr;
4255         break;
4256       case 'I':
4257         {
4258           dest_ip = *interpret_addr2(optarg);
4259           if (zero_ip(dest_ip)) exit(1);
4260           have_ip = True;
4261         }
4262         break;
4263       case 'n':
4264         strcpy(myname,optarg);
4265         break;
4266       case 'N':
4267         got_pass = True;
4268         break;
4269       case 'P':
4270         connect_as_printer = True;
4271         break;
4272       case 'd':
4273         if (*optarg == 'A')
4274           DEBUGLEVEL = 10000;
4275         else
4276           DEBUGLEVEL = atoi(optarg);
4277         break;
4278       case 'l':
4279         sprintf(debugf,"%s.client",optarg);
4280         break;
4281       case 'p':
4282         port = atoi(optarg);
4283         break;
4284       case 'h':
4285         usage(pname);
4286         exit(0);
4287         break;
4288 #ifdef KANJI
4289       case 't':
4290         if (!setup_term_code (optarg)) {
4291             DEBUG(0, ("%s: unknown terminal code name\n", optarg));
4292             usage (pname);
4293             exit (1);
4294         }
4295         break;
4296 #endif /* KANJI */
4297       default:
4298         usage(pname);
4299         exit(1);
4300       }
4301
4302   if (!tar_type && !*query_host && !*service && !message)
4303     {
4304       usage(pname);
4305       exit(1);
4306     }
4307
4308
4309   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
4310
4311   get_myname(*myname?NULL:myname,&myip);  
4312   strupper(myname);
4313
4314   if (tar_type) {
4315     recurse=True;
4316
4317     if (open_sockets(port)) {
4318         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4319         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4320         int ret;
4321
4322         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4323           return(1);
4324
4325         bzero(OutBuffer,smb_size);
4326         if (!send_login(InBuffer,OutBuffer,True,True))
4327           return(False);
4328
4329         if (*base_directory) do_cd(base_directory);
4330
4331         ret=process_tar(InBuffer, OutBuffer);
4332
4333         send_logout();
4334         close_sockets();
4335         return(ret);
4336     } else
4337       return(1);
4338   }
4339   
4340   if (*query_host)
4341     {
4342       int ret = 0;
4343       sprintf(service,"\\\\%s\\IPC$",query_host);
4344       strupper(service);
4345       connect_as_ipc = True;
4346       if (open_sockets(port))
4347         {
4348 #if 0
4349           *username = 0;
4350 #endif
4351           if (!send_login(NULL,NULL,True,True))
4352             return(1);
4353
4354           server_info();
4355           if (!browse_host(True)) {
4356             sleep(1);
4357             browse_host(True);
4358           }
4359           if (!list_servers()) {
4360             sleep(1);
4361             list_servers();
4362           }
4363
4364           send_logout();
4365           close_sockets();
4366         }
4367
4368       return(ret);
4369     }
4370
4371   if (message)
4372     {
4373       int ret = 0;
4374       if (open_sockets(port))
4375         {
4376           pstring inbuf,outbuf;
4377           bzero(outbuf,smb_size);
4378           if (!send_session_request(inbuf,outbuf))
4379             return(1);
4380
4381           send_message(inbuf,outbuf);
4382
4383           close_sockets();
4384         }
4385
4386       return(ret);
4387     }
4388
4389   if (open_sockets(port))
4390     {
4391       if (!process(base_directory))
4392         {
4393           close_sockets();
4394           return(1);
4395         }
4396       close_sockets();
4397     }
4398   else
4399     return(1);
4400
4401   return(0);
4402 }
4403
4404
4405 /* error code stuff - put together by Merik Karman
4406    merik@blackadder.dsh.oz.au */
4407
4408 typedef struct
4409 {
4410   char *name;
4411   int code;
4412   char *message;
4413 } err_code_struct;
4414
4415 /* Dos Error Messages */
4416 err_code_struct dos_msgs[] = {
4417   {"ERRbadfunc",1,"Invalid function."},
4418   {"ERRbadfile",2,"File not found."},
4419   {"ERRbadpath",3,"Directory invalid."},
4420   {"ERRnofids",4,"No file descriptors available"},
4421   {"ERRnoaccess",5,"Access denied."},
4422   {"ERRbadfid",6,"Invalid file handle."},
4423   {"ERRbadmcb",7,"Memory control blocks destroyed."},
4424   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
4425   {"ERRbadmem",9,"Invalid memory block address."},
4426   {"ERRbadenv",10,"Invalid environment."},
4427   {"ERRbadformat",11,"Invalid format."},
4428   {"ERRbadaccess",12,"Invalid open mode."},
4429   {"ERRbaddata",13,"Invalid data."},
4430   {"ERR",14,"reserved."},
4431   {"ERRbaddrive",15,"Invalid drive specified."},
4432   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
4433   {"ERRdiffdevice",17,"Not same device."},
4434   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
4435   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
4436   {"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."},
4437   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
4438   {"ERRbadpipe",230,"Pipe invalid."},
4439   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
4440   {"ERRpipeclosing",232,"Pipe close in progress."},
4441   {"ERRnotconnected",233,"No process on other end of pipe."},
4442   {"ERRmoredata",234,"There is more data to be returned."},
4443   {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
4444   {NULL,-1,NULL}};
4445
4446 /* Server Error Messages */
4447 err_code_struct server_msgs[] = {
4448   {"ERRerror",1,"Non-specific error code."},
4449   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
4450   {"ERRbadtype",3,"reserved."},
4451   {"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."},
4452   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
4453   {"ERRinvnetname",6,"Invalid network name in tree connect."},
4454   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
4455   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
4456   {"ERRqtoobig",50,"Print queue full -- no space."},
4457   {"ERRqeof",51,"EOF on print queue dump."},
4458   {"ERRinvpfid",52,"Invalid print file FID."},
4459   {"ERRsmbcmd",64,"The server did not recognize the command received."},
4460   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
4461   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
4462   {"ERRreserved",68,"reserved."},
4463   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
4464   {"ERRreserved",70,"reserved."},
4465   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
4466   {"ERRpaused",81,"Server is paused."},
4467   {"ERRmsgoff",82,"Not receiving messages."},
4468   {"ERRnoroom",83,"No room to buffer message."},
4469   {"ERRrmuns",87,"Too many remote user names."},
4470   {"ERRtimeout",88,"Operation timed out."},
4471   {"ERRnoresource",89,"No resources currently available for request."},
4472   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
4473   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
4474   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
4475   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
4476   {"ERRcontmpx",252,"Continue in MPX mode."},
4477   {"ERRreserved",253,"reserved."},
4478   {"ERRreserved",254,"reserved."},
4479   {"ERRnosupport",0xFFFF,"Function not supported."},
4480   {NULL,-1,NULL}};
4481
4482 /* Hard Error Messages */
4483 err_code_struct hard_msgs[] = {
4484   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
4485   {"ERRbadunit",20,"Unknown unit."},
4486   {"ERRnotready",21,"Drive not ready."},
4487   {"ERRbadcmd",22,"Unknown command."},
4488   {"ERRdata",23,"Data error (CRC)."},
4489   {"ERRbadreq",24,"Bad request structure length."},
4490   {"ERRseek",25 ,"Seek error."},
4491   {"ERRbadmedia",26,"Unknown media type."},
4492   {"ERRbadsector",27,"Sector not found."},
4493   {"ERRnopaper",28,"Printer out of paper."},
4494   {"ERRwrite",29,"Write fault."},
4495   {"ERRread",30,"Read fault."},
4496   {"ERRgeneral",31,"General failure."},
4497   {"ERRbadshare",32,"A open conflicts with an existing open."},
4498   {"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."},
4499   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
4500   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
4501   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
4502   {NULL,-1,NULL}};
4503
4504
4505 struct
4506 {
4507   int code;
4508   char *class;
4509   err_code_struct *err_msgs;
4510 } err_classes[] = { 
4511   {0,"SUCCESS",NULL},
4512   {0x01,"ERRDOS",dos_msgs},
4513   {0x02,"ERRSRV",server_msgs},
4514   {0x03,"ERRHRD",hard_msgs},
4515   {0x04,"ERRXOS",NULL},
4516   {0xE1,"ERRRMX1",NULL},
4517   {0xE2,"ERRRMX2",NULL},
4518   {0xE3,"ERRRMX3",NULL},
4519   {0xFF,"ERRCMD",NULL},
4520   {-1,NULL,NULL}};
4521
4522
4523 /****************************************************************************
4524 return a SMB error string from a SMB buffer
4525 ****************************************************************************/
4526 char *smb_errstr(char *inbuf)
4527 {
4528   static pstring ret;
4529   int class = CVAL(inbuf,smb_rcls);
4530   int num = SVAL(inbuf,smb_err);
4531   int i,j;
4532
4533   for (i=0;err_classes[i].class;i++)
4534     if (err_classes[i].code == class)
4535       {
4536         if (err_classes[i].err_msgs)
4537           {
4538             err_code_struct *err = err_classes[i].err_msgs;
4539             for (j=0;err[j].name;j++)
4540               if (num == err[j].code)
4541                 {
4542                   if (DEBUGLEVEL > 0)
4543                     sprintf(ret,"%s - %s (%s)",err_classes[i].class,
4544                             err[j].name,err[j].message);
4545                   else
4546                     sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
4547                   return ret;
4548                 }
4549           }
4550
4551         sprintf(ret,"%s - %d",err_classes[i].class,num);
4552         return ret;
4553       }
4554   
4555   sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
4556   return(ret);
4557 }