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