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/ICQ/Protocol_ICQ.pas

909 lines
30 KiB
Plaintext

{
This file is part of R&Q.
Under same license
}
unit Protocol_ICQ;
{$I RnQConfig.inc}
interface
uses
System.Classes, outboxlib, events, ICQCommon, ICQContacts, ICQConsts, ICQSession, RDGLobal;
{$I NoRTTI.inc}
procedure ChangeXStatus(pICQ: TICQSession; const st: Byte; const StName: String = ''; const StText: String = '');
procedure LogICQPacket(What: TWhatLog; const Method, Caption: String; const Data: String = '');
// function findICQViewInfo(c:TRnQContact):TviewInfoFrm;
procedure ProcessICQEvents(var thisICQ: TICQSession; ev: TICQEvent);
//function statusName(s:Tstatus):string;
function StatusNameExt2(s: Byte; extSts: Byte = 0; const Xsts: String = ''; const sts6: String = ''): String;
function Status2ImgName(s: Byte; inv: Boolean = False): TPicName;
function Status2ImgNameExt(s: byte; inv: Boolean = False; extSts: byte= 0):TPicName;
function XStatus2Text(const XStatus: String): String;
// function Visibility2ImgName(vi:Tvisibility):String;
function VisibilityName(vi: TVisibility): String;
function GetRnQVerFor(c: TICQContact): Integer;
procedure UpdateClients;
procedure SetProgBar(const proto: TICQSession; v: Double);
implementation
uses
System.SysUtils, System.DateUtils, Vcl.Forms,
{$IFDEF UNICODE}
System.AnsiStrings,
{$ENDIF}
SciterLib, GlobalLib, UtilLib, RoasterLib, PluginLib, PluginUtil,
RQUtil, RQlog, RnQLangs, RnQStrings, RQThemes, RDUtils, RnQTrayLib, RnQGlobal, RnQPics, RnQ_Avatars,
Protocols_all, history, ChatBox, SQLiteDB;
const
LogWhatNames: Array [TWhatLog] of String = ('CONNECTED', 'DISCONNECTED', 'CLIENT', 'SERVER', 'DC RCVD', 'DC SENT',
'CONNECTING', 'CLIENT', 'SERVER'{$IFDEF DEBUG_PACKETS}, 'UNKNOWN'{$ENDIF DEBUG_PACKETS});
procedure ChangeXStatus(pICQ: TICQSession; const st: Byte; const StName: String = ''; const StText: String = '');
var
b: Boolean;
begin
if (st in [Low(XStatusArray)..High(XStatusArray)])
// and ((UseOldXSt and (xsf_Old in XStatusArray[st].flags))
// or (xsf_6 in XStatusArray[st].flags))
then
begin
b := pICQ.curXStatus <> st;
// if StName > '' then
if StName <> getTranslation(ExtStsStrings[st].Cap) then
begin
b := True;
ExtStsStrings[st].Cap := Copy(StName, 1, 100);
end;
// if StText > '' then
if StText <> getTranslation(ExtStsStrings[st].Desc) then
begin
b := True;
ExtStsStrings[st].Desc := Copy(StText, 1, 255);
end;
// RnQmain.sBar.Repaint;
if b then
begin
// saveListsDelayed := True;
ActionManager.Execute(AK_SAVEXSTATUSES, SaveDelay);
// SaveExtSts;
end;
end;
end;
procedure LogICQPacket(What: TWhatLog; const Method, Caption: String; const Data: String = '');
var
Head: String;
begin
Head := Caption + ' ' + LogWhatNames[What];
if not (Data = '') and not (What in [WL_connecting, WL_connected, WL_disconnected]) then
Head := Head + ' size: ' + IntToStr(Length(Data), 4);
LogProtoPacket(What, Method, Head, Data)
end;
function StatusNameExt2(s: Byte; extSts: Byte = 0; const Xsts: String = ''; const sts6: String = ''): String;
begin
if (s = Byte(SC_ONLINE)) and (extSts > 0) then
begin
if XSts > '' then
// result := getTranslation(Xsts)
result := Xsts
else
if sts6 > '' then
result := sts6
else
// result := getTranslation(XStatusArray[extSts].Caption)
result := getTranslation(status2ShowStr[TICQstatus(s)])
end
else
// if sts6 > '' then
// result := sts6
// else
result := getTranslation(status2ShowStr[TICQstatus(s)])
end;
function Status2ImgName(s: Byte; inv: Boolean = False): TPicName;
const
Prefix = 'status.';
begin
if s in [Byte(LOW(status2Img))..Byte(HIGH(status2Img))] then
Result := Prefix + status2Img[s]
else
Result := Prefix + status2Img[byte(SC_UNK)];
if inv then
Result := INVIS_PREFIX + Result;
end; // status2imgdx
function Status2ImgNameExt(s: byte; inv: Boolean = False; extSts: byte= 0):TPicName;
const
prefix = 'status.';
begin
if False{XStatusAsMain} and (extSts > 0) then
result := XStatusArray[extSts].Status
else
begin
if s in [byte(SC_ONLINE)..byte(SC_Last)] then
result := prefix + status2Img[s]
else
result := prefix + status2Img[Byte(SC_UNK)];
if inv then
result := INVIS_PREFIX + result;
end;
end; // status2imgdx
function XStatus2Text(const XStatus: String): String;
begin
Result := '';
for var XSt in XStatusArray do
if XSt.Status = XStatus then
begin
Result := GetTranslation(XSt.Text);
Break;
end;
end;
function VisibilityName(vi: TVisibility): String;
begin
Result := GetTranslation(Visibility2ShowStr[vi])
end;
procedure ProcessICQEvents(var thisICQ: TICQSession; ev: TICQEvent);
var
c: TICQContact;
b: Boolean;
i: Integer;
sU, Temp: String;
e, TempEv: Thevent;
TempHist: Thistory;
vS: AnsiString;
cuid: TUID;
DlgType: TMsgDlgType;
begin
c := thisICQ.eventContact;
thisICQ.eventContact := nil;
if Assigned(c) then
cuid := c.uid
else
cuid := '';
// these icqevents are associated with hevents
if ev in [IE_msg, IE_buzz, IE_contacts, IE_authReq, IE_addedyou, IE_incoming, IE_outgoing, IE_auth, IE_authDenied,
IE_MsgPatchUpdate, IE_statuschanged, IE_ack, IE_typing, IE_ackXStatus, IE_MultiChat] then
begin
e := Thevent.new(EK_null, nil, c, thisICQ.eventTime, '', [], thisICQ.eventFlags, thisICQ.eventMsgID, thisICQ.eventWID);
e.otherpeer := c;
if ev in [IE_contacts] then
begin
e.cl := thisICQ.eventContacts.clone;
e.cl.remove(thisICQ.getMyInfo);
e.cl.remove(c);
end else if ev in [IE_authreq] then
e.setText(UnUTF(thisICQ.eventMsgA))
else if ev in [IE_authDenied] then
e.setData(UnUTF(thisICQ.eventMsgA), []);
end else
e := nil;
case ev of
IE_serverAck:
begin
i := Account.acks.FindID(thisICQ.eventData);
if i >= 0 then // exploit only for automsgreq
// if Account.acks.getAt(i).kind = OE_msg then
begin
c := Account.acks.GetAt(i).whom;
TempHist := Thistory.Create(c.UID);
TempEv := TempHist.GetByMsgID(Account.acks.GetAt(i).ID);
if Assigned(TempEv) and TempEv.outgoing then
begin
if thisICQ.eventWID = '' then
thisICQ.eventWID := TempEv.WID
else
TempEv.WID := thisICQ.eventWID;
if thisICQ.eventMsgID = 0 then
thisICQ.eventMsgID := TempEv.ID
else
TempEv.ID := thisICQ.eventMsgID;
if thisICQ.eventMsgA = 'sent' then
TempEv.flags := TempEv.flags or IF_Server_Accept
else if thisICQ.eventMsgA = 'failed' then
TempEv.flags := TempEv.flags or IF_Not_Delivered
else if thisICQ.eventMsgA = 'delivered' then
TempEv.flags := TempEv.flags or IF_Delivered;
TempHist.WriteMsgIDs(Account.acks.GetAt(i).ID, thisICQ.eventMsgID, thisICQ.eventWID);
TempHist.WriteMsgFlags(TempEv.ID, TempEv.flags);
Account.acks.SetID(i, TempEv.ID);
UI.Chat.UpdateMsgStatus(TempEv);
if not (TempEv.WID = '') and not (TempEv.ID = 0) then
Account.acks.Delete(i);
FreeAndNil(TempEv);
end;
FreeAndNil(TempHist);
// if (Account.acks.getAt(i).flags and IF_Simple > 0) then
// Account.acks.Delete(i);
end
end;
IE_srvSomeInfo:
begin
i := Account.acks.FindID(thisICQ.eventData);
if i >= 0 then
with Account.acks.GetAt(i) do
begin
if kind = OE_MSG then
Account.acks.Delete(i);
end;
end;
IE_msgError:
begin
i := Account.acks.FindID(thisICQ.eventData);
if i >= 0 then
with Account.acks.GetAt(i) do
begin
if kind = OE_MSG then
begin
c := whom;
if not c.isOnline then
begin
if (info = 'MSG') then
begin
TempHist := Thistory.Create(c.UID);
TempEv := TempHist.getByMsgID(thisICQ.eventMsgID);
if Assigned(TempEv) and TempEv.outgoing then
begin
TempEv.flags := TempEv.flags or IF_not_delivered;// IF_MSG_OK;
TempHist.WriteMsgFlags(TempEv.ID, TempEv.flags);
UI.Chat.UpdateMsgStatus(TempEv);
FreeAndNil(TempEv);
end;
FreeAndNil(TempHist);
end;
end else if (info = 'MSG') then
begin
TempHist := Thistory.Create(c.UID);
TempEv := TempHist.getByMsgID(thisICQ.eventMsgID);
if Assigned(TempEv) and TempEv.outgoing then
begin
TempEv.flags := TempEv.flags or IF_not_delivered;// IF_MSG_OK;
TempHist.WriteMsgFlags(TempEv.ID, TempEv.flags);
UI.Chat.UpdateMsgStatus(TempEv);
FreeAndNil(TempEv);
end;
FreeAndNil(TempHist);
end;
// if not thisICQ.imVisibleTo(c) then
// addTempVisibleFor(5, c);
// Do not remove and wait for received ack if sending to offline client,
// because sometimes it's not even an error when multiple clients are connected
if not (thisICQ.eventInt = 4) then
Account.acks.Delete(i);
end;
end;
end;
IE_Missed_MSG:
begin
sU := getTranslation('You have missed %d messages from %s!', [thisICQ.eventMsgID, c.displayed]);
sU := sU + CRLF + getTranslation('Reason') + ': ' + getTranslation(icq_missed_msgs[thisICQ.eventInt]);
MsgDlg(sU, False, mtWarning);
end;
IE_sendingXStatus:
begin
thisICQ.eventMsgA := UTF(getXStatusMsgFor(c));
Vs := plugins.castEv(PE_XSTATUSMSG_SENDING, cuid, thisICQ.eventInt, UTF(thisICQ.eventNameA), thisICQ.eventMsgA);
if not isAbort(vS) then
begin
if (vS > '') then
if (ord(vS[1]) = PM_DATA) then
try
i := _int_at(vS, 2);
// thisICQ.eventName := UnUTF(_istring_at(vS, 2));
thisICQ.eventNameA := _istring_at(vS, 2); // In UTF8
if length(vS)>2+4+ i then
// thisICQ.eventMsg := UnUTF(_istring_at(vS, 2+4+ i))
thisICQ.eventMsgA := _istring_at(vS, 2+4 + i) // In UTF8
// else
// oe.info := send_msg;
except
thisICQ.eventNameA := '';
thisICQ.eventMsgA := UTF(getXStatusMsgFor(c));
end else if (ord(vS[1]) = PM_ABORT) then
begin
thisICQ.eventMsgA := '';
thisICQ.eventNameA := '';
end;
end else
begin
thisICQ.eventMsgA := '';
thisICQ.eventNameA := '';
end
end;
IE_ack:
begin
TempHist := Thistory.Create(c.UID);
TempEv := TempHist.GetByMsgID(thisICQ.eventMsgID);
if Assigned(TempEv) and TempEv.outgoing then
begin
TempEv.flags := TempEv.flags or IF_delivered;
TempHist.WriteMsgFlags(TempEv.ID, TempEv.flags);
UI.Chat.UpdateMsgStatus(TempEv);
end;
FreeAndNil(TempEv);
FreeAndNil(TempHist);
end;
IE_MsgDecryptFailed:
begin
TempHist := Thistory.Create(c.UID);
TempEv := TempHist.GetByMsgID(thisICQ.eventMsgID);
if Assigned(TempEv) and TempEv.outgoing then
begin
TempEv.flags := TempEv.flags or IF_Not_Delivered;
TempHist.WriteMsgFlags(TempEv.ID, TempEv.flags);
UI.Chat.UpdateMsgStatus(TempEv);
end;
FreeAndNil(TempEv);
FreeAndNil(TempHist);
end;
IE_authDenied:
begin
// case thisICQ.eventAccept of
// AC_OK:
begin
plugins.castEv( PE_AUTH_GOT, cUID);
MsgDlg(getTranslation('%s was grant you an autorization', [c.displayed]), False, mtInformation);
end;
// AC_denied:
begin
plugins.castEv( PE_AUTHDENIED_GOT, cUID);
MsgDlg(getTranslation('%s was declined you an autorization', [c.displayed]), False, mtInformation);
end;
// end;
end;
IE_toofast: MsgDlg('You''re sending too fast!', True, mtWarning);
IE_pause: MsgDlg('You''ll be disconnected soon because server was paused.', True, mtWarning);
IE_resume: MsgDlg('Server was resumed, you may not be disconnected after all.', True, mtWarning);
IE_MyInfoAck: MsgDlg('Your information has been saved', True, mtInformation);
IE_wpEnd,
IE_userSimpleInfo,
IE_wpResult:
begin
end;
IE_serverSent: LogICQPacket(WL_serverSent, thisICQ.eventNameA, thisICQ.eventMsgA, thisICQ.eventData);
IE_serverGot: LogICQPacket(WL_serverGot, thisICQ.eventNameA, thisICQ.eventMsgA, thisICQ.eventData);
IE_connecting:
begin
LogICQPacket(WL_connecting, '', '', thisICQ.eventAddress);
DisableSounds := False;
SetProgBar(thisICQ, 1/progLogonTotal);
end;
IE_loggin: SetProgBar(thisICQ, 2/progLogonTotal);
IE_connected:
begin
LogICQPacket(WL_connected, '', '', thisICQ.eventAddress);
SetProgBar(thisICQ, 3/progLogonTotal);
end;
IE_redirecting:
begin
LogICQPacket(WL_connecting, '', '', thisICQ.eventAddress);
SetProgBar(thisICQ, 4/progLogonTotal);
end;
IE_redirected: SetProgBar(thisICQ, 5/progLogonTotal);
IE_almostonline: SetProgBar(thisICQ, 6/progLogonTotal);
IE_visibilityChanged:
begin
if Assigned(c) then
begin
plugins.castEv(PE_VISIBILITY_CHANGED, cuid);
roasterLib.Update(c)
end else
plugins.castEv(PE_VISIBILITY_CHANGED, '');
UI.CL.UpdateStatusGlyphs;
UI.CL.UpdateVisibilityImage;
Account.AccProto.AbortPolling;
end;
IE_error:
if thisICQ.eventError = EC_Login_Seq_Failed then
begin
SetProgBar(thisICQ, 0);
MsgDlg(GetTranslation(icqerror2str[thisICQ.eventError], [thisICQ.eventMsgA]), False, mtError)
end else if
(thisICQ.eventError = EC_MalformedMsg) or
(thisICQ.eventError = EC_FailedDecrypt) or
(thisICQ.eventError = EC_FailedDecryptNotif) or
(thisICQ.eventError = EC_StoreProblem) then
begin
if (thisICQ.eventError = EC_FailedDecrypt) and thisICQ.eventInBackground then
// Ignore decryption error for old messages from server history, most of them won't be decrypted
else
MsgDlg(GetTranslation(icqerror2str[thisICQ.eventError], [thisICQ.eventMsgA]), False, mtError)
end else if thisICQ.eventError = EC_AddContact_Error then
begin
DlgType := mtError;
case thisICQ.eventInt of
1: thisICQ.eventMsgA := 'Server DB error';
3: begin thisICQ.eventMsgA := 'Contact was already in your CL, fetching it again'; DlgType := mtInformation; end;
13: thisICQ.eventMsgA := 'Request was not executed';
17: thisICQ.eventMsgA := 'Too many contacts in your CL';
26: thisICQ.eventMsgA := 'Operation timed out on server';
end;
MsgDlg(getTranslation(icqerror2str[thisICQ.eventError], [getTranslation(thisICQ.eventMsgA)]), False, DlgType);
end else if thisICQ.eventError = EC_badContact then
LogEvent(format('ERROR: bad contact: %s',[cuid]))
else
begin
SetProgBar(thisICQ, 0);
theme.PlaySound(Str_Error); //sounds.onError);
if (thisICQ.eventError in [
EC_badUIN,
EC_badPwd,
EC_proxy_badPwd,
// EC_anotherLogin,
EC_invalidFlap,
EC_missingLogin
]) then
StayConnected := False;
if thisICQ.eventError = EC_rateExceeded then
begin
SkipAutoconnect := True;
MsgDlg(GetTranslation(ICQError2Str[thisICQ.eventError], [thisICQ.eventInt, thisICQ.eventMsgA]), False, mtError);
end else if thisICQ.eventError = EC_missingLogin then
if thisICQ.enterPWD then
if not (thisICQ.eventData = 'pwdonly') then
DoConnect
else
else
else if thisICQ.eventError = EC_badPwd then
begin
sU := thisICQ.pwd;
thisICQ.pwd := '';
if thisICQ.enterPWD then
begin
thisICQ.Disconnect;
DoConnect;
end else
thisICQ.pwd := sU;
end else if thisICQ.eventError = EC_other then
begin
case TICQAuthError(thisICQ.eventInt) of
EAC_Not_Enough_Data: Temp := 'Failed to get all the data required for starting a new session';
EAC_Unknown: Temp := 'Unknown error';
EAC_Wrong_Login: Temp := 'Wrong login';
EAC_Invalid_Request: Temp := 'Invalid request';
EAC_Auth_Required: Temp := 'Authorization required';
EAC_Req_Timeout: Temp := 'Request timeout';
EAC_Send_Rate_Limit: Temp := 'Messages are sent too often';
EAC_Wrong_DevKey: Temp := 'Wrong DevId key';
EAC_Session_Not_Found: Temp := 'Session not found';
EAC_Missing_Req_Param: Temp := 'Missing required parameter';
EAC_Param_Error: Temp := 'Parameter error';
EAC_Rate_Limit: Temp := 'Request was rate limited';
EAC_SMS_Rate_Limit: Temp := 'SMS code is being requested too often';
EAC_Server_Error: Temp := 'Server error';
EAC_Invalid_Target: Temp := 'Invalid target';
EAC_Target_Doesnt_Exist: Temp := 'Target doesn''t exist';
EAC_Target_Not_Available: Temp := 'Target is not available';
EAC_CAPTCA: Temp := 'CAPTCHA required';
EAC_Message_Too_Big: Temp := 'Message is too big';
end;
Temp := GetTranslation(Temp);
if not (thisICQ.eventMsgA = '') then
Temp := Temp + #13#10 + String(thisICQ.eventMsgA);
SetProgBar(thisICQ, 0);
MsgDlg(Temp, False, mtError);
end else if ShowDisconnectedDlg and not (thisICQ.eventError in [
EC_rateExceeded,
EC_cantConnect,
EC_socket,
EC_serverDisconnected,
EC_loginDelay,
EC_invalidFlap
]) then
MsgDlg(getTranslation(icqerror2str[thisICQ.eventError], [thisICQ.eventInt, thisICQ.eventMsgA]), False, mtError);
end;
IE_statuschanged:
begin
if not Assigned(c) then //or thisICQ.isMyAcc(c) then
begin
plugins.castEv(PE_STATUS_CHANGED, cuid, thisICQ.GetStatus, byte(thisICQ.eventOldStatus), thisICQ.IsInvisible, thisICQ.eventOldInvisible);
UpdateViewInfo(thisICQ.GetMyInfo);
if thisICQ.GetStatus <> Byte(SC_OFFLINE) then
LastStatus := thisICQ.GetStatus;
UI.CL.UpdateStatusGlyphs;
// roasterLib.Redraw;
end
else
begin
plugins.castEv(PE_STATUS_CHANGED, cuid, Byte(c.status), byte(thisICQ.eventOldStatus), False, thisICQ.eventOldInvisible);
UpdateViewInfo(c);
if c.IsInRoster then
begin
if c.status = SC_OFFLINE then
c.SetOffline;
roasterLib.Update(c);
e.setBinary([Integer(c.status), False, c.xStatus]);
//if //(c.xStatus > 0) or
//(c.xStatusDesc > '') then
//begin
// e.setText(c.xStatusDesc);
// e.flags := e.flags or IF_XTended_EVENT;
//end;
if incomingOnAway
and (thisICQ.eventOldStatus in [SC_AWAY, SC_NA])
and not (c.status in [SC_AWAY, SC_NA])
and (NoIncomingCounter = 0) then
behave(e, EK_incoming)
else
behave(e, EK_statuschange);
end;
end;
if Assigned(UI.Chat) then
UI.Chat.RefreshTaskbarButtons;
end;
IE_xstatuschanged:
begin
if Assigned(c) then
begin
UpdateViewInfo(c);
if c.IsInRoster then
roasterLib.UpdateInPlace(c);
end;
end;
IE_avatar_changed:
if thisICQ.AvatarsSupport then
begin
if thisICQ.AvatarsAutoGet then
begin
reqAvatarsQ.add(c);
ActionManager.Execute(AK_PROCESSAVATARDOWNLOAD, 1000);
end else if c.icon.ToShow = IS_AVATAR then
ClearAoP(c, 0);
// if ShowAvt then
if TO_SHOW_ICON[CNT_ICON_AVT] then
UpdateInPlace(c);
end;
IE_ackXStatus:
begin
c.StatusStr := excludeTrailingCRLF(UnUTF(thisICQ.eventMsgA));
c.XStatus := excludeTrailingCRLF(UnUTF(thisICQ.eventData));
if c.XStatusIndex > 0 then
e.setData(c.StatusStr + dword_Zero + c.XStatus, [c.XStatusIndex])
else
e.setBinary([Byte(0)]);
behave(e, EK_XstatusMsg);
UpdateViewInfo(c);
end;
IE_online,
IE_offline:
begin
b := false;
// b := myStatus <> byte(SC_OFFLINE);
// myStatus:= thisICQ.getStatus;
b := b or (thisICQ.getStatus <> byte(SC_OFFLINE));
b := b or (ev = IE_offline);
setProgBar(thisICQ, 0);
if ev = IE_online then
begin
// <20><> <20><>
{$IFDEF USE_BALOONS}
statusIcon.showballoon(2000, getTranslation('Online'), Application.MainForm.Caption, bitInfo{, 'status.' + status2Img[thisICQ.getStatus]});
{$ENDIF USE_BALOONS}
CheckUpdate.Checking := False;
StayConnected := AutoReconnect;
CleanDisconnect := False;
SecondsCount15 := 0;
plugins.castEv(PE_CONNECTED);
ActionManager.Execute(AK_PROCESSOUTBOX);
UI.UpdateSessions;
end
else
begin
if clearPwdOnDSNCT and dontSavePwd then
if Assigned(thisICQ) and thisICQ.IsOffline then
thisICQ.pwd := '';
with TICQSession.contactsDB.clone do
begin
ForEach(procedure(cnt: TICQContact)
begin
cnt.OfflineClear;
cnt.Status := SC_UNK;
end);
Free;
end;
Account.acks.Clear;
plugins.castEv(PE_DISCONNECTED);
end;
NoIncomingCounter := 15;
if Assigned(UI.Chat) then
with UI.Chat do
begin
UpdateContactStatus;
RedrawTabs;
RefreshTaskbarButtons;
end;
UI.CL.UpdateStatusGlyphs;
if b then
roasterLib.RebuildCL;
UpdatePrefsFrm
end;
IE_numOfContactsChanged:
begin
contactsPnlStr := IntToStr(thisICQ.eventInt);
UI.CL.UpdateContactCount;
end;
IE_userinfo, IE_userinfoCP:
begin
plugins.castEv(PE_USERINFO_CHANGED, cuid);
UpdateViewInfo(c);
UI.Chat.UpdateGraphics(c);
if thisICQ.IsMyAcc(c) then
UI.CL.UpdateCaption;
roasterLib.UpdateInPlace(c);
ActionManager.Execute(AK_UPDATEDB, 1000);
end;
IE_incoming:
begin
plugins.castEv(PE_STATUS_CHANGED, cuid, Byte(c.status), Byte(thisICQ.eventOldStatus), False, False);
c.OnlineSince := Now;
roasterLib.Update(c);
TCE(c.data^).LastIncoming := thisICQ.eventTime;
UpdateViewInfo(c);
// Update caps when contact goes online (min 3 sec between updates to ignore blinking contacts)
if (c.LastCapsUpdate = 0) or (SecondsBetween(Now, c.LastCapsUpdate) >= 3) then
begin
c.LastCapsUpdate := Now;
thisICQ.GetContactInfo(c.UID, 'capabilities');
end;
thisICQ.EventResubscribe(c);
e.setBinary([Integer(c.status), False, c.xStatus]);
if NoIncomingCounter = 0 then
behave(e, EK_INCOMING)
else if NoIncomingCounter < 5 then
begin
Inc(NoIncomingCounter, 1);
BoundInt(NoIncomingCounter, 0, 5);
end;
end;
IE_outgoing:
begin
plugins.castEv(PE_STATUS_CHANGED, cuid, byte(c.status), byte(thisICQ.eventOldStatus), False, thisICQ.eventOldInvisible);
c.OfflineClear;
roasterLib.Update(c);
UpdateViewInfo(c);
behave(e, EK_OUTGOING);
end;
IE_contactupdate:
begin
roasterLib.Update(c);
UpdateViewInfo(c);
if Assigned(UI.Chat) then
UI.Chat.RefreshTaskbarButtons;
// autosizeDelayed := True;
end;
IE_contactSelfDeleted:
begin
MsgDlg(getTranslation('Contact %s [%s] Deleted himself from your Contact List', [c.displayed, c.uin2Show]), False, mtInformation);
roasterLib.Update(c);
UpdateViewInfo(c);
// autosizeDelayed:=TRUE;
end;
IE_contactupdateInPlace:
roasterLib.UpdateInPlace(c);
IE_typing:
if not filterRefuse(c) then
begin
roasterLib.UpdateInPlace(c);
if thisICQ.eventInt = MTN_CLOSED then
begin
// <20><> <20><>
end;
if c.typing.bIsTyping then
behave(e, EK_typingBeg)
else
behave(e, EK_typingFin);
end;
IE_contacts:
if not e.cl.empty
and not isAbort(plugins.castEv( PE_CONTACTS_GOT,cuid,e.flags,e.when,e.cl )) then
begin
e.setText(e.cl.tostring);
if behave(e, EK_contacts) then
NILifNIL(c);
end;
IE_authReq:
if not filterRefuse(c, '',IF_auth) and not isAbort(plugins.castEv(PE_AUTHREQ_GOT, cuid, e.flags, e.when, thisICQ.eventMsgA))
and behave(e, EK_authReq) then
begin
UpdateInPlace(c);
NILifNIL(c);
end;
IE_addedYou:
if not isAbort(plugins.castEv( PE_ADDEDYOU_GOT, cuid, e.flags, e.when ))
and behave(e, EK_addedyou) then
begin
UpdateInPlace(c);
NILifNIL(c);
end;
IE_buzz:
begin
if not thisICQ.eventInBackground then
if behave(e, EK_buzz) then
NILifNIL(c);
end;
IE_msg, IE_MultiChat:
if thisICQ.eventInBackground then
begin
e.kind := EK_msg;
if Length(thisICQ.eventData) > 0 then
e.parseData(thisICQ.eventData);
WriteToHistory(e);
end
else
begin
if (ev = IE_MultiChat) and (thisICQ.eventAddress > '') then
e.who := thisICQ.getICQContact(thisICQ.eventAddress);
// if thisICQ.eventEncoding = TEncoding.BigEndianUnicode then
// begin
// Temp := WideBEToStr(thisICQ.eventMsgA);
// vS := plugins.castEv(PE_MSG_GOT, cuid, e.flags, e.when, Temp);
// end else if thisICQ.eventEncoding = TEncoding.UTF8 then
// begin
// Temp := UnUTF(thisICQ.eventMsgA);
// vS := plugins.castEv(PE_MSG_GOT, cuid, e.flags, e.when, Temp);
// end else
// begin
// Temp := thisICQ.eventData;
// vS := plugins.castEv(PE_MSG_GOT, cuid, e.flags, e.when, thisICQ.eventData);
// end;
Temp := thisICQ.eventData;
vS := plugins.castEv(PE_MSG_GOT, cuid, e.flags, e.when, thisICQ.eventData);
if not isAbort(vS) then
begin
if (vS > '') and (ord(vS[1]) = PM_DATA) then
begin
Temp := _istring_at(vS, 2);
e.flags := e.flags and not IF_CODEPAGE_MASK; // Clear Encodings flags
e.flags := e.flags and not IF_Bin; // Clear bin flag
end;
if Length(Temp) > 0 then
e.parseData(Temp);
if behave(e, EK_msg) then
NILifNIL(c);
end;
end;
IE_MsgPatchUpdate:
begin
e.kind := EK_msg;
if Length(thisICQ.eventData) > 0 then
e.parseData(thisICQ.eventData);
WriteToHistory(e, nil, True);
UI.Chat.UpdateEvent(c, e.clone);
end;
IE_MsgPatchDelete:
begin
e := SQLDB.GetByMsgID(c.UID, thisICQ.eventMsgID, False);
if Assigned(e) then
UI.Chat.UpdateEvent(c, e.clone);
end;
IE_serverHistoryReady:
begin
if Assigned(UI.Chat) then
UI.Chat.ShowServerHistoryNotif(c.UID);
end;
IE_stickersupdate:
begin
if Assigned(UI.Chat) then
UI.Chat.LoadStickers;
end;
IE_stickersearchupdate:
begin
if Assigned(UI.Chat) then
UI.Chat.LoadSearchResults;
end;
IE_SmartReply:
begin
if Assigned(c) and Assigned(UI.Chat) then
begin
UI.Chat.SetSmartReplies(c, thisICQ.eventArray);
SetLength(thisICQ.eventArray, 0);
end;
end;
end;
if thisICQ.eventFlags and IF_offline > 0 then
if ev in [IE_msg, IE_MultiChat, IE_addedYou, IE_authReq, IE_contacts] then
// we already played a sound for the first offline message, let's make no other sound
disableSounds := True;
if Assigned(e) then
e.Free;
if Assigned(StatusIcon) then
StatusIcon.Update;
end;
function GetRnQVerFor(c: TICQContact): Integer;
var
s: RawByteString;
capa: RawByteString;
i:integer;
begin
result:=0;
if c=NIL then exit;
if result > 0 then exit;
s := c.extracapabilities;
while s > '' do
begin
capa:=chop(17,0,s);
if pos(AnsiString('R&Qinside'),capa) > 0 then
begin
{ result:='R&Q ';
if capa[14] = #1 then
result:=result + 'lite '
else if capa[14] = #2 then
result:=result + 'test ';
}
i := (Byte(capa[15]) shl 8) + Byte(capa[16]);
if i > 0 then
result := i
else
result := Byte(@capa[14]);
end;
end;
{if result > 0 then exit;
for I := CAPS_Ext_CLI_First to CAPS_Ext_CLI_Last do
if i in c.capabilitiesBig then
begin
result := BigCapability[i].s;
if i = CAPS_big_QIP then
if c.lastupdate_dw > 0 then
result := result + ' (' +ip2str(c.lastupdate_dw) + ')';
Exit;
end;
if CAPS_big_SecIM in c.capabilitiesBig then
begin
result := PIC_CLI_TRIL;
exit;
end;
}
end; // getRnQVerFor
procedure UpdateClients;
begin
if Assigned(Account.AccProto) and (Account.AccProto is TICQSession) then
for var cnt in Account.AccProto.readList(LT_ROSTER) do
Account.AccProto.GetClientPicAndDesc4(cnt, cnt.ClientPic, cnt.ClientDesc)
end;
procedure SetProgBar(const proto: TICQSession; v: Double);
begin
if Assigned(proto) then
proto.progLogon := v
else
progStart := v;
UI.CL.SetProgress(v);
if Assigned(StatusIcon) and Assigned(StatusIcon.TrayIcon) then
StatusIcon.TrayIcon.Update;
end;
end.