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