Adding rewritten restore code ... Old code is still there
[Samba.git] / source3 / client / client.c
blob684a2502b5432fa9c1219d3bee462d2d6cdf38b3
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB client
5 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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.
22 #define NO_SYSLOG
24 #include "includes.h"
26 #ifndef REGISTER
27 #define REGISTER 0
28 #endif
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;
46 extern BOOL doencrypt;
48 extern pstring user_socket_options;
50 static int process_tok(fstring tok);
51 static void cmd_help(char *dum_in, char *dum_out);
53 /* 30 second timeout on most commands */
54 #define CLIENT_TIMEOUT (30*1000)
55 #define SHORT_TIMEOUT (5*1000)
57 /* value for unused fid field in trans2 secondary request */
58 #define FID_UNUSED (0xFFFF)
60 extern int name_type;
62 extern int max_protocol;
65 time_t newer_than = 0;
66 int archive_level = 0;
68 extern pstring debugf;
69 extern int DEBUGLEVEL;
71 BOOL translation = False;
73 extern int cnum;
74 extern int mid;
75 extern int pid;
76 extern int tid;
77 extern int gid;
78 extern int uid;
80 extern BOOL have_ip;
81 extern int max_xmit;
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);
88 /* clitar bits insert */
89 extern int blocksize;
90 extern BOOL tar_inc;
91 extern BOOL tar_reset;
92 /* clitar bits end */
95 int myumask = 0755;
97 extern pstring scope;
99 BOOL prompt = True;
101 int printmode = 1;
103 BOOL recurse = False;
104 BOOL lowercase = False;
106 struct in_addr dest_ip;
108 #define SEPARATORS " \t\n\r"
110 BOOL abort_mget = True;
112 extern int Protocol;
114 extern BOOL readbraw_supported ;
115 extern BOOL writebraw_supported;
117 pstring fileselection = "";
119 extern file_info def_finfo;
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;
127 /* totals globals */
128 int dir_total = 0;
130 extern int Client;
132 #define USENMB
134 #define CNV_LANG(s) dos_to_unix(s,False)
135 #define CNV_INPUT(s) unix_to_dos(s,True)
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)
142 bzero(outbuf,smb_size);
143 set_message(outbuf,3,0,True);
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);
151 send_smb(clnt_fd, outbuf);
152 client_receive_smb(clnt_fd,inbuf,CLIENT_TIMEOUT);
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)
162 int i;
164 if (!translation)
165 return(write(f,b,n));
167 i = 0;
168 while (i < n)
170 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n')
172 b++;i++;
174 if (write(f, b, 1) != 1)
176 break;
178 b++;
179 i++;
182 return(i);
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)
191 int i;
192 int c;
194 if (!translation || (size != 1))
195 return(fread(b,size,n,f));
197 i = 0;
198 while (i < n)
200 if ((c = getc(f)) == EOF)
202 break;
205 if (c == '\n') /* change all LFs to CR/LF */
207 b[i++] = '\r';
208 n++;
211 if(i < n)
212 b[i++] = c;
215 return(i);
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)
225 int i;
227 i = readfile(b,1, n-1,f);
228 #if FORMFEED
229 if (feof(f) && i>0)
230 b[i++] = '\014';
231 #endif
233 return(i);
236 /****************************************************************************
237 check for existance of a dir
238 ****************************************************************************/
239 static BOOL chkpath(char *path,BOOL report)
241 fstring path2;
242 pstring inbuf,outbuf;
243 char *p;
245 fstrcpy(path2,path);
246 trim_string(path2,NULL,"\\");
247 if (!*path2) *path2 = '\\';
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);
255 p = smb_buf(outbuf);
256 *p++ = 4;
257 fstrcpy(p,path2);
259 #if 0
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++;
269 #endif
271 send_smb(Client,outbuf);
272 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
274 if (report && CVAL(inbuf,smb_rcls) != 0)
275 DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
277 return(CVAL(inbuf,smb_rcls) == 0);
281 /****************************************************************************
282 send a message
283 ****************************************************************************/
284 static void send_message(char *inbuf,char *outbuf)
286 int total_len = 0;
288 char *p;
289 int grp_id;
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);
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);
305 set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
307 send_smb(Client,outbuf);
310 if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
312 printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
313 return;
316 grp_id = SVAL(inbuf,smb_vwv0);
318 printf("Connected. Type your message, ending it with a Control-D\n");
320 while (!feof(stdin) && total_len < 1600)
322 int maxlen = MIN(1600 - total_len,127);
323 pstring msg;
324 int l=0;
325 int c;
327 bzero(msg,smb_size);
329 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++)
331 if (c == '\n')
332 msg[l++] = '\r';
333 msg[l] = c;
336 CVAL(outbuf,smb_com) = SMBsendtxt;
338 set_message(outbuf,1,l+3,True);
340 SSVAL(outbuf,smb_vwv0,grp_id);
342 p = smb_buf(outbuf);
343 *p = 1;
344 SSVAL(p,1,l);
345 memcpy(p+3,msg,l);
347 send_smb(Client,outbuf);
350 if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
352 printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
353 return;
356 total_len += l;
359 if (total_len >= 1600)
360 printf("the message was truncated to 1600 bytes ");
361 else
362 printf("sent %d bytes ",total_len);
364 printf("(status was %d-%d)\n",CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err));
366 CVAL(outbuf,smb_com) = SMBsendend;
367 set_message(outbuf,1,0,False);
368 SSVAL(outbuf,smb_vwv0,grp_id);
370 send_smb(Client,outbuf);
373 if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
375 printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
376 return;
382 /****************************************************************************
383 check the space on a device
384 ****************************************************************************/
385 static void do_dskattr(void)
387 pstring inbuf,outbuf;
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);
395 send_smb(Client,outbuf);
396 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
398 if (CVAL(inbuf,smb_rcls) != 0)
399 DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));
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)));
407 /****************************************************************************
408 show cd/pwd
409 ****************************************************************************/
410 static void cmd_pwd(char *dum_in, char *dum_out)
412 DEBUG(0,("Current directory is %s",CNV_LANG(service)));
413 DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
417 /****************************************************************************
418 change directory - inner section
419 ****************************************************************************/
420 static void do_cd(char *newdir)
422 char *p = newdir;
423 pstring saved_dir;
424 pstring dname;
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, "\\");
436 dos_clean_name(cur_dir);
437 pstrcpy(dname,cur_dir);
438 pstrcat(cur_dir,"\\");
439 dos_clean_name(cur_dir);
441 if (!strequal(cur_dir,"\\"))
442 if (!chkpath(dname,True))
443 pstrcpy(cur_dir,saved_dir);
445 pstrcpy(cd_path,cur_dir);
448 /****************************************************************************
449 change directory
450 ****************************************************************************/
451 static void cmd_cd(char *inbuf,char *outbuf)
453 fstring buf;
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)));
462 /****************************************************************************
463 display info about a file
464 ****************************************************************************/
465 static void display_finfo(file_info *finfo)
467 if (do_this_one(finfo)) {
468 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
469 DEBUG(0,(" %-30s%7.7s%.0f %s",
470 CNV_LANG(finfo->name),
471 attrib_string(finfo->mode),
472 (double)finfo->size,
473 asctime(LocalTime(&t))));
474 dir_total += finfo->size;
479 /****************************************************************************
480 do a directory listing, calling fn on each file found. Use the TRANSACT2
481 call for long filenames
482 ****************************************************************************/
483 static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
485 int max_matches = 512;
486 int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
487 char *p;
488 pstring mask;
489 file_info finfo;
490 int i;
491 char *dirlist = NULL;
492 int dirlist_len = 0;
493 int total_received = 0;
494 BOOL First = True;
495 char *resp_data=NULL;
496 char *resp_param=NULL;
497 int resp_data_len = 0;
498 int resp_param_len=0;
500 int ff_resume_key = 0;
501 int ff_searchcount=0;
502 int ff_eos=0;
503 int ff_lastname=0;
504 int ff_dir_handle=0;
505 int loop_count = 0;
507 uint16 setup;
508 pstring param;
510 pstrcpy(mask,Mask);
512 while (ff_eos == 0)
514 loop_count++;
515 if (loop_count > 200)
517 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
518 break;
521 if (First)
523 setup = TRANSACT2_FINDFIRST;
524 SSVAL(param,0,attribute); /* attribute */
525 SSVAL(param,2,max_matches); /* max count */
526 SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
527 SSVAL(param,6,info_level);
528 SIVAL(param,8,0);
529 pstrcpy(param+12,mask);
531 else
533 setup = TRANSACT2_FINDNEXT;
534 SSVAL(param,0,ff_dir_handle);
535 SSVAL(param,2,max_matches); /* max count */
536 SSVAL(param,4,info_level);
537 SIVAL(param,6,ff_resume_key); /* ff_resume_key */
538 SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
539 pstrcpy(param+12,mask);
541 DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
542 ff_dir_handle,ff_resume_key,ff_lastname,mask));
544 /* ??? original code added 1 pad byte after param */
546 cli_send_trans_request(outbuf,SMBtrans2,NULL,0,FID_UNUSED,0,
547 NULL,param,&setup,
548 0,12+strlen(mask)+1,1,
549 BUFFER_SIZE,10,0);
551 if (!cli_receive_trans_response(inbuf,SMBtrans2,
552 &resp_data_len,&resp_param_len,
553 &resp_data,&resp_param))
555 DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
556 break;
559 /* parse out some important return info */
560 p = resp_param;
561 if (First)
563 ff_dir_handle = SVAL(p,0);
564 ff_searchcount = SVAL(p,2);
565 ff_eos = SVAL(p,4);
566 ff_lastname = SVAL(p,8);
568 else
570 ff_searchcount = SVAL(p,0);
571 ff_eos = SVAL(p,2);
572 ff_lastname = SVAL(p,6);
575 if (ff_searchcount == 0)
576 break;
578 /* point to the data bytes */
579 p = resp_data;
581 /* we might need the lastname for continuations */
582 if (ff_lastname > 0)
584 switch(info_level)
586 case 260:
587 ff_resume_key =0;
588 StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
589 /* pstrcpy(mask,p+ff_lastname+94); */
590 break;
591 case 1:
592 pstrcpy(mask,p + ff_lastname + 1);
593 ff_resume_key = 0;
594 break;
597 else
598 pstrcpy(mask,"");
600 /* and add them to the dirlist pool */
601 dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
603 if (!dirlist)
605 DEBUG(0,("Failed to expand dirlist\n"));
606 break;
609 /* put in a length for the last entry, to ensure we can chain entries
610 into the next packet */
612 char *p2;
613 for (p2=p,i=0;i<(ff_searchcount-1);i++)
614 p2 += interpret_long_filename(info_level,p2,NULL);
615 SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
618 /* grab the data for later use */
619 memcpy(dirlist+dirlist_len,p,resp_data_len);
620 dirlist_len += resp_data_len;
622 total_received += ff_searchcount;
624 if (resp_data) free(resp_data); resp_data = NULL;
625 if (resp_param) free(resp_param); resp_param = NULL;
627 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
628 ff_searchcount,ff_eos,ff_resume_key));
630 First = False;
633 if (!fn)
634 for (p=dirlist,i=0;i<total_received;i++)
636 p += interpret_long_filename(info_level,p,&finfo);
637 display_finfo(&finfo);
640 for (p=dirlist,i=0;i<total_received;i++)
642 p += interpret_long_filename(info_level,p,&finfo);
643 dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True, dirstoo);
646 /* free up the dirlist buffer */
647 if (dirlist) free(dirlist);
648 return(total_received);
652 /****************************************************************************
653 do a directory listing, calling fn on each file found
654 ****************************************************************************/
655 static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
657 char *p;
658 int received = 0;
659 BOOL first = True;
660 char status[21];
661 int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
662 int num_received = 0;
663 int i;
664 char *dirlist = NULL;
665 pstring mask;
666 file_info finfo;
668 finfo = def_finfo;
670 bzero(status,21);
672 pstrcpy(mask,Mask);
674 while (1)
676 bzero(outbuf,smb_size);
677 if (first)
678 set_message(outbuf,2,5 + strlen(mask),True);
679 else
680 set_message(outbuf,2,5 + 21,True);
682 #if FFIRST
683 if (Protocol >= PROTOCOL_LANMAN1)
684 CVAL(outbuf,smb_com) = SMBffirst;
685 else
686 #endif
687 CVAL(outbuf,smb_com) = SMBsearch;
689 SSVAL(outbuf,smb_tid,cnum);
690 cli_setup_pkt(outbuf);
692 SSVAL(outbuf,smb_vwv0,num_asked);
693 SSVAL(outbuf,smb_vwv1,attribute);
695 p = smb_buf(outbuf);
696 *p++ = 4;
698 if (first)
699 pstrcpy(p,mask);
700 else
701 pstrcpy(p,"");
702 p += strlen(p) + 1;
704 *p++ = 5;
705 if (first)
706 SSVAL(p,0,0);
707 else
709 SSVAL(p,0,21);
710 p += 2;
711 memcpy(p,status,21);
714 send_smb(Client,outbuf);
715 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
717 received = SVAL(inbuf,smb_vwv0);
719 DEBUG(5,("dir received %d\n",received));
721 DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
723 if (received <= 0) break;
725 first = False;
727 dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
729 if (!dirlist)
730 return 0;
732 p = smb_buf(inbuf) + 3;
734 memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
735 p,received*DIR_STRUCT_SIZE);
737 memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
739 num_received += received;
741 if (CVAL(inbuf,smb_rcls) != 0) break;
744 #if FFIRST
745 if (!first && Protocol >= PROTOCOL_LANMAN1)
747 bzero(outbuf,smb_size);
748 CVAL(outbuf,smb_com) = SMBfclose;
750 SSVAL(outbuf,smb_tid,cnum);
751 cli_setup_pkt(outbuf);
753 p = smb_buf(outbuf);
754 *p++ = 4;
756 pstrcpy(p,"");
757 p += strlen(p) + 1;
759 *p++ = 5;
760 SSVAL(p,0,21);
761 p += 2;
762 memcpy(p,status,21);
764 send_smb(Client,outbuf);
765 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
767 if (CVAL(inbuf,smb_rcls) != 0)
768 DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
770 #endif
772 if (!fn)
773 for (p=dirlist,i=0;i<num_received;i++)
775 p += interpret_short_filename(p,&finfo);
776 display_finfo(&finfo);
779 for (p=dirlist,i=0;i<num_received;i++)
781 p += interpret_short_filename(p,&finfo);
782 dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False,dirstoo);
785 if (dirlist) free(dirlist);
786 return(num_received);
791 /****************************************************************************
792 do a directory listing, calling fn on each file found
793 ****************************************************************************/
794 void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
796 DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
797 if (Protocol >= PROTOCOL_LANMAN2)
799 if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo) > 0)
800 return;
803 expand_mask(Mask,False);
804 do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo);
805 return;
808 /*******************************************************************
809 decide if a file should be operated on
810 ********************************************************************/
811 static BOOL do_this_one(file_info *finfo)
813 if (finfo->mode & aDIR) return(True);
815 if (newer_than && finfo->mtime < newer_than)
816 return(False);
818 if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
819 return(False);
821 return(True);
825 /*****************************************************************************
826 Convert a character pointer in a cli_call_api() response to a form we can use.
827 This function contains code to prevent core dumps if the server returns
828 invalid data.
829 *****************************************************************************/
830 static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
832 if( datap == 0 ) /* turn NULL pointers */
833 { /* into zero length strings */
834 return "";
836 else
838 unsigned int offset = datap - converter;
840 if( offset >= rdrcnt )
842 DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%lu, rdrcnt=%d>", datap, converter, (unsigned long)rdata, rdrcnt));
843 return "<ERROR>";
845 else
847 return &rdata[offset];
852 /****************************************************************************
853 interpret a short filename structure
854 The length of the structure is returned
855 ****************************************************************************/
856 static int interpret_short_filename(char *p,file_info *finfo)
858 finfo->mode = CVAL(p,21);
860 /* this date is converted to GMT by make_unix_date */
861 finfo->ctime = make_unix_date(p+22);
862 finfo->mtime = finfo->atime = finfo->ctime;
863 finfo->size = IVAL(p,26);
864 pstrcpy(finfo->name,p+30);
866 return(DIR_STRUCT_SIZE);
869 /****************************************************************************
870 interpret a long filename structure - this is mostly guesses at the moment
871 The length of the structure is returned
872 The structure of a long filename depends on the info level. 260 is used
873 by NT and 2 is used by OS/2
874 ****************************************************************************/
875 static int interpret_long_filename(int level,char *p,file_info *finfo)
877 if (finfo)
878 memcpy(finfo,&def_finfo,sizeof(*finfo));
880 switch (level)
882 case 1: /* OS/2 understands this */
883 if (finfo)
885 /* these dates are converted to GMT by make_unix_date */
886 finfo->ctime = make_unix_date2(p+4);
887 finfo->atime = make_unix_date2(p+8);
888 finfo->mtime = make_unix_date2(p+12);
889 finfo->size = IVAL(p,16);
890 finfo->mode = CVAL(p,24);
891 pstrcpy(finfo->name,p+27);
893 return(28 + CVAL(p,26));
895 case 2: /* this is what OS/2 uses mostly */
896 if (finfo)
898 /* these dates are converted to GMT by make_unix_date */
899 finfo->ctime = make_unix_date2(p+4);
900 finfo->atime = make_unix_date2(p+8);
901 finfo->mtime = make_unix_date2(p+12);
902 finfo->size = IVAL(p,16);
903 finfo->mode = CVAL(p,24);
904 pstrcpy(finfo->name,p+31);
906 return(32 + CVAL(p,30));
908 /* levels 3 and 4 are untested */
909 case 3:
910 if (finfo)
912 /* these dates are probably like the other ones */
913 finfo->ctime = make_unix_date2(p+8);
914 finfo->atime = make_unix_date2(p+12);
915 finfo->mtime = make_unix_date2(p+16);
916 finfo->size = IVAL(p,20);
917 finfo->mode = CVAL(p,28);
918 pstrcpy(finfo->name,p+33);
920 return(SVAL(p,4)+4);
922 case 4:
923 if (finfo)
925 /* these dates are probably like the other ones */
926 finfo->ctime = make_unix_date2(p+8);
927 finfo->atime = make_unix_date2(p+12);
928 finfo->mtime = make_unix_date2(p+16);
929 finfo->size = IVAL(p,20);
930 finfo->mode = CVAL(p,28);
931 pstrcpy(finfo->name,p+37);
933 return(SVAL(p,4)+4);
935 case 260: /* NT uses this, but also accepts 2 */
936 if (finfo)
938 int ret = SVAL(p,0);
939 int namelen;
940 p += 4; /* next entry offset */
941 p += 4; /* fileindex */
943 /* these dates appear to arrive in a weird way. It seems to
944 be localtime plus the serverzone given in the initial
945 connect. This is GMT when DST is not in effect and one
946 hour from GMT otherwise. Can this really be right??
948 I suppose this could be called kludge-GMT. Is is the GMT
949 you get by using the current DST setting on a different
950 localtime. It will be cheap to calculate, I suppose, as
951 no DST tables will be needed */
953 finfo->ctime = interpret_long_date(p); p += 8;
954 finfo->atime = interpret_long_date(p); p += 8;
955 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
956 finfo->size = IVAL(p,0); p += 8;
957 p += 8; /* alloc size */
958 finfo->mode = CVAL(p,0); p += 4;
959 namelen = IVAL(p,0); p += 4;
960 p += 4; /* EA size */
961 p += 2; /* short name len? */
962 p += 24; /* short name? */
963 StrnCpy(finfo->name,p,namelen);
964 return(ret);
966 return(SVAL(p,0));
969 DEBUG(1,("Unknown long filename format %d\n",level));
970 return(SVAL(p,0));
976 /****************************************************************************
977 act on the files in a dir listing
979 RJS, 4-Apr-1998, dirstoo added to allow caller to indicate that directories
980 should be processed as well.
981 ****************************************************************************/
982 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo)
985 if (!((finfo->mode & aDIR) == 0 && *fileselection &&
986 !mask_match(finfo->name,fileselection,False,False)) &&
987 !(recurse_dir && (strequal(finfo->name,".") ||
988 strequal(finfo->name,".."))))
990 if (recurse_dir && (finfo->mode & aDIR))
992 pstring mask2;
993 pstring sav_dir;
995 if (fn && dirstoo && do_this_one(finfo)) { /* Do dirs, RJS */
996 fn(finfo);
999 pstrcpy(sav_dir,cur_dir);
1000 pstrcat(cur_dir,finfo->name);
1001 pstrcat(cur_dir,"\\");
1002 pstrcpy(mask2,cur_dir);
1004 if (!fn)
1005 DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
1007 pstrcat(mask2,"*");
1009 if (longdir)
1010 do_long_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);
1011 else
1012 do_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);
1014 pstrcpy(cur_dir,sav_dir);
1016 else
1018 if (fn && do_this_one(finfo))
1019 fn(finfo);
1025 /****************************************************************************
1026 get a directory listing
1027 ****************************************************************************/
1028 static void cmd_dir(char *inbuf,char *outbuf)
1030 int attribute = aDIR | aSYSTEM | aHIDDEN;
1031 pstring mask;
1032 fstring buf;
1033 char *p=buf;
1035 dir_total = 0;
1036 pstrcpy(mask,cur_dir);
1037 if(mask[strlen(mask)-1]!='\\')
1038 pstrcat(mask,"\\");
1040 if (next_token(NULL,buf,NULL,sizeof(buf)))
1042 if (*p == '\\')
1043 pstrcpy(mask,p);
1044 else
1045 pstrcat(mask,p);
1047 else {
1048 pstrcat(mask,"*");
1051 do_dir(inbuf,outbuf,mask,attribute,NULL,recurse,False);
1053 do_dskattr();
1055 DEBUG(3, ("Total bytes listed: %d\n", dir_total));
1060 /****************************************************************************
1061 get a file from rname to lname
1062 ****************************************************************************/
1063 static void do_get(char *rname,char *lname,file_info *finfo1)
1065 int handle=0,fnum;
1066 uint32 nread=0;
1067 char *p;
1068 BOOL newhandle = False;
1069 char *inbuf,*outbuf;
1070 file_info finfo;
1071 BOOL close_done = False;
1072 BOOL ignore_close_error = False;
1073 char *dataptr=NULL;
1074 int datalen=0;
1076 struct timeval tp_start;
1077 GetTimeOfDay(&tp_start);
1079 if (finfo1)
1080 finfo = *finfo1;
1081 else
1082 finfo = def_finfo;
1084 if (lowercase)
1085 strlower(lname);
1088 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1089 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1091 if (!inbuf || !outbuf)
1093 DEBUG(0,("out of memory\n"));
1094 return;
1097 bzero(outbuf,smb_size);
1098 set_message(outbuf,15,1 + strlen(rname),True);
1100 CVAL(outbuf,smb_com) = SMBopenX;
1101 SSVAL(outbuf,smb_tid,cnum);
1102 cli_setup_pkt(outbuf);
1104 SSVAL(outbuf,smb_vwv0,0xFF);
1105 SSVAL(outbuf,smb_vwv2,1); /* return additional info */
1106 SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1107 SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1108 SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1109 SSVAL(outbuf,smb_vwv8,1);
1110 SSVAL(outbuf,smb_vwv11,0xffff);
1111 SSVAL(outbuf,smb_vwv12,0xffff);
1113 p = smb_buf(outbuf);
1114 pstrcpy(p,rname);
1115 p = skip_string(p,1);
1117 /* do a chained openX with a readX? */
1118 #if 1
1119 if (finfo.size > 0)
1121 DEBUG(3,("Chaining readX wth openX\n"));
1122 SSVAL(outbuf,smb_vwv0,SMBreadX);
1123 SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
1124 bzero(p,200);
1125 p -= smb_wct;
1126 SCVAL(p,smb_wct,10);
1127 SSVAL(p,smb_vwv0,0xFF);
1128 SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1129 SSVAL(p,smb_vwv9,MIN(BUFFER_SIZE,finfo.size));
1130 smb_setlen(outbuf,smb_len(outbuf)+11*2+1);
1132 #endif
1134 if(!strcmp(lname,"-"))
1135 handle = fileno(stdout);
1136 else
1138 handle = creat(lname,0644);
1139 newhandle = True;
1141 if (handle < 0)
1143 DEBUG(0,("Error opening local file %s\n",lname));
1144 free(inbuf);free(outbuf);
1145 return;
1148 send_smb(Client,outbuf);
1149 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1151 if (CVAL(inbuf,smb_rcls) != 0)
1153 if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1154 SVAL(inbuf,smb_err) == ERRnoresource &&
1155 cli_reopen_connection(inbuf,outbuf))
1157 do_get(rname,lname,finfo1);
1158 return;
1160 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1161 if(newhandle)
1162 close(handle);
1163 free(inbuf);free(outbuf);
1164 return;
1167 pstrcpy(finfo.name,rname);
1169 if (!finfo1)
1171 finfo.mode = SVAL(inbuf,smb_vwv3);
1172 /* these times arrive as LOCAL time, using the DST offset
1173 corresponding to that time, we convert them to GMT */
1174 finfo.mtime = make_unix_date3(inbuf+smb_vwv4);
1175 finfo.atime = finfo.ctime = finfo.mtime;
1176 finfo.size = IVAL(inbuf,smb_vwv6);
1179 DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode));
1181 fnum = SVAL(inbuf,smb_vwv2);
1183 /* we might have got some data from a chained readX */
1184 if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1186 p = (smb_base(inbuf)+SVAL(inbuf,smb_vwv1)) - smb_wct;
1187 datalen = SVAL(p,smb_vwv5);
1188 dataptr = smb_base(inbuf) + SVAL(p,smb_vwv6);
1190 else
1192 dataptr = NULL;
1193 datalen = 0;
1197 DEBUG(2,("getting file %s of size %.0f bytes as %s ",
1198 CNV_LANG(finfo.name),
1199 (double)finfo.size,
1200 lname));
1202 while (nread < finfo.size && !close_done)
1204 int method = -1;
1205 static BOOL can_chain_close = True;
1207 p=NULL;
1209 DEBUG(3,("nread=%d max_xmit=%d fsize=%.0f\n",nread,max_xmit,(double)finfo.size));
1211 /* 3 possible read types. readbraw if a large block is required.
1212 readX + close if not much left and read if neither is supported */
1214 /* we might have already read some data from a chained readX */
1215 if (dataptr && datalen>0)
1216 method=3;
1218 /* if we can finish now then readX+close */
1219 if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) &&
1220 ((finfo.size - nread) <
1221 (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1222 method = 0;
1224 /* if we support readraw then use that */
1225 if (method<0 && readbraw_supported)
1226 method = 1;
1228 /* if we can then use readX */
1229 if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1230 method = 2;
1232 switch (method)
1234 /* use readX */
1235 case 0:
1236 case 2:
1237 if (method == 0)
1238 close_done = True;
1240 /* use readX + close */
1241 bzero(outbuf,smb_size);
1242 set_message(outbuf,10,0,True);
1243 CVAL(outbuf,smb_com) = SMBreadX;
1244 SSVAL(outbuf,smb_tid,cnum);
1245 cli_setup_pkt(outbuf);
1247 if (close_done)
1249 CVAL(outbuf,smb_vwv0) = SMBclose;
1250 SSVAL(outbuf,smb_vwv1,smb_offset(smb_buf(outbuf),outbuf));
1252 else
1253 CVAL(outbuf,smb_vwv0) = 0xFF;
1255 SSVAL(outbuf,smb_vwv2,fnum);
1256 SIVAL(outbuf,smb_vwv3,nread);
1257 SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1258 SSVAL(outbuf,smb_vwv6,0);
1259 SIVAL(outbuf,smb_vwv7,0);
1260 SSVAL(outbuf,smb_vwv9,MIN(BUFFER_SIZE,finfo.size-nread));
1262 if (close_done)
1264 p = smb_buf(outbuf);
1265 bzero(p,9);
1267 CVAL(p,0) = 3;
1268 SSVAL(p,1,fnum);
1269 SIVALS(p,3,-1);
1271 /* now set the total packet length */
1272 smb_setlen(outbuf,smb_len(outbuf)+9);
1275 send_smb(Client,outbuf);
1276 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1278 if (CVAL(inbuf,smb_rcls) != 0)
1280 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1281 break;
1284 if (close_done &&
1285 SVAL(inbuf,smb_vwv0) != SMBclose)
1287 /* NOTE: WfWg sometimes just ignores the chained
1288 command! This seems to break the spec? */
1289 DEBUG(3,("Rejected chained close?\n"));
1290 close_done = False;
1291 can_chain_close = False;
1292 ignore_close_error = True;
1295 datalen = SVAL(inbuf,smb_vwv5);
1296 dataptr = smb_base(inbuf) + SVAL(inbuf,smb_vwv6);
1297 break;
1299 /* use readbraw */
1300 case 1:
1302 static int readbraw_size = BUFFER_SIZE;
1304 extern int Client;
1305 bzero(outbuf,smb_size);
1306 set_message(outbuf,8,0,True);
1307 CVAL(outbuf,smb_com) = SMBreadbraw;
1308 SSVAL(outbuf,smb_tid,cnum);
1309 cli_setup_pkt(outbuf);
1310 SSVAL(outbuf,smb_vwv0,fnum);
1311 SIVAL(outbuf,smb_vwv1,nread);
1312 SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1313 SSVAL(outbuf,smb_vwv4,0);
1314 SIVALS(outbuf,smb_vwv5,-1);
1315 send_smb(Client,outbuf);
1317 /* Now read the raw data into the buffer and write it */
1318 if(read_smb_length(Client,inbuf,0) == -1) {
1319 DEBUG(0,("Failed to read length in readbraw\n"));
1320 exit(1);
1323 /* Even though this is not an smb message, smb_len
1324 returns the generic length of an smb message */
1325 datalen = smb_len(inbuf);
1327 if (datalen == 0)
1329 /* we got a readbraw error */
1330 DEBUG(4,("readbraw error - reducing size\n"));
1331 readbraw_size = (readbraw_size * 9) / 10;
1333 if (readbraw_size < max_xmit)
1335 DEBUG(0,("disabling readbraw\n"));
1336 readbraw_supported = False;
1339 dataptr=NULL;
1340 continue;
1343 if(read_data(Client,inbuf,datalen) != datalen) {
1344 DEBUG(0,("Failed to read data in readbraw\n"));
1345 exit(1);
1347 dataptr = inbuf;
1349 break;
1351 case 3:
1352 /* we've already read some data with a chained readX */
1353 break;
1355 default:
1356 /* use plain read */
1357 bzero(outbuf,smb_size);
1358 set_message(outbuf,5,0,True);
1359 CVAL(outbuf,smb_com) = SMBread;
1360 SSVAL(outbuf,smb_tid,cnum);
1361 cli_setup_pkt(outbuf);
1363 SSVAL(outbuf,smb_vwv0,fnum);
1364 SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1365 SIVAL(outbuf,smb_vwv2,nread);
1366 SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1368 send_smb(Client,outbuf);
1369 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1371 if (CVAL(inbuf,smb_rcls) != 0)
1373 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1374 break;
1377 datalen = SVAL(inbuf,smb_vwv0);
1378 dataptr = smb_buf(inbuf) + 3;
1379 break;
1382 if (writefile(handle,dataptr,datalen) != datalen)
1384 DEBUG(0,("Error writing local file\n"));
1385 break;
1388 nread += datalen;
1389 if (datalen == 0)
1391 DEBUG(0,("Error reading file %s. Got %d bytes\n",CNV_LANG(rname),nread));
1392 break;
1395 dataptr=NULL;
1396 datalen=0;
1401 if (!close_done)
1403 cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
1405 if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1407 DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1408 if(newhandle)
1409 close(handle);
1410 free(inbuf);free(outbuf);
1411 return;
1415 if(newhandle)
1416 close(handle);
1418 if (archive_level >= 2 && (finfo.mode & aARCH)) {
1419 bzero(outbuf,smb_size);
1420 set_message(outbuf,8,strlen(rname)+4,True);
1421 CVAL(outbuf,smb_com) = SMBsetatr;
1422 SSVAL(outbuf,smb_tid,cnum);
1423 cli_setup_pkt(outbuf);
1424 SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
1425 SIVALS(outbuf,smb_vwv1,0);
1426 p = smb_buf(outbuf);
1427 *p++ = 4;
1428 pstrcpy(p,rname);
1429 p += strlen(p)+1;
1430 *p++ = 4;
1431 *p = 0;
1432 send_smb(Client,outbuf);
1433 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1437 struct timeval tp_end;
1438 int this_time;
1440 GetTimeOfDay(&tp_end);
1441 this_time =
1442 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1443 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1444 get_total_time_ms += this_time;
1445 get_total_size += finfo.size;
1447 DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
1448 finfo.size / (1.024*this_time + 1.0e-4),
1449 get_total_size / (1.024*get_total_time_ms)));
1452 free(inbuf);free(outbuf);
1456 /****************************************************************************
1457 get a file
1458 ****************************************************************************/
1459 static void cmd_get(char *dum_in, char *dum_out)
1461 pstring lname;
1462 pstring rname;
1463 char *p;
1465 pstrcpy(rname,cur_dir);
1466 pstrcat(rname,"\\");
1468 p = rname + strlen(rname);
1470 if (!next_token(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
1471 DEBUG(0,("get <filename>\n"));
1472 return;
1474 pstrcpy(lname,p);
1475 dos_clean_name(rname);
1477 next_token(NULL,lname,NULL,sizeof(lname));
1479 do_get(rname,lname,NULL);
1483 /****************************************************************************
1484 do a mget operation on one file
1485 ****************************************************************************/
1486 static void do_mget(file_info *finfo)
1488 pstring rname;
1489 pstring quest;
1491 if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1492 return;
1494 if (abort_mget)
1496 DEBUG(0,("mget aborted\n"));
1497 return;
1500 if (finfo->mode & aDIR)
1501 slprintf(quest,sizeof(pstring)-1,
1502 "Get directory %s? ",CNV_LANG(finfo->name));
1503 else
1504 slprintf(quest,sizeof(pstring)-1,
1505 "Get file %s? ",CNV_LANG(finfo->name));
1507 if (prompt && !yesno(quest)) return;
1509 if (finfo->mode & aDIR)
1511 pstring saved_curdir;
1512 pstring mget_mask;
1513 char *inbuf,*outbuf;
1515 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1516 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1518 if (!inbuf || !outbuf)
1520 DEBUG(0,("out of memory\n"));
1521 return;
1524 pstrcpy(saved_curdir,cur_dir);
1526 pstrcat(cur_dir,finfo->name);
1527 pstrcat(cur_dir,"\\");
1529 unix_format(finfo->name);
1531 if (lowercase)
1532 strlower(finfo->name);
1534 if (!directory_exist(finfo->name,NULL) &&
1535 dos_mkdir(finfo->name,0777) != 0)
1537 DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
1538 pstrcpy(cur_dir,saved_curdir);
1539 free(inbuf);free(outbuf);
1540 return;
1543 if (dos_chdir(finfo->name) != 0)
1545 DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
1546 pstrcpy(cur_dir,saved_curdir);
1547 free(inbuf);free(outbuf);
1548 return;
1552 pstrcpy(mget_mask,cur_dir);
1553 pstrcat(mget_mask,"*");
1555 do_dir((char *)inbuf,(char *)outbuf,
1556 mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False, False);
1557 chdir("..");
1558 pstrcpy(cur_dir,saved_curdir);
1559 free(inbuf);free(outbuf);
1561 else
1563 pstrcpy(rname,cur_dir);
1564 pstrcat(rname,finfo->name);
1565 do_get(rname,finfo->name,finfo);
1569 /****************************************************************************
1570 view the file using the pager
1571 ****************************************************************************/
1572 static void cmd_more(char *dum_in, char *dum_out)
1574 fstring rname,lname,tmpname,pager_cmd;
1575 char *pager;
1577 fstrcpy(rname,cur_dir);
1578 fstrcat(rname,"\\");
1579 slprintf(tmpname,
1580 sizeof(fstring)-1,
1581 "%s/smbmore.%d",tmpdir(),(int)getpid());
1582 fstrcpy(lname,tmpname);
1584 if (!next_token(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
1585 DEBUG(0,("more <filename>\n"));
1586 return;
1588 dos_clean_name(rname);
1590 do_get(rname,lname,NULL);
1592 pager=getenv("PAGER");
1594 slprintf(pager_cmd,sizeof(pager_cmd)-1,
1595 "%s %s",(pager? pager:PAGER), tmpname);
1596 system(pager_cmd);
1597 unlink(tmpname);
1602 /****************************************************************************
1603 do a mget command
1604 ****************************************************************************/
1605 static void cmd_mget(char *inbuf,char *outbuf)
1607 int attribute = aSYSTEM | aHIDDEN;
1608 pstring mget_mask;
1609 fstring buf;
1610 char *p=buf;
1612 *mget_mask = 0;
1614 if (recurse)
1615 attribute |= aDIR;
1617 abort_mget = False;
1619 while (next_token(NULL,p,NULL,sizeof(buf)))
1621 pstrcpy(mget_mask,cur_dir);
1622 if(mget_mask[strlen(mget_mask)-1]!='\\')
1623 pstrcat(mget_mask,"\\");
1625 if (*p == '\\')
1626 pstrcpy(mget_mask,p);
1627 else
1628 pstrcat(mget_mask,p);
1629 do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
1632 if (! *mget_mask)
1634 pstrcpy(mget_mask,cur_dir);
1635 if(mget_mask[strlen(mget_mask)-1]!='\\')
1636 pstrcat(mget_mask,"\\");
1637 pstrcat(mget_mask,"*");
1638 do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
1642 /****************************************************************************
1643 make a directory of name "name"
1644 ****************************************************************************/
1645 static BOOL do_mkdir(char *name)
1647 char *p;
1648 char *inbuf,*outbuf;
1650 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1651 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1653 if (!inbuf || !outbuf)
1655 DEBUG(0,("out of memory\n"));
1656 return False;
1659 bzero(outbuf,smb_size);
1660 set_message(outbuf,0,2 + strlen(name),True);
1662 CVAL(outbuf,smb_com) = SMBmkdir;
1663 SSVAL(outbuf,smb_tid,cnum);
1664 cli_setup_pkt(outbuf);
1667 p = smb_buf(outbuf);
1668 *p++ = 4;
1669 pstrcpy(p,name);
1671 send_smb(Client,outbuf);
1672 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1674 if (CVAL(inbuf,smb_rcls) != 0)
1676 DEBUG(0,("%s making remote directory %s\n",
1677 smb_errstr(inbuf),CNV_LANG(name)));
1679 free(inbuf);free(outbuf);
1680 return(False);
1683 free(inbuf);free(outbuf);
1684 return(True);
1688 /****************************************************************************
1689 make a directory
1690 ****************************************************************************/
1691 static void cmd_mkdir(char *inbuf,char *outbuf)
1693 pstring mask;
1694 fstring buf;
1695 char *p=buf;
1697 pstrcpy(mask,cur_dir);
1699 if (!next_token(NULL,p,NULL,sizeof(buf)))
1701 if (!recurse)
1702 DEBUG(0,("mkdir <dirname>\n"));
1703 return;
1705 pstrcat(mask,p);
1707 if (recurse)
1709 pstring ddir;
1710 pstring ddir2;
1711 *ddir2 = 0;
1713 pstrcpy(ddir,mask);
1714 trim_string(ddir,".",NULL);
1715 p = strtok(ddir,"/\\");
1716 while (p)
1718 pstrcat(ddir2,p);
1719 if (!chkpath(ddir2,False))
1721 do_mkdir(ddir2);
1723 pstrcat(ddir2,"\\");
1724 p = strtok(NULL,"/\\");
1727 else
1728 do_mkdir(mask);
1732 /*******************************************************************
1733 write to a file using writebraw
1734 ********************************************************************/
1735 static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
1737 extern int Client;
1738 pstring inbuf;
1740 bzero(outbuf,smb_size);
1741 bzero(inbuf,smb_size);
1742 set_message(outbuf,Protocol>PROTOCOL_COREPLUS?12:10,0,True);
1744 CVAL(outbuf,smb_com) = SMBwritebraw;
1745 SSVAL(outbuf,smb_tid,cnum);
1746 cli_setup_pkt(outbuf);
1748 SSVAL(outbuf,smb_vwv0,fnum);
1749 SSVAL(outbuf,smb_vwv1,n);
1750 SIVAL(outbuf,smb_vwv3,pos);
1751 SSVAL(outbuf,smb_vwv7,1);
1753 send_smb(Client,outbuf);
1755 if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
1756 return(0);
1758 _smb_setlen(buf-4,n); /* HACK! XXXX */
1760 if (write_socket(Client,buf-4,n+4) != n+4)
1761 return(0);
1763 if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
1764 DEBUG(0,("Error writing remote file (2)\n"));
1765 return(0);
1767 return(SVAL(inbuf,smb_vwv0));
1772 /*******************************************************************
1773 write to a file
1774 ********************************************************************/
1775 static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
1777 pstring inbuf;
1779 if (writebraw_supported && n > (max_xmit-200))
1780 return(smb_writeraw(outbuf,fnum,pos,buf,n));
1782 bzero(outbuf,smb_size);
1783 bzero(inbuf,smb_size);
1784 set_message(outbuf,5,n + 3,True);
1786 CVAL(outbuf,smb_com) = SMBwrite;
1787 SSVAL(outbuf,smb_tid,cnum);
1788 cli_setup_pkt(outbuf);
1790 SSVAL(outbuf,smb_vwv0,fnum);
1791 SSVAL(outbuf,smb_vwv1,n);
1792 SIVAL(outbuf,smb_vwv2,pos);
1793 SSVAL(outbuf,smb_vwv4,0);
1794 CVAL(smb_buf(outbuf),0) = 1;
1795 SSVAL(smb_buf(outbuf),1,n);
1797 memcpy(smb_buf(outbuf)+3,buf,n);
1799 send_smb(Client,outbuf);
1800 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1802 if (CVAL(inbuf,smb_rcls) != 0) {
1803 DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
1804 return(0);
1806 return(SVAL(inbuf,smb_vwv0));
1811 /****************************************************************************
1812 put a single file
1813 ****************************************************************************/
1814 static void do_put(char *rname,char *lname,file_info *finfo)
1816 int fnum;
1817 FILE *f;
1818 int nread=0;
1819 char *p;
1820 char *inbuf,*outbuf;
1821 time_t close_time = finfo->mtime;
1822 char *buf=NULL;
1823 static int maxwrite=0;
1825 struct timeval tp_start;
1826 GetTimeOfDay(&tp_start);
1828 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1829 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1831 if (!inbuf || !outbuf)
1833 DEBUG(0,("out of memory\n"));
1834 return;
1837 bzero(outbuf,smb_size);
1838 set_message(outbuf,3,2 + strlen(rname),True);
1840 if (finfo->mtime == 0 || finfo->mtime == -1)
1841 finfo->mtime = finfo->atime = finfo->ctime = time(NULL);
1843 CVAL(outbuf,smb_com) = SMBcreate;
1844 SSVAL(outbuf,smb_tid,cnum);
1845 cli_setup_pkt(outbuf);
1847 SSVAL(outbuf,smb_vwv0,finfo->mode);
1848 put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
1850 p = smb_buf(outbuf);
1851 *p++ = 4;
1852 pstrcpy(p,rname);
1854 send_smb(Client,outbuf);
1855 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1857 if (CVAL(inbuf,smb_rcls) != 0)
1859 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1861 free(inbuf);free(outbuf);if (buf) free(buf);
1862 return;
1865 /* allow files to be piped into smbclient
1866 jdblair 24.jun.98 */
1867 if (!strcmp(lname, "-")) {
1868 f = stdin;
1869 /* size of file is not known */
1870 finfo->size = 0;
1871 } else {
1872 f = fopen(lname,"r");
1875 if (!f)
1877 DEBUG(0,("Error opening local file %s\n",lname));
1878 free(inbuf);free(outbuf);
1879 return;
1883 fnum = SVAL(inbuf,smb_vwv0);
1884 if (finfo->size < 0)
1885 finfo->size = file_size(lname);
1887 DEBUG(1,("putting file %s of size %.0f bytes as %s ",lname,(double)finfo->size,CNV_LANG(rname)));
1889 if (!maxwrite)
1890 maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
1892 /* This is a rewrite of the read/write loop that doesn't require the input
1893 file to be of a known length. This allows the stream pointer 'f' to
1894 refer to stdin.
1896 Rather than reallocing the read buffer every loop to keep it the min
1897 necessary length this look uses a fixed length buffer and just tests
1898 for eof on the file stream at the top of each loop.
1899 jdblair, 24.jun.98 */
1901 buf = (char *)malloc(maxwrite+4);
1902 while (! feof(f) )
1904 int n = maxwrite;
1905 int ret;
1907 fseek(f,nread,SEEK_SET);
1908 if ((n = readfile(buf+4,1,n,f)) < 1)
1910 DEBUG(0,("Error reading local file\n"));
1911 break;
1914 ret = smb_writefile(outbuf,fnum,nread,buf+4,n);
1916 if (n != ret) {
1917 if (!maxwrite) {
1918 DEBUG(0,("Error writing file\n"));
1919 break;
1920 } else {
1921 maxwrite /= 2;
1922 continue;
1926 nread += n;
1929 bzero(outbuf,smb_size);
1930 set_message(outbuf,3,0,True);
1931 CVAL(outbuf,smb_com) = SMBclose;
1932 SSVAL(outbuf,smb_tid,cnum);
1933 cli_setup_pkt(outbuf);
1935 SSVAL(outbuf,smb_vwv0,fnum);
1936 put_dos_date3(outbuf,smb_vwv1,close_time);
1938 send_smb(Client,outbuf);
1939 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1941 if (CVAL(inbuf,smb_rcls) != 0)
1943 DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1944 fclose(f);
1945 free(inbuf);free(outbuf);
1946 if (buf) free(buf);
1947 return;
1951 fclose(f);
1952 free(inbuf);free(outbuf);
1953 if (buf) free(buf);
1956 struct timeval tp_end;
1957 int this_time;
1959 GetTimeOfDay(&tp_end);
1960 this_time =
1961 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1962 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1963 put_total_time_ms += this_time;
1964 put_total_size += finfo->size;
1966 DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
1967 finfo->size / (1.024*this_time + 1.0e-4),
1968 put_total_size / (1.024*put_total_time_ms)));
1974 /****************************************************************************
1975 put a file
1976 ****************************************************************************/
1977 static void cmd_put(char *dum_in, char *dum_out)
1979 pstring lname;
1980 pstring rname;
1981 fstring buf;
1982 char *p=buf;
1983 file_info finfo;
1984 finfo = def_finfo;
1986 pstrcpy(rname,cur_dir);
1987 pstrcat(rname,"\\");
1990 if (!next_token(NULL,p,NULL,sizeof(buf)))
1992 DEBUG(0,("put <filename>\n"));
1993 return;
1995 pstrcpy(lname,p);
1997 if (next_token(NULL,p,NULL,sizeof(buf)))
1998 pstrcat(rname,p);
1999 else
2000 pstrcat(rname,lname);
2002 dos_clean_name(rname);
2005 SMB_STRUCT_STAT st;
2006 /* allow '-' to represent stdin
2007 jdblair, 24.jun.98 */
2008 if (!file_exist(lname,&st) &&
2009 (strcmp(lname,"-"))) {
2010 DEBUG(0,("%s does not exist\n",lname));
2011 return;
2013 finfo.mtime = st.st_mtime;
2016 do_put(rname,lname,&finfo);
2019 /****************************************************************************
2020 seek in a directory/file list until you get something that doesn't start with
2021 the specified name
2022 ****************************************************************************/
2023 static BOOL seek_list(FILE *f,char *name)
2025 pstring s;
2026 while (!feof(f))
2028 if (fscanf(f,"%s",s) != 1) return(False);
2029 trim_string(s,"./",NULL);
2030 if (strncmp(s,name,strlen(name)) != 0)
2032 pstrcpy(name,s);
2033 return(True);
2037 return(False);
2041 /****************************************************************************
2042 set the file selection mask
2043 ****************************************************************************/
2044 static void cmd_select(char *dum_in, char *dum_out)
2046 pstrcpy(fileselection,"");
2047 next_token(NULL,fileselection,NULL,sizeof(fileselection));
2051 /****************************************************************************
2052 mput some files
2053 ****************************************************************************/
2054 static void cmd_mput(char *dum_in, char *dum_out)
2056 pstring lname;
2057 pstring rname;
2058 file_info finfo;
2059 fstring buf;
2060 char *p=buf;
2062 finfo = def_finfo;
2065 while (next_token(NULL,p,NULL,sizeof(buf)))
2067 SMB_STRUCT_STAT st;
2068 pstring cmd;
2069 pstring tmpname;
2070 FILE *f;
2072 slprintf(tmpname,sizeof(pstring)-1,
2073 "%s/ls.smb.%d",tmpdir(),(int)getpid());
2074 if (recurse)
2075 slprintf(cmd,sizeof(pstring)-1,
2076 "find . -name \"%s\" -print > %s",p,tmpname);
2077 else
2078 slprintf(cmd,sizeof(pstring)-1,
2079 "/bin/ls %s > %s",p,tmpname);
2080 system(cmd);
2082 f = fopen(tmpname,"r");
2083 if (!f) continue;
2085 while (!feof(f))
2087 pstring quest;
2089 if (fscanf(f,"%s",lname) != 1) break;
2090 trim_string(lname,"./",NULL);
2092 again1:
2094 /* check if it's a directory */
2095 if (directory_exist(lname,&st))
2097 if (!recurse) continue;
2098 slprintf(quest,sizeof(pstring)-1,
2099 "Put directory %s? ",lname);
2100 if (prompt && !yesno(quest))
2102 pstrcat(lname,"/");
2103 if (!seek_list(f,lname))
2104 break;
2105 goto again1;
2108 pstrcpy(rname,cur_dir);
2109 pstrcat(rname,lname);
2110 if (!chkpath(rname,False) && !do_mkdir(rname)) {
2111 pstrcat(lname,"/");
2112 if (!seek_list(f,lname))
2113 break;
2114 goto again1;
2117 continue;
2119 else
2121 slprintf(quest,sizeof(quest)-1,
2122 "Put file %s? ",lname);
2123 if (prompt && !yesno(quest)) continue;
2125 pstrcpy(rname,cur_dir);
2126 pstrcat(rname,lname);
2128 dos_format(rname);
2130 /* null size so do_put knows to ignore it */
2131 finfo.size = -1;
2133 /* set the date on the file */
2134 finfo.mtime = st.st_mtime;
2136 do_put(rname,lname,&finfo);
2138 fclose(f);
2139 unlink(tmpname);
2143 /****************************************************************************
2144 cancel a print job
2145 ****************************************************************************/
2146 static void do_cancel(int job)
2148 char *rparam = NULL;
2149 char *rdata = NULL;
2150 char *p;
2151 int rdrcnt,rprcnt;
2152 pstring param;
2154 bzero(param,sizeof(param));
2156 p = param;
2157 SSVAL(p,0,81); /* DosPrintJobDel() */
2158 p += 2;
2159 pstrcpy(p,"W");
2160 p = skip_string(p,1);
2161 pstrcpy(p,"");
2162 p = skip_string(p,1);
2163 SSVAL(p,0,job);
2164 p += 2;
2166 if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
2167 6, 1000,
2168 &rprcnt,&rdrcnt,
2169 param,NULL, NULL,
2170 &rparam,&rdata))
2172 int res = SVAL(rparam,0);
2174 if (!res)
2175 printf("Job %d cancelled\n",job);
2176 else
2177 printf("Error %d calcelling job %d\n",res,job);
2178 return;
2180 else
2181 printf("Server refused cancel request\n");
2183 if (rparam) free(rparam);
2184 if (rdata) free(rdata);
2186 return;
2190 /****************************************************************************
2191 cancel a print job
2192 ****************************************************************************/
2193 static void cmd_cancel(char *inbuf,char *outbuf )
2195 fstring buf;
2196 int job;
2198 if (!connect_as_printer)
2200 DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2201 DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
2204 if (!next_token(NULL,buf,NULL,sizeof(buf))) {
2205 printf("cancel <jobid> ...\n");
2206 return;
2208 do {
2209 job = atoi(buf);
2210 do_cancel(job);
2211 } while (next_token(NULL,buf,NULL,sizeof(buf)));
2217 /****************************************************************************
2218 print a file
2219 ****************************************************************************/
2220 static void cmd_print(char *inbuf,char *outbuf )
2222 int fnum;
2223 FILE *f = NULL;
2224 uint32 nread=0;
2225 pstring lname;
2226 pstring rname;
2227 char *p;
2229 if (!connect_as_printer)
2231 DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2232 DEBUG(0,("Trying to print without -P may fail\n"));
2235 if (!next_token(NULL,lname,NULL, sizeof(lname)))
2237 DEBUG(0,("print <filename>\n"));
2238 return;
2241 pstrcpy(rname,lname);
2242 p = strrchr(rname,'/');
2243 if (p)
2245 pstring tname;
2246 pstrcpy(tname,p+1);
2247 pstrcpy(rname,tname);
2250 if ((int)strlen(rname) > 14)
2251 rname[14] = 0;
2253 if (strequal(lname,"-"))
2255 f = stdin;
2256 pstrcpy(rname,"stdin");
2259 dos_clean_name(rname);
2261 bzero(outbuf,smb_size);
2262 set_message(outbuf,2,2 + strlen(rname),True);
2264 CVAL(outbuf,smb_com) = SMBsplopen;
2265 SSVAL(outbuf,smb_tid,cnum);
2266 cli_setup_pkt(outbuf);
2268 SSVAL(outbuf,smb_vwv0,0);
2269 SSVAL(outbuf,smb_vwv1,printmode);
2271 p = smb_buf(outbuf);
2272 *p++ = 4;
2273 pstrcpy(p,rname);
2275 send_smb(Client,outbuf);
2276 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2278 if (CVAL(inbuf,smb_rcls) != 0)
2280 DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
2281 return;
2284 if (!f)
2285 f = fopen(lname,"r");
2286 if (!f)
2288 DEBUG(0,("Error opening local file %s\n",lname));
2289 return;
2293 fnum = SVAL(inbuf,smb_vwv0);
2295 DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname)));
2297 while (!feof(f))
2299 int n;
2301 bzero(outbuf,smb_size);
2302 set_message(outbuf,1,3,True);
2304 /* for some strange reason the OS/2 print server can't handle large
2305 packets when printing. weird */
2306 n = MIN(1024,max_xmit-(smb_len(outbuf)+4));
2308 if (translation)
2309 n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n));
2310 else
2311 n = readfile(smb_buf(outbuf)+3,1,n,f);
2312 if (n <= 0)
2314 DEBUG(0,("read gave %d\n",n));
2315 break;
2318 smb_setlen(outbuf,smb_len(outbuf) + n);
2320 CVAL(outbuf,smb_com) = SMBsplwr;
2321 SSVAL(outbuf,smb_tid,cnum);
2322 cli_setup_pkt(outbuf);
2324 SSVAL(outbuf,smb_vwv0,fnum);
2325 SSVAL(outbuf,smb_vwv1,n+3);
2326 CVAL(smb_buf(outbuf),0) = 1;
2327 SSVAL(smb_buf(outbuf),1,n);
2329 send_smb(Client,outbuf);
2330 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2332 if (CVAL(inbuf,smb_rcls) != 0)
2334 DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf)));
2335 break;
2338 nread += n;
2341 DEBUG(2,("%d bytes printed\n",nread));
2343 bzero(outbuf,smb_size);
2344 set_message(outbuf,1,0,True);
2345 CVAL(outbuf,smb_com) = SMBsplclose;
2346 SSVAL(outbuf,smb_tid,cnum);
2347 cli_setup_pkt(outbuf);
2349 SSVAL(outbuf,smb_vwv0,fnum);
2351 send_smb(Client,outbuf);
2352 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2354 if (CVAL(inbuf,smb_rcls) != 0)
2356 DEBUG(0,("%s closing print file\n",smb_errstr(inbuf)));
2357 if (f != stdin)
2358 fclose(f);
2359 return;
2362 if (f != stdin)
2363 fclose(f);
2366 /****************************************************************************
2367 show a print queue - this is deprecated as it uses the old smb that
2368 has limited support - the correct call is the cmd_p_queue_4() after this.
2369 ****************************************************************************/
2370 static void cmd_queue(char *inbuf,char *outbuf )
2372 int count;
2373 char *p;
2375 bzero(outbuf,smb_size);
2376 set_message(outbuf,2,0,True);
2378 CVAL(outbuf,smb_com) = SMBsplretq;
2379 SSVAL(outbuf,smb_tid,cnum);
2380 cli_setup_pkt(outbuf);
2382 SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
2383 SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
2385 send_smb(Client,outbuf);
2386 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2388 if (CVAL(inbuf,smb_rcls) != 0)
2390 DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf)));
2391 return;
2394 count = SVAL(inbuf,smb_vwv0);
2395 p = smb_buf(inbuf) + 3;
2396 if (count <= 0)
2398 DEBUG(0,("No entries in the print queue\n"));
2399 return;
2403 char status[20];
2405 DEBUG(0,("Job Name Size Status\n"));
2407 while (count--)
2409 switch (CVAL(p,4))
2411 case 0x01: safe_strcpy(status,"held or stopped", sizeof(status)-1); break;
2412 case 0x02: safe_strcpy(status,"printing",sizeof(status)-1); break;
2413 case 0x03: safe_strcpy(status,"awaiting print", sizeof(status)-1); break;
2414 case 0x04: safe_strcpy(status,"in intercept",sizeof(status)-1); break;
2415 case 0x05: safe_strcpy(status,"file had error",sizeof(status)-1); break;
2416 case 0x06: safe_strcpy(status,"printer error",sizeof(status)-1); break;
2417 default: safe_strcpy(status,"unknown",sizeof(status)-1); break;
2420 DEBUG(0,("%-6d %-16.16s %-9d %s\n",
2421 SVAL(p,5),p+12,IVAL(p,7),status));
2422 p += 28;
2429 /****************************************************************************
2430 show information about a print queue
2431 ****************************************************************************/
2432 static void cmd_p_queue_4(char *inbuf,char *outbuf )
2434 char *rparam = NULL;
2435 char *rdata = NULL;
2436 char *p;
2437 int rdrcnt, rprcnt;
2438 pstring param;
2439 int result_code=0;
2441 if (!connect_as_printer)
2443 DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2444 DEBUG(0,("Trying to print without -P may fail\n"));
2447 bzero(param,sizeof(param));
2449 p = param;
2450 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
2451 p += 2;
2452 pstrcpy(p,"zWrLeh"); /* parameter description? */
2453 p = skip_string(p,1);
2454 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
2455 p = skip_string(p,1);
2456 pstrcpy(p,strrchr(service,'\\')+1); /* name of queue */
2457 p = skip_string(p,1);
2458 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
2459 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
2460 p += 4;
2461 pstrcpy(p,""); /* subformat */
2462 p = skip_string(p,1);
2464 DEBUG(1,("Calling DosPrintJobEnum()...\n"));
2465 if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
2466 10, 4096,
2467 &rprcnt, &rdrcnt,
2468 param, NULL, NULL,
2469 &rparam, &rdata) )
2471 int converter;
2472 result_code = SVAL(rparam,0);
2473 converter = SVAL(rparam,2); /* conversion factor */
2475 DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2477 if (result_code == 0) /* if no error, */
2479 int i;
2480 uint16 JobId;
2481 uint16 Priority;
2482 uint32 Size;
2483 char *UserName;
2484 char *JobName;
2485 char *JobTimeStr;
2486 time_t JobTime;
2487 fstring PrinterName;
2489 fstrcpy(PrinterName,strrchr(service,'\\')+1); /* name of queue */
2490 strlower(PrinterName); /* in lower case */
2492 p = rdata; /* received data */
2493 for( i = 0; i < SVAL(rparam,4); ++i)
2495 JobId = SVAL(p,0);
2496 Priority = SVAL(p,2);
2497 UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
2498 strlower(UserName);
2499 Priority = SVAL(p,2);
2500 JobTime = make_unix_date3( p + 12);
2501 JobTimeStr = asctime(LocalTime( &JobTime));
2502 Size = IVAL(p,16);
2503 JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
2506 printf("%s-%u %s priority %u %s %s %u bytes\n",
2507 PrinterName, JobId, UserName,
2508 Priority, JobTimeStr, JobName, Size);
2510 #if 0 /* DEBUG code */
2511 printf("Job Id: \"%u\"\n", SVAL(p,0));
2512 printf("Priority: \"%u\"\n", SVAL(p,2));
2514 printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
2515 printf("Position: \"%u\"\n", SVAL(p,8));
2516 printf("Status: \"%u\"\n", SVAL(p,10));
2518 JobTime = make_unix_date3( p + 12);
2519 printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
2520 printf("date: \"%u\"\n", SVAL(p,12));
2522 printf("Size: \"%u\"\n", SVAL(p,16));
2523 printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2524 printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2525 #endif /* DEBUG CODE */
2526 p += 28;
2530 else /* cli_call_api() failed */
2532 printf("Failed, error = %d\n", result_code);
2535 /* If any parameters or data were returned, free the storage. */
2536 if(rparam) free(rparam);
2537 if(rdata) free(rdata);
2539 return;
2542 /****************************************************************************
2543 show information about a print queue
2544 ****************************************************************************/
2545 static void cmd_qinfo(char *inbuf,char *outbuf )
2547 char *rparam = NULL;
2548 char *rdata = NULL;
2549 char *p;
2550 int rdrcnt, rprcnt;
2551 pstring param;
2552 int result_code=0;
2554 bzero(param,sizeof(param));
2556 p = param;
2557 SSVAL(p,0,70); /* API function number 70 (DosPrintQGetInfo) */
2558 p += 2;
2559 pstrcpy(p,"zWrLh"); /* parameter description? */
2560 p = skip_string(p,1);
2561 pstrcpy(p,"zWWWWzzzzWWzzl"); /* returned data format */
2562 p = skip_string(p,1);
2563 pstrcpy(p,strrchr(service,'\\')+1); /* name of queue */
2564 p = skip_string(p,1);
2565 SSVAL(p,0,3); /* API function level 3, just queue info, no job info */
2566 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
2567 p += 4;
2568 pstrcpy(p,""); /* subformat */
2569 p = skip_string(p,1);
2571 DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
2572 if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
2573 10, 4096,
2574 &rprcnt, &rdrcnt,
2575 param, NULL, NULL,
2576 &rparam, &rdata) )
2578 int converter;
2579 result_code = SVAL(rparam,0);
2580 converter = SVAL(rparam,2); /* conversion factor */
2582 DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2584 if (result_code == 0) /* if no error, */
2586 p = rdata; /* received data */
2588 printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
2589 printf("Priority: %u\n", SVAL(p,4) );
2590 printf("Start time: %u\n", SVAL(p,6) );
2591 printf("Until time: %u\n", SVAL(p,8) );
2592 printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
2593 printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
2594 printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2595 printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2596 printf("Status: %u\n", SVAL(p,28) );
2597 printf("Jobs: %u\n", SVAL(p,30) );
2598 printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
2599 printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
2601 /* Dump the driver data */
2603 int count, x, y, c;
2604 char *ddptr;
2606 ddptr = rdata + SVAL(p,40) - converter;
2607 if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
2608 printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
2610 for(x=8; x < count; x+=16)
2612 for(y=0; y < 16; y++)
2614 if( (x+y) < count )
2615 printf("%2.2X ", CVAL(ddptr,(x+y)) );
2616 else
2617 fputs(" ", stdout);
2619 for(y=0; y < 16 && (x+y) < count; y++)
2621 c = CVAL(ddptr,(x+y));
2622 if(isprint(c))
2623 fputc(c, stdout);
2624 else
2625 fputc('.', stdout);
2627 fputc('\n', stdout);
2633 else /* cli_call_api() failed */
2635 printf("Failed, error = %d\n", result_code);
2638 /* If any parameters or data were returned, free the storage. */
2639 if(rparam) free(rparam);
2640 if(rdata) free(rdata);
2642 return;
2645 /****************************************************************************
2646 delete some files
2647 ****************************************************************************/
2648 static void do_del(file_info *finfo)
2650 char *p;
2651 char *inbuf,*outbuf;
2652 pstring mask;
2654 pstrcpy(mask,cur_dir);
2655 pstrcat(mask,finfo->name);
2657 if (finfo->mode & aDIR)
2658 return;
2660 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2661 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2663 if (!inbuf || !outbuf)
2665 DEBUG(0,("out of memory\n"));
2666 return;
2669 bzero(outbuf,smb_size);
2670 set_message(outbuf,1,2 + strlen(mask),True);
2672 CVAL(outbuf,smb_com) = SMBunlink;
2673 SSVAL(outbuf,smb_tid,cnum);
2674 cli_setup_pkt(outbuf);
2676 SSVAL(outbuf,smb_vwv0,0);
2678 p = smb_buf(outbuf);
2679 *p++ = 4;
2680 pstrcpy(p,mask);
2682 send_smb(Client,outbuf);
2683 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2685 if (CVAL(inbuf,smb_rcls) != 0)
2686 DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2688 free(inbuf);free(outbuf);
2692 /****************************************************************************
2693 delete some files
2694 ****************************************************************************/
2695 static void cmd_del(char *inbuf,char *outbuf )
2697 pstring mask;
2698 fstring buf;
2699 int attribute = aSYSTEM | aHIDDEN;
2701 if (recurse)
2702 attribute |= aDIR;
2704 pstrcpy(mask,cur_dir);
2706 if (!next_token(NULL,buf,NULL,sizeof(buf)))
2708 DEBUG(0,("del <filename>\n"));
2709 return;
2711 pstrcat(mask,buf);
2713 do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False,False);
2717 /****************************************************************************
2718 remove a directory
2719 ****************************************************************************/
2720 static void cmd_rmdir(char *inbuf,char *outbuf )
2722 pstring mask;
2723 fstring buf;
2724 char *p;
2726 pstrcpy(mask,cur_dir);
2728 if (!next_token(NULL,buf,NULL,sizeof(buf)))
2730 DEBUG(0,("rmdir <dirname>\n"));
2731 return;
2733 pstrcat(mask,buf);
2735 bzero(outbuf,smb_size);
2736 set_message(outbuf,0,2 + strlen(mask),True);
2738 CVAL(outbuf,smb_com) = SMBrmdir;
2739 SSVAL(outbuf,smb_tid,cnum);
2740 cli_setup_pkt(outbuf);
2743 p = smb_buf(outbuf);
2744 *p++ = 4;
2745 pstrcpy(p,mask);
2747 send_smb(Client,outbuf);
2748 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2750 if (CVAL(inbuf,smb_rcls) != 0)
2752 DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2753 return;
2758 /****************************************************************************
2759 rename some files
2760 ****************************************************************************/
2761 static void cmd_rename(char *inbuf,char *outbuf )
2763 pstring src,dest;
2764 fstring buf,buf2;
2765 char *p;
2767 pstrcpy(src,cur_dir);
2768 pstrcpy(dest,cur_dir);
2770 if (!next_token(NULL,buf,NULL,sizeof(buf)) ||
2771 !next_token(NULL,buf2,NULL, sizeof(buf2)))
2773 DEBUG(0,("rename <src> <dest>\n"));
2774 return;
2776 pstrcat(src,buf);
2777 pstrcat(dest,buf2);
2779 bzero(outbuf,smb_size);
2780 set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
2782 CVAL(outbuf,smb_com) = SMBmv;
2783 SSVAL(outbuf,smb_tid,cnum);
2784 SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
2785 cli_setup_pkt(outbuf);
2787 p = smb_buf(outbuf);
2788 *p++ = 4;
2789 pstrcpy(p,src);
2790 p = skip_string(p,1);
2791 *p++ = 4;
2792 pstrcpy(p,dest);
2794 send_smb(Client,outbuf);
2795 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2797 if (CVAL(inbuf,smb_rcls) != 0)
2799 DEBUG(0,("%s renaming files\n",smb_errstr(inbuf)));
2800 return;
2806 /****************************************************************************
2807 toggle the prompt flag
2808 ****************************************************************************/
2809 static void cmd_prompt(char *dum_in, char *dum_out)
2811 prompt = !prompt;
2812 DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2816 /****************************************************************************
2817 set the newer than time
2818 ****************************************************************************/
2819 static void cmd_newer(char *dum_in, char *dum_out)
2821 fstring buf;
2822 BOOL ok;
2823 SMB_STRUCT_STAT sbuf;
2825 ok = next_token(NULL,buf,NULL,sizeof(buf));
2826 if (ok && (dos_stat(buf,&sbuf) == 0))
2828 newer_than = sbuf.st_mtime;
2829 DEBUG(1,("Getting files newer than %s",
2830 asctime(LocalTime(&newer_than))));
2832 else
2833 newer_than = 0;
2835 if (ok && newer_than == 0)
2836 DEBUG(0,("Error setting newer-than time\n"));
2839 /****************************************************************************
2840 set the archive level
2841 ****************************************************************************/
2842 static void cmd_archive(char *dum_in, char *dum_out)
2844 fstring buf;
2846 if (next_token(NULL,buf,NULL,sizeof(buf))) {
2847 archive_level = atoi(buf);
2848 } else
2849 DEBUG(0,("Archive level is %d\n",archive_level));
2852 /****************************************************************************
2853 toggle the lowercaseflag
2854 ****************************************************************************/
2855 static void cmd_lowercase(char *dum_in, char *dum_out)
2857 lowercase = !lowercase;
2858 DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2864 /****************************************************************************
2865 toggle the recurse flag
2866 ****************************************************************************/
2867 static void cmd_recurse(char *dum_in, char *dum_out)
2869 recurse = !recurse;
2870 DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2873 /****************************************************************************
2874 toggle the translate flag
2875 ****************************************************************************/
2876 static void cmd_translate(char *dum_in, char *dum_out)
2878 translation = !translation;
2879 DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2880 translation?"on":"off"));
2884 /****************************************************************************
2885 do a printmode command
2886 ****************************************************************************/
2887 static void cmd_printmode(char *dum_in, char *dum_out)
2889 fstring buf;
2890 fstring mode;
2892 if (next_token(NULL,buf,NULL,sizeof(buf)))
2894 if (strequal(buf,"text"))
2895 printmode = 0;
2896 else
2898 if (strequal(buf,"graphics"))
2899 printmode = 1;
2900 else
2901 printmode = atoi(buf);
2905 switch(printmode)
2907 case 0:
2908 fstrcpy(mode,"text");
2909 break;
2910 case 1:
2911 fstrcpy(mode,"graphics");
2912 break;
2913 default:
2914 slprintf(mode,sizeof(mode)-1,"%d",printmode);
2915 break;
2918 DEBUG(2,("the printmode is now %s\n",mode));
2921 /****************************************************************************
2922 do the lcd command
2923 ****************************************************************************/
2924 static void cmd_lcd(char *dum_in, char *dum_out)
2926 fstring buf;
2927 pstring d;
2929 if (next_token(NULL,buf,NULL,sizeof(buf)))
2930 dos_chdir(buf);
2931 DEBUG(2,("the local directory is now %s\n",GetWd(d)));
2935 /****************************************************************************
2936 try and browse available connections on a host
2937 ****************************************************************************/
2938 static BOOL browse_host(BOOL sort)
2940 char *rparam = NULL;
2941 char *rdata = NULL;
2942 char *p;
2943 int rdrcnt,rprcnt;
2944 pstring param;
2945 int count = -1;
2947 /* now send a SMBtrans command with api RNetShareEnum */
2948 p = param;
2949 SSVAL(p,0,0); /* api number */
2950 p += 2;
2951 pstrcpy(p,"WrLeh");
2952 p = skip_string(p,1);
2953 pstrcpy(p,"B13BWz");
2954 p = skip_string(p,1);
2955 SSVAL(p,0,1);
2956 SSVAL(p,2,BUFFER_SIZE);
2957 p += 4;
2959 if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
2960 1024, BUFFER_SIZE,
2961 &rprcnt,&rdrcnt,
2962 param,NULL, NULL,
2963 &rparam,&rdata))
2965 int res = SVAL(rparam,0);
2966 int converter=SVAL(rparam,2);
2967 int i;
2968 BOOL long_share_name=False;
2970 if (res == 0 || res == ERRmoredata)
2972 count=SVAL(rparam,4);
2973 p = rdata;
2975 if (count > 0)
2977 printf("\n\tSharename Type Comment\n");
2978 printf("\t--------- ---- -------\n");
2981 if (sort)
2982 qsort(p,count,20,QSORT_CAST StrCaseCmp);
2984 for (i=0;i<count;i++)
2986 char *sname = p;
2987 int type = SVAL(p,14);
2988 int comment_offset = IVAL(p,16) & 0xFFFF;
2989 fstring typestr;
2990 *typestr=0;
2992 switch (type)
2994 case STYPE_DISKTREE:
2995 fstrcpy(typestr,"Disk"); break;
2996 case STYPE_PRINTQ:
2997 fstrcpy(typestr,"Printer"); break;
2998 case STYPE_DEVICE:
2999 fstrcpy(typestr,"Device"); break;
3000 case STYPE_IPC:
3001 fstrcpy(typestr,"IPC"); break;
3004 printf("\t%-15.15s%-10.10s%s\n",
3005 sname, typestr,
3006 comment_offset?rdata+comment_offset-converter:"");
3008 if (strlen(sname)>8) long_share_name=True;
3010 p += 20;
3013 if (long_share_name) {
3014 printf("\nNOTE: There were share names longer than 8 chars.\n\
3015 On older clients these may not be accessible or may give browsing errors\n");
3018 if(res == ERRmoredata)
3019 printf("\nNOTE: More data was available, the list was truncated.\n");
3023 if (rparam) free(rparam);
3024 if (rdata) free(rdata);
3026 return(count>0);
3030 /****************************************************************************
3031 get some server info
3032 ****************************************************************************/
3033 static void server_info(void)
3035 char *rparam = NULL;
3036 char *rdata = NULL;
3037 char *p;
3038 int rdrcnt,rprcnt;
3039 pstring param;
3041 bzero(param,sizeof(param));
3043 p = param;
3044 SSVAL(p,0,63); /* NetServerGetInfo()? */
3045 p += 2;
3046 pstrcpy(p,"WrLh");
3047 p = skip_string(p,1);
3048 pstrcpy(p,"zzzBBzz");
3049 p = skip_string(p,1);
3050 SSVAL(p,0,10); /* level 10 */
3051 SSVAL(p,2,1000);
3052 p += 6;
3054 if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
3055 6, 1000,
3056 &rprcnt,&rdrcnt,
3057 param,NULL, NULL,
3058 &rparam,&rdata))
3060 int res = SVAL(rparam,0);
3061 int converter=SVAL(rparam,2);
3063 if (res == 0)
3065 p = rdata;
3067 printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3068 rdata+SVAL(p,0)-converter,
3069 rdata+SVAL(p,4)-converter,
3070 rdata+SVAL(p,8)-converter,
3071 rdata+SVAL(p,14)-converter);
3075 if (rparam) free(rparam);
3076 if (rdata) free(rdata);
3078 return;
3082 /****************************************************************************
3083 try and browse available connections on a host
3084 ****************************************************************************/
3085 static BOOL list_servers(char *wk_grp)
3087 char *rparam = NULL;
3088 char *rdata = NULL;
3089 int rdrcnt,rprcnt;
3090 char *p,*svtype_p;
3091 pstring param;
3092 int uLevel = 1;
3093 int count = 0;
3094 BOOL ok = False;
3095 BOOL generic_request = False;
3098 if (strequal(wk_grp,"WORKGROUP")) {
3099 /* we won't specify a workgroup */
3100 generic_request = True;
3103 /* now send a SMBtrans command with api ServerEnum? */
3104 p = param;
3105 SSVAL(p,0,0x68); /* api number */
3106 p += 2;
3108 pstrcpy(p,generic_request?"WrLehDO":"WrLehDz");
3109 p = skip_string(p,1);
3111 pstrcpy(p,"B16BBDz");
3113 p = skip_string(p,1);
3114 SSVAL(p,0,uLevel);
3115 SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
3116 p += 4;
3118 svtype_p = p;
3119 p += 4;
3121 if (!generic_request) {
3122 pstrcpy(p, wk_grp);
3123 p = skip_string(p,1);
3126 /* first ask for a list of servers in this workgroup */
3127 SIVAL(svtype_p,0,SV_TYPE_ALL);
3129 if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
3130 8, BUFFER_SIZE - SAFETY_MARGIN,
3131 &rprcnt,&rdrcnt,
3132 param,NULL, NULL,
3133 &rparam,&rdata))
3135 int res = SVAL(rparam,0);
3136 int converter=SVAL(rparam,2);
3137 int i;
3139 if (res == 0 || res == ERRmoredata) {
3140 char *p2 = rdata;
3141 count=SVAL(rparam,4);
3143 if (count > 0) {
3144 printf("\n\nThis machine has a browse list:\n");
3145 printf("\n\tServer Comment\n");
3146 printf("\t--------- -------\n");
3149 for (i=0;i<count;i++) {
3150 char *sname = p2;
3151 int comment_offset = IVAL(p2,22) & 0xFFFF;
3152 printf("\t%-16.16s %s\n", sname,
3153 comment_offset?rdata+comment_offset-converter:"");
3155 ok=True;
3156 p2 += 26;
3159 if(res == ERRmoredata)
3160 printf("\nNOTE: More data was available, the list was truncated.\n");
3164 if (rparam) {free(rparam); rparam = NULL;}
3165 if (rdata) {free(rdata); rdata = NULL;}
3167 /* now ask for a list of workgroups */
3168 SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
3170 if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
3171 8, BUFFER_SIZE - SAFETY_MARGIN,
3172 &rprcnt,&rdrcnt,
3173 param,NULL, NULL,
3174 &rparam,&rdata))
3176 int res = SVAL(rparam,0);
3177 int converter=SVAL(rparam,2);
3178 int i;
3180 if (res == 0 || res == ERRmoredata) {
3181 char *p2 = rdata;
3182 count=SVAL(rparam,4);
3184 if (count > 0) {
3185 printf("\n\nThis machine has a workgroup list:\n");
3186 printf("\n\tWorkgroup Master\n");
3187 printf("\t--------- -------\n");
3190 for (i=0;i<count;i++) {
3191 char *sname = p2;
3192 int comment_offset = IVAL(p2,22) & 0xFFFF;
3193 printf("\t%-16.16s %s\n", sname,
3194 comment_offset?rdata+comment_offset-converter:"");
3196 ok=True;
3197 p2 += 26;
3200 if(res == ERRmoredata)
3201 printf("\nNOTE: More data was available, the list was truncated.\n");
3205 if (rparam) free(rparam);
3206 if (rdata) free(rdata);
3208 return(ok);
3212 /* Some constants for completing filename arguments */
3214 #define COMPL_NONE 0 /* No completions */
3215 #define COMPL_REMOTE 1 /* Complete remote filename */
3216 #define COMPL_LOCAL 2 /* Complete local filename */
3218 /* This defines the commands supported by this client */
3219 struct
3221 char *name;
3222 void (*fn)(char *, char *);
3223 char *description;
3224 char compl_args[2]; /* Completion argument info */
3225 } commands[] =
3227 {"ls",cmd_dir,"<mask> list the contents of the current directory",COMPL_REMOTE},
3228 {"dir",cmd_dir,"<mask> list the contents of the current directory",COMPL_REMOTE},
3229 {"lcd",cmd_lcd,"[directory] change/report the local current working directory",COMPL_LOCAL},
3230 {"cd",cmd_cd,"[directory] change/report the remote directory",COMPL_REMOTE},
3231 {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
3232 {"get",cmd_get,"<remote name> [local name] get a file",COMPL_REMOTE,COMPL_LOCAL},
3233 {"mget",cmd_mget,"<mask> get all the matching files",COMPL_REMOTE},
3234 {"put",cmd_put,"<local name> [remote name] put a file",COMPL_LOCAL,COMPL_REMOTE},
3235 {"mput",cmd_mput,"<mask> put all matching files",COMPL_REMOTE},
3236 {"rename",cmd_rename,"<src> <dest> rename some files",COMPL_REMOTE,COMPL_REMOTE},
3237 {"more",cmd_more,"<remote name> view a remote file with your pager",COMPL_REMOTE},
3238 {"mask",cmd_select,"<mask> mask all filenames against this",COMPL_REMOTE},
3239 {"del",cmd_del,"<mask> delete all matching files",COMPL_REMOTE},
3240 {"rm",cmd_del,"<mask> delete all matching files",COMPL_REMOTE},
3241 {"mkdir",cmd_mkdir,"<directory> make a directory"},
3242 {"md",cmd_mkdir,"<directory> make a directory"},
3243 {"rmdir",cmd_rmdir,"<directory> remove a directory"},
3244 {"rd",cmd_rmdir,"<directory> remove a directory"},
3245 {"pq",cmd_p_queue_4,"enumerate the print queue"},
3246 {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},
3247 {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},
3248 {"translate",cmd_translate,"toggle text translation for printing"},
3249 {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},
3250 {"print",cmd_print,"<file name> print a file"},
3251 {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
3252 {"queue",cmd_queue,"show the print queue"},
3253 {"qinfo",cmd_qinfo,"show print queue information"},
3254 {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
3255 {"quit",cli_send_logout,"logoff the server"},
3256 {"q",cli_send_logout,"logoff the server"},
3257 {"exit",cli_send_logout,"logoff the server"},
3258 {"newer",cmd_newer,"<file> only mget files newer than the specified local file",COMPL_LOCAL},
3259 {"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"},
3260 {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
3261 {"blocksize",cmd_block,"blocksize <number> (default 20)" },
3262 {"tarmode",cmd_tarmode,
3263 "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
3264 {"setmode",cmd_setmode,"filename <setmode string> change modes of file",COMPL_REMOTE},
3265 {"help",cmd_help,"[command] give help on a command"},
3266 {"?",cmd_help,"[command] give help on a command"},
3267 {"!",NULL,"run a shell command on the local system"},
3268 {"",NULL,NULL}
3272 /*******************************************************************
3273 lookup a command string in the list of commands, including
3274 abbreviations
3275 ******************************************************************/
3276 static int process_tok(fstring tok)
3278 int i = 0, matches = 0;
3279 int cmd=0;
3280 int tok_len = strlen(tok);
3282 while (commands[i].fn != NULL)
3284 if (strequal(commands[i].name,tok))
3286 matches = 1;
3287 cmd = i;
3288 break;
3290 else if (strnequal(commands[i].name, tok, tok_len))
3292 matches++;
3293 cmd = i;
3295 i++;
3298 if (matches == 0)
3299 return(-1);
3300 else if (matches == 1)
3301 return(cmd);
3302 else
3303 return(-2);
3306 /****************************************************************************
3307 help
3308 ****************************************************************************/
3309 static void cmd_help(char *dum_in, char *dum_out)
3311 int i=0,j;
3312 fstring buf;
3314 if (next_token(NULL,buf,NULL,sizeof(buf)))
3316 if ((i = process_tok(buf)) >= 0)
3317 DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));
3319 else
3320 while (commands[i].description)
3322 for (j=0; commands[i].description && (j<5); j++) {
3323 DEBUG(0,("%-15s",commands[i].name));
3324 i++;
3326 DEBUG(0,("\n"));
3332 /****************************************************************************
3333 wait for keyboard activity, swallowing network packets
3334 ****************************************************************************/
3335 static void wait_keyboard(char *buffer)
3337 fd_set fds;
3338 int selrtn;
3339 struct timeval timeout;
3341 while (1)
3343 extern int Client;
3344 FD_ZERO(&fds);
3345 FD_SET(Client,&fds);
3346 FD_SET(fileno(stdin),&fds);
3348 timeout.tv_sec = 20;
3349 timeout.tv_usec = 0;
3350 selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
3352 if (FD_ISSET(fileno(stdin),&fds))
3353 return;
3355 /* We deliberately use receive_smb instead of
3356 client_receive_smb as we want to receive
3357 session keepalives and then drop them here.
3359 if (FD_ISSET(Client,&fds))
3360 receive_smb(Client,buffer,0);
3362 chkpath("\\",False);
3366 #ifdef HAVE_LIBREADLINE
3368 /****************************************************************************
3369 completion routines for GNU Readline
3370 ****************************************************************************/
3372 /* To avoid filename completion being activated when no valid
3373 completions are found, we assign this stub completion function
3374 to the rl_completion_entry_function variable. */
3376 char *complete_cmd_null(char *text, int state)
3378 return NULL;
3381 /* Argh. This is starting to get ugly. We need to be able to pass data
3382 back from the do_dir() iterator function. */
3384 static int compl_state;
3385 static char *compl_text;
3386 static pstring result;
3388 /* Iterator function for do_dir() */
3390 void complete_process_file(file_info *f)
3392 /* Do we have a partial match? */
3394 if ((compl_state >= 0) && (strncmp(compl_text, f->name,
3395 strlen(compl_text)) == 0)) {
3397 /* Return filename if we have made enough matches */
3399 if (compl_state == 0) {
3400 pstrcpy(result, f->name);
3401 compl_state = -1;
3403 return;
3405 compl_state--;
3409 /* Complete a remote file */
3411 char *complete_remote_file(char *text, int state)
3413 char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3414 char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3415 int attribute = aDIR | aSYSTEM | aHIDDEN;
3416 pstring mask;
3418 if ((InBuffer == NULL) || (OutBuffer == NULL))
3419 return(NULL);
3421 /* Create dir mask */
3423 pstrcpy(mask, cur_dir);
3424 pstrcat(mask, "*");
3426 /* Initialise static vars for filename match */
3428 compl_text = text;
3429 compl_state = state;
3430 result[0] = '\0';
3432 /* Iterate over all files in directory */
3434 do_dir(InBuffer, OutBuffer, mask, attribute, complete_process_file, False,
3435 True);
3437 /* Clean up */
3439 free(InBuffer);
3440 free(OutBuffer);
3442 /* Return matched filename */
3444 if (result[0] != '\0') {
3445 return strdup(result); /* Readline will dispose of strings */
3446 } else {
3447 return NULL;
3451 /* Complete a smbclient command */
3453 char *complete_cmd(char *text, int state)
3455 static int cmd_index;
3456 char *name;
3458 /* Initialise */
3460 if (state == 0) {
3461 cmd_index = 0;
3464 /* Return the next name which partially matches the list of commands */
3466 while (strlen(name = commands[cmd_index++].name) > 0) {
3467 if (strncmp(name, text, strlen(text)) == 0) {
3468 return strdup(name);
3472 return NULL;
3475 /* Main completion function for smbclient. Work out which word we are
3476 trying to complete and call the appropriate function. */
3478 char **completion_fn(char *text, int start, int end)
3480 int i, num_words, cmd_index;
3481 char lastch = ' ';
3483 /* If we are at the start of a word, we are completing a smbclient
3484 command. */
3486 if (start == 0) {
3487 return completion_matches(text, complete_cmd);
3490 /* Count # of words in command */
3492 num_words = 0;
3493 for (i = 0; i <= end; i++) {
3494 if ((rl_line_buffer[i] != ' ') && (lastch == ' '))
3495 num_words++;
3496 lastch = rl_line_buffer[i];
3499 if (rl_line_buffer[end] == ' ')
3500 num_words++;
3502 /* Work out which command we are completing for */
3504 for (cmd_index = 0; strcmp(commands[cmd_index].name, "") != 0;
3505 cmd_index++) {
3507 /* Check each command in array */
3509 if (strncmp(rl_line_buffer, commands[cmd_index].name,
3510 strlen(commands[cmd_index].name)) == 0) {
3512 /* Call appropriate completion function */
3514 if ((num_words == 2) || (num_words == 3)) {
3515 switch (commands[cmd_index].compl_args[num_words - 2]) {
3517 case COMPL_REMOTE:
3518 return completion_matches(text, complete_remote_file);
3519 break;
3521 case COMPL_LOCAL:
3522 return completion_matches(text, filename_completion_function);
3523 break;
3525 default:
3526 /* An invalid completion type */
3527 break;
3531 /* We're either completing an argument > 3 or found an invalid
3532 completion type. Either way do nothing about it. */
3534 break;
3538 return NULL;
3541 #endif /* HAVE_LIBREADLINE */
3543 /****************************************************************************
3544 process commands from the client
3545 ****************************************************************************/
3546 static BOOL process(char *base_directory)
3548 pstring line;
3549 char *cmd;
3551 char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3552 char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3554 if ((InBuffer == NULL) || (OutBuffer == NULL))
3555 return(False);
3557 bzero(OutBuffer,smb_size);
3559 if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
3560 return(False);
3562 if (*base_directory) do_cd(base_directory);
3564 cmd = cmdstr;
3565 if (cmd[0] != '\0') while (cmd[0] != '\0')
3567 char *p;
3568 fstring tok;
3569 int i;
3571 if ((p = strchr(cmd, ';')) == 0)
3573 strncpy(line, cmd, 999);
3574 line[1000] = '\0';
3575 cmd += strlen(cmd);
3577 else
3579 if (p - cmd > 999) p = cmd + 999;
3580 strncpy(line, cmd, p - cmd);
3581 line[p - cmd] = '\0';
3582 cmd = p + 1;
3585 /* input language code to internal one */
3586 CNV_INPUT (line);
3588 /* and get the first part of the command */
3590 char *ptr = line;
3591 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3594 if ((i = process_tok(tok)) >= 0)
3595 commands[i].fn(InBuffer,OutBuffer);
3596 else if (i == -2)
3597 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
3598 else
3599 DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
3601 else while (!feof(stdin))
3603 fstring tok;
3604 int i;
3606 bzero(OutBuffer,smb_size);
3608 #ifdef HAVE_LIBREADLINE
3611 pstring prompt;
3613 /* Read input using GNU Readline */
3615 slprintf(prompt, sizeof(prompt) - 1, "smb: %s> ", CNV_LANG(cur_dir));
3616 if (!readline(prompt))
3617 break;
3619 /* Copy read line to samba buffer */
3621 pstrcpy(line, rl_line_buffer);
3622 pstrcat(line, "\n");
3624 /* Add line to history */
3626 if (strlen(line) > 0)
3627 add_history(line);
3630 #else
3632 /* display a prompt */
3633 DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
3634 dbgflush( );
3636 wait_keyboard(InBuffer);
3638 /* and get a response */
3639 if (!fgets(line,1000,stdin))
3640 break;
3642 #endif
3644 /* input language code to internal one */
3645 CNV_INPUT (line);
3647 /* special case - first char is ! */
3648 if (*line == '!')
3650 system(line + 1);
3651 continue;
3654 /* and get the first part of the command */
3656 char *ptr = line;
3657 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3660 if ((i = process_tok(tok)) >= 0)
3661 commands[i].fn(InBuffer,OutBuffer);
3662 else if (i == -2)
3663 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
3664 else
3665 DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
3668 cli_send_logout(InBuffer,OutBuffer);
3669 return(True);
3672 /****************************************************************************
3673 usage on the program
3674 ****************************************************************************/
3675 static void usage(char *pname)
3677 DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
3678 pname));
3680 DEBUG(0,("\nVersion %s\n",VERSION));
3681 DEBUG(0,("\t-p port connect to the specified port\n"));
3682 DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
3683 DEBUG(0,("\t-l log basename. Basename for log/debug files\n"));
3684 DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n"));
3685 DEBUG(0,("\t-N don't ask for a password\n"));
3686 DEBUG(0,("\t-P connect to service as a printer\n"));
3687 DEBUG(0,("\t-M host send a winpopup message to the host\n"));
3688 DEBUG(0,("\t-m max protocol set the max protocol level\n"));
3689 DEBUG(0,("\t-L host get a list of shares available on a host\n"));
3690 DEBUG(0,("\t-I dest IP use this IP to connect to\n"));
3691 DEBUG(0,("\t-R name resolve order use these name resolution services only\n"));
3692 DEBUG(0,("\t-E write messages to stderr instead of stdout\n"));
3693 DEBUG(0,("\t-U username set the network username\n"));
3694 DEBUG(0,("\t-W workgroup set the workgroup name\n"));
3695 DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
3696 DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
3697 DEBUG(0,("\t-T<c|x>IXgbNa command line tar\n"));
3698 DEBUG(0,("\t-D directory start from directory\n"));
3699 DEBUG(0,("\n"));
3702 /****************************************************************************
3703 main program
3704 ****************************************************************************/
3705 int main(int argc,char *argv[])
3707 fstring base_directory;
3708 char *pname = argv[0];
3709 int port = SMB_PORT;
3710 int opt;
3711 extern FILE *dbf;
3712 extern char *optarg;
3713 extern int optind;
3714 pstring query_host;
3715 BOOL message = False;
3716 BOOL nt_domain_logon = False;
3717 BOOL explicit_user = False;
3718 extern char tar_type;
3719 static pstring servicesf = CONFIGFILE;
3720 pstring term_code;
3721 pstring new_name_resolve_order;
3722 char *p;
3724 #ifdef KANJI
3725 pstrcpy(term_code, KANJI);
3726 #else /* KANJI */
3727 *term_code = 0;
3728 #endif /* KANJI */
3730 *query_host = 0;
3731 *base_directory = 0;
3733 *new_name_resolve_order = 0;
3735 DEBUGLEVEL = 2;
3737 setup_logging(pname,True);
3739 TimeInit();
3740 charset_initialise();
3742 if(!get_myname(myhostname,NULL))
3744 DEBUG(0,("Failed to get my hostname.\n"));
3747 if (!lp_load(servicesf,True,False,False)) {
3748 fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
3751 codepage_initialise(lp_client_code_page());
3753 interpret_coding_system(term_code);
3755 #ifdef WITH_SSL
3756 sslutil_init(0);
3757 #endif
3759 pstrcpy(workgroup,lp_workgroup());
3761 load_interfaces();
3762 pid = getpid();
3763 uid = getuid();
3764 gid = getgid();
3765 mid = pid + 100;
3766 myumask = umask(0);
3767 umask(myumask);
3769 if (getenv("USER"))
3771 pstrcpy(username,getenv("USER"));
3773 /* modification to support userid%passwd syntax in the USER var
3774 25.Aug.97, jdblair@uab.edu */
3776 if ((p=strchr(username,'%')))
3778 *p = 0;
3779 pstrcpy(password,p+1);
3780 got_pass = True;
3781 memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
3783 strupper(username);
3786 /* modification to support PASSWD environmental var
3787 25.Aug.97, jdblair@uab.edu */
3789 if (getenv("PASSWD")) {
3790 pstrcpy(password,getenv("PASSWD"));
3791 got_pass = True;
3794 if (*username == 0 && getenv("LOGNAME"))
3796 pstrcpy(username,getenv("LOGNAME"));
3797 strupper(username);
3800 if (argc < 2)
3802 usage(pname);
3803 exit(1);
3806 if (*argv[1] != '-')
3809 pstrcpy(service,argv[1]);
3810 /* Convert any '/' characters in the service name to '\' characters */
3811 string_replace( service, '/','\\');
3812 argc--;
3813 argv++;
3815 if (count_chars(service,'\\') < 3)
3817 usage(pname);
3818 printf("\n%s: Not enough '\\' characters in service\n",service);
3819 exit(1);
3823 if (count_chars(service,'\\') > 3)
3825 usage(pname);
3826 printf("\n%s: Too many '\\' characters in service\n",service);
3827 exit(1);
3831 if (argc > 1 && (*argv[1] != '-'))
3833 got_pass = True;
3834 pstrcpy(password,argv[1]);
3835 memset(argv[1],'X',strlen(argv[1]));
3836 argc--;
3837 argv++;
3841 while ((opt =
3842 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)
3843 switch (opt)
3845 case 'm':
3846 max_protocol = interpret_protocol(optarg,max_protocol);
3847 break;
3848 case 'O':
3849 pstrcpy(user_socket_options,optarg);
3850 break;
3851 case 'R':
3852 pstrcpy(new_name_resolve_order, optarg);
3853 break;
3854 case 'S':
3855 pstrcpy(desthost,optarg);
3856 strupper(desthost);
3857 nt_domain_logon = True;
3858 break;
3859 case 'M':
3860 name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
3861 pstrcpy(desthost,optarg);
3862 strupper(desthost);
3863 message = True;
3864 break;
3865 case 'B':
3866 iface_set_default(NULL,optarg,NULL);
3867 break;
3868 case 'D':
3869 pstrcpy(base_directory,optarg);
3870 break;
3871 case 'T':
3872 if (!tar_parseargs(argc, argv, optarg, optind)) {
3873 usage(pname);
3874 exit(1);
3876 break;
3877 case 'i':
3878 pstrcpy(scope,optarg);
3879 break;
3880 case 'L':
3881 got_pass = True;
3882 pstrcpy(query_host,optarg);
3883 if(!explicit_user)
3884 *username = '\0';
3885 break;
3886 case 'U':
3888 char *lp;
3889 explicit_user = True;
3890 pstrcpy(username,optarg);
3891 if ((lp=strchr(username,'%')))
3893 *lp = 0;
3894 pstrcpy(password,lp+1);
3895 got_pass = True;
3896 memset(strchr(optarg,'%')+1,'X',strlen(password));
3900 break;
3901 case 'W':
3902 pstrcpy(workgroup,optarg);
3903 break;
3904 case 'E':
3905 dbf = stderr;
3906 break;
3907 case 'I':
3909 dest_ip = *interpret_addr2(optarg);
3910 if (zero_ip(dest_ip)) exit(1);
3911 have_ip = True;
3913 break;
3914 case 'n':
3915 pstrcpy(global_myname,optarg);
3916 break;
3917 case 'N':
3918 got_pass = True;
3919 no_pass = True;
3920 break;
3921 case 'P':
3922 connect_as_printer = True;
3923 break;
3924 case 'd':
3925 if (*optarg == 'A')
3926 DEBUGLEVEL = 10000;
3927 else
3928 DEBUGLEVEL = atoi(optarg);
3929 break;
3930 case 'l':
3931 slprintf(debugf,sizeof(debugf)-1, "%s.client",optarg);
3932 break;
3933 case 'p':
3934 port = atoi(optarg);
3935 break;
3936 case 'c':
3937 cmdstr = optarg;
3938 got_pass = True;
3939 break;
3940 case 'h':
3941 usage(pname);
3942 exit(0);
3943 break;
3944 case 's':
3945 pstrcpy(servicesf, optarg);
3946 break;
3947 case 't':
3948 pstrcpy(term_code, optarg);
3949 break;
3950 default:
3951 usage(pname);
3952 exit(1);
3955 get_myname((*global_myname)?NULL:global_myname,NULL);
3956 strupper(global_myname);
3958 if(*new_name_resolve_order)
3959 lp_set_name_resolve_order(new_name_resolve_order);
3961 if (!tar_type && !*query_host && !*service && !message)
3963 usage(pname);
3964 exit(1);
3967 #ifdef HAVE_LIBREADLINE
3969 /* Initialise GNU Readline */
3971 rl_readline_name = "smbclient";
3972 rl_attempted_completion_function = completion_fn;
3973 rl_completion_entry_function = (Function *)complete_cmd_null;
3975 /* Initialise history list */
3977 using_history();
3979 #endif /* HAVE_LIBREADLINE */
3981 DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
3983 if (tar_type) {
3984 recurse=True;
3986 if (cli_open_sockets(port)) {
3987 char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3988 char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3989 int ret;
3991 if ((InBuffer == NULL) || (OutBuffer == NULL))
3992 return(1);
3994 bzero(OutBuffer,smb_size);
3995 if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
3996 return(False);
3998 if (*base_directory) do_cd(base_directory);
4000 ret=process_tar(InBuffer, OutBuffer);
4002 cli_send_logout(InBuffer, OutBuffer);
4003 close_sockets();
4004 return(ret);
4005 } else
4006 return(1);
4009 if (*query_host && !nt_domain_logon)
4011 int ret = 0;
4012 slprintf(service,sizeof(service)-1,
4013 "\\\\%s\\IPC$",query_host);
4014 strupper(service);
4015 connect_as_ipc = True;
4016 if (cli_open_sockets(port))
4018 #if 0
4019 *username = 0;
4020 #endif
4021 if (!cli_send_login(NULL,NULL,True,True,NULL))
4022 return(1);
4024 server_info();
4025 if (!browse_host(True)) {
4026 sleep(1);
4027 browse_host(True);
4029 if (!list_servers(workgroup)) {
4030 sleep(1);
4031 list_servers(workgroup);
4034 cli_send_logout(NULL,NULL);
4035 close_sockets();
4038 return(ret);
4041 if (message)
4043 int ret = 0;
4044 if (cli_open_sockets(port))
4046 pstring inbuf,outbuf;
4047 bzero(outbuf,smb_size);
4048 if (!cli_send_session_request(inbuf,outbuf))
4049 return(1);
4051 send_message(inbuf,outbuf);
4053 close_sockets();
4056 return(ret);
4059 if (cli_open_sockets(port))
4061 if (!process(base_directory))
4063 close_sockets();
4064 return(1);
4066 close_sockets();
4068 else
4069 return(1);
4071 return(0);