Small update to clitar.c to omit warnings about servers not
[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-1998
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 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 #ifndef REGISTER
27 #define REGISTER 0
28 #endif
29
30 pstring cur_dir = "\\";
31 pstring cd_path = "";
32 extern pstring service;
33 extern pstring desthost;
34 extern pstring global_myname;
35 extern pstring myhostname;
36 extern pstring password;
37 extern pstring username;
38 extern pstring workgroup;
39 char *cmdstr="";
40 extern BOOL got_pass;
41 extern BOOL no_pass;
42 extern BOOL connect_as_printer;
43 extern BOOL connect_as_ipc;
44 extern struct in_addr ipzero;
45
46 extern BOOL doencrypt;
47
48 extern pstring user_socket_options;
49
50 static int process_tok(fstring tok);
51 static void cmd_help(char *dum_in, char *dum_out);
52
53 /* 30 second timeout on most commands */
54 #define CLIENT_TIMEOUT (30*1000)
55 #define SHORT_TIMEOUT (5*1000)
56
57 /* value for unused fid field in trans2 secondary request */
58 #define FID_UNUSED (0xFFFF)
59
60 extern int name_type;
61
62 extern int max_protocol;
63
64
65 time_t newer_than = 0;
66 int archive_level = 0;
67
68 extern pstring debugf;
69 extern int DEBUGLEVEL;
70
71 BOOL translation = False;
72
73 extern int cnum;
74 extern int mid;
75 extern int pid;
76 extern int tid;
77 extern int gid;
78 extern int uid;
79
80 extern BOOL have_ip;
81 extern int max_xmit;
82
83 static int interpret_long_filename(int level,char *p,file_info *finfo);
84 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo);
85 static int interpret_short_filename(char *p,file_info *finfo);
86 static BOOL do_this_one(file_info *finfo);
87
88 /* clitar bits insert */
89 extern int blocksize;
90 extern BOOL tar_inc;
91 extern BOOL tar_reset;
92 /* clitar bits end */
93  
94
95 int myumask = 0755;
96
97 extern pstring scope;
98
99 BOOL prompt = True;
100
101 int printmode = 1;
102
103 BOOL recurse = False;
104 BOOL lowercase = False;
105
106 struct in_addr dest_ip;
107
108 #define SEPARATORS " \t\n\r"
109
110 BOOL abort_mget = True;
111
112 extern int Protocol;
113
114 extern BOOL readbraw_supported ;
115 extern BOOL writebraw_supported;
116
117 pstring fileselection = "";
118
119 extern file_info def_finfo;
120
121 /* timing globals */
122 int get_total_size = 0;
123 int get_total_time_ms = 0;
124 int put_total_size = 0;
125 int put_total_time_ms = 0;
126
127 /* totals globals */
128 int dir_total = 0;
129
130 extern int Client;
131
132 #define USENMB
133
134 #define CNV_LANG(s) dos_to_unix(s,False)
135 #define CNV_INPUT(s) unix_to_dos(s,True)
136
137 /****************************************************************************
138 send an SMBclose on an SMB file handle
139 ****************************************************************************/
140 static void cli_smb_close(char *inbuf, char *outbuf, int clnt_fd, int c_num, int f_num)
141 {
142   bzero(outbuf,smb_size);
143   set_message(outbuf,3,0,True);
144
145   CVAL (outbuf,smb_com) = SMBclose;
146   SSVAL(outbuf,smb_tid,c_num);
147   cli_setup_pkt(outbuf);
148   SSVAL (outbuf,smb_vwv0, f_num);
149   SIVALS(outbuf,smb_vwv1, -1);
150   
151   send_smb(clnt_fd, outbuf);
152   client_receive_smb(clnt_fd,inbuf,CLIENT_TIMEOUT);
153 }
154
155
156 /****************************************************************************
157 write to a local file with CR/LF->LF translation if appropriate. return the 
158 number taken from the buffer. This may not equal the number written.
159 ****************************************************************************/
160 static int writefile(int f, char *b, int n)
161 {
162   int i;
163
164   if (!translation)
165     return(write(f,b,n));
166   
167   i = 0;
168   while (i < n)
169     {
170       if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n')
171         {
172           b++;i++;
173         }
174       if (write(f, b, 1) != 1)
175         {
176           break;
177         }
178       b++;
179       i++;
180     }
181   
182   return(i);
183 }
184
185 /****************************************************************************
186   read from a file with LF->CR/LF translation if appropriate. return the 
187   number read. read approx n bytes.
188 ****************************************************************************/
189 static int readfile(char *b, int size, int n, FILE *f)
190 {
191   int i;
192   int c;
193
194   if (!translation || (size != 1))
195     return(fread(b,size,n,f));
196   
197   i = 0;
198   while (i < n)
199     {
200       if ((c = getc(f)) == EOF)
201         {
202           break;
203         }
204       
205       if (c == '\n') /* change all LFs to CR/LF */
206         {
207           b[i++] = '\r';
208           n++;
209         }
210       
211       if(i < n)
212         b[i++] = c;
213     }
214   
215   return(i);
216 }
217  
218
219 /****************************************************************************
220 read from a file with print translation. return the number read. read approx n
221 bytes.
222 ****************************************************************************/
223 static int printread(FILE *f,char *b,int n)
224 {
225   int i;
226
227   i = readfile(b,1, n-1,f);
228 #if FORMFEED
229   if (feof(f) && i>0)
230     b[i++] = '\014';
231 #endif
232
233   return(i);
234 }
235
236 /****************************************************************************
237 check for existance of a dir
238 ****************************************************************************/
239 static BOOL chkpath(char *path,BOOL report)
240 {
241   fstring path2;
242   pstring inbuf,outbuf;
243   char *p;
244
245   fstrcpy(path2,path);
246   trim_string(path2,NULL,"\\");
247   if (!*path2) *path2 = '\\';
248
249   bzero(outbuf,smb_size);
250   set_message(outbuf,0,4 + strlen(path2),True);
251   SCVAL(outbuf,smb_com,SMBchkpth);
252   SSVAL(outbuf,smb_tid,cnum);
253   cli_setup_pkt(outbuf);
254
255   p = smb_buf(outbuf);
256   *p++ = 4;
257   fstrcpy(p,path2);
258
259 #if 0
260   {
261           /* this little bit of code can be used to extract NT error codes.
262              Just feed a bunch of "cd foo" commands to smbclient then watch
263              in netmon (tridge) */
264           static int code=0;
265           SIVAL(outbuf, smb_rcls, code | 0xC0000000);
266           SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
267           code++;
268   }
269 #endif
270
271   send_smb(Client,outbuf);
272   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
273
274   if (report && CVAL(inbuf,smb_rcls) != 0)
275     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
276
277   return(CVAL(inbuf,smb_rcls) == 0);
278 }
279
280
281 /****************************************************************************
282 send a message
283 ****************************************************************************/
284 static void send_message(char *inbuf,char *outbuf)
285 {
286   int total_len = 0;
287
288   char *p;
289   int grp_id;
290
291   /* send a SMBsendstrt command */
292   bzero(outbuf,smb_size);
293   set_message(outbuf,0,0,True);
294   CVAL(outbuf,smb_com) = SMBsendstrt;
295   SSVAL(outbuf,smb_tid,cnum);
296
297   p = smb_buf(outbuf);
298   *p++ = 4;
299   pstrcpy(p,username);
300   p = skip_string(p,1);
301   *p++ = 4;
302   pstrcpy(p,desthost);
303   p = skip_string(p,1);
304
305   set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
306
307   send_smb(Client,outbuf);
308   
309
310   if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
311     {
312       printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
313       return;
314     }
315
316   grp_id = SVAL(inbuf,smb_vwv0);
317
318   printf("Connected. Type your message, ending it with a Control-D\n");
319
320   while (!feof(stdin) && total_len < 1600)
321     {
322       int maxlen = MIN(1600 - total_len,127);
323       pstring msg;
324       int l=0;
325       int c;
326
327       bzero(msg,smb_size);
328
329       for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++)
330         {
331           if (c == '\n')
332             msg[l++] = '\r';
333           msg[l] = c;   
334         }
335
336       CVAL(outbuf,smb_com) = SMBsendtxt;
337
338       set_message(outbuf,1,l+3,True);
339
340       SSVAL(outbuf,smb_vwv0,grp_id);
341
342       p = smb_buf(outbuf);
343       *p = 1;
344       SSVAL(p,1,l);
345       memcpy(p+3,msg,l);
346
347       send_smb(Client,outbuf);
348       
349
350       if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
351         {
352           printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
353           return;
354         }      
355
356       total_len += l;
357     }
358
359   if (total_len >= 1600)
360     printf("the message was truncated to 1600 bytes ");
361   else
362     printf("sent %d bytes ",total_len);
363
364   printf("(status was %d-%d)\n",CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err));
365
366   CVAL(outbuf,smb_com) = SMBsendend;
367   set_message(outbuf,1,0,False);
368   SSVAL(outbuf,smb_vwv0,grp_id);
369
370   send_smb(Client,outbuf);
371   
372
373   if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
374     {
375       printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
376       return;
377     }      
378 }
379
380
381
382 /****************************************************************************
383 check the space on a device
384 ****************************************************************************/
385 static void do_dskattr(void)
386 {
387   pstring inbuf,outbuf;
388
389   bzero(outbuf,smb_size);
390   set_message(outbuf,0,0,True);
391   CVAL(outbuf,smb_com) = SMBdskattr;
392   SSVAL(outbuf,smb_tid,cnum);
393   cli_setup_pkt(outbuf);
394
395   send_smb(Client,outbuf);
396   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
397
398   if (CVAL(inbuf,smb_rcls) != 0) 
399     DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));      
400
401   DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n",
402         SVAL(inbuf,smb_vwv0),
403         SVAL(inbuf,smb_vwv1)*SVAL(inbuf,smb_vwv2),
404         SVAL(inbuf,smb_vwv3)));
405 }
406
407 /****************************************************************************
408 show cd/pwd
409 ****************************************************************************/
410 static void cmd_pwd(char *dum_in, char *dum_out)
411 {
412   DEBUG(0,("Current directory is %s",CNV_LANG(service)));
413   DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
414 }
415
416
417 /****************************************************************************
418 change directory - inner section
419 ****************************************************************************/
420 static void do_cd(char *newdir)
421 {
422   char *p = newdir;
423   pstring saved_dir;
424   pstring dname;
425       
426   /* Save the current directory in case the
427      new directory is invalid */
428   pstrcpy(saved_dir, cur_dir);
429   if (*p == '\\')
430     pstrcpy(cur_dir,p);
431   else
432     pstrcat(cur_dir,p);
433   if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
434     pstrcat(cur_dir, "\\");
435   }
436   dos_clean_name(cur_dir);
437   pstrcpy(dname,cur_dir);
438   pstrcat(cur_dir,"\\");
439   dos_clean_name(cur_dir);
440
441   if (!strequal(cur_dir,"\\"))
442     if (!chkpath(dname,True))
443       pstrcpy(cur_dir,saved_dir);
444
445   pstrcpy(cd_path,cur_dir);
446 }
447
448 /****************************************************************************
449 change directory
450 ****************************************************************************/
451 static void cmd_cd(char *inbuf,char *outbuf)
452 {
453   fstring buf;
454
455   if (next_token(NULL,buf,NULL,sizeof(buf)))
456     do_cd(buf);
457   else
458     DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
459 }
460
461
462 /****************************************************************************
463   display info about a file
464   ****************************************************************************/
465 static void display_finfo(file_info *finfo)
466 {
467   if (do_this_one(finfo)) {
468     time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
469     DEBUG(0,("  %-30s%7.7s%.0f  %s",
470        CNV_LANG(finfo->name),
471            attrib_string(finfo->mode),
472            (double)finfo->size,
473            asctime(LocalTime(&t))));
474     dir_total += finfo->size;
475   }
476 }
477
478
479 /****************************************************************************
480   calculate size of a file
481   ****************************************************************************/
482 static void do_du(file_info *finfo)
483 {
484   if (do_this_one(finfo)) {
485     dir_total += finfo->size;
486   }
487 }
488
489
490 /****************************************************************************
491   do a directory listing, calling fn on each file found. Use the TRANSACT2
492   call for long filenames
493   ****************************************************************************/
494 static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
495 {
496   int max_matches = 512;
497   int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
498   char *p;
499   pstring mask;
500   file_info finfo;
501   int i;
502   char *dirlist = NULL;
503   int dirlist_len = 0;
504   int total_received = 0;
505   BOOL First = True;
506   char *resp_data=NULL;
507   char *resp_param=NULL;
508   int resp_data_len = 0;
509   int resp_param_len=0;
510
511   int ff_resume_key = 0;
512   int ff_searchcount=0;
513   int ff_eos=0;
514   int ff_lastname=0;
515   int ff_dir_handle=0;
516   int loop_count = 0;
517
518   uint16 setup;
519   pstring param;
520
521   pstrcpy(mask,Mask);
522
523   while (ff_eos == 0)
524     {
525       loop_count++;
526       if (loop_count > 200)
527         {
528           DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
529           break;
530         }
531
532       if (First)
533         {
534           setup = TRANSACT2_FINDFIRST;
535           SSVAL(param,0,attribute); /* attribute */
536           SSVAL(param,2,max_matches); /* max count */
537           SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
538           SSVAL(param,6,info_level); 
539           SIVAL(param,8,0);
540           pstrcpy(param+12,mask);
541         }
542       else
543         {
544           setup = TRANSACT2_FINDNEXT;
545           SSVAL(param,0,ff_dir_handle);
546           SSVAL(param,2,max_matches); /* max count */
547           SSVAL(param,4,info_level); 
548           SIVAL(param,6,ff_resume_key); /* ff_resume_key */
549           SSVAL(param,10,8+4+2);        /* resume required + close on end + continue */
550           pstrcpy(param+12,mask);
551
552           DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
553                    ff_dir_handle,ff_resume_key,ff_lastname,mask));
554         }
555       /* ??? original code added 1 pad byte after param */
556
557       cli_send_trans_request(outbuf,SMBtrans2,NULL,0,FID_UNUSED,0,
558                          NULL,param,&setup,
559                          0,12+strlen(mask)+1,1,
560                          BUFFER_SIZE,10,0);
561
562       if (!cli_receive_trans_response(inbuf,SMBtrans2,
563                               &resp_data_len,&resp_param_len,
564                                   &resp_data,&resp_param))
565         {
566           DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
567           break;
568         }
569
570       /* parse out some important return info */
571       p = resp_param;
572       if (First)
573         {
574           ff_dir_handle = SVAL(p,0);
575           ff_searchcount = SVAL(p,2);
576           ff_eos = SVAL(p,4);
577           ff_lastname = SVAL(p,8);
578         }
579       else
580         {
581           ff_searchcount = SVAL(p,0);
582           ff_eos = SVAL(p,2);
583           ff_lastname = SVAL(p,6);
584         }
585
586       if (ff_searchcount == 0) 
587         break;
588
589       /* point to the data bytes */
590       p = resp_data;
591
592       /* we might need the lastname for continuations */
593       if (ff_lastname > 0)
594         {
595           switch(info_level)
596             {
597             case 260:
598               ff_resume_key =0;
599               StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
600               /* pstrcpy(mask,p+ff_lastname+94); */
601               break;
602             case 1:
603               pstrcpy(mask,p + ff_lastname + 1);
604               ff_resume_key = 0;
605               break;
606             }
607         }
608       else
609         pstrcpy(mask,"");
610   
611       /* and add them to the dirlist pool */
612       dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
613
614       if (!dirlist)
615         {
616           DEBUG(0,("Failed to expand dirlist\n"));
617           break;
618         }
619
620       /* put in a length for the last entry, to ensure we can chain entries 
621          into the next packet */
622       {
623         char *p2;
624         for (p2=p,i=0;i<(ff_searchcount-1);i++)
625           p2 += interpret_long_filename(info_level,p2,NULL);
626         SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
627       }
628
629       /* grab the data for later use */
630       memcpy(dirlist+dirlist_len,p,resp_data_len);
631       dirlist_len += resp_data_len;
632
633       total_received += ff_searchcount;
634
635       if (resp_data) free(resp_data); resp_data = NULL;
636       if (resp_param) free(resp_param); resp_param = NULL;
637
638       DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
639                ff_searchcount,ff_eos,ff_resume_key));
640
641       First = False;
642     }
643
644   if (!fn)
645     for (p=dirlist,i=0;i<total_received;i++)
646       {
647         p += interpret_long_filename(info_level,p,&finfo);
648         display_finfo(&finfo);
649       }
650
651   for (p=dirlist,i=0;i<total_received;i++)
652     {
653       p += interpret_long_filename(info_level,p,&finfo);
654       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True, dirstoo);
655     }
656
657   /* free up the dirlist buffer */
658   if (dirlist) free(dirlist);
659   return(total_received);
660 }
661
662
663 /****************************************************************************
664   do a directory listing, calling fn on each file found
665   ****************************************************************************/
666 static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
667 {
668   char *p;
669   int received = 0;
670   BOOL first = True;
671   char status[21];
672   int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
673   int num_received = 0;
674   int i;
675   char *dirlist = NULL;
676   pstring mask;
677   file_info finfo;
678
679   finfo = def_finfo;
680
681   bzero(status,21);
682
683   pstrcpy(mask,Mask);
684   
685   while (1)
686     {
687       bzero(outbuf,smb_size);
688       if (first)        
689         set_message(outbuf,2,5 + strlen(mask),True);
690       else
691         set_message(outbuf,2,5 + 21,True);
692
693 #if FFIRST
694       if (Protocol >= PROTOCOL_LANMAN1)
695         CVAL(outbuf,smb_com) = SMBffirst;
696       else
697 #endif
698         CVAL(outbuf,smb_com) = SMBsearch;
699
700       SSVAL(outbuf,smb_tid,cnum);
701       cli_setup_pkt(outbuf);
702
703       SSVAL(outbuf,smb_vwv0,num_asked);
704       SSVAL(outbuf,smb_vwv1,attribute);
705   
706       p = smb_buf(outbuf);
707       *p++ = 4;
708       
709       if (first)
710         pstrcpy(p,mask);
711       else
712         pstrcpy(p,"");
713       p += strlen(p) + 1;
714       
715       *p++ = 5;
716       if (first)
717         SSVAL(p,0,0);
718       else
719         {
720           SSVAL(p,0,21);
721           p += 2;
722           memcpy(p,status,21);
723         }
724
725       send_smb(Client,outbuf);
726       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
727
728       received = SVAL(inbuf,smb_vwv0);
729
730       DEBUG(5,("dir received %d\n",received));
731
732       DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
733
734       if (received <= 0) break;
735
736       first = False;
737
738       dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
739
740       if (!dirlist) 
741         return 0;
742
743       p = smb_buf(inbuf) + 3;
744
745       memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
746              p,received*DIR_STRUCT_SIZE);
747
748       memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
749
750       num_received += received;
751
752       if (CVAL(inbuf,smb_rcls) != 0) break;
753     }
754
755 #if FFIRST
756   if (!first && Protocol >= PROTOCOL_LANMAN1)
757     {
758       bzero(outbuf,smb_size);
759       CVAL(outbuf,smb_com) = SMBfclose;
760
761       SSVAL(outbuf,smb_tid,cnum);
762       cli_setup_pkt(outbuf);
763
764       p = smb_buf(outbuf);
765       *p++ = 4;
766       
767       pstrcpy(p,"");
768       p += strlen(p) + 1;
769       
770       *p++ = 5;
771       SSVAL(p,0,21);
772       p += 2;
773       memcpy(p,status,21);
774
775       send_smb(Client,outbuf);
776       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
777
778       if (CVAL(inbuf,smb_rcls) != 0) 
779         DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));      
780     }
781 #endif
782
783   if (!fn)
784     for (p=dirlist,i=0;i<num_received;i++)
785       {
786         p += interpret_short_filename(p,&finfo);
787         display_finfo(&finfo);
788       }
789
790   for (p=dirlist,i=0;i<num_received;i++)
791     {
792       p += interpret_short_filename(p,&finfo);
793       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False,dirstoo);
794     }
795
796   if (dirlist) free(dirlist);
797   return(num_received);
798 }
799
800
801
802 /****************************************************************************
803   do a directory listing, calling fn on each file found
804   ****************************************************************************/
805 void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
806 {
807   DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
808   if (Protocol >= PROTOCOL_LANMAN2)
809     {
810       if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo) > 0)
811         return;
812     }
813
814   expand_mask(Mask,False);
815   do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo);
816   return;
817 }
818
819 /*******************************************************************
820   decide if a file should be operated on
821   ********************************************************************/
822 static BOOL do_this_one(file_info *finfo)
823 {
824   if (finfo->mode & aDIR) return(True);
825
826   if (newer_than && finfo->mtime < newer_than)
827     return(False);
828
829   if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
830     return(False);
831
832   return(True);
833 }
834
835
836 /*****************************************************************************
837  Convert a character pointer in a cli_call_api() response to a form we can use.
838  This function contains code to prevent core dumps if the server returns 
839  invalid data.
840 *****************************************************************************/
841 static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
842 {
843 if( datap == 0 )                /* turn NULL pointers */
844   {                             /* into zero length strings */
845   return "";
846   }
847 else
848   {
849   unsigned int offset = datap - converter;
850
851   if( offset >= rdrcnt )
852     {
853       DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%lu, rdrcnt=%d>", datap, converter, (unsigned long)rdata, rdrcnt));
854     return "<ERROR>";
855     }
856   else
857     {
858     return &rdata[offset];
859     }
860   }
861 }
862
863 /****************************************************************************
864 interpret a short filename structure
865 The length of the structure is returned
866 ****************************************************************************/
867 static int interpret_short_filename(char *p,file_info *finfo)
868 {
869   finfo->mode = CVAL(p,21);
870
871   /* this date is converted to GMT by make_unix_date */
872   finfo->ctime = make_unix_date(p+22);
873   finfo->mtime = finfo->atime = finfo->ctime;
874   finfo->size = IVAL(p,26);
875   pstrcpy(finfo->name,p+30);
876   
877   return(DIR_STRUCT_SIZE);
878 }
879
880 /****************************************************************************
881 interpret a long filename structure - this is mostly guesses at the moment
882 The length of the structure is returned
883 The structure of a long filename depends on the info level. 260 is used
884 by NT and 2 is used by OS/2
885 ****************************************************************************/
886 static int interpret_long_filename(int level,char *p,file_info *finfo)
887 {
888   if (finfo)
889     memcpy(finfo,&def_finfo,sizeof(*finfo));
890
891   switch (level)
892     {
893     case 1: /* OS/2 understands this */
894       if (finfo)
895         {
896           /* these dates are converted to GMT by make_unix_date */
897           finfo->ctime = make_unix_date2(p+4);
898           finfo->atime = make_unix_date2(p+8);
899           finfo->mtime = make_unix_date2(p+12);
900           finfo->size = IVAL(p,16);
901           finfo->mode = CVAL(p,24);
902           pstrcpy(finfo->name,p+27);
903         }
904       return(28 + CVAL(p,26));
905
906     case 2: /* this is what OS/2 uses mostly */
907       if (finfo)
908         {
909           /* these dates are converted to GMT by make_unix_date */
910           finfo->ctime = make_unix_date2(p+4);
911           finfo->atime = make_unix_date2(p+8);
912           finfo->mtime = make_unix_date2(p+12);
913           finfo->size = IVAL(p,16);
914           finfo->mode = CVAL(p,24);
915           pstrcpy(finfo->name,p+31);
916         }
917       return(32 + CVAL(p,30));
918
919       /* levels 3 and 4 are untested */
920     case 3:
921       if (finfo)
922         {
923           /* these dates are probably like the other ones */
924           finfo->ctime = make_unix_date2(p+8);
925           finfo->atime = make_unix_date2(p+12);
926           finfo->mtime = make_unix_date2(p+16);
927           finfo->size = IVAL(p,20);
928           finfo->mode = CVAL(p,28);
929           pstrcpy(finfo->name,p+33);
930         }
931       return(SVAL(p,4)+4);
932
933     case 4:
934       if (finfo)
935         {
936           /* these dates are probably like the other ones */
937           finfo->ctime = make_unix_date2(p+8);
938           finfo->atime = make_unix_date2(p+12);
939           finfo->mtime = make_unix_date2(p+16);
940           finfo->size = IVAL(p,20);
941           finfo->mode = CVAL(p,28);
942           pstrcpy(finfo->name,p+37);
943         }
944       return(SVAL(p,4)+4);
945
946     case 260: /* NT uses this, but also accepts 2 */
947       if (finfo)
948         {
949           int ret = SVAL(p,0);
950           int namelen;
951           p += 4; /* next entry offset */
952           p += 4; /* fileindex */
953
954           /* these dates appear to arrive in a weird way. It seems to
955              be localtime plus the serverzone given in the initial
956              connect. This is GMT when DST is not in effect and one
957              hour from GMT otherwise. Can this really be right??
958
959              I suppose this could be called kludge-GMT. Is is the GMT
960              you get by using the current DST setting on a different
961              localtime. It will be cheap to calculate, I suppose, as
962              no DST tables will be needed */
963
964           finfo->ctime = interpret_long_date(p); p += 8;
965           finfo->atime = interpret_long_date(p); p += 8;
966           finfo->mtime = interpret_long_date(p); p += 8; p += 8;
967           finfo->size = IVAL(p,0); p += 8;
968           p += 8; /* alloc size */
969           finfo->mode = CVAL(p,0); p += 4;
970           namelen = IVAL(p,0); p += 4;
971           p += 4; /* EA size */
972           p += 2; /* short name len? */
973           p += 24; /* short name? */      
974           StrnCpy(finfo->name,p,namelen);
975           return(ret);
976         }
977       return(SVAL(p,0));
978     }
979
980   DEBUG(1,("Unknown long filename format %d\n",level));
981   return(SVAL(p,0));
982 }
983
984
985
986
987 /****************************************************************************
988   act on the files in a dir listing
989
990   RJS, 4-Apr-1998, dirstoo added to allow caller to indicate that directories
991                    should be processed as well.
992   ****************************************************************************/
993 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo)
994 {
995
996   if (!((finfo->mode & aDIR) == 0 && *fileselection && 
997         !mask_match(finfo->name,fileselection,False,False)) &&
998       !(recurse_dir && (strequal(finfo->name,".") || 
999                         strequal(finfo->name,".."))))
1000     {
1001       if (recurse_dir && (finfo->mode & aDIR))
1002         {
1003           pstring mask2;
1004           pstring sav_dir;
1005
1006           if (fn && dirstoo && do_this_one(finfo)) { /* Do dirs, RJS */
1007             fn(finfo);
1008           }
1009
1010           pstrcpy(sav_dir,cur_dir);
1011           pstrcat(cur_dir,finfo->name);
1012           pstrcat(cur_dir,"\\");
1013           pstrcpy(mask2,cur_dir);
1014
1015           if (!fn)
1016             DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
1017
1018           pstrcat(mask2,"*");
1019
1020           if (longdir)
1021             do_long_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);      
1022           else
1023             do_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);
1024
1025           pstrcpy(cur_dir,sav_dir);
1026         }
1027       else
1028         {
1029           if (fn && do_this_one(finfo))
1030             fn(finfo);
1031         }
1032     }
1033 }
1034
1035
1036 /****************************************************************************
1037   get a directory listing
1038   ****************************************************************************/
1039 static void cmd_dir(char *inbuf,char *outbuf)
1040 {
1041   int attribute = aDIR | aSYSTEM | aHIDDEN;
1042   pstring mask;
1043   fstring buf;
1044   char *p=buf;
1045
1046   dir_total = 0;
1047   pstrcpy(mask,cur_dir);
1048   if(mask[strlen(mask)-1]!='\\')
1049     pstrcat(mask,"\\");
1050
1051   if (next_token(NULL,buf,NULL,sizeof(buf)))
1052     {
1053       if (*p == '\\')
1054         pstrcpy(mask,p);
1055       else
1056         pstrcat(mask,p);
1057     }
1058   else {
1059     pstrcat(mask,"*");
1060   }
1061
1062   do_dir(inbuf,outbuf,mask,attribute,NULL,recurse,False);
1063
1064   do_dskattr();
1065
1066   DEBUG(3, ("Total bytes listed: %d\n", dir_total));
1067 }
1068
1069
1070 /****************************************************************************
1071   get a directory listing
1072   ****************************************************************************/
1073 static void cmd_du(char *inbuf,char *outbuf)
1074 {
1075   int attribute = aDIR | aSYSTEM | aHIDDEN;
1076   pstring mask;
1077   fstring buf;
1078   char *p=buf;
1079
1080   dir_total = 0;
1081   pstrcpy(mask,cur_dir);
1082   if(mask[strlen(mask)-1]!='\\')
1083     pstrcat(mask,"\\");
1084
1085   if (next_token(NULL,buf,NULL,sizeof(buf)))
1086     {
1087       if (*p == '\\')
1088         pstrcpy(mask,p);
1089       else
1090         pstrcat(mask,p);
1091     }
1092   else {
1093     pstrcat(mask,"*");
1094   }
1095
1096   do_dir(inbuf,outbuf,mask,attribute,do_du,recurse,False);
1097
1098   do_dskattr();
1099
1100   DEBUG(0, ("Total number of bytes: %d\n", dir_total));
1101 }
1102
1103 /****************************************************************************
1104   get a file from rname to lname
1105   ****************************************************************************/
1106 static void do_get(char *rname,char *lname,file_info *finfo1)
1107 {  
1108   int handle=0,fnum;
1109   uint32 nread=0;
1110   char *p;
1111   BOOL newhandle = False;
1112   char *inbuf,*outbuf;
1113   file_info finfo;
1114   BOOL close_done = False;
1115   BOOL ignore_close_error = False;
1116   char *dataptr=NULL;
1117   int datalen=0;
1118
1119   struct timeval tp_start;
1120   GetTimeOfDay(&tp_start);
1121
1122   if (finfo1) 
1123     finfo = *finfo1;
1124   else
1125     finfo = def_finfo;
1126
1127   if (lowercase)
1128     strlower(lname);
1129
1130
1131   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1132   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1133
1134   if (!inbuf || !outbuf)
1135     {
1136       DEBUG(0,("out of memory\n"));
1137       return;
1138     }
1139
1140   bzero(outbuf,smb_size);
1141   set_message(outbuf,15,1 + strlen(rname),True);
1142
1143   CVAL(outbuf,smb_com) = SMBopenX;
1144   SSVAL(outbuf,smb_tid,cnum);
1145   cli_setup_pkt(outbuf);
1146
1147   SSVAL(outbuf,smb_vwv0,0xFF);
1148   SSVAL(outbuf,smb_vwv2,1); /* return additional info */
1149   SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1150   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1151   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1152   SSVAL(outbuf,smb_vwv8,1);
1153   SSVAL(outbuf,smb_vwv11,0xffff);
1154   SSVAL(outbuf,smb_vwv12,0xffff);
1155   
1156   p = smb_buf(outbuf);
1157   pstrcpy(p,rname);
1158   p = skip_string(p,1);
1159
1160   /* do a chained openX with a readX? */
1161 #if 1
1162   if (finfo.size > 0)
1163     {
1164       DEBUG(3,("Chaining readX wth openX\n"));
1165       SSVAL(outbuf,smb_vwv0,SMBreadX);
1166       SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
1167       bzero(p,200);
1168       p -= smb_wct;
1169       SCVAL(p,smb_wct,10);
1170       SSVAL(p,smb_vwv0,0xFF);
1171       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1172       SSVAL(p,smb_vwv9,MIN(BUFFER_SIZE,finfo.size));
1173       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
1174     }
1175 #endif
1176
1177   if(!strcmp(lname,"-"))
1178     handle = fileno(stdout);
1179   else 
1180     {
1181       handle = creat(lname,0644);
1182       newhandle = True;
1183     }
1184   if (handle < 0)
1185     {
1186       DEBUG(0,("Error opening local file %s\n",lname));
1187       free(inbuf);free(outbuf);
1188       return;
1189     }
1190
1191   send_smb(Client,outbuf);
1192   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1193
1194   if (CVAL(inbuf,smb_rcls) != 0)
1195     {
1196       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1197           SVAL(inbuf,smb_err) == ERRnoresource &&
1198           cli_reopen_connection(inbuf,outbuf))
1199         {
1200           do_get(rname,lname,finfo1);
1201           return;
1202         }
1203       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1204       if(newhandle)
1205         close(handle);
1206       free(inbuf);free(outbuf);
1207       return;
1208     }
1209
1210   pstrcpy(finfo.name,rname);
1211
1212   if (!finfo1)
1213     {
1214       finfo.mode = SVAL(inbuf,smb_vwv3);
1215       /* these times arrive as LOCAL time, using the DST offset 
1216          corresponding to that time, we convert them to GMT */
1217       finfo.mtime = make_unix_date3(inbuf+smb_vwv4);
1218       finfo.atime = finfo.ctime = finfo.mtime;
1219       finfo.size = IVAL(inbuf,smb_vwv6);
1220     }
1221
1222   DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode));
1223
1224   fnum = SVAL(inbuf,smb_vwv2);
1225
1226   /* we might have got some data from a chained readX */
1227   if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1228     {
1229       p = (smb_base(inbuf)+SVAL(inbuf,smb_vwv1)) - smb_wct;
1230       datalen = SVAL(p,smb_vwv5);
1231       dataptr = smb_base(inbuf) + SVAL(p,smb_vwv6);
1232     }
1233   else
1234     {
1235       dataptr = NULL;
1236       datalen = 0;
1237     }
1238
1239
1240   DEBUG(2,("getting file %s of size %.0f bytes as %s ",
1241            CNV_LANG(finfo.name),
1242            (double)finfo.size,
1243            lname));
1244
1245   while (nread < finfo.size && !close_done)
1246     {
1247       int method = -1;
1248       static BOOL can_chain_close = True;
1249
1250       p=NULL;
1251       
1252       DEBUG(3,("nread=%d max_xmit=%d fsize=%.0f\n",nread,max_xmit,(double)finfo.size));
1253
1254       /* 3 possible read types. readbraw if a large block is required.
1255          readX + close if not much left and read if neither is supported */
1256
1257       /* we might have already read some data from a chained readX */
1258       if (dataptr && datalen>0)
1259         method=3;
1260
1261       /* if we can finish now then readX+close */
1262       if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
1263           ((finfo.size - nread) < 
1264            (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1265         method = 0;
1266
1267       /* if we support readraw then use that */
1268       if (method<0 && readbraw_supported)
1269         method = 1;
1270
1271       /* if we can then use readX */
1272       if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1273         method = 2;
1274
1275       switch (method)
1276         {
1277           /* use readX */
1278         case 0:
1279         case 2:
1280           if (method == 0)
1281             close_done = True;
1282             
1283           /* use readX + close */
1284           bzero(outbuf,smb_size);
1285           set_message(outbuf,10,0,True);
1286           CVAL(outbuf,smb_com) = SMBreadX;
1287           SSVAL(outbuf,smb_tid,cnum);
1288           cli_setup_pkt(outbuf);
1289           
1290           if (close_done)
1291             {
1292               CVAL(outbuf,smb_vwv0) = SMBclose;
1293               SSVAL(outbuf,smb_vwv1,smb_offset(smb_buf(outbuf),outbuf));
1294             }
1295           else
1296             CVAL(outbuf,smb_vwv0) = 0xFF;             
1297           
1298           SSVAL(outbuf,smb_vwv2,fnum);
1299           SIVAL(outbuf,smb_vwv3,nread);
1300           SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1301           SSVAL(outbuf,smb_vwv6,0);
1302           SIVAL(outbuf,smb_vwv7,0);
1303           SSVAL(outbuf,smb_vwv9,MIN(BUFFER_SIZE,finfo.size-nread));
1304           
1305           if (close_done)
1306             {
1307               p = smb_buf(outbuf);
1308               bzero(p,9);
1309               
1310               CVAL(p,0) = 3;
1311               SSVAL(p,1,fnum);
1312               SIVALS(p,3,-1);
1313               
1314               /* now set the total packet length */
1315               smb_setlen(outbuf,smb_len(outbuf)+9);
1316             }
1317           
1318           send_smb(Client,outbuf);
1319           client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1320           
1321           if (CVAL(inbuf,smb_rcls) != 0)
1322             {
1323               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1324               break;
1325             }
1326           
1327           if (close_done &&
1328               SVAL(inbuf,smb_vwv0) != SMBclose)
1329             {
1330               /* NOTE: WfWg sometimes just ignores the chained
1331                  command! This seems to break the spec? */
1332               DEBUG(3,("Rejected chained close?\n"));
1333               close_done = False;
1334               can_chain_close = False;
1335               ignore_close_error = True;
1336             }
1337           
1338           datalen = SVAL(inbuf,smb_vwv5);
1339           dataptr = smb_base(inbuf) + SVAL(inbuf,smb_vwv6);
1340           break;
1341
1342           /* use readbraw */
1343         case 1:
1344           {
1345             static int readbraw_size = BUFFER_SIZE;
1346           
1347             extern int Client;
1348             bzero(outbuf,smb_size);
1349             set_message(outbuf,8,0,True);
1350             CVAL(outbuf,smb_com) = SMBreadbraw;
1351             SSVAL(outbuf,smb_tid,cnum);
1352             cli_setup_pkt(outbuf);
1353             SSVAL(outbuf,smb_vwv0,fnum);
1354             SIVAL(outbuf,smb_vwv1,nread);
1355             SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1356             SSVAL(outbuf,smb_vwv4,0);
1357             SIVALS(outbuf,smb_vwv5,-1);
1358             send_smb(Client,outbuf);
1359
1360             /* Now read the raw data into the buffer and write it */      
1361             if(read_smb_length(Client,inbuf,0) == -1) {
1362               DEBUG(0,("Failed to read length in readbraw\n"));     
1363               exit(1);
1364             }
1365             
1366             /* Even though this is not an smb message, smb_len
1367                returns the generic length of an smb message */
1368             datalen = smb_len(inbuf);
1369
1370             if (datalen == 0)
1371               {
1372                 /* we got a readbraw error */
1373                 DEBUG(4,("readbraw error - reducing size\n"));
1374                 readbraw_size = (readbraw_size * 9) / 10;
1375                 
1376                 if (readbraw_size < max_xmit)
1377                   {
1378                     DEBUG(0,("disabling readbraw\n"));
1379                     readbraw_supported = False;
1380                   }
1381                 
1382                 dataptr=NULL;
1383                 continue;
1384               }
1385
1386             if(read_data(Client,inbuf,datalen) != datalen) {
1387               DEBUG(0,("Failed to read data in readbraw\n"));
1388               exit(1);
1389             }
1390             dataptr = inbuf;
1391           }
1392           break;
1393
1394         case 3:
1395           /* we've already read some data with a chained readX */
1396           break;
1397
1398         default:
1399           /* use plain read */
1400           bzero(outbuf,smb_size);
1401           set_message(outbuf,5,0,True);
1402           CVAL(outbuf,smb_com) = SMBread;
1403           SSVAL(outbuf,smb_tid,cnum);
1404           cli_setup_pkt(outbuf);
1405
1406           SSVAL(outbuf,smb_vwv0,fnum);
1407           SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1408           SIVAL(outbuf,smb_vwv2,nread);
1409           SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1410
1411           send_smb(Client,outbuf);
1412           client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1413
1414           if (CVAL(inbuf,smb_rcls) != 0)
1415             {
1416               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1417               break;
1418             }
1419
1420           datalen = SVAL(inbuf,smb_vwv0);
1421           dataptr = smb_buf(inbuf) + 3;
1422           break;
1423         }
1424  
1425       if (writefile(handle,dataptr,datalen) != datalen)
1426         {
1427           DEBUG(0,("Error writing local file\n"));
1428           break;
1429         }
1430       
1431       nread += datalen;
1432       if (datalen == 0) 
1433         {
1434           DEBUG(0,("Error reading file %s. Got %d bytes\n",CNV_LANG(rname),nread));
1435           break;
1436         }
1437
1438       dataptr=NULL;
1439       datalen=0;
1440     }
1441
1442
1443
1444   if (!close_done)
1445     {
1446       cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
1447       
1448       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1449         {
1450           DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1451           if(newhandle)
1452             close(handle);
1453           free(inbuf);free(outbuf);
1454           return;
1455         }
1456     }
1457
1458   if(newhandle)
1459     close(handle);
1460
1461   if (archive_level >= 2 && (finfo.mode & aARCH)) {
1462     bzero(outbuf,smb_size);
1463     set_message(outbuf,8,strlen(rname)+4,True);
1464     CVAL(outbuf,smb_com) = SMBsetatr;
1465     SSVAL(outbuf,smb_tid,cnum);
1466     cli_setup_pkt(outbuf);
1467     SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
1468     SIVALS(outbuf,smb_vwv1,0);
1469     p = smb_buf(outbuf);
1470     *p++ = 4;
1471     pstrcpy(p,rname);
1472     p += strlen(p)+1;
1473     *p++ = 4;
1474     *p = 0;
1475     send_smb(Client,outbuf);
1476     client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1477   }
1478
1479   {
1480     struct timeval tp_end;
1481     int this_time;
1482
1483     GetTimeOfDay(&tp_end);
1484     this_time = 
1485       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1486         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1487     get_total_time_ms += this_time;
1488     get_total_size += finfo.size;
1489
1490     DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
1491              finfo.size / (1.024*this_time + 1.0e-4),
1492              get_total_size / (1.024*get_total_time_ms)));
1493   }
1494
1495   free(inbuf);free(outbuf);
1496 }
1497
1498
1499 /****************************************************************************
1500   get a file
1501   ****************************************************************************/
1502 static void cmd_get(char *dum_in, char *dum_out)
1503 {
1504   pstring lname;
1505   pstring rname;
1506   char *p;
1507
1508   pstrcpy(rname,cur_dir);
1509   pstrcat(rname,"\\");
1510
1511   p = rname + strlen(rname);
1512
1513   if (!next_token(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
1514     DEBUG(0,("get <filename>\n"));
1515     return;
1516   }
1517   pstrcpy(lname,p);
1518   dos_clean_name(rname);
1519     
1520   next_token(NULL,lname,NULL,sizeof(lname));
1521
1522   do_get(rname,lname,NULL);
1523 }
1524
1525
1526 /****************************************************************************
1527   do a mget operation on one file
1528   ****************************************************************************/
1529 static void do_mget(file_info *finfo)
1530 {
1531   pstring rname;
1532   pstring quest;
1533
1534   if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1535     return;
1536
1537   if (abort_mget)
1538     {
1539       DEBUG(0,("mget aborted\n"));
1540       return;
1541     }
1542
1543   if (finfo->mode & aDIR)
1544     slprintf(quest,sizeof(pstring)-1,
1545              "Get directory %s? ",CNV_LANG(finfo->name));
1546   else
1547     slprintf(quest,sizeof(pstring)-1,
1548              "Get file %s? ",CNV_LANG(finfo->name));
1549
1550   if (prompt && !yesno(quest)) return;
1551
1552   if (finfo->mode & aDIR)
1553     {
1554       pstring saved_curdir;
1555       pstring mget_mask;
1556       char *inbuf,*outbuf;
1557
1558       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1559       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1560
1561       if (!inbuf || !outbuf)
1562         {
1563           DEBUG(0,("out of memory\n"));
1564           return;
1565         }
1566
1567       pstrcpy(saved_curdir,cur_dir);
1568
1569       pstrcat(cur_dir,finfo->name);
1570       pstrcat(cur_dir,"\\");
1571
1572       unix_format(finfo->name);
1573       {
1574         if (lowercase)
1575           strlower(finfo->name);
1576
1577         if (!directory_exist(finfo->name,NULL) && 
1578             dos_mkdir(finfo->name,0777) != 0) 
1579           {
1580             DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
1581             pstrcpy(cur_dir,saved_curdir);
1582             free(inbuf);free(outbuf);
1583             return;
1584           }
1585
1586         if (dos_chdir(finfo->name) != 0)
1587           {
1588             DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
1589             pstrcpy(cur_dir,saved_curdir);
1590             free(inbuf);free(outbuf);
1591             return;
1592           }
1593       }       
1594
1595       pstrcpy(mget_mask,cur_dir);
1596       pstrcat(mget_mask,"*");
1597       
1598       do_dir((char *)inbuf,(char *)outbuf,
1599              mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False, False);
1600       chdir("..");
1601       pstrcpy(cur_dir,saved_curdir);
1602       free(inbuf);free(outbuf);
1603     }
1604   else
1605     {
1606       pstrcpy(rname,cur_dir);
1607       pstrcat(rname,finfo->name);
1608       do_get(rname,finfo->name,finfo);
1609     }
1610 }
1611
1612 /****************************************************************************
1613 view the file using the pager
1614 ****************************************************************************/
1615 static void cmd_more(char *dum_in, char *dum_out)
1616 {
1617   fstring rname,lname,tmpname,pager_cmd;
1618   char *pager;
1619
1620   fstrcpy(rname,cur_dir);
1621   fstrcat(rname,"\\");
1622   slprintf(tmpname,
1623            sizeof(fstring)-1,
1624            "%s/smbmore.%d",tmpdir(),(int)getpid());
1625   fstrcpy(lname,tmpname);
1626
1627   if (!next_token(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
1628     DEBUG(0,("more <filename>\n"));
1629     return;
1630   }
1631   dos_clean_name(rname);
1632
1633   do_get(rname,lname,NULL);
1634
1635   pager=getenv("PAGER");
1636
1637   slprintf(pager_cmd,sizeof(pager_cmd)-1,
1638            "%s %s",(pager? pager:PAGER), tmpname);
1639   system(pager_cmd);
1640   unlink(tmpname);
1641 }
1642
1643
1644
1645 /****************************************************************************
1646 do a mget command
1647 ****************************************************************************/
1648 static void cmd_mget(char *inbuf,char *outbuf)
1649 {
1650   int attribute = aSYSTEM | aHIDDEN;
1651   pstring mget_mask;
1652   fstring buf;
1653   char *p=buf;
1654
1655   *mget_mask = 0;
1656
1657   if (recurse)
1658     attribute |= aDIR;
1659
1660   abort_mget = False;
1661
1662   while (next_token(NULL,p,NULL,sizeof(buf)))
1663     {
1664       pstrcpy(mget_mask,cur_dir);
1665       if(mget_mask[strlen(mget_mask)-1]!='\\')
1666         pstrcat(mget_mask,"\\");
1667
1668       if (*p == '\\')
1669         pstrcpy(mget_mask,p);
1670       else
1671         pstrcat(mget_mask,p);
1672       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
1673     }
1674
1675   if (! *mget_mask)
1676     {
1677       pstrcpy(mget_mask,cur_dir);
1678       if(mget_mask[strlen(mget_mask)-1]!='\\')
1679         pstrcat(mget_mask,"\\");
1680       pstrcat(mget_mask,"*");
1681       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
1682     }
1683 }
1684
1685 /****************************************************************************
1686 make a directory of name "name"
1687 ****************************************************************************/
1688 static BOOL do_mkdir(char *name)
1689 {
1690   char *p;
1691   char *inbuf,*outbuf;
1692
1693   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1694   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1695
1696   if (!inbuf || !outbuf)
1697     {
1698       DEBUG(0,("out of memory\n"));
1699       return False;
1700     }
1701
1702   bzero(outbuf,smb_size);
1703   set_message(outbuf,0,2 + strlen(name),True);
1704   
1705   CVAL(outbuf,smb_com) = SMBmkdir;
1706   SSVAL(outbuf,smb_tid,cnum);
1707   cli_setup_pkt(outbuf);
1708
1709   
1710   p = smb_buf(outbuf);
1711   *p++ = 4;      
1712   pstrcpy(p,name);
1713   
1714   send_smb(Client,outbuf);
1715   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1716   
1717   if (CVAL(inbuf,smb_rcls) != 0)
1718     {
1719       DEBUG(0,("%s making remote directory %s\n",
1720                smb_errstr(inbuf),CNV_LANG(name)));
1721
1722       free(inbuf);free(outbuf);
1723       return(False);
1724     }
1725
1726   free(inbuf);free(outbuf);
1727   return(True);
1728 }
1729
1730
1731 /****************************************************************************
1732   make a directory
1733   ****************************************************************************/
1734 static void cmd_mkdir(char *inbuf,char *outbuf)
1735 {
1736   pstring mask;
1737   fstring buf;
1738   char *p=buf;
1739   
1740   pstrcpy(mask,cur_dir);
1741
1742   if (!next_token(NULL,p,NULL,sizeof(buf)))
1743     {
1744       if (!recurse)
1745         DEBUG(0,("mkdir <dirname>\n"));
1746       return;
1747     }
1748   pstrcat(mask,p);
1749
1750   if (recurse)
1751     {
1752       pstring ddir;
1753       pstring ddir2;
1754       *ddir2 = 0;
1755
1756       pstrcpy(ddir,mask);
1757       trim_string(ddir,".",NULL);
1758       p = strtok(ddir,"/\\");
1759       while (p)
1760         {
1761           pstrcat(ddir2,p);
1762           if (!chkpath(ddir2,False))
1763             {             
1764               do_mkdir(ddir2);
1765             }
1766           pstrcat(ddir2,"\\");
1767           p = strtok(NULL,"/\\");
1768         }        
1769     }
1770   else
1771     do_mkdir(mask);
1772 }
1773
1774
1775 /*******************************************************************
1776   write to a file using writebraw
1777   ********************************************************************/
1778 static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
1779 {
1780   extern int Client;
1781   pstring inbuf;
1782
1783   bzero(outbuf,smb_size);
1784   bzero(inbuf,smb_size);  
1785   set_message(outbuf,Protocol>PROTOCOL_COREPLUS?12:10,0,True);
1786
1787   CVAL(outbuf,smb_com) = SMBwritebraw;
1788   SSVAL(outbuf,smb_tid,cnum);
1789   cli_setup_pkt(outbuf);
1790
1791   SSVAL(outbuf,smb_vwv0,fnum);
1792   SSVAL(outbuf,smb_vwv1,n);
1793   SIVAL(outbuf,smb_vwv3,pos);
1794   SSVAL(outbuf,smb_vwv7,1);
1795
1796   send_smb(Client,outbuf);
1797   
1798   if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
1799     return(0);
1800
1801   _smb_setlen(buf-4,n);         /* HACK! XXXX */
1802
1803   if (write_socket(Client,buf-4,n+4) != n+4)
1804     return(0);
1805
1806   if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
1807     DEBUG(0,("Error writing remote file (2)\n"));
1808     return(0);
1809   }
1810   return(SVAL(inbuf,smb_vwv0));
1811 }
1812       
1813
1814
1815 /*******************************************************************
1816   write to a file
1817   ********************************************************************/
1818 static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
1819 {
1820   pstring inbuf;
1821
1822   if (writebraw_supported && n > (max_xmit-200)) 
1823     return(smb_writeraw(outbuf,fnum,pos,buf,n));
1824
1825   bzero(outbuf,smb_size);
1826   bzero(inbuf,smb_size);
1827   set_message(outbuf,5,n + 3,True);
1828
1829   CVAL(outbuf,smb_com) = SMBwrite;
1830   SSVAL(outbuf,smb_tid,cnum);
1831   cli_setup_pkt(outbuf);
1832
1833   SSVAL(outbuf,smb_vwv0,fnum);
1834   SSVAL(outbuf,smb_vwv1,n);
1835   SIVAL(outbuf,smb_vwv2,pos);
1836   SSVAL(outbuf,smb_vwv4,0);
1837   CVAL(smb_buf(outbuf),0) = 1;
1838   SSVAL(smb_buf(outbuf),1,n);
1839
1840   memcpy(smb_buf(outbuf)+3,buf,n);
1841
1842   send_smb(Client,outbuf);
1843   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1844
1845   if (CVAL(inbuf,smb_rcls) != 0) {
1846     DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
1847     return(0);
1848   }
1849   return(SVAL(inbuf,smb_vwv0));
1850 }
1851       
1852
1853
1854 /****************************************************************************
1855   put a single file
1856   ****************************************************************************/
1857 static void do_put(char *rname,char *lname,file_info *finfo)
1858 {
1859   int fnum;
1860   FILE *f;
1861   int nread=0;
1862   char *p;
1863   char *inbuf,*outbuf; 
1864   time_t close_time = finfo->mtime;
1865   char *buf=NULL;
1866   static int maxwrite=0;
1867
1868   struct timeval tp_start;
1869   GetTimeOfDay(&tp_start);
1870
1871   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1872   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1873
1874   if (!inbuf || !outbuf)
1875     {
1876       DEBUG(0,("out of memory\n"));
1877       return;
1878     }
1879
1880   bzero(outbuf,smb_size);
1881   set_message(outbuf,3,2 + strlen(rname),True);
1882
1883   if (finfo->mtime == 0 || finfo->mtime == -1)
1884     finfo->mtime = finfo->atime = finfo->ctime = time(NULL);
1885
1886   CVAL(outbuf,smb_com) = SMBcreate;
1887   SSVAL(outbuf,smb_tid,cnum);
1888   cli_setup_pkt(outbuf);
1889
1890   SSVAL(outbuf,smb_vwv0,finfo->mode);
1891   put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
1892   
1893   p = smb_buf(outbuf);
1894   *p++ = 4;      
1895   pstrcpy(p,rname);
1896   
1897   send_smb(Client,outbuf);
1898   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1899   
1900   if (CVAL(inbuf,smb_rcls) != 0)
1901     {
1902       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1903
1904       free(inbuf);free(outbuf);if (buf) free(buf);
1905       return;
1906     }
1907
1908   /* allow files to be piped into smbclient
1909      jdblair 24.jun.98 */
1910   if (!strcmp(lname, "-")) {
1911     f = stdin;
1912     /* size of file is not known */
1913     finfo->size = 0;
1914   } else {
1915     f = fopen(lname,"r");
1916   }
1917
1918   if (!f)
1919     {
1920       DEBUG(0,("Error opening local file %s\n",lname));
1921       free(inbuf);free(outbuf);
1922       return;
1923     }
1924
1925   
1926   fnum = SVAL(inbuf,smb_vwv0);
1927   if (finfo->size < 0)
1928     finfo->size = file_size(lname);
1929   
1930   DEBUG(1,("putting file %s of size %.0f bytes as %s ",lname,(double)finfo->size,CNV_LANG(rname)));
1931   
1932   if (!maxwrite)
1933     maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
1934
1935   /* This is a rewrite of the read/write loop that doesn't require the input
1936      file to be of a known length.  This allows the stream pointer 'f' to
1937      refer to stdin.
1938
1939      Rather than reallocing the read buffer every loop to keep it the min
1940      necessary length this look uses a fixed length buffer and just tests
1941      for eof on the file stream at the top of each loop.
1942      jdblair, 24.jun.98 */
1943
1944   buf = (char *)malloc(maxwrite+4);
1945   while (! feof(f) )
1946     {
1947       int n = maxwrite;
1948       int ret;
1949
1950       fseek(f,nread,SEEK_SET);
1951       if ((n = readfile(buf+4,1,n,f)) < 1)
1952         {
1953           DEBUG(0,("Error reading local file\n"));
1954           break;
1955         }         
1956
1957       ret = smb_writefile(outbuf,fnum,nread,buf+4,n);
1958
1959       if (n != ret) {
1960         if (!maxwrite) {
1961           DEBUG(0,("Error writing file\n"));
1962           break;
1963         } else {
1964           maxwrite /= 2;
1965           continue;
1966         }
1967       }
1968
1969       nread += n;
1970     }
1971
1972   bzero(outbuf,smb_size);
1973   set_message(outbuf,3,0,True);
1974   CVAL(outbuf,smb_com) = SMBclose;
1975   SSVAL(outbuf,smb_tid,cnum);
1976   cli_setup_pkt(outbuf);
1977
1978   SSVAL(outbuf,smb_vwv0,fnum);  
1979   put_dos_date3(outbuf,smb_vwv1,close_time);
1980
1981   send_smb(Client,outbuf);
1982   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1983   
1984   if (CVAL(inbuf,smb_rcls) != 0)
1985     {
1986       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1987       fclose(f);
1988       free(inbuf);free(outbuf);
1989       if (buf) free(buf);
1990       return;
1991     }
1992
1993   
1994   fclose(f);
1995   free(inbuf);free(outbuf);
1996   if (buf) free(buf);
1997
1998   {
1999     struct timeval tp_end;
2000     int this_time;
2001
2002     GetTimeOfDay(&tp_end);
2003     this_time = 
2004       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
2005         (tp_end.tv_usec - tp_start.tv_usec)/1000;
2006     put_total_time_ms += this_time;
2007     put_total_size += finfo->size;
2008
2009     DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
2010              finfo->size / (1.024*this_time + 1.0e-4),
2011              put_total_size / (1.024*put_total_time_ms)));
2012   }
2013 }
2014
2015  
2016
2017 /****************************************************************************
2018   put a file
2019   ****************************************************************************/
2020 static void cmd_put(char *dum_in, char *dum_out)
2021 {
2022   pstring lname;
2023   pstring rname;
2024   fstring buf;
2025   char *p=buf;
2026   file_info finfo;
2027   finfo = def_finfo;
2028   
2029   pstrcpy(rname,cur_dir);
2030   pstrcat(rname,"\\");
2031   
2032   
2033   if (!next_token(NULL,p,NULL,sizeof(buf)))
2034     {
2035       DEBUG(0,("put <filename>\n"));
2036       return;
2037     }
2038   pstrcpy(lname,p);
2039   
2040   if (next_token(NULL,p,NULL,sizeof(buf)))
2041     pstrcat(rname,p);      
2042   else
2043     pstrcat(rname,lname);
2044
2045   dos_clean_name(rname);
2046
2047   {
2048     SMB_STRUCT_STAT st;
2049     /* allow '-' to represent stdin
2050        jdblair, 24.jun.98 */
2051     if (!file_exist(lname,&st) &&
2052       (strcmp(lname,"-"))) {
2053       DEBUG(0,("%s does not exist\n",lname));
2054       return;
2055     }
2056     finfo.mtime = st.st_mtime;
2057   }
2058
2059   do_put(rname,lname,&finfo);
2060 }
2061
2062 /****************************************************************************
2063   seek in a directory/file list until you get something that doesn't start with
2064   the specified name
2065   ****************************************************************************/
2066 static BOOL seek_list(FILE *f,char *name)
2067 {
2068   pstring s;
2069   while (!feof(f))
2070     {
2071       if (fscanf(f,"%s",s) != 1) return(False);
2072       trim_string(s,"./",NULL);
2073       if (strncmp(s,name,strlen(name)) != 0)
2074         {
2075           pstrcpy(name,s);
2076           return(True);
2077         }
2078     }
2079       
2080   return(False);
2081 }
2082
2083
2084 /****************************************************************************
2085   set the file selection mask
2086   ****************************************************************************/
2087 static void cmd_select(char *dum_in, char *dum_out)
2088 {
2089   pstrcpy(fileselection,"");
2090   next_token(NULL,fileselection,NULL,sizeof(fileselection));
2091 }
2092
2093
2094 /****************************************************************************
2095   mput some files
2096   ****************************************************************************/
2097 static void cmd_mput(char *dum_in, char *dum_out)
2098 {
2099   pstring lname;
2100   pstring rname;
2101   file_info finfo;
2102   fstring buf;
2103   char *p=buf;
2104
2105   finfo = def_finfo;
2106
2107   
2108   while (next_token(NULL,p,NULL,sizeof(buf)))
2109     {
2110       SMB_STRUCT_STAT st;
2111       pstring cmd;
2112       pstring tmpname;
2113       FILE *f;
2114       
2115       slprintf(tmpname,sizeof(pstring)-1,
2116                "%s/ls.smb.%d",tmpdir(),(int)getpid());
2117       if (recurse)
2118         slprintf(cmd,sizeof(pstring)-1,
2119                 "find . -name \"%s\" -print > %s",p,tmpname);
2120       else
2121         slprintf(cmd,sizeof(pstring)-1,
2122                  "/bin/ls %s > %s",p,tmpname);
2123       system(cmd);
2124
2125       f = fopen(tmpname,"r");
2126       if (!f) continue;
2127
2128       while (!feof(f))
2129         {
2130           pstring quest;
2131
2132           if (fscanf(f,"%s",lname) != 1) break;
2133           trim_string(lname,"./",NULL);
2134
2135         again1:
2136
2137           /* check if it's a directory */
2138           if (directory_exist(lname,&st))
2139             {
2140               if (!recurse) continue;
2141               slprintf(quest,sizeof(pstring)-1,
2142                        "Put directory %s? ",lname);
2143               if (prompt && !yesno(quest)) 
2144                 {
2145                   pstrcat(lname,"/");
2146                   if (!seek_list(f,lname))
2147                     break;
2148                   goto again1;              
2149                 }
2150               
2151               pstrcpy(rname,cur_dir);
2152               pstrcat(rname,lname);
2153               if (!chkpath(rname,False) && !do_mkdir(rname)) {
2154                 pstrcat(lname,"/");
2155                 if (!seek_list(f,lname))
2156                   break;
2157                 goto again1;                              
2158               }
2159
2160               continue;
2161             }
2162           else
2163             {
2164               slprintf(quest,sizeof(quest)-1,
2165                        "Put file %s? ",lname);
2166               if (prompt && !yesno(quest)) continue;
2167
2168               pstrcpy(rname,cur_dir);
2169               pstrcat(rname,lname);
2170             }
2171           dos_format(rname);
2172
2173           /* null size so do_put knows to ignore it */
2174           finfo.size = -1;
2175
2176           /* set the date on the file */
2177           finfo.mtime = st.st_mtime;
2178
2179           do_put(rname,lname,&finfo);
2180         }
2181       fclose(f);
2182       unlink(tmpname);
2183     }
2184 }
2185
2186 /****************************************************************************
2187   cancel a print job
2188   ****************************************************************************/
2189 static void do_cancel(int job)
2190 {
2191   char *rparam = NULL;
2192   char *rdata = NULL;
2193   char *p;
2194   int rdrcnt,rprcnt;
2195   pstring param;
2196
2197   bzero(param,sizeof(param));
2198
2199   p = param;
2200   SSVAL(p,0,81);                /* DosPrintJobDel() */
2201   p += 2;
2202   pstrcpy(p,"W");
2203   p = skip_string(p,1);
2204   pstrcpy(p,"");
2205   p = skip_string(p,1);
2206   SSVAL(p,0,job);     
2207   p += 2;
2208
2209   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
2210            6, 1000,
2211                &rprcnt,&rdrcnt,
2212                param,NULL, NULL,
2213                &rparam,&rdata))
2214     {
2215       int res = SVAL(rparam,0);
2216
2217       if (!res)
2218         printf("Job %d cancelled\n",job);
2219       else
2220         printf("Error %d calcelling job %d\n",res,job);
2221       return;
2222     }
2223   else
2224   printf("Server refused cancel request\n");
2225
2226   if (rparam) free(rparam);
2227   if (rdata) free(rdata);
2228
2229   return;
2230 }
2231
2232
2233 /****************************************************************************
2234   cancel a print job
2235   ****************************************************************************/
2236 static void cmd_cancel(char *inbuf,char *outbuf )
2237 {
2238   fstring buf;
2239   int job; 
2240
2241   if (!connect_as_printer)
2242     {
2243       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2244       DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
2245     }
2246
2247   if (!next_token(NULL,buf,NULL,sizeof(buf))) {
2248     printf("cancel <jobid> ...\n");
2249     return;
2250   }
2251   do {
2252     job = atoi(buf);
2253     do_cancel(job);
2254   } while (next_token(NULL,buf,NULL,sizeof(buf)));
2255 }
2256
2257
2258
2259
2260 /****************************************************************************
2261   print a file
2262   ****************************************************************************/
2263 static void cmd_print(char *inbuf,char *outbuf )
2264 {
2265   int fnum;
2266   FILE *f = NULL;
2267   uint32 nread=0;
2268   pstring lname;
2269   pstring rname;
2270   char *p;
2271
2272   if (!connect_as_printer)
2273     {
2274       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2275       DEBUG(0,("Trying to print without -P may fail\n"));
2276     }
2277
2278   if (!next_token(NULL,lname,NULL, sizeof(lname)))
2279     {
2280       DEBUG(0,("print <filename>\n"));
2281       return;
2282     }
2283
2284   pstrcpy(rname,lname);
2285   p = strrchr(rname,'/');
2286   if (p)
2287     {
2288       pstring tname;
2289       pstrcpy(tname,p+1);
2290       pstrcpy(rname,tname);
2291     }
2292
2293   if ((int)strlen(rname) > 14)
2294     rname[14] = 0;
2295
2296   if (strequal(lname,"-"))
2297     {
2298       f = stdin;
2299       pstrcpy(rname,"stdin");
2300     }
2301   
2302   dos_clean_name(rname);
2303
2304   bzero(outbuf,smb_size);
2305   set_message(outbuf,2,2 + strlen(rname),True);
2306   
2307   CVAL(outbuf,smb_com) = SMBsplopen;
2308   SSVAL(outbuf,smb_tid,cnum);
2309   cli_setup_pkt(outbuf);
2310
2311   SSVAL(outbuf,smb_vwv0,0);
2312   SSVAL(outbuf,smb_vwv1,printmode);
2313   
2314   p = smb_buf(outbuf);
2315   *p++ = 4;      
2316   pstrcpy(p,rname);
2317   
2318   send_smb(Client,outbuf);
2319   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2320   
2321   if (CVAL(inbuf,smb_rcls) != 0)
2322     {
2323       DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
2324       return;
2325     }
2326   
2327   if (!f)
2328     f = fopen(lname,"r");
2329   if (!f)
2330     {
2331       DEBUG(0,("Error opening local file %s\n",lname));
2332       return;
2333     }
2334
2335   
2336   fnum = SVAL(inbuf,smb_vwv0);
2337   
2338   DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname)));
2339   
2340   while (!feof(f))
2341     {
2342       int n;
2343   
2344       bzero(outbuf,smb_size);
2345       set_message(outbuf,1,3,True);
2346
2347       /* for some strange reason the OS/2 print server can't handle large
2348          packets when printing. weird */
2349       n = MIN(1024,max_xmit-(smb_len(outbuf)+4));
2350
2351       if (translation)
2352         n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n));
2353       else
2354         n = readfile(smb_buf(outbuf)+3,1,n,f);
2355       if (n <= 0) 
2356         {
2357           DEBUG(0,("read gave %d\n",n));
2358           break;
2359         }
2360
2361       smb_setlen(outbuf,smb_len(outbuf) + n);
2362
2363       CVAL(outbuf,smb_com) = SMBsplwr;
2364       SSVAL(outbuf,smb_tid,cnum);
2365       cli_setup_pkt(outbuf);
2366
2367       SSVAL(outbuf,smb_vwv0,fnum);
2368       SSVAL(outbuf,smb_vwv1,n+3);
2369       CVAL(smb_buf(outbuf),0) = 1;
2370       SSVAL(smb_buf(outbuf),1,n);
2371
2372       send_smb(Client,outbuf);
2373       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2374
2375       if (CVAL(inbuf,smb_rcls) != 0)
2376         {
2377           DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf)));
2378           break;
2379         }
2380
2381       nread += n;
2382     }
2383
2384   DEBUG(2,("%d bytes printed\n",nread));
2385
2386   bzero(outbuf,smb_size);
2387   set_message(outbuf,1,0,True);
2388   CVAL(outbuf,smb_com) = SMBsplclose;
2389   SSVAL(outbuf,smb_tid,cnum);
2390   cli_setup_pkt(outbuf);
2391
2392   SSVAL(outbuf,smb_vwv0,fnum);
2393
2394   send_smb(Client,outbuf);
2395   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2396   
2397   if (CVAL(inbuf,smb_rcls) != 0)
2398     {
2399       DEBUG(0,("%s closing print file\n",smb_errstr(inbuf)));
2400       if (f != stdin)
2401         fclose(f);
2402       return;
2403     }
2404
2405   if (f != stdin)
2406     fclose(f);
2407 }
2408
2409 /****************************************************************************
2410 show a print queue - this is deprecated as it uses the old smb that
2411 has limited support - the correct call is the cmd_p_queue_4() after this.
2412 ****************************************************************************/
2413 static void cmd_queue(char *inbuf,char *outbuf )
2414 {
2415   int count;
2416   char *p;
2417
2418   bzero(outbuf,smb_size);
2419   set_message(outbuf,2,0,True);
2420   
2421   CVAL(outbuf,smb_com) = SMBsplretq;
2422   SSVAL(outbuf,smb_tid,cnum);
2423   cli_setup_pkt(outbuf);
2424
2425   SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
2426   SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
2427   
2428   send_smb(Client,outbuf);
2429   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2430   
2431   if (CVAL(inbuf,smb_rcls) != 0)
2432     {
2433       DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf)));
2434       return;
2435     }
2436
2437   count = SVAL(inbuf,smb_vwv0);
2438   p = smb_buf(inbuf) + 3;
2439   if (count <= 0)
2440     {
2441       DEBUG(0,("No entries in the print queue\n"));
2442       return;
2443     }  
2444
2445   {
2446     char status[20];
2447
2448     DEBUG(0,("Job      Name              Size         Status\n"));
2449
2450     while (count--)
2451       {
2452         switch (CVAL(p,4))
2453           {
2454           case 0x01: safe_strcpy(status,"held or stopped", sizeof(status)-1); break;
2455           case 0x02: safe_strcpy(status,"printing",sizeof(status)-1); break;
2456           case 0x03: safe_strcpy(status,"awaiting print", sizeof(status)-1); break;
2457           case 0x04: safe_strcpy(status,"in intercept",sizeof(status)-1); break;
2458           case 0x05: safe_strcpy(status,"file had error",sizeof(status)-1); break;
2459           case 0x06: safe_strcpy(status,"printer error",sizeof(status)-1); break;
2460           default: safe_strcpy(status,"unknown",sizeof(status)-1); break;
2461           }
2462
2463         DEBUG(0,("%-6d   %-16.16s  %-9d    %s\n",
2464                  SVAL(p,5),p+12,IVAL(p,7),status));
2465         p += 28;
2466       }
2467   }
2468   
2469 }
2470
2471
2472 /****************************************************************************
2473 show information about a print queue
2474 ****************************************************************************/
2475 static void cmd_p_queue_4(char *inbuf,char *outbuf )
2476 {
2477   char *rparam = NULL;
2478   char *rdata = NULL;
2479   char *p;
2480   int rdrcnt, rprcnt;
2481   pstring param;
2482   int result_code=0;
2483
2484   if (!connect_as_printer)
2485     {
2486       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2487       DEBUG(0,("Trying to print without -P may fail\n"));
2488     }
2489   
2490   bzero(param,sizeof(param));
2491
2492   p = param;
2493   SSVAL(p,0,76);                        /* API function number 76 (DosPrintJobEnum) */
2494   p += 2;
2495   pstrcpy(p,"zWrLeh");                   /* parameter description? */
2496   p = skip_string(p,1);
2497   pstrcpy(p,"WWzWWDDzz");                /* returned data format */
2498   p = skip_string(p,1);
2499   pstrcpy(p,strrchr(service,'\\')+1);    /* name of queue */
2500   p = skip_string(p,1);
2501   SSVAL(p,0,2);                 /* API function level 2, PRJINFO_2 data structure */
2502   SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
2503   p += 4;
2504   pstrcpy(p,"");                         /* subformat */
2505   p = skip_string(p,1);
2506
2507   DEBUG(1,("Calling DosPrintJobEnum()...\n"));
2508   if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
2509                10, 4096,
2510                &rprcnt, &rdrcnt,
2511                param, NULL, NULL,
2512                &rparam, &rdata) )
2513     {
2514       int converter;
2515       result_code = SVAL(rparam,0);
2516       converter = SVAL(rparam,2);             /* conversion factor */
2517
2518       DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2519
2520       if (result_code == 0)                   /* if no error, */
2521         {
2522           int i;
2523           uint16 JobId;
2524           uint16 Priority;
2525           uint32 Size;
2526           char *UserName;
2527           char *JobName;
2528           char *JobTimeStr;
2529           time_t JobTime;
2530           fstring PrinterName;
2531              
2532           fstrcpy(PrinterName,strrchr(service,'\\')+1);       /* name of queue */
2533           strlower(PrinterName);                             /* in lower case */
2534
2535           p = rdata;                          /* received data */
2536           for( i = 0; i < SVAL(rparam,4); ++i)
2537             {
2538               JobId = SVAL(p,0);
2539               Priority = SVAL(p,2);
2540               UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
2541               strlower(UserName);
2542               Priority = SVAL(p,2);
2543               JobTime = make_unix_date3( p + 12);
2544               JobTimeStr = asctime(LocalTime( &JobTime));
2545               Size = IVAL(p,16);
2546               JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
2547             
2548
2549               printf("%s-%u    %s    priority %u   %s    %s   %u bytes\n", 
2550                 PrinterName, JobId, UserName,
2551                 Priority, JobTimeStr, JobName, Size);
2552    
2553 #if 0 /* DEBUG code */
2554               printf("Job Id: \"%u\"\n", SVAL(p,0));
2555               printf("Priority: \"%u\"\n", SVAL(p,2));
2556             
2557               printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
2558               printf("Position: \"%u\"\n", SVAL(p,8));
2559               printf("Status: \"%u\"\n", SVAL(p,10));
2560             
2561               JobTime = make_unix_date3( p + 12);
2562               printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
2563               printf("date: \"%u\"\n", SVAL(p,12));
2564
2565               printf("Size: \"%u\"\n", SVAL(p,16));
2566               printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2567               printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2568 #endif /* DEBUG CODE */ 
2569               p += 28;
2570             }
2571         }
2572     }
2573   else                  /* cli_call_api() failed */
2574     {
2575       printf("Failed, error = %d\n", result_code);
2576     }
2577
2578   /* If any parameters or data were returned, free the storage. */
2579   if(rparam) free(rparam);
2580   if(rdata) free(rdata);
2581
2582   return;
2583 }
2584
2585 /****************************************************************************
2586 show information about a print queue
2587 ****************************************************************************/
2588 static void cmd_qinfo(char *inbuf,char *outbuf )
2589 {
2590   char *rparam = NULL;
2591   char *rdata = NULL;
2592   char *p;
2593   int rdrcnt, rprcnt;
2594   pstring param;
2595   int result_code=0;
2596   
2597   bzero(param,sizeof(param));
2598
2599   p = param;
2600   SSVAL(p,0,70);                        /* API function number 70 (DosPrintQGetInfo) */
2601   p += 2;
2602   pstrcpy(p,"zWrLh");                   /* parameter description? */
2603   p = skip_string(p,1);
2604   pstrcpy(p,"zWWWWzzzzWWzzl");          /* returned data format */
2605   p = skip_string(p,1);
2606   pstrcpy(p,strrchr(service,'\\')+1);   /* name of queue */
2607   p = skip_string(p,1);
2608   SSVAL(p,0,3);                         /* API function level 3, just queue info, no job info */
2609   SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
2610   p += 4;
2611   pstrcpy(p,"");                                /* subformat */
2612   p = skip_string(p,1);
2613
2614   DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
2615   if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
2616            10, 4096,
2617                &rprcnt, &rdrcnt,
2618                param, NULL, NULL,
2619                &rparam, &rdata) )
2620         {
2621         int converter;
2622         result_code = SVAL(rparam,0);
2623         converter = SVAL(rparam,2);             /* conversion factor */
2624
2625         DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2626
2627         if (result_code == 0)                   /* if no error, */
2628             {
2629             p = rdata;                          /* received data */
2630
2631             printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
2632             printf("Priority: %u\n", SVAL(p,4) );
2633             printf("Start time: %u\n", SVAL(p,6) );
2634             printf("Until time: %u\n", SVAL(p,8) );
2635             printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
2636             printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
2637             printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2638             printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2639             printf("Status: %u\n", SVAL(p,28) );
2640             printf("Jobs: %u\n", SVAL(p,30) );
2641             printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
2642             printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
2643
2644             /* Dump the driver data */
2645             {
2646             int count, x, y, c;
2647             char *ddptr;
2648
2649             ddptr = rdata + SVAL(p,40) - converter;
2650             if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
2651             printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
2652
2653             for(x=8; x < count; x+=16)
2654                 {
2655                 for(y=0; y < 16; y++)
2656                     {
2657                     if( (x+y) < count )
2658                         printf("%2.2X ", CVAL(ddptr,(x+y)) );
2659                     else
2660                         fputs("   ", stdout);
2661                     }
2662                 for(y=0; y < 16 && (x+y) < count; y++)
2663                     {
2664                     c = CVAL(ddptr,(x+y));
2665                     if(isprint(c))
2666                         fputc(c, stdout);
2667                     else
2668                         fputc('.', stdout);
2669                     }
2670                 fputc('\n', stdout);
2671                 }
2672             }
2673             
2674             }
2675         }
2676   else                  /* cli_call_api() failed */
2677         {
2678         printf("Failed, error = %d\n", result_code);
2679         }
2680
2681   /* If any parameters or data were returned, free the storage. */
2682   if(rparam) free(rparam);
2683   if(rdata) free(rdata);
2684
2685   return;
2686 }
2687
2688 /****************************************************************************
2689 delete some files
2690 ****************************************************************************/
2691 static void do_del(file_info *finfo)
2692 {
2693   char *p;
2694   char *inbuf,*outbuf;
2695   pstring mask;
2696
2697   pstrcpy(mask,cur_dir);
2698   pstrcat(mask,finfo->name);
2699
2700   if (finfo->mode & aDIR) 
2701     return;
2702
2703   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2704   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2705   
2706   if (!inbuf || !outbuf)
2707     {
2708       DEBUG(0,("out of memory\n"));
2709       return;
2710     }
2711
2712   bzero(outbuf,smb_size);
2713   set_message(outbuf,1,2 + strlen(mask),True);
2714   
2715   CVAL(outbuf,smb_com) = SMBunlink;
2716   SSVAL(outbuf,smb_tid,cnum);
2717   cli_setup_pkt(outbuf);
2718
2719   SSVAL(outbuf,smb_vwv0,0);
2720   
2721   p = smb_buf(outbuf);
2722   *p++ = 4;      
2723   pstrcpy(p,mask);
2724   
2725   send_smb(Client,outbuf);
2726   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2727   
2728   if (CVAL(inbuf,smb_rcls) != 0)
2729     DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2730
2731   free(inbuf);free(outbuf);
2732   
2733 }
2734
2735 /****************************************************************************
2736 delete some files
2737 ****************************************************************************/
2738 static void cmd_del(char *inbuf,char *outbuf )
2739 {
2740   pstring mask;
2741   fstring buf;
2742   int attribute = aSYSTEM | aHIDDEN;
2743
2744   if (recurse)
2745     attribute |= aDIR;
2746   
2747   pstrcpy(mask,cur_dir);
2748     
2749   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2750     {
2751       DEBUG(0,("del <filename>\n"));
2752       return;
2753     }
2754   pstrcat(mask,buf);
2755
2756   do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False,False);
2757 }
2758
2759
2760 /****************************************************************************
2761 remove a directory
2762 ****************************************************************************/
2763 static void cmd_rmdir(char *inbuf,char *outbuf )
2764 {
2765   pstring mask;
2766   fstring buf;
2767   char *p;
2768   
2769   pstrcpy(mask,cur_dir);
2770   
2771   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2772     {
2773       DEBUG(0,("rmdir <dirname>\n"));
2774       return;
2775     }
2776   pstrcat(mask,buf);
2777
2778   bzero(outbuf,smb_size);
2779   set_message(outbuf,0,2 + strlen(mask),True);
2780   
2781   CVAL(outbuf,smb_com) = SMBrmdir;
2782   SSVAL(outbuf,smb_tid,cnum);
2783   cli_setup_pkt(outbuf);
2784
2785   
2786   p = smb_buf(outbuf);
2787   *p++ = 4;      
2788   pstrcpy(p,mask);
2789   
2790   send_smb(Client,outbuf);
2791   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2792   
2793   if (CVAL(inbuf,smb_rcls) != 0)
2794     {
2795       DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2796       return;
2797     }
2798   
2799 }
2800
2801 /****************************************************************************
2802 rename some files
2803 ****************************************************************************/
2804 static void cmd_rename(char *inbuf,char *outbuf )
2805 {
2806   pstring src,dest;
2807   fstring buf,buf2;
2808   char *p;
2809   
2810   pstrcpy(src,cur_dir);
2811   pstrcpy(dest,cur_dir);
2812   
2813   if (!next_token(NULL,buf,NULL,sizeof(buf)) || 
2814       !next_token(NULL,buf2,NULL, sizeof(buf2)))
2815     {
2816       DEBUG(0,("rename <src> <dest>\n"));
2817       return;
2818     }
2819   pstrcat(src,buf);
2820   pstrcat(dest,buf2);
2821
2822   bzero(outbuf,smb_size);
2823   set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
2824   
2825   CVAL(outbuf,smb_com) = SMBmv;
2826   SSVAL(outbuf,smb_tid,cnum);
2827   SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
2828   cli_setup_pkt(outbuf);
2829   
2830   p = smb_buf(outbuf);
2831   *p++ = 4;      
2832   pstrcpy(p,src);
2833   p = skip_string(p,1);
2834   *p++ = 4;      
2835   pstrcpy(p,dest);
2836   
2837   send_smb(Client,outbuf);
2838   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2839   
2840   if (CVAL(inbuf,smb_rcls) != 0)
2841     {
2842       DEBUG(0,("%s renaming files\n",smb_errstr(inbuf)));
2843       return;
2844     }
2845   
2846 }
2847
2848
2849 /****************************************************************************
2850 toggle the prompt flag
2851 ****************************************************************************/
2852 static void cmd_prompt(char *dum_in, char *dum_out)
2853 {
2854   prompt = !prompt;
2855   DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2856 }
2857
2858
2859 /****************************************************************************
2860 set the newer than time
2861 ****************************************************************************/
2862 static void cmd_newer(char *dum_in, char *dum_out)
2863 {
2864   fstring buf;
2865   BOOL ok;
2866   SMB_STRUCT_STAT sbuf;
2867
2868   ok = next_token(NULL,buf,NULL,sizeof(buf));
2869   if (ok && (dos_stat(buf,&sbuf) == 0))
2870     {
2871       newer_than = sbuf.st_mtime;
2872       DEBUG(1,("Getting files newer than %s",
2873                asctime(LocalTime(&newer_than))));
2874     }
2875   else
2876     newer_than = 0;
2877
2878   if (ok && newer_than == 0)
2879     DEBUG(0,("Error setting newer-than time\n"));
2880 }
2881
2882 /****************************************************************************
2883 set the archive level
2884 ****************************************************************************/
2885 static void cmd_archive(char *dum_in, char *dum_out)
2886 {
2887   fstring buf;
2888
2889   if (next_token(NULL,buf,NULL,sizeof(buf))) {
2890     archive_level = atoi(buf);
2891   } else
2892     DEBUG(0,("Archive level is %d\n",archive_level));
2893 }
2894
2895 /****************************************************************************
2896 toggle the lowercaseflag
2897 ****************************************************************************/
2898 static void cmd_lowercase(char *dum_in, char *dum_out)
2899 {
2900   lowercase = !lowercase;
2901   DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2902 }
2903
2904
2905
2906
2907 /****************************************************************************
2908 toggle the recurse flag
2909 ****************************************************************************/
2910 static void cmd_recurse(char *dum_in, char *dum_out)
2911 {
2912   recurse = !recurse;
2913   DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2914 }
2915
2916 /****************************************************************************
2917 toggle the translate flag
2918 ****************************************************************************/
2919 static void cmd_translate(char *dum_in, char *dum_out)
2920 {
2921   translation = !translation;
2922   DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2923         translation?"on":"off"));
2924 }
2925
2926
2927 /****************************************************************************
2928 do a printmode command
2929 ****************************************************************************/
2930 static void cmd_printmode(char *dum_in, char *dum_out)
2931 {
2932   fstring buf;
2933   fstring mode;
2934
2935   if (next_token(NULL,buf,NULL,sizeof(buf)))
2936     {
2937       if (strequal(buf,"text"))
2938         printmode = 0;      
2939       else
2940         {
2941           if (strequal(buf,"graphics"))
2942             printmode = 1;
2943           else
2944             printmode = atoi(buf);
2945         }
2946     }
2947
2948   switch(printmode)
2949     {
2950     case 0: 
2951       fstrcpy(mode,"text");
2952       break;
2953     case 1: 
2954       fstrcpy(mode,"graphics");
2955       break;
2956     default: 
2957       slprintf(mode,sizeof(mode)-1,"%d",printmode);
2958       break;
2959     }
2960
2961   DEBUG(2,("the printmode is now %s\n",mode));
2962 }
2963
2964 /****************************************************************************
2965 do the lcd command
2966 ****************************************************************************/
2967 static void cmd_lcd(char *dum_in, char *dum_out)
2968 {
2969   fstring buf;
2970   pstring d;
2971
2972   if (next_token(NULL,buf,NULL,sizeof(buf)))
2973     dos_chdir(buf);
2974   DEBUG(2,("the local directory is now %s\n",GetWd(d)));
2975 }
2976
2977
2978 /****************************************************************************
2979 try and browse available connections on a host
2980 ****************************************************************************/
2981 static BOOL browse_host(BOOL sort)
2982 {
2983   char *rparam = NULL;
2984   char *rdata = NULL;
2985   char *p;
2986   int rdrcnt,rprcnt;
2987   pstring param;
2988   int count = -1;
2989
2990   /* now send a SMBtrans command with api RNetShareEnum */
2991   p = param;
2992   SSVAL(p,0,0); /* api number */
2993   p += 2;
2994   pstrcpy(p,"WrLeh");
2995   p = skip_string(p,1);
2996   pstrcpy(p,"B13BWz");
2997   p = skip_string(p,1);
2998   SSVAL(p,0,1);
2999   SSVAL(p,2,BUFFER_SIZE);
3000   p += 4;
3001
3002   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
3003              1024, BUFFER_SIZE,
3004              &rprcnt,&rdrcnt,
3005              param,NULL, NULL,
3006              &rparam,&rdata))
3007   {
3008     int res = SVAL(rparam,0);
3009     int converter=SVAL(rparam,2);
3010     int i;
3011     BOOL long_share_name=False;
3012       
3013     if (res == 0 || res == ERRmoredata)
3014     {
3015       count=SVAL(rparam,4);
3016       p = rdata;
3017
3018       if (count > 0)
3019       {
3020         printf("\n\tSharename      Type      Comment\n");
3021         printf("\t---------      ----      -------\n");
3022       }
3023
3024       if (sort)
3025         qsort(p,count,20,QSORT_CAST StrCaseCmp);
3026
3027       for (i=0;i<count;i++)
3028       {
3029         char *sname = p;
3030         int type = SVAL(p,14);
3031         int comment_offset = IVAL(p,16) & 0xFFFF;
3032         fstring typestr;
3033         *typestr=0;
3034
3035         switch (type)
3036         {
3037           case STYPE_DISKTREE:
3038             fstrcpy(typestr,"Disk"); break;
3039           case STYPE_PRINTQ:
3040             fstrcpy(typestr,"Printer"); break;        
3041           case STYPE_DEVICE:
3042             fstrcpy(typestr,"Device"); break;
3043           case STYPE_IPC:
3044             fstrcpy(typestr,"IPC"); break;      
3045         }
3046
3047         printf("\t%-15.15s%-10.10s%s\n",
3048                sname, typestr,
3049                comment_offset?rdata+comment_offset-converter:"");
3050           
3051         if (strlen(sname)>8) long_share_name=True;
3052           
3053         p += 20;
3054       }
3055
3056       if (long_share_name) {
3057         printf("\nNOTE: There were share names longer than 8 chars.\n\
3058 On older clients these may not be accessible or may give browsing errors\n");
3059       }
3060
3061       if(res == ERRmoredata)
3062         printf("\nNOTE: More data was available, the list was truncated.\n");
3063     }
3064   }
3065   
3066   if (rparam) free(rparam);
3067   if (rdata) free(rdata);
3068
3069   return(count>0);
3070 }
3071
3072
3073 /****************************************************************************
3074 get some server info
3075 ****************************************************************************/
3076 static void server_info(void)
3077 {
3078   char *rparam = NULL;
3079   char *rdata = NULL;
3080   char *p;
3081   int rdrcnt,rprcnt;
3082   pstring param;
3083
3084   bzero(param,sizeof(param));
3085
3086   p = param;
3087   SSVAL(p,0,63);                /* NetServerGetInfo()? */
3088   p += 2;
3089   pstrcpy(p,"WrLh");
3090   p = skip_string(p,1);
3091   pstrcpy(p,"zzzBBzz");
3092   p = skip_string(p,1);
3093   SSVAL(p,0,10); /* level 10 */
3094   SSVAL(p,2,1000);
3095   p += 6;
3096
3097   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
3098            6, 1000,
3099                &rprcnt,&rdrcnt,
3100                param,NULL, NULL,
3101                &rparam,&rdata))
3102     {
3103       int res = SVAL(rparam,0);
3104       int converter=SVAL(rparam,2);
3105
3106       if (res == 0)
3107         {
3108       p = rdata;
3109
3110       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3111              rdata+SVAL(p,0)-converter,
3112              rdata+SVAL(p,4)-converter,
3113              rdata+SVAL(p,8)-converter,
3114              rdata+SVAL(p,14)-converter);
3115     }
3116     }
3117
3118   if (rparam) free(rparam);
3119   if (rdata) free(rdata);
3120
3121   return;
3122 }
3123
3124
3125 /****************************************************************************
3126 try and browse available connections on a host
3127 ****************************************************************************/
3128 static BOOL list_servers(char *wk_grp)
3129 {
3130   char *rparam = NULL;
3131   char *rdata = NULL;
3132   int rdrcnt,rprcnt;
3133   char *p,*svtype_p;
3134   pstring param;
3135   int uLevel = 1;
3136   int count = 0;
3137   BOOL ok = False;
3138   BOOL generic_request = False;
3139
3140
3141   if (strequal(wk_grp,"WORKGROUP")) {
3142     /* we won't specify a workgroup */
3143     generic_request = True;
3144   } 
3145
3146   /* now send a SMBtrans command with api ServerEnum? */
3147   p = param;
3148   SSVAL(p,0,0x68); /* api number */
3149   p += 2;
3150
3151   pstrcpy(p,generic_request?"WrLehDO":"WrLehDz");
3152   p = skip_string(p,1);
3153
3154   pstrcpy(p,"B16BBDz");
3155
3156   p = skip_string(p,1);
3157   SSVAL(p,0,uLevel);
3158   SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
3159   p += 4;
3160
3161   svtype_p = p;
3162   p += 4;
3163
3164   if (!generic_request) {
3165     pstrcpy(p, wk_grp);
3166     p = skip_string(p,1);
3167   }
3168
3169   /* first ask for a list of servers in this workgroup */
3170   SIVAL(svtype_p,0,SV_TYPE_ALL);
3171
3172   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
3173            8, BUFFER_SIZE - SAFETY_MARGIN,
3174            &rprcnt,&rdrcnt,
3175            param,NULL, NULL,
3176            &rparam,&rdata))
3177   {
3178     int res = SVAL(rparam,0);
3179     int converter=SVAL(rparam,2);
3180     int i;
3181
3182     if (res == 0 || res == ERRmoredata) {       
3183       char *p2 = rdata;
3184       count=SVAL(rparam,4);
3185
3186       if (count > 0) {
3187         printf("\n\nThis machine has a browse list:\n");
3188         printf("\n\tServer               Comment\n");
3189         printf("\t---------            -------\n");
3190       }
3191         
3192       for (i=0;i<count;i++) {
3193         char *sname = p2;
3194         int comment_offset = IVAL(p2,22) & 0xFFFF;
3195         printf("\t%-16.16s     %s\n", sname,
3196                comment_offset?rdata+comment_offset-converter:"");
3197
3198         ok=True;
3199         p2 += 26;
3200       }
3201
3202       if(res == ERRmoredata)
3203         printf("\nNOTE: More data was available, the list was truncated.\n");
3204     }
3205   }
3206
3207   if (rparam) {free(rparam); rparam = NULL;}
3208   if (rdata) {free(rdata); rdata = NULL;}
3209
3210   /* now ask for a list of workgroups */
3211   SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
3212
3213   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
3214            8, BUFFER_SIZE - SAFETY_MARGIN,
3215            &rprcnt,&rdrcnt,
3216            param,NULL, NULL,
3217            &rparam,&rdata))
3218   {
3219     int res = SVAL(rparam,0);
3220     int converter=SVAL(rparam,2);
3221     int i;
3222
3223     if (res == 0 || res == ERRmoredata) {
3224       char *p2 = rdata;
3225       count=SVAL(rparam,4);
3226
3227       if (count > 0) {
3228         printf("\n\nThis machine has a workgroup list:\n");
3229         printf("\n\tWorkgroup            Master\n");
3230         printf("\t---------            -------\n");
3231       }
3232         
3233       for (i=0;i<count;i++) {
3234         char *sname = p2;
3235         int comment_offset = IVAL(p2,22) & 0xFFFF;
3236         printf("\t%-16.16s     %s\n", sname,
3237                comment_offset?rdata+comment_offset-converter:"");
3238           
3239         ok=True;
3240         p2 += 26;
3241       }
3242
3243       if(res == ERRmoredata)
3244         printf("\nNOTE: More data was available, the list was truncated.\n");
3245     }
3246   }
3247
3248   if (rparam) free(rparam);
3249   if (rdata) free(rdata);
3250
3251   return(ok);
3252 }
3253
3254
3255 /* Some constants for completing filename arguments */
3256
3257 #define COMPL_NONE        0          /* No completions */
3258 #define COMPL_REMOTE      1          /* Complete remote filename */
3259 #define COMPL_LOCAL       2          /* Complete local filename */
3260
3261 /* This defines the commands supported by this client */
3262 struct
3263 {
3264   char *name;
3265   void (*fn)(char *, char *);
3266   char *description;
3267   char compl_args[2];      /* Completion argument info */
3268 } commands[] = 
3269 {
3270   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3271   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3272   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3273   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
3274   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
3275   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
3276   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
3277   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
3278   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
3279   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
3280   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
3281   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
3282   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
3283   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3284   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3285   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3286   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3287   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3288   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3289   {"pq",cmd_p_queue_4,"enumerate the print queue",{COMPL_NONE,COMPL_NONE}},
3290   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3291   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3292   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},  
3293   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
3294   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
3295   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
3296   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
3297   {"qinfo",cmd_qinfo,"show print queue information",{COMPL_NONE,COMPL_NONE}},
3298   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
3299   {"quit",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3300   {"q",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3301   {"exit",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3302   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
3303   {"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",{COMPL_NONE,COMPL_NONE}},
3304   {"tar",cmd_tar,"tar <c|x>[IXbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
3305   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
3306   {"tarmode",cmd_tarmode,
3307      "<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
3308   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
3309   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3310   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3311   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
3312   {"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
3313 };
3314
3315
3316 /*******************************************************************
3317   lookup a command string in the list of commands, including 
3318   abbreviations
3319   ******************************************************************/
3320 static int process_tok(fstring tok)
3321 {
3322   int i = 0, matches = 0;
3323   int cmd=0;
3324   int tok_len = strlen(tok);
3325   
3326   while (commands[i].fn != NULL)
3327     {
3328       if (strequal(commands[i].name,tok))
3329         {
3330           matches = 1;
3331           cmd = i;
3332           break;
3333         }
3334       else if (strnequal(commands[i].name, tok, tok_len))
3335         {
3336           matches++;
3337           cmd = i;
3338         }
3339       i++;
3340     }
3341   
3342   if (matches == 0)
3343     return(-1);
3344   else if (matches == 1)
3345     return(cmd);
3346   else
3347     return(-2);
3348 }
3349
3350 /****************************************************************************
3351 help
3352 ****************************************************************************/
3353 static void cmd_help(char *dum_in, char *dum_out)
3354 {
3355   int i=0,j;
3356   fstring buf;
3357
3358   if (next_token(NULL,buf,NULL,sizeof(buf)))
3359     {
3360       if ((i = process_tok(buf)) >= 0)
3361         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
3362     }
3363   else
3364     while (commands[i].description)
3365       {
3366         for (j=0; commands[i].description && (j<5); j++) {
3367           DEBUG(0,("%-15s",commands[i].name));
3368           i++;
3369         }
3370         DEBUG(0,("\n"));
3371       }
3372 }
3373
3374
3375
3376 /****************************************************************************
3377 wait for keyboard activity, swallowing network packets
3378 ****************************************************************************/
3379 static void wait_keyboard(char *buffer)
3380 {
3381   fd_set fds;
3382   int selrtn;
3383   struct timeval timeout;
3384   
3385   while (1) 
3386     {
3387       extern int Client;
3388       FD_ZERO(&fds);
3389       FD_SET(Client,&fds);
3390       FD_SET(fileno(stdin),&fds);
3391
3392       timeout.tv_sec = 20;
3393       timeout.tv_usec = 0;
3394       selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
3395       
3396       if (FD_ISSET(fileno(stdin),&fds))
3397         return;
3398
3399       /* We deliberately use receive_smb instead of
3400          client_receive_smb as we want to receive
3401          session keepalives and then drop them here.
3402        */
3403       if (FD_ISSET(Client,&fds))
3404         receive_smb(Client,buffer,0);
3405       
3406       chkpath("\\",False);
3407     }  
3408 }
3409
3410 #ifdef HAVE_LIBREADLINE
3411
3412 /****************************************************************************
3413   completion routines for GNU Readline
3414 ****************************************************************************/
3415
3416 /* To avoid filename completion being activated when no valid
3417    completions are found, we assign this stub completion function
3418    to the rl_completion_entry_function variable. */
3419
3420 char *complete_cmd_null(char *text, int state)
3421 {
3422   return NULL;
3423 }
3424
3425 /* Argh.  This is starting to get ugly.  We need to be able to pass data
3426    back from the do_dir() iterator function. */
3427
3428 static int compl_state;
3429 static char *compl_text;
3430 static pstring result;
3431
3432 /* Iterator function for do_dir() */
3433
3434 void complete_process_file(file_info *f)
3435 {
3436   /* Do we have a partial match? */
3437
3438   if ((compl_state >= 0) && (strncmp(compl_text, f->name, 
3439                                      strlen(compl_text)) == 0)) {
3440
3441     /* Return filename if we have made enough matches */
3442
3443     if (compl_state == 0) {
3444       pstrcpy(result, f->name);
3445       compl_state = -1;
3446
3447       return;
3448     }
3449     compl_state--;
3450   }
3451 }
3452
3453 /* Complete a remote file */
3454
3455 char *complete_remote_file(char *text, int state)
3456 {
3457   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3458   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3459   int attribute = aDIR | aSYSTEM | aHIDDEN;
3460   pstring mask;
3461
3462   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3463     return(NULL);
3464
3465   /* Create dir mask */
3466
3467   pstrcpy(mask, cur_dir);
3468   pstrcat(mask, "*");
3469
3470   /* Initialise static vars for filename match */
3471
3472   compl_text = text;
3473   compl_state = state;
3474   result[0] = '\0';
3475
3476   /* Iterate over all files in directory */
3477
3478   do_dir(InBuffer, OutBuffer, mask, attribute, complete_process_file, False, 
3479          True);
3480
3481   /* Clean up */
3482
3483   free(InBuffer);
3484   free(OutBuffer);
3485
3486   /* Return matched filename */
3487
3488   if (result[0] != '\0') {
3489     return strdup(result);      /* Readline will dispose of strings */
3490   } else {
3491     return NULL;
3492   }
3493 }
3494
3495 /* Complete a smbclient command */
3496
3497 char *complete_cmd(char *text, int state)
3498 {
3499   static int cmd_index;
3500   char *name;
3501
3502   /* Initialise */
3503   
3504   if (state == 0) {
3505     cmd_index = 0;
3506   }
3507
3508   /* Return the next name which partially matches the list of commands */
3509
3510   while (strlen(name = commands[cmd_index++].name) > 0) {
3511     if (strncmp(name, text, strlen(text)) == 0) {
3512       return strdup(name);
3513     }
3514   }
3515
3516   return NULL;
3517 }
3518
3519 /* Main completion function for smbclient.  Work out which word we are
3520    trying to complete and call the appropriate function. */
3521
3522 char **completion_fn(char *text, int start, int end)
3523 {
3524   int i, num_words, cmd_index;
3525   char lastch = ' ';
3526
3527   /* If we are at the start of a word, we are completing a smbclient
3528      command. */
3529
3530   if (start == 0) {
3531     return completion_matches(text, complete_cmd);
3532   }
3533
3534   /* Count # of words in command */
3535
3536   num_words = 0;
3537   for (i = 0; i <= end; i++) {
3538     if ((rl_line_buffer[i] != ' ') && (lastch == ' '))
3539       num_words++;
3540     lastch = rl_line_buffer[i];
3541   }
3542
3543   if (rl_line_buffer[end] == ' ')
3544     num_words++;
3545
3546   /* Work out which command we are completing for */
3547
3548   for (cmd_index = 0; strcmp(commands[cmd_index].name, "") != 0; 
3549        cmd_index++) {
3550
3551     /* Check each command in array */
3552
3553     if (strncmp(rl_line_buffer, commands[cmd_index].name,
3554                 strlen(commands[cmd_index].name)) == 0) {
3555
3556       /* Call appropriate completion function */
3557
3558       if ((num_words == 2) || (num_words == 3)) {
3559         switch (commands[cmd_index].compl_args[num_words - 2]) {
3560
3561         case COMPL_REMOTE:
3562           return completion_matches(text, complete_remote_file);
3563           break;
3564
3565         case COMPL_LOCAL:
3566           return completion_matches(text, filename_completion_function);
3567           break;
3568
3569         default:
3570             /* An invalid completion type */
3571             break;
3572         }
3573       }
3574
3575       /* We're either completing an argument > 3 or found an invalid
3576          completion type.  Either way do nothing about it. */
3577
3578       break;
3579     }
3580   }
3581  
3582   return NULL;
3583 }
3584
3585 #endif /* HAVE_LIBREADLINE */
3586
3587 /****************************************************************************
3588   process commands from the client
3589 ****************************************************************************/
3590 static BOOL process(char *base_directory)
3591 {
3592   pstring line;
3593   char *cmd;
3594
3595   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3596   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3597
3598   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3599     return(False);
3600   
3601   bzero(OutBuffer,smb_size);
3602
3603   if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
3604     return(False);
3605
3606   if (*base_directory) do_cd(base_directory);
3607
3608   cmd = cmdstr;
3609   if (cmd[0] != '\0') while (cmd[0] != '\0')
3610     {
3611       char *p;
3612       fstring tok;
3613       int i;
3614
3615       if ((p = strchr(cmd, ';')) == 0)
3616         {
3617           strncpy(line, cmd, 999);
3618           line[1000] = '\0';
3619           cmd += strlen(cmd);
3620         }
3621       else
3622         {
3623           if (p - cmd > 999) p = cmd + 999;
3624           strncpy(line, cmd, p - cmd);
3625           line[p - cmd] = '\0';
3626           cmd = p + 1;
3627         }
3628
3629       /* input language code to internal one */
3630       CNV_INPUT (line);
3631       
3632       /* and get the first part of the command */
3633       {
3634         char *ptr = line;
3635         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3636       }
3637
3638       if ((i = process_tok(tok)) >= 0)
3639         commands[i].fn(InBuffer,OutBuffer);
3640       else if (i == -2)
3641         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
3642       else
3643         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
3644     }
3645   else while (!feof(stdin))
3646     {
3647       fstring tok;
3648       int i;
3649
3650       bzero(OutBuffer,smb_size);
3651
3652 #ifdef HAVE_LIBREADLINE
3653
3654       {
3655         pstring prompt;
3656         
3657         /* Read input using GNU Readline */
3658
3659         slprintf(prompt, sizeof(prompt) - 1, "smb: %s> ", CNV_LANG(cur_dir));
3660         if (!readline(prompt))
3661           break;
3662
3663         /* Copy read line to samba buffer */
3664         
3665         pstrcpy(line, rl_line_buffer);
3666         pstrcat(line, "\n");
3667
3668         /* Add line to history */
3669
3670         if (strlen(line) > 0)
3671           add_history(line);
3672       }
3673
3674 #else
3675
3676       /* display a prompt */
3677       DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
3678       dbgflush( );
3679
3680       wait_keyboard(InBuffer);
3681   
3682       /* and get a response */
3683       if (!fgets(line,1000,stdin))
3684         break;
3685
3686 #endif
3687
3688       /* input language code to internal one */
3689       CNV_INPUT (line);
3690
3691       /* special case - first char is ! */
3692       if (*line == '!')
3693         {
3694           system(line + 1);
3695           continue;
3696         }
3697       
3698       /* and get the first part of the command */
3699       {
3700         char *ptr = line;
3701         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3702       }
3703
3704       if ((i = process_tok(tok)) >= 0)
3705         commands[i].fn(InBuffer,OutBuffer);
3706       else if (i == -2)
3707         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
3708       else
3709         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
3710     }
3711   
3712   cli_send_logout(InBuffer,OutBuffer);
3713   return(True);
3714 }
3715
3716 /****************************************************************************
3717 usage on the program
3718 ****************************************************************************/
3719 static void usage(char *pname)
3720 {
3721   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
3722            pname));
3723
3724   DEBUG(0,("\nVersion %s\n",VERSION));
3725   DEBUG(0,("\t-p port               connect to the specified port\n"));
3726   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
3727   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
3728   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
3729   DEBUG(0,("\t-N                    don't ask for a password\n"));
3730   DEBUG(0,("\t-P                    connect to service as a printer\n"));
3731   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
3732   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
3733   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
3734   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
3735   DEBUG(0,("\t-R name resolve order use these name resolution services only\n"));
3736   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
3737   DEBUG(0,("\t-U username           set the network username\n"));
3738   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
3739   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
3740   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
3741   DEBUG(0,("\t-T<c|x>IXgbNan        command line tar\n"));
3742   DEBUG(0,("\t-D directory          start from directory\n"));
3743   DEBUG(0,("\n"));
3744 }
3745
3746 /****************************************************************************
3747   main program
3748 ****************************************************************************/
3749  int main(int argc,char *argv[])
3750 {
3751   fstring base_directory;
3752   char *pname = argv[0];
3753   int port = SMB_PORT;
3754   int opt;
3755   extern FILE *dbf;
3756   extern char *optarg;
3757   extern int optind;
3758   pstring query_host;
3759   BOOL message = False;
3760   BOOL nt_domain_logon = False;
3761   BOOL explicit_user = False;
3762   extern char tar_type;
3763   static pstring servicesf = CONFIGFILE;
3764   pstring term_code;
3765   pstring new_name_resolve_order;
3766   char *p;
3767
3768 #ifdef KANJI
3769   pstrcpy(term_code, KANJI);
3770 #else /* KANJI */
3771   *term_code = 0;
3772 #endif /* KANJI */
3773
3774   *query_host = 0;
3775   *base_directory = 0;
3776
3777   *new_name_resolve_order = 0;
3778
3779   DEBUGLEVEL = 2;
3780
3781   setup_logging(pname,True);
3782
3783   TimeInit();
3784   charset_initialise();
3785
3786   if(!get_myname(myhostname,NULL))
3787   {
3788     DEBUG(0,("Failed to get my hostname.\n"));
3789   }
3790
3791   if (!lp_load(servicesf,True,False,False)) {
3792     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
3793   }
3794
3795   codepage_initialise(lp_client_code_page());
3796
3797   interpret_coding_system(term_code);
3798
3799 #ifdef WITH_SSL
3800   sslutil_init(0);
3801 #endif
3802
3803   pstrcpy(workgroup,lp_workgroup());
3804
3805   load_interfaces();
3806   pid = getpid();
3807   uid = getuid();
3808   gid = getgid();
3809   mid = pid + 100;
3810   myumask = umask(0);
3811   umask(myumask);
3812
3813   if (getenv("USER"))
3814   {
3815     pstrcpy(username,getenv("USER"));
3816
3817     /* modification to support userid%passwd syntax in the USER var
3818        25.Aug.97, jdblair@uab.edu */
3819
3820     if ((p=strchr(username,'%')))
3821     {
3822       *p = 0;
3823       pstrcpy(password,p+1);
3824       got_pass = True;
3825       memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
3826     }
3827     strupper(username);
3828   }
3829
3830  /* modification to support PASSWD environmental var
3831   25.Aug.97, jdblair@uab.edu */
3832
3833   if (getenv("PASSWD")) {
3834     pstrcpy(password,getenv("PASSWD"));
3835     got_pass = True;
3836   }
3837
3838   if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
3839     int fd = -1;
3840     BOOL close_it;
3841     pstring spec;
3842     char pass[128];
3843
3844     if ((p = getenv("PASSWD_FD")) != NULL) {
3845       pstrcpy(spec, "descriptor ");
3846       pstrcat(spec, p);
3847       sscanf(p, "%d", &fd);
3848       close_it = False;
3849     } else if ((p = getenv("PASSWD_FILE")) != NULL) {
3850       fd = open(p, O_RDONLY);
3851       pstrcpy(spec, p);
3852       if (fd < 0) {
3853         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
3854                 spec, strerror(errno));
3855         exit(1);
3856       }
3857       close_it = True;
3858     }
3859     for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
3860         p && p - pass < sizeof(pass);) {
3861       switch (read(fd, p, 1)) {
3862       case 1:
3863         if (*p != '\n' && *p != '\0') {
3864           *++p = '\0'; /* advance p, and null-terminate pass */
3865           break;
3866         }
3867       case 0:
3868         if (p - pass) {
3869           *p = '\0'; /* null-terminate it, just in case... */
3870           p = NULL; /* then force the loop condition to become false */
3871           break;
3872         } else {
3873           fprintf(stderr, "Error reading password from file %s: %s\n",
3874                   spec, "empty password\n");
3875           exit(1);
3876         }
3877
3878       default:
3879         fprintf(stderr, "Error reading password from file %s: %s\n",
3880                 spec, strerror(errno));
3881         exit(1);
3882       }
3883     }
3884     pstrcpy(password, pass);
3885     got_pass = True;
3886     if (close_it)
3887       close(fd);
3888   }
3889
3890   if (*username == 0 && getenv("LOGNAME"))
3891     {
3892       pstrcpy(username,getenv("LOGNAME"));
3893       strupper(username);
3894     }
3895
3896   if (argc < 2)
3897     {
3898       usage(pname);
3899       exit(1);
3900     }
3901   
3902   if (*argv[1] != '-')
3903     {
3904
3905       pstrcpy(service,argv[1]);  
3906       /* Convert any '/' characters in the service name to '\' characters */
3907       string_replace( service, '/','\\');
3908       argc--;
3909       argv++;
3910
3911       if (count_chars(service,'\\') < 3)
3912         {
3913           usage(pname);
3914           printf("\n%s: Not enough '\\' characters in service\n",service);
3915           exit(1);
3916         }
3917
3918 /*
3919       if (count_chars(service,'\\') > 3)
3920         {
3921           usage(pname);
3922           printf("\n%s: Too many '\\' characters in service\n",service);
3923           exit(1);
3924         }
3925         */
3926
3927       if (argc > 1 && (*argv[1] != '-'))
3928         {
3929           got_pass = True;
3930           pstrcpy(password,argv[1]);  
3931           memset(argv[1],'X',strlen(argv[1]));
3932           argc--;
3933           argv++;
3934         }
3935     }
3936
3937   while ((opt = 
3938           getopt(argc, argv,"s:B:O:R:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
3939     switch (opt)
3940       {
3941       case 'm':
3942         max_protocol = interpret_protocol(optarg,max_protocol);
3943         break;
3944       case 'O':
3945         pstrcpy(user_socket_options,optarg);
3946         break;  
3947       case 'R':
3948         pstrcpy(new_name_resolve_order, optarg);
3949         break;
3950       case 'S':
3951         pstrcpy(desthost,optarg);
3952         strupper(desthost);
3953         nt_domain_logon = True;
3954         break;
3955       case 'M':
3956         name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
3957         pstrcpy(desthost,optarg);
3958         strupper(desthost);
3959         message = True;
3960         break;
3961       case 'B':
3962         iface_set_default(NULL,optarg,NULL);
3963         break;
3964       case 'D':
3965         pstrcpy(base_directory,optarg);
3966         break;
3967       case 'T':
3968         if (!tar_parseargs(argc, argv, optarg, optind)) {
3969           usage(pname);
3970           exit(1);
3971         }
3972         break;
3973       case 'i':
3974         pstrcpy(scope,optarg);
3975         break;
3976       case 'L':
3977         got_pass = True;
3978         pstrcpy(query_host,optarg);
3979     if(!explicit_user)
3980       *username = '\0';
3981         break;
3982       case 'U':
3983         {
3984           char *lp;
3985       explicit_user = True;
3986       pstrcpy(username,optarg);
3987       if ((lp=strchr(username,'%')))
3988           {
3989             *lp = 0;
3990             pstrcpy(password,lp+1);
3991             got_pass = True;
3992             memset(strchr(optarg,'%')+1,'X',strlen(password));
3993           }
3994         }
3995             
3996         break;
3997       case 'W':
3998         pstrcpy(workgroup,optarg);
3999         break;
4000       case 'E':
4001         dbf = stderr;
4002         break;
4003       case 'I':
4004         {
4005           dest_ip = *interpret_addr2(optarg);
4006           if (zero_ip(dest_ip)) exit(1);
4007           have_ip = True;
4008         }
4009         break;
4010       case 'n':
4011         pstrcpy(global_myname,optarg);
4012         break;
4013       case 'N':
4014         got_pass = True;
4015         no_pass = True;
4016         break;
4017       case 'P':
4018         connect_as_printer = True;
4019         break;
4020       case 'd':
4021         if (*optarg == 'A')
4022           DEBUGLEVEL = 10000;
4023         else
4024           DEBUGLEVEL = atoi(optarg);
4025         break;
4026       case 'l':
4027         slprintf(debugf,sizeof(debugf)-1, "%s.client",optarg);
4028         break;
4029       case 'p':
4030         port = atoi(optarg);
4031         break;
4032       case 'c':
4033         cmdstr = optarg;
4034         got_pass = True;
4035         break;
4036       case 'h':
4037         usage(pname);
4038         exit(0);
4039         break;
4040       case 's':
4041         pstrcpy(servicesf, optarg);
4042         break;
4043       case 't':
4044         pstrcpy(term_code, optarg);
4045         break;
4046       default:
4047         usage(pname);
4048         exit(1);
4049       }
4050
4051   get_myname((*global_myname)?NULL:global_myname,NULL);  
4052   strupper(global_myname);
4053
4054   if(*new_name_resolve_order)
4055     lp_set_name_resolve_order(new_name_resolve_order);
4056
4057   if (!tar_type && !*query_host && !*service && !message)
4058     {
4059       usage(pname);
4060       exit(1);
4061     }
4062
4063 #ifdef HAVE_LIBREADLINE
4064
4065   /* Initialise GNU Readline */
4066   
4067   rl_readline_name = "smbclient";
4068   rl_attempted_completion_function = completion_fn;
4069   rl_completion_entry_function = (Function *)complete_cmd_null;
4070
4071   /* Initialise history list */
4072
4073   using_history();
4074
4075 #endif /* HAVE_LIBREADLINE */
4076
4077   DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
4078
4079   if (tar_type) {
4080     recurse=True;
4081
4082     if (cli_open_sockets(port)) {
4083         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4084         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4085         int ret;
4086
4087         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4088           return(1);
4089
4090         bzero(OutBuffer,smb_size);
4091         if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
4092           return(False);
4093
4094         if (*base_directory) do_cd(base_directory);
4095
4096         ret=process_tar(InBuffer, OutBuffer);
4097
4098         cli_send_logout(InBuffer, OutBuffer);
4099         close_sockets();
4100         return(ret);
4101     } else
4102       return(1);
4103   }
4104   
4105   if (*query_host && !nt_domain_logon)
4106     {
4107       int ret = 0;
4108       slprintf(service,sizeof(service)-1,
4109                "\\\\%s\\IPC$",query_host);
4110       strupper(service);
4111       connect_as_ipc = True;
4112       if (cli_open_sockets(port))
4113         {
4114 #if 0
4115           *username = 0;
4116 #endif
4117           if (!cli_send_login(NULL,NULL,True,True,NULL))
4118             return(1);
4119
4120           server_info();
4121           if (!browse_host(True)) {
4122             sleep(1);
4123             browse_host(True);
4124           }
4125           if (!list_servers(workgroup)) {
4126             sleep(1);
4127             list_servers(workgroup);
4128           }
4129
4130           cli_send_logout(NULL,NULL);
4131           close_sockets();
4132         }
4133
4134       return(ret);
4135     }
4136
4137   if (message)
4138     {
4139       int ret = 0;
4140       if (cli_open_sockets(port))
4141         {
4142           pstring inbuf,outbuf;
4143           bzero(outbuf,smb_size);
4144           if (!cli_send_session_request(inbuf,outbuf))
4145             return(1);
4146
4147           send_message(inbuf,outbuf);
4148
4149           close_sockets();
4150         }
4151
4152       return(ret);
4153     }
4154
4155   if (cli_open_sockets(port))
4156     {
4157       if (!process(base_directory))
4158         {
4159           close_sockets();
4160           return(1);
4161         }
4162       close_sockets();
4163     }
4164   else
4165     return(1);
4166
4167   return(0);
4168 }