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/pluginLib.pas

1058 lines
36 KiB
Plaintext

{
This file is part of R&Q.
Under same license
}
{$I RnQConfig.inc}
unit pluginLib;
{$WARN IMPLICIT_STRING_CAST OFF}
{$WARN IMPLICIT_STRING_CAST_LOSS OFF}
{$WARN SUSPICIOUS_TYPECAST ERROR}
interface
uses
Winapi.Windows, System.Classes, System.Types, System.StrUtils, System.SysUtils, Vcl.Graphics,
events, RDGlobal, ICQCommon, ICQContacts, ICQConsts, RnQGraphics32, GR32;
{$I NoRTTI.inc}
{$I plugin.inc }
{ $I pluginutil.inc }
type
Tplugin = class
public
hnd: Thandle;
screenName, filename: string;
fun: TpluginFun;
funC: TpluginFunC;
active: boolean;
function activate: boolean;
procedure disactivate;
function cast(data: RawByteString): RawByteString;
procedure cast_preferences;
end;
Tplugins = class
private
enumIdx: integer;
list: Tlist;
public
constructor Create;
destructor Destroy; override;
procedure resetEnumeration;
function hasMore: boolean;
function getNext: Tplugin;
procedure load;
procedure unload;
function cast(const data: RawByteString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime; cl: TRnQCList): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime; const s1: AnsiString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime; const s1, s2: AnsiString)
: RawByteString; overload;
function castEv(ev_id: byte; when: Tdatetime; const name, addr, text: AnsiString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; flags: integer; const s1: AnsiString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; const s1: AnsiString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; const s1, s2: AnsiString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; b1: byte; const s1, s2: AnsiString): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; status, oldstatus: byte; inv, oldInv: boolean): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID): RawByteString; overload;
function castEv(ev_id: byte; uin: integer): RawByteString; overload;
function castEv(ev_id: byte; const uin: TUID; flags: integer; cl: TRnQCList): RawByteString; overload;
function castEv(ev_id: byte): RawByteString; overload;
function castEv(ev_id: byte; const s1, s2, s3: AnsiString; b: boolean; i: integer): RawByteString; overload;
function castEvList(ev_id: byte; list: byte; c: TICQContact): RawByteString;
end;
TPlugButton = class
proc: Pointer;
hint: String;
pic: AnsiString;
end;
TPlugButtons = class
public
btns: array of TPlugButton;
public
function Add(proc: Pointer; iIcon: HIcon; const bHint: String; const sPic: AnsiString = ''): integer;
procedure Del(bAddr: integer);
procedure Modify(bAddr: integer; iIcon: HIcon; const bHint: String; const sPic: AnsiString = '');
end;
implementation
uses
SciterLib, ThemesLib,
RQUtil, RnQLangs, RQThemes, RnQDialogs, RQLog, RnQTips, RDUtils, RnQGlobal,
ChatBox, outboxLib, globalLib, utilLib,
prefSheet, RnQPrefsLib, Protocols_all, Protocol_ICQ, pluginutil;
const
Status2OldStatus: array [TICQStatus] of Byte = (0, 6, 7, 1, 2, 3, 4, 5, 8, 9);
OldStatus2Status: array [TICQStatus] of Byte = (0, 3, 4, 5, 6, 7, 1, 2, 8, 9);
vis2OldVis: array [TOldVisibility] of Byte = (2, 0, 1, 3, 4);
OldVis2Vis: array [TOldVisibility] of Byte = (1, 2, 0, 3, 4);
var
// outBuffer:RawByteString; // callback result buffer
outBuffer00: RawByteString; // callback result buffer
function whatlist(id: byte): TRnQCList;
begin
case id of
PL_ROSTER:
result := Account.AccProto.readList(LT_ROSTER);
PL_IGNORELIST:
result := ignoreList;
PL_DB:
result := Account.AccProto.contactsDB;
PL_NIL:
result := notInList; // not in list
else
result := NIL;
end;
end; // whatlist
procedure addCL2list(id: byte; cl: TRnQCList);
begin
case id of
PL_DB:
Account.AccProto.contactsDB.Add(cl);
PL_NIL:
notInList.Add(cl); // not in list
// else result:=NIL;
end;
end; // whatlist
function add2list(id: byte; c: TICQContact): boolean;
begin
result := True;
case id of
PL_ROSTER:
Account.AccProto.AddToList(LT_ROSTER, c);
PL_IGNORELIST:
begin
result := True;
addToIgnorelist(c)
end;
PL_DB:
result := Account.AccProto.contactsDB.Add(c);
PL_NIL:
result := notInList.Add(c); // not in list
else
result := false;
end;
end;
function rem_fr_list(id: byte; c: TICQContact): boolean;
begin
result := True;
case id of
PL_ROSTER:
Account.AccProto.RemFromList(LT_ROSTER, c);
PL_IGNORELIST:
begin
result := True;
removeFromIgnorelist(c);
end;
PL_DB:
result := Account.AccProto.contactsDB.remove(c);
PL_NIL:
result := notInList.remove(c); // not in list
else
result := false;
end;
end;
function _contactinfo(c: TICQContact): RawByteString;
begin
if c = NIL then
begin
result := '';
exit;
end;
if c is TICQcontact then
result := _int(TICQcontact(c).uinInt) + AnsiChar(Status2OldStatus[TICQcontact(c).status]) // For old
+ AnsiChar(False) + _istring(c.displayed) + _istring(c.first) + _istring(c.last)
else
result := _int(StrToIntDef(c.uid, 0)) + AnsiChar(0) + AnsiChar(0) + _istring(c.displayed) + _istring(c.first) +
_istring(c.last);
end; // _contactinfo
function _icontactinfo(c: TICQContact): RawByteString;
begin
result := _istring(_contactinfo(c))
end;
function _get(what: byte): RawByteString;
begin
result := AnsiChar(PM_GET) + AnsiChar(what)
end;
function _event(what: byte): RawByteString;
begin
result := AnsiChar(PM_EVENT) + AnsiChar(what)
end;
// function callbackStr(const data:RawByteString):RawByteString; stdcall;
procedure callbackStr3(const data: RawByteString; var res: RawByteString);
var
resStr: RawByteString;
function minimum(min: integer): boolean;
begin
result := length(data) >= min;
if not result then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_BAD_REQ);
end; // minimum
const
tenthsPerDay = 10 * 60 * 60 * 24;
var
b: boolean;
i, k: integer;
Rect: TRect;
bmp: TBitmap;
bmp32: TBitmap32;
// R : TRect;
cl: TRnQCList;
cnt: TICQContact;
ints: TintegerDynArray;
rct: TRect;
tS, tS2: RawByteString;
sU: String;
PrefVal: TPrefElement;
vRnQpicEx: TRnQBitmap;
RnQPicStream: TMemoryStream;
begin
ints := NIL;
if data = '' then
begin
resStr := AnsiChar(PM_ACK) + AnsiChar(PA_OK);
// Result := resStr;
res := resStr;
exit;
end;
resStr := AnsiChar(PM_ABORT);
try
case _byte_at(data, 1) of
PM_CMD:
if minimum(2) then
case _byte_at(data, 2) of
PC_SET_AUTOMSG:
if minimum(2 + 4) then
;
PC_SEND_MSG:
if minimum(2 + 3 * 4) then
begin
// outbox.add(OE_msg, IntToStr(_int_at(data,3)), _int_at(data,7), _istring_at(data,11));
OutboxAdd(OE_msg, Account.AccProto.getContact(IntToStr(_int_at(data, 3))), _int_at(data, 7),
_istring_at(data, 11));
end;
PC_ADD_MSG:
if minimum(2 + 4 + 8 + 4) then // By Rapid D
with Account.AccProto do
begin
eventContact := getICQContact(_int_at(data, 3));
eventTime := _dt_at(data, 7);
eventFlags := 0;
Account.AccProto.AddMsg(0, True, _istring_at(data, 15));
end;
PC_POPUP_ADD:
if minimum(2 + 4 + 4) then // By Rapid D
begin
bmp := TBitmap.create;
bmp.Handle := _int_at(data, 3);
RnQPicStream := TMemoryStream.create;
bmp.SaveToStream(RnQPicStream);
vRnQpicEx := TRnQBitmap.create;
if loadPic(TStream(RnQPicStream), vRnQpicEx, 0, PA_FORMAT_UNK) then
begin
// TipAdd(bmp, _int_at(data,7));
UI.Tips.Add(nil, vRnQpicEx, nil, _int_at(data, 7));
end;
FreeAndNil(vRnQpicEx);
FreeAndNil(RnQPicStream);
// bmp.ReleaseHandle;
FreeAndNil(bmp);
end;
PC_ADD_TO_INPUT:
if minimum(2 + 4) then // By Rapid D
begin
if (UI.Chat.ThisChat <> nil) and (UI.Chat.ThisChat.chatType = CT_IM) then
begin
tS := _istring_at(data, 3);
sU := UnUTF(tS);
sU := applyVars(UI.Chat.ThisChat.who, sU);
UI.Chat.AddToCurrentInput(sU);
end;
end;
PC_SEND_CONTACTS:
if minimum(2 + 3 * 4) then
begin
OutboxAdd(OE_contacts, Account.AccProto.GetICQContact(_int_at(data, 3)),
_int_at(data, 7), ints2cl(Account.AccProto, _intlist_at(data, 11)));
end;
PC_SEND_ADDEDYOU:
if minimum(2 + 4) then
begin
OutboxAdd(OE_addedyou, Account.AccProto.GetContact(IntToStr(_int_at(data, 3))));
end;
PC_SEND_AUTOMSG_REQ:
if minimum(2 + 4) then
;
PC_LIST_REMOVE, PC_LIST_ADD:
if minimum(2 + 1 + 4) then
begin
k := _byte_at(data, 3);
// if cl=NIL then
// outBuffer:=char(PM_ERROR)+char(PERR_UNEXISTENT)
// else
begin
b := _byte_at(data, 2) = PC_LIST_ADD;
ints := _intlist_at(data, 4);
for i := 0 to length(ints) - 1 do
if b then
begin
if not add2list(k, Account.AccProto.GetContact(IntToStr(ints[i]))) then
ints[i] := 0;
end
else if not rem_fr_list(k, Account.AccProto.GetContact(IntToStr(ints[i]))) then
ints[i] := 0;
packArray(ints, 0);
if length(ints) > 0 then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_FAILED_FOR) + _intlist(ints);
ints := NIL;
end;
end;
PC_QUIT:
ActionManager.Execute(AK_QUIT, 500);
PC_SET_STATUS:
if minimum(2 + 1) then
Account.AccProto.UserSetStatus(OldStatus2Status[TICQStatus(_byte_at(data, 3))], Account.AccProto.getVisibility);
PC_SET_VISIBILITY:
if minimum(2 + 1) then
Account.AccProto.UserSetStatus(Account.AccProto.getStatus, oldVis2Vis[TOldVisibility(_byte_at(data, 3))]);
PC_SET_XSTATUS:
if minimum(2 + 1) then
begin
tS := '';
tS2 := '';
if length(data) > 2 + 1 + 4 then
tS := _istring_at(data, 2 + 1 + 1);
if length(data) > 2 + 1 + 4 + 4 + length(tS) then
tS2 := _istring_at(data, 2 + 1 + 4 + length(tS) + 1);
ChangeXStatus(Account.AccProto, (_byte_at(data, 3)), tS, tS2);
end;
PC_CONNECT:
DoConnect;
PC_DISCONNECT:
Account.AccProto.UserSetStatus(Byte(SC_OFFLINE), Account.AccProto.GetVisibility);
PC_PLAYSOUND:
if minimum(2 + 4) then // By Rapid D
theme.PlaySound(_istring_at(data, 3));
PC_PLAYSOUNDFN:
if minimum(2 + 4) then // By Rapid D
SoundPlay(_istring_at(data, 3));
PC_SHOWINFO:
if minimum(2 + 4) then // By Rapid D
begin
cnt := Account.AccProto.getContact(_istring_at(data, 3));
if Assigned(cnt) then
cnt.ViewInfo;
end;
PC_OPENCHAT:
if minimum(2 + 4) then // By Rapid D
begin
cnt := Account.AccProto.getContact(_istring_at(data, 3));
if Assigned(cnt) then
UI.Chat.OpenOn(cnt);
end;
PC_ADDBUTTON:
if minimum(2 + 4 + 4 + 4) then
begin
tS := _istring_at(data, 11);
if length(data) > 2 + 4 + 4 + 4 + length(tS) then
tS := _istring_at(data, 2 + 4 + 4 + 4 + 1 + length(tS))
else
tS := '';
resStr := // #00#00#00 + //outBuffer+char(PM_DATA) +
_int(UI.Chat.plugBtns.Add(Pointer(_int_at(data, 3)), HIcon(_int_at(data, 7)), _istring_at(data, 11), tS) + 1);
end;
PC_DELBUTTON:
if minimum(4) then
UI.Chat.plugBtns.Del(_int_at(data, 3) - 1);
PC_MODIFY_BUTTON:
if minimum(2 + 4 + 4 + 4) then
begin
tS := _istring_at(data, 11);
if length(data) > 2 + 4 + 4 + 4 + length(tS) then
tS := _istring_at(data, 2 + 4 + 4 + 4 + length(tS) + 1)
else
tS := '';
UI.Chat.plugBtns.Modify(_int_at(data, 3) - 1, HIcon(_int_at(data, 7)), _istring_at(data, 11), tS);
end;
PC_ADDCONTACTMENU:
if minimum(2 + 4) then
begin
// TODO: Adding items to menu by plugins
// i := RnQmain.AddContactMenuItem(PCLISTMENUITEM(Pointer(_int_at(data, 2 + 1))) // Proc
// { _int_at(data, 2+1+4), // menuIcon
// _istring_at(data, 2+1+4+4), // menuCaption
// _istring_at(data, 15), // menuHint
// _int_at(data, 19), // position
// _istring_at(data, 23), // PopupName
// _int_at(data, 27), // popupPosition
// _int_at(data, 31), // hotKey
// _istring_at(data, 35) // PicName
// }
// );
{
tS :=_istring_at(data, 11);
if length(data)>2+4+4+4+length(tS) then
tS :=_istring_at(data, 2+4+4+4+1+length(tS))
else
tS := '';
outBuffer := //#00#00#00 + //outBuffer+char(PM_DATA) +
_int(chatFrm.plugBtns.Add(Pointer(_int_at(data, 3)),
_int_at(data, 7), _istring_at(data, 11), tS)+1); }
if i > 0 then
resStr := // #00#00#00 + //outBuffer+
AnsiChar(PM_DATA) + _int(i)
else
resStr := AnsiChar(PM_ERROR);
end;
PC_MODIFYCONTACTMENU:
if minimum(2 + 4 + 4) then
begin
// i :=
// TODO: Adding items to menu by plugins
//RnQmain.UpdateContactMenuItem(_int_at(data, 2 + 1), PCLISTMENUITEM(Pointer(_int_at(data, 2 + 4 + 1))));
// Proc
end;
PC_DELETECONTACTMENU:
begin
// TODO: Adding items to menu by plugins
// if minimum(2 + 4) then
// RnQmain.DelContactMenuItem(_int_at(data, 3));
end;
{ PC_UNLOAD:
begin
unloadPluginName := _istring_at(data, 3);
unloadPlugin:=True;
end; }
PC_RELOAD_THEME:
reloadCurrentTheme;
PC_RELOAD_LANG:
reloadCurrentLang;
// by S@x
PC_TAB_ADD:
begin
// msgDlg(_istring_at(data, 3), mtInformation);
resStr := _int(CHAT_TAB_ADD(_int_at(data, 3), _int_at(data, 7), _istring_at(data, 11)));
end;
PC_TAB_MODIFY:
begin
// msgDlg(_istring_at(data, 3), mtInformation);
CHAT_TAB_MODIFY(_int_at(data, 3), _int_at(data, 7), _istring_at(data, 11));
end;
PC_TAB_DELETE:
begin
// msgDlg(_istring_at(data, 3), mtInformation);
CHAT_TAB_DELETE(_int_at(data, 3));
end;
else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNK_REQ);
end; // case
PM_GET:
if minimum(2) then
case _byte_at(data, 2) of
PG_USER:
// if MainProto.myinfo=NIL then
if Account.AccProto.MyAccNum = '' then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_NOUSER)
else
resStr := AnsiChar(PM_DATA) + _int(StrToIntDef(Account.AccProto.MyAccNum, 0)) +
_istring(Account.AccProto.MyAccNum);
PG_DISPLAYED_NAME:
resStr := AnsiChar(PM_DATA) + _istring(Account.AccProto.GetContact(IntToStr(_int_at(data, 3))).displayed);
PG_ANDRQ_VER:
resStr := AnsiChar(PM_DATA) + _int(RQversion);
PG_ANDRQ_VER_STR:
resStr := AnsiChar(PM_DATA) + _istring(''{ip2str(RQversion)});
PG_RNQ_BUILD:
resStr := AnsiChar(PM_DATA) + _int(RnQBuild) + _dt(BuiltTime);
PG_TIME:
resStr := AnsiChar(PM_DATA) + _dt(now);
PG_CONTACTINFO:
if minimum(6) then
begin
i := _int_at(data, 3);
// tS := IntToStrA(_int_at(data,3));
// outBuffer:=AnsiChar(PM_DATA)+_icontactinfo( Account.AccProto.getContact(tS) );
resStr := AnsiChar(PM_DATA) + _icontactinfo(Account.AccProto.getICQContact(i));
end;
PG_LIST:
if minimum(3) then
begin
cl := whatlist(_byte_at(data, 3));
if cl = NIL then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNEXISTENT)
else
resStr := AnsiChar(PM_DATA) + _intlist(cl.toIntArray);
end;
PG_CHAT_XYZ:
begin
// ShowMessage('chat coord request');
if UI.Chat.Chats.Count = 0 then
resStr := AnsiChar(PM_DATA) + _intlist([0, 0, 0, 0])
else
begin
rct := UI.Chat.GetPluginBounds;
resStr := AnsiChar(PM_DATA) + _intlist([rct.Top, rct.Left, rct.Right, rct.Bottom]);
end;
end;
PG_NOF_UINLISTS:
resStr := AnsiChar(PM_DATA) + _int(uinlists.count);
PG_UINLIST:
if minimum(2 + 4) then
begin
i := _int_at(data, 3);
if (i >= 0) and (i < uinlists.count) then
resStr := AnsiChar(PM_DATA) + _intlist(uinlists.getAt(i).cl.toIntArray)
else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNEXISTENT);
end;
PG_AWAYTIME:
if Account.AccProto.getMyInfo = NIL then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_NOUSER)
else
resStr := AnsiChar(PM_DATA) + _dt(autoaway.time / tenthsPerDay);
PG_ANDRQ_PATH:
resStr := AnsiChar(PM_DATA) + _istring(mypath);
PG_USERTIME:
if Account.AccProto.getMyInfo = NIL then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_NOUSER)
else
resStr := AnsiChar(PM_DATA) + _dt(Now - UserStartTime);
PG_USER_PATH:
if Account.AccProto.getMyInfo = NIL then
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_NOUSER)
else
resStr := AnsiChar(PM_DATA) + _istring(AccPath);
PG_CONNECTIONSTATE:
if Account.AccProto.isOnline then
resStr := AnsiChar(PM_DATA) + AnsiChar(PCS_CONNECTED)
else if Account.AccProto.isOffline then
resStr := AnsiChar(PM_DATA) + AnsiChar(PCS_DISCONNECTED)
else
resStr := AnsiChar(PM_DATA) + AnsiChar(PCS_CONNECTING);
PG_WINDOW:
begin
if (_byte_at(data, 3) = PW_ROSTER) then
begin
if Assigned(UI.CL) then
begin
Rect := UI.CL.GetBounds;
resStr := AnsiChar(PM_DATA) + _int([UI.CL.Window, Rect.Left, Rect.Top, Rect.Width, Rect.Height])
end else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNEXISTENT)
end else if (_byte_at(data, 3) = PW_PREFERENCES) then
begin
if Assigned(UI.Prefs) then
begin
Rect := UI.Prefs.GetBounds;
resStr := AnsiChar(PM_DATA) + _int([UI.Prefs.Window, Rect.Left, Rect.Top, Rect.Width, Rect.Height])
end else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNEXISTENT)
end else if (_byte_at(data, 3) = PW_CHAT) then
begin
if Assigned(UI.Chat) then
begin
Rect := UI.Chat.GetBounds;
resStr := AnsiChar(PM_DATA) + _int([UI.Chat.Window, Rect.Left, Rect.Top, Rect.Width, Rect.Height])
end else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNEXISTENT)
end;
end;
PG_AUTOMSG:
resStr := AnsiChar(PM_DATA) + _istring('');
PG_CHAT_UIN:
begin
sU := UI.Chat.ThisChatUID;
if sU > '' then
resStr := AnsiChar(PM_DATA) + _int(StrToIntDef(sU, 0)) + _istring(sU)
else
resStr := AnsiChar(PM_ERROR) + _int(0);
end;
PG_TRANSLATE:
resStr := AnsiChar(PM_DATA) + _istring(getTranslation(_istring_at(data, 3)));
PG_THEME_PIC:
begin
bmp32 := TBitmap32.create;
if theme.GetPicOld(LowerCase(_istring_at(data, 3)), bmp32) then
resStr := AnsiChar(PM_DATA) + _int(bmp32.BitmapHandle)
else
resStr := AnsiChar(PM_ERROR);
FreeAndNil(bmp32);
end;
PG_PREF_VALUE: { TODO : <20><> PG_PREF_VALUE !!!! }
begin
if minimum(2 + 4) then
begin
tS := _istring_at(data, 3);
PrefVal := MainPrefs.getPrefVal(tS);
if PrefVal <> NIL then
begin
resStr := AnsiChar(PM_DATA) + AnsiChar(PrefVal.ElType) + _istring(PrefVal.AsBlob);
PrefVal.Free;
end
else
resStr := AnsiChar(PM_ABORT);
end
else
resStr := AnsiChar(PM_ABORT);
end;
PG_STATUS:
begin
if Assigned(Account.AccProto) then
begin
resStr := AnsiChar(PM_DATA) + AnsiChar(Status2OldStatus[TICQStatus(Account.AccProto.getStatus)]) +
AnsiChar(vis2OldVis[TOldVisibility(Account.AccProto.getVisibility)]) +
AnsiChar(Account.AccProto.getXStatus);
if Account.AccProto.getXStatus > 0 then
resStr := resStr +
_istring(ExtStsStrings[Account.AccProto.getXStatus].Cap) +
_istring(ExtStsStrings[Account.AccProto.getXStatus].Desc)
else
resStr := resStr + _istring('') + _istring('');
end else
resStr := AnsiChar(PM_ERROR);
end;
PG_XSTATUS:
begin
if minimum(2 + 1) then
i := byte(data[3])
else
i := $FF;
if not(i in [Low(XStatusArray) .. High(XStatusArray)]) then
i := Account.AccProto.getXStatus;
resStr := AnsiChar(PM_DATA) + AnsiChar(byte(i)) + _istring(getTranslation(ExtStsStrings[i].Cap)) +
_istring(getXStatusMsgFor(nil));
end;
else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNK_REQ);
end; // case
else
resStr := AnsiChar(PM_ERROR) + AnsiChar(PERR_UNK_REQ);
end; // case
finally
// result:=resStr;
res := resStr;
end;
end; // callbackStr
{$WARN UNSAFE_CODE OFF}
function callback(data: Pinteger): Pointer; stdcall;
var
s, s2: RawByteString;
ppp: TThreadProcedure;
begin
result := NIL;
if data = NIL then
exit;
// FoutBufferCS.Acquire;
// try
setlength(s, data^);
if length(s) > 0 then
begin
inc(data);
move(data^, s[1], length(s));
end;
// ppp := TThreadProcedure((@RunCBS));
ppp := procedure
begin
// s2 := callbackStr2(s);
callbackStr3(s, s2);
end;
try
TThread.Synchronize(NIL, ppp);
except
s2 := AnsiChar(PM_ABORT);
end;
// callbackStr(s);
outBuffer00 := _int(length(s2)) + s2;
result := @outBuffer00[1];
// finally
// FoutBufferCS.Release;
// end;
end; // callback
/// /////////////////////////////////////////////////////////////////////
function Tplugin.activate: boolean;
var
s: RawByteString;
begin
result := false;
if active then
exit;
LogEvent(filename + ': loading');
hnd := LoadLibrary(PChar(mypath + pluginsPath + filename));
// hnd:=LoadLibraryEx(PChar(myPath+pluginsPath+filename));
if hnd = 0 then
exit;
fun := GetProcAddress(hnd, PAnsiChar('pluginFun'));
if not Assigned(fun) then
fun := GetProcAddress(hnd, '_pluginFun');
if Assigned(fun) then
LogEvent(filename + ': found pluginFun');
funC := GetProcAddress(hnd, 'pluginFunC');
if not Assigned(funC) then
funC := GetProcAddress(hnd, '_pluginFunC');
if Assigned(funC) then
LogEvent(filename + ': found pluginFunC');
if not Assigned(fun) and not Assigned(funC) then
begin
LogEvent(filename + ': neither pluginFun and pluginFunC found');
freeLibrary(hnd);
exit;
end;
active := True;
screenName := filename;
// fun(NIL);
LogEvent(filename + ': initializing');
s := cast(_event(PE_INITIALIZE) + _int(integer(@callback)) + _int(APIversion) + _istring(mypath) + _istring(AccPath) +
_int(StrToIntDef(lastUser, 0)));
if (s > '') then
if (ord(s[1]) = PM_DATA) then
begin
screenName := _istring_at(s, 2);
LogEvent(filename + ': name: ' + screenName);
end
else if (ord(s[1]) = PM_ABORT) then
begin
result := false;
try
freeLibrary(hnd);
hnd := 0;
except
end;
exit;
end;
result := True;
end; // activate
procedure Tplugin.disactivate;
begin
if not active then
exit;
try
LogEvent(filename + ': disactivating');
cast(_event(PE_FINALIZE));
except
LogEvent(filename + ': ERROR on disactivating!!!!', IconNames[mtError]);
end;
try
freeLibrary(hnd);
except
LogEvent(filename + ': ERROR on freing!!!!', IconNames[mtError]);
end;
hnd := 0;
fun := NIL;
funC := NIL;
active := false;
end; // disactivate
function Tplugin.cast(data: RawByteString): RawByteString;
var
p: Pinteger;
begin
result := '';
if not active or not(Assigned(fun) or Assigned(funC)) then
exit;
data := _int(length(data)) + data;
p := nil;
// loggaEvt(format('%s: sending %d bytes',[filename,length(data)]));
try
if Assigned(fun) then
p := fun(@data[1])
else
p := funC(@data[1]);
except
on E: Exception do
msgDlg(getTranslation('Error at plugin "%s": %s', [screenName, E.Message]), false, mtError);
else
msgDlg(getTranslation('Error at plugin "%s"', [screenName]), false, mtError);
// msgDlg(getTranslation('Error at plugin "%s"', [screenName]), mtError);
end;
if Assigned(p) then
begin
// loggaEvt(format('%s: received %d bytes',[filename,p^]));
try
setlength(result, p^);
inc(p);
move(p^, result[1], length(result));
except
setlength(result, 0);
result := '';
msgDlg(getTranslation('Error at plugin "%s"', [screenName]), false, mtError);
end;
end;
end; // cast
{$WARN UNSAFE_CODE ON}
procedure Tplugin.cast_preferences;
begin
cast(_event(PE_PREFERENCES))
end;
/// ////////////////////////////////////////////////////////////////////
constructor Tplugins.Create;
begin
list := Tlist.Create;
end; // create
destructor Tplugins.Destroy;
begin
unload;
list.Free;
inherited;
end; // destroy
procedure Tplugins.resetEnumeration;
begin
enumIdx := 0
end;
function Tplugins.hasMore: boolean;
begin
result := enumIdx < list.count
end;
{$WARN UNSAFE_CAST OFF}
function Tplugins.getNext: Tplugin;
begin
result := Tplugin(list[enumIdx]);
inc(enumIdx);
end; // getNext
procedure Tplugins.load;
var
sr: TsearchRec;
plugin: Tplugin;
begin
LogEvent('Scanning for plugins: ' + mypath + pluginsPath + '*.dll');
if findFirst(mypath + pluginsPath + '*.dll', faAnyFile, sr) = 0 then
repeat
plugin := Tplugin.create;
list.Add(plugin);
with plugin do
begin
filename := sr.name;
screenName := '';
if ansiContainsText(disabledPlugins, filename) then
LogEvent(filename + ': skipped (disabled)')
else if activate then
LogEvent(filename + ': activated')
else
begin
LogEvent(filename + ': activation failed');
list.remove(plugin);
plugin.Free;
end;
end;
until findNext(sr) <> 0;
findClose(sr);
LogEvent('Scanning finished');
end; // load
procedure Tplugins.unload;
var
s: String;
pl: Tplugin;
begin
while list.count > 0 do
try
pl := Tplugin(list.last);
s := pl.screenName + ' (' + pl.filename + ')';
pl.disactivate;
pl.Free;
list.delete(list.count - 1);
except
LogEvent('Error in unloading ' + s);
end;
end; // unload
{$WARN UNSAFE_CAST ON}
function Tplugins.cast(const data: RawByteString): RawByteString;
var
plugin: Tplugin;
begin
result := '';
resetEnumeration;
while hasMore do
begin
plugin := getNext;
result := result + plugin.cast(data);
end;
end; // cast
function Tplugins.castEv(ev_id: byte; const s1, s2, s3: AnsiString; b: boolean; i: integer): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _istring(s1) + _istring(s2) + _istring(s3) + AnsiChar(b) + _int(i))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime; cl: TRnQCList): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _int(flags) + _dt(when) +
_intlist(cl.toIntArray))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _int(flags) + _dt(when))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime; const s1: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _int(flags) + _dt(when) + _istring(s1))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; flags: integer; when: Tdatetime; const s1, s2: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _int(flags) + _dt(when) + _istring(s1) +
_istring(s2))
end;
function Tplugins.castEv(ev_id: byte; when: Tdatetime; const name, addr, text: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _dt(when) + _istring(name) + _istring(addr) + _istring(text))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; flags: integer; const s1: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _int(flags) + _istring(s1))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; const s1: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _istring(s1))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; const s1, s2: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _istring(s1) + _istring(s2))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; b1: byte; const s1, s2: AnsiString): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + AnsiChar(b1) + _istring(s1) + _istring(s2))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; status, oldstatus: byte; inv, oldInv: boolean): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + AnsiChar(Status2OldStatus[TICQStatus(status)])
+ AnsiChar(Status2OldStatus[TICQStatus(oldstatus)]) + AnsiChar(inv) + AnsiChar(oldInv))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID; flags: integer; cl: TRnQCList): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)) + _int(flags) + _intlist(cl.toIntArray))
end;
function Tplugins.castEv(ev_id: byte; const uin: TUID): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(StrToIntDef(uin, 0)))
end;
function Tplugins.castEv(ev_id: byte; uin: integer): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + _int(uin))
end;
function Tplugins.castEv(ev_id: byte): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id))
end;
function Tplugins.castEvList(ev_id: byte; list: byte; c: TICQContact): RawByteString;
begin
result := cast(AnsiChar(PM_EVENT) + AnsiChar(ev_id) + AnsiChar(list) + _intlist([StrToIntDef(c.uid, 0)]))
end;
function TPlugButtons.Add(proc: Pointer; iIcon: HIcon; const bHint: String; const sPic: AnsiString = ''): integer;
var
i: Integer;
begin
i := Length(btns);
SetLength(btns, i + 1);
btns[i] := TPlugButton.Create;
btns[i].proc := proc;
btns[i].hint := bHint;
if sPic = '' then
btns[i].pic := AnsiString('pluginbtn') + AnsiString(IntToStr(i))
else
btns[i].pic := sPic;
if Assigned(UI.Chat) then
UI.Chat.AddPluginButton(i);
Modify(i, iIcon, bHint, sPic);
Result := i;
end;
procedure TPlugButtons.Del(bAddr: integer);
var
i: integer;
begin
i := bAddr; // - 1;
if (i < Low(btns)) or (i > High(btns)) then
Exit;
if not Assigned(btns[i]) then
Exit;
// theme.delPic(btns[i].ImageName);
btns[i].pic := '';
btns[i].hint := '';
if Assigned(UI.Chat) then
UI.Chat.DelPluginButton(i);
FreeAndNil(btns[i]);
end;
procedure TPlugButtons.Modify(bAddr: integer; iIcon: HIcon; const bHint: String; const sPic: AnsiString = '');
var
i: integer;
begin
i := bAddr; // - 1;
if (i < Low(btns)) or (i > High(btns)) then
Exit;
if not Assigned(btns[i]) then
Exit;
if not (iIcon = 0) then
if not (sPic = '') then
theme.addHIco(sPic, iIcon, True)
else
theme.addHIco(btns[i].pic, iIcon, True);
if not (sPic = '') then
btns[i].pic := sPic;
if not (bHint = '') then
btns[i].hint := getTranslation(bHint);
if Assigned(UI.Chat) then
UI.Chat.ModifyPluginButton(i);
end;
end.