//--------------------------------------------------------------------------- #include #pragma hdrstop #include "FileMasks.h" namespace Masks { bool __fastcall MatchesMask(const AnsiString Filename, const AnsiString Mask); } using namespace Masks; #include "Common.h" #include "TextsCore.h" #include "RemoteFiles.h" #include "PuttyTools.h" #include "Terminal.h" //--------------------------------------------------------------------------- AnsiString __fastcall MaskFilePart(const AnsiString Part, const AnsiString Mask, bool& Masked) { AnsiString Result; int RestStart = 1; bool Delim = false; for (int Index = 1; Index <= Mask.Length(); Index++) { switch (Mask[Index]) { case '\\': if (!Delim) { Delim = true; Masked = true; break; } case '*': if (!Delim) { Result += Part.SubString(RestStart, Part.Length() - RestStart + 1); RestStart = Part.Length() + 1; Masked = true; break; } case '?': if (!Delim) { if (RestStart <= Part.Length()) { Result += Part[RestStart]; RestStart++; } Masked = true; break; } default: Result += Mask[Index]; RestStart++; Delim = false; break; } } return Result; } //--------------------------------------------------------------------------- AnsiString __fastcall MaskFileName(AnsiString FileName, const AnsiString Mask) { if (!Mask.IsEmpty() && (Mask != "*") && (Mask != "*.*")) { bool Masked; int P = Mask.LastDelimiter("."); if (P > 0) { int P2 = FileName.LastDelimiter("."); // only dot at beginning of file name is not considered as // name/ext separator AnsiString FileExt = P2 > 1 ? FileName.SubString(P2 + 1, FileName.Length() - P2) : AnsiString(); FileExt = MaskFilePart(FileExt, Mask.SubString(P + 1, Mask.Length() - P), Masked); if (P2 > 1) { FileName.SetLength(P2 - 1); } FileName = MaskFilePart(FileName, Mask.SubString(1, P - 1), Masked); if (!FileExt.IsEmpty()) { FileName += "." + FileExt; } } else { FileName = MaskFilePart(FileName, Mask, Masked); } } return FileName; } //--------------------------------------------------------------------------- bool __fastcall IsFileNameMask(const AnsiString Mask) { bool Masked = false; MaskFilePart("", Mask, Masked); return Masked; } //--------------------------------------------------------------------------- AnsiString __fastcall DelimitFileNameMask(AnsiString Mask) { for (int i = 1; i <= Mask.Length(); i++) { if (strchr("\\*?", Mask[i]) != NULL) { Mask.Insert("\\", i); i++; } } return Mask; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- TFileMasks::TParams::TParams() : Size(0) { } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- bool __fastcall TFileMasks::IsMask(const AnsiString Mask) { return (Mask.LastDelimiter("?*[") > 0); } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::SingleMaskMatch(const AnsiString Mask, const AnsiString FileName) { return MatchesFileMask(FileName, Mask); } //--------------------------------------------------------------------------- __fastcall TFileMasks::TFileMasks() { FMasks = ""; } //--------------------------------------------------------------------------- __fastcall TFileMasks::TFileMasks(const TFileMasks & Source) { Masks = Source.Masks; } //--------------------------------------------------------------------------- __fastcall TFileMasks::TFileMasks(const AnsiString AMasks) { FMasks = AMasks; } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::MatchesFileMask(const AnsiString & Filename, const AnsiString & Mask) { bool Result; if (Mask == "*.*") { Result = true; } else if ((Mask == "*.") && (Filename.Pos(".") == 0)) { Result = true; } else { Result = ::MatchesMask(Filename, Mask); } return Result; } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::MatchesMask(AnsiString FileName, bool Directory, AnsiString Path, const TParams * Params, AnsiString Masks) { bool Result = true; char NextDelimiter = '\0'; while (Result && !Masks.IsEmpty()) { AnsiString M; char Delimiter = NextDelimiter; M = CutToChars(Masks, "<>", true, &NextDelimiter); if (Delimiter != '\0') { if (Directory || (Params == NULL)) { Result = false; } else { enum { Less, LessEqual, Greater, GreaterEqual } Op; int Offset = 0; Op = ((Delimiter == '>') ? Greater : Less); if ((M.Length() >= 1) && (M[1] == '=')) { Op = ((Op == Less) ? LessEqual : GreaterEqual); Offset++; } __int64 Size = ParseSize(M.SubString(Offset + 1, M.Length() - Offset)); switch (Op) { case Less: Result = (Params->Size < Size); break; case LessEqual: Result = (Params->Size <= Size); break; case Greater: Result = (Params->Size > Size); break; case GreaterEqual: Result = (Params->Size >= Size); break; } } } else if (!M.IsEmpty()) { int D = M.LastDelimiter("\\/"); bool DirectoryMask = (D > 0) && (D == M.Length()); // directory masks match only directories, // non-directory masks match anything Result = (!DirectoryMask || Directory); if (Result) { bool PathMatch = true; if (DirectoryMask) { M.SetLength(M.Length() - 1); D = M.LastDelimiter("\\/"); } if (D > 0) { // make sure sole "/" (root dir) is preservedas is AnsiString MP = UnixExcludeTrailingBackslash(ToUnixPath(M.SubString(1, D))); // 'Path' must already have unix slashes PathMatch = ::MatchesMask(Path, MP); M = M.SubString(D + 1, M.Length() - D); } Result = (PathMatch && MatchesFileMask(FileName, M)); } } } return Result; } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::Matches(AnsiString FileName, bool Directory, AnsiString Path, const TParams * Params) const { AnsiString S = Masks; while (!S.IsEmpty()) { AnsiString M; M = CutToChars(S, ",;", true); if (MatchesMask(FileName, Directory, Path, Params, M)) { return true; } } return false; } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::Matches(AnsiString FileName, bool Local, bool Directory, const TParams * Params) const { AnsiString Path; if (Local) { Path = ExtractFilePath(FileName); if (!Path.IsEmpty()) { Path = ToUnixPath(ExcludeTrailingBackslash(Path)); } FileName = ExtractFileName(FileName); } else { Path = UnixExcludeTrailingBackslash(UnixExtractFilePath(FileName)); FileName = UnixExtractFileName(FileName); } return Matches(FileName, Directory, Path, Params); } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::IsValid() { int Start, Length; return IsValid(Start, Length); } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::IsValid(int & Start, int & Length) { AnsiString S = Masks; int IStart = 1; while (!S.IsEmpty()) { AnsiString M; M = CutToChars(S, ",;", false); int P = M.Length() + 1; if (!M.IsEmpty()) { try { MatchesMask("*.*", false, "", NULL, Trim(M)); } catch (Exception &E) { // Ignore leading/trainling spaces while (!M.IsEmpty() && (M[1] == ' ')) { IStart++; M.Delete(1, 1); } Start = IStart-1; Length = M.Trim().Length(); return False; } } if (P) IStart += P; } return true; } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::operator ==(const TFileMasks & rhm) const { return (Masks == rhm.Masks); } //--------------------------------------------------------------------------- TFileMasks & __fastcall TFileMasks::operator =(const AnsiString rhs) { Masks = rhs; return *this; } //--------------------------------------------------------------------------- TFileMasks & __fastcall TFileMasks::operator =(const TFileMasks & rhm) { Masks = rhm.Masks; return *this; } //--------------------------------------------------------------------------- bool __fastcall TFileMasks::operator ==(const AnsiString rhs) const { return (Masks == rhs); } //--------------------------------------------------------------------------- TFileMasks & __fastcall TFileMasks::operator =(const char * rhs) { Masks = rhs; return *this; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #define TEXT_TOKEN '\255' //--------------------------------------------------------------------------- const char TCustomCommand::NoQuote = '\0'; const AnsiString TCustomCommand::Quotes = "\"'"; //--------------------------------------------------------------------------- TCustomCommand::TCustomCommand() { } //--------------------------------------------------------------------------- void __fastcall TCustomCommand::GetToken( const AnsiString & Command, int Index, int & Len, char & PatternCmd) { assert(Index <= Command.Length()); const char * Ptr = Command.c_str() + Index - 1; if (Ptr[0] == '!') { PatternCmd = Ptr[1]; if (PatternCmd == '!') { Len = 2; } else { Len = PatternLen(Index, PatternCmd); } if (Len < 0) { throw Exception(FMTLOAD(CUSTOM_COMMAND_UNKNOWN, (PatternCmd, Index))); } else if (Len > 0) { if ((Command.Length() - Index + 1) < Len) { throw Exception(FMTLOAD(CUSTOM_COMMAND_UNTERMINATED, (PatternCmd, Index))); } } else if (Len == 0) { const char * PatternEnd = strchr(Ptr + 1, '!'); if (PatternEnd == NULL) { throw Exception(FMTLOAD(CUSTOM_COMMAND_UNTERMINATED, (PatternCmd, Index))); } Len = PatternEnd - Ptr + 1; } } else { PatternCmd = TEXT_TOKEN; const char * NextPattern = strchr(Ptr, '!'); if (NextPattern == NULL) { Len = Command.Length() - Index + 1; } else { Len = NextPattern - Ptr; } } } //--------------------------------------------------------------------------- AnsiString __fastcall TCustomCommand::Complete(const AnsiString & Command, bool LastPass) { AnsiString Result; int Index = 1; while (Index <= Command.Length()) { int Len; char PatternCmd; GetToken(Command, Index, Len, PatternCmd); if (PatternCmd == TEXT_TOKEN) { Result += Command.SubString(Index, Len); } else if (PatternCmd == '!') { if (LastPass) { Result += '!'; } else { Result += Command.SubString(Index, Len); } } else { char Quote = NoQuote; if ((Index > 1) && (Index + Len - 1 < Command.Length()) && Command.IsDelimiter(Quotes, Index - 1) && Command.IsDelimiter(Quotes, Index + Len) && (Command[Index - 1] == Command[Index + Len])) { Quote = Command[Index - 1]; } AnsiString Pattern = Command.SubString(Index, Len); AnsiString Replacement; bool Delimit = true; if (PatternReplacement(Index, Pattern, Replacement, Delimit)) { if (!LastPass) { Replacement = StringReplace(Replacement, "!", "!!", TReplaceFlags() << rfReplaceAll); } if (Delimit) { DelimitReplacement(Replacement, Quote); } Result += Replacement; } else { Result += Pattern; } } Index += Len; } return Result; } //--------------------------------------------------------------------------- void __fastcall TCustomCommand::DelimitReplacement(AnsiString & Replacement, char Quote) { Replacement = ShellDelimitStr(Replacement, Quote); } //--------------------------------------------------------------------------- void __fastcall TCustomCommand::Validate(const AnsiString & Command) { CustomValidate(Command, NULL); } //--------------------------------------------------------------------------- void __fastcall TCustomCommand::CustomValidate(const AnsiString & Command, void * Arg) { int Index = 1; while (Index <= Command.Length()) { int Len; char PatternCmd; GetToken(Command, Index, Len, PatternCmd); ValidatePattern(Command, Index, Len, PatternCmd, Arg); Index += Len; } } //--------------------------------------------------------------------------- bool __fastcall TCustomCommand::FindPattern(const AnsiString & Command, char PatternCmd) { bool Result = false; int Index = 1; while (!Result && (Index <= Command.Length())) { int Len; char APatternCmd; GetToken(Command, Index, Len, APatternCmd); if (((PatternCmd != '!') && (PatternCmd == APatternCmd)) || ((PatternCmd == '!') && (Len == 1) && (APatternCmd != TEXT_TOKEN))) { Result = true; } Index += Len; } return Result; } //--------------------------------------------------------------------------- void __fastcall TCustomCommand::ValidatePattern(const AnsiString & /*Command*/, int /*Index*/, int /*Len*/, char /*PatternCmd*/, void * /*Arg*/) { } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- TInteractiveCustomCommand::TInteractiveCustomCommand( TCustomCommand * ChildCustomCommand) { FChildCustomCommand = ChildCustomCommand; } //--------------------------------------------------------------------------- void __fastcall TInteractiveCustomCommand::Prompt(int /*Index*/, const AnsiString & /*Prompt*/, AnsiString & Value) { Value = ""; } //--------------------------------------------------------------------------- int __fastcall TInteractiveCustomCommand::PatternLen(int Index, char PatternCmd) { int Len; switch (PatternCmd) { case '?': Len = 0; break; default: Len = FChildCustomCommand->PatternLen(Index, PatternCmd); break; } return Len; } //--------------------------------------------------------------------------- bool __fastcall TInteractiveCustomCommand::PatternReplacement(int Index, const AnsiString & Pattern, AnsiString & Replacement, bool & Delimit) { bool Result; if ((Pattern.Length() >= 3) && (Pattern[2] == '?')) { AnsiString PromptStr; int Pos = Pattern.SubString(3, Pattern.Length() - 2).Pos("?"); if (Pos > 0) { Replacement = Pattern.SubString(3 + Pos, Pattern.Length() - 3 - Pos); if ((Pos > 1) && (Pattern[3 + Pos - 2] == '\\')) { Delimit = false; Pos--; } PromptStr = Pattern.SubString(3, Pos - 1); } else { PromptStr = Pattern.SubString(3, Pattern.Length() - 3); } Prompt(Index, PromptStr, Replacement); Result = true; } else { Result = false; } return Result; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- __fastcall TCustomCommandData::TCustomCommandData() { } //--------------------------------------------------------------------------- __fastcall TCustomCommandData::TCustomCommandData(TTerminal * Terminal) { HostName = Terminal->SessionData->HostName; UserName = Terminal->SessionData->UserName; Password = Terminal->Password; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- TFileCustomCommand::TFileCustomCommand() { } //--------------------------------------------------------------------------- TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data, const AnsiString & Path) { FData = Data; FPath = Path; } //--------------------------------------------------------------------------- TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data, const AnsiString & Path, const AnsiString & FileName, const AnsiString & FileList) : TCustomCommand() { FData = Data; FPath = Path; FFileName = FileName; FFileList = FileList; } //--------------------------------------------------------------------------- int __fastcall TFileCustomCommand::PatternLen(int /*Index*/, char PatternCmd) { int Len; switch (toupper(PatternCmd)) { case '@': case 'U': case 'P': case '/': case '&': Len = 2; break; default: Len = 1; break; } return Len; } //--------------------------------------------------------------------------- bool __fastcall TFileCustomCommand::PatternReplacement(int /*Index*/, const AnsiString & Pattern, AnsiString & Replacement, bool & Delimit) { // keep consistent with TSessionLog::OpenLogFile if (Pattern == "!@") { Replacement = FData.HostName; } else if (AnsiSameText(Pattern, "!u")) { Replacement = FData.UserName; } else if (AnsiSameText(Pattern, "!p")) { Replacement = FData.Password; } else if (Pattern == "!/") { Replacement = UnixIncludeTrailingBackslash(FPath); } else if (Pattern == "!&") { Replacement = FFileList; // already delimited Delimit = false; } else { assert(Pattern.Length() == 1); Replacement = FFileName; } return true; } //--------------------------------------------------------------------------- void __fastcall TFileCustomCommand::Validate(const AnsiString & Command) { int Found[2] = { 0, 0 }; CustomValidate(Command, &Found); if ((Found[0] > 0) && (Found[1] > 0)) { throw Exception(FMTLOAD(CUSTOM_COMMAND_FILELIST_ERROR, (Found[1], Found[0]))); } } //--------------------------------------------------------------------------- void __fastcall TFileCustomCommand::ValidatePattern(const AnsiString & /*Command*/, int Index, int /*Len*/, char PatternCmd, void * Arg) { int * Found = static_cast(Arg); assert(Index > 0); if (PatternCmd == '&') { Found[0] = Index; } else if ((PatternCmd != TEXT_TOKEN) && (PatternLen(Index, PatternCmd) == 1)) { Found[1] = Index; } } //--------------------------------------------------------------------------- bool __fastcall TFileCustomCommand::IsFileListCommand(const AnsiString & Command) { return FindPattern(Command, '&'); } //--------------------------------------------------------------------------- bool __fastcall TFileCustomCommand::IsFileCommand(const AnsiString & Command) { return FindPattern(Command, '!') || FindPattern(Command, '&'); } //---------------------------------------------------------------------------