some cleanups in the clientutil.c code.
[samba.git] / source3 / client / client.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-1997
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
25
26 #include "includes.h"
27
28 #ifndef REGISTER
29 #define REGISTER 0
30 #endif
31
32 pstring cur_dir = "\\";
33 pstring cd_path = "";
34 pstring service="";
35 pstring desthost="";
36 extern pstring myname;
37 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   if (SVAL(inbuf, smb_vwv2) & 1)
3417           DEBUG(1,("connected as guest "));
3418   if (sec_mode & 1)
3419           DEBUG(1,("security=user\n"));
3420   else
3421           DEBUG(1,("security=share\n"));
3422
3423   /* now we've got a connection - send a tcon message */
3424   bzero(outbuf,smb_size);
3425
3426   if (strncmp(service,"\\\\",2) != 0)
3427     {
3428       DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
3429       DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
3430     }
3431
3432
3433  again2:
3434
3435   {
3436     int passlen = strlen(pass)+1;
3437     fstring pword;
3438     strcpy(pword,pass);
3439
3440     if (doencrypt && *pass) {
3441       passlen=24;
3442       SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);      
3443     }
3444
3445     /* if in user level security then don't send a password now */
3446     if ((sec_mode & 1)) {
3447       strcpy(pword, ""); passlen=1; 
3448     }
3449
3450     if (Protocol <= PROTOCOL_COREPLUS) {
3451       set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
3452       CVAL(outbuf,smb_com) = SMBtcon;
3453       setup_pkt(outbuf);
3454
3455       p = smb_buf(outbuf);
3456       *p++ = 0x04;
3457       strcpy(p, service);
3458       p = skip_string(p,1);
3459       *p++ = 0x04;
3460       memcpy(p,pword,passlen);
3461       p += passlen;
3462       *p++ = 0x04;
3463       strcpy(p, dev);
3464     }
3465     else {
3466       set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
3467       CVAL(outbuf,smb_com) = SMBtconX;
3468       setup_pkt(outbuf);
3469   
3470       SSVAL(outbuf,smb_vwv0,0xFF);
3471       SSVAL(outbuf,smb_vwv3,passlen);
3472   
3473       p = smb_buf(outbuf);
3474       memcpy(p,pword,passlen);
3475       p += passlen;
3476       strcpy(p,service);
3477       p = skip_string(p,1);
3478       strcpy(p,dev);
3479     }
3480   }
3481
3482   send_smb(Client,outbuf);
3483   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3484
3485   /* trying again with a blank password */
3486   if (CVAL(inbuf,smb_rcls) != 0 && 
3487       (int)strlen(pass) > 0 && 
3488       !doencrypt &&
3489       Protocol >= PROTOCOL_LANMAN1)
3490     {
3491       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
3492       strcpy(pass,"");
3493       goto again2;
3494     }  
3495
3496   if (CVAL(inbuf,smb_rcls) != 0)
3497     {
3498       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
3499       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
3500       DEBUG(0,("Some servers insist that these be in uppercase\n"));
3501       if (was_null)
3502         {
3503           free(inbuf);
3504           free(outbuf);
3505         }
3506       return(False);
3507     }
3508   
3509
3510   if (Protocol <= PROTOCOL_COREPLUS) {
3511     max_xmit = SVAL(inbuf,smb_vwv0);
3512
3513     cnum = SVAL(inbuf,smb_vwv1);
3514   }
3515   else {
3516     max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
3517     if (max_xmit <= 0)
3518       max_xmit = BUFFER_SIZE - 4;
3519
3520     cnum = SVAL(inbuf,smb_tid);
3521   }
3522
3523   DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
3524
3525   if (was_null)
3526     {
3527       free(inbuf);
3528       free(outbuf);
3529     }
3530
3531   return True;
3532 }
3533
3534
3535 /****************************************************************************
3536 send a logout command
3537 ****************************************************************************/
3538 static void send_logout(void )
3539 {
3540   pstring inbuf,outbuf;
3541
3542   bzero(outbuf,smb_size);
3543   set_message(outbuf,0,0,True);
3544   CVAL(outbuf,smb_com) = SMBtdis;
3545   SSVAL(outbuf,smb_tid,cnum);
3546   setup_pkt(outbuf);
3547
3548   send_smb(Client,outbuf);
3549   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3550
3551   if (CVAL(inbuf,smb_rcls) != 0)
3552     {
3553       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
3554     }
3555
3556   
3557 #ifdef STATS
3558   stats_report();
3559 #endif
3560   exit(0);
3561 }
3562
3563
3564
3565 /****************************************************************************
3566 call a remote api
3567 ****************************************************************************/
3568 static BOOL call_api(int prcnt,int drcnt,
3569                      int mprcnt,int mdrcnt,
3570                      int *rprcnt,int *rdrcnt,
3571                      char *param,char *data,
3572                      char **rparam,char **rdata)
3573 {
3574   static char *inbuf=NULL;
3575   static char *outbuf=NULL;
3576
3577   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3578   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3579
3580   send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
3581                      data,param,NULL,
3582                      drcnt,prcnt,0,
3583                      mdrcnt,mprcnt,0);
3584
3585   return (receive_trans_response(inbuf,SMBtrans,
3586                                  rdrcnt,rprcnt,
3587                                  rdata,rparam));
3588 }
3589
3590 /****************************************************************************
3591   send a SMB trans or trans2 request
3592   ****************************************************************************/
3593 static BOOL send_trans_request(char *outbuf,int trans,
3594                                char *name,int fid,int flags,
3595                                char *data,char *param,uint16 *setup,
3596                                int ldata,int lparam,int lsetup,
3597                                int mdata,int mparam,int msetup)
3598 {
3599   int i;
3600   int this_ldata,this_lparam;
3601   int tot_data=0,tot_param=0;
3602   char *outdata,*outparam;
3603   pstring inbuf;
3604   char *p;
3605
3606   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
3607   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
3608
3609   bzero(outbuf,smb_size);
3610   set_message(outbuf,14+lsetup,0,True);
3611   CVAL(outbuf,smb_com) = trans;
3612   SSVAL(outbuf,smb_tid,cnum);
3613   setup_pkt(outbuf);
3614
3615   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
3616   outdata = outparam+this_lparam;
3617
3618   /* primary request */
3619   SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3620   SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3621   SSVAL(outbuf,smb_mprcnt,mparam);      /* mprcnt */
3622   SSVAL(outbuf,smb_mdrcnt,mdata);       /* mdrcnt */
3623   SCVAL(outbuf,smb_msrcnt,msetup);      /* msrcnt */
3624   SSVAL(outbuf,smb_flags,flags);        /* flags */
3625   SIVAL(outbuf,smb_timeout,0);          /* timeout */
3626   SSVAL(outbuf,smb_pscnt,this_lparam);  /* pscnt */
3627   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
3628   SSVAL(outbuf,smb_dscnt,this_ldata);   /* dscnt */
3629   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
3630   SCVAL(outbuf,smb_suwcnt,lsetup);      /* suwcnt */
3631   for (i=0;i<lsetup;i++)                /* setup[] */
3632     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
3633   p = smb_buf(outbuf);
3634   if (trans==SMBtrans)
3635     strcpy(p,name);                     /* name[] */
3636   else
3637     {
3638       *p++ = 0;                         /* put in a null smb_name */
3639       *p++ = 'D'; *p++ = ' ';           /* this was added because OS/2 does it */
3640     }
3641   if (this_lparam)                      /* param[] */
3642     memcpy(outparam,param,this_lparam);
3643   if (this_ldata)                       /* data[] */
3644     memcpy(outdata,data,this_ldata);
3645   set_message(outbuf,14+lsetup,         /* wcnt, bcc */
3646               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3647
3648   show_msg(outbuf);
3649   send_smb(Client,outbuf);
3650
3651   if (this_ldata < ldata || this_lparam < lparam)
3652     {
3653       /* receive interim response */
3654       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
3655         {
3656           DEBUG(0,("%s request failed (%s)\n",
3657                    trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
3658           return(False);
3659         }      
3660
3661       tot_data = this_ldata;
3662       tot_param = this_lparam;
3663
3664       while (tot_data < ldata || tot_param < lparam)
3665     {
3666           this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
3667           this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
3668
3669           set_message(outbuf,trans==SMBtrans?8:9,0,True);
3670           CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
3671
3672           outparam = smb_buf(outbuf);
3673           outdata = outparam+this_lparam;
3674
3675           /* secondary request */
3676           SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3677           SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3678           SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
3679           SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
3680           SSVAL(outbuf,smb_spsdisp,tot_param);  /* psdisp */
3681           SSVAL(outbuf,smb_sdscnt,this_ldata);  /* dscnt */
3682           SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
3683           SSVAL(outbuf,smb_sdsdisp,tot_data);   /* dsdisp */
3684           if (trans==SMBtrans2)
3685             SSVAL(outbuf,smb_sfid,fid);         /* fid */
3686           if (this_lparam)                      /* param[] */
3687             memcpy(outparam,param,this_lparam);
3688           if (this_ldata)                       /* data[] */
3689             memcpy(outdata,data,this_ldata);
3690           set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
3691                       PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3692
3693           show_msg(outbuf);
3694           send_smb(Client,outbuf);
3695
3696           tot_data += this_ldata;
3697           tot_param += this_lparam;
3698         }
3699     }
3700
3701     return(True);
3702 }
3703
3704
3705 /****************************************************************************
3706 try and browse available connections on a host
3707 ****************************************************************************/
3708 static BOOL browse_host(BOOL sort)
3709 {
3710 #ifdef NOSTRCASECMP
3711 /* If strcasecmp is already defined, remove it. */
3712 #ifdef strcasecmp
3713 #undef strcasecmp
3714 #endif /* strcasecmp */
3715 #define strcasecmp StrCaseCmp
3716 #endif /* NOSTRCASECMP */
3717
3718   extern int strcasecmp();
3719
3720   char *rparam = NULL;
3721   char *rdata = NULL;
3722   char *p;
3723   int rdrcnt,rprcnt;
3724   pstring param;
3725   int count = -1;
3726
3727   /* now send a SMBtrans command with api RNetShareEnum */
3728   p = param;
3729   SSVAL(p,0,0); /* api number */
3730   p += 2;
3731   strcpy(p,"WrLeh");
3732   p = skip_string(p,1);
3733   strcpy(p,"B13BWz");
3734   p = skip_string(p,1);
3735   SSVAL(p,0,1);
3736   SSVAL(p,2,BUFFER_SIZE);
3737   p += 4;
3738
3739   if (call_api(PTR_DIFF(p,param),0,
3740                1024,BUFFER_SIZE,
3741                &rprcnt,&rdrcnt,
3742                param,NULL,
3743                &rparam,&rdata))
3744     {
3745       int res = SVAL(rparam,0);
3746       int converter=SVAL(rparam,2);
3747       int i;
3748       BOOL long_share_name=False;
3749       
3750       if (res == 0)
3751         {
3752           count=SVAL(rparam,4);
3753           p = rdata;
3754
3755           if (count > 0)
3756             {
3757               printf("\n\tSharename      Type      Comment\n");
3758               printf("\t---------      ----      -------\n");
3759             }
3760
3761           if (sort)
3762             qsort(p,count,20,QSORT_CAST strcasecmp);
3763
3764           for (i=0;i<count;i++)
3765             {
3766               char *sname = p;
3767               int type = SVAL(p,14);
3768               int comment_offset = IVAL(p,16) & 0xFFFF;
3769               fstring typestr;
3770               *typestr=0;
3771
3772               switch (type)
3773                 {
3774                 case STYPE_DISKTREE:
3775                   strcpy(typestr,"Disk"); break;
3776                 case STYPE_PRINTQ:
3777                   strcpy(typestr,"Printer"); break;           
3778                 case STYPE_DEVICE:
3779                   strcpy(typestr,"Device"); break;
3780                 case STYPE_IPC:
3781                   strcpy(typestr,"IPC"); break;      
3782                 }
3783
3784               printf("\t%-15.15s%-10.10s%s\n",
3785                      sname,
3786                      typestr,
3787                      comment_offset?rdata+comment_offset-converter:"");
3788           
3789               if (strlen(sname)>8) long_share_name=True;
3790           
3791               p += 20;
3792             }
3793
3794           if (long_share_name) {
3795             printf("\nNOTE: There were share names longer than 8 chars.\nOn older clients these may not be accessible or may give browsing errors\n");
3796           }
3797         }
3798     }
3799   
3800   if (rparam) free(rparam);
3801   if (rdata) free(rdata);
3802
3803   return(count>0);
3804 }
3805
3806
3807 /****************************************************************************
3808 get some server info
3809 ****************************************************************************/
3810 static void server_info()
3811 {
3812   char *rparam = NULL;
3813   char *rdata = NULL;
3814   char *p;
3815   int rdrcnt,rprcnt;
3816   pstring param;
3817
3818   bzero(param,sizeof(param));
3819
3820   p = param;
3821   SSVAL(p,0,63);                /* NetServerGetInfo()? */
3822   p += 2;
3823   strcpy(p,"WrLh");
3824   p = skip_string(p,1);
3825   strcpy(p,"zzzBBzz");
3826   p = skip_string(p,1);
3827   SSVAL(p,0,10); /* level 10 */
3828   SSVAL(p,2,1000);
3829   p += 6;
3830
3831   if (call_api(PTR_DIFF(p,param),0,
3832                6,1000,
3833                &rprcnt,&rdrcnt,
3834                param,NULL,
3835                &rparam,&rdata))
3836     {
3837       int res = SVAL(rparam,0);
3838       int converter=SVAL(rparam,2);
3839
3840       if (res == 0)
3841         {
3842       p = rdata;
3843
3844       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3845              rdata+SVAL(p,0)-converter,
3846              rdata+SVAL(p,4)-converter,
3847              rdata+SVAL(p,8)-converter,
3848              rdata+SVAL(p,14)-converter);
3849     }
3850     }
3851
3852   if (rparam) free(rparam);
3853   if (rdata) free(rdata);
3854
3855   return;
3856 }
3857
3858
3859 /****************************************************************************
3860 try and browse available connections on a host
3861 ****************************************************************************/
3862 static BOOL list_servers(char *wk_grp)
3863 {
3864   char *rparam = NULL;
3865   char *rdata = NULL;
3866   int rdrcnt,rprcnt;
3867   char *p,*svtype_p;
3868   pstring param;
3869   int uLevel = 1;
3870   int count = 0;
3871   BOOL ok = False;
3872   BOOL generic_request = False;
3873
3874
3875   if (strequal(wk_grp,"WORKGROUP")) {
3876     /* we won't specify a workgroup */
3877     generic_request = True;
3878   } 
3879
3880   /* now send a SMBtrans command with api ServerEnum? */
3881   p = param;
3882   SSVAL(p,0,0x68); /* api number */
3883   p += 2;
3884
3885   strcpy(p,generic_request?"WrLehDO":"WrLehDz");
3886   p = skip_string(p,1);
3887
3888   strcpy(p,"B16BBDz");
3889
3890   p = skip_string(p,1);
3891   SSVAL(p,0,uLevel);
3892   SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
3893   p += 4;
3894
3895   svtype_p = p;
3896   p += 4;
3897
3898   if (!generic_request) {
3899     strcpy(p, wk_grp);
3900     p = skip_string(p,1);
3901   }
3902
3903   /* first ask for a list of servers in this workgroup */
3904   SIVAL(svtype_p,0,SV_TYPE_ALL);
3905
3906   if (call_api(PTR_DIFF(p+4,param),0,
3907                8,BUFFER_SIZE - SAFETY_MARGIN,
3908                &rprcnt,&rdrcnt,
3909                param,NULL,
3910                &rparam,&rdata))
3911     {
3912       int res = SVAL(rparam,0);
3913       int converter=SVAL(rparam,2);
3914       int i;
3915
3916       if (res == 0) {   
3917         char *p2 = rdata;
3918         count=SVAL(rparam,4);
3919
3920         if (count > 0) {
3921           printf("\n\nThis machine has a browse list:\n");
3922           printf("\n\tServer               Comment\n");
3923           printf("\t---------            -------\n");
3924         }
3925         
3926         for (i=0;i<count;i++) {
3927           char *sname = p2;
3928           int comment_offset = IVAL(p2,22) & 0xFFFF;
3929           printf("\t%-16.16s     %s\n",
3930                  sname,
3931                  comment_offset?rdata+comment_offset-converter:"");
3932
3933           ok=True;
3934           p2 += 26;
3935         }
3936       }
3937     }
3938
3939   if (rparam) {free(rparam); rparam = NULL;}
3940   if (rdata) {free(rdata); rdata = NULL;}
3941
3942   /* now ask for a list of workgroups */
3943   SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
3944
3945   if (call_api(PTR_DIFF(p+4,param),0,
3946                8,BUFFER_SIZE - SAFETY_MARGIN,
3947                &rprcnt,&rdrcnt,
3948                param,NULL,
3949                &rparam,&rdata))
3950     {
3951       int res = SVAL(rparam,0);
3952       int converter=SVAL(rparam,2);
3953       int i;
3954
3955       if (res == 0) {
3956         char *p2 = rdata;
3957         count=SVAL(rparam,4);
3958
3959         if (count > 0) {
3960           printf("\n\nThis machine has a workgroup list:\n");
3961           printf("\n\tWorkgroup            Master\n");
3962           printf("\t---------            -------\n");
3963         }
3964         
3965         for (i=0;i<count;i++) {
3966           char *sname = p2;
3967           int comment_offset = IVAL(p2,22) & 0xFFFF;
3968           printf("\t%-16.16s     %s\n",
3969                  sname,
3970                  comment_offset?rdata+comment_offset-converter:"");
3971           
3972           ok=True;
3973           p2 += 26;
3974         }
3975       }
3976     }
3977
3978   if (rparam) free(rparam);
3979   if (rdata) free(rdata);
3980
3981   return(ok);
3982 }
3983
3984
3985 /* This defines the commands supported by this client */
3986 struct
3987 {
3988   char *name;
3989   void (*fn)();
3990   char *description;
3991 } commands[] = 
3992 {
3993   {"ls",cmd_dir,"<mask> list the contents of the current directory"},
3994   {"dir",cmd_dir,"<mask> list the contents of the current directory"},
3995   {"lcd",cmd_lcd,"[directory] change/report the local current working directory"},
3996   {"cd",cmd_cd,"[directory] change/report the remote directory"},
3997   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
3998   {"get",cmd_get,"<remote name> [local name] get a file"},
3999   {"mget",cmd_mget,"<mask> get all the matching files"},
4000   {"put",cmd_put,"<local name> [remote name] put a file"},
4001   {"mput",cmd_mput,"<mask> put all matching files"},
4002   {"rename",cmd_rename,"<src> <dest> rename some files"},
4003   {"more",cmd_more,"<remote name> view a remote file with your pager"},  
4004   {"mask",cmd_select,"<mask> mask all filenames against this"},
4005   {"del",cmd_del,"<mask> delete all matching files"},
4006   {"rm",cmd_del,"<mask> delete all matching files"},
4007   {"mkdir",cmd_mkdir,"<directory> make a directory"},
4008   {"md",cmd_mkdir,"<directory> make a directory"},
4009   {"rmdir",cmd_rmdir,"<directory> remove a directory"},
4010   {"rd",cmd_rmdir,"<directory> remove a directory"},
4011   {"pq",cmd_p_queue_4,"enumerate the print queue"},
4012   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},  
4013   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},  
4014   {"translate",cmd_translate,"toggle text translation for printing"},  
4015   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},  
4016   {"print",cmd_print,"<file name> print a file"},
4017   {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
4018   {"queue",cmd_queue,"show the print queue"},
4019   {"qinfo",cmd_qinfo,"show print queue information"},
4020   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
4021   {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
4022   {"quit",send_logout,"logoff the server"},
4023   {"q",send_logout,"logoff the server"},
4024   {"exit",send_logout,"logoff the server"},
4025   {"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
4026   {"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"},
4027   {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
4028   {"blocksize",cmd_block,"blocksize <number> (default 20)" },
4029   {"tarmode",cmd_tarmode,
4030      "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
4031   {"setmode",cmd_setmode,"filename <setmode string> change modes of file"},
4032   {"help",cmd_help,"[command] give help on a command"},
4033   {"?",cmd_help,"[command] give help on a command"},
4034   {"!",NULL,"run a shell command on the local system"},
4035   {"",NULL,NULL}
4036 };
4037
4038
4039 /*******************************************************************
4040   lookup a command string in the list of commands, including 
4041   abbreviations
4042   ******************************************************************/
4043 static int process_tok(fstring tok)
4044 {
4045   int i = 0, matches = 0;
4046   int cmd=0;
4047   int tok_len = strlen(tok);
4048   
4049   while (commands[i].fn != NULL)
4050     {
4051       if (strequal(commands[i].name,tok))
4052         {
4053           matches = 1;
4054           cmd = i;
4055           break;
4056         }
4057       else if (strnequal(commands[i].name, tok, tok_len+1))
4058         {
4059           matches++;
4060           cmd = i;
4061         }
4062       i++;
4063     }
4064   
4065   if (matches == 0)
4066     return(-1);
4067   else if (matches == 1)
4068     return(cmd);
4069   else
4070     return(-2);
4071 }
4072
4073 /****************************************************************************
4074 help
4075 ****************************************************************************/
4076 void cmd_help(void)
4077 {
4078   int i=0,j;
4079   fstring buf;
4080
4081   if (next_token(NULL,buf,NULL))
4082     {
4083       if ((i = process_tok(buf)) >= 0)
4084         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
4085     }
4086   else
4087     while (commands[i].description)
4088       {
4089         for (j=0; commands[i].description && (j<5); j++) {
4090           DEBUG(0,("%-15s",commands[i].name));
4091           i++;
4092         }
4093         DEBUG(0,("\n"));
4094       }
4095 }
4096
4097 /****************************************************************************
4098 open the client sockets
4099 ****************************************************************************/
4100 static BOOL open_sockets(int port )
4101 {
4102   static int last_port;
4103   char *host;
4104   pstring service2;
4105   extern int Client;
4106 #ifdef USENMB
4107   BOOL failed = True;
4108 #endif
4109
4110   if (port == 0) port=last_port;
4111   last_port=port;
4112
4113   strupper(service);
4114
4115   if (*desthost)
4116     {
4117       host = desthost;
4118     }
4119   else
4120     {
4121       strcpy(service2,service);
4122       host = strtok(service2,"\\/");
4123       if (!host) {
4124         DEBUG(0,("Badly formed host name\n"));
4125         return(False);
4126       }
4127       strcpy(desthost,host);
4128     }
4129
4130   if (!(*myname)) {
4131       get_myname(myname,NULL);
4132   }
4133   strupper(myname);
4134
4135   DEBUG(3,("Opening sockets\n"));
4136
4137   if (!have_ip)
4138     {
4139       struct hostent *hp;
4140
4141       if ((hp = Get_Hostbyname(host))) {
4142         putip((char *)&dest_ip,(char *)hp->h_addr);
4143         failed = False;
4144       } else {
4145 #ifdef USENMB
4146         /* Try and resolve the name with the netbios server */
4147         int             bcast;
4148
4149         if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3,
4150                                     interpret_addr(lp_socket_address()))) != -1) {
4151           set_socket_options(bcast, "SO_BROADCAST");
4152
4153           if (name_query(bcast, host, name_type, True, True, *iface_bcast(dest_ip),
4154                          &dest_ip,0)) {
4155             failed = False;
4156           }
4157           close (bcast);
4158         }
4159 #endif
4160         if (failed) {
4161           DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
4162           return False;
4163         }
4164       }
4165     }
4166
4167   Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
4168   if (Client == -1)
4169     return False;
4170
4171   DEBUG(3,("Connected\n"));
4172   
4173   set_socket_options(Client,user_socket_options);  
4174   
4175   return True;
4176 }
4177
4178 /****************************************************************************
4179 wait for keyboard activity, swallowing network packets
4180 ****************************************************************************/
4181 #ifdef CLIX
4182 static char wait_keyboard(char *buffer)
4183 #else
4184 static void wait_keyboard(char *buffer)
4185 #endif
4186 {
4187   fd_set fds;
4188   int selrtn;
4189   struct timeval timeout;
4190   
4191 #ifdef CLIX
4192   int delay = 0;
4193 #endif
4194   
4195   while (1) 
4196     {
4197       extern int Client;
4198       FD_ZERO(&fds);
4199       FD_SET(Client,&fds);
4200 #ifndef CLIX
4201       FD_SET(fileno(stdin),&fds);
4202 #endif
4203
4204       timeout.tv_sec = 20;
4205       timeout.tv_usec = 0;
4206 #ifdef CLIX
4207       timeout.tv_sec = 0;
4208 #endif
4209       selrtn = sys_select(&fds,&timeout);
4210       
4211 #ifndef CLIX
4212       if (FD_ISSET(fileno(stdin),&fds))
4213         return;
4214 #else
4215       {
4216         char ch;
4217         int readret;
4218
4219     set_blocking(fileno(stdin), False); 
4220         readret = read_data( fileno(stdin), &ch, 1);
4221         set_blocking(fileno(stdin), True);
4222         if (readret == -1)
4223           {
4224             if (errno != EAGAIN)
4225               {
4226                 /* should crash here */
4227                 DEBUG(1,("readchar stdin failed\n"));
4228               }
4229           }
4230         else if (readret != 0)
4231           {
4232             return ch;
4233           }
4234       }
4235 #endif
4236       if (FD_ISSET(Client,&fds))
4237         receive_smb(Client,buffer,0);
4238       
4239 #ifdef CLIX
4240       delay++;
4241       if (delay > 100000)
4242         {
4243           delay = 0;
4244           chkpath("\\",False);
4245         }
4246 #else
4247       chkpath("\\",False);
4248 #endif
4249     }  
4250 }
4251
4252
4253 /****************************************************************************
4254 close and open the connection again
4255 ****************************************************************************/
4256 BOOL reopen_connection(char *inbuf,char *outbuf)
4257 {
4258   static int open_count=0;
4259
4260   open_count++;
4261
4262   if (open_count>5) return(False);
4263
4264   DEBUG(1,("Trying to re-open connection\n"));
4265
4266   set_message(outbuf,0,0,True);
4267   SCVAL(outbuf,smb_com,SMBtdis);
4268   SSVAL(outbuf,smb_tid,cnum);
4269   setup_pkt(outbuf);
4270
4271   send_smb(Client,outbuf);
4272   receive_smb(Client,inbuf,SHORT_TIMEOUT);
4273
4274   close_sockets();
4275   if (!open_sockets(0)) return(False);
4276
4277   return(send_login(inbuf,outbuf,True,True));
4278 }
4279
4280 /****************************************************************************
4281   process commands from the client
4282 ****************************************************************************/
4283 static BOOL process(char *base_directory)
4284 {
4285   extern FILE *dbf;
4286   pstring line;
4287   char *cmd;
4288
4289   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4290   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4291
4292   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4293     return(False);
4294   
4295   bzero(OutBuffer,smb_size);
4296
4297   if (!send_login(InBuffer,OutBuffer,True,True))
4298     return(False);
4299
4300   if (*base_directory) do_cd(base_directory);
4301
4302   cmd = cmdstr;
4303   if (cmd[0] != '\0') while (cmd[0] != '\0')
4304     {
4305       char *p;
4306       fstring tok;
4307       int i;
4308
4309       if ((p = strchr(cmd, ';')) == 0)
4310         {
4311           strncpy(line, cmd, 999);
4312           line[1000] = '\0';
4313           cmd += strlen(cmd);
4314         }
4315       else
4316         {
4317           if (p - cmd > 999) p = cmd + 999;
4318           strncpy(line, cmd, p - cmd);
4319           line[p - cmd] = '\0';
4320           cmd = p + 1;
4321         }
4322
4323       /* input language code to internal one */
4324       CNV_INPUT (line);
4325       
4326       /* and get the first part of the command */
4327       {
4328         char *ptr = line;
4329         if (!next_token(&ptr,tok,NULL)) continue;
4330       }
4331
4332       if ((i = process_tok(tok)) >= 0)
4333         commands[i].fn(InBuffer,OutBuffer);
4334       else if (i == -2)
4335         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4336       else
4337         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4338     }
4339   else while (!feof(stdin))
4340     {
4341       fstring tok;
4342       int i;
4343
4344       bzero(OutBuffer,smb_size);
4345
4346       /* display a prompt */
4347       DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
4348       fflush(dbf);
4349
4350 #ifdef CLIX
4351       line[0] = wait_keyboard(InBuffer);
4352       /* this might not be such a good idea... */
4353       if ( line[0] == EOF)
4354         break;
4355 #else
4356       wait_keyboard(InBuffer);
4357 #endif
4358   
4359       /* and get a response */
4360 #ifdef CLIX
4361       fgets( &line[1],999, stdin);
4362 #else
4363       if (!fgets(line,1000,stdin))
4364         break;
4365 #endif
4366
4367       /* input language code to internal one */
4368       CNV_INPUT (line);
4369
4370       /* special case - first char is ! */
4371       if (*line == '!')
4372         {
4373           system(line + 1);
4374           continue;
4375         }
4376       
4377       /* and get the first part of the command */
4378       {
4379         char *ptr = line;
4380         if (!next_token(&ptr,tok,NULL)) continue;
4381       }
4382
4383       if ((i = process_tok(tok)) >= 0)
4384         commands[i].fn(InBuffer,OutBuffer);
4385       else if (i == -2)
4386         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4387       else
4388         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4389     }
4390   
4391   send_logout();
4392   return(True);
4393 }
4394
4395
4396 /****************************************************************************
4397 usage on the program
4398 ****************************************************************************/
4399 static void usage(char *pname)
4400 {
4401   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
4402            pname));
4403
4404   DEBUG(0,("\nVersion %s\n",VERSION));
4405   DEBUG(0,("\t-p port               listen on the specified port\n"));
4406   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
4407   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
4408   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
4409   DEBUG(0,("\t-N                    don't ask for a password\n"));
4410   DEBUG(0,("\t-P                    connect to service as a printer\n"));
4411   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
4412   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
4413   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
4414   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
4415   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
4416   DEBUG(0,("\t-U username           set the network username\n"));
4417   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
4418   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
4419   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
4420   DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
4421   DEBUG(0,("\t-D directory          start from directory\n"));
4422   DEBUG(0,("\n"));
4423 }
4424
4425 /****************************************************************************
4426   main program
4427 ****************************************************************************/
4428  int main(int argc,char *argv[])
4429 {
4430   fstring base_directory;
4431   char *pname = argv[0];
4432   int port = SMB_PORT;
4433   int opt;
4434   extern FILE *dbf;
4435   extern char *optarg;
4436   extern int optind;
4437   pstring query_host;
4438   BOOL message = False;
4439   extern char tar_type;
4440   static pstring servicesf = CONFIGFILE;
4441   pstring term_code;
4442   char *p;
4443
4444 #ifdef KANJI
4445   strcpy(term_code, KANJI);
4446 #else /* KANJI */
4447   *term_code = 0;
4448 #endif /* KANJI */
4449
4450   *query_host = 0;
4451   *base_directory = 0;
4452
4453   DEBUGLEVEL = 2;
4454
4455   setup_logging(pname,True);
4456
4457   TimeInit();
4458   charset_initialise();
4459
4460   pid = getpid();
4461   uid = getuid();
4462   gid = getgid();
4463   mid = pid + 100;
4464   myumask = umask(0);
4465   umask(myumask);
4466
4467   if (getenv("USER"))
4468   {
4469     strcpy(username,getenv("USER"));
4470
4471     /* modification to support userid%passwd syntax in the USER var
4472        25.Aug.97, jdblair@uab.edu */
4473
4474     if ((p=strchr(username,'%')))
4475     {
4476       *p = 0;
4477       strcpy(password,p+1);
4478       got_pass = True;
4479       memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
4480     }
4481     strupper(username);
4482   }
4483
4484  /* modification to support PASSWD environmental var
4485   25.Aug.97, jdblair@uab.edu */
4486
4487   if (getenv("PASSWD"))
4488     strcpy(password,getenv("PASSWD"));
4489
4490   if (*username == 0 && getenv("LOGNAME"))
4491     {
4492       strcpy(username,getenv("LOGNAME"));
4493       strupper(username);
4494     }
4495
4496   if (argc < 2)
4497     {
4498       usage(pname);
4499       exit(1);
4500     }
4501   
4502   if (*argv[1] != '-')
4503     {
4504
4505       strcpy(service,argv[1]);  
4506       /* Convert any '/' characters in the service name to '\' characters */
4507       string_replace( service, '/','\\');
4508       argc--;
4509       argv++;
4510
4511       if (count_chars(service,'\\') < 3)
4512         {
4513           usage(pname);
4514           printf("\n%s: Not enough '\\' characters in service\n",service);
4515           exit(1);
4516         }
4517
4518 /*
4519       if (count_chars(service,'\\') > 3)
4520         {
4521           usage(pname);
4522           printf("\n%s: Too many '\\' characters in service\n",service);
4523           exit(1);
4524         }
4525         */
4526
4527       if (argc > 1 && (*argv[1] != '-'))
4528         {
4529           got_pass = True;
4530           strcpy(password,argv[1]);  
4531           memset(argv[1],'X',strlen(argv[1]));
4532           argc--;
4533           argv++;
4534         }
4535     }
4536
4537   while ((opt = 
4538           getopt(argc, argv,"s:B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
4539     switch (opt)
4540       {
4541       case 'm':
4542         max_protocol = interpret_protocol(optarg,max_protocol);
4543         break;
4544       case 'O':
4545         strcpy(user_socket_options,optarg);
4546         break;  
4547       case 'M':
4548         name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
4549         strcpy(desthost,optarg);
4550         strupper(desthost);
4551         message = True;
4552         break;
4553       case 'B':
4554         iface_set_default(NULL,optarg,NULL);
4555         break;
4556       case 'D':
4557         strcpy(base_directory,optarg);
4558         break;
4559       case 'T':
4560         if (!tar_parseargs(argc, argv, optarg, optind)) {
4561           usage(pname);
4562           exit(1);
4563         }
4564         break;
4565       case 'i':
4566         strcpy(scope,optarg);
4567         break;
4568       case 'L':
4569         got_pass = True;
4570         strcpy(query_host,optarg);
4571         break;
4572       case 'U':
4573         {
4574           char *lp;
4575         strcpy(username,optarg);
4576         if ((lp=strchr(username,'%')))
4577           {
4578             *lp = 0;
4579             strcpy(password,lp+1);
4580             got_pass = True;
4581             memset(strchr(optarg,'%')+1,'X',strlen(password));
4582           }
4583         }
4584             
4585         break;
4586       case 'W':
4587         strcpy(workgroup,optarg);
4588         break;
4589       case 'E':
4590         dbf = stderr;
4591         break;
4592       case 'I':
4593         {
4594           dest_ip = *interpret_addr2(optarg);
4595           if (zero_ip(dest_ip)) exit(1);
4596           have_ip = True;
4597         }
4598         break;
4599       case 'n':
4600         strcpy(myname,optarg);
4601         break;
4602       case 'N':
4603         got_pass = True;
4604         break;
4605       case 'P':
4606         connect_as_printer = True;
4607         break;
4608       case 'd':
4609         if (*optarg == 'A')
4610           DEBUGLEVEL = 10000;
4611         else
4612           DEBUGLEVEL = atoi(optarg);
4613         break;
4614       case 'l':
4615         sprintf(debugf,"%s.client",optarg);
4616         break;
4617       case 'p':
4618         port = atoi(optarg);
4619         break;
4620       case 'c':
4621         cmdstr = optarg;
4622         got_pass = True;
4623         break;
4624       case 'h':
4625         usage(pname);
4626         exit(0);
4627         break;
4628       case 's':
4629         strcpy(servicesf, optarg);
4630         break;
4631       case 't':
4632         strcpy(term_code, optarg);
4633         break;
4634       default:
4635         usage(pname);
4636         exit(1);
4637       }
4638
4639   if (!tar_type && !*query_host && !*service && !message)
4640     {
4641       usage(pname);
4642       exit(1);
4643     }
4644
4645
4646   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
4647
4648   if(!get_myname(myhostname,NULL))
4649   {
4650     DEBUG(0,("Failed to get my hostname.\n"));
4651   }
4652
4653   if (!lp_load(servicesf,True)) {
4654     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
4655   }
4656
4657   codepage_initialise(lp_client_code_page());
4658
4659   if(lp_client_code_page() == KANJI_CODEPAGE)
4660   {
4661         if (!setup_term_code (term_code))
4662     {
4663             DEBUG(0, ("%s: unknown terminal code name\n", optarg));
4664             usage (pname);
4665             exit (1);
4666         }
4667   }
4668
4669   if (*workgroup == 0)
4670     strcpy(workgroup,lp_workgroup());
4671
4672   load_interfaces();
4673   get_myname((*myname)?NULL:myname,NULL);  
4674   strupper(myname);
4675
4676   if (tar_type) {
4677     recurse=True;
4678
4679     if (open_sockets(port)) {
4680         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4681         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4682         int ret;
4683
4684         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4685           return(1);
4686
4687         bzero(OutBuffer,smb_size);
4688         if (!send_login(InBuffer,OutBuffer,True,True))
4689           return(False);
4690
4691         if (*base_directory) do_cd(base_directory);
4692
4693         ret=process_tar(InBuffer, OutBuffer);
4694
4695         send_logout();
4696         close_sockets();
4697         return(ret);
4698     } else
4699       return(1);
4700   }
4701   
4702   if (*query_host)
4703     {
4704       int ret = 0;
4705       sprintf(service,"\\\\%s\\IPC$",query_host);
4706       strupper(service);
4707       connect_as_ipc = True;
4708       if (open_sockets(port))
4709         {
4710 #if 0
4711           *username = 0;
4712 #endif
4713           if (!send_login(NULL,NULL,True,True))
4714             return(1);
4715
4716           server_info();
4717           if (!browse_host(True)) {
4718             sleep(1);
4719             browse_host(True);
4720           }
4721           if (!list_servers(workgroup)) {
4722             sleep(1);
4723             list_servers(workgroup);
4724           }
4725
4726           send_logout();
4727           close_sockets();
4728         }
4729
4730       return(ret);
4731     }
4732
4733   if (message)
4734     {
4735       int ret = 0;
4736       if (open_sockets(port))
4737         {
4738           pstring inbuf,outbuf;
4739           bzero(outbuf,smb_size);
4740           if (!send_session_request(inbuf,outbuf))
4741             return(1);
4742
4743           send_message(inbuf,outbuf);
4744
4745           close_sockets();
4746         }
4747
4748       return(ret);
4749     }
4750
4751   if (open_sockets(port))
4752     {
4753       if (!process(base_directory))
4754         {
4755           close_sockets();
4756           return(1);
4757         }
4758       close_sockets();
4759     }
4760   else
4761     return(1);
4762
4763   return(0);
4764 }
4765
4766
4767 /* error code stuff - put together by Merik Karman
4768    merik@blackadder.dsh.oz.au */
4769
4770 typedef struct
4771 {
4772   char *name;
4773   int code;
4774   char *message;
4775 } err_code_struct;
4776
4777 /* Dos Error Messages */
4778 err_code_struct dos_msgs[] = {
4779   {"ERRbadfunc",1,"Invalid function."},
4780   {"ERRbadfile",2,"File not found."},
4781   {"ERRbadpath",3,"Directory invalid."},
4782   {"ERRnofids",4,"No file descriptors available"},
4783   {"ERRnoaccess",5,"Access denied."},
4784   {"ERRbadfid",6,"Invalid file handle."},
4785   {"ERRbadmcb",7,"Memory control blocks destroyed."},
4786   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
4787   {"ERRbadmem",9,"Invalid memory block address."},
4788   {"ERRbadenv",10,"Invalid environment."},
4789   {"ERRbadformat",11,"Invalid format."},
4790   {"ERRbadaccess",12,"Invalid open mode."},
4791   {"ERRbaddata",13,"Invalid data."},
4792   {"ERR",14,"reserved."},
4793   {"ERRbaddrive",15,"Invalid drive specified."},
4794   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
4795   {"ERRdiffdevice",17,"Not same device."},
4796   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
4797   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
4798   {"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."},
4799   {"ERRnosuchshare", 67, "You specified an invalid share name"},
4800   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
4801   {"ERRbadpipe",230,"Pipe invalid."},
4802   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
4803   {"ERRpipeclosing",232,"Pipe close in progress."},
4804   {"ERRnotconnected",233,"No process on other end of pipe."},
4805   {"ERRmoredata",234,"There is more data to be returned."},
4806   {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
4807   {NULL,-1,NULL}};
4808
4809 /* Server Error Messages */
4810 err_code_struct server_msgs[] = {
4811   {"ERRerror",1,"Non-specific error code."},
4812   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
4813   {"ERRbadtype",3,"reserved."},
4814   {"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."},
4815   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
4816   {"ERRinvnetname",6,"Invalid network name in tree connect."},
4817   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
4818   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
4819   {"ERRqtoobig",50,"Print queue full -- no space."},
4820   {"ERRqeof",51,"EOF on print queue dump."},
4821   {"ERRinvpfid",52,"Invalid print file FID."},
4822   {"ERRsmbcmd",64,"The server did not recognize the command received."},
4823   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
4824   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
4825   {"ERRreserved",68,"reserved."},
4826   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
4827   {"ERRreserved",70,"reserved."},
4828   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
4829   {"ERRpaused",81,"Server is paused."},
4830   {"ERRmsgoff",82,"Not receiving messages."},
4831   {"ERRnoroom",83,"No room to buffer message."},
4832   {"ERRrmuns",87,"Too many remote user names."},
4833   {"ERRtimeout",88,"Operation timed out."},
4834   {"ERRnoresource",89,"No resources currently available for request."},
4835   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
4836   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
4837   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
4838   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
4839   {"ERRcontmpx",252,"Continue in MPX mode."},
4840   {"ERRreserved",253,"reserved."},
4841   {"ERRreserved",254,"reserved."},
4842   {"ERRnosupport",0xFFFF,"Function not supported."},
4843   {NULL,-1,NULL}};
4844
4845 /* Hard Error Messages */
4846 err_code_struct hard_msgs[] = {
4847   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
4848   {"ERRbadunit",20,"Unknown unit."},
4849   {"ERRnotready",21,"Drive not ready."},
4850   {"ERRbadcmd",22,"Unknown command."},
4851   {"ERRdata",23,"Data error (CRC)."},
4852   {"ERRbadreq",24,"Bad request structure length."},
4853   {"ERRseek",25 ,"Seek error."},
4854   {"ERRbadmedia",26,"Unknown media type."},
4855   {"ERRbadsector",27,"Sector not found."},
4856   {"ERRnopaper",28,"Printer out of paper."},
4857   {"ERRwrite",29,"Write fault."},
4858   {"ERRread",30,"Read fault."},
4859   {"ERRgeneral",31,"General failure."},
4860   {"ERRbadshare",32,"An open conflicts with an existing open."},
4861   {"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."},
4862   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
4863   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
4864   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
4865   {NULL,-1,NULL}};
4866
4867
4868 struct
4869 {
4870   int code;
4871   char *class;
4872   err_code_struct *err_msgs;
4873 } err_classes[] = { 
4874   {0,"SUCCESS",NULL},
4875   {0x01,"ERRDOS",dos_msgs},
4876   {0x02,"ERRSRV",server_msgs},
4877   {0x03,"ERRHRD",hard_msgs},
4878   {0x04,"ERRXOS",NULL},
4879   {0xE1,"ERRRMX1",NULL},
4880   {0xE2,"ERRRMX2",NULL},
4881   {0xE3,"ERRRMX3",NULL},
4882   {0xFF,"ERRCMD",NULL},
4883   {-1,NULL,NULL}};
4884
4885
4886 /****************************************************************************
4887 return a SMB error string from a SMB buffer
4888 ****************************************************************************/
4889 char *smb_errstr(char *inbuf)
4890 {
4891   static pstring ret;
4892   int class = CVAL(inbuf,smb_rcls);
4893   int num = SVAL(inbuf,smb_err);
4894   int i,j;
4895
4896   for (i=0;err_classes[i].class;i++)
4897     if (err_classes[i].code == class)
4898       {
4899         if (err_classes[i].err_msgs)
4900           {
4901             err_code_struct *err = err_classes[i].err_msgs;
4902             for (j=0;err[j].name;j++)
4903               if (num == err[j].code)
4904                 {
4905                   if (DEBUGLEVEL > 0)
4906                     sprintf(ret,"%s - %s (%s)",err_classes[i].class,
4907                             err[j].name,err[j].message);
4908                   else
4909                     sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
4910                   return ret;
4911                 }
4912           }
4913
4914         sprintf(ret,"%s - %d",err_classes[i].class,num);
4915         return ret;
4916       }
4917   
4918   sprintf(ret,"Error: Unknown error (%d,%d)",class,num);
4919   return(ret);
4920 }