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