BSOne.SFC/eCrmHE/EXE_eCrmHomeEdition/Manager/ManagerCampaign.pas

1250 lines
40 KiB
Plaintext

{*******************************************************}
{ }
{ ManagerCampaign }
{ }
{ Copyright (C) 2023 kku }
{ }
{*******************************************************}
unit ManagerCampaign;
interface
uses
Tocsg.Obj, System.SysUtils, System.Classes, Winapi.Windows,
System.Generics.Collections, IdHTTP, IdSSLOpenSSL, IdIOHandler, Define,
superobject, CttSchDefine;
type
TCampnType = (ctVul, ctScan, ctScanPatial, ctForceEnc);
TCampnRecursive = (crcOnce, crcWeekly, crcMonthly, crcDay, crcMonthDay{매월몇째주요일});
TCampnRespaction = (crtNone, crtDelete, crtPerDel, crtDRM, crtAIP);
TCampnDelayCond = (cdnNone, cdnOnce, cdnNoChange, cdnMaxCnt);
TCampnInfo = record
dtStar,
dtEnd,
dtStd: TDateTime;
sId,
sName: String;
CampnType: TCampnType;
Recursive: TCampnRecursive;
Respaction: TCampnRespaction;
DelayCond: TCampnDelayCond;
sExts,
sCRList,
sTgFolders,
sExpFolders: String;
nTimeoutSec,
nLimitSizeMB,
nNotiIfCnt,
nNotiWarIfCnt,
nNotiCriIfCnt,
nDelayPeriod,
nDelayFileCnt: Integer;
bIncOldRst,
bIncFName,
bNoFindEnc,
bDecompress,
bDelayNotice,
bUseFilter,
bUseFilterAnd,
bGetFile,
bGetContents,
bShowScan,
bPopupResult,
bNoActionVul,
bScanNotice,
bScanHighNotice: Boolean;
bPwSafe,
bFwSafe,
bOsSafe,
bAvSafe,
bScrnSafe,
bOsPatch: Boolean;
CttSchLimitMB: Integer;
end;
PCampnEnt = ^TCampnEnt;
TCampnEnt = record
Info: TCampnInfo;
sSchRstPath,
sSchRstExpPath: String;
dtLastWork,
dtLastNoti: TDateTime;
end;
TCampnEntList = TList<PCampnEnt>;
TManagerCampaign = class(TTgObject)
private
HTTP_: TIdHTTP;
SSL_: TIdSSLIOHandlerSocketOpenSSL;
// UTC 시간 계산 (한국=+09:00)
sUtcOffset_: String;
CampnEntList_: TCampnEntList;
procedure OnEntNotify(Sender: TObject; const Item: PCampnEnt; Action: TCollectionNotification);
procedure AddTestEnt;
public
// dtTest_: TDateTime;
Constructor Create;
Destructor Destroy; override;
procedure ClearScanDate; // 테스트를 제외하고 쓸일 없음
function GetCampnFromId(sId: String): PCampnEnt;
procedure RemoveCampnFromId(sId: String);
function GetWorkableCampaign(bIgrLastWrokDT: Boolean = false): PCampnEnt;
function GetDelayNotiCampaign: PCampnEnt;
function GetNoActionVulCampaign: PCampnEnt;
procedure UpdateCampnEnts(aO: ISuperObject);
procedure SendCampaignProgress(pEnt: PCampnEnt; aProg: TCttSchProg);
procedure SendCampaignResultVul(sTaskId: String);
procedure SendCampaignResultFile(sTaskId: String; pResult: PSchResult;
nProcIdx: Integer; bCollectFile: Boolean; nLimitMB: Integer; aRespaction: TCampnRespaction);
procedure SendCampaignResultSelfAction(sTaskId, sKind, sPath: String; nProcIdx: Integer);
procedure SendTestMsg;
procedure SendPrintTest;
procedure Save;
function SaveToFile(const sPath: String): Boolean;
procedure Load;
end;
function GetExistPiFileCount(sCampId: String): Integer;
implementation
uses
Tocsg.Json, Tocsg.Path, GlobalDefine, ManagerService,
Tocsg.Exception, Tocsg.Safe, Tocsg.Strings, System.DateUtils, Tocsg.DateTime,
Tocsg.PCRE, Tocsg.Files, Tocsg.Convert, System.Hash, IdMultipartFormData, ManagerModel, Tocsg.Trace, System.TimeSpan,
Tocsg.DRM.Encrypt,
Tocsg.Registry,
Condition;
Constructor TManagerCampaign.Create;
procedure InitHttp;
begin
try
SSL_ := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
SSL_.SSLOptions.Method := sslvSSLv23;
SSL_.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1, sslvTLSv1];
HTTP_ := TIdHTTP.Create(nil);
HTTP_.IOHandler := SSL_;
with HTTP_ do
begin
// HandleRedirects := true;
// Request.BasicAuthentication := true;
Request.Clear;
Request.UserAgent := 'Mozilla/5.0';
Request.ContentType := 'application/xml';
Request.AcceptCharSet := 'UTF-8'; //'application/json; charset=utf-8';
// Request.Connection := 'Keep-Alive';
// Request.CustomHeaders.Values['Keep-Alive'] := 'timeout=300, max=100';
Request.Connection := 'close';
HTTPOptions := HTTPOptions - [hoKeepOrigProtocol];
ConnectTimeout := 3000;
ReadTimeout := 10000;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Create() .. InitHttp()');
end;
end;
begin
Inherited Create;
sUtcOffset_ := '+00:00';
try
var TS: TTimeSpan := TTimeZone.Local.GetUtcOffset(Now);
sUtcOffset_ := Format('%s%.2d:%.2d', [BooleanToStr(TS.Ticks >= 0, '+', '-'), Abs(TS.Hours), Abs(TS.Minutes)]);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. GetUtcOffset()');
end;
// dtTest_ := 0;
InitHttp;
CampnEntList_ := TCampnEntList.Create;
CampnEntList_.OnNotify := OnEntNotify;
Load;
end;
Destructor TManagerCampaign.Destroy;
begin
FreeAndNil(CampnEntList_);
FreeAndNil(HTTP_);
FreeAndNil(SSL_);
Inherited;
end;
procedure TManagerCampaign.OnEntNotify(Sender: TObject; const Item: PCampnEnt; Action: TCollectionNotification);
begin
if Action = cnRemoved then
Dispose(Item);
end;
procedure TManagerCampaign.ClearScanDate; // 테스트를 제외하고 쓸일 없음
var
i: Integer;
begin
for i := 0 to CampnEntList_.Count - 1 do
CampnEntList_[i].dtLastWork := 0;
end;
function TManagerCampaign.GetCampnFromId(sId: String): PCampnEnt;
var
i: Integer;
begin
Result := nil;
for i := 0 to CampnEntList_.Count - 1 do
if CampnEntList_[i].Info.sId = sId then
begin
Result := CampnEntList_[i];
exit;
end;
end;
procedure TManagerCampaign.RemoveCampnFromId(sId: String);
var
i: Integer;
begin
try
for i := 0 to CampnEntList_.Count - 1 do
if CampnEntList_[i].Info.sId = sId then
begin
try
if (gMgSvc <> nil) and (gMgSvc.ProcCampn <> nil) and
(gMgSvc.ProcCampn.Info.sId = sId) then
begin
// 동작중인 캠페인이면 중지 후 제거 24_0221 13:11:59 kku
gMgSvc.StopCampaignTask;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. RemoveCampnFromId() .. StopCampaignTask()');
end;
CampnEntList_.Delete(i);
exit;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. RemoveCampnFromId()');
end;
end;
function TManagerCampaign.GetWorkableCampaign(bIgrLastWrokDT: Boolean = false): PCampnEnt;
var
i, n1, n2, n3: Integer;
pEnt: PCampnEnt;
dtNow: TDateTime;
sWorkingCpId: String;
begin
Result := nil;
try
dtNow := Now;
sWorkingCpId := GetRegValueAsString(HKEY_LOCAL_MACHINE, REG_HE, 'cpid');
for i := 0 to CampnEntList_.Count - 1 do
begin
pEnt := CampnEntList_[i];
// if sWorkingCpId <> '' then
// begin
// _Trace('GetWorkableCampaign() .. WorkingCpId = %s, ID=%s', [sWorkingCpId, pEnt.Info.sId]);
// end;
if (sWorkingCpId <> '') and (pEnt.Info.sId = sWorkingCpId) then
begin
// 작업중인게 있다면 바로 이어서 하도록 기능 추가 25_0519 11:26:49 kku
_Trace('GetWorkableCampaign() .. Found .. WorkingCpId = %s, ID=%s', [sWorkingCpId, pEnt.Info.sId]);
Result := pEnt;
exit;
end;
if not ( (CompareDateTime(pEnt.Info.dtStar, dtNow) = -1) and
(CompareDateTime(pEnt.Info.dtEnd, dtNow) = 1) ) then continue;
// 오늘 한번 작업한건 무시
if not bIgrLastWrokDT and IsToday(pEnt.dtLastWork) then
continue;
case pEnt.Info.Recursive of
crcOnce : // 1회
begin
if IsSameDay(pEnt.Info.dtStd, dtNow) and
(CompareTime(pEnt.Info.dtStd, dtNow) <= 0) then
begin
Result := pEnt;
exit;
end;
end;
crcWeekly : // 매주 (요일)
begin
if (DayOfWeek(pEnt.Info.dtStd) = DayOfWeek(dtNow)) and
(CompareTime(pEnt.Info.dtStd, dtNow) <= 0) then
begin
Result := pEnt;
exit;
end;
end;
crcMonthly : // 매월 (일)
begin
n1 := DayOfTheMonth(pEnt.Info.dtStd);
n2 := DayOfTheMonth(dtNow);
n3 := DayOfTheMonth(EndOfTheMonth(dtNow));
// 같은 날짜거나, 설정 날짜가 이달의 마지막 날보다 크고 오늘이 마지막 날인 경우...
if (n1 = n2) or
( (n1 >= n3) and (n2 = n3) ) then
begin
if CompareTime(pEnt.Info.dtStd, dtNow) <= 0 then
begin
Result := pEnt;
exit;
end;
end;
end;
crcDay : // 매일
begin
if CompareTime(pEnt.Info.dtStd, dtNow) <= 0 then
begin
Result := pEnt;
exit;
end;
end;
crcMonthDay : // 매월 (요일)
begin
// 몇째주 무슨요일인지 체크
if (WeekOfTheMonth(pEnt.Info.dtStd) = WeekOfTheMonth(dtNow)) and
(DayOfWeek(pEnt.Info.dtStd) = DayOfWeek(dtNow)) and
(CompareTime(pEnt.Info.dtStd, dtNow) <= 0) then
begin
Result := pEnt;
exit;
end;
end;
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. GetWorkableCampaign()');
end;
end;
function GetExistPiFileCount(sCampId: String): Integer;
var
// sFld,
// sFName,
// sFrName,
sPath: String;
StrList,
DataList: TStringList;
i, c, nEncCnt, nExpCnt: Integer;
// MgCampExpt: TManagerCampExcept;
O: ISuperObject;
begin
Result := 0;
try
nEncCnt := 0;
nExpCnt := 0;
if LoadJsonObjFromFile(O, GetRunExePathDir + DIR_CTTSCHRST + sCampId + '.' + DAT_CTTSCHRST) then
begin
Result := O.I['FoundFileCount'] - O.I['DelFileCount'] - O.I['EncFileCount'] - O.I['ExpFileCount'];
// nEncCnt := O.I['EncFileCount'];
// nExpCnt := O.I['ExpFileCount']; // 예외 카운트 계산은 뺌
end;
try
// 1000개 이하일 경우에만 삭제된 파일까지 체크,
// 파일이 많으면 오래걸려서 조건을 둠 24_0612 09:31:47 kku
if Result <= 1000 then
begin
sPath := GetRunExePathDir + DIR_CTTSCHRST + sCampId + '.' + DAT_CTTSCHRSTDATA;
if not FileExists(sPath) then
exit;
Guard(StrList, TStringList.Create);
StrList.LoadFromFile(sPath, TEncoding.UTF8);
Guard(DataList, TStringList.Create);
// Guard(MgCampExpt, TManagerCampExcept.Create);
Result := 0;
for i := 0 to StrList.Count - 1 do
begin
SplitString(StrList[i], '<!>', DataList, true);
if DataList.Count < 4 then
continue;
sPath := DataList[2];
// sFld := ExtractFilePath(sPath);
// sFName := ExtractFileName(sPath);
// if DataList.Count >= 5 then
// sFrName := DataList[4]
// else
// sFrName := sFName;
//
// c := Pos(' > ', sFName);
// if c > 0 then
// SetLength(sFName, c - 1);
// if (sPath.StartsWith('\\') or FileExists(sPath)) and not MgCampExpt.IsExceptFile(sPath) then
// if CheckSign(sPath, SIG_DRM) then
// continue;
if (sPath.StartsWith('\\') or FileExists(sPath)) then
Inc(Result);
end;
Dec(Result, O.I['EncFileCount']);
Dec(Result, O.I['ExpFileCount']);
if Result < 0 then
Result := 0;
end;
finally
// Dec(Result, nEncCnt);
// Dec(Result, nExpCnt);
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. GetExistsFileCount()');
end;
end;
function GetFoundPiFileCount(sCampId: String): Integer;
var
O: ISuperObject;
begin
Result := 0;
if not LoadJsonObjFromFile(O, GetRunExePathDir + DIR_CTTSCHRST + sCampId + '.' + DAT_CTTSCHRST) then
exit;
Result := O.I['FoundFileCount'];// - O.I['EncFileCount'];
end;
function TManagerCampaign.GetDelayNotiCampaign: PCampnEnt;
var
i, n1, n2, n3: Integer;
pEnt: PCampnEnt;
dtNow: TDateTime;
begin
Result := nil;
try
// if dtTest_ = 1 then // 미조치 알림 테스트를 위함 23_1114 15:42:01 kku
// begin
// dtNow := EncodeDateTime(2024, 12, 31, 0, 0, 0, 0);
// dtTest_ := 0;
// end else
dtNow := Now;
for i := 0 to CampnEntList_.Count - 1 do
begin
pEnt := CampnEntList_[i];
if not ( (CompareDateTime(pEnt.Info.dtStar, dtNow) = -1) and
(CompareDateTime(pEnt.Info.dtEnd, dtNow) = 1) ) then continue;
if not pEnt.Info.bDelayNotice then
continue;
if pEnt.dtLastNoti = 0 then
continue;
// 오늘 한번 알림한거
// if IsToday(pEnt.dtLastNoti) then
// continue;
// 간격을 일자에서 시간 단위로 변경 24_0612 08:48:30 kku
// if DaysBetween(pEnt.dtLastNoti, dtNow) <= pEnt.Info.nDelayPeriod then
// continue;
if HoursBetween(pEnt.dtLastNoti, dtNow) < pEnt.Info.nDelayPeriod then
continue;
if GetFoundPiFileCount(pEnt.Info.sId) = 0 then
begin
pEnt.dtLastNoti := dtNow;
continue;
end;
case pEnt.Info.DelayCond of
cdnNone : ;
cdnOnce : ; // pEnt.dtLastNoti 이걸 0으로 바꿔주는걸로 처리
cdnNoChange :
begin
if GetFoundPiFileCount(pEnt.Info.sId) <> GetExistPiFileCount(pEnt.Info.sId) then
begin
pEnt.dtLastNoti := dtNow;
continue;
end;
end;
cdnMaxCnt :
begin
if GetExistPiFileCount(pEnt.Info.sId) < pEnt.Info.nDelayFileCnt then
begin
pEnt.dtLastNoti := dtNow;
continue;
end;
end;
end;
Result := pEnt;
exit;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. GetDelayNotiCampaign()');
end;
end;
function TManagerCampaign.GetNoActionVulCampaign: PCampnEnt;
var
i, n1, n2, n3: Integer;
pEnt: PCampnEnt;
dtNow: TDateTime;
begin
Result := nil;
dtNow := Now;
try
for i := 0 to CampnEntList_.Count - 1 do
begin
pEnt := CampnEntList_[i];
if not ( (CompareDateTime(pEnt.Info.dtStar, dtNow) = -1) and
(CompareDateTime(pEnt.Info.dtEnd, dtNow) = 1) ) then continue;
if not pEnt.Info.bDelayNotice or not pEnt.Info.bNoActionVul then
continue;
case pEnt.Info.DelayCond of
cdnNone : ;
cdnOnce : ; // pEnt.dtLastNoti 이걸 0으로 바꿔주는걸로 처리
cdnNoChange :
begin
if GetFoundPiFileCount(pEnt.Info.sId) <> GetExistPiFileCount(pEnt.Info.sId) then
continue;
end;
cdnMaxCnt :
begin
if GetExistPiFileCount(pEnt.Info.sId) < pEnt.Info.nDelayFileCnt then
continue;
end;
end;
Result := pEnt;
exit;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. GetDelayNotiCampaign()');
end;
end;
procedure TManagerCampaign.Save;
var
O, OA: ISuperObject;
i: Integer;
begin
try
OA := TSuperObject.Create(stArray);
for i := 0 to CampnEntList_.Count - 1 do
OA.AsArray.Add(TTgJson.ValueToJsonObject<TCampnEnt>(CampnEntList_[i]^));
O := SO;
O.O['List'] := OA;
SaveJsonObjToEncFile(O, GetRunExePathDir + DIR_CONF + DAT_CAMPN, PASS_STRENC);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. Save()');
end;
end;
function TManagerCampaign.SaveToFile(const sPath: String): Boolean;
var
O, OA: ISuperObject;
i: Integer;
begin
Result := false;
try
OA := TSuperObject.Create(stArray);
for i := 0 to CampnEntList_.Count - 1 do
OA.AsArray.Add(TTgJson.ValueToJsonObject<TCampnEnt>(CampnEntList_[i]^));
O := SO;
O.O['List'] := OA;
Result := SaveJsonObjToFile(O, sPath, TEncoding.UTF8, true);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SaveToFile()');
end;
end;
procedure TManagerCampaign.Load;
var
sPath: String;
O: ISuperObject;
i: Integer;
pEnt: PCampnEnt;
begin
// CampnEntList_.Clear;
// AddTestEnt;
// exit;
sPath := GetRunExePathDir + DIR_CONF + DAT_CAMPN;
if not FileExists(sPath) then
exit;
if not LoadJsonObjFromEncFile(O, sPath, PASS_STRENC) then
exit;
if (O.O['List'] = nil) or (O.O['List'].DataType <> stArray) then
exit;
for i := 0 to O.A['List'].Length - 1 do
begin
New(pEnt);
pEnt^ := TTgJson.GetDataAsType<TCampnEnt>(O.A['List'].O[i]);
// {$IFDEF DEBUG} // TEST_KJ
// pEnt.Info.dtStd := AppendTime(Now, 0, 0, 0, 0);
// {$ENDIF}
CampnEntList_.Add(pEnt);
end;
end;
procedure TManagerCampaign.AddTestEnt;
var
pEnt: PCampnEnt;
begin
CampnEntList_.Clear;
New(pEnt);
ZeroMemory(pEnt, SizeOf(TCampnEnt));
with pEnt.Info do
begin
dtStar := AppendTime(StrToDate('2023-08-01'), 0, 0, 0, 0);
dtEnd := AppendTime(StrToDateTime('2023-08-31'), 23, 59, 59, 0);
dtStd := AppendTime(Today, 9, 0, 0, 0);
sId := '4382351325320'; // 15.4
// sId := '51327596581893'; // 0.13
sName := '캠패인-TEST-1ttttt';
_Trace('DEBUG......4');
CampnType := ctScan;
Recursive := crcOnce;
Respaction := crtNone;
DelayCond := cdnNone;
sExts := 'txt;xlsx';
sCRList := ';D003;D001';
sTgFolders := 'D:\Temp';
// sExpFolders
// nDelayPeriod := 0;
// nDelayNotice := 0;
// nDelayFileCnt,
// nDelayCondition: Integer;
bUseFilter := true;
// bUseFilterAnd
// bGetFile,
// bGetContents,
bShowScan := true;
bPopupResult := true;
bScanNotice := true;
// bScanHighNotice: Boolean;
// bPwSafe,
// bFwSafe,
// bOsSafe,
// bAvSafe,
// bScrnSafe,
// bOsPatch: Boolean;
end;
CampnEntList_.Add(pEnt);
end;
procedure TManagerCampaign.UpdateCampnEnts(aO: ISuperObject);
var
sRes: String;
sTemp,
sTemp2,
sCamId: String;
i, nPos: Integer;
O: ISuperObject;
pEnt: PCampnEnt;
CamIdList: TStringList;
begin
try
if aO = nil then
exit;
if aO.DataType <> stArray then
exit;
_Trace('Update Campaign ..', 2);
Guard(CamIdList, TStringList.Create);
for i := 0 to aO.AsArray.Length - 1 do
CamIdList.Add(aO.AsArray.O[i].S['campaignId']);
// 할당 해제된 캠페인 처리
for i := CampnEntList_.Count - 1 downto 0 do
begin
if CamIdList.IndexOf(CampnEntList_[i].Info.sId) = -1 then
CampnEntList_.Delete(i);
end;
for i := 0 to CamIdList.Count - 1 do
begin
sCamId := CamIdList[i];
sRes := gMgSvc.HttpPost(gMgSvc.DestIPort + 'campaignRequest.do', sCamId, '{}');
if (sRes = '') or (sRes = 'true') then
begin
// 캠패인 만료
RemoveCampnFromId(sCamId);
continue;
end;
try
O := SO(sRes);
if O = nil then
begin
_Trace('UpdateCampnEnts() .. Invalid Response ... 2, ID=%s', [sCamId]);
exit;
end;
except
_Trace('UpdateCampnEnts() .. Invalid Response ... 1, ID=%s', [sCamId]);
exit;
end;
{$IFDEF DEBUG} SaveJsonObjToFile(O, Format('c:\cs-%s.json', [sCamId])); {$ENDIF}
pEnt := GetCampnFromId(sCamId);
if pEnt = nil then
begin
New(pEnt);
ZeroMemory(pEnt, SizeOf(TCampnEnt));
CampnEntList_.Add(pEnt);
pEnt.Info.sId := sCamId;
end;
with pEnt.Info do
begin
dtStar := StrToDate(O.S['KEY_STARTDATE']);
dtEnd := StrToDate(O.S['KEY_ENDDATE']);
// sId,
sName := O.S['KEY_CAMPAIGNNAME'];
// 취약 0, 전체스캔 1, 증분스캔 2, 파일 암호화 3
case StrToIntDef(O.S['KEY_CAMPAIGNTYPE'], 1) of
1 : CampnType := ctScan;
2 : CampnType := ctScanPatial;
3 : CampnType := ctForceEnc;
end;
sTemp := O.S['KEY_RECURSIVE'].ToLower;
nPos := Pos(';', sTemp);
{$IFDEF DEBUG}
ASSERT(nPos > 0);
{$ELSE}
if nPos = 0 then
_Trace('Fail .. Invalid KEY_RECURSIVE Value=%s', [sTemp]);
{$ENDIF}
dtStd := StrToDateDef(Copy(sTemp, nPos + 1, Length(sTemp) - nPos), 0);
SetLength(sTemp, nPos - 1);
if sTemp = 'day' then
Recursive := crcDay
else if sTemp = 'once' then
Recursive := crcOnce
else if sTemp = 'weekly' then
Recursive := crcWeekly
else if sTemp = 'monthday' then
Recursive := crcMonthDay
else
Recursive := crcMonthly;
if O.S['KEY_STARTTIME'] <> '' then
begin
var wHour, wMin: WORD;
wHour := 0;
wMin := 0;
sTemp := O.S['KEY_STARTTIME'];
nPos := Pos(':', sTemp);
if nPos > 0 then
begin
wHour := StrToIntDef(Copy(sTemp, 1, nPos - 1), 0);
if 24 <= wHour then
wHour := 0;
Delete(sTemp, 1, nPos);
wMin := StrToIntDef(sTemp, 0);
if 60 < wMin then
wMin := 0;
end;
if (wHour > 0) or (wMin > 0) then
dtStd := AppendTime(dtStd, wHour, wMin, 0, 0);
end;
sTemp := O.S['KEY_RESPACTION'].ToLower;
if sTemp = 'delete' then
Respaction := crtDelete
else if sTemp = 'erase' then
Respaction := crtPerDel
else if sTemp = 'drm' then
Respaction := crtDRM
else if sTemp = 'aip' then
Respaction := crtAIP
else
Respaction := crtNone;
sExts := StringReplace(O.S['KEY_EXTENSION'], ';', '|', [rfReplaceAll]);
sCRList := O.S['KEY_CRLIST'];
sTgFolders := O.S['KEY_TARGETFOLDER'];
sExpFolders := O.S['KEY_EXCEPTFOLDER'];
bDelayNotice := O.S['KEY_DELAYNOTICE'].ToLower = 'true'; // 미조치 다시 알림 ON/OFF
nDelayPeriod := StrToIntDef(O.S['KEY_DELAYPERIOD'], 0); // 미조치 기간
nDelayFileCnt := StrToIntDef(O.S['KEY_DELAYSCANCNT'], 0); // 미조치 개수
sTemp := O.S['KEY_DELAYCONDITION'].ToLower; // 미조치 조건 (once : 1회, nochange : 변경 없을 경우, maxcnt : 개수 이상 위반 유지)
if sTemp = 'once' then
DelayCond := cdnOnce
else if sTemp = 'nochange' then
DelayCond := cdnNoChange
else if sTemp = 'maxcnt' then
DelayCond := cdnMaxCnt
else
DelayCond := cdnNone;
nNotiIfCnt := StrToIntDef(O.S['KEY_POPUPRESULT'], 1);
nNotiWarIfCnt := StrToIntDef(O.S['KEY_POPUPRESULTHIGH'], 0);
nNotiCriIfCnt := StrToIntDef(O.S['KEY_POPUPRESULTCRITICAL'], 0);
nTimeoutSec := StrToIntDef(O.S['KEY_MAXFILETIMEOUT'], 0);
if nTimeoutSec = 0 then
nTimeoutSec := 20;
nLimitSizeMB := StrToIntDef(O.S['KEY_MAXFILESIZE'], 0);
if nLimitSizeMB = 0 then
nLimitSizeMB := 100;
bDecompress := O.S['KEY_SCANZIP'].ToLower = 'true'; // 압축해제 여부
bUseFilter := O.S['KEY_FILTERENABLE'].ToLower = 'true';
bUseFilterAnd := O.S['KEY_FILTERAND'].ToLower = 'true';
bGetFile := O.S['KEY_GETFILE'].ToLower = 'true';
bGetContents := O.S['KEY_GETCONTENTS'].ToLower = 'true';
bShowScan := O.S['KEY_SHOWSCAN'].ToLower = 'true';
// bPopupResult := O.S['KEY_POPUPRESULT'].ToLower = 'true';
bScanNotice := O.S['KEY_SCANNOTICE'].ToLower = 'true';
bScanHighNotice := O.S['KEY_SCANHIGHNOTICE'].ToLower = 'true';
bNoFindEnc := O.S['KEY_NONDETECTEDFILEAIP'].ToLower = 'true';
bNoActionVul := O.S['KEY_VULCHECK'].ToLower = 'true';
bIncFName := O.S['key_fileNameSearch'].ToLower = 'true';
bIncOldRst := O.S['key_resultType'].ToLower = 'maintain';
bPwSafe := O.S['KEY_PWSAFE'].ToLower = 'true';
bFwSafe := O.S['KEY_FWSAFE'].ToLower = 'true';
bOsSafe := O.S['KEY_OSSAFE'].ToLower = 'true';
bAvSafe := O.S['KEY_AVSAFE'].ToLower = 'true';
bScrnSafe := O.S['KEY_SCRNSAFE'].ToLower = 'true';
bOsPatch := O.S['KEY_OSPATCH'].ToLower = 'true';
CttSchLimitMB := StrToIntDef(O.S['key_getFileSize'], 0);
end;
end;
Save;
gMgSvc.UpdateCttSchVulState(true);
_Trace('Update Campaign .. OK', 2);
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. ProcessRcvCampaign()');
end;
end;
procedure TManagerCampaign.SendCampaignProgress(pEnt: PCampnEnt; aProg: TCttSchProg);
var
O: ISuperObject;
dt: TDateTime;
begin
try
O := SO;
dt := Now;
O.S['KEY_AGENTID'] := gMgSvc.AgentId;
O.S['KEY_EMPNO'] := gMgSvc.EmpNo;
O.S['KEY_HOSTNAME'] := gMgSvc.UserName;
O.S['KEY_SUBMITTIME'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dt);
O.S['key_submitTime'] := FormatDateTime('yyyy-MM-dd"T"hh:nn:ss.zzz', dt) + sUtcOffset_;
O.S['CAMPAIGN_ID'] := pEnt.Info.sId;
O.S['KEY_TASKID'] := aProg.sTaskId;
O.S['CAMPAIGN_STATUS'] := aProg.sStatus;
O.S['CAMPAIGN_STARTTIME'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', aProg.dtStart);
O.S['campaignStartTime'] := FormatDateTime('yyyy-MM-dd"T"hh:nn:ss.zzz', aProg.dtStart) + sUtcOffset_;
if aProg.sStatus = 'DONE' then // 캠페인 진행 상황 (PROGRESS, STOP, PENDING, DONE)
begin
O.S['CAMPAIGN_ENDTIME'] := O.S['KEY_SUBMITTIME'];
O.S['campaignEndTime'] := O.S['key_submitTime'];
end;
// O.S['VUL_RESULT'] // 취약점 실패 항목
O.S['SCAN_CNT_COMPLETED'] := IntToStr(aProg.llProc);
O.S['SCAN_CNT_TOTAL'] := IntToStr(aProg.llTotal);
O.S['SCAN_CNT_FOUND'] := IntToStr(aProg.llFound);
O.S['SCAN_CNT_DRM'] := IntToStr(aProg.llEncFileCnt);
O.S['SCAN_CNT_ENCFAILED'] := IntToStr(aProg.llEncFailFileCnt);
gMgSvc.EventLog.Push(O.AsJSon);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SendCampaignProgress()');
end;
end;
procedure TManagerCampaign.SendCampaignResultVul(sTaskId: String);
begin
try
// gMgSvc.EventLog.Push(O.AsJSon); // todo : 식별자 필요
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SendCampaignResultVul()');
end;
end;
procedure TManagerCampaign.SendCampaignResultFile(sTaskId: String; pResult: PSchResult;
nProcIdx: Integer; bCollectFile: Boolean; nLimitMB: Integer; aRespaction: TCampnRespaction);
var
O, OA, OTemp: ISuperObject;
dtNow: TDateTime;
StrList,
RstList: TStringList;
i: Integer;
begin
try
O := SO;
dtNow := Now;
O.S['TYP_MSG'] := '@(!)_CAMPN';
O.S['KEY_AGENTID'] := gMgSvc.AgentId;
O.S['KEY_EMPNO'] := gMgSvc.EmpNo;
O.S['KEY_HOSTNAME'] := gMgSvc.UserName;
O.S['KEY_EVENTID'] := 'CM' + FormatDateTime('yymmddhhnnss', dtNow) + IntToStr(nProcIdx);
O.S['KEY_TASKID'] := sTaskId;
O.S['KEY_SUBMITTIME'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dtNow);
O.S['key_submitTime'] := FormatDateTime('yyyy-MM-dd"T"hh:nn:ss.zzz', dtNow) + sUtcOffset_;
O.S['DETECTION_DATE'] := O.S['KEY_SUBMITTIME'];// 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각.
O.S['detectionDate'] := O.S['key_submitTime'];// 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각.
// O.S['PARENT_LA_ID'] // 상위 이벤트가 존재하는 경우 상위 이벤트 ID
if pResult.sExtrTxt <> '' then
begin
if (gMgSvc.PrefModel.TextLimit > 0) and (Length(pResult.sExtrTxt) > gMgSvc.PrefModel.TextLimit) then
SetLength(pResult.sExtrTxt, gMgSvc.PrefModel.TextLimit);
var sExt: String := GetFileExt(pResult.sFName).ToUpper;
if Pos(sExt, IMAGE_EXTS) > 0 then
O.S['OCR_BODY'] := pResult.sExtrTxt
else
O.S['MESSAGE_BODY'] := pResult.sExtrTxt;
end;
if (pResult.sSchName <> '') and
(pResult.sResultStr <> '') then
begin
OA := TSuperObject.Create(stArray);
Guard(StrList, TStringList.Create);
SplitString(pResult.sSchName, RESULT_SEPARATOR, StrList);
Guard(RstList, TStringList.Create);
SplitString(pResult.sResultStr, RESULT_SEPARATOR, RstList);
for i := 0 to StrList.Count - 1 do
begin
OTemp := SO;
OTemp.S['RULE_ID'] := StrList[i];
OTemp.S['TEXT'] := GetCountOverlapWords(RstList[i], ';');
OTemp.S['CNT'] := IntToStr(pResult.nHitCnt);
OA.AsArray.Add(OTemp);
end;
O.O['RULE_VIOLATED'] := OA;
end;
if bCollectFile then
begin
if GetFileSize_path(pResult.sPath) <= (LONGLONG(nLimitMB) * 1048576) then
begin
O.S['COMPONENT_ID'] := gMgSvc.MakeComponentId(sTaskId + '_' + IntToStr(nProcIdx));
case aRespaction of
crtDelete,
crtPerDel : gMgSvc.SendFileNor(false, O.S['COMPONENT_ID'], 'quarantineLogCollect.do', pResult.sPath, 0, nLimitMB, aRespaction);
else gMgSvc.SendFileNor(false, O.S['COMPONENT_ID'], 'quarantineLogCollect.do', pResult.sPath, 0, nLimitMB); // 암호화는 앞서 처리됨
end;
end;
end;
O.S['COMPONENT_FILENAME'] := pResult.sFName;
O.S['COMPONENT_PATH'] := ExtractFilePath(pResult.sPath);
if FileExists(pResult.sPath) then
begin
var dtCreate, dtModify, dtAccess: TDateTime;
GetFileDateTime_Local(pResult.sPath, dtCreate, dtModify, dtAccess);
var dwAttr: DWORD := GetFileAttributes(PChar(pResult.sPath));
OTemp := SO;
OTemp.S['FILESIZE'] := IntToStr(GetFileSize_path(pResult.sPath));
OTemp.S['LASTMODIFIED'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dtModify);
if dwAttr <> DWORD(-1) then
OTemp.S['READONLY'] := BooleanToStr((dwAttr and FILE_ATTRIBUTE_READONLY) <> 0, 'true', 'false');
if dwAttr <> DWORD(-1) then
OTemp.S['HIDDEN'] := BooleanToStr((dwAttr and FILE_ATTRIBUTE_HIDDEN) <> 0, 'true', 'false');
// OTemp.S['AUTHOR'] // {만든 이}
// OTemp.S['LASTUSER'] // {마지막으로 저장한 사람}
// OTemp.S['FILETYPE'] // {컨텐츠 타입}
// OTemp.S['FILECLS'] // {컨텐츠 형식}
// OTemp.S['PASSWORD'] // {암호적용여부}
OTemp.S['ENCRYPTED'] := BooleanToStr(pResult.bDrm, 'true', 'false');
if pResult.bOtherDrm then
OTemp.S['OTHER_ENC'] := 'true';
/// </summary>
// OTemp.S['CORRUPT'] // {깨진파일/정상파일여부}
O.O['COMPONENT_METADATA'] := OTemp;
O.S['COMPONENT_LASTACCESS'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dtAccess);
end;
case aRespaction of // 적용된 대응 정보 (DELETE, ERASE, DRM, AIP, EXCEPT 등)
crtDelete :
begin
O.S['RESPONSE_INFO'] := 'DELETE';
// 일단... 대응이 있으면 무조건 true 처리
O.S['RESPONSE_RESULT'] := 'true'; // 적용된 대응 적용 결과 (true / false / pending / decline)
end;
crtPerDel :
begin
O.S['RESPONSE_INFO'] := 'ERASE';
// 일단... 대응이 있으면 무조건 true 처리
O.S['RESPONSE_RESULT'] := 'true'; // 적용된 대응 적용 결과 (true / false / pending / decline)
end;
crtDRM :
begin
O.S['RESPONSE_INFO'] := 'DRM';
// 일단... 대응이 있으면 무조건 true 처리
// O.S['RESPONSE_RESULT'] := 'true'; // 적용된 대응 적용 결과 (true / false / pending / decline)
O.S['RESPONSE_RESULT'] := BooleanToStr(pResult.bMakeDrm, 'true', 'false');
end;
crtAIP :
begin
O.S['RESPONSE_INFO'] := 'AIP';
O.S['RESPONSE_RESULT'] := BooleanToStr(pResult.bMakeDrm, 'true', 'false');
end;
crtNone :
begin
// if CUSTOMER_TYPE = CUSTOMER_SERVE1 then
// begin
// // 서브원 : 대응이 없어도 암호화 되어 있는 파일은 "대응 내용"에 DRM 이라고 표시되도록 수정 (4263) 25_0910 14:41:26 kku
// if pResult.bDrm then
// begin
// if IsUseEncOnlyAIP then
// O.S['RESPONSE_INFO'] := 'AIP'
// else
// O.S['RESPONSE_INFO'] := 'DRM';
// end;
// end;
end;
end;
// O.S['REQUEST_COMMENT'] // 사용자가 기입하는 예외 사유
//var Str: TStringList;
//Guard(Str, TStringList.Create);
//Str.Text := O.AsJSon;
//Str.SaveToFile('c:\temp11.txt');
gMgSvc.EventLog.Push(O.AsJSon);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SendCampaignResultFile()');
end;
end;
procedure TManagerCampaign.SendCampaignResultSelfAction(sTaskId, sKind, sPath: String; nProcIdx: Integer);
var
O, OA, OTemp: ISuperObject;
dtNow: TDateTime;
StrList,
RstList: TStringList;
i: Integer;
begin
try
O := SO;
dtNow := Now;
O.S['TYP_MSG'] := '@(!)_CAMPN';
O.S['KEY_AGENTID'] := gMgSvc.AgentId;
O.S['KEY_EMPNO'] := gMgSvc.EmpNo;
O.S['KEY_HOSTNAME'] := gMgSvc.UserName;
O.S['KEY_EVENTID'] := 'CM' + FormatDateTime('yymmddhhnnss', dtNow) + IntToStr(nProcIdx);
O.S['KEY_TASKID'] := sTaskId;
O.S['KEY_SUBMITTIME'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dtNow);
O.S['key_submitTime'] := FormatDateTime('yyyy-MM-dd"T"hh:nn:ss.zzz', dtNow) + sUtcOffset_;
O.S['DETECTION_DATE'] := O.S['KEY_SUBMITTIME'];// 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각.
O.S['detectionDate'] := O.S['key_submitTime'];// 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각.
O.S['COMPONENT_FILENAME'] := ExtractFileName(sPath);
O.S['COMPONENT_PATH'] := ExtractFilePath(sPath);
O.S['RESPONSE_INFO'] := sKind;
O.S['RESPONSE_RESULT'] := 'true';
gMgSvc.EventLog.Push(O.AsJSon);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SendCampaignResultFile()');
end;
end;
procedure TManagerCampaign.SendTestMsg;
var
pEnt: PCampnEnt;
Prog: TCttSchProg;
sId, sComName: String;
Rst: TSchResult;
begin
sId := '4382351325320'; // 15.4
// sId := '51327596581893'; // 0.13
pEnt := GetCampnFromId(sId);
ASSERT(pEnt <> nil);
ZeroMemory(@Prog, SizeOf(Prog));
Prog.dtStart := Now;
Prog.sScanId := sId;
// Prog.sTaskId := FormatDateTime('yyyymmddhhnnss', Prog.dtStart);
sComName := gMgSvc.ComName;
Prog.sTaskId := sComName + '\' + FormatDateTime('yymmddhhnnss', Prog.dtStart);
if Length(Prog.sTaskId) > 64 then
begin
SetLength(sComName, Length(sComName) - (Length(Prog.sTaskId) - 64));
Prog.sTaskId := sComName + '\' + FormatDateTime('yymmddhhnnss', Prog.dtStart);
end;
Prog.llProc := 0;
Prog.llTotal := 1;
Prog.sStatus := 'PROGRESS';
SendCampaignProgress(pEnt, Prog);
ZeroMemory(@Rst, SizeOf(Rst));
Rst.nHitCnt := 1;
Rst.sFName := '1새 텍스트 문서.txt';
Rst.sPath := 'C:\Users\kku\Desktop\이전 바탕화면\';
Rst.sSchName := 'D001|!*!|D004';
Rst.sResultStr := '811108-1234567|!*!|010-1234-5678';
SendCampaignResultFile(Prog.sTaskId, @Rst, 1, false, 50, crtNone); // , 'tocsg1234');
Prog.llProc := 1;
Prog.llTotal := 1;
Prog.sStatus := 'DONE';
SendCampaignProgress(pEnt, Prog);
end;
procedure TManagerCampaign.SendPrintTest;
var
O: ISuperObject;
sPath,
sCompId,
sThumIds: String;
sCode,
sMsg: String;
dt: TDateTime;
begin
try
sCode := LOGCODE_EVENT_PRINTER;
sMsg := 'print test';
_Trace('SendPrintLog > Code=%s, Msg=%s', [LOGCODE_EVENT_PRINTER, 'print test'], 3);
sThumIds := '';
sPath := 'C:\Users\kku\Desktop\새 폴더\TEST.txt - 메모장.png';
sCompId := gMgSvc.MakeComponentId(ExtractFileName(sPath));
SumString(sThumIds, sCompId, ';');
gMgSvc.SendFileNor(false, sCompId, 'printLogCollect.do', sPath);
sPath := 'C:\Users\kku\Desktop\새 폴더\TEST.txt - 메모장_0002.png';
sCompId := gMgSvc.MakeComponentId(ExtractFileName(sPath));
SumString(sThumIds, sCompId, ';');
gMgSvc.SendFileNor(false, sCompId, 'printLogCollect.do', sPath);
sPath := 'C:\Users\kku\Desktop\이전 바탕화면\TEST.txt';
sCompId := gMgSvc.MakeComponentId(ExtractFileName(sPath));
gMgSvc.SendFileNor(false, sCompId, 'printLogCollect.do', sPath);
dt := Now;
O := SO;
O.S['TYP_MSG'] := '@(!)_IC_M';
O.S['KEY_AGENTID'] := gMgSvc.AgentId;
O.S['KEY_EMPNO'] := gMgSvc.EmpNo;
O.S['KEY_HOSTNAME'] := gMgSvc.UserName;
O.S['KEY_SUBMITTIME'] := FormatDateTime('yyyy-mm-dd hh:nn:ss', dt);
O.S['key_submitTime'] := FormatDateTime('yyyy-MM-dd"T"hh:nn:ss.zzz', dt) + sUtcOffset_;
O.S['KEY_LOGCODE'] := sCode;
O.S['DETECTION_DATE'] := O.S['KEY_SUBMITTIME']; // 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각
O.S['detectionDate'] := O.S['key_submitTime']; // 이벤트 발생 시각. REQUEST의 경우, 예외 신청할 이벤트의 발생 시각
O.S['KEY_SUMMARY'] := sMsg;
// O.S['PARENT_LA_ID'] // 상위 이벤트
O.S['POLICY_ID'] := gMgSvc.ModePolicy.PolicyId;
// O.S['POLICY_KEY'] // 정책 위반한 경우 (PREVENT, MONITOR), 위반한 정책의 정책 키 값, 수집인 경우 (DEPLOY), 수집 요청 ID
// O.S['MESSAGE_BODY'] // 정책 위반한 경우 (PREVENT, MONITOR), 원문 (본문) 컨텐츠, 수집인 경우 (DEPLOY), 수집 결과 내용, 원문 수집 정책이 비활성화인경우 수집하지 않음
O.S['OCR_BODY'] := 'ocr text!!!!'; // 이미지 OCR 추출된 컨텐츠, 원문 수집 정책이 비활성화인 경우 수집하지 않음
// O.S['RULE_VIOLATED'] // 정책 위반 규칙과 위반 개수. (LIST)
O.S['COMPONENT_ID'] := sCompId; // 파일 고유값. 에이전트에서 임의 생성. (이벤트간 동일 파일 판단은 서버에서 하겠습니다.)
O.S['COMPONENT_FILENAME'] := ExtractFileName(sPath); // 파일명
O.S['COMPONENT_PATH'] := ExtractFilePath(sPath);// 파일 절대 경로
// O.S['COMPONENT_METADATA']
// O.S['COMPONENT_LASTACCESS'] // 파일 최종 접근 일시
O.S['COMPONENT_THUMBNAIL_ID'] := sThumIds; // 이미지 미리보기 혹은 이미지가 있는경우, 이미지 파일의 파일 고유값. (출력물의 경우 첫 3장 이미지, 캡쳐 이미지 등), 복수개 허용, ";" 구분
// O.S['SOURCE_IP'] // 이벤트 발생 시점의 에이전트 IP. 단, 외부에서 수신하는 이벤트의 경우, 발송지의 IP가 되고, DESTINATION_URL이 에이전트 IP가 된다
// O.S['SOURCE_PORT'] // 송신지 사용 포트
// O.S['EMAIL_SENDER'] // 메일 발신자
// O.S['DESTINATION_URL'] // 수신지 URL (혹은 IP)
// O.S['DESTINATION_PORT'] // 수신지 포트
// O.S['EMAIL_RECIPIENT'] // 메일 수신자 ; 로 구분
// O.S['EMAIL_SUBJECT'] // 메일 제목
// O.S['APPLICATION_NAME'] // 사용 APP 이름
// O.S['APPLICATION_PATH'] // 사용 APP 절대 경로 (실행 파일 exe의 절대 경로)
O.S['PRINTER_JOBNAME'] := 'TEST.txt 출력 테스트';
O.S['PRINTER_METADATA'] := '{"PAGEINFO": "2/2", "COLOR": "true", "WARTERMARK": "false"}';
// O.S['REMOVABLE_NAME'] := aExptInfo.sDevName; // USB등과 같은 매체 혹은 프린터 등과 같은 외부 장치 이름
// O.S['REMOVABLE_DEVICEID'] := aExptInfo.sSerial; // USB등과 같은 매체 혹은 프린터 등과 같은 외부 장치 Device ID
// O.S['DEVICE_TYPE'] := IntToStr(Integer(aExptInfo.ReqDevType)); // 의미 없어서 제외 23_0822 12:40:55 kku
// O.S['REMOVABLE_CLASSID'] // USB등과 같은 매체 혹은 프린터 등과 같은 외부 장치 Class ID
// O.S['RESPONSE_INFO'] // 적용된 대응 정보 (DELETE, DRM, POPUP, LOG, EXCEPT 등)
// O.S['RESPONSE_RESULT'] // 적용된 대응 적용 결과 (true / false / pending / decline)
// O.S['REQUEST_COMMENT'] := sComment; // 사용자가 기입하는 요청 코멘트
// O.S['REQUEST_DUEDATE'] := sDueDate; // 사용자가 기입하는 예외 기간 (언제 까지. 최종일)
// O.S['REQUEST_TARGET'] := IntToStr(nTarget); // 사용자가 기입하는 예외 대상 (0 - 해당 pc, 1 - 해당 사용자, 2 - 해당 부서, 3-전체)
// gMgSvc.EventLog.Push(O.AsString);
gMgSvc.EventLog.Push(O.AsJSon);
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. SendEventLog()');
end;
end;
end.