You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
9.9 KiB
Plaintext
393 lines
9.9 KiB
Plaintext
{
|
|
This file is part of R&Q.
|
|
Under same license
|
|
}
|
|
unit history;
|
|
{$I RnQConfig.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, classes, events, sysutils, graphics,
|
|
RDGlobal, RnQDialogs, RnQProtocol, DateUtils;
|
|
|
|
{$I NoRTTI.inc}
|
|
|
|
const
|
|
CRYPT_SIMPLE = 0;
|
|
CRYPT_KEY1 = 1;
|
|
|
|
type
|
|
Thistory = class
|
|
private
|
|
huid: TUID;
|
|
loading: boolean;
|
|
cryptMode: byte;
|
|
hashed: RawByteString;
|
|
function old_fromStream(str: Tstream; uid: TUID): boolean;
|
|
public
|
|
themeToken, SmilesToken: Cardinal;
|
|
old_eventList: TList;
|
|
|
|
constructor Create(const uid: TUID);
|
|
destructor Destroy;
|
|
class function getExistingChats: TUIDS;
|
|
function getAllEvents: Thevents;
|
|
function getLastEvents(offset, cnt: Integer; var noMoreMessages: Boolean): Thevents;
|
|
function getLastEvent(cnt: integer = 1): Thevent;
|
|
function getTimeRange(fromTime, toTime: TDateTime; var noMoreMessages: Boolean; toInclusive: Boolean = True): Thevents; overload;
|
|
function getTimeRange(fromTime, toTime: TDateTime): Thevents; overload;
|
|
function getByRowID(rowID: Int64): Thevent;
|
|
function getByMsgID(pID: Int64): Thevent;
|
|
function getByTime(time: TDateTime): Thevent;
|
|
function getByWID(const wid: String): Thevent;
|
|
function getBySender(const sender: TUID): Thevents;
|
|
procedure writeWID(MsgID: Int64; const WID: RawByteString);
|
|
procedure deleteFromToTime(st, en: TDateTime);
|
|
procedure deleteBySender(const sender: TUID);
|
|
function dataSearch(const txt: String; caseSensitive: Boolean = False): Thevents;
|
|
function old_Load(cnt: TRnQContact): boolean;
|
|
end; // Thistory
|
|
|
|
procedure DelHistWith(const uid: TUID);
|
|
function ExistsHistWith(const uid: TUID): boolean;
|
|
procedure WriteToHistory(ev: Thevent; other: TRnQContact = nil);
|
|
|
|
implementation
|
|
|
|
uses
|
|
RDFileUtil, RnQBinUtils,
|
|
RQUtil, RnQLangs,
|
|
utilLib, globalLib, SQLiteDB;
|
|
|
|
function Thistory.old_Load(cnt: TRnQContact): Boolean;
|
|
{$IFNDEF DB_ENABLED}
|
|
var
|
|
str: Tstream;
|
|
memstream: TMemoryStream;
|
|
{$ENDIF ~DB_ENABLED}
|
|
begin
|
|
Result := False;
|
|
if not Assigned(cnt) then
|
|
Exit;
|
|
// Result := fromString(loadFile(userPath+historyPath + uid), quite);
|
|
str := GetStream(Account.ProtoPath + historyPath + cnt.UID2cmp);
|
|
if Assigned(str) then
|
|
begin
|
|
str.Position := 0;
|
|
// Result := fromSteam(str, quite);
|
|
memstream := TMemoryStream.Create;
|
|
memstream.CopyFrom(str, str.Size);
|
|
memstream.Position := 0;
|
|
FreeAndNil(str);
|
|
Result := old_fromStream(memstream, cnt.UID2cmp);
|
|
FreeAndNil(memstream);
|
|
end else
|
|
Result := old_fromStream(nil, cnt.UID2cmp);
|
|
end;
|
|
|
|
constructor Thistory.Create(const uid: TUID);
|
|
begin
|
|
huid := uid;
|
|
if uid = '' then
|
|
old_eventList := TList.Create
|
|
else
|
|
old_eventList := nil;
|
|
end;
|
|
|
|
destructor Thistory.Destroy;
|
|
begin
|
|
if Assigned(old_eventList) then
|
|
FreeAndNil(old_eventList);
|
|
end;
|
|
|
|
function SortFunc(Item1, Item2: Pointer): Integer;
|
|
begin
|
|
Result := CompareDateTime(Thevent(Item1).when, Thevent(Item2).when);
|
|
end;
|
|
|
|
function Thistory.old_fromStream(str: Tstream; uid: TUID): boolean;
|
|
var
|
|
ev: Thevent;
|
|
thisCnt, thisCnt2: TRnQContact;
|
|
Cnt1I, Cnt2I: Int64;
|
|
// cur:integer;
|
|
|
|
function getByte: byte;
|
|
begin
|
|
str.Read(Result, 1);
|
|
// inc(cur)
|
|
end;
|
|
|
|
function getDatetime: Tdatetime;
|
|
begin
|
|
str.Read(Result, 8);
|
|
// inc(cur,8)
|
|
end;
|
|
|
|
function getInt: integer;
|
|
begin
|
|
str.Read(Result, 4);
|
|
// inc(cur,4);
|
|
end;
|
|
|
|
function getString: RawByteString;
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := getInt;
|
|
SetLength(Result, i);
|
|
str.Read(Result[1], i);
|
|
// inc(cur,length(result))
|
|
end;
|
|
|
|
procedure parseExtrainfo;
|
|
var
|
|
code, next, extraEnd: integer;
|
|
cur: integer;
|
|
s: AnsiString;
|
|
begin
|
|
cur := 1;
|
|
extraEnd := 4 + getInt;
|
|
inc(cur, 4);
|
|
while cur < extraEnd do
|
|
begin
|
|
code := getInt;
|
|
inc(cur, 4);
|
|
// inc(cur, 4);
|
|
next := cur + getInt + 4;
|
|
case code of
|
|
EI_flags:
|
|
begin
|
|
ev.flags := getInt;
|
|
// inc(cur, 4);
|
|
end;
|
|
EI_UID:
|
|
begin
|
|
// s := str.re
|
|
s := getString;
|
|
if Length(s) > 0 then
|
|
if Assigned(thisCnt) and thisCnt.equals(s) then
|
|
ev.who := thisCnt
|
|
else if Account.AccProto.getMyInfo.equals(s) then
|
|
ev.who := Account.AccProto.getMyInfo
|
|
else
|
|
begin
|
|
thisCnt := Account.AccProto.getContact(s);
|
|
ev.who := thisCnt;
|
|
end;
|
|
end;
|
|
EI_WID:
|
|
begin
|
|
ev.WID := getString;
|
|
end;
|
|
end;
|
|
cur := next;
|
|
end;
|
|
end; // parseExtraInfo
|
|
|
|
var
|
|
len: Int64;
|
|
// iu : TUID;
|
|
i: Integer;
|
|
curPos: Int64;
|
|
begin
|
|
loading := True;
|
|
try
|
|
// cur:=1;
|
|
cryptMode := CRYPT_SIMPLE;
|
|
hashed := '';
|
|
Cnt2I := 0;
|
|
Cnt1I := 0;
|
|
if not Assigned(str) then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
len := str.Size;
|
|
thisCnt := nil;
|
|
thisCnt2 := nil;
|
|
str.Seek(0, 0);
|
|
curPos := 0;
|
|
// while str.Position < len do
|
|
if len > 0 then
|
|
repeat
|
|
ev := Thevent.Create;
|
|
case getInt of
|
|
// case getInt1(str) of
|
|
HI_event:
|
|
begin
|
|
ev.cryptMode := cryptMode;
|
|
ev.kind := getByte;
|
|
begin
|
|
// iu := IntToStr(getInt);
|
|
i := getInt;
|
|
if i > 0 then
|
|
begin
|
|
if Assigned(thisCnt) and thisCnt.equals(i) then
|
|
begin
|
|
inc(Cnt1I);
|
|
ev.who := thisCnt
|
|
end
|
|
else if Account.AccProto.getMyInfo.equals(i) then
|
|
ev.who := Account.AccProto.getMyInfo
|
|
else if Assigned(thisCnt2) and thisCnt2.equals(i) then
|
|
begin
|
|
inc(Cnt2I);
|
|
ev.who := thisCnt2
|
|
end
|
|
else
|
|
begin
|
|
if not Assigned(thisCnt) or (Assigned(thisCnt2) and (Cnt2I > Cnt1I)) then
|
|
begin
|
|
Cnt1I := 0;
|
|
thisCnt := Account.AccProto.getContact(i);
|
|
ev.who := thisCnt;
|
|
end
|
|
else
|
|
begin
|
|
Cnt2I := 0;
|
|
thisCnt2 := Account.AccProto.getContact(i);
|
|
ev.who := thisCnt2;
|
|
end
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
// thisCnt := NIL;
|
|
ev.who := Account.AccProto.getMyInfo;
|
|
end
|
|
end;
|
|
ev.when := getDatetime;
|
|
parseExtrainfo;
|
|
ev.old_decryptInfo(getString);
|
|
old_eventList.add(ev);
|
|
end;
|
|
HI_hashed:
|
|
hashed := getString;
|
|
HI_cryptMode:
|
|
begin
|
|
// getInt; // skip length
|
|
str.Seek(4, soFromCurrent); // skip length
|
|
cryptMode := getByte;
|
|
end;
|
|
else
|
|
begin
|
|
TThread.Queue(nil, procedure
|
|
begin
|
|
msgDlg(getTranslation('The history of %s is corrupted, some data is lost', [uid]), True, mtError);
|
|
end);
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
curPos := str.Position;
|
|
until (curPos >= len);
|
|
Result := True;
|
|
finally
|
|
loading := false;
|
|
end;
|
|
end; // fromStream
|
|
|
|
class function Thistory.getExistingChats: TUIDS;
|
|
begin
|
|
Result := SQLHist.GetExistingChats;
|
|
end;
|
|
|
|
function Thistory.getAllEvents: Thevents;
|
|
begin
|
|
Result := SQLHist.GetAll(huid);
|
|
end;
|
|
|
|
function Thistory.getLastEvents(offset, cnt: Integer; var noMoreMessages: Boolean): Thevents;
|
|
begin
|
|
Result := SQLHist.GetLastMulti(huid, offset, cnt, noMoreMessages);
|
|
end;
|
|
|
|
function Thistory.getLastEvent(cnt: integer = 1): Thevent;
|
|
begin
|
|
Result := SQLHist.GetLastSingle(huid, cnt);
|
|
end;
|
|
|
|
function Thistory.getTimeRange(fromTime, toTime: TDateTime; var noMoreMessages: Boolean; toInclusive: Boolean = True): Thevents;
|
|
begin
|
|
Result := SQLHist.GetByTimeRange(huid, fromTime, toTime, noMoreMessages, toInclusive);
|
|
end;
|
|
|
|
function Thistory.getTimeRange(fromTime, toTime: TDateTime): Thevents;
|
|
var
|
|
dummy: Boolean;
|
|
begin
|
|
Result := SQLHist.GetByTimeRange(huid, fromTime, toTime, dummy);
|
|
end;
|
|
|
|
function Thistory.getByRowID(rowID: Int64): Thevent;
|
|
begin
|
|
Result := SQLHist.GetByRowID(huid, rowID);
|
|
end;
|
|
|
|
function Thistory.getByMsgID(pID: Int64): Thevent;
|
|
begin
|
|
Result := SQLHist.GetByMsgID(huid, pID);
|
|
end;
|
|
|
|
function Thistory.getByTime(time: TDateTime): Thevent;
|
|
begin
|
|
Result := SQLHist.GetByTime(huid, time);
|
|
end;
|
|
|
|
function Thistory.getByWID(const wid: String): Thevent;
|
|
begin
|
|
Result := SQLHist.GetByWID(huid, wid);
|
|
end;
|
|
|
|
function Thistory.getBySender(const sender: TUID): Thevents;
|
|
begin
|
|
Result := SQLHist.GetBySender(huid, sender);
|
|
end;
|
|
|
|
procedure Thistory.writeWID(MsgID: Int64; const WID: RawByteString);
|
|
begin
|
|
SQLHist.WriteWID(huid, MsgID, WID);
|
|
end;
|
|
|
|
procedure Thistory.deleteFromToTime(st, en: TDateTime);
|
|
begin
|
|
SQLHist.DeleteByTimeRange(huid, st, en);
|
|
end;
|
|
|
|
procedure Thistory.deleteBySender(const sender: TUID);
|
|
begin
|
|
SQLHist.DeleteBySender(huid, sender);
|
|
end;
|
|
|
|
function Thistory.dataSearch(const txt: String; caseSensitive: Boolean = False): Thevents;
|
|
begin
|
|
Result := SQLHist.DataSearch(huid, txt, caseSensitive);
|
|
end;
|
|
|
|
procedure DelHistWith(const uid: TUID);
|
|
begin
|
|
SQLHist.DeleteChat(uid);
|
|
end;
|
|
|
|
procedure WriteToHistory(ev: Thevent; other: TRnQContact = nil);
|
|
begin
|
|
ev := ev.clone;
|
|
if other <> nil then
|
|
ev.otherpeer := other;
|
|
if ev.otherpeer = nil then
|
|
ev.otherpeer := ev.chat;
|
|
if ev.otherpeer = nil then
|
|
ev.otherpeer := ev.who;
|
|
ev.WriteToHistory(ev.otherpeer.uid);
|
|
ev.Free;
|
|
end;
|
|
|
|
function ExistsHistWith(const uid: TUID): boolean;
|
|
begin
|
|
Result := SQLHist.ChatExists(uid);
|
|
end;
|
|
|
|
end.
|