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.
RnQ/RnQ/history.pas

410 lines
10 KiB
Plaintext

{
This file is part of R&Q.
Under same license
}
unit history;
{$I RnQConfig.inc}
interface
uses
System.Classes, System.SysUtils, System.DateUtils,
RDGlobal, ICQCommon, ICQContacts, SQLiteDB, events;
{$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; const UID: TUID): Boolean;
public
ThemeToken, SmilesToken: Cardinal;
old_EventList: TList;
constructor Create(const UID: TUID);
destructor Destroy; override;
class function getExistingChats: TUIDS;
function GetEventCount: Integer;
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(MsgID: TMsgID; Recent: Boolean = True): Thevent;
function GetByTime(Time: TDateTime): Thevent;
function GetByWID(const WID: String): Thevent;
function GetBySender(const Sender: TUID): Thevents;
procedure WriteMsgIDs(ReqID, MsgID: UInt64; const WID: RawByteString);
procedure WriteMsgFlags(MsgID: TMsgID; Flags: Integer);
procedure DeleteFromToTime(St, En: TDateTime);
procedure DeleteByMsgID(MsgID: TMsgID);
procedure DeleteBySender(const Sender: TUID);
function DataSearch(const Txt: String; CaseSensitive: Boolean = False): Thevents;
function old_Load(Cnt: TICQContact): Boolean;
end; // Thistory
procedure DelHistWith(const UID: TUID);
function ExistsHistWith(const UID: TUID): Boolean;
procedure WriteToHistory(ev: Thevent; other: TICQContact = nil; patch: Boolean = False);
implementation
uses
RDFileUtil, RQUtil, RnQLangs, globalLib;
function Thistory.old_Load(Cnt: TICQContact): 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 + AnsiLowerCase(cnt.UID));
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, AnsiLowerCase(Cnt.UID));
FreeAndNil(MemStream);
end else
Result := old_FromStream(nil, AnsiLowerCase(Cnt.UID));
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);
inherited;
end;
function SortFunc(Item1, Item2: Pointer): Integer;
begin
Result := CompareDateTime(Thevent(Item1).when, Thevent(Item2).when);
end;
function Thistory.old_FromStream(Str: TStream; const UID: TUID): Boolean;
var
ev: Thevent;
thisCnt, thisCnt2: TICQContact;
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 := SQLDB.GetExistingChats;
end;
function Thistory.GetEventCount: Integer;
begin
Result := SQLDB.GetEventCount(hUID);
end;
function Thistory.GetAllEvents: Thevents;
begin
Result := SQLDB.GetAllEvents(hUID);
end;
function Thistory.GetLastEvents(Offset, Cnt: Integer; var NoMoreMessages: Boolean): Thevents;
begin
Result := SQLDB.GetLastMulti(hUID, Offset, Cnt, NoMoreMessages);
end;
function Thistory.GetLastEvent(Cnt: integer = 1): Thevent;
begin
Result := SQLDB.GetLastSingle(hUID, Cnt);
end;
function Thistory.GetTimeRange(FromTime, ToTime: TDateTime; var NoMoreMessages: Boolean; ToInclusive: Boolean = True): Thevents;
begin
Result := SQLDB.GetByTimeRange(hUID, FromTime, ToTime, NoMoreMessages, ToInclusive);
end;
function Thistory.GetTimeRange(FromTime, ToTime: TDateTime): Thevents;
var
Dummy: Boolean;
begin
Result := SQLDB.GetByTimeRange(hUID, FromTime, ToTime, Dummy);
end;
function Thistory.GetByRowID(RowID: Int64): Thevent;
begin
Result := SQLDB.GetByRowID(hUID, RowID);
end;
function Thistory.GetByMsgID(MsgID: TMsgID; Recent: Boolean = True): Thevent;
begin
Result := SQLDB.GetByMsgID(hUID, MsgID, Recent);
end;
function Thistory.GetByTime(Time: TDateTime): Thevent;
begin
Result := SQLDB.GetByTime(hUID, Time);
end;
function Thistory.GetByWID(const WID: String): Thevent;
begin
Result := SQLDB.GetByWID(hUID, WID);
end;
function Thistory.GetBySender(const Sender: TUID): Thevents;
begin
Result := SQLDB.GetBySender(hUID, Sender);
end;
procedure Thistory.WriteMsgIDs(ReqID, MsgID: TMsgID; const WID: RawByteString);
begin
SQLDB.WriteMsgIDs(hUID, ReqID, MsgID, WID);
end;
procedure Thistory.WriteMsgFlags(MsgID: TMsgID; Flags: Integer);
begin
SQLDB.WriteMsgFlags(hUID, MsgID, Flags);
end;
procedure Thistory.DeleteFromToTime(St, En: TDateTime);
begin
SQLDB.DeleteByTimeRange(hUID, St, En);
end;
procedure Thistory.DeleteByMsgID(MsgID: TMsgID);
begin
SQLDB.DeleteByMsgID(hUID, MsgID);
end;
procedure Thistory.DeleteBySender(const Sender: TUID);
begin
SQLDB.DeleteBySender(hUID, Sender);
end;
function Thistory.DataSearch(const Txt: String; CaseSensitive: Boolean = False): Thevents;
begin
Result := SQLDB.DataSearch(hUID, Txt, CaseSensitive);
end;
procedure DelHistWith(const UID: TUID);
begin
SQLDB.DeleteChat(UID);
end;
procedure WriteToHistory(ev: Thevent; other: TICQContact = nil; patch: Boolean = False);
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, patch);
ev.Free;
end;
function ExistsHistWith(const UID: TUID): Boolean;
begin
Result := SQLDB.ChatExists(UID);
end;
end.