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