text: ﻿#include <all_far.h>
  #pragma hdrstop
  
  #include "Int.h"
  
  BOOL FTP::SetDirectoryStepped(LPCSTR Dir, BOOL update)
  {
  	PROC(("SetDirectoryStepped","%s",Dir))
  
  	if(ShowHosts || !hConnect)
  	{
  		SetLastError(ERROR_INVALID_PARAMETER);
  		return FALSE;
  	}
  
  	//Empty dir
  	if(!Dir[0])
  		return TRUE;
  
  	//Try direct change
  	if(FtpSetCurrentDirectory(hConnect,Dir))
  	{
  		if(update) Invalidate();
  
  		if(ShowHosts || !hConnect)
  		{
  			SetLastError(ERROR_CANCELLED);
  			return FALSE;
  		}
  
  		return TRUE;
  	}
  
  	//dir name contains only one name
  	if(strchr(Dir, '/') == NULL)
  	{
  		//Cancel
  		return FALSE;
  	}
  
  	//Cancel changes in automatic mode
  	if(IS_SILENT(FP_LastOpMode))
  		return FALSE;
  
  	//Ask user
  	{
  		static LPCSTR MsgItems[] =
  		{
  			FMSG(MAttention),
  			FMSG(MAskDir1),
  			NULL,
  			FMSG(MAskDir3),
  			FMSG(MYes), FMSG(MNo)
  		};
  		MsgItems[2] = Dir;
  
  		if(FMessage(FMSG_WARNING|FMSG_LEFTALIGN, NULL, MsgItems, ARRAYSIZE(MsgItems),2) != 0)
  		{
  			SetLastError(ERROR_CANCELLED);
  			return FALSE;
  		}
  	}
  	//Try change to directory one-by-one
  	char     str[MAX_PATH];
  	LPCSTR m = NULL;
  	int      num;
  
  	do
  	{
  		if(*Dir == '/')
  		{
  			Dir++;
  
  			if(*Dir == 0) break;
  
  			str[0] = '/';
  			str[1] = 0;
  		}
  		else
  		{
  			m = strchr(Dir, '/');
  
  			if(m)
  			{
  				num = Min((int)ARRAYSIZE(str)-1, (int)(m-Dir));
  				strncpy(str, Dir, num);
  				str[num] = 0;
  				Dir = m+1;
  			}
  			else
  				StrCpy(str, Dir, ARRAYSIZE(str));
  		}
  
  		Log(("Dir: [%s]",str));
  
  		if(!FtpSetCurrentDirectory(hConnect,str))
  			return FALSE;
  
  		if(update) Invalidate();
  
  		if(ShowHosts || !hConnect)
  		{
  			SetLastError(ERROR_CANCELLED);
  			return FALSE;
  		}
  	}
  	while(m);
  
  	return TRUE;
  }
  
  int FTP::SetDirectoryFAR(LPCSTR _Dir,int OpMode)
  {
  	FP_Screen _scr;
  	return SetDirectory(_Dir, OpMode);
  }
  
  BOOL FTP::CheckDotsBack(const String& OldDir,const String& CmdDir)
  {
  	String str;
  
  	if(!Opt.CloseDots || !CmdDir.Cmp(".."))
  		return FALSE;
  
  	GetCurPath(str);
  	DelEndSlash(str,'/');
  	Log(("UPDIR: [%s] [%s] %d",str.c_str(), OldDir.c_str(), str == OldDir));
  
  	if(str == OldDir)
  	{
  		BackToHosts();
  		return TRUE;
  	}
  
  	return FALSE;
  }
  
  int FTP::SetDirectory(LPCSTR Dir,int OpMode)
  {
  	char   *Slash;
  	String  OldDir;
  	int     rc;
  	GetCurPath(OldDir);
  	Log(("FTP::SetDirectory [%s] -> [%s]",OldDir.c_str(),Dir));
  
  //Hosts
  	if(ShowHosts)
  	{
  		do
  		{
  			//Up
  			if(StrCmp(Dir,"..") == 0)
  			{
  				if(!OldDir[0] || (OldDir[0] == '\\' && !OldDir[1]))
  				{
  					Log(("Close plugin"));
  					CurrentState = fcsClose;
  					FP_Info->Control((HANDLE)this, FCTL_CLOSEPLUGIN, NULL);
  					return TRUE;
  				}
  
  				Slash = strrchr(HostsPath,'\\');
  
  				if(Slash)
  					*Slash=0;
  				else
  					*HostsPath=0;
  
  				Log(("DirBack"));
  				break;
  			}
  			else
  
  				//Root
  				if(*Dir == 0 || (*Dir == '\\' && Dir[1] == 0))
  				{
  					HostsPath[0] = 0;
  					Log(("Set to root"));
  					break;
  				}
  				else
  
  					//Directory
  					if(FTPHost::CheckHostFolder(HostsPath, Dir))
  					{
  						AddEndSlash(HostsPath,'\\',ARRAYSIZE(HostsPath));
  						StrCat(HostsPath, Dir, ARRAYSIZE(HostsPath));
  						Log(("InDir"));
  						break;
  					}
  		}
  		while(0);
  
  		if(!HostsPath[0])
  		{
  			HostsPath[0] = '\\';
  			HostsPath[1] = 0;
  		}
  
  		Log(("HostsDir set to [%s]",HostsPath));
  		//Save old directory
  		FP_SetRegKey("LastHostsPath",HostsPath);
  		return TRUE;
  	}
  
  //FTP
  
  	/* Back to prev directory.
  	   Directories allways separated by '/'!
  	*/
  	if(StrCmp(Dir,"..") == 0)
  	{
  		//Back from root
  		if(Opt.CloseDots &&
  		        (OldDir[0] == '/' || OldDir[0] == '*') && OldDir[1] == 0)
  		{
  			if(!IS_SILENT(OpMode))
  				BackToHosts();
  
  			return FALSE;
  		}
  
  		//Del last slash if any
  		DelEndSlash(OldDir, '/');
  		//Locate prev slash
  		FTPDirList    dl;
  		FTPServerInfo si;
  		String        Line;
  		si.ServerType = Host.ServerType;
  		StrCpy(si.ServerInfo, hConnect->SystemInfo, ARRAYSIZE(si.ServerInfo));
  		WORD idx = dl.DetectStringType(&si, Line.c_str(), Line.Length());
  
  		if(idx!=FTP_TYPE_MVS)
  			Slash = strrchr(OldDir.c_str(),'/');
  		else
  			Slash = strrchr(OldDir.c_str(),'.');
  
  		//Set currently leaving directory to select in panel
  		if(Slash != NULL)
  		{
  			SelectFile = Slash+1;
  
  			if(idx==FTP_TYPE_MVS&&SelectFile[1]==0)
  			{
  				char* s1 = Slash;
  				*s1=0;
  				Slash = strrchr(OldDir.c_str(),'.');
  				*s1='.';
  
  				if(Slash != NULL)
  					SelectFile = Slash+1;
  			}
  		}
  	}
  
  	//Change directory
  	rc = TRUE;
  
  	do
  	{
  		if(!hConnect)
  		{
  			rc = FALSE;
  			break;
  		}
  
  		if(SetDirectoryStepped(Dir,FALSE))
  		{
  			if(!IS_SILENT(OpMode))
  				CheckDotsBack(OldDir,Dir);
  
  			break;
  		}
  
  		if(!hConnect ||
  		        GetLastError() == ERROR_CANCELLED)
  		{
  			rc = FALSE;
  			break;
  		}
  
  		if(!hConnect->ConnectMessageTimeout(MChangeDirError,Dir,-MRetry))
  		{
  			rc = FALSE;
  			break;
  		}
  
  		if(FtpCmdLineAlive(hConnect) &&
  		        FtpKeepAlive(hConnect))
  			continue;
  
  		SaveUsedDirNFile();
  
  		if(!FullConnect())
  		{
  			rc = FALSE;
  			break;
  		}
  	}
  	while(true);
  
  	return rc;
  }
  