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