text: /* io_getfiles.c
   *
   * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
   * All rights reserved.
   *
   */
  
  #include "syshdrs.h"
  #ifdef PRAGMA_HDRSTOP
  #	pragma hdrstop
  #endif
  
  #ifndef NO_SIGNALS
  #	define NO_SIGNALS 1
  #endif
  
  int
  FTPGetFiles3(
  	const FTPCIPtr cip,
  	const char *pattern1,
  	const char *const dstdir1,
  	const int recurse,
  	int doGlob,
  	const int xtype,
  	const int resumeflag,
  	int appendflag,
  	const int deleteflag,
  	const int tarflag,
  	const FTPConfirmResumeDownloadProc resumeProc,
  	int UNUSED(reserved))
  {
  	FTPLineList globList;
  	FTPLinePtr itemPtr;
  	FTPFileInfoList files;
  	FTPFileInfoPtr filePtr;
  	int batchResult;
  	int result;
  	char *ldir;
  	char *cp;
  	const char *dstdir;
  	const char *pattern;
  	char *pattern2, *dstdir2;
  	char c;
  	int recurse1;
  	int errRc;
  
  	LIBNCFTP_USE_VAR(reserved);
  	if (cip == NULL)
  		return (kErrBadParameter);
  	if (strcmp(cip->magic, kLibraryMagic))
  		return (kErrBadMagic);
  	if (pattern1 == NULL)
  		return (kErrBadParameter);
  
  	dstdir2 = NULL;
  	pattern2 = NULL;
  
  	if (dstdir1 == NULL) {
  		dstdir = NULL;
  	} else {
  		dstdir2 = StrDup(dstdir1);
  		if (dstdir2 == NULL) {
  			errRc = kErrMallocFailed;
  			goto return_err;
  		}
  		StrRemoveTrailingLocalPathDelim(dstdir2);
  		dstdir = dstdir2;
  	}
  
  	pattern2 = StrDup(pattern1);
  	if (pattern2 == NULL) {
  		errRc = kErrMallocFailed;
  		goto return_err;
  	}
  	StrRemoveTrailingSlashes(pattern2);
  	pattern = pattern2;
  
  	if (pattern[0] == '\0') {
  		if (recurse == kRecursiveNo) {
  			errRc = kErrBadParameter;
  			goto return_err;
  		}
  		pattern = ".";
  		doGlob = kGlobNo;
  	} else if (strcmp(pattern, ".") == 0) {
  		if (recurse == kRecursiveNo) {
  			errRc = kErrBadParameter;
  			goto return_err;
  		}
  		doGlob = kGlobNo;
  	} else if ((strcmp(pattern, "/") == 0) && ((dstdir == NULL) || (strcmp(dstdir, ".") == 0) || (dstdir[0] == '\0'))) {
  		/* Ick... but works around a problem we need to fix */
  		free(pattern2);
  		pattern2 = StrDup("/.");
  		pattern = pattern2;
  		/*
  		errRc = kErrKnownBug;
  		goto return_err;
  		*/
  	}
  	if (recurse == kRecursiveYes)
  		appendflag = kAppendNo;
  
  	batchResult = FTPRemoteGlob(cip, &globList, pattern, doGlob);
  	if (batchResult != kNoErr) {
  		errRc = batchResult;
  		goto return_err;
  	}
  
  	cip->cancelXfer = 0;	/* should already be zero */
  
  	for (itemPtr = globList.first; itemPtr != NULL; itemPtr = itemPtr->next) {
  		if ((recurse == kRecursiveYes) && (FTPIsDir(cip, itemPtr->line) > 0)) {
  #ifdef TAR
  			if ((tarflag == kTarYes) && (xtype == kTypeBinary) && (appendflag == kAppendNo) && (deleteflag == kDeleteNo) && (FTPGetOneTarF(cip, itemPtr->line, dstdir) == kNoErr)) {
  				/* Great! */
  				continue;
  			}
  #endif	/* TAR */
  			(void) FTPRemoteRecursiveFileList2(cip, itemPtr->line, &files);
  			(void) ComputeLNames(&files, itemPtr->line, dstdir, 1);
  			recurse1 = recurse;
  		} else {
  			recurse1 = kRecursiveNo;
  			(void) LineToFileInfoList(itemPtr, &files);
  			(void) ComputeRNames(&files, ".", 0, 1);
  			(void) ComputeLNames(&files, NULL, dstdir, 0);
  		}
  		if (cip->cancelXfer > 0) {
  			DisposeFileInfoListContents(&files);
  			break;
  		}
  
  #if 0
  		for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
  			PrintF(cip, "  R=%s, L=%s, 2=%s, size=%lld, mdtm=%u, type=%c\n",
  				filePtr->rname,
  				filePtr->lname,
  				filePtr->rlinkto ? filePtr->rlinkto : "",
  				(longest_int) filePtr->size,
  				(unsigned int) filePtr->mdtm,
  				filePtr->type
  			);
  		}
  #endif
  
  		result = kNoErr;
  		for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
  			result = kNoErr;
  			if (cip->connected == 0) {
  				if (batchResult == kNoErr)
  					batchResult = kErrRemoteHostClosedConnection;
  				break;
  			}
  			if (filePtr->type == 'd') {
  				(void) MkDirs(filePtr->lname, 00777);
  			} else if (filePtr->type == 'l') {
  				/* skip it -- we do that next pass. */
  			} else if (recurse1 != kRecursiveYes) {
  				result = FTPGetOneF(cip, filePtr->rname, filePtr->lname, xtype, -1, filePtr->size, filePtr->mdtm, resumeflag, appendflag, deleteflag, resumeProc);
  				if (files.nFileInfos == 1) {
  					if (result != kNoErr)
  						batchResult = result;
  				} else {
  					if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote))
  						batchResult = result;
  				}
  				if (result == kErrUserCanceled)
  					cip->cancelXfer = 1;
  				if (cip->cancelXfer > 0)
  					break;
  			} else {
  				ldir = filePtr->lname;
  				cp = StrRFindLocalPathDelim(ldir);
  				if (cp != NULL) {
  					while (cp >= ldir) {
  						if (! IsLocalPathDelim(*cp)) {
  							++cp;
  							break;
  						}
  						--cp;
  					}
  					if (cp > ldir) {
  						c = *cp;
  						*cp = '\0';
  						if (MkDirs(ldir, 00777) < 0) {
  							FTPLogError(cip, kDoPerror, "Could not create local directory \"%s\"\n", ldir);
  							batchResult = kErrGeneric;
  							*cp = c;
  							continue;
  						}
  						*cp = c;
  					}
  				}
  				if (xtype == kTypeAscii) {
  					/* Make sure we got the SIZE from
  					 * a SIZE command, and not a
  					 * directory listing, which may
  					 * not have taken into the account
  					 * the required end-of-line format
  					 * for text files sent over FTP.
  					 */
  					if ((resumeflag == kResumeYes) || (resumeProc != kNoFTPConfirmResumeDownloadProc)) {
  						FTPCheckForRestartModeAvailability(cip); 
  					}
  					result = FTPSetTransferType(cip, xtype);
  					if (result < 0)
  						return (result);
  					(void) FTPFileSize(cip, filePtr->rname, &filePtr->size, xtype);
  				}
  				result = FTPGetOneF(cip, filePtr->rname, filePtr->lname, xtype, -1, filePtr->size, filePtr->mdtm, resumeflag, appendflag, deleteflag, resumeProc);
  
  				if (files.nFileInfos == 1) {
  					if (result != kNoErr)
  						batchResult = result;
  				} else {
  					if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote))
  						batchResult = result;
  				}
  				if (result == kErrUserCanceled)
  					cip->cancelXfer = 1;
  				if (cip->cancelXfer > 0)
  					break;
  			}
  		}
  		if (cip->cancelXfer > 0) {
  			DisposeFileInfoListContents(&files);
  			break;
  		}
  
  #ifdef HAVE_SYMLINK
  		for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
  			if (filePtr->type == 'l') {
  				(void) unlink(filePtr->lname);
  				if (symlink(filePtr->rlinkto, filePtr->lname) < 0) {
  					FTPLogError(cip, kDoPerror, "Could not symlink %s to %s\n", filePtr->rlinkto, filePtr->lname);
  					/* Note: not worth setting batchResult */
  				}
  			}
  		}
  #endif	/* HAVE_SYMLINK */
  
  		/* Try to clean up empty directories */
  		if ((result == kNoErr) && (recurse1 == kRecursiveYes) && (deleteflag == kDeleteYes)) {
  			(void) FTPRmdirRecursive2(cip, itemPtr->line, /* remove only empty directories: */ 1);
  #ifdef TAR
  			/* We could do rm -rf here if Tar was successful, but above
  			 * we never use tar mode when delete mode is on.
  			 */
  #endif	/* TAR */
  		}
  
  
  		DisposeFileInfoListContents(&files);
  	}
  
  	DisposeLineListContents(&globList);
  	if (batchResult < 0)
  		cip->errNo = batchResult;
  	errRc = batchResult;
  
  return_err:
  	if (dstdir2 != NULL)
  		free(dstdir2);
  	if (pattern2 != NULL)
  		free(pattern2);
  	return (errRc);
  }	/* FTPGetFiles3 */
  
  
  
  
  int
  FTPGetFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
  {
  	return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeBinary, kResumeNo, kAppendNo, kDeleteNo, kTarYes, (FTPConfirmResumeDownloadProc) 0, 0));
  }	/* FTPGetFiles */
  
  
  
  
  int
  FTPGetFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int resumeflag, const int appendflag)
  {
  	return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, resumeflag, appendflag, kDeleteNo, kTarYes, (FTPConfirmResumeDownloadProc) 0, 0));
  }	/* FTPGetFiles2 */
  
  
  
  
  int
  FTPGetFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
  {
  	return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeAscii, kResumeNo, kAppendNo, kDeleteNo, kTarNo, (FTPConfirmResumeDownloadProc) 0, 0));
  }	/* FTPGetFilesAscii */
  