1 /***************************************************************************/
2 /*                                                                         */
3 /* Fast Webpage Exchanger - an FTP client for updating webpages            */
4 /* Copyright (C) 1999-2000 Yuuki NINOMIYA <gm@debian.or.jp>                */
5 /*                                                                         */
6 /* This program is free software; you can redistribute it and/or modify    */
7 /* it under the terms of the GNU General Public License as published by    */
8 /* the Free Software Foundation; either version 2, or (at your option)     */
9 /* any later version.                                                      */
10 /*                                                                         */
11 /* This program is distributed in the hope that it will be useful,         */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of          */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           */
14 /* GNU General Public License for more details.                            */
15 /*                                                                         */
16 /* You should have received a copy of the GNU General Public License       */
17 /* along with this program; if not, write to the                           */
18 /* Free Software Foundation, Inc., 59 Temple Place - Suite 330,            */
19 /* Boston, MA 02111-1307, USA.                                             */
20 /*                                                                         */
21 /***************************************************************************/
22 
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <dirent.h>
30 #include <string.h>
31 #include <time.h>
32 #include <ctype.h>
33 #include <sys/stat.h>
34 #include "intl.h"
35 #include "strlib.h"
36 #include "variable.h"
37 #include "proto.h"
38 
39 #ifndef PATH_MAX
40 #  define PATH_MAX 512
41 #endif /* PATH_MAX */
42 
43 
44 /* --------------------------------------------------
45  NAME       get_local_file_data
46  FUNCTION   get the data of local files
47  INPUT      local_data ... pointer to stored date
48  OUTPUT     the maximum number of local files
49 -------------------------------------------------- */
get_local_file_data(FileData ** local_data)50 int get_local_file_data(FileData **local_data)
51 {
52 	DIR *dir;
53 	struct dirent *ent;
54 	struct stat file_stat;
55 	struct tm *ftime;
56 	char time_temp[10];
57 	char date_temp[10];
58 	int isdir;
59 	int file_num=0;
60 	int i;
61 
62 	dir=opendir(".");
63 	while((ent=readdir(dir))!=NULL){
64 		if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0){
65 			continue;
66 		}
67 		lstat(ent->d_name,&file_stat);
68 
69 		/* follow symlinks */
70 		if (follow_symlinks[host_number] && (file_stat.st_mode & S_IFLNK)==S_IFLNK){
71 			char realfname[PATH_MAX];
72 
73 			DebugPrint((stderr,"Local symlink is detected: %s\n",ent->d_name));
74 			if(realpath(ent->d_name,realfname)==NULL){
75 				char *temp;
76 
77 				fprintf(stderr,_("Cannot expand symbolic link `%s'. Ignore this file.\n"),ent->d_name);
78 				temp=str_dup_printf(_("Expanding symbolic link failed: %s"),ent->d_name);
79 				log_write(temp);
80 				free(temp);
81 				continue;
82 			}
83 			stat(realfname,&file_stat);
84 			DebugPrint((stderr,"Realfname is %s\n",realfname));
85 		}
86 		isdir = ((file_stat.st_mode & S_IFDIR) == S_IFDIR);
87 		ftime=gmtime(&file_stat.st_mtime);
88 
89 		if(isdir){
90 			if(is_ignore_dir(ent->d_name,LOCAL)){
91 				DebugPrint((stderr,"Ignore local dir: %s\n",ent->d_name));
92 				continue;
93 			}
94 		}else{
95 			if(is_ignore_file(ent->d_name,LOCAL)){
96 				DebugPrint((stderr,"Ignore local file: %s\n",ent->d_name));
97 				continue;
98 			}
99 		}
100 
101 		sprintf(date_temp,"%04d%02d%02d",1900+ftime->tm_year,ftime->tm_mon+1,ftime->tm_mday);
102 		sprintf(time_temp,"%02d%02d%02d",ftime->tm_hour,ftime->tm_min,ftime->tm_sec);
103 
104 		*local_data=str_realloc(*local_data,sizeof(**local_data)*(file_num+1));
105 		(*local_data)[file_num].date=atol(date_temp);
106 		(*local_data)[file_num].time=atol(time_temp);
107 		(*local_data)[file_num].isdir=isdir;
108 		(*local_data)[file_num].name=str_dup(ent->d_name);
109 
110 		DebugPrint((stderr,"Local: [%08ld] [%06ld] [%08o] [%d] [%s]\n",(*local_data)[file_num].date,(*local_data)[file_num].time,file_stat.st_mode,(*local_data)[file_num].isdir,(*local_data)[file_num].name));
111 
112 		if(conv_to_lower[host_number]){
113 			for(i=0;i<file_num;i++){
114 				if(strcasecmp((*local_data)[file_num].name,(*local_data)[i].name)==0){
115 					char *temp;
116 
117 					fprintf(stderr,_("ConvToLower causes a conflict between `%s' and `%s'. Proceed anyway.\n"),(*local_data)[i].name,(*local_data)[file_num].name);
118 
119 					temp=str_dup_printf(_("Confliction by ConvToLower: %s"),(*local_data)[i].name);
120 					log_write(temp);
121 					free(temp);
122 				}
123 			}
124 		}
125 
126 		file_num++;
127 	}
128 	closedir(dir);
129 	return(file_num);
130 }
131 
132 
133 /* --------------------------------------------------
134  NAME       get_remote_file_data
135  FUNCTION   get the data of remote files
136  INPUT      remote_data ... pointer to stored date
137  OUTPUT     the maximum number of remote files
138 -------------------------------------------------- */
get_remote_file_data(FileData ** remote_data)139 int get_remote_file_data(FileData **remote_data)
140 {
141 	char list_temp[32];
142 	int  fd;
143 	FILE *fp;
144 	char *fgets_temp;
145 	char *file_name;
146 	long date,mtime;
147 	char mod_temp[20];
148 	char dir_flag;
149 	char *temp;
150 	int *add_cache_num=NULL;
151 	int add_cache_files=0;
152 	int file_num=0;
153 	int i;
154 
155 	if(strcmp(current_dir[REMOTE],dest_dir[host_number])!=0){
156 		change_dir_actually(REMOTE);
157 	}
158 	strcpy(list_temp, "/tmp/weexXXXXXX");
159 	fd=mkstemp(list_temp);
160 	if(fd==-1){
161 		fprintf(stderr,_("Cannot create a unique file name.\n"));
162 		ftp_disconnect();
163 		exit(1);
164 	}
165 
166 	if((show_hidden_file[host_number] && FtpDir(list_temp,"-a",ftp_buf)==0) ||
167 	  (!show_hidden_file[host_number] && FtpDir(list_temp,NULL,ftp_buf)==0)){
168 		fprintf(stderr,_("Cannot get remote directory list.\n"));
169 		log_write(_("Getting remote directory list failed"));
170 		ftp_disconnect();
171 		exit(1);
172 	}
173 	fp=fdopen(fd,"r");
174 	if(fp==NULL){
175 		fprintf(stderr,_("Cannot open `%s'.\n"),list_temp);
176 		ftp_disconnect();
177 		exit(1);
178 	}
179 
180 	while((fgets_temp=str_fgets(fp))!=NULL){
181 		if(strncmp(fgets_temp,"total",5)==0){
182 			free(fgets_temp);
183 			continue;
184 		}
185 
186 		DebugPrint((stderr,"Remote: %s\n",fgets_temp));
187 
188 		dir_flag=parse_file_and_filetype(fgets_temp,&file_name);
189 
190 		free(fgets_temp);
191 
192 		/*
193 		  Test to which this entry is directory or file.
194 		  This way is very dirty and slow.
195 		*/
196 		if(dir_flag=='l'){
197 			DebugPrint((stderr,"Remote symlink is detected: %s\n",file_name));
198 			dir_flag=FtpChdir(file_name,ftp_buf) ? 'd' : '-';
199 			FtpChdir(current_dir[REMOTE], ftp_buf);
200 			DebugPrint((stderr,"Symlink type is '%c'\n",dir_flag));
201 		}
202 
203 		if(strcmp(file_name,".")==0 ||
204 		   strcmp(file_name,"..")==0 ||
205 		   (dir_flag=='d' && is_ignore_dir(file_name,REMOTE)) ||
206 		   (dir_flag!='d' && is_ignore_file(file_name,REMOTE)) ){
207 			DebugPrint((stderr,"[%c] Ignore remote `%s'\n",dir_flag,file_name));
208 			free(file_name);
209 			continue;
210 		}
211 
212 		date=mtime=0;
213 		if(dir_flag!='d'){
214 			if(conv_to_lower[host_number]){
215 				temp=str_tolower(file_name);
216 				DebugPrint((stderr,"conv_to_lower from `%s' to `%s'\n",file_name,temp));
217 				free(file_name);
218 				file_name=temp;
219 			}
220 			if(get_cache(file_name,&date,&mtime)==-1){
221 				DebugPrint((stderr,"No cache: %s\n",file_name));
222 				if(FtpModDate(file_name,mod_temp,20,ftp_buf)==1){
223 					date=n_atol(mod_temp,8);
224 					mtime=n_atol(mod_temp+8,6);
225 					add_cache_num=str_realloc(add_cache_num,sizeof(*add_cache_num)*(add_cache_files+1));
226 					add_cache_num[add_cache_files++]=file_num;
227 				} else {
228 					/* Ignore the MDTM failure and store the current date */
229 					/* it would be better to use the LIST date ... */
230 					time_t curtime = time(NULL);
231 					struct tm *tmcur = gmtime(&curtime);
232 
233 					date=(1900+tmcur->tm_year)*10000 + (tmcur->tm_mon+1)*100 + (tmcur->tm_mday);
234 					mtime=tmcur->tm_hour*10000 + tmcur->tm_min*100 + tmcur->tm_sec;
235 					add_cache_num=str_realloc(add_cache_num,sizeof(*add_cache_num)*(add_cache_files+1));
236 					add_cache_num[add_cache_files++]=file_num;
237 				}
238 			}
239 
240 		}
241 
242 		*remote_data=str_realloc(*remote_data,sizeof(**remote_data)*(file_num+1));
243 		(*remote_data)[file_num].date=date;
244 		(*remote_data)[file_num].time=mtime;
245 		(*remote_data)[file_num].isdir=(dir_flag=='d');
246 		(*remote_data)[file_num].name=file_name;
247 
248 		DebugPrint((stderr,"Remote: [%08ld] [%06ld] [%c] [%d] [%s]\n",(*remote_data)[file_num].date,(*remote_data)[file_num].time,dir_flag,(*remote_data)[file_num].isdir,(*remote_data)[file_num].name));
249 
250 		file_num++;
251 	}
252 
253 	for(i=0;i<add_cache_files;i++){
254 		update_cache((*remote_data)[add_cache_num[i]].name,(*remote_data)[add_cache_num[i]].date,(*remote_data)[add_cache_num[i]].time);
255 		DebugPrint((stderr,"Update cache `%s' : %ld %ld\n",(*remote_data)[add_cache_num[i]].name,(*remote_data)[add_cache_num[i]].date,(*remote_data)[add_cache_num[i]].time));
256 	}
257 
258 	fclose(fp);
259 	if(remove(list_temp)==-1){
260 		fprintf(stderr,_("Cannot remove `%s'.\n"),list_temp);
261 		ftp_disconnect();
262 		exit(1);
263 	}
264 	free(add_cache_num);
265 	/* free(list_temp); */
266 	return(file_num);
267 }
268 
269 
270 /* --------------------------------------------------
271  NAME       free_file_data
272  FUNCTION   release memory stored file data
273  INPUT      file_data ... file data
274             max_file_data ... the maximum number of file data
275  OUTPUT     none
276 -------------------------------------------------- */
free_file_data(FileData * file_data,int max_file_data)277 void free_file_data(FileData *file_data,int max_file_data)
278 {
279 	int i;
280 
281 	for(i=0;i<max_file_data;i++){
282 		free(file_data[i].name);
283 	}
284 	free(file_data);
285 }
286 
287 
288 /* --------------------------------------------------
289  NAME       parse_file_and_filetype
290  FUNCTION   parse file and filetype (whether dir) from file list
291  INPUT      str .... file list (a single line)
292             file ... pointer to stored file name
293  OUTPUT     dir_flag ... directory is 'd'
294                          symlink is 'l'
295                          others are '-'
296                          return -1 if error
297 -------------------------------------------------- */
parse_file_and_filetype(char * str,char ** file)298 int parse_file_and_filetype(char *str,char **file)
299 {
300 	char dir_flag;
301 	int i;
302 	char *ptr;
303 	char *lnktmp;
304 
305 	ptr=strtok(str," ");
306 	if(ptr==NULL){
307 		fprintf(stderr,_("Cannot get the remote directory list correctly.\n"));
308 		ftp_disconnect();
309 		exit(1);
310 	}
311 	if(isdigit(*ptr) && isdigit(*(ptr+1)) && *(ptr+2)=='-'){	/* Remote system type is Windows_NT */
312 		for(i=0;i<2;i++){
313 			if((ptr=strtok(NULL," "))==NULL){
314 				fprintf(stderr,_("Cannot get the remote directory list correctly.\n"));
315 				ftp_disconnect();
316 				exit(1);
317 			}
318 		}
319 		dir_flag=(strcmp(ptr,"<DIR>")==0) ? 'd' : '-';
320 	}else{	/* Remote system type is UNIX or MACOS */
321 		dir_flag=str[0];
322 
323 		for(i=0;i<7;i++){
324 			if((ptr=strtok(NULL," "))==NULL){
325 				fprintf(stderr,_("Cannot get the remote directory list correctly.\n"));
326 				ftp_disconnect();
327 				exit(1);
328 			}
329 			if((i==0 && strcmp(ptr,"folder")==0) ||
330 			   (i==1 && strcmp(ptr,"0000/0000")==0) ||
331 			   (i==3 && isupper(*ptr) && islower(*(ptr+1)) && islower(*(ptr+2)) && *(ptr+3)=='\0')){
332 				i++;
333 			}
334 		}
335 	}
336 	ptr=ptr+strlen(ptr)+1;
337 	if((lnktmp=strstr(ptr," -> "))!=NULL){	/* This file is a symbolic link. */
338 		*lnktmp='\0';
339 	}
340 
341 	/* Strip leading spaces from the filename which can occur
342 	   with an FTP server based on Windows NT */
343 	while (*ptr == ' '){
344 		ptr++;
345 	}
346 
347 	*file=str_dup(ptr);
348 
349 	return(dir_flag);
350 }
351 
352 
353 /* --------------------------------------------------
354  NAME       is_ignore_dir
355  FUNCTION   whether ???IgnoreDir or not
356  INPUT      dir_name ... name of the directory
357             side ....... LOCAL or REMOTE
358  OUTPUT     return 1 if match ???IgnoreDir otherwise return 0
359 -------------------------------------------------- */
is_ignore_dir(char * dir_name,LocalOrRemote side)360 int is_ignore_dir(char *dir_name,LocalOrRemote side)
361 {
362 	cfgList *l;
363 	char *temp;
364 
365 	if((side==LOCAL && ignore_local_dir[host_number]==NULL) || (side==REMOTE && ignore_remote_dir[host_number]==NULL)){
366 		return(0);
367 	}
368 	temp=str_concat(current_dir[side],dir_name,"/",NULL);
369 	if(side==LOCAL){
370 		for(l=ignore_local_dir[host_number];l!=NULL;l=l->next){
371 			if(cmp_file_with_wildcard(temp,l->str)==0){
372 				free(temp);
373 				return(1);
374 			}
375 		}
376 	}else if(side==REMOTE){
377 		for(l=ignore_remote_dir[host_number];l!=NULL;l=l->next){
378 			if(cmp_file_with_wildcard(temp,l->str)==0){
379 				free(temp);
380 				return(1);
381 			}
382 		}
383 	}
384 	free(temp);
385 	return(0);
386 }
387 
388 
389 /* --------------------------------------------------
390  NAME       is_ignore_file
391  FUNCTION   whether ???IgnoreFile or not
392  INPUT      file_name ... file name
393             side ........ LOCAL or REMOTE
394  OUTPUT     return 1 if match ???IgnoreFile otherwise return 0
395 -------------------------------------------------- */
is_ignore_file(char * file_name,LocalOrRemote side)396 int is_ignore_file(char *file_name,LocalOrRemote side)
397 {
398 	cfgList *l;
399 	char *temp;
400 
401 	if((side==LOCAL && ignore_local_file[host_number]==NULL) || (side==REMOTE && ignore_remote_file[host_number]==NULL)){
402 		return(0);
403 	}
404 	temp=str_concat(current_dir[side],file_name,NULL);
405 	if(side==LOCAL){
406 		for(l=ignore_local_file[host_number];l!=NULL;l=l->next){
407 			if(strchr(l->str,'/')==NULL){
408 				if(cmp_file_with_wildcard(file_name,l->str)==0){
409 					free(temp);
410 					return(1);
411 				}
412 			}else{
413 				if(cmp_file_with_wildcard(temp,l->str)==0){
414 					free(temp);
415 					return(1);
416 				}
417 			}
418 		}
419 	}else if(side==REMOTE){
420 		for(l=ignore_remote_file[host_number];l!=NULL;l=l->next){
421 			if(strchr(l->str,'/')==NULL){
422 				if(cmp_file_with_wildcard(file_name,l->str)==0){
423 					free(temp);
424 					return(1);
425 				}
426 			}else{
427 				if(cmp_file_with_wildcard(temp,l->str)==0){
428 					free(temp);
429 					return(1);
430 				}
431 			}
432 		}
433 	}
434 	free(temp);
435 	return(0);
436 }
437 
438 
439 /* --------------------------------------------------
440  NAME       is_ascii_file
441  FUNCTION   whether AsciiFile or not
442  INPUT      file_name ... file name
443  OUTPUT     return 1 if match AsciiFile otherwise return 0
444 -------------------------------------------------- */
is_ascii_file(char * file_name)445 int is_ascii_file(char *file_name)
446 {
447 	cfgList *l;
448 	char *temp;
449 
450 	if(ascii_file[host_number]==NULL){
451 		return(0);
452 	}
453 	temp=str_concat(current_dir[LOCAL],file_name,NULL);
454 	for(l=ascii_file[host_number];l!=NULL;l=l->next){
455 		if(strchr(l->str,'/')==NULL){
456 			if(cmp_file_with_wildcard(file_name,l->str)==0){
457 				free(temp);
458 				return(1);
459 			}
460 		}else{
461 			if(cmp_file_with_wildcard(temp,l->str)==0){
462 				free(temp);
463 				return(1);
464 			}
465 		}
466 	}
467 	free(temp);
468 	return(0);
469 }
470 
471 
472 /* --------------------------------------------------
473  NAME       is_change_permission_dir
474  FUNCTION   whether ChangePermissionDir or not
475  OUTPUT     return 1 if match ChangePermissionDir otherwise return 0
476 -------------------------------------------------- */
is_change_permission_dir(void)477 int is_change_permission_dir(void)
478 {
479 	cfgList *l;
480 
481 	if(change_permission_dir[host_number]==NULL){
482 		return(0);
483 	}
484 	for(l=change_permission_dir[host_number];l!=NULL;l=l->next){
485 		if(cmp_file_with_wildcard(current_dir[LOCAL],l->str)==0){
486 			return(1);
487 		}
488 	}
489 	return(0);
490 }
491 
492 
493 /* --------------------------------------------------
494  NAME       is_preserve_permission_dir
495  FUNCTION   whether PreservePermissionDir or not
496  OUTPUT     return 1 if match PreservePermissionDir otherwise return 0
497 -------------------------------------------------- */
is_preserve_permission_dir(void)498 int is_preserve_permission_dir(void)
499 {
500 	cfgList *l;
501 
502 	if(preserve_permission_dir[host_number]==NULL){
503 		return(0);
504 	}
505 	for(l=preserve_permission_dir[host_number];l!=NULL;l=l->next){
506 		if(cmp_file_with_wildcard(current_dir[LOCAL],l->str)==0){
507 			return(1);
508 		}
509 	}
510 	return(0);
511 }
512 
513 
514 /* --------------------------------------------------
515  NAME       is_keep_remote_dir
516  FUNCTION   whether KeepRemoteDir or not
517  OUTPUT     return 1 if match KeepRemoteDir otherwise return 0
518 -------------------------------------------------- */
is_keep_remote_dir(void)519 int is_keep_remote_dir(void)
520 {
521 	cfgList *l;
522 
523 	if(keep_remote_dir[host_number]==NULL){
524 		return(0);
525 	}
526 	for(l=keep_remote_dir[host_number];l!=NULL;l=l->next){
527 		if(cmp_file_with_wildcard(current_dir[REMOTE],l->str)==0){
528 			return(1);
529 		}
530 	}
531 	return(0);
532 }
533