summaryrefslogtreecommitdiff
path: root/plugins/Actman30
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2013-07-16 20:08:30 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2013-07-16 20:08:30 +0000
commit74e738f374f759723daf8920677158712d0ca5c1 (patch)
tree89a93d70f87e950e28d23466d3c84120ead0e770 /plugins/Actman30
parente5c9c0077f7b50bbfe90201154c31c13e1a6fc63 (diff)
- Actman 3 added (not adopted)
git-svn-id: http://svn.miranda-ng.org/main/trunk@5391 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Actman30')
-rw-r--r--plugins/Actman30/actman.dpr254
-rw-r--r--plugins/Actman30/ask.rc20
-rw-r--r--plugins/Actman30/dlgshare.pas73
-rw-r--r--plugins/Actman30/dlgshare.rc13
-rw-r--r--plugins/Actman30/global.pas29
-rw-r--r--plugins/Actman30/hooks/hooks.pas69
-rw-r--r--plugins/Actman30/hooks/hooks.rc28
-rw-r--r--plugins/Actman30/hooks/i_hconst.inc20
-rw-r--r--plugins/Actman30/hooks/i_hook.inc154
-rw-r--r--plugins/Actman30/hooks/i_opt_dlg.inc419
-rw-r--r--plugins/Actman30/hooks/i_options.inc71
-rw-r--r--plugins/Actman30/i_cnst_chain.inc6
-rw-r--r--plugins/Actman30/i_cnst_contact.inc6
-rw-r--r--plugins/Actman30/i_cnst_database.inc18
-rw-r--r--plugins/Actman30/i_cnst_dlgshare.inc11
-rw-r--r--plugins/Actman30/i_cnst_inout.inc17
-rw-r--r--plugins/Actman30/i_cnst_jump.inc15
-rw-r--r--plugins/Actman30/i_cnst_message.inc17
-rw-r--r--plugins/Actman30/i_cnst_program.inc13
-rw-r--r--plugins/Actman30/i_cnst_service.inc12
-rw-r--r--plugins/Actman30/i_cnst_settings.inc11
-rw-r--r--plugins/Actman30/i_cnst_storage.inc5
-rw-r--r--plugins/Actman30/i_cnst_text.inc4
-rw-r--r--plugins/Actman30/i_const.inc31
-rw-r--r--plugins/Actman30/i_opt_dlg.inc52
-rw-r--r--plugins/Actman30/i_opt_dlg2.inc1318
-rw-r--r--plugins/Actman30/i_options.inc177
-rw-r--r--plugins/Actman30/i_services.inc317
-rw-r--r--plugins/Actman30/iac_.pas155
-rw-r--r--plugins/Actman30/iac_chain.pas372
-rw-r--r--plugins/Actman30/iac_chain.rc18
-rw-r--r--plugins/Actman30/iac_contact.pas252
-rw-r--r--plugins/Actman30/iac_contact.rc18
-rw-r--r--plugins/Actman30/iac_database.rc37
-rw-r--r--plugins/Actman30/iac_dbrw.pas686
-rw-r--r--plugins/Actman30/iac_global.pas428
-rw-r--r--plugins/Actman30/iac_inout.pas667
-rw-r--r--plugins/Actman30/iac_inout.rc30
-rw-r--r--plugins/Actman30/iac_jump.pas699
-rw-r--r--plugins/Actman30/iac_jump.rc32
-rw-r--r--plugins/Actman30/iac_messagebox.pas386
-rw-r--r--plugins/Actman30/iac_messagebox.rc36
-rw-r--r--plugins/Actman30/iac_program.pas491
-rw-r--r--plugins/Actman30/iac_program.rc31
-rw-r--r--plugins/Actman30/iac_service.pas1023
-rw-r--r--plugins/Actman30/iac_service.rc32
-rw-r--r--plugins/Actman30/iac_settings.pas157
-rw-r--r--plugins/Actman30/iac_settings.rc26
-rw-r--r--plugins/Actman30/iac_storage.pas292
-rw-r--r--plugins/Actman30/iac_storage.rc16
-rw-r--r--plugins/Actman30/iac_text.pas495
-rw-r--r--plugins/Actman30/iac_text.rc14
-rw-r--r--plugins/Actman30/ico/advance.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/apply.icobin0 -> 1406 bytes
-rw-r--r--plugins/Actman30/ico/chain.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/contact.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/delete.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/down.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/export.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/format.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/import.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/insert.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/jump.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/message.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/new.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/program.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/reload.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/rw.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/service.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/settings.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/storage.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/test.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/text.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ico/up.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/inoutini.pas153
-rw-r--r--plugins/Actman30/inoutxml.pas155
-rw-r--r--plugins/Actman30/lowlevelc.pas294
-rw-r--r--plugins/Actman30/m_actman.h96
-rw-r--r--plugins/Actman30/m_actman.inc152
-rw-r--r--plugins/Actman30/make.bat18
-rw-r--r--plugins/Actman30/options.rc70
-rw-r--r--plugins/Actman30/question.pas58
-rw-r--r--plugins/Actman30/readme.txt126
-rw-r--r--plugins/Actman30/services.ini523
-rw-r--r--plugins/Actman30/tasks/i_opt_dlg.inc536
-rw-r--r--plugins/Actman30/tasks/i_options.inc99
-rw-r--r--plugins/Actman30/tasks/i_service.inc87
-rw-r--r--plugins/Actman30/tasks/i_task.inc242
-rw-r--r--plugins/Actman30/tasks/i_tconst.inc27
-rw-r--r--plugins/Actman30/tasks/scheduler.pas76
-rw-r--r--plugins/Actman30/tasks/tasks.rc47
-rw-r--r--plugins/Actman30/ua/action.icobin0 -> 2550 bytes
-rw-r--r--plugins/Actman30/ua/i_inoutjson.inc355
-rw-r--r--plugins/Actman30/ua/i_inoutxm.inc357
-rw-r--r--plugins/Actman30/ua/i_opt_dlg.inc572
-rw-r--r--plugins/Actman30/ua/i_options.inc252
-rw-r--r--plugins/Actman30/ua/i_ua.inc219
-rw-r--r--plugins/Actman30/ua/i_uaplaces.inc832
-rw-r--r--plugins/Actman30/ua/i_uavars.inc121
-rw-r--r--plugins/Actman30/ua/i_uconst.inc34
-rw-r--r--plugins/Actman30/ua/ua.pas108
-rw-r--r--plugins/Actman30/ua/ua.rc51
102 files changed, 15233 insertions, 0 deletions
diff --git a/plugins/Actman30/actman.dpr b/plugins/Actman30/actman.dpr
new file mode 100644
index 0000000000..2f22cda9e2
--- /dev/null
+++ b/plugins/Actman30/actman.dpr
@@ -0,0 +1,254 @@
+{$include compilers.inc}
+{$IFDEF COMPILER_16_UP}
+ {$WEAKLINKRTTI ON}
+ {.$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
+{$ENDIF}
+{$IMAGEBASE $13200000}
+library actman;
+{%File 'm_actman.inc'}
+{%File 'i_const.inc'}
+{%File 'i_opt_dlg2.inc'}
+{%File 'i_opt_dlg.inc'}
+{%File 'i_options.inc'}
+{%File 'i_services.inc'}
+{%File 'i_vars.inc'}
+{%File 'i_inoutxm.inc'}
+{%File 'tasks\i_opt_dlg.inc'}
+{%File 'tasks\i_options.inc'}
+{%File 'tasks\i_task.inc'}
+{%File 'hooks\i_options.inc'}
+{%File 'hooks\i_hook.inc'}
+{%File 'hooks\i_opt_dlg.inc'}
+{%File 'ua\i_opt_dlg.inc'}
+{%File 'ua\i_inoutxm.inc'}
+{%File 'ua\i_options.inc'}
+{%File 'ua\i_ua.inc'}
+{%File 'ua\i_uaplaces.inc'}
+{%File 'ua\i_uconst.inc'}
+
+uses
+// fastmm4,
+ m_api,
+ Windows,
+ messages,
+ commctrl,
+ common,
+ wrapper,
+ io,
+ dbsettings,
+ mirutils,
+ syswin,
+ base64,
+ question,
+ mApiCardM,
+ global,
+ lowlevelc,
+ dlgshare,
+ iac_global,
+ iac_settings,
+ iac_storage,
+ iac_dbrw,
+ iac_messagebox,
+ iac_text,
+ iac_jump,
+ iac_inout,
+ iac_service,
+ iac_program,
+ iac_chain,
+ iac_contact,
+ inoutxml,
+ sedit,
+ strans,
+ ua in 'ua\ua.pas',
+ hooks in 'hooks\hooks.pas',
+ scheduler in 'tasks\scheduler.pas';
+
+{$r options.res}
+
+const
+ PluginName = 'Action Manager';
+var
+ hevaction,hHookChanged,hevinout:THANDLE;
+
+{$include m_actman.inc}
+
+
+function MirandaPluginInfoEx(mirandaVersion:DWORD):PPLUGININFOEX; cdecl;
+begin
+ result:=@PluginInfo;
+ PluginInfo.cbSize :=SizeOf(TPLUGININFOEX);
+ PluginInfo.shortName :='Action manager';
+ PluginInfo.version :=$00030001;
+ PluginInfo.description:='Plugin for manage hotkeys to open contact window, insert text, '+
+ 'run program and call services';
+ PluginInfo.author :='Awkward';
+ PluginInfo.authorEmail:='panda75@bk.ru; awk1975@ya.ru';
+ PluginInfo.copyright :='(c) 2007-2013 Awkward';
+ PluginInfo.homepage :='http://code.google.com/p/delphi-miranda-plugins/';
+ PluginInfo.flags :=UNICODE_AWARE;
+ PluginInfo.uuid :=MIID_ACTMAN;
+end;
+
+{$include i_const.inc}
+
+{$include i_options.inc}
+{$include i_services.inc}
+{$include i_opt_dlg.inc}
+{.$include i_inoutxm.inc}
+
+function PreShutdown(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ ptr:pActionLink;
+begin
+ result:=0;
+
+ ptr:=ActionLink;
+ while ptr<>nil do
+ begin
+ if @ptr^.DeInit<>nil then
+ ptr^.DeInit;
+ ptr:=ptr^.Next;
+ end;
+
+ MacroList.Clear;
+ MacroList.Free;
+
+ DestroyHookableEvent(hHookChanged);
+ DestroyHookableEvent(hevinout);
+ DestroyHookableEvent(hevaction);
+
+end;
+
+procedure RegisterActTypes;
+var
+ p:pActModule;
+ sid:TSKINICONDESC;
+ buf:array [0..63] of AnsiChar;
+ pc:pAnsiChar;
+// ii:tIconItem;
+begin
+ FillChar(sid,SizeOf(sid),0);
+ sid.cbSize:=SizeOf(sid);
+ sid.cx:=16;
+ sid.cy:=16;
+ sid.szSection.a:='Actions';
+ sid.pszName :=@buf;
+ pc:=StrCopyE(buf,IcoLibPrefix);
+ p:=ModuleLink;
+{
+ ii.size :=0;
+ ii.hIcolib:=0;
+ ii.szName :=@buf;
+}
+ while p<>nil do
+ begin
+ if p^.Hash=0 then
+ p^.Hash:=Hash(p^.Name,StrLen(p^.Name));
+ //!! must add icon registration in icolib
+{
+ StrCopy(pc,p^.Name);
+ ii.szDescr :=p^.Name;
+ ii.DefIconID:=;
+ Icon_Register(hInstance,'Actions',@ii,1);
+}
+ sid.hDefaultIcon :=LoadImageA(hInstance,p^.Icon,IMAGE_ICON,16,16,0);
+ sid.szDescription.a:=p^.Name;
+ StrCopy(pc,p^.Name);
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+
+ p:=p^.Next;
+ end;
+end;
+
+// This function implements autostart action execution after all others plugins loading
+function DoAutostart(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ i:integer;
+ Macro:pMacroRecord;
+ section:array [0..127] of AnsiChar;
+ p,p1:pAnsiChar;
+begin
+ Result:=0;
+ CallService(MS_ACT_RUNBYNAME,TWPARAM(AutoStartName),0);
+
+ p1:=StrCopyE(section,opt_group);
+ for i:=0 to MacroList.Count-1 do
+ begin
+ Macro:=MacroList[i];
+ if (Macro^.flags and ACF_FIRSTRUN)<>0 then
+ begin
+ CallService(MS_ACT_RUNBYID,TWPARAM(Macro^.id),0);
+ Macro^.flags:=Macro^.flags and not ACF_FIRSTRUN;
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p);
+ StrCopy(p,opt_flags); DBWriteDWord(0,DBBranch,section,Macro^.flags);
+ end;
+ end;
+end;
+
+function OnModulesLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ ptr:pActionLink;
+begin
+ Result:=0;
+
+ RegisterActTypes;
+
+ LoadMacros;
+ RegisterIcons;
+
+ HookEvent(ME_OPT_INITIALISE ,@OnOptInitialise);
+ HookEvent(ME_SYSTEM_SHUTDOWN{ME_SYSTEM_OKTOEXIT},@PreShutdown);
+ NotifyEventHooks(hHookChanged,twparam(ACTM_LOADED),0);
+
+ //----- DBEDITOR support -----
+// CallService(MS_DBEDIT_REGISTERSINGLEMODULE,twparam(PluginShort),0);
+
+ IsMultiThread:=true;
+ // Load additional modules
+ ptr:=ActionLink;
+ while ptr<>nil do
+ begin
+ if @ptr^.Init<>nil then
+ ptr^.Init;
+ ptr:=ptr^.Next;
+ end;
+
+ // cheat
+ HookEvent(ME_SYSTEM_MODULESLOADED,@DoAutostart);
+// DoAutostart(0,0);
+end;
+
+function Load:int; cdecl;
+begin
+ Result:=0;
+ Langpack_Register;
+
+ hHookChanged:=CreateHookableEvent(ME_ACT_CHANGED);
+ hevinout :=CreateHookableEvent(ME_ACT_INOUT);
+ hevaction :=CreateHookableEvent(ME_ACT_ACTION);
+
+ CreateServiceFunction(MS_ACT_FREELIST ,@ActFreeList);
+ CreateServiceFunction(MS_ACT_GETLIST ,@ActGetList);
+ CreateServiceFunction(MS_ACT_RUNBYID ,@ActRun);
+ CreateServiceFunction(MS_ACT_RUNBYNAME,@ActRunGroup);
+ CreateServiceFunction(MS_ACT_RUNPARAMS,@ActRunParam);
+//!! CreateServiceFunction(MS_ACT_INOUT ,@ActInOut);
+ CreateServiceFunction(MS_ACT_SELECT ,@ActSelect);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED,@OnModulesLoaded);
+end;
+
+function Unload: int; cdecl;
+begin
+ Result:=0;
+end;
+
+exports
+ Load, Unload,
+ MirandaPluginInfoEx;
+
+begin
+ DisableThreadLibraryCalls(hInstance);
+end.
diff --git a/plugins/Actman30/ask.rc b/plugins/Actman30/ask.rc
new file mode 100644
index 0000000000..cb36bcf8ee
--- /dev/null
+++ b/plugins/Actman30/ask.rc
@@ -0,0 +1,20 @@
+#include "i_const.inc"
+
+LANGUAGE 0,0
+
+IDD_ASK DIALOGEX 0, 0, 276, 72, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Choose action"
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ CTEXT "", IDC_ASK,4,4,268,42,SS_CENTERIMAGE
+
+ CONTROL "", -1, "STATIC", SS_ETCHEDHORZ, 2, 50, 272, 2
+
+ DEFPUSHBUTTON "&Yes" , IDOK , 4, 54, 40, 16
+ PUSHBUTTON "&No" , IDCANCEL , 52, 54, 40, 16
+ PUSHBUTTON "A&ppend" , IDC_APPEND, 100, 54, 52, 16
+ PUSHBUTTON "Yes to &All", IDC_YESALL, 160, 54, 52, 16
+ PUSHBUTTON "N&o to All" , IDC_NOALL , 220, 54, 52, 16
+}
diff --git a/plugins/Actman30/dlgshare.pas b/plugins/Actman30/dlgshare.pas
new file mode 100644
index 0000000000..cd6dbb9023
--- /dev/null
+++ b/plugins/Actman30/dlgshare.pas
@@ -0,0 +1,73 @@
+unit dlgshare;
+
+interface
+
+uses windows,lowlevelc;
+
+var
+ MacroListWindow,
+ ActionListWindow:HWND;
+var
+ EditMacroList:tMacroList;
+
+const
+ ACI_APPLY = 0;
+ ACI_NEW = 1;
+ ACI_DELETE = 2;
+ ACI_UP = 3;
+ ACI_DOWN = 4;
+ ACI_TEST = 5;
+ ACI_IMPORT = 6;
+ ACI_EXPORT = 7;
+ ACI_REFRESH = 8;
+
+procedure RegisterIcons;
+function OptSetButtonIcon(btn:HWND;num:integer):HICON;
+procedure OptFillContactList(wnd:HWND);
+
+implementation
+
+uses messages, m_api, dbsettings, contact, common, global;
+
+{$include i_cnst_dlgshare.inc}
+{$resource dlgshare.res}
+
+const
+ IconAmount = 9;
+const
+ Icons:array [0..IconAmount-1] of tIconItem = (
+ (szDescr: 'Apply' ; szName: 'Apply' ; defIconID: IDI_APPLY ; size: 0; hIcolib: 0;),
+ (szDescr: 'New' ; szName: 'New' ; defIconID: IDI_NEW ; size: 0; hIcolib: 0;),
+ (szDescr: 'Delete' ; szName: 'Delete'; defIconID: IDI_DELETE; size: 0; hIcolib: 0;),
+ (szDescr: 'Up' ; szName: 'Up' ; defIconID: IDI_UP ; size: 0; hIcolib: 0;),
+ (szDescr: 'Down' ; szName: 'Down' ; defIconID: IDI_DOWN ; size: 0; hIcolib: 0;),
+ (szDescr: 'Test' ; szName: 'Test' ; defIconID: IDI_TEST ; size: 0; hIcolib: 0;),
+ (szDescr: 'Import' ; szName: 'Import'; defIconID: IDI_IMPORT; size: 0; hIcolib: 0;),
+ (szDescr: 'Export' ; szName: 'Export'; defIconID: IDI_EXPORT; size: 0; hIcolib: 0;),
+ (szDescr: 'Reload/Refresh'; szName: 'Reload'; defIconID: IDI_RELOAD; size: 0; hIcolib: 0;)
+ );
+
+
+procedure RegisterIcons;
+begin
+ Icon_Register(hInstance,'Actions',@Icons,IconAmount,'ACI');
+end;
+
+function OptSetButtonIcon(btn:HWND;num:integer):HICON;
+begin
+ result:=CallService(MS_SKIN2_GETICONBYHANDLE,0,LPARAM(Icons[num].hIcolib));
+ SendMessage(btn,BM_SETIMAGE,IMAGE_ICON,result);
+end;
+
+procedure OptFillContactList(wnd:HWND);
+var
+ fCLformat:pWideChar;
+ fCLfilter:byte;
+begin
+ fCLfilter:=DBReadByte (0,DBBranch,'CLfilter',BST_UNCHECKED);
+ fCLformat:=DBReadUnicode(0,DBBranch,'CLformat');
+ FillContactList(wnd, fCLfilter<>BST_UNCHECKED, fCLformat);
+ mFreeMem(fCLformat);
+end;
+
+end.
diff --git a/plugins/Actman30/dlgshare.rc b/plugins/Actman30/dlgshare.rc
new file mode 100644
index 0000000000..dfeb197281
--- /dev/null
+++ b/plugins/Actman30/dlgshare.rc
@@ -0,0 +1,13 @@
+#include "i_cnst_dlgshare.inc"
+
+LANGUAGE 0,0
+
+IDI_NEW ICON "ico\new.ico"
+IDI_UP ICON "ico\up.ico"
+IDI_DOWN ICON "ico\down.ico"
+IDI_DELETE ICON "ico\delete.ico"
+IDI_RELOAD ICON "ico\reload.ico"
+IDI_TEST ICON "ico\test.ico"
+IDI_EXPORT ICON "ico\export.ico"
+IDI_IMPORT ICON "ico\import.ico"
+IDI_APPLY ICON "ico\apply.ico"
diff --git a/plugins/Actman30/global.pas b/plugins/Actman30/global.pas
new file mode 100644
index 0000000000..276f71dea7
--- /dev/null
+++ b/plugins/Actman30/global.pas
@@ -0,0 +1,29 @@
+unit global;
+
+interface
+
+const
+ DBBranch = 'ActMan';
+const
+ ACF_SELECTED = $08000000;
+ ACF_EXPORT = ACF_SELECTED;
+ ACF_IMPORT = ACF_SELECTED;
+ ACF_OVERLOAD = $01000000;
+
+type
+ tAddOption = function(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+type
+ pActionLink=^tActionLink;
+ tActionLink=record
+ Next :pActionLink;
+ Init :procedure;
+ DeInit :procedure;
+ AddOption:tAddOption;
+ end;
+
+const
+ ActionLink:pActionLink=nil;
+
+implementation
+
+end. \ No newline at end of file
diff --git a/plugins/Actman30/hooks/hooks.pas b/plugins/Actman30/hooks/hooks.pas
new file mode 100644
index 0000000000..02ab937cab
--- /dev/null
+++ b/plugins/Actman30/hooks/hooks.pas
@@ -0,0 +1,69 @@
+unit hooks;
+
+interface
+
+implementation
+
+uses
+ windows, commctrl, messages,
+ mirutils, common, dbsettings, m_api, wrapper,
+ global, mApiCardM;
+
+{$R hooks.res}
+
+{$include m_actman.inc}
+
+{$include i_hook.inc}
+{$include i_hconst.inc}
+{$include i_options.inc}
+{$include i_opt_dlg.inc}
+
+// ------------ base interface functions -------------
+
+procedure Init;
+begin
+
+ MessageWindow:=CreateWindowExW(0,'STATIC',nil,0,1,1,1,1,HWND_MESSAGE,0,hInstance,nil);
+ if MessageWindow<>0 then
+ SetWindowLongPtrW(MessageWindow,GWL_WNDPROC,LONG_PTR(@HookWndProc));
+
+ if LoadHooks=0 then
+ begin
+ MaxHooks:=8;
+ GetMem (HookList ,MaxHooks*SizeOf(tHookRec));
+ FillChar(HookList^,MaxHooks*SizeOf(tHookRec),0);
+ end
+ else
+ SetAllHooks;
+end;
+
+procedure DeInit;
+begin
+ ClearHooks;
+ if MessageWindow<>0 then
+ DestroyWindow(MessageWindow);
+end;
+
+function AddOptionPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ result:=0;
+ tmpl:=PAnsiChar(IDD_HOOKS);
+ proc:=@DlgProcOpt;
+ name:='Hooks';
+end;
+
+var
+ amLink:tActionLink;
+
+procedure InitLink;
+begin
+ amLink.Next :=ActionLink;
+ amLink.Init :=@Init;
+ amLink.DeInit :=@DeInit;
+ amLink.AddOption:=@AddOptionPage;
+ ActionLink :=@amLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Actman30/hooks/hooks.rc b/plugins/Actman30/hooks/hooks.rc
new file mode 100644
index 0000000000..ff351cc94d
--- /dev/null
+++ b/plugins/Actman30/hooks/hooks.rc
@@ -0,0 +1,28 @@
+#include "i_hconst.inc"
+
+LANGUAGE 0,0
+
+IDD_HOOKS DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ CONTROL "", IDC_HOOKLIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP |
+ LVS_SHOWSELALWAYS| LVS_REPORT | LVS_EDITLABELS,// | LVS_SINGLESEL
+ 0, 2, 280, 160, WS_EX_CONTROLPARENT
+
+ CONTROL "Help" ,IDC_EVENT_HELP ,"MButtonClass",WS_TABSTOP,284, 2,16,16,$18000000
+ CONTROL "Delete",IDC_HOOK_DELETE,"MButtonClass",WS_TABSTOP,284, 96,16,16,$18000000
+
+ CONTROL "New" ,IDC_HOOK_NEW ,"MButtonClass",WS_TABSTOP,284,126,16,16,$18000000
+ CONTROL "Apply" ,IDC_HOOK_APPLY ,"MButtonClass",WS_TABSTOP,284,146,16,16,$18000000
+
+ CONTROL "Help" ,IDC_EVENT_CHELP,"MButtonClass",WS_TABSTOP,2 ,162,16,16,$18000000
+ CTEXT "Event" ,-1 ,18, 165, 121, 11, SS_CENTERIMAGE
+ COMBOBOX IDC_EVENTLIST , 0, 178, 157, 128, CBS_DROPDOWN | CBS_SORT | WS_VSCROLL
+ CTEXT "Action",-1 , 0, 195, 157, 11, SS_CENTERIMAGE
+ COMBOBOX IDC_ACTIONLIST, 0, 208, 157, 128, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL
+
+ LTEXT "",IDC_DESCR, 160, 165, 138, 57
+}
diff --git a/plugins/Actman30/hooks/i_hconst.inc b/plugins/Actman30/hooks/i_hconst.inc
new file mode 100644
index 0000000000..d011278b7e
--- /dev/null
+++ b/plugins/Actman30/hooks/i_hconst.inc
@@ -0,0 +1,20 @@
+{resource constants}
+const
+ // dialogs
+ IDD_HOOKS = 1029;
+
+ // icons
+ IDI_NEW = 1025;
+ IDI_DELETE = 1028;
+
+ // Hook editor
+ IDC_HOOKLIST = 1025;
+ IDC_ACTIONLIST = 1026;
+ IDC_EVENTLIST = 1027;
+ IDC_EVENT_HELP = 1028;
+ IDC_HOOK_NEW = 1029;
+ IDC_HOOK_DELETE = 1030;
+ IDC_HOOK_APPLY = 1031;
+ IDC_EVENT_CHELP = 1032;
+
+ IDC_DESCR = 1040;
diff --git a/plugins/Actman30/hooks/i_hook.inc b/plugins/Actman30/hooks/i_hook.inc
new file mode 100644
index 0000000000..8b7b487d98
--- /dev/null
+++ b/plugins/Actman30/hooks/i_hook.inc
@@ -0,0 +1,154 @@
+{}
+
+const
+ HWND_MESSAGE = HWND(-3);
+const
+ ACF_ASSIGNED = $80000000; // hook assigned
+ ACF_DISABLED = $10000000; // hook disabled
+const
+ WM_RESETHOOKS = WM_USER+1312;
+ WM_FIRSTHOOK = WM_USER+1313;
+ WM_LASTHOOK = WM_FIRSTHOOK+1000;
+
+type
+ pHookRec = ^tHookRec;
+ tHookRec = record
+ flags :dword;
+ name :PAnsiChar; // name for hook
+ handle :THANDLE; // handle of hook
+ descr :PWideChar; // name for list
+ action :dword; // assigned action
+ message:uint; // window message for hook
+ end;
+ pHookList = ^tHookList;
+ tHookList = array [0..1023] of tHookRec;
+
+var
+ HookList:pHookList = nil;
+ MaxHooks:integer = 0;
+ MessageWindow:HWND = 0;
+
+function GetNextMessage:uint;
+var
+ i:uint;
+ j:integer;
+begin
+ result:=0;
+ for i:=WM_FIRSTHOOK to WM_LASTHOOK do
+ begin
+ for j:=0 to MaxHooks-1 do
+ begin
+ with HookList^[j] do
+ begin
+ if ((flags and ACF_ASSIGNED)<>0) and (i=message) then
+ begin
+ inc(result);
+ break;
+ end;
+ end;
+ end;
+ if result=0 then
+ begin
+ result:=i;
+ break;
+ end
+ else
+ result:=0;
+ end;
+end;
+
+procedure SetAllHooks;
+var
+ i:integer;
+ msg:cardinal;
+begin
+ msg:=WM_FIRSTHOOK;
+ for i:=0 to MaxHooks-1 do
+ begin
+ with HookList[i] do
+ begin
+ message:=msg;
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ if (flags and ACF_DISABLED)<>0 then
+ begin
+ if handle<>0 then
+ begin
+ UnhookEvent(handle);
+ handle:=0;
+ end;
+ end
+ else
+ begin
+ if handle<>0 then
+ UnhookEvent(handle);
+ handle:=HookEventMessage(name,MessageWindow,message);
+ end;
+ end;
+ end;
+ inc(msg);
+ end;
+end;
+
+function GetHookByMessage(msg:uint):pHookRec;
+var
+ i:integer;
+begin
+ result:=nil;
+ for i:=0 to MaxHooks-1 do
+ begin
+ with HookList[i] do
+ begin
+ if ((flags and ACF_ASSIGNED)<>0) and (msg=message) then
+ begin
+ result:=@HookList[i];
+ break;
+ end;
+ end;
+ end;
+end;
+
+function HookWndProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ p:pHookRec;
+ ap:tAct_Param;
+begin
+ result:=0;
+ case hMessage of
+ WM_FIRSTHOOK..WM_LASTHOOK: begin
+ p:=GetHookByMessage(hMessage);
+ if p<>nil then
+ begin
+ ap.flags :=ACTP_WAIT;
+ ap.Id :=p^.action;
+ ap.wParam:=wParam;
+ ap.lParam:=lParam;
+ result:=CallService(MS_ACT_RUNPARAMS,0,TLPARAM(@ap));
+ end;
+ end;
+ else
+ result:=DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
+
+procedure ClearHooks;
+var
+ i:integer;
+begin
+ for i:=0 to MaxHooks-1 do
+ begin
+ with HookList[i] do
+ begin
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ mFreeMem(descr);
+ mFreeMem(name);
+ if handle<>0 then
+ UnhookEvent(handle);
+ end;
+ end;
+ end;
+ FreeMem(HookList);
+ MaxHooks:=0;
+end;
+
diff --git a/plugins/Actman30/hooks/i_opt_dlg.inc b/plugins/Actman30/hooks/i_opt_dlg.inc
new file mode 100644
index 0000000000..012fc5b361
--- /dev/null
+++ b/plugins/Actman30/hooks/i_opt_dlg.inc
@@ -0,0 +1,419 @@
+{}
+const
+ settings:HWND = 0;
+var
+ OldTableProc:pointer;
+ onactchanged:THANDLE;
+ ApiCard:tmApiCard;
+
+const
+ ACI_NEW :PAnsiChar = 'ACI_New';
+ ACI_APPLY :PAnsiChar = 'ACI_Apply';
+ ACI_DELETE :PAnsiChar = 'ACI_Delete';
+
+procedure CheckHookList(wnd:HWND);
+var
+ i:integer;
+ li:LV_ITEMW;
+ arr:array [0..127] of WideChar;
+begin
+ ClearHooks;
+
+ li.mask :=LVIF_TEXT or LVIF_PARAM;
+ li.pszText :=@arr;
+ li.cchTextMax:=SizeOf(arr) div SizeOf(WideChar);
+
+ MaxHooks:=SendMessage(wnd,LVM_GETITEMCOUNT,0,0);
+
+ GetMem (HookList ,MaxHooks*SizeOf(tHookRec));
+ FillChar(HookList^,MaxHooks*SizeOf(tHookRec),0);
+ for i:=0 to MaxHooks-1 do
+ begin
+ with HookList[i] do
+ begin
+ flags:=ACF_ASSIGNED;
+ li.iItem :=i;
+ li.iSubItem:=0;
+ SendMessageW(wnd,LVM_GETITEMW,0,LPARAM(@li));
+ StrDupW(descr,arr);
+ action:=li.lParam;
+ li.iSubItem:=1;
+ SendMessageA(wnd,LVM_GETITEMA,0,LPARAM(@li));
+ StrDup(name,pAnsiChar(@arr));
+
+ if ListView_GetCheckState(wnd,i)=0 then // disabled
+ flags:=flags or ACF_DISABLED;
+ end;
+ end;
+end;
+
+procedure FillHookList(wnd:HWND);
+var
+ i:integer;
+ li:LV_ITEMW;
+begin
+ SendMessage(wnd,LVM_DELETEALLITEMS,0,0);
+ for i:=0 to MaxHooks-1 do
+ begin
+ with HookList[i] do
+ begin
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ li.mask :=LVIF_TEXT+LVIF_PARAM;
+ li.iSubItem:=0;
+ li.iItem :=i;
+ li.lParam :=action;
+ li.pszText :=descr;
+ li.iItem :=SendMessageW(wnd,LVM_INSERTITEMW,0,LPARAM(@li));
+ li.mask :=LVIF_TEXT;
+ li.iSubItem:=1;
+ li.pszText :=pWideChar(name);
+ SendMessageA(wnd,LVM_SETITEMA,0,LPARAM(@li));
+ ListView_SetCheckState(wnd,li.iItem,(flags and ACF_DISABLED)=0);
+ end;
+ end;
+ end;
+ ListView_SetItemState(wnd,0,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+end;
+
+procedure FillActionList(wnd:HWND);
+var
+ ptr,ptr1:pChain;
+ i,cnt:integer;
+begin
+ cnt:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ if cnt>0 then
+ begin
+ ptr1:=ptr;
+ inc(pbyte(ptr),4);
+ for i:=0 to cnt-1 do
+ begin
+ CB_AddStrDataW(wnd,ptr^.descr,ptr^.id);
+ inc(ptr);
+ end;
+
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+ end;
+end;
+
+function ActListChange(wParam:WPARAM;lParam:LPARAM):integer; cdecl;
+begin
+ result:=0;
+ if settings<>0 then
+ FillActionList(GetDlgItem(settings,IDC_ACTIONLIST));
+end;
+
+procedure ShowHookData(Dialog:HWND; item:integer=-1);
+var
+ li:LV_ITEM;
+ arr:array [0..127] of WideChar;
+ wnd:HWND;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_HOOKLIST);
+ if item<0 then
+ li.iItem:=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED)
+ else
+ li.iItem:=item;
+
+ li.mask :=LVIF_TEXT+LVIF_PARAM;
+ li.iSubItem :=1;
+ li.pszText :=@arr;
+ li.cchTextMax:=SizeOf(arr) div SizeOf(WideChar);
+ arr[0]:=#0;
+ SendMessageW(wnd,LVM_GETITEMW,0,LPARAM(@li));
+ if arr[0]<>#0 then
+ SetDlgItemTextW(Dialog,IDC_EVENTLIST,arr);
+ CB_SelectData(GetDlgItem(Dialog,IDC_ACTIONLIST),li.lParam);
+end;
+
+procedure SaveHookData(Dialog:HWND; item:integer=-1);
+var
+ wnd:HWND;
+ li:LV_ITEMW;
+ p:pAnsiChar;
+ buf:array [0..127] of WideChar;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_HOOKLIST);
+ if item<0 then
+ li.iItem:=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED)
+ else
+ li.iItem:=item;
+ li.mask :=LVIF_PARAM;
+ li.lParam :=CB_GetData(GetDlgItem(Dialog,IDC_ACTIONLIST));
+ li.iSubItem :=0;
+ SendMessageW(wnd,LVM_SETITEMW,0,LPARAM(@li));
+ li.mask :=LVIF_TEXT;
+ li.iSubItem :=1;
+ p:=ApiCard.NameFromList(GetDlgItem(Dialog,IDC_EVENTLIST));
+ li.pszText :=FastAnsitoWideBuf(p,buf);
+ //GetDlgText(Dialog,IDC_EVENTLIST);
+ SendMessageW(wnd,LVM_SETITEMW,0,LPARAM(@li));
+ mFreeMem(li.pszText);
+end;
+
+function NewHook(Dialog:HWND;item:integer=-1):integer;
+var
+ wnd:HWND;
+ li:LV_ITEMW;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_HOOKLIST);
+ li.mask :=LVIF_TEXT;
+ if item<0 then
+ li.iItem :=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED)+1
+ else
+ li.iItem :=item;
+ li.iSubItem:=0;
+ li.pszText :=TranslateW('hook sample');
+ result:=SendMessageW(wnd,LVM_INSERTITEMW,0,LPARAM(@li));
+end;
+
+function DeleteHook(Dialog:HWND):integer;
+var
+ wnd:HWND;
+ i:integer;
+begin
+ result:=0;
+ wnd:=GetDlgItem(Dialog,IDC_HOOKLIST);
+ for i:=ListView_GetItemCount(wnd)-1 downto 0 do
+ begin
+ if ListView_GetItemState(wnd,i,LVIS_SELECTED)<>0 then
+ SendMessage(wnd,LVM_DELETEITEM,i,0);
+ end;
+ Listview_SetItemState(wnd,0,LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+end;
+
+function NewHKTableProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_KEYDOWN: begin
+ if (lParam and (1 shl 30))=0 then
+ begin
+ case wParam of
+ VK_F2: begin
+ i:=SendMessage(Dialog,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ if i>=0 then
+ PostMessageW(Dialog,LVM_EDITLABELW,i,0);
+ exit;
+ end;
+ VK_INSERT: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_HOOK_NEW,0);
+ exit;
+ end;
+ VK_DELETE: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_HOOK_DELETE,0);
+ exit;
+ end;
+ end;
+ end;
+ end;
+ end;
+ result:=CallWindowProc(OldTableProc,Dialog,hMessage,wParam,lParam);
+end;
+
+procedure SetIcons(Dialog:HWND);
+var
+ ti:TTOOLINFOW;
+ hwndTooltip:HWND;
+begin
+ hwndTooltip:=CreateWindowW(TOOLTIPS_CLASS,nil,TTS_ALWAYSTIP,
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ Dialog,0,hInstance,nil);
+
+ FillChar(ti,SizeOf(ti),0);
+ ti.cbSize :=sizeof(TOOLINFO);
+ ti.uFlags :=TTF_IDISHWND or TTF_SUBCLASS;
+ ti.hwnd :=dialog;
+ ti.hinst :=hInstance;
+
+ ti.lpszText:=TranslateW('Help');
+ ti.uId :=GetDlgItem(Dialog,IDC_EVENT_HELP);
+ SendMessage(ti.uId,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+ ti.uId :=GetDlgItem(Dialog,IDC_EVENT_CHELP);
+ SendMessage(ti.uId,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_HOOK_NEW);
+ ti.lpszText:=TranslateW('New');
+ SetButtonIcon(ti.uId,ACI_NEW);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+ ti.uId :=GetDlgItem(Dialog,IDC_HOOK_APPLY);
+ ti.lpszText:=TranslateW('Apply');
+ SetButtonIcon(ti.uId,ACI_APPLY);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+ ti.uId :=GetDlgItem(Dialog,IDC_HOOK_DELETE);
+ ti.lpszText:=TranslateW('Delete');
+ SetButtonIcon(ti.uId,ACI_DELETE);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+end;
+
+function DlgProcOpt(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ wnd:HWND;
+ lv:LV_COLUMNW;
+ i:integer;
+ tmp:pAnsiChar;
+ buf:array [0..255] of AnsiChar;
+begin
+ result:=0;
+ case hMessage of
+ WM_CLOSE: begin
+ ApiCard.Free;
+
+ UnhookEvent(onactchanged);
+ settings:=0;
+ end;
+
+ WM_INITDIALOG: begin
+ ApiCard:=CreateEventCard(Dialog);
+
+ wnd:=GetDlgItem(Dialog,IDC_HOOKLIST);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ FillChar(lv,SizeOf(lv),0);
+ lv.mask :=LVCF_TEXT or LVCF_WIDTH;
+ lv.pszText:=TranslateW('Description');
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW ,0,TLPARAM(@lv));
+ lv.pszText:=TranslateW('Name');
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW ,1,TLPARAM(@lv));
+ SendMessageW(wnd,LVM_SETCOLUMNWIDTH,1,LVSCW_AUTOSIZE_USEHEADER);
+// SendMessage (wnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_CHECKBOXES,LVS_EX_CHECKBOXES);
+ SendMessage (wnd,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
+ LVS_EX_FULLROWSELECT or LVS_EX_CHECKBOXES or LVS_EX_GRIDLINES);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ OldTableProc:=pointer(SetWindowLongPtrW(wnd,GWL_WNDPROC,LONG_PTR(@NewHKTableProc)));
+ TranslateDialogDefault(Dialog);
+
+ SetIcons(Dialog);
+
+ ApiCard.FillList(GetDlgItem(Dialog,IDC_EVENTLIST),
+ DBReadByte(0,DBBranch,'SrvListMode'));
+
+ FillActionList(GetDlgItem(Dialog,IDC_ACTIONLIST));
+ FillHookList(wnd);
+ ShowHookData(Dialog);
+
+ onactchanged:=HookEvent(ME_ACT_CHANGED,@ActListChange);
+ settings:=Dialog;
+ end;
+
+ WM_HELP: begin
+ tmp:=ApiCard.NameFromList(GetDlgItem(Dialog,IDC_EVENTLIST));
+ ApiCard.Event:=tmp;
+ mFreeMem(tmp);
+ ApiCard.Show;
+ end;
+
+ WM_RESETHOOKS:begin
+ FillHookList(GetDlgItem(Dialog,IDC_HOOKLIST));
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE,
+ CBN_EDITCHANGE,
+ CBN_SELCHANGE: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ case wParam shr 16 of
+ CBN_EDITCHANGE: begin
+ case loword(wParam) of
+ IDC_EVENTLIST: begin
+ tmp :=GetDlgText(Dialog,IDC_EVENTLIST,true);
+ ApiCard.Event:=tmp;
+ mFreeMem(tmp);
+ tmp:=ApiCard.Description;
+ SetDlgItemTextA(Dialog,IDC_DESCR,Translate(tmp));
+ mFreeMem(tmp);
+ end;
+ end;
+ end;
+
+ CBN_SELENDOK: begin
+ case loword(wParam) of
+ IDC_EVENTLIST: begin
+ i:=SendMessage(LOWORD(lParam),CB_GETCURSEL,0,0);
+ SendMessageA(LOWORD(lParam),CB_GETLBTEXT,i,TLPARAM(@buf));
+ ApiCard.Event:=@buf;
+ tmp:=ApiCard.Description;
+ SetDlgItemTextA(Dialog,IDC_DESCR,Translate(tmp));
+ mFreeMem(tmp);
+ end;
+ end;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_EVENT_CHELP: SendMessage(Dialog,WM_HELP,0,0);
+ IDC_EVENT_HELP : ;
+ IDC_HOOK_NEW : NewHook(Dialog);
+ IDC_HOOK_DELETE: DeleteHook(Dialog);
+ IDC_HOOK_APPLY : SaveHookData(Dialog);
+ end;
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ case integer(PNMHdr(lParam)^.code) of
+ PSN_APPLY: begin
+ SaveHookData(Dialog);
+ CheckHookList(GetDlgItem(Dialog,IDC_HOOKLIST));
+ SetAllHooks;
+ SaveHooks;
+ end;
+
+ NM_DBLCLK: begin
+ if PNMListView(lParam)^.iItem>=0 then
+ PostMessageW(PNMHdr(lParam)^.hWndFrom,LVM_EDITLABELW,
+ PNMListView(lParam)^.iItem,0);
+ end;
+
+ LVN_ENDLABELEDITW: begin
+ with PLVDISPINFOW(lParam)^ do
+ begin
+ if item.pszText<>nil then
+ begin
+ item.mask:=LVIF_TEXT;
+ SendMessageW(hdr.hWndFrom,LVM_SETITEMW,0,TLPARAM(@item));
+ end;
+ end;
+ result:=1;
+ end;
+
+ LVN_ITEMCHANGED: begin
+ if PNMLISTVIEW(lParam)^.uChanged=LVIF_STATE then
+ begin
+ i:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_FOCUSED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_FOCUSED);
+
+ if i>0 then // old focus
+ SaveHookData(Dialog,PNMLISTVIEW(lParam)^.iItem)
+ else if i<0 then // new focus
+ begin
+ ShowHookData(Dialog,PNMLISTVIEW(lParam)^.iItem);
+ end
+ else if (settings<>0) and
+ ((PNMLISTVIEW(lParam)^.uOldState or PNMLISTVIEW(lParam)^.uNewState)=$3000) then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/hooks/i_options.inc b/plugins/Actman30/hooks/i_options.inc
new file mode 100644
index 0000000000..4404cfbde6
--- /dev/null
+++ b/plugins/Actman30/hooks/i_options.inc
@@ -0,0 +1,71 @@
+{}
+const
+ opt_hook :PAnsiChar = 'Hook';
+ opt_hooks :PAnsiChar = 'Hooks';
+ opt_count :PAnsiChar = 'numhooks';
+ opt_flags :PAnsiChar = 'flags';
+ opt_descr :PAnsiChar = 'descr';
+ opt_name :PAnsiChar = 'name';
+ opt_action:PAnsiChar = 'action';
+
+procedure SaveHooks;
+var
+ section:array [0..63] of AnsiChar;
+ p,p1:PAnsiChar;
+ i,amount:integer;
+begin
+ DBDeleteGroup(0,DBBranch,opt_hooks);
+ amount:=0;
+ p1:=StrCopyE(section,opt_hooks);
+ p1^:='/'; inc(p1);
+ p1:=StrCopyE(p1,opt_hook);
+ for i:=0 to MaxHooks-1 do
+ begin
+ if (HookList[i].flags and ACF_ASSIGNED)=0 then
+ continue;
+
+ p:=StrEnd(IntToStr(p1,amount));
+ p^:='/'; inc(p);
+
+ with HookList[i] do
+ begin
+ StrCopy(p,opt_flags ); DBWriteDWord (0,DBBranch,section,flags);
+ StrCopy(p,opt_descr ); DBWriteUnicode(0,DBBranch,section,descr);
+ StrCopy(p,opt_name ); DBWriteString (0,DBBranch,section,name);
+ StrCopy(p,opt_action); DBWriteDWord (0,DBBranch,section,action);
+ end;
+ inc(amount);
+ end;
+ DBWriteByte(0,DBBranch,opt_count,amount);
+end;
+
+function LoadHooks:integer;
+var
+ section:array [0..63] of AnsiChar;
+ p,p1:PAnsiChar;
+ i:integer;
+begin
+ MaxHooks:=DBReadByte(0,DBBranch,opt_count);
+ result:=MaxHooks;
+ if MaxHooks>0 then
+ begin
+ GetMem (HookList ,MaxHooks*SizeOf(tHookRec));
+ FillChar(HookList^,MaxHooks*SizeOf(tHookRec),0);
+ p1:=StrCopyE(section,opt_hooks);
+ p1^:='/'; inc(p1);
+ p1:=StrCopyE(p1,opt_hook);
+ for i:=0 to MaxHooks-1 do
+ begin
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p);
+
+ with HookList[i] do
+ begin
+ StrCopy(p,opt_flags ); flags :=DBReadDWord (0,DBBranch,section);
+ StrCopy(p,opt_descr ); descr :=DBReadUnicode(0,DBBranch,section);
+ StrCopy(p,opt_name ); name :=DBReadString (0,DBBranch,section);
+ StrCopy(p,opt_action); action:=DBReadDWord (0,DBBranch,section);
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/i_cnst_chain.inc b/plugins/Actman30/i_cnst_chain.inc
new file mode 100644
index 0000000000..477d8ce137
--- /dev/null
+++ b/plugins/Actman30/i_cnst_chain.inc
@@ -0,0 +1,6 @@
+{resource constants}
+const
+ IDC_MACRO_LIST = 2501;
+ IDC_MACRO_NOWAIT = 2502;
+ IDC_MACRO_KEEPOLD = 2503;
+ IDC_MACRO_SAMETHREAD = 2504;
diff --git a/plugins/Actman30/i_cnst_contact.inc b/plugins/Actman30/i_cnst_contact.inc
new file mode 100644
index 0000000000..5b2cf3991d
--- /dev/null
+++ b/plugins/Actman30/i_cnst_contact.inc
@@ -0,0 +1,6 @@
+{resource constants}
+const
+ IDC_CONTACTLIST = 2141;
+ IDC_CNT_KEEP = 2142;
+ IDC_CNT_GET = 2143;
+ IDC_CNT_REFRESH = 2147;
diff --git a/plugins/Actman30/i_cnst_database.inc b/plugins/Actman30/i_cnst_database.inc
new file mode 100644
index 0000000000..01b6e382c5
--- /dev/null
+++ b/plugins/Actman30/i_cnst_database.inc
@@ -0,0 +1,18 @@
+{resource constants}
+const
+ IDC_RW_READ = 2601;
+ IDC_RW_WRITE = 2602;
+ IDC_RW_DELETE = 2603;
+ IDC_RW_MODULE = 2606;
+ IDC_RW_SETTING = 2608;
+ IDC_RW_VALUE = 2610;
+ IDC_RW_DATATYPE = 2611;
+ IDC_RW_CURRENT = 2614;
+ IDC_RW_PARAM = 2615;
+ IDC_RW_MANUAL = 2616;
+ IDC_RW_RESULT = 2619;
+ IDC_RW_LAST = 2620;
+ IDC_RW_SAVE = 2621;
+
+ IDC_CONTACTLIST = 2141;
+ IDC_CNT_REFRESH = 2142;
diff --git a/plugins/Actman30/i_cnst_dlgshare.inc b/plugins/Actman30/i_cnst_dlgshare.inc
new file mode 100644
index 0000000000..396499e68a
--- /dev/null
+++ b/plugins/Actman30/i_cnst_dlgshare.inc
@@ -0,0 +1,11 @@
+{all dialogs icons}
+const
+ IDI_NEW = 1025;
+ IDI_UP = 1026;
+ IDI_DOWN = 1027;
+ IDI_DELETE = 1028;
+ IDI_RELOAD = 1029;
+ IDI_TEST = 1037;
+ IDI_EXPORT = 1038;
+ IDI_IMPORT = 1039;
+ IDI_APPLY = 1044;
diff --git a/plugins/Actman30/i_cnst_inout.inc b/plugins/Actman30/i_cnst_inout.inc
new file mode 100644
index 0000000000..ff1cf50d7c
--- /dev/null
+++ b/plugins/Actman30/i_cnst_inout.inc
@@ -0,0 +1,17 @@
+{clipboard/file}
+const
+ IDC_FLAG_CLIP = 2454;
+ IDC_FLAG_MESSAGE = 2455;
+ IDC_CLIP_COPYTO = 2456;
+ IDC_CLIP_PASTE = 2457;
+ IDC_FILE_ENC = 2459;
+// IDC_CLIP_ANSI = 2459;
+// IDC_CLIP_WIDE = 2460;
+ IDC_FLAG_FILE = 2461;
+ IDC_FILE_PATH = 2462;
+ IDC_FILE_FILEBTN = 2463;
+ IDC_FILE_READ = 2464;
+ IDC_FILE_WRITE = 2465;
+ IDC_FILE_APPEND = 2466;
+
+ IDC_TEXT_SEND = 2453;
diff --git a/plugins/Actman30/i_cnst_jump.inc b/plugins/Actman30/i_cnst_jump.inc
new file mode 100644
index 0000000000..9782c9a9d3
--- /dev/null
+++ b/plugins/Actman30/i_cnst_jump.inc
@@ -0,0 +1,15 @@
+{resource constants}
+const
+ IDC_FLAG_MATH = 2506;
+ IDC_FLAG_TEXT = 2507;
+ IDC_FLAG_NOP = 2509;
+ IDC_FLAG_NOT = 2510;
+
+ IDC_JMP_MATH = 2511;
+ IDC_JMP_TEXT = 2512;
+ IDC_JMP_VALUE = 2513;
+ IDC_FLAG_CASE = 2514;
+ IDC_FLAG_BACK = 2515;
+ IDC_JMP_ACTLIST = 2522;
+ IDC_FLAG_BREAK = 2523;
+ IDC_FLAG_JUMP = 2524;
diff --git a/plugins/Actman30/i_cnst_message.inc b/plugins/Actman30/i_cnst_message.inc
new file mode 100644
index 0000000000..02db4c3d9b
--- /dev/null
+++ b/plugins/Actman30/i_cnst_message.inc
@@ -0,0 +1,17 @@
+{resource constants}
+const
+ IDC_MSG_TITLE = 2703;
+ IDC_MSG_TEXT = 2704;
+ IDC_MSGB_ARI = 2706;
+ IDC_MSGB_OK = 2707;
+ IDC_MSGB_OC = 2708;
+ IDC_MSGB_RC = 2709;
+ IDC_MSGB_YN = 2710;
+ IDC_MSGB_YNC = 2711;
+ IDC_MSGI_NONE = 2713;
+ IDC_MSGI_WARN = 2714;
+ IDC_MSGI_INFO = 2715;
+ IDC_MSGI_QUEST = 2716;
+ IDC_MSGI_ERROR = 2717;
+ IDC_MSG_RTL = 2718;
+ IDC_MSG_RIGHT = 2719;
diff --git a/plugins/Actman30/i_cnst_program.inc b/plugins/Actman30/i_cnst_program.inc
new file mode 100644
index 0000000000..93d2ed5d0b
--- /dev/null
+++ b/plugins/Actman30/i_cnst_program.inc
@@ -0,0 +1,13 @@
+{resource constants}
+const
+ IDC_FLAG_MINIMIZE = 2350;
+ IDC_EDIT_PRGPATH = 2352;
+ IDC_PROGRAM = 2353;
+ IDC_EDIT_PRGARGS = 2355;
+ IDC_EDIT_PROCTIME = 2356;
+ IDC_FLAG_NORMAL = 2360;
+ IDC_FLAG_HIDDEN = 2361;
+ IDC_FLAG_MAXIMIZE = 2362;
+ IDC_FLAG_CURPATH = 2363;
+ IDC_FLAG_PARALLEL = 2364;
+ IDC_FLAG_CONTINUE = 2365;
diff --git a/plugins/Actman30/i_cnst_service.inc b/plugins/Actman30/i_cnst_service.inc
new file mode 100644
index 0000000000..2e5f0cca83
--- /dev/null
+++ b/plugins/Actman30/i_cnst_service.inc
@@ -0,0 +1,12 @@
+const
+ IDC_FLAG_WPAR = 2154;
+ IDC_FLAG_LPAR = 2155;
+ IDC_EDIT_WPAR = 2156;
+ IDC_EDIT_LPAR = 2157;
+ IDC_EDIT_SERVICE = 2159;
+ IDC_WSTRUCT = 2160;
+ IDC_LSTRUCT = 2161;
+
+ IDC_SRV_RESULT = 2255;
+ IDC_RES_FREEMEM = 2256;
+ IDC_RES_UNICODE = 2257;
diff --git a/plugins/Actman30/i_cnst_settings.inc b/plugins/Actman30/i_cnst_settings.inc
new file mode 100644
index 0000000000..6728f953a9
--- /dev/null
+++ b/plugins/Actman30/i_cnst_settings.inc
@@ -0,0 +1,11 @@
+{resource constants}
+const
+ IDC_EDIT_FORMAT = 2144;
+ IDC_CNT_FILTER = 2145;
+ IDC_CNT_APPLY = 2146;
+
+ IDC_SERVICELIST = 2150;
+ IDC_SRV_APPLY = 2151;
+
+ IDC_FR_FLAG = 2155;
+ IDC_HC_WPAR = 2156;
diff --git a/plugins/Actman30/i_cnst_storage.inc b/plugins/Actman30/i_cnst_storage.inc
new file mode 100644
index 0000000000..adaa7690c6
--- /dev/null
+++ b/plugins/Actman30/i_cnst_storage.inc
@@ -0,0 +1,5 @@
+{resource constants}
+const
+ IDC_STORAGELIST = 2141;
+ IDC_FLAG_TO = 2142;
+ IDC_FLAG_FROM = 2143;
diff --git a/plugins/Actman30/i_cnst_text.inc b/plugins/Actman30/i_cnst_text.inc
new file mode 100644
index 0000000000..b25f155ef2
--- /dev/null
+++ b/plugins/Actman30/i_cnst_text.inc
@@ -0,0 +1,4 @@
+{text data}
+const
+ IDC_TXT_TEXT = 2190;
+ IDC_TXT_POST = 2191;
diff --git a/plugins/Actman30/i_const.inc b/plugins/Actman30/i_const.inc
new file mode 100644
index 0000000000..baf5b5edf3
--- /dev/null
+++ b/plugins/Actman30/i_const.inc
@@ -0,0 +1,31 @@
+{resource constants}
+const
+ // dialogs
+ IDD_ACTION = 1025;
+ IDD_ASK = 1028;
+
+ IDC_ACTION_TYPE = 2005;
+ IDC_STAT_ACTION = 2006;
+
+ IDC_ACTION_LIST = 2007;
+ IDC_ACTION_NEW = 2008;
+ IDC_ACTION_DELETE = 2009;
+ IDC_ACTION_UP = 2010;
+ IDC_ACTION_DOWN = 2011;
+
+ IDC_MACRO_LIST = 2012;
+ IDC_GROUP_NEW = 2015;
+ IDC_GROUP_RELOAD = 2016;
+ IDC_GROUP_DELETE = 2017;
+ IDC_GROUP_TEST = 2018;
+ IDC_GROUP_UP = 2019;
+ IDC_GROUP_DOWN = 2020;
+ IDC_GROUP_EXPORT = 2021;
+ IDC_GROUP_IMPORT = 2022;
+ IDC_ACTION_HELP = 2023;
+
+// Question
+ IDC_ASK = 1025;
+ IDC_YESALL = 1026;
+ IDC_NOALL = 1027;
+ IDC_APPEND = 1028;
diff --git a/plugins/Actman30/i_opt_dlg.inc b/plugins/Actman30/i_opt_dlg.inc
new file mode 100644
index 0000000000..62a0a6c66f
--- /dev/null
+++ b/plugins/Actman30/i_opt_dlg.inc
@@ -0,0 +1,52 @@
+{}
+var
+ xmlfilename:array [0..511] of WideChar;
+const
+ etMacro = 1; // Groups changed
+ etACT = 2; // Actions changed
+
+{$include i_opt_dlg2.inc}
+
+function OnOptInitialise(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ odp:TOPTIONSDIALOGPAGE;
+ ptr:pActionLink;
+ tmpl:pAnsiChar;
+ name:pansiChar;
+ proc:pointer;
+ i:integer;
+begin
+ result:=0;
+ NoDescription:=TranslateW('No Description');
+
+ StrCopyW(xmlfilename,'c:\export.xml');
+
+ DoInitCommonControls(ICC_USEREX_CLASSES);
+
+ FillChar(odp,SizeOf(odp),0);
+ odp.cbSize :=SizeOf(odp);
+ odp.flags :=ODPF_BOLDGROUPS;
+ odp.Position :=900003000;
+ odp.hInstance :=hInstance;
+ odp.szGroup.a :='Services';
+ odp.szTitle.a :='Actions';
+ odp.szTab.a :='Actions';
+ odp.pfnDlgProc :=@DlgProcOpt2;
+ odp.pszTemplate:=PAnsiChar(IDD_ACTION);
+ Options_AddPage(wParam,@odp);
+
+ ptr:=ActionLink;
+ while ptr<>nil do
+ begin
+ if @ptr^.AddOption<>nil then
+ begin
+ i:=ptr^.AddOption(tmpl,proc,name);
+ odp.pszTemplate:=tmpl;
+ odp.pfnDlgProc :=proc;
+ odp.szTab.a :=name;
+ Options_AddPage(wParam,@odp);
+ if i>0 then continue;
+ end;
+ ptr:=ptr^.Next;
+ end;
+end;
diff --git a/plugins/Actman30/i_opt_dlg2.inc b/plugins/Actman30/i_opt_dlg2.inc
new file mode 100644
index 0000000000..8313b4d4a3
--- /dev/null
+++ b/plugins/Actman30/i_opt_dlg2.inc
@@ -0,0 +1,1318 @@
+{}
+
+const
+ inoutfilter:pWideChar = 'XML files'#0'*.xml'#0'All files'#0'*.*'#0#0;
+const
+ MaxDescrLen = 128;
+const
+ hlpVariables = 30;
+ hlpAdvVariables = 31;
+
+var
+ DontReact:bool;
+ OldGroupTableProc,
+ OldActTableProc:pointer;
+ EventMask:dword;
+
+procedure ChangeListNotify(list:integer);
+var
+ p:pActModule;
+begin
+ p:=ModuleLink;
+ while p<>nil do
+ begin
+ SendMessage(p^.DlgHandle,WM_ACT_LISTCHANGE,list,0);
+ p:=p^.Next;
+ end;
+end;
+
+procedure ResetDialogs;
+var
+ p:pActModule;
+begin
+ p:=ModuleLink;
+ while p<>nil do
+ begin
+ SendMessage(p^.DlgHandle,WM_ACT_RESET,0,0);
+ p:=p^.Next;
+ end;
+end;
+
+procedure ClearDialogData;
+var
+ p:pActModule;
+begin
+ p:=ModuleLink;
+ while p<>nil do
+ begin
+ if p^.DlgHandle<>0 then ShowWindow(p^.DlgHandle,SW_HIDE);
+ p:=p^.Next;
+ end;
+end;
+
+function CheckChanges:dword;
+var
+ i,j:integer;
+ found:boolean;
+begin
+ result:=0;
+ // 1 - search new items (EditMacroList elements which don't exists in MacroList)
+ found:=true;
+ for i:=0 to EditMacroList.Count-1 do
+ begin
+ if (EditMacroList[i]^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ found:=false;
+ for j:=0 to MacroList.Count-1 do
+ begin
+ if (MacroList[j]^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ if EditMacroList[i]^.id=MacroList[j]^.id then
+ begin
+ found:=true;
+ break;
+ end;
+ end;
+ end;
+ if not found then break;
+ end;
+ end;
+ if not found then
+ result:=result or ACTM_NEW;
+ // 2 - search deleted items (MacroList elements which don't exists in EditMacroList)
+ found:=true;
+ for i:=0 to MacroList.Count-1 do
+ begin
+ if (MacroList[i]^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ found:=false;
+ for j:=0 to EditMacroList.Count-1 do
+ begin
+ if (EditMacroList[j]^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ if MacroList[i]^.id=EditMacroList[j]^.id then
+ begin
+ found:=true;
+ break;
+ end;
+ end;
+ end;
+ if not found then break;
+ end;
+ end;
+ if not found then
+ result:=result or ACTM_DELETE;
+ // 3 - resort? (maybe ANY EditMacroList position changes)
+end;
+
+procedure SetChanged(wnd:HWND;atype:integer);
+begin
+ SendMessage(GetParent(wnd),PSM_CHANGED,0,0);
+// if ((atype and etMacro)<>0) and (NewGroupList =GroupList ) then NewGroupList :=CloneGroupList;
+// if ((atype and etACT )<>0) and (NewActionList=ActionList) then NewActionList:=CloneActionList;
+end;
+
+procedure SetStart;
+begin
+ EditMacroList:=MacroList.Clone();
+end;
+
+// Cancel button pressed OR Edit window closed (After apply action)
+// No main list changed (except flags clearance - not necessary)
+// Edit macro list freeing with actions marked as introduced
+procedure SetCancel;
+var
+ i,j:integer;
+begin
+ // Delete changed data
+ EditMacroList.Clear(ACF_INTRODUCED);
+ EditMacroList.Free;
+
+ // Clear editing flags
+ for i:=0 to MacroList.Count-1 do
+ begin
+ with MacroList[i]^ do
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ for j:=0 to ActionCount-1 do
+ begin
+ ActionList^[j].flags:=ActionList^[j].flags and not ACF_REPLACED;
+ end;
+ end;
+ end;
+end;
+
+// SAVE: fill edit macro list by dialog options,
+// Free main macro list with actions marked as replaced
+// copy content to main macro list (state as at option editing start)
+// clear "introduced" and "replaced" flags
+procedure SetSave(Dialog:HWND);
+var
+ i,j:integer;
+ TmpMacroList:tMacroList;
+ TmpMacroCount:integer;
+ wnd:HWND;
+ li:LV_ITEMW;
+begin
+ wnd:=MacroListWindow;
+ TmpMacroCount:=SendMessageW(wnd,LVM_GETITEMCOUNT,0,0);
+
+ // need to clear flags and resort
+ if TmpMacroCount>0 then
+ begin
+ // Clear actions editing flags
+ for i:=0 to EditMacroList.Count-1 do
+ begin
+ with EditMacroList[i]^ do
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ for j:=0 to ActionCount-1 do
+ begin
+ ActionList^[j].flags:=ActionList^[j].flags and not ACF_INTRODUCED;
+ end;
+ end;
+ end;
+
+ TmpMacroList:=tMacroList.Create(TmpMacroCount);
+
+ // resort/copy macros
+ li.mask :=LVIF_PARAM;
+ li.iSubItem:=0;
+ for i:=0 to TmpMacroCount-1 do
+ begin
+ li.iItem:=i;
+ SendMessageW(wnd,LVM_GETITEMW,0,lparam(@li)); // GetLParam(wnd,i);
+ move(EditMacroList[loword(li.lParam)]^,TmpMacroList[i]^,SizeOf(tMacroRecord));
+ if (li.lParam and ACF_FIRSTRUN)<>0 then
+ TmpMacroList[i]^.flags:=TmpMacroList[i]^.flags or ACF_FIRSTRUN
+ else
+ TmpMacroList[i]^.flags:=TmpMacroList[i]^.flags and not ACF_FIRSTRUN;
+ li.lParam:=(li.lParam and (not $FFFF)) or i;
+ SendMessageW(wnd,LVM_SETITEMW,0,lparam(@li));
+ end;
+
+ EditMacroList.Free;
+ EditMacroList:=TmpMacroList;
+ end;
+
+ MacroList.Clear(ACF_REPLACED);
+ MacroList.Free;
+ MacroList:=EditMacroList.Clone;
+end;
+
+// Fill action type combobox
+function FillActTypeList(list:hwnd):HWND;
+var
+ cbei:TCOMBOBOXEXITEMW;
+ il:HIMAGELIST;
+ i:integer;
+ buf:array [0..127] of WideChar;
+ p:pActModule;
+ rc:TRECT;
+ dlg:HWND;
+begin
+ il:=ImageList_Create(16,16,ILC_COLOR32 or ILC_MASK,0,1);
+ SendMessage(list,CB_RESETCONTENT,0,0);
+
+ FillChar(cbei,SizeOf(cbei),0);
+ cbei.mask:=CBEIF_IMAGE or CBEIF_SELECTEDIMAGE or CBEIF_TEXT or CBEIF_LPARAM;
+ p:=ModuleLink;
+ i:=0;
+ // initial action dialogs position
+ SetRect(rc,134,22,0,0);
+ dlg:=GetParent(list);
+ MapDialogRect(dlg,rc);
+ while p<>nil do
+ begin
+ StrCopy(StrCopyE(@buf,IcoLibPrefix),p^.Name);
+ ImageList_AddIcon(il,CallService(MS_SKIN2_GETICON,0,lparam(@buf)));
+
+ cbei.pszText :=TranslateW(FastAnsiToWideBuf(p^.Name,buf));
+ cbei.iItem :=i;
+ cbei.lParam :=p^.Hash;
+ cbei.iImage :=i;
+ cbei.iSelectedImage:=i;
+ if SendMessageW(list,CBEM_INSERTITEMW,0,lparam(@cbei))=-1 then
+ break;
+ p^.DlgHandle:=p^.Dialog(dlg);
+ SetWindowPos(p^.DlgHandle,0,rc.left,rc.top,0,0,SWP_NOZORDER or SWP_NOSIZE or SWP_HIDEWINDOW);
+ p:=p^.Next;
+ inc(i);
+ end;
+ ImageList_Destroy(SendMessage(list,CBEM_SETIMAGELIST,0,il));
+
+ SendMessage(list,CB_SETCURSEL,0,0);
+ result:=GetLink(CB_GetData(list,0))^.DlgHandle;
+end;
+
+//----- Action list stuff -----
+
+procedure SHActButtons(Dialog:HWND;mode:integer);
+begin
+ ShowWindow(GetDlgItem(Dialog,IDC_STAT_ACTION),mode);
+ ShowWindow(GetDlgItem(Dialog,IDC_ACTION_TYPE),mode);
+ if mode=SW_HIDE then
+ ClearDialogData;
+end;
+
+procedure CheckActListDirectionButtons(Dialog:HWND);
+var
+ wnd:HWND;
+ dir:integer;
+ okup,okdown:boolean;
+begin
+ wnd:=ActionListWindow;
+
+ dir:=LV_CheckDirection(wnd);
+ okup :=odd(loword(dir));
+ okdown:=(loword(dir) and 2)<>0;
+
+ EnableWindow(GetDlgItem(Dialog,IDC_ACTION_UP ),okup);
+ EnableWindow(GetDlgItem(Dialog,IDC_ACTION_DOWN),okdown);
+ SendMessage(wnd,LVM_ENSUREVISIBLE,hiword(dir)-1,0);
+end;
+
+procedure CheckActListButtons(Dialog:HWND);
+var
+ mode:integer;
+ wnd:HWND;
+ b:boolean;
+begin
+ wnd:=ActionListWindow;
+ b:=SendMessage(wnd,LVM_GETITEMCOUNT,0,0)>0;
+ if b then
+{
+ ListView_SetItemState(wnd,next,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+}
+ mode:=SW_SHOW
+ else
+ mode:=SW_HIDE;
+
+ SHActButtons(Dialog,mode);
+
+ EnableWindow(wnd,b);
+ EnableWindow(GetDlgItem(Dialog,IDC_ACTION_HELP ),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_TEST ),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_ACTION_DELETE),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_ACTION_TYPE ),b);
+
+ CheckActListDirectionButtons(Dialog);
+end;
+
+// Fill dialog fields by choosen action
+procedure FillAction(Dialog:HWND;act:tBaseAction);
+var
+ p:pActModule;
+ i:lresult;
+ wnd:HWND;
+begin
+ if act<>nil then
+ begin
+ p:=GetLink(act.UID);
+ if p<>nil then
+ SendMessage(p^.DlgHandle,WM_ACT_SETVALUE,0,tlparam(act));
+ end
+ // for newly added and activated action
+ else
+ p:=ModuleLink;
+
+ if p<>nil then
+ begin
+ wnd:=GetDlgItem(Dialog,IDC_ACTION_TYPE);
+ i:=CB_SelectData(wnd,tlparam(p^.Hash));
+ ShowWindow(p^.DlgHandle,SW_SHOW);
+ // Saving "normal" action type
+ if p^.Hash>10 then
+ begin
+ SetWindowLongPtrW(wnd,GWLP_USERDATA,i);
+ end;
+ end;
+end;
+
+// Fill Chain list
+procedure FillActionList(Dialog:HWND;Macro:pMacroRecord);
+var
+ idx:integer;
+ wnd:HWND;
+ li:LV_ITEMW;
+begin
+ wnd:=ActionListWindow;
+ SendMessage(wnd,LVM_DELETEALLITEMS,0,0);
+
+ if (Macro<>nil) and (Macro^.ActionCount>0) then
+ begin
+ li.mask :=LVIF_TEXT or LVIF_PARAM;
+ li.iSubitem:=0;
+ idx:=0;
+ while idx<Macro^.ActionCount do
+ begin
+ li.pszText:=Macro^.ActionList^[idx].ActionDescr;
+ li.iItem :=idx;
+ li.lParam :=tlparam(Macro^.ActionList^[idx]);
+ SendMessageW(wnd,LVM_INSERTITEMW,0,tlparam(@li));
+ ListView_SetCheckState(wnd,idx,(Macro^.ActionList^[idx].flags and ACF_DISABLED)=0);
+ inc(idx);
+ end;
+
+ Listview_SetItemState(wnd,0,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+
+ FillAction(Dialog,Macro^.ActionList^[0]);
+ end;
+ CheckActListButtons(Dialog);
+end;
+
+// change current action name ONLY IN LIST
+procedure ChangeActionName(Dialog:HWND; num:integer=-1;str:PWideChar=nil);
+var
+ li:LV_ITEMW;
+ wnd:HWND;
+ buf:array [0..127] of WideChar;
+begin
+ wnd:=ActionListWindow;
+ if num<0 then
+ li.iItem:=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED)
+
+ else
+ li.iItem:=num;
+ if li.iItem>=0 then
+ begin
+ li.iSubItem:=0;
+ // getting SubAction number
+ li.mask:=LVIF_PARAM;
+ SendMessage(wnd,LVM_GETITEM,0,tlparam(@li));
+
+ // changing to default name
+ if str=nil then
+ begin
+ str:=StrCopyEW(@buf,TranslateW('Action'));
+ str^:=' '; inc(str);
+ IntToStr(str,SendMessage(wnd,LVM_GETITEMCOUNT,0,0));
+ str:=@buf;
+ end;
+
+ li.mask :=LVIF_TEXT;
+ li.pszText:=str;
+ SendMessageW(wnd,LVM_SETITEMW,0,tlparam(@li));
+ end;
+end;
+
+procedure SaveAction(Dialog:HWND;listnum:integer;actptr:tBaseAction);
+var
+ wnd:HWND;
+// li:LV_ITEMW;
+// arr: array [0..255] of WideChar;
+ p:pActModule;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_ACTION_TYPE);
+ p:=GetLink(CB_GetData(wnd));
+ if p^.Hash<10 then
+ begin
+ p:=GetLink(CB_GetData(wnd,GetWindowLongPtrW(wnd,GWLP_USERDATA)));
+ end;
+
+ wnd:=ActionListWindow;
+
+ if listnum<0 then
+ begin
+ listnum:=SendMessageW(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ if listnum<0 then
+ exit;
+ actptr:=tBaseAction(LV_GetLParam(wnd,listnum));
+ end;
+
+ // changed existing action
+ if actptr<>nil then
+ begin
+ if (actptr.flags and ACF_INTRODUCED)<>0 then // new but changed
+ actptr.Free
+ else // old
+ actptr.flags:=actptr.flags or ACF_REPLACED;
+ end;
+
+ // Action saving
+ actptr:=p.Create;
+ SendMessage(p.DlgHandle,WM_ACT_SAVE,0,tlparam(actptr));
+ actptr.flags:=actptr.flags or ACF_INTRODUCED;
+{ maybe do it at full chain saving?
+
+ li.iItem :=listnum;
+ li.mask :=LVIF_TEXT;
+ li.iSubItem :=0;
+ li.pszText :=@arr;
+ li.cchTextMax:=SizeOf(arr) div SizeOf(WideChar);
+ SendDlgItemMessageW(Dialog,IDC_ACTION_LIST,LVM_GETITEMW,0,tlparam(@li));
+ StrDupW(actptr.ActionDescr,arr);
+
+ if ListView_GetCheckState(wnd,listnum)=0 then
+ actptr.flags:=actptr.flags or ACF_DISABLED;
+}
+ LV_SetLParam(wnd,tlparam(actptr),listnum);
+end;
+
+procedure BuildActionChain(Dialog:HWND;group:integer=-1);
+var
+ item:integer;
+ wnd:HWND;
+ idx:integer;
+ li:LV_ITEMW;
+ arr: array [0..255] of WideChar;
+begin
+ idx:=loword(LV_GetLParam(MacroListWindow,group));
+ if idx>=0 then // we have macro to save
+ begin
+ SaveAction(Dialog,-1,nil);
+
+ with EditMacroList[idx]^ do
+ begin
+ if ActionCount>0 then
+ begin
+ ActionCount:=0;
+ FreeMem(ActionList);
+ ActionList:=nil;
+ end;
+ end;
+
+ wnd:=ActionListWindow;
+ with EditMacroList[idx]^ do
+ begin
+ ActionCount:=SendMessageW(wnd,LVM_GETITEMCOUNT,0,0);
+ if ActionCount>0 then // have some actions - need to build list
+ begin
+ // fix count for empty actions
+ item:=0;
+ idx:=0;
+ while item<ActionCount do
+ begin
+ // if created but not changed action (fools proof)
+ if LV_GetLParam(wnd,item)<>0 then
+ Inc(idx);
+ Inc(item);
+ end;
+ // if REAL amount to save>0 (macro not empty)
+ if idx>0 then
+ begin
+ GetMem(ActionList,SizeOf(tBaseAction)*idx);
+
+ li.mask :=LVIF_TEXT;
+ li.iSubItem :=0;
+ li.pszText :=@arr;
+ li.cchTextMax:=SizeOf(arr) div SizeOf(WideChar);
+
+ idx:=0;
+ for item:=0 to ActionCount-1 do
+ begin
+ ActionList^[idx]:=tBaseAction(LV_GetLParam(wnd,item));
+ if ActionList^[idx]<>nil then
+ begin
+ // set name and enabled/disabled flag
+ li.iItem:=item;
+ SendDlgItemMessageW(Dialog,IDC_ACTION_LIST,LVM_GETITEMW,0,tlparam(@li));
+ mFreeMem(ActionList^[idx].ActionDescr);
+ StrDupW(ActionList^[idx].ActionDescr,arr);
+
+ if ListView_GetCheckState(wnd,item)=0 then
+ ActionList^[idx].flags:=ActionList^[item].flags or ACF_DISABLED
+ else
+ ActionList^[idx].flags:=ActionList^[item].flags and not ACF_DISABLED;
+ inc(idx);
+ end;
+ end;
+ end;
+ ActionCount:=idx; // fix for empty actions
+ end;
+ end;
+ end;
+end;
+
+// action (chain) table procedure (key hook)
+function NewActTableProc(Dialog:HWnd;hMessage:uint;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_KEYDOWN: begin
+ if (lParam and (1 shl 30))=0 then
+ begin
+ case wParam of
+ VK_F2: begin
+ i:=SendMessage(Dialog,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ if i>=0 then
+ PostMessageW(Dialog,LVM_EDITLABELW,i,0);
+ exit;
+ end;
+ VK_UP: begin
+ if (GetKeyState(VK_CONTROL) and $8000)<>0 then
+ begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_ACTION_UP,0);
+ exit;
+ end;
+ end;
+ VK_DOWN: begin
+ if (GetKeyState(VK_CONTROL) and $8000)<>0 then
+ begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_ACTION_DOWN,0);
+ exit;
+ end;
+ end;
+ VK_INSERT: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_ACTION_NEW,0);
+ exit;
+ end;
+ VK_DELETE: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_ACTION_DELETE,0);
+ exit;
+ end;
+ end;
+ end;
+ end;
+ end;
+ result:=CallWindowProc(OldActTableProc,Dialog,hMessage,wParam,lParam);
+end;
+
+//----- Macro list stuff -----
+
+// action group table procedure (key hook)
+function NewGroupTableProc(Dialog:HWnd;hMessage:uint;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_KEYDOWN: begin
+ if (lParam and (1 shl 30))=0 then
+ begin
+ case wParam of
+ VK_F2: begin
+ i:=SendMessage(Dialog,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ if i>=0 then
+ PostMessageW(Dialog,LVM_EDITLABELW,i,0);
+ exit;
+ end;
+ VK_INSERT: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_GROUP_NEW,0);
+ exit;
+ end;
+ VK_DELETE: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_GROUP_DELETE,0);
+ exit;
+ end;
+ VK_UP: begin
+ if (GetKeyState(VK_CONTROL) and $8000)<>0 then
+ begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_GROUP_UP,0);
+ exit;
+ end;
+ end;
+ VK_DOWN: begin
+ if (GetKeyState(VK_CONTROL) and $8000)<>0 then
+ begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_GROUP_DOWN,0);
+ exit;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+ result:=CallWindowProc(OldGroupTableProc,Dialog,hMessage,wParam,lParam);
+end;
+
+function AddMacro(Dialog:HWND;MacroNum:cardinal):integer;
+var
+ li:LV_ITEMW;
+ list:HWND;
+begin
+ with EditMacroList[MacroNum]^ do
+ begin
+ list:=MacroListWindow;
+ li.mask :=LVIF_PARAM+LVIF_TEXT;
+ li.iItem :=SendMessage(list,LVM_GETNEXTITEM,-1,LVNI_FOCUSED)+1;
+ li.iSubItem :=0;
+ li.lParam :=MacroNum;
+ li.pszText :=@descr;
+ li.iItem :=SendMessageW(list,LVM_INSERTITEMW,0,lparam(@li));
+ if li.iItem>0 then
+ dec(li.iItem);
+ ListView_SetItemState(list,li.iItem,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+ result:=li.iItem;
+ end;
+end;
+
+function MoveMacro(list:HWND;num:integer;incr:integer):integer;
+var
+ i,j:integer;
+begin
+ if num<0 then
+ begin
+ result:=-1;
+ j:=SendMessage(list,LVM_GETITEMCOUNT,0,0)-1;
+ if incr<0 then // up, from beginning
+ begin
+ for i:=0 to j do
+ begin
+ if SendMessage(list,LVM_GETITEMSTATE,i,LVIS_SELECTED)<>0 then
+ begin
+ if i=0 then break; // first selected is first already, nothing to move
+ LV_MoveItem(list,incr,i);
+ if result<0 then result:=i+incr;
+ end;
+ end;
+ end
+ else // down, from the end
+ begin
+ for i:=j downto 0 do
+ begin
+ if SendMessage(list,LVM_GETITEMSTATE,i,LVIS_SELECTED)<>0 then
+ begin
+ if i=j then break; // last selected is last already, nothing to move
+ LV_MoveItem(list,incr,i);
+ if result<0 then result:=i+incr;
+ end;
+ end;
+ end;
+ end
+ else
+ begin
+ LV_MoveItem(list,incr,num);
+ result:=num;
+ end;
+end;
+
+// enable/disable navigation chain buttons
+procedure CheckMacroListDirectionButtons(Dialog:HWND);
+var
+ wnd:HWND;
+ dir:integer;
+ okup,okdown:boolean;
+begin
+ wnd:=MacroListWindow;
+ dir:=LV_CheckDirection(wnd);
+ okup :=odd(loword(dir));
+ okdown:=(loword(dir) and 2)<>0;
+
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_UP ),okup);
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_DOWN),okdown);
+ SendMessage(wnd,LVM_ENSUREVISIBLE,hiword(dir)-1,0);
+end;
+
+procedure CheckMacroList(Dialog:HWND);
+var
+ wnd:HWND;
+ b:boolean;
+begin
+ wnd:=MacroListWindow;
+
+ b:=SendMessage(wnd,LVM_GETITEMCOUNT,0,0)>0;
+ if not b then
+ CheckActListButtons(Dialog);
+
+ EnableWindow(wnd,b);
+ EnableWindow(GetDlgItem(Dialog,IDC_ACTION_NEW ),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_DELETE),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_EXPORT),b);
+
+ CheckMacroListDirectionButtons(Dialog);
+end;
+
+// Fill action group list and disable chain controls
+function FillMacroList(Dialog:hwnd):integer;
+var
+ CurMacro:pMacroRecord;
+ i:integer;
+ list:HWND;
+ lvi:TLVITEMW;
+begin
+ SendDlgItemMessage(Dialog,IDC_ACTION_LIST,LVM_DELETEALLITEMS,0,0);
+ CheckActListButtons(Dialog);
+
+ list:=MacroListWindow;
+
+ SendMessage(list,LVM_DELETEALLITEMS,0,0);
+ result:=-1;
+ if EditMacroList.Count>0 then
+ begin
+ CurMacro:=EditMacroList[0];
+ lvi.mask:=LVIF_TEXT+LVIF_PARAM;
+ lvi.iSubItem:=0;
+ for i:=0 to EditMacroList.Count-1 do
+ begin
+ if (CurMacro^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ lvi.iItem :=i;
+
+ lvi.lParam:=i;
+ if (CurMacro^.flags and ACF_FIRSTRUN)<>0 then
+ lvi.lParam:=lvi.lParam or ACF_FIRSTRUN;
+
+ lvi.pszText:=@(CurMacro^.descr);
+ SendMessageW(list,LVM_INSERTITEMW,0,tlparam(@lvi));
+ inc(result);
+ end;
+ inc(CurMacro);
+ end;
+ end;
+
+ CheckMacroList(Dialog);
+//?? SendMessage(list,CB_SETCURSEL,0,0);
+ SendMessage(list,LVM_SETCOLUMNWIDTH,0,LVSCW_AUTOSIZE_USEHEADER);
+
+ ListView_SetItemState(list,0,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+end;
+
+//----- Other stuff -----
+
+procedure SetButtonIcons2(Dialog:HWND);
+var
+ ti:TTOOLINFOW;
+ hwndTooltip:HWND;
+begin
+ hwndTooltip:=CreateWindowW(TOOLTIPS_CLASS,nil,TTS_ALWAYSTIP,
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ Dialog,0,hInstance,nil);
+
+ FillChar(ti,SizeOf(ti),0);
+ ti.cbSize :=sizeof(TOOLINFO);
+ ti.uFlags :=TTF_IDISHWND or TTF_SUBCLASS;
+ ti.hwnd :=Dialog;
+ ti.hinst :=hInstance;
+
+ ti.uId :=GetDlgItem(Dialog,IDC_ACTION_HELP);
+ ti.lpszText:=TranslateW('Help');
+ SendMessage(ti.uId,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_ACTION_NEW);
+ ti.lpszText:=TranslateW('New');
+ OptSetButtonIcon(ti.uId,ACI_NEW);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+{
+ hNew:=GetDlgItem(Dialog,IDC_NEW);
+ SendMessage (hNew,BUTTONADDTOOLTIP,TWPARAM(TranslateW('New')),BATF_UNICODE);
+ OptSetButtonIcon(hNew,ACI_NEW);
+}
+
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_NEW);
+ OptSetButtonIcon(ti.uId,ACI_NEW);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_ACTION_UP);
+ ti.lpszText:=TranslateW('Up');
+ OptSetButtonIcon(ti.uId,ACI_UP);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_UP);
+ OptSetButtonIcon(ti.uId,ACI_UP);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_ACTION_DOWN);
+ ti.lpszText:=TranslateW('Down');
+ OptSetButtonIcon(ti.uId,ACI_DOWN);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_DOWN);
+ OptSetButtonIcon(ti.uId,ACI_DOWN);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_ACTION_DELETE);
+ ti.lpszText:=TranslateW('Delete');
+ OptSetButtonIcon(ti.uId,ACI_DELETE);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_DELETE);
+ OptSetButtonIcon(ti.uId,ACI_DELETE);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+{
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_RELOAD);
+ ti.lpszText:=TranslateW('Reload');
+ OptSetButtonIcon(ti.uId,ACI_RELOAD);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+}
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_TEST);
+ ti.lpszText:=TranslateW('Test');
+ OptSetButtonIcon(ti.uId,ACI_TEST);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_IMPORT);
+ ti.lpszText:=TranslateW('Import');
+ OptSetButtonIcon(ti.uId,ACI_IMPORT);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_GROUP_EXPORT);
+ ti.lpszText:=TranslateW('Export');
+ OptSetButtonIcon(ti.uId,ACI_EXPORT);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+end;
+
+function DlgProcOpt2(Dialog:HWnd;hMessage:uint;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ wnd:HWND;
+ p:pActModule;
+ i,j,num:int_ptr;
+ lvflag:integer;
+ li:LV_ITEMW;
+ lv:LV_COLUMNW;
+begin
+ result:=0;
+ case hMessage of
+ WM_DESTROY: begin
+ SetCancel;
+ end;
+
+ WM_INITDIALOG: begin
+ SetStart;
+ DontReact :=true;
+ // variant - put after all dialogs adds (to translate them too)
+ TranslateDialogDefault(Dialog);
+ // For some actions
+ MacroListWindow :=GetDlgItem(Dialog,IDC_MACRO_LIST);
+ ActionListWindow:=GetDlgItem(Dialog,IDC_ACTION_LIST);
+
+ SetButtonIcons2(Dialog);
+ wnd:=ActionListWindow;
+ SendMessage(wnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_CHECKBOXES,LVS_EX_CHECKBOXES);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ FillChar(lv,SizeOf(lv),0);
+ lv.mask:=LVCF_WIDTH;
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW ,0,tlparam(@lv));
+ SendMessageW(wnd,LVM_SETCOLUMNWIDTH,0,LVSCW_AUTOSIZE_USEHEADER);
+
+ // action type combobox
+ FillActTypeList(GetDlgItem(Dialog,IDC_ACTION_TYPE));
+
+ // XML import/export service
+ if ServiceExists(MS_SYSTEM_GET_XI)=0 then
+ begin
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_EXPORT),false);
+ EnableWindow(GetDlgItem(Dialog,IDC_GROUP_IMPORT),false);
+ end;
+
+ OldActTableProc :=pointer(SetWindowLongPtrW(wnd,GWL_WNDPROC,long_ptr(@NewActTableProc)));
+ OldGroupTableProc:=pointer(SetWindowLongPtrW(MacroListWindow,
+ GWL_WNDPROC,long_ptr(@NewGroupTableProc)));
+
+ ClearDialogData;
+ ResetDialogs;
+
+ // fill group list
+ wnd:=MacroListWindow;
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ lv.mask:=LVCF_WIDTH;
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW,0,tlparam(@lv));
+ FillMacroList(Dialog);
+ ChangeListNotify(1);
+
+ // fill current group
+ FillActionList(Dialog,EditMacroList[0]);
+ ChangeListNotify(2);
+ EventMask:=0;
+ DontReact:=false;
+ end;
+
+ WM_COMMAND: begin
+ if DontReact then exit;
+ case wParam shr 16 of
+{
+ EN_CHANGE: begin
+// check for group renaming
+ if loword(wParam)<>IDC_EDIT_FORMAT then
+ begin
+ SetChanged(Dialog,etACT);
+ end;
+ end;
+}
+ CBN_SELCHANGE: begin
+ case loword(wParam) of
+ IDC_ACTION_TYPE: begin
+ ClearDialogData;
+ p:=GetLink(CB_GetData(lParam));
+ ShowWindow(p^.DlgHandle,SW_SHOW);
+
+ // Saving prevoius "normal" action type
+ if p^.Hash>10 then
+ begin
+ SetWindowLongPtrW(lParam,GWLP_USERDATA,
+ SendMessage(lParam,CB_GETCURSEL,0,0));
+ SetChanged(Dialog,etACT);
+ end;
+ end;
+ end;
+ end;
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_GROUP_RELOAD, // don't affect to saved (DB) datas
+ IDC_ACTION_HELP,
+ IDC_GROUP_EXPORT,
+ IDC_GROUP_TEST: ;
+
+ IDC_GROUP_UP,
+ IDC_GROUP_DOWN,
+ IDC_GROUP_NEW : SetChanged(Dialog,etMacro);
+
+ IDC_GROUP_DELETE, // action deleting with subactions
+ IDC_GROUP_IMPORT,
+ IDC_ACTION_NEW,
+ IDC_ACTION_DELETE,
+ IDC_ACTION_UP,
+ IDC_ACTION_DOWN: begin
+ SetChanged(Dialog,etMacro+etACT);
+ end;
+ else
+ SetChanged(Dialog,etACT);
+ end;
+
+ case loword(wParam) of
+{
+ IDC_GROUP_EXPORT: begin
+ if ShowDlgW(xmlfilename,xmlfilename,TranslateW(inoutfilter),false) then
+ begin
+ wnd:=MacroListWindow;
+ for i:=0 to ListView_GetItemCount(wnd)-1 do
+ begin
+ if ListView_GetItemState(wnd,i,LVIS_SELECTED)<>0 then
+ begin
+ with EditMacroList[LV_GetLParam(wnd,i)] do
+ if (flags and ACF_ASSIGNED)<>0 then // must be always true
+ flags:=flags or ACF_EXPORT;
+ end
+ else
+ with EditMacroList[i] do
+ if (flags and (ACF_EXPORT or ACF_ASSIGNED))=
+ (ACF_EXPORT or ACF_ASSIGNED) then
+ flags:=flags and not ACF_EXPORT;
+ end;
+ i:=ACIO_EXPORT or ACIO_SELECTED;
+ if GetFSize(xmlfilename)>0 then
+ if MessageBoxW(Dialog,TranslateW('Append data to file'),
+ PluginName,MB_YESNO+MB_ICONWARNING)=IDYES then
+ i:=i or ACIO_APPEND;
+//!!!!!!!!!!!!!!!
+// we MUST Export EditMacroList, NOT MacroList
+// OR
+// Use "Apply" code before
+ CallService(MS_ACT_INOUT,i,TLPARAM(@xmlfilename));
+ for i:=0 to MaxGroups-1 do
+ with EditMacroList[i] do
+ if (flags and (ACF_EXPORT or ACF_ASSIGNED))=
+ (ACF_EXPORT or ACF_ASSIGNED) then
+ flags:=flags and not ACF_EXPORT;
+ end;
+ end;
+}
+ IDC_GROUP_IMPORT: begin
+ if ShowDlgW(xmlfilename,xmlfilename,TranslateW(inoutfilter)) then
+ begin
+ // "save" selected macro (in edit list only)
+ BuildActionChain(Dialog);
+
+ if Import(EditMacroList,xmlfilename,0)<>0 then
+// if CallService(MS_ACT_INOUT,0,TLPARAM(@xmlfilename))<>0 then
+ begin
+ // copy from WM_INITDIALOG
+ FillMacroList(Dialog);
+ ChangeListNotify(1);
+
+ // fill current group
+ FillActionList(Dialog,EditMacroList[0]);
+ ChangeListNotify(2);
+
+ CheckMacroListDirectionButtons(Dialog);
+ end;
+ end;
+ end;
+
+ IDC_GROUP_TEST: begin
+ li.mask :=LVIF_PARAM;
+ li.iSubItem:=0;
+ // Get selected macro
+ li.iItem :=SendMessage(MacroListWindow,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ // "save" selected macro (in edit list only)
+ BuildActionChain(Dialog,li.iItem);
+ // Get lParam = EditMacroList element
+ SendMessageW(MacroListWindow,LVM_GETITEMW,0,tlparam(@li));
+
+ ActionStarter(EditMacroList[loword(li.lParam)],nil,ACTP_SAMETHREAD or ACTP_WAIT);
+ end;
+
+ IDC_GROUP_NEW: begin
+ if AddMacro(Dialog,EditMacroList.NewMacro())>=0 then
+ begin
+ CheckMacroList(Dialog);
+ ChangeListNotify(1);
+ end;
+ end;
+ IDC_GROUP_DELETE: begin
+ DontReact:=true;
+ wnd:=MacroListWindow;
+ for i:=ListView_GetItemCount(wnd)-1 downto 0 do
+ begin
+ if ListView_GetItemState(wnd,i,LVIS_SELECTED)<>0 then
+ begin
+ num:=Loword(LV_GetLParam(wnd,i));
+ // mark old to delete on apply (must be first)
+ with EditMacroList[num]^ do
+ for j:=0 to ActionCount-1 do
+ ActionList[j].flags:=ActionList[j].flags or ACF_REPLACED;
+ // delete new actions
+ FreeMacro(EditMacroList[num],ACF_INTRODUCED);
+
+ SendMessage(wnd,LVM_DELETEITEM,i,0);
+ end;
+ end;
+ Listview_SetItemState(wnd,-1,0,LVIS_FOCUSED or LVIS_SELECTED);
+ DontReact:=false;
+ SendDlgItemMessage(Dialog,IDC_ACTION_LIST,LVM_DELETEALLITEMS,0,0);
+ Listview_SetItemState(wnd,0,LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+ CheckMacroList(Dialog);
+ ChangeListNotify(1);
+ end;
+
+ IDC_ACTION_HELP: begin
+ SendMessage(
+ GetLink(CB_GetData(GetDlgItem(Dialog,IDC_ACTION_TYPE)))^.DlgHandle,
+ WM_HELP,0,0);
+ end;
+
+ IDC_ACTION_NEW: begin
+ wnd:=ActionListWindow;
+ li.mask :=LVIF_PARAM;
+ i :=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ li.iItem :=i+1;
+ li.iSubItem:=0;
+ li.lParam :=0;{NewAction(NewActionList,NewMaxActions);}
+ SendMessageW(wnd,LVM_INSERTITEMW,0,tlparam(@li));
+ ListView_SetCheckState(wnd,li.iItem,true);
+ if li.iItem=0 then
+ begin
+ ListView_SetItemState(wnd,0,LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+ SHActButtons(Dialog,SW_SHOW);
+ SendDlgItemMessage(Dialog,IDC_ACTION_TYPE,CB_SETCURSEL,0,0);
+ end;
+ ChangeActionName(Dialog,li.iItem);
+
+ CheckActListButtons(Dialog);
+ ChangeListNotify(2);
+ end;
+ IDC_ACTION_DELETE: begin
+ DontReact:=true;
+ wnd:=ActionListWindow;
+ for i:=ListView_GetItemCount(wnd)-1 downto 0 do
+ begin
+ if ListView_GetItemState(wnd,i,LVIS_SELECTED)<>0 then
+ begin
+ j:=LV_GetLParam(wnd,i);
+ if j<>0 then
+ begin
+ if (tBaseAction(j).flags and ACF_INTRODUCED)<>0 then
+ tBaseAction(j).Free
+ else
+ tBaseAction(j).flags:=tBaseAction(j).flags or ACF_REPLACED;
+ end;
+ SendMessage(wnd,LVM_DELETEITEM,i,0);
+ end;
+ end;
+ Listview_SetItemState(wnd,-1,0,LVIS_FOCUSED or LVIS_SELECTED);
+ DontReact:=false;
+ Listview_SetItemState(wnd,0,LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+ CheckActListButtons(Dialog);
+ ChangeListNotify(2);
+ end;
+
+ IDC_GROUP_UP: begin
+ MoveMacro(MacroListWindow,-1,-1);
+ CheckMacroListDirectionButtons(Dialog);
+ EventMask:=EventMask or ACTM_SORT;
+ ChangeListNotify(1);
+ end;
+ IDC_GROUP_DOWN: begin
+ MoveMacro(MacroListWindow,-1,1);
+ CheckMacroListDirectionButtons(Dialog);
+ EventMask:=EventMask or ACTM_SORT;
+ ChangeListNotify(1);
+ end;
+
+ IDC_ACTION_UP: begin
+ MoveMacro(ActionListWindow,-1,-1);
+ CheckActListDirectionButtons(Dialog);
+ ChangeListNotify(2);
+ end;
+ IDC_ACTION_DOWN: begin
+ MoveMacro(ActionListWindow,-1,1);
+ CheckActListDirectionButtons(Dialog);
+ ChangeListNotify(2);
+ end;
+
+ end;
+ end;
+ end;
+ end;
+
+ WM_HELP: begin
+ SendMessage(
+ GetLink(CB_GetData(GetDlgItem(Dialog,IDC_ACTION_TYPE)))^.DlgHandle,
+ WM_HELP,0,lParam);
+ result:=1;
+ end;
+
+ WM_NOTIFY: begin
+ case integer(PNMHdr(lParam)^.code) of
+ PSN_APPLY: begin
+ BuildActionChain(Dialog);
+
+ EventMask:=EventMask or CheckChanges();
+ SetSave(Dialog);
+ SaveMacros;
+
+ if EventMask<>0 then //??
+ begin
+ NotifyEventHooks(hHookChanged,EventMask,0);
+ EventMask:=0;
+ end;
+
+ end;
+
+ NM_DBLCLK: begin
+ if PNMListView(lParam)^.iItem>=0 then
+ PostMessageW(PNMHdr(lParam)^.hWndFrom,LVM_EDITLABELW,
+ PNMListView(lParam)^.iItem,0);
+ end;
+
+ LVN_ITEMCHANGED: begin
+ if DontReact then exit; // bug when group moved avoid
+
+ if wParam=IDC_MACRO_LIST then
+ begin
+ if PNMLISTVIEW(lParam)^.uChanged=LVIF_STATE then
+ begin
+ lvflag:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_FOCUSED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_FOCUSED);
+
+ if lvflag>0 then // old focus
+ BuildActionChain(Dialog,PNMLISTVIEW(lParam)^.iItem)
+ else if lvflag<0 then // new focus
+ begin
+ DontReact:=true;
+
+ ClearDialogData;
+ ResetDialogs;
+ FillActionList(Dialog,EditMacroList[Loword(PNMLISTVIEW(lParam)^.lParam)]);
+ CheckMacroListDirectionButtons(Dialog);
+ ChangeListNotify(2);
+
+ DontReact:=false;
+ end
+ else
+ begin
+{??
+ lvflag:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_SELECTED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_SELECTED);
+
+ if lvflag<>0 then
+ CheckMacroListDirectionButtons(Dialog);
+}
+ end;
+ end;
+ end
+
+ else if wParam=IDC_ACTION_LIST then
+ begin
+ lvflag:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_FOCUSED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_FOCUSED);
+ if lvflag>0 then // old focus
+ begin
+ SaveAction(Dialog,
+ PNMLISTVIEW(lParam)^.iItem,
+ tBaseAction(PNMLISTVIEW(lParam)^.lParam));
+ end
+ else if lvflag<0 then // new focus
+ begin
+ DontReact:=true;
+
+ ClearDialogData;
+ ResetDialogs;
+ FillAction(Dialog,tBaseAction(PNMLISTVIEW(lParam)^.lParam));
+ CheckActListDirectionButtons(Dialog);
+
+ DontReact:=false;
+ end
+ else
+ begin // checkboxes
+{??
+ lvflag:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_SELECTED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_SELECTED);
+
+ if lvflag<>0 then
+ CheckMacroListDirectionButtons(Dialog);
+}
+ if (PNMLISTVIEW(lParam)^.uOldState or PNMLISTVIEW(lParam)^.uNewState)=$3000 then
+ begin
+ SetChanged(Dialog,etACT);
+ end;
+ end;
+ end;
+ end;
+
+ LVN_ENDLABELEDITW: begin
+ if DontReact then exit;
+
+ if wParam=IDC_MACRO_LIST then
+ begin
+ with PLVDISPINFOW(lParam)^ do
+ begin
+ if item.pszText<>nil then
+ begin
+ EventMask:=EventMask or ACTM_RENAME;
+ SetChanged(Dialog,etMacro);
+ item.mask:=LVIF_TEXT;
+ if pWideChar(item.pszText)^=#0 then
+ pWideChar(item.pszText):=NoDescription;
+ SendMessageW(hdr.hWndFrom,LVM_SETITEMW,0,tlparam(@item));
+
+ with EditMacroList[loword(item.lParam)]^ do
+ begin
+ StrCopyW(descr,item.pszText,MacroNameLen-1);
+ end;
+ ChangeListNotify(1);
+
+ result:=1;
+ end;
+ end;
+ end
+ else if wParam=IDC_ACTION_LIST then
+ begin
+ with PLVDISPINFOW(lParam)^ do
+ begin
+ if item.pszText<>nil then
+ begin
+ SetChanged(Dialog,etACT);
+ ChangeActionName(Dialog,item.iItem,pWideChar(item.pszText));
+ ChangeListNotify(2);
+ result:=1;
+ end;
+ end;
+ end;
+ end;
+
+ end;
+ end;
+ else
+// {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+// {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+end;
diff --git a/plugins/Actman30/i_options.inc b/plugins/Actman30/i_options.inc
new file mode 100644
index 0000000000..3a3d8dc65a
--- /dev/null
+++ b/plugins/Actman30/i_options.inc
@@ -0,0 +1,177 @@
+{Save/load options}
+
+const
+ opt_group = 'Group';
+ opt_actions = 'Action';
+ opt_numacts = 'numactions';
+ opt_nummacro = 'numgroups';
+
+ opt_descr = 'descr';
+ opt_id = 'id';
+ opt_uid = 'uid';
+ opt_flags = 'flags';
+
+//----- Save settings -----
+
+procedure SaveActions(Macro:pMacroRecord;section:pAnsiChar);
+var
+ p,p1:PAnsiChar;
+ i:integer;
+begin
+ p:=StrEnd(section);
+ StrCopy(p,opt_numacts); DBWriteWord(0,DBBranch,section,Macro^.ActionCount);
+
+ // in: section = "Group#/"
+ p1:=StrCopyE(p,opt_actions); // "Group#/Action"
+ DBDeleteGroup(0,DBBranch,section);
+
+ for i:=0 to Macro^.ActionCount-1 do
+ begin
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p); // "Group#/Action#/"
+
+//?? StrCopy(p,opt_uid); DBWriteDWord(0,DBBranch,section,Macro^.ActionList[i].uid);
+ p^:=#0;
+ Macro^.ActionList[i].Save(section,0);
+ end;
+
+end;
+
+procedure SaveMacros;
+var
+ Macro:pMacroRecord;
+ NumMacro:integer;
+ i:integer;
+ section:array [0..127] of AnsiChar;
+ p,p1:PAnsiChar;
+begin
+// even if crap in settings, skip on read
+// DBDeleteGroup(0,DBBranch,opt_group);
+ Macro:=MacroList[0];
+ i:=MacroList.Count;
+ NumMacro:=0;
+
+ p1:=StrCopyE(section,opt_group);
+ while i>0 do
+ begin
+ with Macro^ do
+ begin
+ if (flags and (ACF_ASSIGNED or ACF_VOLATILE))=ACF_ASSIGNED then
+ begin
+ p:=StrEnd(IntToStr(p1,NumMacro));
+ p^:='/'; inc(p);
+
+ StrCopy(p,opt_id ); DBWriteDWord(0,DBBranch,section,id);
+ StrCopy(p,opt_flags); DBWriteDWord(0,DBBranch,section,flags);
+ StrCopy(p,opt_descr); DBWriteUnicode (0,DBBranch,section,descr);
+
+ p^:=#0;
+
+ SaveActions(Macro,section);
+
+ inc(NumMacro);
+ end;
+ end;
+ inc(Macro);
+ dec(i);
+ end;
+ DBWriteWord(0,DBBranch,opt_nummacro,NumMacro);
+end;
+
+//----- Load settings -----
+
+function LoadActions(Macro:pMacroRecord;section:pAnsiChar):integer;
+var
+ p,p1:PAnsiChar;
+ i,num:integer;
+ actm:pActModule;
+ action:tBaseAction;
+ uid:dword;
+ tmp:pActionList;
+begin
+ result:=0;
+ p:=StrEnd(section);
+ StrCopy(p,opt_numacts); Macro^.ActionCount:=DBReadWord(0,DBBranch,section);
+ if Macro^.ActionCount>0 then
+ begin
+ GetMem(Macro^.ActionList,SizeOf(tBaseAction)*Macro^.ActionCount);
+ p1:=StrCopyE(p,opt_actions); // "Group#/Action"
+
+ num:=0;
+ for i:=0 to Macro^.ActionCount-1 do
+ begin
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p); // "Group#/Action#/"
+
+ // get uid
+ StrCopy(p,opt_uid); uid:=DBReadDWord(0,DBBranch,section,0);
+ if uid<>0 then
+ begin
+ p^:=#0;
+ // call proper constructor
+ actm:=GetLink(uid);
+ if actm=nil then
+ continue;
+
+ action:=actm.Create;
+ // call proper loader
+ action.Load(section,0);
+
+ Macro^.ActionList^[num]:=action;
+ inc(num);
+ end;
+ end;
+ if Macro^.ActionCount<>num then
+ begin
+ GetMem(tmp,SizeOf(tBaseAction)*num);
+ move(Macro^.ActionList^,tmp^,SizeOf(tBaseAction)*num);
+ Macro^.ActionCount:=num;
+ FreeMem(Macro^.ActionList);
+ Macro^.ActionList:=tmp;
+ end;
+ end;
+end;
+
+procedure LoadMacros;
+var
+ Macro:pMacroRecord;
+ i:cardinal;
+ p,p1:PAnsiChar;
+ section:array [0..127] of AnsiChar;
+ NumMacros:cardinal;
+ tmp:pWideChar;
+begin
+ // Allocate macro list
+ NumMacros :=DBReadWord(0,DBBranch,opt_nummacro,0);
+ MacroList:=tMacroList.Create(NumMacros);
+
+ // read macro list settings
+ if NumMacros>0 then //?? really, not so necessary
+ begin
+ Macro:=MacroList[0];
+ i:=0;
+ p1:=StrCopyE(section,opt_group);
+ while i<NumMacros do
+ begin
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p);
+
+ StrCopy(p,opt_flags);
+ with Macro^ do
+ begin
+ flags:=DBReadDWord(0,DBBranch,section,0) and ACF_TOSAVE;
+ if (flags and ACF_ASSIGNED)<>0 then //?? not needed in normal cases
+ begin
+ StrCopy(p,opt_id ); id :=DBReadDWord (0,DBBranch,section);
+ StrCopy(p,opt_descr); tmp:=DBReadUnicode(0,DBBranch,section,NoDescription);
+ StrCopyW(descr,tmp,MacroNameLen-1);
+ mFreeMem(tmp);
+ p^:=#0;
+ LoadActions(Macro,section);
+ end;
+ end;
+ inc(Macro);
+ inc(i);
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/i_services.inc b/plugins/Actman30/i_services.inc
new file mode 100644
index 0000000000..2954fa4b15
--- /dev/null
+++ b/plugins/Actman30/i_services.inc
@@ -0,0 +1,317 @@
+{Basic ActMan services}
+
+function ActSelect(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+begin
+ if odd(wParam) then
+ result:=int_ptr(MacroList.GetMacro(lParam))
+ else
+ result:=int_ptr(MacroList.GetMacro(pWideChar(lParam)));
+
+ if result<>0 then
+ with pMacroRecord(result)^ do
+ begin
+ if (wParam and 4)<>0 then
+ result:=ord((flags and ACF_SELECTED)<>0)
+ else
+ begin
+ if (wParam and 2)<>0 then
+ flags:=flags and not ACF_SELECTED
+ else
+ flags:=flags or ACF_SELECTED;
+ end;
+ end;
+end;
+
+function ActFreeList(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+begin
+ result:=0;
+ mFreeMem(PAnsiChar(lParam));
+end;
+
+function ActGetList(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ pc:^tChain;
+ p:pMacroRecord;
+ i,cnt:integer;
+begin
+ p:=MacroList[0];
+ cnt:=0;
+ for i:=0 to MacroList.Count-1 do
+ begin
+ if (p^.flags and (ACF_ASSIGNED or ACF_VOLATILE))=ACF_ASSIGNED then inc(cnt);
+ inc(p);
+ end;
+ result:=cnt;
+ if lParam=0 then exit;
+ if cnt>0 then
+ begin
+ mGetMem(pc,cnt*SizeOf(tChain)+4);
+ puint_ptr(lParam)^:=uint_ptr(pc);
+ pdword(pc)^:=SizeOf(tChain);
+ inc(PByte(pc),4);
+
+ p:=MacroList[0];
+ for i:=0 to MacroList.Count-1 do
+ begin
+ if (p^.flags and (ACF_ASSIGNED or ACF_VOLATILE))=ACF_ASSIGNED then
+ begin
+ pc^.descr:=p^.descr;
+ pc^.id :=p^.id;
+ pc^.flags:=p^.flags;
+ inc(pc);
+ end;
+ inc(p);
+ end;
+ end
+ else
+ puint_ptr(lParam)^:=0;
+end;
+
+//====================== Execute code =======================
+
+{$IFDEF DEBUG}
+procedure ActmanMacroDebug(txt:pWideChar);
+begin
+ OutputDebugStringW(txt);
+end;
+{$ENDIF}
+
+procedure DoAction(Macro:pMacroRecord;var WorkData:tWorkData);
+var
+ res:LRESULT;
+ i,cnt:integer;
+{$IFDEF DEBUG}
+ buf:array [0..1023] of WideChar;
+ buf1,buf2:array [0..31] of WideChar;
+ p:pWideChar;
+{$ENDIF}
+begin
+ cnt:=Macro^.ActionCount;
+ if cnt<>0 then
+ begin
+//!! act:=CloneActions(action);
+ i:=0;
+ WorkData.ActionList :=Macro^.ActionList;
+ WorkData.ActionCount:=Macro^.ActionCount;
+ while i<cnt do
+ begin
+ if (Macro^.ActionList^[i].flags and ACF_DISABLED)=0 then
+ begin
+{$IFDEF DEBUG}
+ if WorkData.ResultType=rtWide then
+ p:=pWideChar(WorkData.LastResult)
+ else
+ p:=IntToStr(buf2,WorkData.LastResult);
+ StrCopyEW(
+ StrCopyEW(
+ StrCopyEW(
+ StrCopyEW(
+ StrCopyEW(
+ StrCopyEW(
+ StrCopyEW(
+ StrCopyEW(buf,'ActMan: Macro "'),
+ Macro^.descr
+ ),'", Action #'
+ ),IntToStr(buf1,i)
+ ),' "'
+ ),Macro^.ActionList^[i].ActionDescr
+ ),'", LR: '
+ ),p{IIF(WorkData.ResultType=rtWide,
+ pWideChar(WorkData.LastResult),
+ IntToStr(buf1,WorkData.LastResult))}
+ );
+ ActmanMacroDebug(buf);
+{$ENDIF}
+ res:=Macro^.ActionList^[i].DoAction(WorkData);
+ if res<0 then break
+ else if res>0 then // res = next action number+1
+ begin
+ i:=res-1;
+ continue;
+ end;
+ end;
+ inc(i);
+ end;
+//!! FreeActionsContinued(act_org);
+ end;
+end;
+
+type
+ pActStartData = ^tActStartData;
+ tActStartData = record
+ macro :pMacroRecord;
+ event :THANDLE;
+ WorkData:tWorkData;
+ flags :dword;
+ end;
+
+procedure ThDoAction(arg:pActStartData); cdecl;
+var
+ i:integer;
+begin
+ if (arg^.flags and ACTP_NOTIFY)<>0 then
+ begin
+ NotifyEventHooks(hevaction,arg^.macro.id,0); // started
+ arg^.macro.flags:=arg^.macro.flags or ACF_USEDNOW;
+ end;
+
+ DoAction(arg^.macro,arg^.WorkData);
+
+ if (arg^.flags and ACTP_NOTIFY)<>0 then
+ begin
+ arg^.macro.flags:=arg^.macro.flags and not ACF_USEDNOW;
+ NotifyEventHooks(hevaction,arg^.macro.id,1); // finished
+ end;
+
+ if arg^.event<>0 then // service, waiting
+ SetEvent(arg^.event)
+ else if (arg^.flags and ACTP_SAMETHREAD)=0 then // no waiting
+ begin
+ ClearResult(arg^.WorkData); // free last result memory if needs
+ // Free Storage
+ for i:=0 to 9 do
+ ClearResult(arg^.WorkData,i);
+ mFreeMem(arg); // free ActStartData (no time to free after)
+ end;
+end;
+
+function ActionStarter(macro:pMacroRecord;wd:pWorkData;flags:dword):LPARAM;
+var
+ tmp:pActStartData;
+ i:integer;
+begin
+ mGetMem (tmp ,SizeOf(tActStartData));
+ FillChar(tmp^,SizeOf(tActStartData),0);
+
+ if wd<>nil then
+ begin
+ tmp^.WorkData.ResultType:=wd^.ResultType;
+ case wd^.ResultType of
+ rtInt : tmp^.WorkData.LastResult:=wd^.LastResult;
+ rtWide: StrDupW(pWideChar(tmp^.WorkData.LastResult),pWideChar(wd^.LastResult));
+ rtAnsi: begin
+ AnsiToWide(pAnsiChar(wd^.LastResult),pWideChar(tmp^.WorkData.LastResult));
+ tmp^.WorkData.ResultType:=rtWide;
+ end;
+ rtUTF8: begin
+ UTF8ToWide(pAnsiChar(wd^.LastResult),pWideChar(tmp^.WorkData.LastResult));
+ tmp^.WorkData.ResultType:=rtWide;
+ end;
+ end;
+ tmp^.WorkData.Parameter:=wd^.Parameter;
+ end
+ else
+ tmp^.WorkData.ResultType:=rtInt;
+
+ tmp^.macro :=macro;
+ tmp^.flags :=flags;
+
+ if (flags and ACTP_SAMETHREAD)<>0 then // with waiting, macro or service
+ begin
+ tmp^.event:=0;
+ ThDoAction(tmp);
+ // keep text result (for macro from macro)
+ if (flags and ACTP_KEEPRESULT)<>0 then
+ begin
+ wd^.ResultType:=tmp^.WorkData.ResultType;
+ if wd^.ResultType=rtInt then
+ wd^.LastResult:=tmp^.WorkData.LastResult
+ else
+ StrDupW(pWideChar(wd^.LastResult),pWideChar(tmp^.WorkData.LastResult));
+ result:=0;
+ end
+ else if tmp^.WorkData.ResultType=rtInt then
+ result:=tmp^.WorkData.LastResult
+ // result no needs or macro from service
+ else
+ result:=StrToInt(pWideChar(tmp^.WorkData.LastResult));
+ end
+
+ else if (flags and ACTP_WAIT)<>0 then // with waiting, service
+ begin
+ tmp^.event:=CreateEvent(nil,FALSE,FALSE,nil);
+ {CloseHandle}(mir_forkthread(@ThDoAction,tmp));
+ //!!!!!!!!! movetmp structure (event handle) to array, not stack?
+ WaitForSingleObjectEx(tmp^.event,INFINITE,true);
+ CloseHandle(tmp^.event);
+ if tmp^.WorkData.ResultType=rtWide then
+ result:=StrToInt(pWideChar(tmp^.WorkData.LastResult))
+ else
+ result:=tmp^.WorkData.LastResult;
+ end
+
+ else // no waiting, service or macro
+ begin
+ tmp^.event:=0;
+ {CloseHandle}(mir_forkthread(@ThDoAction,tmp));
+ result:=0;
+ exit;
+ end;
+
+ ClearResult(tmp^.WorkData); // free last result memory if needs
+ // Free Storage
+ for i:=0 to 9 do
+ ClearResult(tmp^.WorkData,i);
+ mFreeMem(tmp); // free ActStartData (no time to free after)
+end;
+
+//----- execute services -----
+
+function ActRun(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ p:pMacroRecord;
+ w:tWorkData;
+begin
+ result:=-1;
+ p:=MacroList.GetMacro(wParam);
+ if p<>nil then
+ begin
+ FillChar(w,SizeOf(w),0);
+ w.ResultType:=rtInt;
+ w.Parameter:=lParam;
+ result:=ActionStarter(p,@w,ACTP_SAMETHREAD);
+ end;
+end;
+
+function ActRunGroup(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ p:pMacroRecord;
+ w:tWorkData;
+begin
+ result:=-1;
+ p:=MacroList.GetMacro(pWideChar(wParam));
+ if p<>nil then
+ begin
+ FillChar(w,SizeOf(w),0);
+ w.ResultType:=rtInt;
+ w.Parameter:=lParam;
+ result:=ActionStarter(p,@w,ACTP_SAMETHREAD);
+ end;
+end;
+
+function ActRunParam(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ p:pMacroRecord;
+ w:tWorkData;
+begin
+ result:=-1;
+ if (pAct_Param(lParam)^.flags and ACTP_BYNAME)=0 then
+ p:=MacroList.GetMacro(pAct_Param(lParam)^.Id)
+ else
+ p:=MacroList.GetMacro(pWideChar(pAct_Param(lParam)^.Id));
+
+ if p<>nil then
+ begin
+ FillChar(w,SizeOf(w),0);
+ w.Parameter :=pAct_Param(lParam)^.wParam;
+ w.LastResult:=pAct_Param(lParam)^.lParam;
+ w.ResultType:=pAct_Param(lParam)^.lPType;
+ result:=ActionStarter(p,@w,pAct_Param(lParam)^.flags);
+ if (pAct_Param(lParam)^.flags and (ACTP_KEEPRESULT or ACTP_SAMETHREAD))=
+ (ACTP_KEEPRESULT or ACTP_SAMETHREAD) then
+ begin
+ pAct_Param(lParam)^.lParam:=w.LastResult;
+ pAct_Param(lParam)^.lPType:=w.ResultType;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/iac_.pas b/plugins/Actman30/iac_.pas
new file mode 100644
index 0000000000..f99e4f7366
--- /dev/null
+++ b/plugins/Actman30/iac_.pas
@@ -0,0 +1,155 @@
+unit iac_;
+
+interface
+
+implementation
+
+uses windows, iac_global, mirutils;
+
+
+type
+ = class(tBaseAction)
+
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+ function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor .Create(uid:dword);
+begin
+ inherited Create(uid);
+end;
+
+destructor .Destroy;
+begin
+
+ inherited Destroy;
+end;
+
+function .Clone:tBaseAction;
+begin
+ result:=.Create(0);
+ Duplicate(result);
+
+end;
+
+function .DoAction(var WorkData:tWorkData):LRESULT;
+begin
+ result:=0;
+end;
+
+procedure .Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+procedure .Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure ClearFields(Dialog:HWND);
+begin
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ ClearFields(Dialog);
+ with (lParam) do
+ begin
+ end;
+ end;
+
+ WM_ACT_RESET: begin
+ ClearFields(Dialog);
+ end;
+
+ WM_ACT_SAVE: begin
+ with (lParam) do
+ begin
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,,parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :=;
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :=;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_chain.pas b/plugins/Actman30/iac_chain.pas
new file mode 100644
index 0000000000..a4736ab1ca
--- /dev/null
+++ b/plugins/Actman30/iac_chain.pas
@@ -0,0 +1,372 @@
+unit iac_chain;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ global, iac_global, mirutils, m_api,
+ dlgshare,lowlevelc,common,dbsettings, wrapper;
+
+{$include m_actman.inc}
+{$include i_cnst_chain.inc}
+{$resource iac_chain.res}
+
+const
+ ACF_BYNAME = $00000001; // Address action link by name, not Id
+ ACF_NOWAIT = $00000002; // Don't wait execution result, continue
+ ACF_KEEPOLD = $00000004; // Don't change LastResult value
+ ACF_SAMETHREAD = $00000008; // Execute in same thread with waiting
+const
+ ioNoWait = 'nowait';
+ ioKeepOld = 'keepold';
+ ioSameThread = 'samethread';
+const
+ opt_chain = 'chain';
+ opt_actname = 'actname';
+const
+ NoChainText:PWideChar = 'not defined';
+
+type
+ tChainAction = class(tBaseAction)
+ private
+ id :dword;
+ actname:pWideChar;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tChainAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ id :=0;
+ actname:=nil;
+end;
+
+destructor tChainAction.Destroy;
+begin
+ if (flags and ACF_BYNAME)<>0 then
+ mFreeMem(actname);
+
+ inherited Destroy;
+end;
+{
+function tChainAction.Clone:tBaseAction;
+begin
+ result:=tChainAction.Create(0);
+ Duplicate(result);
+
+ tChainAction(result).id:=id;
+ StrDupW(tChainAction(result).actname,actname);
+end;
+}
+function tChainAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ params:tAct_Param;
+ res:int_ptr;
+begin
+ result:=0;
+
+ if (flags and ACF_BYNAME)<>0 then
+ begin
+ params.flags:=ACTP_BYNAME;
+ params.Id :=uint_ptr(actname);
+ end
+ else
+ begin
+ params.flags:=0;
+ params.Id :=id;
+ end;
+ if (flags and ACF_SAMETHREAD)<>0 then
+ params.flags:=params.flags or ACTP_SAMETHREAD
+ else if (flags and ACF_NOWAIT)=0 then
+ params.flags:=params.flags or ACTP_WAIT;
+
+ if (flags and ACF_KEEPOLD)=0 then
+ params.flags:=params.flags or ACTP_KEEPRESULT;
+
+ params.wParam:=WorkData.Parameter;
+ params.lParam:=WorkData.LastResult;
+ res:=CallService(MS_ACT_RUNPARAMS,0,tlparam(@params));
+
+ if (flags and ACF_KEEPOLD)=0 then
+ begin
+ ClearResult(WorkData);
+ if (flags and ACF_SAMETHREAD)=0 then
+ begin
+ WorkData.LastResult:=res;
+ WorkData.ResultType:=rtInt;
+ end
+ else
+ begin
+ WorkData.LastResult:=params.lParam;
+ WorkData.ResultType:=params.lPType;
+ end;
+ end;
+end;
+
+procedure tChainAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ if (flags and ACF_BYNAME)=0 then
+ begin
+ StrCopy(pc,opt_chain); id:=DBReadDWord(0,DBBranch,section);
+ end
+ else
+ begin
+ StrCopy(pc,opt_actname); actname:=DBReadUnicode(0,DBBranch,section);
+ end;
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ StrDupW(actname,getText(HXML(node)));
+ flags:=flags or ACF_BYNAME;
+
+ if StrToInt(getAttrValue(HXML(node),ioNoWait))=1 then
+ flags:=flags or ACF_NOWAIT;
+
+ if StrToInt(getAttrValue(HXML(node),ioKeepOld))=1 then
+ flags:=flags or ACF_KEEPOLD;
+
+ if StrToInt(getAttrValue(HXML(node),ioSameThread))=1 then
+ flags:=flags or ACF_SAMETHREAD;
+ end;
+ end;
+{
+ 2: begin
+
+ UF8ToWide(GetParamSectionStr(node,'name',nil),actname);
+ flags:=flags or ACF_BYNAME;
+
+ if GetParamSectionInt(node,ioNoWait)=1 then
+ flags:=flags or ACF_NOWAIT;
+
+ if GetParamSectionInt(node,ioKeepOld)=1 then
+ flags:=flags or ACF_KEEPOLD;
+
+ if GetParamSectionInt(node,ioSameThread)=1 then
+ flags:=flags or ACF_SAMETHREAD;
+ end;
+}
+ end;
+end;
+
+procedure tChainAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ if (flags and ACF_BYNAME)=0 then
+ begin
+ StrCopy(pc,opt_chain); DBWriteDWord(0,DBBranch,section,id);
+ end
+ else
+ begin
+ StrCopy(pc,opt_actname); DBWriteUnicode(0,DBBranch,section,actname);
+ end;
+ end;
+{
+ 1: begin
+ end;
+}
+{
+ 2: begin
+ end;
+}
+{
+ 3: begin
+ Out(node,['CallAction',actname,
+ IFF(flags or ACF_SAMETHREAD,'samethread',''),
+ IFF(flags or ACF_NOWAIT ,'nowait',''),
+ IFF(flags or ACF_KEEPOLD ,'keepold','')
+ ]);
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure FillChainList(Dialog:hwnd);
+var
+ wnd,list:HWND;
+ i:integer;
+
+ li:LV_ITEMW;
+ Macro:pMacroRecord;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_MACRO_LIST);
+
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ SendMessage(wnd,CB_SETITEMDATA,
+ SendMessageW(wnd,CB_ADDSTRING,0,lparam(TranslateW(NoChainText))),0);
+
+ list:=MacroListWindow;
+ li.mask :=LVIF_PARAM;
+ li.iSubItem :=0;
+ for i:=0 to SendMessage(list,LVM_GETITEMCOUNT,0,0)-1 do
+ begin
+ li.iItem:=i;
+ SendMessageW(list,LVM_GETITEMW,0,tlparam(@li));
+ Macro:=EditMacroList[loword(li.lParam)];
+ SendMessage(wnd,CB_SETITEMDATA,
+ SendMessageW(wnd,CB_ADDSTRING,0,lparam(@(Macro.descr))),Macro.id);
+ end;
+
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_MACRO_NOWAIT ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MACRO_SAMETHREAD,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MACRO_KEEPOLD ,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ tmp:dword;
+ wnd:HWND;
+ bb:boolean;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ FillChainList(Dialog);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ ClearFields(Dialog);
+ with tChainAction(lParam) do
+ begin
+ if (flags and ACF_BYNAME)<>0 then
+ SendDlgItemMessageW(Dialog,IDC_MACRO_LIST,CB_SELECTSTRING,twparam(-1),tlparam(actname))
+ else
+ CB_SelectData(Dialog,IDC_MACRO_LIST,id);
+ if (flags and ACF_KEEPOLD)<>0 then
+ CheckDlgButton(Dialog,IDC_MACRO_KEEPOLD,BST_CHECKED);
+
+ if (flags and ACF_SAMETHREAD)<>0 then
+ begin
+ bb:=false;
+ CheckDlgButton(Dialog,IDC_MACRO_SAMETHREAD,BST_CHECKED);
+ end
+ else
+ begin
+ bb:=true;
+ if (flags and ACF_NOWAIT)<>0 then
+ CheckDlgButton(Dialog,IDC_MACRO_NOWAIT,BST_CHECKED);
+ end;
+ EnableWindow(GetDlgItem(Dialog,IDC_MACRO_NOWAIT),bb);
+ end;
+ end;
+
+ WM_ACT_RESET: begin
+ ClearFields(Dialog);
+ CheckDlgButton(Dialog,IDC_MACRO_SAMETHREAD,BST_CHECKED);
+ SendDlgItemMessage(Dialog,IDC_MACRO_LIST,CB_SETCURSEL,0,0);
+ end;
+
+ WM_ACT_SAVE: begin
+ with tChainAction(lParam) do
+ begin
+ id:=CB_GetData(GetDlgItem(Dialog,IDC_MACRO_LIST));
+
+ if IsDlgButtonChecked(Dialog,IDC_MACRO_SAMETHREAD)<>BST_UNCHECKED then
+ flags:=flags or ACF_SAMETHREAD
+ else if IsDlgButtonChecked(Dialog,IDC_MACRO_NOWAIT)<>BST_UNCHECKED then
+ flags:=flags or ACF_NOWAIT;
+
+ if IsDlgButtonChecked(Dialog,IDC_MACRO_KEEPOLD)<>BST_UNCHECKED then
+ flags:=flags or ACF_KEEPOLD;
+ end;
+ end;
+
+ WM_ACT_LISTCHANGE: begin
+ if wParam=1 then
+ begin
+ wnd:=GetDlgItem(Dialog,IDC_MACRO_LIST);
+ tmp:=CB_GetData(wnd);
+ FillChainList(Dialog);
+ CB_SelectData(wnd,tmp);
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ CBN_SELCHANGE: SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ BN_CLICKED: begin
+ if loword(wParam)=IDC_MACRO_SAMETHREAD then
+ begin
+ EnableWindow(GetDlgItem(Dialog,IDC_MACRO_NOWAIT),
+ IsDlgButtonChecked(Dialog,IDC_MACRO_SAMETHREAD)=BST_UNCHECKED);
+ end;
+
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+ end;
+// result:=DefWindowProc(Dialog,hMessage,wParam,lParam);
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tChainAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTCHAIN',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Chain';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_CHAIN';
+ vc.Hash :=0;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_chain.rc b/plugins/Actman30/iac_chain.rc
new file mode 100644
index 0000000000..35cc17f53f
--- /dev/null
+++ b/plugins/Actman30/iac_chain.rc
@@ -0,0 +1,18 @@
+#include "i_cnst_chain.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTCHAIN DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ RTEXT "Other Action groups",-1, 0, 2, 160, 10
+ COMBOBOX IDC_MACRO_LIST, 1, 13, 166, 128,
+ CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL
+ AUTOCHECKBOX "Keep old result" , IDC_MACRO_KEEPOLD , 1, 31, 166, 11
+ AUTOCHECKBOX "Same thread" , IDC_MACRO_SAMETHREAD, 1, 44, 166, 11
+ AUTOCHECKBOX "Don't wait end of execution", IDC_MACRO_NOWAIT , 1, 57, 166, 11
+}
+
+IDI_CHAIN ICON "ico\chain.ico"
diff --git a/plugins/Actman30/iac_contact.pas b/plugins/Actman30/iac_contact.pas
new file mode 100644
index 0000000000..eb9a5790cd
--- /dev/null
+++ b/plugins/Actman30/iac_contact.pas
@@ -0,0 +1,252 @@
+unit iac_contact;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ m_api, global, iac_global, common,
+ contact, dlgshare, syswin,
+ wrapper, mirutils, dbsettings;
+
+{$include i_cnst_contact.inc}
+{$resource iac_contact.res}
+
+const
+ ACF_KEEPONLY = $00000001; // keep contact handle in Last, don't show window
+ ACF_GETACTIVE = $00000002; // try to get contact from active window
+
+const
+ ioKeepOnly = 'keeponly';
+ ioWindow = 'window';
+
+type
+ tContactAction = class(tBaseAction)
+ private
+ contact:THANDLE;
+ public
+ constructor Create(uid:dword);
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+constructor tContactAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ contact:=0;
+end;
+{
+function tContactAction.Clone:tBaseAction;
+begin
+ result:=tContactAction.Create(0);
+ Duplicate(result);
+
+ tContactAction(result).contact:=contact;
+end;
+}
+
+//----- Object realization -----
+
+function tContactAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ wnd:HWND;
+begin
+ ClearResult(WorkData);
+
+ if (flags and ACF_GETACTIVE)<>0 then
+ begin
+ wnd:=WaitFocusedWndChild(GetForegroundWindow){GetFocus};
+ if wnd<>0 then
+ contact:=WndToContact(wnd)
+ else
+ contact:=0;
+ end
+ else if (flags and ACF_KEEPONLY)=0 then
+ ShowContactDialog(contact);
+
+ WorkData.LastResult:=contact;
+ WorkData.ResultType:=rtInt;
+
+ result:=0;
+end;
+
+procedure tContactAction.Load(node:pointer;fmt:integer);
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: if (flags and ACF_GETACTIVE)=0 then
+ contact:=LoadContact(DBBranch,node);
+
+ 1: begin
+ with xmlparser do
+ begin
+ contact:=ImportContact(HXML(node));
+ if StrToInt(getAttrValue(HXML(node),ioKeepOnly))=1 then
+ flags:=flags or ACF_KEEPONLY;
+ if StrToInt(getAttrValue(HXML(node),ioWindow))=1 then
+ flags:=flags or ACF_GETACTIVE;
+ end;
+ end;
+{
+ 2: begin
+ contact:=ImportContactINI(node);
+
+ if GetParamSectionInt(node,ioKeepOnly)=1 then
+ flags:=flags or ACF_KEEPONLY;
+ if GetParamSectionInt(node,ioWindow)=1 then
+ flags:=flags or ACF_GETACTIVE;
+ end;
+}
+ end;
+end;
+
+procedure tContactAction.Save(node:pointer;fmt:integer);
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: if (flags and ACF_GETACTIVE)=0 then
+ SaveContact(contact,DBBranch,node);
+{
+ 1: begin
+ sub:=AddChild(actnode,ioContactWindow,nil);
+ ExportContact(sub,contact);
+// AddAttrInt(sub,ioNumber,0); // contact
+ if (flags and ACF_KEEPONLY)<>0 then AddAttrInt(sub,ioKeepOnly,1);
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_CNT_KEEP,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_CNT_GET ,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ wnd:HWND;
+ bb:boolean;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ wnd:=GetDlgItem(Dialog,IDC_CNT_REFRESH);
+ OptSetButtonIcon(wnd,ACI_REFRESH);
+ SendMessage(wnd,BUTTONADDTOOLTIP,TWPARAM(TranslateW('Refresh')),BATF_UNICODE);
+ OptFillContactList(GetDlgItem(Dialog,IDC_CONTACTLIST));
+ end;
+
+ WM_ACT_SETVALUE: begin
+ ClearFields(Dialog);
+
+ with tContactAction(lParam) do
+ begin
+ if (flags and ACF_GETACTIVE)<>0 then
+ begin
+ bb:=false;
+ CheckDlgButton(Dialog,IDC_CNT_GET,BST_CHECKED);
+ end
+ else
+ begin
+ bb:=true;
+ if (flags and ACF_KEEPONLY)<>0 then
+ CheckDlgButton(Dialog,IDC_CNT_KEEP,BST_CHECKED);
+
+ SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_SETCURSEL,
+ FindContact(GetDlgItem(Dialog,IDC_CONTACTLIST),contact),0);
+ end;
+ EnableWindow(GetDlgItem(Dialog,IDC_CNT_REFRESH),bb);
+ EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),bb);
+ EnableWindow(GetDlgItem(Dialog,IDC_CNT_KEEP ),bb);
+ end;
+ end;
+
+ WM_ACT_RESET: begin
+ ClearFields(Dialog);
+ EnableWindow(GetDlgItem(Dialog,IDC_CNT_REFRESH),true);
+ EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),true);
+ EnableWindow(GetDlgItem(Dialog,IDC_CNT_KEEP ),true);
+ end;
+
+ WM_ACT_SAVE: begin
+ with tContactAction(lParam) do
+ begin
+ contact:=SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_GETITEMDATA,
+ SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_GETCURSEL,0,0),0);
+ if IsDlgButtonChecked(Dialog,IDC_CNT_KEEP)=BST_CHECKED then
+ flags:=flags or ACF_KEEPONLY;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ CBN_SELCHANGE: SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_CNT_GET: begin
+ bb:=IsDlgButtonChecked(Dialog,IDC_CNT_GET)=BST_UNCHECKED;
+ EnableWindow(GetDlgItem(Dialog,IDC_CNT_REFRESH),bb);
+ EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),bb);
+ EnableWindow(GetDlgItem(Dialog,IDC_CNT_KEEP ),bb);
+ end;
+
+ IDC_CNT_REFRESH: begin
+ OptFillContactList(GetDlgItem(Dialog,IDC_CONTACTLIST));
+ exit;
+ end;
+ end;
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tContactAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTCONTACT',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Contact';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_CONTACT';
+ vc.Hash :=0;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_contact.rc b/plugins/Actman30/iac_contact.rc
new file mode 100644
index 0000000000..b3923502b3
--- /dev/null
+++ b/plugins/Actman30/iac_contact.rc
@@ -0,0 +1,18 @@
+#include "i_cnst_contact.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTCONTACT DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ RTEXT "Choose Contact", -1 , 0, 2, 160, 10
+ CONTROL "Refresh",IDC_CNT_REFRESH,"MButtonClass",WS_TABSTOP,1,12,16,16,$18000000
+ COMBOBOX IDC_CONTACTLIST, 19, 14, 148, 128, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL
+ AUTOCHECKBOX "Keep handle only", IDC_CNT_KEEP , 1, 31, 160, 11
+
+ AUTOCHECKBOX "Get from active window", IDC_CNT_GET, 1, 45, 160, 11
+}
+
+IDI_CONTACT ICON "ico\contact.ico"
diff --git a/plugins/Actman30/iac_database.rc b/plugins/Actman30/iac_database.rc
new file mode 100644
index 0000000000..5c5fe1f791
--- /dev/null
+++ b/plugins/Actman30/iac_database.rc
@@ -0,0 +1,37 @@
+#include "i_cnst_database.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTDATABASE DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ AUTORADIOBUTTON "Own settings", IDC_RW_CURRENT, 1, 0, 81, 11, BS_RIGHT | BS_LEFTTEXT | WS_GROUP
+ AUTORADIOBUTTON "Manual" , IDC_RW_MANUAL , 1, 12, 81, 11, BS_RIGHT | BS_LEFTTEXT
+ AUTORADIOBUTTON "Parameter" , IDC_RW_PARAM , 86, 0, 81, 11
+ AUTORADIOBUTTON "Last result" , IDC_RW_RESULT , 86, 12, 81, 11
+
+ CONTROL "Refresh",IDC_CNT_REFRESH,"MButtonClass",WS_TABSTOP,1,23,16,16,$18000000
+ COMBOBOX IDC_CONTACTLIST, 18, 25, 148, 128, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL
+
+ RTEXT "Module" , -1, 1, 43, 160, 8, SS_CENTERIMAGE
+ EDITTEXT IDC_RW_MODULE , 1, 52, 166, 12, ES_AUTOHSCROLL
+ RTEXT "Setting" , -1, 1, 67, 160, 8, SS_CENTERIMAGE
+ EDITTEXT IDC_RW_SETTING, 1, 76, 166, 12, ES_AUTOHSCROLL
+
+ GROUPBOX "Operation" , -1, 1, 92, 166, 23, WS_GROUP
+ AUTORADIOBUTTON "Read" , IDC_RW_READ , 4, 101, 52, 11
+ AUTORADIOBUTTON "Write" , IDC_RW_WRITE , 57, 101, 52, 11
+ AUTORADIOBUTTON "Delete" , IDC_RW_DELETE , 110, 101, 52, 11
+
+ GROUPBOX "Value" , -1, 1, 116, 166, 64, WS_GROUP
+
+ COMBOBOX IDC_RW_DATATYPE, 86, 125, 79, 96, CBS_DROPDOWNLIST | WS_VSCROLL
+
+ AUTOCHECKBOX "Last result" , IDC_RW_LAST , 6, 142, 156, 11, BS_RIGHT | BS_LEFTTEXT
+ EDITTEXT IDC_RW_VALUE, 4, 154, 160, 11, ES_AUTOHSCROLL
+ AUTOCHECKBOX "Save value" , IDC_RW_SAVE , 6, 166, 156, 11, BS_RIGHT | BS_LEFTTEXT
+}
+
+IDI_DATABASE ICON "ico\rw.ico"
diff --git a/plugins/Actman30/iac_dbrw.pas b/plugins/Actman30/iac_dbrw.pas
new file mode 100644
index 0000000000..0c9e0ad502
--- /dev/null
+++ b/plugins/Actman30/iac_dbrw.pas
@@ -0,0 +1,686 @@
+unit iac_dbrw;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ global, iac_global,
+ m_api,dbsettings,
+ common,mirutils,wrapper,
+ editwrapper,contact,dlgshare;
+
+{$include i_cnst_database.inc}
+{$resource iac_database.res}
+
+const
+ opt_module = 'module';
+ opt_setting = 'setting';
+ opt_value = 'value';
+const
+ ioOper = 'oper';
+ ioDelete = 'delete';
+ ioWrite = 'write';
+ ioCurrent = 'current';
+ ioParam = 'param';
+ ioResult = 'result';
+ ioModule = 'module';
+ ioSetting = 'setting';
+ ioContact = 'contact';
+ ioFileVariable = 'modvariables';
+ ioArgVariable = 'argvariables';
+ ioVariables = 'variables';
+ ioType = 'type';
+ ioByte = 'byte';
+ ioWord = 'word';
+ ioDword = 'dword';
+ ioAnsi = 'ansi';
+ ioLast = 'last';
+ ioSaveValue = 'savevalue';
+
+const
+ ACF_DBWRITE = $00000001; // write to (not read from) DB
+ ACF_DBDELETE = $00000002; // delete setting
+ ACF_DBBYTE = $00000004; // read/write byte (def. dword)
+ ACF_DBWORD = $00000008; // read/write word (def. dword)
+ ACF_DBUTEXT = $00000010; // read/write Unicode string
+ ACF_DBANSI = $00000020; // read/write ANSI string
+ ACF_PARAM = $00000040; // hContact from parameter
+ ACF_CURRENT = $00000080; // hContact is 0 (user settings)
+ ACF_RESULT = $00000100; // hContact is last result value
+ ACF_LAST = $00000200; // use last result for DB writing
+ ACF_SAVE = $00000400; // save writing value to Last Result
+ // dummy
+ ACF_DBDWORD = 0;
+ ACF_DBREAD = 0;
+ ACF_MANUAL = 0;
+
+ ACF_NOCONTACT = ACF_PARAM or ACF_CURRENT or ACF_RESULT;
+ ACF_VALUETYPE = ACF_DBBYTE or ACF_DBWORD or ACF_DBUTEXT or ACF_DBANSI;
+ ACF_TEXT = ACF_DBUTEXT or ACF_DBANSI;
+ ACF_OPERATION = ACF_DBWRITE or ACF_DBDELETE;
+
+ ACF_RW_MODULE = $00001000; // script for module name
+ ACF_RW_SETTING = $00002000; // script for setting name
+ ACF_RW_VALUE = $00004000; // script for data value
+
+type
+ tDataBaseAction = class(tBaseAction)
+ private
+ dbcontact:THANDLE;
+ dbmodule :PWideChar;
+ dbsetting:PWideChar;
+ dbvalue :PWideChar; // keep all in unicode (str to int translation fast)
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tDataBaseACtion.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ dbcontact:=0;
+ dbmodule :=nil;
+ dbsetting:=nil;
+ dbvalue :=nil;
+end;
+
+destructor tDataBaseAction.Destroy;
+begin
+ mFreeMem(dbmodule);
+ mFreeMem(dbsetting);
+ mFreeMem(dbvalue);
+
+ inherited Destroy;
+end;
+{
+function tDataBaseAction.Clone:tBaseAction;
+var
+ tmp:tDataBaseAction;
+begin
+ result:=tDataBaseAction.Create(0);
+ Duplicate(result);
+
+ tmp.dbcontact:=dbcontact;
+ StrDupW(tmp.dbmodule ,dbmodule);
+ StrDupW(tmp.dbsetting,dbsetting);
+
+ if ((flags and ACF_DBDELETE)=0) and
+ ((flags and ACF_LAST)=0) then
+ StrDupW(tmp.dbvalue,dbvalue);
+
+ result:=tmp;
+end;
+}
+function tDataBaseAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ sbuf:array [0..31] of WideChar;
+ bufw:array [0..255] of WideChar;
+ ambuf,asbuf:array [0..127] of AnsiChar;
+ ls,tmp:pWideChar;
+ tmpa,tmpa1:pAnsiChar;
+ hContact:THANDLE;
+ proto:pAnsiChar;
+ avalue:uint_ptr;
+begin
+ result:=0;
+ // contact
+ case (flags and ACF_NOCONTACT) of
+ ACF_CURRENT: hContact:=0;
+ ACF_PARAM : hContact:=WorkData.Parameter;
+ ACF_RESULT : hContact:=WorkData.LastResult;
+ else
+ hContact:=dbcontact;
+ end;
+
+ //---
+ // last result for scripts
+ if WorkData.ResultType=rtWide then
+ ls:=pWideChar(WorkData.LastResult)
+ else
+ begin
+ ls:=@sbuf;
+ IntToStr(sbuf,WorkData.LastResult);
+ end;
+
+ proto:=GetContactProtoAcc(hContact);
+ // now need to process module
+ if (flags and ACF_RW_MODULE)<>0 then
+ begin
+ tmp:=ParseVarString(dbmodule,hContact,ls);
+ StrCopyW(bufw,tmp);
+ mFreeMem(tmp);
+ end
+ else
+ StrCopyW(bufw,dbmodule);
+ StrReplaceW(@bufw,'<last>',ls);
+ FastWideToAnsiBuf(bufw,ambuf,SizeOf(ambuf)-1);
+ StrReplace(ambuf,protostr,proto);
+
+ // now process settings
+ if (flags and ACF_RW_SETTING)<>0 then
+ begin
+ tmp:=ParseVarString(dbsetting,hContact,ls);
+ StrCopyW(bufw,tmp);
+ mFreeMem(tmp);
+ end
+ else
+ StrCopyW(bufw,dbsetting);
+ StrReplaceW(@bufw,'<last>',ls);
+ FastWideToAnsiBuf(bufw,asbuf,SizeOf(asbuf)-1);
+ StrReplace(asbuf,protostr,proto);
+
+ // Delete data
+ if (flags and ACF_DBDELETE)<>0 then
+ begin
+ if (asbuf[0]='*') or (asbuf[StrLen(asbuf)-1]='*') then
+ DBDeleteGroup(hContact,ambuf,asbuf)
+ else
+ DBDeleteSetting(hContact,ambuf,asbuf);
+ end
+ else
+ begin
+ if (flags and ACF_LAST)<>0 then
+ begin
+ avalue:=WorkData.LastResult;
+ if WorkData.ResultType=rtInt then // have number
+ begin
+ if (flags and ACF_DBUTEXT)=ACF_DBUTEXT then // need wide text
+ avalue:=uint_ptr(IntToStr(sbuf,avalue))
+ else if (flags and ACF_DBANSI)=ACF_DBANSI then // need ansi text
+ avalue:=uint_ptr(IntToStr(pAnsiChar(@sbuf),avalue));
+ end
+ // got wide text
+ else if (flags and ACF_TEXT)=0 then // need number
+ avalue:=NumToInt(pWideChar(avalue));
+{
+ val=LR(wide) (wide,ansi)
+ val=pointer to static buffer (wide, ansi)
+ val=number(number)
+}
+ end
+ else
+ begin
+ if (flags and ACF_RW_VALUE)<>0 then
+ begin
+ avalue:=uint_ptr(ParseVarString(dbvalue,hContact,ls));
+ end
+ else
+ avalue:=uint_ptr(dbvalue);
+
+ if (flags and ACF_TEXT)=0 then // need a number
+ begin
+ tmp:=pWideChar(avalue);
+ avalue:=NumToInt(pWideChar(avalue));
+ if (flags and ACF_RW_VALUE)<>0 then
+ mFreeMem(tmp);
+ end;
+{
+ val=uint_ptr if need number(number)
+ val=script result wide(need to free) (wide,ansi)
+ val=original dbvalue wide (wide,ansi)
+}
+ end;
+ // Write value
+ if (flags and ACF_DBWRITE)<>0 then
+ begin
+ case (flags and ACF_VALUETYPE) of
+ ACF_DBBYTE: DBWriteByte(hContact,ambuf,asbuf,avalue);
+ ACF_DBWORD: DBWriteWord(hContact,ambuf,asbuf,avalue);
+ ACF_DBANSI: begin
+ WideToAnsi(pWideChar(avalue),tmpa,MirandaCP);
+ DBWriteString(hContact,ambuf,asbuf,tmpa);
+ mFreeMem(tmpa);
+ end;
+ ACF_DBUTEXT: begin
+ DBWriteUnicode(hContact,ambuf,asbuf,pWideChar(avalue));
+ end;
+ else
+ DBWriteDWord(hContact,ambuf,asbuf,avalue);
+ end;
+
+ if (flags and ACF_SAVE)<>0 then
+ begin
+ ClearResult(WorkData);
+ case (flags and ACF_VALUETYPE) of
+ ACF_DBANSI,
+ ACF_DBUTEXT: begin
+ StrDupW(pWideChar(WorkData.LastResult),pWideChar(avalue));
+ WorkData.ResultType:=rtWide;
+ end;
+ else
+ WorkData.LastResult:=avalue;
+ WorkData.ResultType:=rtInt;
+ end;
+ end;
+ end
+ // Read value
+ else
+ begin
+ ClearResult(WorkData);
+ WorkData.ResultType:=rtInt;
+ case (flags and ACF_VALUETYPE) of
+ ACF_DBBYTE: WorkData.LastResult:=DBReadByte(hContact,ambuf,asbuf,avalue);
+ ACF_DBWORD: WorkData.LastResult:=DBReadWord(hContact,ambuf,asbuf,avalue);
+ ACF_DBANSI: begin
+ WideToAnsi(pWideChar(avalue),tmpa1,MirandaCP);
+ tmpa:=DBReadString(hContact,ambuf,asbuf,tmpa1);
+ AnsiToWide(tmpa,PWideChar(WorkData.LastResult),MirandaCP);
+ WorkData.ResultType:=rtWide;
+ mFreeMem(tmpa1);
+ mFreeMem(tmpa);
+ end;
+ ACF_DBUTEXT: begin
+ WorkData.LastResult:=uint_ptr(DBReadUnicode(hContact,ambuf,asbuf,pWideChar(avalue)));
+ WorkData.ResultType:=rtWide;
+ end
+ else
+ WorkData.LastResult:=DBReadDWord(hContact,ambuf,asbuf,avalue);
+ end;
+ end;
+
+ if (flags and ACF_RW_VALUE)<>0 then
+ begin
+ if (flags and ACF_TEXT)<>0 then
+ begin
+ mFreeMem(avalue);
+ end;
+ end;
+ end;
+end;
+
+procedure tDataBaseAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+ tmp:pWideChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ if (flags and ACF_NOCONTACT)=0 then
+ dbcontact:=LoadContact(DBBranch,node);
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_module ); dbmodule :=DBReadUnicode(0,DBBranch,section);
+ StrCopy(pc,opt_setting); dbsetting:=DBReadUnicode(0,DBBranch,section);
+ if ((flags and ACF_DBDELETE)=0) and
+ ((flags and ACF_LAST)=0) then
+ begin
+ StrCopy(pc,opt_value); dbvalue:=DBReadUnicode(0,DBBranch,section);
+ end;
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ tmp:=getAttrValue(HXML(node),ioOper);
+ if lstrcmpiw(tmp,ioDelete)=0 then flags:=flags or ACF_DBDELETE
+ else if lstrcmpiw(tmp,ioWrite )=0 then flags:=flags or ACF_DBWRITE;
+ // else if lstrcmpiw(tmp,ioRead)=0 then ;
+ tmp:=getAttrValue(HXML(node),ioContact);
+ if lstrcmpiw(tmp,ioCurrent)=0 then flags:=flags or ACF_CURRENT
+ else if lstrcmpiw(tmp,ioResult )=0 then flags:=flags or ACF_RESULT
+ else if lstrcmpiw(tmp,ioParam )=0 then flags:=flags or ACF_PARAM
+ else if lstrcmpiw(tmp,ioContact)=0 then
+ begin
+ dbcontact:=ImportContact(HXML(node));
+ end;
+
+ StrDupW(dbmodule ,getAttrValue(HXML(node),ioModule));
+ StrDupW(dbsetting,getAttrValue(HXML(node),ioSetting));
+
+ if StrToInt(getAttrValue(HXML(node),ioFileVariable))=1 then flags:=flags or ACF_RW_MODULE;
+ if StrToInt(getAttrValue(HXML(node),ioArgVariable ))=1 then flags:=flags or ACF_RW_SETTING;
+ if StrToInt(getAttrValue(HXML(node),ioVariables ))=1 then flags:=flags or ACF_RW_VALUE;
+
+ tmp:=getAttrValue(HXML(node),ioType);
+ if lstrcmpiw(tmp,ioByte )=0 then flags:=flags or ACF_DBBYTE
+ else if lstrcmpiw(tmp,ioWord )=0 then flags:=flags or ACF_DBWORD
+ else if lstrcmpiw(tmp,ioDword)=0 then
+ else if lstrcmpiw(tmp,ioAnsi )=0 then flags:=flags or ACF_DBANSI
+ else flags:=flags or ACF_DBUTEXT;
+
+ if StrToInt(getAttrValue(HXML(node),ioSaveValue))=1 then
+ flags:=flags or ACF_SAVE;
+
+ if StrToInt(getAttrValue(HXML(node),ioLast))=1 then
+ flags:=flags or ACF_LAST
+ else
+ StrDupW(dbvalue,getText(HXML(node)));
+ end;
+ end;
+{
+ 2: begin
+ pc:=GetParamSectionStr(node,ioOper);
+ if lstrcmpi(pc,ioDelete)=0 then flags:=flags or ACF_DBDELETE
+ else if lstrcmpi(pc,ioWrite )=0 then flags:=flags or ACF_DBWRITE;
+// else if lstrcmpiw(tmp,ioRead)=0 then ;
+ pc:=GetParamSectionStr(node,ioContact);
+ if lstrcmpi(pc,ioCurrent)=0 then flags:=flags or ACF_CURRENT
+ else if lstrcmpi(pc,ioResult )=0 then flags:=flags or ACF_RESULT
+ else if lstrcmpi(pc,ioParam )=0 then flags:=flags or ACF_PARAM
+ else if lstrcmpi(pc,ioContact)=0 then
+ begin
+ dbcontact:=ImportContactINI(node);
+ end;
+
+ UF8ToWide(GetParamSectionStr(node,ioModule ),dbmodule);
+ UF8ToWide(GetParamSectionStr(node,ioSetting),dbsetting);
+
+ if GetParamSectionInt(node,ioFileVariable)=1 then flags:=flags or ACF_RW_MODULE;
+ if GetParamSectionInt(node,ioArgVariable )=1 then flags:=flags or ACF_RW_SETTING;
+ if GetParamSectionInt(node,ioVariables )=1 then flags:=flags or ACF_RW_VALUE;
+
+ pc:=GetParamSectionStr(node,ioType);
+ if lstrcmpi(pc,ioByte )=0 then flags:=flags or ACF_DBBYTE
+ else if lstrcmpi(pc,ioWord )=0 then flags:=flags or ACF_DBWORD
+ else if lstrcmpi(pc,ioDword)=0 then
+ else if lstrcmpi(pc,ioAnsi )=0 then flags:=flags or ACF_DBANSI
+ else flags:=flags or ACF_DBUTEXT;
+
+ if GetParamSectionInt(node,ioLast))=1 then
+ flags:=flags or ACF_LAST
+ else
+ UF8ToWide(GetParamSectionStr(node,'value'),dbvalue); //!!
+ end;
+}
+ end;
+end;
+
+procedure tDataBaseAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ if (flags and ACF_NOCONTACT)=0 then
+ SaveContact(dbcontact,DBBranch,node);
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_module ); DBWriteUnicode(0,DBBranch,section,dbmodule);
+ StrCopy(pc,opt_setting); DBWriteUnicode(0,DBBranch,section,dbsetting);
+ if ((flags and ACF_DBDELETE)=0) and
+ ((flags and ACF_LAST)=0) then
+ begin
+ StrCopy(pc,opt_value); DBWriteUnicode(0,DBBranch,section,dbvalue);
+ end;
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure MakeDataTypeList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ InsertString(wnd,0,'Byte');
+ InsertString(wnd,1,'Word');
+ InsertString(wnd,2,'DWord');
+ InsertString(wnd,3,'Ansi');
+ InsertString(wnd,4,'Unicode');
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_RW_LAST,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RW_SAVE,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_RW_CURRENT,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RW_MANUAL ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RW_PARAM ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RW_RESULT ,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_RW_READ ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RW_WRITE ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RW_DELETE,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+var
+ wnd:HWND;
+ i:integer;
+ bb:boolean;
+begin
+ result:=0;
+
+ case hMessage of
+
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ MakeDataTypeList(GetDlgItem(Dialog,IDC_RW_DATATYPE));
+
+ wnd:=GetDlgItem(Dialog,IDC_CNT_REFRESH);
+ OptSetButtonIcon(wnd,ACI_REFRESH);
+ SendMessage(wnd,BUTTONADDTOOLTIP,TWPARAM(TranslateW('Refresh')),BATF_UNICODE);
+ OptFillContactList(GetDlgItem(Dialog,IDC_CONTACTLIST));
+
+ MakeEditField(Dialog,IDC_RW_MODULE);
+ MakeEditField(Dialog,IDC_RW_SETTING);
+ MakeEditField(Dialog,IDC_RW_VALUE);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ with tDataBaseAction(lParam) do
+ begin
+ // operation
+ if (flags and ACF_DBDELETE)<>0 then i:=IDC_RW_DELETE
+ else if (flags and ACF_DBWRITE )= 0 then i:=IDC_RW_READ
+ else i:=IDC_RW_WRITE;
+ CheckDlgButton(Dialog,i,BST_CHECKED);
+
+ // contact
+ bb:=false;
+ case (flags and ACF_NOCONTACT) of
+ ACF_CURRENT: i:=IDC_RW_CURRENT;
+ ACF_PARAM : i:=IDC_RW_PARAM;
+ ACF_RESULT : i:=IDC_RW_RESULT;
+ else
+ i:=IDC_RW_MANUAL;
+ bb:=true;
+ SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_SETCURSEL,
+ FindContact(GetDlgItem(Dialog,IDC_CONTACTLIST),dbcontact),0);
+ end;
+ CheckDlgButton(Dialog,i,BST_CHECKED);
+ EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),bb);
+
+ SetDlgItemTextW(Dialog,IDC_RW_MODULE ,dbmodule);
+ SetDlgItemTextW(Dialog,IDC_RW_SETTING,dbsetting);
+ SetEditFlags(Dialog,IDC_RW_MODULE ,EF_SCRIPT,ord((flags and ACF_RW_MODULE )<>0));
+ SetEditFlags(Dialog,IDC_RW_SETTING,EF_SCRIPT,ord((flags and ACF_RW_SETTING)<>0));
+
+ // values
+ bb:=true;
+ if (flags and ACF_LAST)<>0 then
+ begin
+ CheckDlgButton(Dialog,IDC_RW_LAST,BST_CHECKED);
+ bb:=false;
+ end;
+ if (flags and ACF_DBDELETE)<>0 then
+ bb:=false;
+ EnableWindow(GetDlgItem(Dialog,IDC_RW_VALUE),bb);
+
+ if (flags and ACF_SAVE)<>0 then
+ CheckDlgButton(Dialog,IDC_RW_SAVE,BST_CHECKED);
+ EnableWindow(GetDlgItem(Dialog,IDC_RW_SAVE),(flags and ACF_DBWRITE)<>0);
+
+ case (flags and ACF_VALUETYPE) of
+ ACF_DBBYTE : i:=0;
+ ACF_DBWORD : i:=1;
+ ACF_DBANSI : i:=3;
+ ACF_DBUTEXT: i:=4;
+ else
+ i:=2;
+ end;
+ CB_SelectData(GetDlgItem(Dialog,IDC_RW_DATATYPE),i);
+
+ SetDlgItemTextW(Dialog,IDC_RW_VALUE,dbvalue);
+ SetEditFlags(Dialog,IDC_RW_VALUE,EF_SCRIPT,ord((flags and ACF_RW_VALUE)<>0));
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ SetDlgItemTextW(Dialog,IDC_RW_MODULE ,nil);
+ SetDlgItemTextW(Dialog,IDC_RW_SETTING,nil);
+ SetDlgItemTextW(Dialog,IDC_RW_VALUE ,nil);
+ SetEditFlags(Dialog,IDC_RW_MODULE ,EF_ALL,0);
+ SetEditFlags(Dialog,IDC_RW_SETTING,EF_ALL,0);
+ SetEditFlags(Dialog,IDC_RW_VALUE ,EF_ALL,0);
+
+ CB_SelectData(GetDlgItem(Dialog,IDC_RW_DATATYPE),0);
+ CheckDlgButton(Dialog,IDC_RW_READ ,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_RW_MANUAL,BST_CHECKED);
+
+ EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),true);
+ EnableWindow(GetDlgItem(Dialog,IDC_RW_VALUE),true);
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tDataBaseAction(lParam) do
+ begin
+ // contact
+ if IsDlgButtonChecked(Dialog,IDC_RW_CURRENT)=BST_CHECKED then flags:=flags or ACF_CURRENT
+ else if IsDlgButtonChecked(Dialog,IDC_RW_RESULT )=BST_CHECKED then flags:=flags or ACF_RESULT
+ else if IsDlgButtonChecked(Dialog,IDC_RW_PARAM )=BST_CHECKED then flags:=flags or ACF_PARAM
+ else
+ dbcontact:=SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_GETITEMDATA,
+ SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_GETCURSEL,0,0),0);
+
+ {mFreeMem(dbmodule ); }dbmodule :=GetDlgText(Dialog,IDC_RW_MODULE);
+ {mFreeMem(dbsetting); }dbsetting:=GetDlgText(Dialog,IDC_RW_SETTING);
+ if (GetEditFlags(Dialog,IDC_RW_MODULE ) and EF_SCRIPT)<>0 then flags:=flags or ACF_RW_MODULE;
+ if (GetEditFlags(Dialog,IDC_RW_SETTING) and EF_SCRIPT)<>0 then flags:=flags or ACF_RW_SETTING;
+
+ // operation
+ if IsDlgButtonChecked(Dialog,IDC_RW_WRITE )=BST_CHECKED then flags:=flags or ACF_DBWRITE
+ else if IsDlgButtonChecked(Dialog,IDC_RW_DELETE)=BST_CHECKED then flags:=flags or ACF_DBDELETE;
+
+ // value
+ if IsDlgButtonChecked(Dialog,IDC_RW_LAST)<>BST_UNCHECKED then
+ flags:=flags or ACF_LAST
+ else if (flags and ACF_DBDELETE)=0 then
+ begin
+ {mFreeMem(dbvalue); }dbvalue:=GetDlgText(Dialog,IDC_RW_VALUE);
+ if (GetEditFlags(Dialog,IDC_RW_VALUE) and EF_SCRIPT)<>0 then flags:=flags or ACF_RW_VALUE;
+ end;
+
+ if IsDlgButtonChecked(Dialog,IDC_RW_SAVE)<>BST_UNCHECKED then
+ flags:=flags or ACF_SAVE;
+
+ i:=CB_GetData(GetDlgItem(Dialog,IDC_RW_DATATYPE));
+ case i of
+ 0: flags:=flags or ACF_DBBYTE;
+ 1: flags:=flags or ACF_DBWORD;
+ 2: flags:=flags or 0;
+ 3: flags:=flags or ACF_DBANSI;
+ 4: flags:=flags or ACF_DBUTEXT;
+ end;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ CBN_SELCHANGE,
+ EN_CHANGE: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_RW_READ,
+ IDC_RW_WRITE,
+ IDC_RW_DELETE: begin
+ bb:=IsDlgButtonChecked(Dialog,IDC_RW_DELETE)=BST_UNCHECKED;
+ EnableWindow(GetDlgItem(Dialog,IDC_RW_DATATYPE),bb);
+ EnableWindow(GetDlgItem(Dialog,IDC_RW_LAST),bb);
+ if bb then
+ bb:=IsDlgButtonChecked(Dialog,IDC_RW_LAST)=BST_UNCHECKED;
+ EnableEditField(GetDlgItem(Dialog,IDC_RW_VALUE),bb);
+
+ bb:=loword(wParam)=IDC_RW_WRITE;
+ EnableWindow(GetDlgItem(Dialog,IDC_RW_SAVE),bb);
+ end;
+ IDC_RW_CURRENT,
+ IDC_RW_PARAM,
+ IDC_RW_RESULT: EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),false);
+ IDC_RW_MANUAL: EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),true);
+
+ IDC_RW_LAST: begin
+ EnableEditField(GetDlgItem(Dialog,IDC_RW_VALUE),
+ IsDlgButtonChecked(Dialog,IDC_RW_LAST)=BST_UNCHECKED);
+ end;
+
+ IDC_CNT_REFRESH: begin
+ OptFillContactList(GetDlgItem(Dialog,IDC_CONTACTLIST));
+ exit;
+ end;
+ end;
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tDataBaseAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTDATABASE',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Database';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_DATABASE';
+ vc.Hash :=0;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_global.pas b/plugins/Actman30/iac_global.pas
new file mode 100644
index 0000000000..64a8604b2c
--- /dev/null
+++ b/plugins/Actman30/iac_global.pas
@@ -0,0 +1,428 @@
+unit iac_global;
+
+interface
+
+uses
+ windows, messages,
+ m_api;
+
+var
+ xmlparser:XML_API_W;
+
+const
+ IcoLibPrefix = 'action_type_';
+const
+ NoDescription:PWideChar='No Description';
+const
+ protostr = '<proto>';
+const
+ WM_ACT_SETVALUE = WM_USER + 13;
+ WM_ACT_RESET = WM_USER + 14;
+ WM_ACT_SAVE = WM_USER + 15;
+ WM_ACT_LISTCHANGE = WM_USER + 16; // group, action
+
+const
+ ACF_DISABLED = $10000000; // action disabled
+ ACF_REPLACED = $20000000; // action replaced by new in options
+ ACF_INTRODUCED = $40000000; // action is newly created (not saved) in options
+
+type
+ tLRType = record
+ value:uint_ptr;
+ rtype:byte; // rt* const
+ end;
+type
+ pWorkData = ^tWorkData;
+ tWorkData = record
+ Parameter :LPARAM;
+ ActionList :pointer;
+ LastResult :uint_ptr;
+ ActionCount:integer;
+ ResultType :integer; // rt* const
+ Storage :array [0..9] of tLRType;
+ end;
+
+type
+ pBaseAction = ^tBaseAction;
+ tBaseAction = class
+ ActionDescr:pWideChar; // description (user name)
+ UID :dword; // hash of action type name
+ flags :dword;
+
+ procedure Duplicate(var dst:tBaseAction);
+
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; virtual;
+ function DoAction(var WorkData:tWorkData):LRESULT; virtual; // process action
+ procedure Load(node:pointer;fmt:integer); virtual; // load/import action
+ procedure Save(node:pointer;fmt:integer); virtual; // save/export action
+ end;
+
+type
+ tCreateActionFunc = function:tBaseAction;
+ tCreateDialogFunc = function(parent:HWND):HWND;
+// tCheckImportFunc = function(node:pointer;fmt:integer):boolean;
+
+type
+ pActModule = ^tActModule;
+ tActModule = record
+ Next :pActModule;
+ Name :pAnsiChar; // action type name
+ Dialog :tCreateDialogFunc; // action dialog creating
+ Create :tCreateActionFunc; // action object creation
+// CheckImp :tCheckImportFunc; // check for action type
+ Icon :pAnsiChar; // icon resource name
+ // runtime data
+ DlgHandle:HWND;
+ Hash :dword; // will be calculated at registration cycle
+ end;
+
+const
+ ModuleLink:pActModule=nil;
+
+function ClearResult(var WorkData:tWorkData;num:integer=-1):uint_ptr;
+function GetResultNumber(var WorkData:tWorkData;num:integer=-1):uint_ptr;
+
+procedure InsertString(wnd:HWND;num:dword;str:PAnsiChar);
+
+function GetLink(hash:dword):pActModule;
+function GetLinkByName(name:pAnsiChar):pActModule;
+
+function ImportContact (node:HXML ):THANDLE;
+function ImportContactINI(node:pointer):THANDLE;
+
+implementation
+
+uses Common, global, dbsettings, base64, mirutils;
+
+//----- tBaseAction code -----
+const
+ ioDisabled = 'disabled';
+ ioName = 'name';
+const
+ opt_uid = 'uid';
+ opt_descr = 'descr';
+ opt_flags = 'flags';
+
+constructor tBaseAction.Create(uid:dword);
+begin
+ inherited Create;
+
+ if uid<>0 then
+ begin
+ StrDupW(ActionDescr,NoDescription);
+ Self.UID:=uid;
+ flags:=0;
+ end;
+end;
+
+destructor tBaseAction.Destroy;
+begin
+ mFreeMem(ActionDescr);
+
+ inherited Destroy;
+end;
+
+procedure tBaseAction.Duplicate(var dst:tBaseAction);
+begin
+ StrDupW(dst.ActionDescr,ActionDescr);
+ dst.UID :=UID;
+ dst.flags:=flags;
+end;
+{
+function tBaseAction.Clone:tBaseAction;
+begin
+ //dummy
+ result:=nil;
+end;
+}
+function tBaseAction.DoAction(var WorkData:tWorkData):LRESULT;
+begin
+ result:=0;
+ // nothing
+end;
+
+procedure tBaseAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ mFreeMem(ActionDescr); // created by constructor
+ StrCopy(pc,opt_descr); ActionDescr:=DBReadUnicode(0,DBBranch,section,NoDescription);
+ StrCopy(pc,opt_flags); flags :=DBReadDword (0,DBBranch,section);
+ // UID reading in main program, set by constructor
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ if StrToInt(getAttrValue(HXML(node),ioDisabled))=1 then
+ flags:=flags or ACF_DISABLED;
+
+ StrDupW(ActionDescr,getAttrValue(HXML(node),ioName));
+ end;
+ end;
+{
+ 2: begin
+ if GetParamSectionInt(node,ioDisabled))=1 then
+ flags:=flags or ACF_DISABLED;
+
+ UF8ToWide(GetParamSectionStr(node,ioName),ActionDescr);
+ end;
+}
+ end;
+end;
+
+procedure tBaseAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_uid ); DBWriteDWord (0,DBBranch,section,uid);
+ StrCopy(pc,opt_flags); DBWriteDWord (0,DBBranch,section,flags);
+ StrCopy(pc,opt_descr); DBWriteUnicode(0,DBBranch,section,ActionDescr);
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- LastResult processing -----
+
+function ClearResult(var WorkData:tWorkData;num:integer=-1):uint_ptr;
+var
+ rt:pbyte;
+ lr:^uint_ptr;
+begin
+ result:=0;
+
+ if num<0 then
+ begin
+ rt:=@WorkData.ResultType;
+ lr:=@WorkData.LastResult;
+ end
+ else if num<10 then
+ begin
+ rt:=@WorkData.Storage[num].rtype;
+ lr:=@WorkData.Storage[num].value;
+ end
+ else
+ exit;
+
+ if rt^=rtInt then
+ result:=lr^
+ else if rt^<>rtUnkn then
+ begin
+ mFreeMem(pWideChar(lr^));
+ result:=0;
+ end;
+end;
+
+function GetResultNumber(var WorkData:tWorkData;num:integer=-1):uint_ptr;
+var
+ rt:pbyte;
+ lr:^uint_ptr;
+begin
+ result:=0;
+
+ if num<0 then
+ begin
+ rt:=@WorkData.ResultType;
+ lr:=@WorkData.LastResult;
+ end
+ else if num<10 then
+ begin
+ rt:=@WorkData.Storage[num].rtype;
+ lr:=@WorkData.Storage[num].value;
+ end
+ else
+ exit;
+
+ if rt^=rtInt then
+ result:=lr^
+ else if rt^<>rtUnkn then
+ begin
+ result:=NumToInt(pWideChar(lr^));
+{
+ if (pWideChar(WorkData.LastResult)[0]='$') and
+ (AnsiChar(pWideChar(WorkData.LastResult)[1]) in sHexNum) then
+ result:=HexToInt(pWideChar(WorkData.LastResult)+1)
+ else
+ if (pWideChar(WorkData.LastResult)[0]='0') and
+ (pWideChar(WorkData.LastResult)[1]='x') and
+ (AnsiChar(pWideChar(WorkData.LastResult)[2]) in sHexNum) then
+ result:=HexToInt(pWideChar(WorkData.LastResult)+2)
+ else
+ result:=StrToInt(pWideChar(WorkData.LastResult));
+}
+ end;
+end;
+
+procedure InsertString(wnd:HWND;num:dword;str:PAnsiChar);
+var
+ buf:array [0..127] of WideChar;
+begin
+ SendMessageW(wnd,CB_SETITEMDATA,
+ SendMessageW(wnd,CB_ADDSTRING,0,
+ lparam(TranslateW(FastAnsiToWideBuf(str,buf)))),
+ num);
+{
+ SendMessageW(wnd,CB_INSERTSTRING,num,
+ dword(TranslateW(FastAnsiToWideBuf(str,buf))));
+}
+end;
+
+function GetLink(hash:dword):pActModule;
+begin
+ result:=ModuleLink;
+ while (result<>nil) and (result.Hash<>hash) do
+ result:=result^.Next;
+end;
+
+function GetLinkByName(name:pAnsiChar):pActModule;
+begin
+ result:=ModuleLink;
+ while (result<>nil) and (StrCmp(result.Name,name)<>0) do
+ result:=result^.Next;
+end;
+
+const
+ ioCProto = 'cproto';
+ ioIsChat = 'ischat';
+ ioCUID = 'cuid';
+ ioCUIDType = 'cuidtype';
+
+function ImportContact(node:HXML):THANDLE;
+var
+ proto:pAnsiChar;
+ tmpbuf:array [0..63] of AnsiChar;
+ dbv:TDBVARIANT;
+ tmp:pWideChar;
+ is_chat:boolean;
+begin
+ with xmlparser do
+ begin
+ proto:=FastWideToAnsiBuf(getAttrValue(node,ioCProto),tmpbuf);
+ if (proto=nil) or (proto^=#0) then
+ begin
+ result:=0;
+ exit;
+ end;
+ is_chat:=StrToInt(getAttrValue(node,ioIsChat))<>0;
+
+ tmp:=getAttrValue(node,ioCUID);
+ if is_chat then
+ begin
+ dbv.szVal.W:=tmp;
+ end
+ else
+ begin
+ FillChar(dbv,SizeOf(TDBVARIANT),0);
+ dbv._type:=StrToInt(getAttrValue(node,ioCUIDType));
+ case dbv._type of
+ DBVT_BYTE : dbv.bVal:=StrToInt(tmp);
+ DBVT_WORD : dbv.wVal:=StrToInt(tmp);
+ DBVT_DWORD : dbv.dVal:=StrToInt(tmp);
+ DBVT_ASCIIZ: FastWideToAnsi(tmp,dbv.szVal.A);
+ DBVT_UTF8 : WideToUTF8(tmp,dbv.szVal.A);
+ DBVT_WCHAR : dbv.szVal.W:=tmp;
+ DBVT_BLOB : begin
+ Base64Decode(FastWideToAnsi(tmp,pAnsiChar(dbv.pbVal)),dbv.pbVal);
+ end;
+ end;
+ end;
+ end;
+ result:=FindContactHandle(proto,dbv,is_chat);
+ if not is_chat then
+ case dbv._type of
+ DBVT_ASCIIZ,
+ DBVT_UTF8 : mFreeMem(dbv.szVal.A);
+ DBVT_BLOB : mFreeMem(dbv.pbVal);
+ end;
+end;
+
+function ImportContactINI(node:pointer):THANDLE;
+{
+var
+ proto:pAnsiChar;
+ dbv:TDBVARIANT;
+ tmp:pAnsiChar;
+ is_chat:boolean;
+}
+begin
+ result:=0;
+{
+ proto:=GetParamSectionStr(node,ioCProto); // LATIN chars must be
+ if (proto=nil) or (proto^=#0) then
+ begin
+ result:=0;
+ exit;
+ end;
+ is_chat:=GetParamSectionInt(node,ioIsChat)<>0;
+
+ tmp:=GetParamSectionStr(node,ioCUID);
+ if is_chat then
+ begin
+ dbv.szVal.W:=UTF8ToWide(tmp);
+ end
+ else
+ begin
+ FillChar(dbv,SizeOf(TDBVARIANT),0);
+ dbv._type:=GetParamSectionInt(node,ioCUIDType);
+ case dbv._type of
+ DBVT_BYTE : dbv.bVal:=StrToInt(tmp);
+ DBVT_WORD : dbv.wVal:=StrToInt(tmp);
+ DBVT_DWORD : dbv.dVal:=StrToInt(tmp);
+ DBVT_ASCIIZ: dbv.szVal.A:=tmp; // must be LATIN
+ DBVT_UTF8 : dbv.szVal.A:=tmp;
+ DBVT_WCHAR : UTF8ToWide(tmp);
+ DBVT_BLOB : begin // must be LATIN (base64)
+ Base64Decode(tmp,dbv.pbVal);
+ end;
+ end;
+ end;
+
+ result:=FindContactHandle(proto,dbv,is_chat);
+
+ if is_chat or (dbv._type=DBVT_WCHAR) then
+ mFreeMem(dbv.szVal.W)
+ else if dbv._type=DBVT_BLOB then
+ mFreeMem(dbv.pbVal);
+}
+end;
+{
+function CreateImportClass(node:pointer;fmt:integer):tBaseAction;
+var
+ module:pActModule;
+ uid:dword;
+ section:array [0..127] of AnsiChar;
+begin
+ result:=nil;
+ module:=ModuleLink;
+ case fmt of
+ 0: begin
+ StrCopy(StrCopyE(section,pAnsiChar(node)),opt_uid);
+ uid:=DBReadDWord(0,DBBranch,section,0);
+
+ while module<>nil do
+ begin
+ module:=module^.Next;
+ end;
+ end;
+ 1: begin
+ end;
+ 2: begin
+ end;
+ end;
+end;
+}
+end.
diff --git a/plugins/Actman30/iac_inout.pas b/plugins/Actman30/iac_inout.pas
new file mode 100644
index 0000000000..999d3fccaf
--- /dev/null
+++ b/plugins/Actman30/iac_inout.pas
@@ -0,0 +1,667 @@
+unit iac_inout;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ iac_global, global,
+ mirutils, common, dbsettings,
+ wrapper, editwrapper, io, syswin,
+ m_api;
+
+{$include i_cnst_inout.inc}
+{$resource iac_inout.res}
+
+const
+ opt_file = 'file';
+const
+ ioObject = 'object';
+ ioClipboard = 'clipboard';
+ ioOper = 'oper';
+ ioCopy = 'copy';
+ ioFile = 'file';
+ ioFileVariable = 'modvariables';
+ ioWrite = 'write';
+ ioAppend = 'append';
+ ioEnc = 'enc';
+const
+ ACF_CLIPBRD = $00000002; // Clipboard operations, not window
+ ACF_ANSI = $00000004; // File: ANSI or Unicode (UTF8/UTF16) text
+ ACF_COPYTO = $00000008; // Clipboard operations: 'copy to' or 'paste from'
+
+ ACF_FILE = $00000010; // File operations
+ ACF_FWRITE = $00000020; // read/write file
+ ACF_FAPPEND = $00000040; // append file
+ ACF_UTF8 = $00000080; // File: UTF8 or UTF16
+ ACF_SIGN = $00000100; // File: with signature or not
+ ACF_FILE_PATH = $00000200;
+
+ ACF_TEXTSEND = $00000400;
+ // dummy
+ ACF_MESSAGE = 0;
+
+type
+ tInOutAction = class(tBaseAction)
+ private
+ tfile:pWideChar;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tInOutAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ tfile:=nil;
+end;
+
+destructor tInOutAction.Destroy;
+begin
+ mFreeMem(tfile);
+
+ inherited Destroy;
+end;
+{
+function tInOutAction.Clone:tBaseAction;
+begin
+ result:=.Create(0);
+ Duplicate(result);
+
+end;
+}
+function tInOutAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ tmp:PWideChar;
+ blob,p:PAnsiChar;
+ w:PWideChar;
+ hContact:THANDLE;
+ wnd:HWND;
+ fexist:bool;
+ dbei:TDBEVENTINFO;
+ i:cardinal;
+ cp:integer;
+ fh:THANDLE;
+ lstr:pWideChar;
+ llen:integer;
+ buf:array [0..31] of WideChar;
+ b,b1:array [0..MAX_PATH] of AnsiChar;
+
+ last:pWideChar;
+begin
+ result:=0;
+
+ if WorkData.ResultType=rtInt then
+ last:=pWideChar(IntToStr(buf,WorkData.LastResult))
+ else
+ last:=pWideChar(WorkData.LastResult);
+
+ // Clipboard
+ if (flags and ACF_CLIPBRD)<>0 then
+ begin
+ if (flags and ACF_COPYTO)<>0 then
+ CopyToClipboard(last,false)
+ else
+ begin
+ ClearResult(WorkData);
+ WorkData.LastResult:=uint_ptr(PasteFromClipboard(false));
+ WorkData.ResultType:=rtWide;
+ end;
+ exit;
+ end;
+
+ // File
+ if (flags and ACF_FILE)<>0 then
+ begin
+ if (flags and ACF_FILE_PATH)<>0 then
+ begin
+ if CallService(MS_DB_CONTACT_IS,WorkData.Parameter,0)<>0 then
+ hContact:=WorkData.Parameter
+ else
+ hContact:=0;
+ tmp:=ParseVarString(tfile,hContact,last)
+ end
+ else
+ tmp:=tfile;
+
+ // File write
+ if (flags and (ACF_FAPPEND or ACF_FWRITE))<>0 then
+ begin
+ if (flags and ACF_ANSI)=ACF_ANSI then cp:=1 // Ansi
+ else if (flags and (ACF_UTF8 or ACF_SIGN))=ACF_UTF8 then cp:=2 // UTF8
+ else if (flags and (ACF_UTF8 or ACF_SIGN))=ACF_SIGN then cp:=4 // Wide+Sign
+ else if (flags and (ACF_UTF8 or ACF_SIGN))=(ACF_UTF8 or ACF_SIGN) then cp:=3 // UTF8+Sign
+ else cp:=0; // Wide
+
+ case cp of
+ 1: begin
+ llen:=StrLen(WideToAnsi(last,pAnsiChar(lstr),MirandaCP));
+ end;
+ 2,3: begin
+ llen:=StrLen(WideToUTF8(last,pAnsiChar(lstr)));
+ end;
+ else
+ lstr:=last;
+ llen:=StrLenW(lstr)*SizeOf(WideChar);
+ end;
+
+ fexist:=FileExists(tmp);
+ // Append file
+ if fexist and ((flags and ACF_FAPPEND)<>0) then
+ begin
+ fh:=Append(tmp);
+ if fh<>THANDLE(INVALID_HANDLE_VALUE) then
+ begin
+ BlockWrite(fh,lstr^,llen);
+ end;
+ if (cp<>0) and (cp<>4) then
+ mFreeMem(lstr);
+ end
+ // Write file
+ else if ((flags and ACF_FWRITE)<>0) or
+ (not fexist and ((flags and ACF_FAPPEND)<>0)) then
+ begin
+ fh:=ReWrite(tmp);
+ if fh<>THANDLE(INVALID_HANDLE_VALUE) then
+ begin
+ if cp=3 then
+ begin
+ i:=SIGN_UTF8;
+ BlockWrite(fh,i,3); // UTF8 sign
+ end
+ else if cp=4 then
+ begin
+ i:=SIGN_UNICODE;
+ BlockWrite(fh,i,2); // UTF16 sign
+ end;
+
+ BlockWrite(fh,lstr^,llen);
+ if (cp<>0) and (cp<>4) then
+ mFreeMem(lstr);
+ end;
+ end
+ else
+ fh:=THANDLE(INVALID_HANDLE_VALUE);
+ end
+ // File read
+ else
+ begin
+ // remove file - download
+ if StrPosW(tmp,'://')<>nil then // remote
+ begin
+ GetTempPathA(MAX_PATH,b);
+ GetTempFileNameA(b,'wat',GetCurrentTime,b1);
+ GetFile(FastWideToAnsiBuf(tmp,b),b1);
+ if tmp<>tfile then
+ mFreeMem(tmp);
+ FastAnsiToWide(b1,tmp);
+ end
+ else
+ b1[0]:=#0;
+ fh:=Reset(tmp);
+ // process file
+ if fh<>THANDLE(INVALID_HANDLE_VALUE) then
+ begin
+ i:=GetFSize(tmp);
+ mGetMem (w ,i+SizeOf(WideChar));
+ FillChar(w^,i+SizeOf(WideChar),0);
+ BlockRead(fh,w^,i);
+ if (flags and ACF_ANSI)<>0 then
+ begin
+ AnsiToWide(pAnsiChar(w),lstr,MirandaCP);
+ mFreeMem(w);
+ w:=lstr;
+ end
+ else if (flags and ACF_UTF8)<>0 then
+ begin
+ UTF8ToWide(pAnsiChar(w),lstr);
+ mFreeMem(w);
+ w:=lstr;
+ end
+ else
+ ChangeUnicode(w);
+
+ ClearResult(WorkData);
+ WorkData.LastResult:=uint_ptr(w);
+ WorkData.ResultType:=rtWide;
+ end;
+ if b1[0]<>#0 then
+ DeleteFileA(b1);
+ end;
+
+ if fh<>THANDLE(INVALID_HANDLE_VALUE) then
+ CloseHandle(fh);
+ if tmp<>tfile then
+ mFreeMem(tmp);
+ exit;
+ end;
+
+ // Message
+ wnd:=WaitFocusedWndChild(GetForegroundWindow){GetFocus};
+
+ // with Autosend
+ if (flags and ACF_TEXTSEND)<>0 then
+ begin
+ if wnd<>0 then
+ hContact:=WndToContact(wnd)
+ else
+ hContact:=0;
+
+ if hContact=0 then
+ begin
+ if CallService(MS_DB_CONTACT_IS,WorkData.Parameter,0)<>0 then
+ hContact:=WorkData.Parameter;
+ end;
+
+ if hContact=0 then exit;
+
+ p:=GetContactProtoAcc(hContact);
+ cp:=DBReadDWord(hContact,'Tab_SRMsg','ANSIcodepage',MirandaCP);
+ if DBReadByte(hContact,p,'ChatRoom',0)<>1 then
+ begin
+ i:=WideToCombo(last,blob,cp);
+// if CallContactService(hContact,PSS_MESSAGEW,0,TLPARAM(blob))=
+// ACKRESULT_FAILED then
+ CallContactService(hContact,PSS_MESSAGE,PREF_UNICODE,tlparam(blob));
+ dbei.cbSize :=sizeof(dbei);
+ dbei.cbBlob :=i;
+ dbei.pBlob :=pByte(blob);
+ dbei.eventType:=EVENTTYPE_MESSAGE;
+ dbei.timestamp:=GetCurrentTime;
+ dbei.szModule :=p;
+ dbei.flags :=DBEF_SENT;
+ db_event_add(hContact, @dbei);
+ mFreeMem(blob);
+ end
+ else
+ SendToChat(hContact,last);
+ end
+ else
+ begin
+ GetWindowThreadProcessId(GetForegroundWindow,@i);
+ if (i=GetCurrentProcessId) and (wnd<>0) then
+ SendMessageW(wnd,EM_REPLACESEL,1,tlparam(last))
+ else
+ SendString(0,last);
+ end;
+
+end;
+
+procedure tInOutAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+ tmp:pWideChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ if (flags and ACF_FILE)<>0 then
+ begin
+ StrCopy(pc,opt_file); tfile:=DBReadUnicode(0,DBBranch,section,nil);
+ end;
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ tmp:=getAttrValue(HXML(node),ioObject);
+ if lstrcmpiw(tmp,ioClipboard)=0 then
+ begin
+ flags:=flags or ACF_CLIPBRD;
+ tmp:=getAttrValue(HXML(node),ioOper);
+ if lstrcmpiw(tmp,ioCopy)=0 then flags:=flags or ACF_COPYTO;
+ // else if lstrcmpiw(tmp,'paste')=0 then ;
+ end
+ else
+ begin
+ if lstrcmpiw(tmp,ioFile)=0 then
+ begin
+
+ if StrToInt(getAttrValue(HXML(node),ioFileVariable))=1 then
+ flags:=flags or ACF_FILE_PATH;
+
+ flags:=flags or ACF_FILE;
+ StrDupW(tfile,getAttrValue(HXML(node),ioFile));
+ tmp:=getAttrValue(HXML(node),ioOper);
+ if lstrcmpiw(tmp,ioWrite )=0 then flags:=flags or ACF_FWRITE
+ else if lstrcmpiw(tmp,ioAppend)=0 then flags:=flags or ACF_FAPPEND;
+ case StrToInt(getAttrValue(HXML(node),ioEnc)) of
+ 0: flags:=flags or ACF_ANSI;
+ 1: flags:=flags or ACF_UTF8;
+ 2: flags:=flags or ACF_UTF8 or ACF_SIGN;
+ 3: flags:=flags or 0;
+ 4: flags:=flags or ACF_SIGN;
+ end;
+ end;
+ end;
+ end;
+ end;
+{
+ 2: begin
+ pc:=GetParamSectionStr(node,ioObject);
+ if lstrcmpi(tmp,ioClipboard)=0 then
+ begin
+ flags:=flags or ACF_CLIPBRD;
+ pc:=GetParamSectionStr(node,ioOper);
+ if lstrcmpi(pc,ioCopy)=0 then flags:=flags or ACF_COPYTO;
+// else if lstrcmpi(pc,'paste')=0 then ;
+ end
+ else
+ begin
+ if lstrcmpi(pc,ioFile)=0 then
+ begin
+ flags:=flags or ACF_FILE;
+
+ if GetParamSectionInt(node,ioFileVariable))=1 then
+ flags:=flags or ACF_FILE_PATH;
+
+ UTF8ToWide(GetParamSectionStr(node,ioFile),tfile);
+
+ pc:=GetParamSectionStr(node,ioOper);
+ if lstrcmpi(pc,ioWrite )=0 then flags:=flags or ACF_FWRITE
+ else if lstrcmpi(pc,ioAppend)=0 then flags:=flags or ACF_FAPPEND;
+
+ case GetParamSectionInt(node,ioEnc)) of
+ 0: flags:=flags or ACF_ANSI;
+ 1: flags:=flags or ACF_UTF8;
+ 2: flags:=flags or ACF_UTF8 or ACF_SIGN;
+ 3: flags:=flags or 0;
+ 4: flags:=flags or ACF_SIGN;
+ end;
+ end;
+ end;
+ end;
+}
+ end;
+end;
+
+procedure tInOutAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ if (flags and ACF_FILE)<>0 then
+ begin
+ StrCopy(pc,opt_file); DBWriteUnicode(0,DBBranch,section,tfile);
+ end;
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure FillFileName(Dialog:HWND;idc:integer);
+var
+ pw,ppw:pWideChar;
+begin
+ mGetMem(pw,1024*SizeOf(WideChar));
+ ppw:=GetDlgText(Dialog,idc);
+ if ShowDlgW(pw,ppw) then
+ begin
+ SetDlgItemTextW(Dialog,idc,pw);
+ SetEditFlags(Dialog,idc,EF_SCRIPT,0);
+ end;
+ mFreeMem(ppw);
+ mFreeMem(pw);
+end;
+
+procedure MakeTextTypeList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ InsertString(wnd,0,'Ansi');
+ InsertString(wnd,1,'UTF8');
+ InsertString(wnd,2,'UTF8+sign');
+ InsertString(wnd,3,'UTF16');
+ InsertString(wnd,4,'UTF16+sign');
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure SetSet(Dialog:HWND;num:integer);
+var
+ lclip,lfile,lmess:boolean;
+begin
+ case num of
+ 0: begin lclip:=true ; lfile:=false; lmess:=false; end;
+ 1: begin lclip:=false; lfile:=true ; lmess:=false; end;
+// 2: begin lclip:=false; lfile:=false; lmess:=true; end;
+ else
+ lclip:=false; lfile:=false; lmess:=true;
+ end;
+ EnableWindow(GetDlgItem(Dialog,IDC_CLIP_COPYTO),lclip);
+ EnableWindow(GetDlgItem(Dialog,IDC_CLIP_PASTE ),lclip);
+
+ EnableWindow(GetDlgItem(Dialog,IDC_FILE_READ ),lfile);
+ EnableWindow(GetDlgItem(Dialog,IDC_FILE_WRITE ),lfile);
+ EnableWindow(GetDlgItem(Dialog,IDC_FILE_APPEND ),lfile);
+ EnableWindow(GetDlgItem(Dialog,IDC_FILE_ENC ),lfile);
+ EnableWindow(GetDlgItem(Dialog,IDC_FILE_FILEBTN),lfile);
+ EnableEditField(Dialog,IDC_FILE_PATH,lfile);
+
+ EnableWindow(GetDlgItem(Dialog,IDC_TEXT_SEND),lmess);
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ SetDlgItemTextW(Dialog,IDC_FILE_PATH,nil);
+ SetEditFlags(Dialog,IDC_FILE_PATH,EF_ALL,0);
+
+ CheckDlgButton(Dialog,IDC_FLAG_CLIP ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_FILE ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_MESSAGE,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_CLIP_COPYTO,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_CLIP_PASTE ,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_FILE_READ ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FILE_WRITE ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FILE_APPEND,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_TEXT_SEND,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+var
+ i:integer;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ MakeTextTypeList(GetDlgItem(Dialog,IDC_FILE_ENC));
+
+ MakeEditField(Dialog,IDC_FILE_PATH);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ with tInOutAction(lParam) do
+ begin
+ if (flags and ACF_CLIPBRD)<>0 then
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_CLIP,BST_CHECKED);
+ if (flags and ACF_COPYTO)<>0 then
+ CheckDlgButton(Dialog,IDC_CLIP_COPYTO,BST_CHECKED)
+ else
+ CheckDlgButton(Dialog,IDC_CLIP_PASTE,BST_CHECKED);
+ SetSet(Dialog,0);
+ end
+
+ else if (flags and ACF_FILE)<>0 then
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_FILE,BST_CHECKED);
+
+ if (flags and ACF_ANSI)<>0 then
+ i:=0
+ else if (flags and ACF_UTF8)<>0 then
+ begin
+ if (flags and ACF_SIGN)<>0 then
+ i:=2
+ else
+ i:=1
+ end
+ else if (flags and ACF_SIGN)<>0 then
+ i:=4
+ else
+ i:=3;
+ CB_SelectData(GetDlgItem(Dialog,IDC_FILE_ENC),i);
+
+ if (flags and ACF_FAPPEND)<>0 then CheckDlgButton(Dialog,IDC_FILE_APPEND,BST_CHECKED)
+ else if (flags and ACF_FWRITE )<>0 then CheckDlgButton(Dialog,IDC_FILE_WRITE ,BST_CHECKED)
+ else CheckDlgButton(Dialog,IDC_FILE_READ ,BST_CHECKED);
+ SetDlgItemTextW(Dialog,IDC_FILE_PATH,tfile);
+ SetEditFlags(Dialog,IDC_FILE_PATH,EF_SCRIPT,ord((flags and ACF_FILE_PATH)<>0));
+
+ SetSet(Dialog,1);
+ end
+ else
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_MESSAGE,BST_CHECKED);
+
+ if (flags and ACF_TEXTSEND)<>0 then CheckDlgButton(Dialog,IDC_TEXT_SEND,BST_CHECKED);
+
+ SetSet(Dialog,2);
+ end;
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ CheckDlgButton(Dialog,IDC_FLAG_CLIP,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_CLIP_COPYTO,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_FILE_READ,BST_CHECKED);
+ SetSet(Dialog,0); // clipboard
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tInOutAction(lParam) do
+ begin
+// flags:=0;
+ // Clipboard
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_CLIP)<>BST_UNCHECKED then
+ begin
+ flags:=flags or ACF_CLIPBRD;
+ if IsDlgButtonChecked(Dialog,IDC_CLIP_COPYTO)<>BST_UNCHECKED then
+ flags:=flags or ACF_COPYTO;
+ end
+ // text file
+ else if IsDlgButtonChecked(Dialog,IDC_FLAG_FILE)<>BST_UNCHECKED then
+ begin
+ flags:=flags or ACF_FILE;
+ case CB_GetData(GetDlgItem(Dialog,IDC_FILE_ENC)) of
+ 0: flags:=flags or ACF_ANSI;
+ 1: flags:=flags or ACF_UTF8;
+ 2: flags:=flags or ACF_UTF8 or ACF_SIGN;
+ 3: flags:=flags or 0;
+ 4: flags:=flags or ACF_SIGN;
+ end;
+
+ tfile:=GetDlgText(Dialog,IDC_FILE_PATH);
+ if (GetEditFlags(Dialog,IDC_FILE_PATH) and EF_SCRIPT)<>0 then flags:=flags or ACF_FILE_PATH;
+
+ if IsDlgButtonChecked(Dialog,IDC_FILE_APPEND)<>BST_UNCHECKED then
+ flags:=flags or ACF_FAPPEND
+ else if IsDlgButtonChecked(Dialog,IDC_FILE_WRITE)<>BST_UNCHECKED then
+ flags:=flags or ACF_FWRITE;
+ end
+ // Message
+ else
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_TEXT_SEND)<>BST_UNCHECKED then
+ flags:=flags or ACF_TEXTSEND;
+ end;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ CBN_SELCHANGE,
+ EN_CHANGE: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_FLAG_CLIP: begin
+ SetSet(Dialog,0);
+ end;
+ IDC_FLAG_FILE: begin
+ SetSet(Dialog,1);
+ end;
+ IDC_FLAG_MESSAGE: begin
+ SetSet(Dialog,2);
+ end;
+ IDC_FILE_FILEBTN: begin
+ FillFileName(Dialog,IDC_FILE_PATH);
+ end;
+ end;
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tInOutAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_INOUT',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='In/Out';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_INOUT';
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_inout.rc b/plugins/Actman30/iac_inout.rc
new file mode 100644
index 0000000000..ca61e5f492
--- /dev/null
+++ b/plugins/Actman30/iac_inout.rc
@@ -0,0 +1,30 @@
+#include "i_cnst_inout.inc"
+
+LANGUAGE 0,0
+
+IDD_INOUT DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ AUTORADIOBUTTON "Clipboard" , IDC_FLAG_CLIP , 1, 2, 166, 11, WS_GROUP
+ AUTORADIOBUTTON "File" , IDC_FLAG_FILE , 1, 52, 166, 11
+ AUTORADIOBUTTON "Message window", IDC_FLAG_MESSAGE, 1, 118, 166, 11
+
+ GROUPBOX "" , -1 , 1, 11, 166, 33
+ AUTORADIOBUTTON "Copy to" , IDC_CLIP_COPYTO, 6, 18, 158, 11, WS_GROUP
+ AUTORADIOBUTTON "Paste from", IDC_CLIP_PASTE , 6, 29, 158, 11
+
+ GROUPBOX "" , -1 , 1, 61, 166, 52
+ AUTORADIOBUTTON "Read" , IDC_FILE_READ , 4, 69, 52, 11, WS_GROUP
+ AUTORADIOBUTTON "Write" , IDC_FILE_WRITE , 57, 69, 52, 11
+ AUTORADIOBUTTON "Append" , IDC_FILE_APPEND , 110, 69, 52, 11
+ EDITTEXT IDC_FILE_PATH , 4, 82, 140, 12, ES_AUTOHSCROLL
+ PUSHBUTTON "..." , IDC_FILE_FILEBTN, 147, 82, 16, 12
+ COMBOBOX IDC_FILE_ENC , 4, 97, 160, 76, CBS_DROPDOWNLIST | WS_VSCROLL
+
+ GROUPBOX "" , -1 , 1, 127, 166, 22
+ AUTOCHECKBOX "Autosend" , IDC_TEXT_SEND, 6, 135, 158, 11
+}
+
+IDI_INOUT ICON "ico\insert.ico"
diff --git a/plugins/Actman30/iac_jump.pas b/plugins/Actman30/iac_jump.pas
new file mode 100644
index 0000000000..9a54d7181b
--- /dev/null
+++ b/plugins/Actman30/iac_jump.pas
@@ -0,0 +1,699 @@
+unit iac_jump;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ m_api, dbsettings,
+ global,iac_global, editwrapper, dlgshare,
+ common, mirutils, wrapper;
+
+{$include i_cnst_jump.inc}
+{$resource iac_jump.res}
+
+const // condition code
+ aeGT = 1;
+ aeLT = 2;
+ aeEQ = 3;
+ aeXR = 4;
+ aeND = 5;
+
+ aeEMP = 1;
+ aeEQU = 2;
+ aeCON = 3;
+ aeSTR = 4;
+ aeEND = 5;
+const
+ opt_value = 'value';
+ opt_condition = 'condition';
+ opt_label = 'label';
+const
+ ioIf = 'IF';
+ ioCond = 'cond';
+ ioNop = 'nop';
+ ioNot = 'not';
+ ioValue = 'value';
+ ioOper = 'oper';
+ ioAction = 'action';
+ ioLabel = 'label';
+ ioBreak = 'break';
+ ioJump = 'jump';
+ ioPost = 'POST';
+ ioCase = 'case';
+ ioBack = 'back';
+const
+ ACF_NOP = $00000001;
+ ACF_MATH = $00000002;
+ ACF_NOT = $00000004;
+ ACF_CASE = $00000008;
+ ACF_BREAK = $00000010;
+ ACF_BACK = $00000020;
+ ACF_VALUE = $00000100;
+
+type
+ tJumpAction = class(tBaseAction)
+ private
+ value :pWideChar;
+ actlabel :pWideChar;
+ condition:integer;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tJumpAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ condition:=0;
+ value :=nil;
+ actlabel :=nil;
+end;
+
+destructor tJumpAction.Destroy;
+begin
+ mFreeMem(value);
+ mFreeMem(actlabel);
+
+ inherited Destroy;
+end;
+{
+function tJumpAction.Clone:tBaseAction;
+begin
+ result:=tJumpAction.Create(0);
+ Duplicate(result);
+
+ result.condition:=condition;
+ StrDupW(result.value,value);
+ StrDupW(result.actlabel,actlabel);
+end;
+}
+function tJumpAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ tmpint:int64;
+ vnum:int_ptr;
+ vstr,vlast:pWideChar;
+ buf:array [0..31] of WideChar;
+ res:boolean;
+ vlr,vval:pWideChar;
+ tmp:pWideChar;
+ delta:integer;
+ lptr:pBaseAction;
+begin
+ result:=0;
+
+ // Condition
+ if (flags and ACF_NOP)=0 then
+ begin
+ // preparing value
+ if WorkData.ResultType=rtInt then
+ vlast:=IntToStr(buf,WorkData.LastResult)
+ else
+ vlast:=pWideChar(WorkData.LastResult);
+
+ if (flags and ACF_VALUE)<>0 then
+ begin
+ vstr:=ParseVarString(value,WorkData.Parameter,vlast);
+ end
+ else
+ vstr:=value;
+
+ res:=false;
+ // now comparing
+ if (flags and ACF_MATH)<>0 then
+ begin
+ vnum:=int_ptr(GetResultNumber(WorkData));
+ tmpint:=NumToInt(vstr);
+ case condition of
+ aeGT: res:=vnum>tmpint;
+ aeLT: res:=vnum<tmpint;
+ aeEQ: res:=vnum=tmpint;
+ aeXR: res:=(vnum xor tmpint)<>0;
+ aeND: res:=(vnum and tmpint)<>0;
+ end;
+
+ end
+ else
+ begin
+ if (condition=aeEMP) and ((vlast=nil) or (vlast[0]=#0)) then
+ res:=true
+ else
+ begin
+ if (flags and ACF_CASE)=0 then
+ begin
+ StrDupW(vlr,vlast);
+ StrDupW(vval,vstr);
+ CharUpperW(vlr);
+ CharUpperW(vval);
+ end
+ else
+ begin
+ vlr :=vlast;
+ vval:=vstr;
+ end;
+
+ if (flags and ACF_BACK)<>0 then
+ begin
+ tmp:=vlr;
+ vlr:=vval;
+ vval:=tmp;
+ end;
+
+ case condition of
+ aeEQU: res:=StrCmpW(vlr,vval)=0;
+ aeCON: res:=StrPosW(vlr,vval)<>nil;
+ aeSTR: res:=StrPosW(vlr,vval)=vlr;
+ aeEND: begin
+ delta:=StrLenW(vval)-StrLenW(vlr);
+ if delta>=0 then
+ res:=StrCmpW(vlr,vval+delta)=0;
+ end;
+ end;
+
+ if (vlr<>vlast) and (vlr<>vstr) then
+ begin
+ mFreeMem(vlr);
+ mFreeMem(vval);
+ end;
+ end;
+ end;
+
+ if (flags and ACF_NOT)<>0 then
+ res:=not res;
+
+ if (flags and ACF_VALUE)<>0 then
+ mFreeMem(vstr);
+ end
+ else
+ res:=true;
+
+ // Operation
+ if res then
+ if (flags and ACF_BREAK)<>0 then
+ result:=-1
+ else
+ begin
+ lptr:=pBaseAction(WorkData.ActionList);
+ for delta:=0 to WorkData.ActionCount-1 do
+ begin
+ if StrCmpW(actlabel,lptr^.ActionDescr)=0 then
+ begin
+ result:=delta+1;
+ break;
+ end;
+ inc(lptr);
+ end;
+ end;
+end;
+
+procedure tJumpAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+ tmp:pWideChar;
+ sub:HXML;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ if (flags and ACF_NOP)=0 then
+ begin
+ StrCopy(pc,opt_value ); value :=DBReadUnicode(0,DBBranch,section,nil);
+ StrCopy(pc,opt_condition); condition:=DBReadByte (0,DBBranch,section,0);
+ end;
+ if (flags and ACF_BREAK)=0 then
+ begin
+ StrCopy(pc,opt_label); actlabel:=DBReadUnicode(0,DBBranch,section,nil);
+ end;
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ sub:=getNthChild(HXML(node),ioIf,0);
+ if sub<>0 then
+ begin
+ tmp:=getAttrValue(sub,ioOper);
+ if lstrcmpiw(tmp,'math')=0 then flags:=flags or ACF_MATH
+ else if lstrcmpiw(tmp,ioNop )=0 then flags:=flags or ACF_NOP;
+
+ tmp:=getAttrValue(sub,ioCond);
+ if lstrcmpiw(tmp,ioNop)=0 then flags:=flags or ACF_NOP // compatibility
+ else if (flags and ACF_NOP)=0 then
+ begin
+ if flags and ACF_MATH<>0 then
+ begin
+ if lstrcmpiw(tmp,'gt' )=0 then condition:=aeGT
+ else if lstrcmpiw(tmp,'lt' )=0 then condition:=aeLT
+ else if lstrcmpiw(tmp,'eq' )=0 then condition:=aeEQ
+ else if lstrcmpiw(tmp,'xor')=0 then condition:=aeXR
+ else if lstrcmpiw(tmp,'and')=0 then condition:=aeND;
+ end
+ else
+ begin
+ if lstrcmpiw(tmp,'empty')=0 then condition:=aeEMP
+ else if lstrcmpiw(tmp,'eq' )=0 then condition:=aeEQU
+ else if lstrcmpiw(tmp,'cont' )=0 then condition:=aeCON
+ else if lstrcmpiw(tmp,'start')=0 then condition:=aeSTR
+ else if lstrcmpiw(tmp,'ends' )=0 then condition:=aeEND;
+
+ if StrToInt(getAttrValue(sub,ioCase))=1 then
+ flags:=flags or ACF_CASE;
+ if StrToInt(getAttrValue(sub,ioBack))=1 then
+ flags:=flags or ACF_BACK;
+ end;
+ if StrToInt(getAttrValue(sub,ioNot))=1 then
+ flags:=flags or ACF_NOT;
+
+ if ((flags and ACF_MATH)<>0) or (condition<>aeEMP) then
+ StrDupW(value,getAttrValue(sub,ioValue));
+ end;
+ end;
+
+ sub:=getNthChild(HXML(node),ioPost,0);
+ if sub<>0 then
+ begin
+ tmp:=getAttrValue(sub,ioOper);
+ if lstrcmpiw(tmp,ioBreak)=0 then flags:=flags or ACF_BREAK
+ else if lstrcmpiw(tmp,ioJump )=0 then StrDupW(actlabel,getAttrValue(sub,ioValue));
+ end;
+ end;
+ end;
+{
+ 2: begin
+ pc:=GetParamSectionStr(node,ioOper);
+ if lstrcmpi(pc,'math')=0 then flags:=flags or ACF_MATH
+ else if lstrcmpi(pc,ioNop )=0 then flags:=flags or ACF_NOP;
+
+ pc:=GetParamSectionStr(node,ioCond);
+ if lstrcmpi(pc,ioNop)=0 then flags:=flags or ACF_NOP // compatibility
+ else if (flags and ACF_NOP)=0 then
+ begin
+ if flags and ACF_MATH<>0 then
+ begin
+ if lstrcmpi(pc,'gt' )=0 then condition:=aeGT
+ else if lstrcmpi(pc,'lt' )=0 then condition:=aeLT
+ else if lstrcmpi(pc,'eq' )=0 then condition:=aeEQ
+ else if lstrcmpi(pc,'xor')=0 then condition:=aeXR
+ else if lstrcmpi(pc,'and')=0 then condition:=aeND;
+ end
+ else
+ begin
+ if lstrcmpi(pc,'empty')=0 then condition:=aeEMP
+ else if lstrcmpi(pc,'eq' )=0 then condition:=aeEQU
+ else if lstrcmpi(pc,'cont' )=0 then condition:=aeCON
+ else if lstrcmpi(pc,'start')=0 then condition:=aeSTR
+ else if lstrcmpi(pc,'ends' )=0 then condition:=aeEND;
+
+ if GetParamSectionInt(node,ioCase)=1 then
+ flags:=flags or ACF_CASE;
+ if GetParamSectionInt(node,ioBack)=1 then
+ flags:=flags or ACF_BACK;
+ end;
+ if GetParamSectionInt(node,ioNot)=1 then
+ flags:=flags or ACF_NOT;
+
+ if ((flags and ACF_MATH)<>0) or (condition<>aeEMP) then
+ UTF8ToWide(GetParamSectionStr(node,ioValue),value);
+ end;
+
+ pc:=GetParamSectionStr(node,ioAction);
+ if lstrcmpi(pc,ioBreak)=0 then flags:=flags or ACF_BREAK
+ else if lstrcmpi(pc,ioJump )=0 then UTF8ToWide(GetParamSectionStr(node,ioLabel),actlabel);
+ end;
+}
+ end;
+end;
+
+procedure tJumpAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ if (flags and ACF_NOP)=0 then
+ begin
+ StrCopy(pc,opt_value ); DBWriteUnicode(0,DBBranch,section,value);
+ StrCopy(pc,opt_condition); DBWriteByte (0,DBBranch,section,condition);
+ end;
+ if (flags and ACF_BREAK)=0 then
+ begin
+ StrCopy(pc,opt_label); DBWriteUnicode(0,DBBranch,section,actlabel);
+ end;
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure FillMathList(Dialog:HWND);
+var
+ wnd:HWND;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_JMP_MATH);
+
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+
+ InsertString(wnd,cardinal(aeGT),'> greater');
+ InsertString(wnd,cardinal(aeLT),'> lesser');
+ InsertString(wnd,cardinal(aeEQ),'= equ');
+ InsertString(wnd,cardinal(aeXR),'^ xor');
+ InsertString(wnd,cardinal(aeND),'& and');
+
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure FillTextList(Dialog:HWND);
+var
+ wnd:HWND;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_JMP_TEXT);
+
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+
+ InsertString(wnd,cardinal(aeEMP),'empty');
+ InsertString(wnd,cardinal(aeEQU),'= equ');
+ InsertString(wnd,cardinal(aeCON),'contains');
+ InsertString(wnd,cardinal(aeSTR),'starts with');
+ InsertString(wnd,cardinal(aeEND),'ends with');
+
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure FillActionList(Dialog:HWND);
+var
+ list,wnd:HWND;
+ i,act:integer;
+ arr:array [0..127] of WideChar;
+ li:LV_ITEMW;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_JMP_ACTLIST);
+
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+
+ list:=ActionListWindow;
+ act:=SendMessageW(list,LVM_GETITEMCOUNT,0,0);
+ i:=0;
+ li.mask :=LVIF_TEXT;
+ li.iSubItem :=0;
+ li.pszText :=@arr;
+ li.cchTextMax:=SizeOf(arr) div SizeOf(WideChar);
+ while i<act do
+ begin
+ li.iItem:=i;
+ SendMessageW(list,LVM_GETITEMW,0,lparam(@li));
+ SendMessageW(wnd,CB_ADDSTRING,0,lparam(PWideChar(@arr)));
+ inc(i);
+ end;
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure SetFields(Dialog:HWND);
+var
+ bmath,btext:boolean;
+begin
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_NOP)<>BST_UNCHECKED then
+ begin
+ bmath:=false;
+ btext:=false;
+ end
+ else if IsDlgButtonChecked(Dialog,IDC_FLAG_MATH)<>BST_UNCHECKED then
+ begin
+ bmath:=true;
+ btext:=false;
+ end
+ else
+ begin
+ bmath:=false;
+ btext:=true;
+ end;
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_MATH ),bmath);
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_TEXT ),btext);
+ EnableWindow(GetDlgItem(Dialog,IDC_FLAG_CASE),btext);
+ EnableWindow(GetDlgItem(Dialog,IDC_FLAG_BACK),btext);
+ EnableWindow(GetDlgItem(Dialog,IDC_FLAG_NOT ),bmath or btext);
+ EnableEditField(GetDlgItem(Dialog,IDC_JMP_VALUE),bmath or btext);
+ if btext then
+ begin
+ btext:=CB_GetData(GetDlgItem(Dialog,IDC_JMP_TEXT))<>aeEMP;
+ EnableWindow (GetDlgItem(Dialog,IDC_FLAG_CASE),btext);
+ EnableWindow (GetDlgItem(Dialog,IDC_FLAG_BACK),btext);
+ EnableEditField(GetDlgItem(Dialog,IDC_JMP_VALUE),btext);
+ end;
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_MATH ),true);
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_TEXT ),true);
+ EnableWindow(GetDlgItem(Dialog,IDC_FLAG_NOT ),true);
+ EnableWindow(GetDlgItem(Dialog,IDC_FLAG_CASE),true);
+ EnableEditField(GetDlgItem(Dialog,IDC_JMP_VALUE),true);
+ SetDlgItemTextW(Dialog,IDC_JMP_VALUE,nil);
+ SetEditFlags(Dialog,IDC_JMP_VALUE,EF_ALL,0);
+
+ CheckDlgButton(Dialog,IDC_FLAG_NOP ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_MATH ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_TEXT ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_NOT ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_CASE ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_BACK ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_BREAK,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_JUMP ,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+var
+ bb:boolean;
+ wnd:HWND;
+ tmp:dword;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ FillMathList(Dialog);
+ FillTextList(Dialog);
+
+ TranslateDialogDefault(Dialog);
+
+ MakeEditField(Dialog,IDC_JMP_VALUE);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+ with tJumpAction(lParam) do
+ begin
+ FillActionList(Dialog);
+// SendDlgItemMessage(Dialog,IDC_JMP_ACTLIST,CB_SETCURSEL,0,0);
+ // Condition
+ if (flags and ACF_NOP)<>0 then
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_NOP,BST_CHECKED);
+ end
+ else
+ begin
+ if (flags and ACF_NOT)<>0 then
+ CheckDlgButton(Dialog,IDC_FLAG_NOT,BST_CHECKED);
+ SetDlgItemTextW(Dialog,IDC_JMP_VALUE,value);
+ SetEditFlags(Dialog,IDC_JMP_VALUE,EF_SCRIPT,ord((flags and ACF_VALUE)<>0));
+
+ // Math
+ if (flags and ACF_MATH)<>0 then
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_MATH,BST_CHECKED);
+ CB_SelectData(Dialog,IDC_JMP_MATH,condition);
+ end
+ // Text
+ else
+ begin
+ if (flags and ACF_CASE)<>0 then
+ CheckDlgButton(Dialog,IDC_FLAG_CASE,BST_CHECKED);
+ if (flags and ACF_BACK)<>0 then
+ CheckDlgButton(Dialog,IDC_FLAG_BACK,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_TEXT,BST_CHECKED);
+ CB_SelectData(Dialog,IDC_JMP_TEXT,condition);
+ end;
+ end;
+ SetFields(Dialog);
+
+ //Operation
+ if (flags and ACF_BREAK)<>0 then
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_BREAK,BST_CHECKED);
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_ACTLIST),false);
+ end
+ else
+ begin
+ CheckDlgButton(Dialog,IDC_FLAG_JUMP,BST_CHECKED);
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_ACTLIST),true);
+ SendDlgItemMessageW(Dialog,IDC_JMP_ACTLIST,CB_SELECTSTRING,
+ twparam(-1),tlparam(actlabel));
+ end;
+
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ CheckDlgButton(Dialog,IDC_FLAG_BREAK,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_NOP ,BST_CHECKED);
+ SetFields(Dialog);
+ CB_SelectData(GetDlgItem(Dialog,IDC_JMP_MATH),aeEQ);
+ CB_SelectData(GetDlgItem(Dialog,IDC_JMP_TEXT),aeEQU);
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_ACTLIST),false);
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tJumpAction(lParam) do
+ begin
+ // Condition
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_NOP)<>BST_UNCHECKED then
+ flags:=flags or ACF_NOP
+ else
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_NOT)<>BST_UNCHECKED then
+ flags:=flags or ACF_NOT;
+
+ value:=GetDlgText(Dialog,IDC_JMP_VALUE);
+ if (GetEditFlags(Dialog,IDC_JMP_VALUE) and EF_SCRIPT)<>0 then
+ flags:=flags or ACF_VALUE;
+
+ // math
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_MATH)<>BST_UNCHECKED then
+ begin
+ flags:=flags or ACF_MATH;
+ condition:=CB_GetData(GetDlgItem(Dialog,IDC_JMP_MATH));
+ end
+ // text
+ else
+ begin
+ condition:=CB_GetData(GetDlgItem(Dialog,IDC_JMP_TEXT));
+ if condition<>aeEMP then
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_CASE)<>BST_UNCHECKED then
+ flags:=flags or ACF_CASE;
+
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_BACK)<>BST_UNCHECKED then
+ flags:=flags or ACF_BACK;
+ end;
+ end;
+ end;
+
+ // Operation
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_BREAK)<>BST_UNCHECKED then
+ flags:=flags or ACF_BREAK
+ else
+ begin
+ actlabel:=GetDlgText(Dialog,IDC_JMP_ACTLIST);
+ end;
+
+ end;
+ end;
+
+ WM_ACT_LISTCHANGE: begin
+ if wParam=2 then
+ begin
+ wnd:=GetDlgItem(Dialog,IDC_JMP_ACTLIST);
+ tmp:=CB_GetData(wnd);
+ FillActionList(Dialog);
+ CB_SelectData(wnd,tmp);
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+
+ CBN_SELCHANGE: begin
+ case loword(wParam) of
+ IDC_JMP_TEXT: begin
+ bb:=CB_GetData(lParam)<>aeEMP;
+ EnableWindow (GetDlgItem(Dialog,IDC_FLAG_CASE),bb);
+ EnableWindow (GetDlgItem(Dialog,IDC_FLAG_BACK),bb);
+ EnableEditField(GetDlgItem(Dialog,IDC_JMP_VALUE),bb);
+ end;
+ end;
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_FLAG_NOP,
+ IDC_FLAG_MATH,
+ IDC_FLAG_TEXT: SetFields(Dialog);
+ IDC_FLAG_BREAK: begin
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_ACTLIST),false);
+ end;
+ IDC_FLAG_JUMP: begin
+ EnableWindow(GetDlgItem(Dialog,IDC_JMP_ACTLIST),true);
+ end;
+ end;
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tJumpAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTJUMP',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Jump';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_JUMP';
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_jump.rc b/plugins/Actman30/iac_jump.rc
new file mode 100644
index 0000000000..4731042c38
--- /dev/null
+++ b/plugins/Actman30/iac_jump.rc
@@ -0,0 +1,32 @@
+#include "i_cnst_jump.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTJUMP DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ GROUPBOX "Condition", -1 , 1, 2, 166, 144
+
+ AUTORADIOBUTTON "NOP" , IDC_FLAG_NOP , 4, 11, 160, 11, WS_GROUP
+ AUTORADIOBUTTON "Math" , IDC_FLAG_MATH, 4, 24, 160, 11
+ AUTORADIOBUTTON "Text" , IDC_FLAG_TEXT, 4, 53, 160, 11
+
+ COMBOBOX IDC_JMP_MATH , 12, 37, 152, 96, CBS_DROPDOWNLIST | WS_VSCROLL | CBS_AUTOHSCROLL
+
+ AUTOCHECKBOX "Case sensitive", IDC_FLAG_CASE, 4, 66, 160, 11
+ AUTOCHECKBOX "Opposite order", IDC_FLAG_BACK, 4, 78, 160, 11
+ COMBOBOX IDC_JMP_TEXT , 12, 92, 152, 96, CBS_DROPDOWNLIST | WS_VSCROLL | CBS_AUTOHSCROLL
+
+ AUTOCHECKBOX "NOT" , IDC_FLAG_NOT , 4, 118, 32, 11
+ RTEXT "Value" , -1 , 86, 118, 78, 11, SS_CENTERIMAGE
+ EDITTEXT IDC_JMP_VALUE, 4, 132, 160, 11, ES_AUTOHSCROLL
+
+ GROUPBOX "Operation", -1 , 1, 152, 166, 39, WS_GROUP
+ AUTORADIOBUTTON "BREAK" , IDC_FLAG_BREAK , 4, 161, 62, 12
+ AUTORADIOBUTTON "JUMP" , IDC_FLAG_JUMP , 4, 174, 62, 12
+ COMBOBOX IDC_JMP_ACTLIST, 66, 174, 99, 96, CBS_DROPDOWNLIST | WS_VSCROLL | CBS_AUTOHSCROLL
+}
+
+IDI_JUMP ICON "ico\jump.ico"
diff --git a/plugins/Actman30/iac_messagebox.pas b/plugins/Actman30/iac_messagebox.pas
new file mode 100644
index 0000000000..f782e54e94
--- /dev/null
+++ b/plugins/Actman30/iac_messagebox.pas
@@ -0,0 +1,386 @@
+unit iac_messagebox;
+
+interface
+
+implementation
+
+uses
+ editwrapper,
+ windows, messages, commctrl,
+ m_api, global, iac_global,
+ wrapper, mirutils, common, dbsettings;
+
+{$include i_cnst_message.inc}
+{$resource iac_messagebox.res}
+
+const
+ ACF_MSG_TTL = $00000001;
+ ACF_MSG_TXT = $00000002;
+
+const
+ opt_msgtitle = 'msgtitle';
+ opt_msgtext = 'msgtext';
+ opt_boxopts = 'boxopts';
+const
+ ioTitle = 'title';
+ ioText = 'text';
+ ioType = 'type';
+ ioArgVariable = 'argvariables';
+ ioVariables = 'variables';
+type
+ tMessageAction = class(tBaseAction)
+ private
+ msgtitle:pWideChar;
+ msgtext :pWideChar;
+ boxopts :uint;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Object realization -----
+
+constructor tMessageAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ msgtext :=nil;
+ msgtitle:=nil;
+ boxopts :=0;
+end;
+
+destructor tMessageAction.Destroy;
+begin
+ mFreeMem(msgtitle);
+ mFreeMem(msgtext);
+
+ inherited Destroy;
+end;
+{
+function tMessageAction.Clone:tBaseAction;
+begin
+ result:=tMessageAction.Create(0);
+ Duplicate(result);
+
+ StrDupW(tMessageAction(result).msgtext ,msgtext);
+ StrDupW(tMessageAction(result).msgtitle,msgtitle);
+ tMessageAction(result).boxopts:=boxopts;
+end;
+}
+function tMessageAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ i:integer;
+ buf:array [0..31] of WideChar;
+ tmpc:pWideChar; // LastResult value
+ tmpc1,tmpc2:pWideChar; // title/text after LastResult insertion
+ tmpcv1,tmpcv2:pWideChar; // title/text after Variables processing
+begin
+ result:=0;
+
+ if WorkData.ResultType=rtWide then
+ tmpc:=pWidechar(WorkData.LastResult)
+ else
+ begin
+ IntToStr(buf,WorkData.LastResult);
+ tmpc:=@buf;
+ end;
+ // LastResult
+ if StrPosW(msgtitle,'<last>')<>nil then
+ begin
+ mGetMem(tmpc1,8192);
+ StrCopyW(tmpc1,msgtitle);
+ StrReplaceW(tmpc1,'<last>',tmpc);
+ end
+ else
+ tmpc1:=msgtitle;
+ if StrPosW(msgtext,'<last>')<>nil then
+ begin
+ mGetMem(tmpc2,8192);
+ StrCopyW(tmpc2,msgtext);
+ StrReplaceW(tmpc2,'<last>',tmpc);
+ end
+ else
+ tmpc2:=msgtext;
+ // Variables
+ if (flags and ACF_MSG_TTL)<>0 then
+ tmpcv1:=ParseVarString(tmpc1,WorkData.Parameter,tmpc)
+ else
+ tmpcv1:=tmpc1;
+ if (flags and ACF_MSG_TXT)<>0 then
+ tmpcv2:=ParseVarString(tmpc2,WorkData.Parameter,tmpc)
+ else
+ tmpcv2:=tmpc2;
+
+ i:=MessageBoxW(0,tmpcv2,tmpcv1,boxopts);
+
+ // Keep old result just if has single OK button
+ if (boxopts and $0F)<>MB_OK then
+ begin
+ ClearResult(WorkData);
+
+ WorkData.ResultType:=rtInt;
+ WorkData.LastResult:=i;
+ end;
+
+ if tmpcv1<>tmpc1 then mFreeMem(tmpcv1);
+ if tmpcv2<>tmpc2 then mFreeMem(tmpcv2);
+ if tmpc1 <>msgtitle then mFreeMem(tmpc1);
+ if tmpc2 <>msgtext then mFreeMem(tmpc2);
+end;
+
+procedure tMessageAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc: pAnsiChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_msgtitle); msgtitle:=DBReadUnicode(0,DBBranch,section);
+ StrCopy(pc,opt_msgtext ); msgtext :=DBReadUnicode(0,DBBranch,section);
+ StrCopy(pc,opt_boxopts ); boxopts :=DBReadDword (0,DBBranch,section);
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ StrDupW(msgtitle,getAttrValue(HXML(node),ioTitle));
+ StrDupW(msgtext,getText(HXML(node)));
+ boxopts:=StrToInt(getAttrValue(HXML(node),ioType));
+
+ if StrToInt(getAttrValue(HXML(node),ioArgVariable))=1 then flags:=flags or ACF_MSG_TXT;
+ if StrToInt(getAttrValue(HXML(node),ioVariables ))=1 then flags:=flags or ACF_MSG_TTL;
+ end;
+ end;
+{
+ 2: begin
+ UTF8ToWide(GetParamSectionInt(node,ioTitle),msgtitle);
+ UTF8ToWide(GetParamSectionInt(node,ioText ),msgtext);
+ boxopts:=GetParamSectionInt(node,ioType);
+
+ if GetParamSectionInt(node,ioArgVariable)=1 then flags:=flags or ACF_MSG_TXT;
+ if GetParamSectionInt(node,ioVariables )=1 then flags:=flags or ACF_MSG_TTL;
+ end;
+}
+ end;
+end;
+
+procedure tMessageAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc: pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_msgtitle); DBWriteUnicode(0,DBBranch,section,msgtitle);
+ StrCopy(pc,opt_msgtext ); DBWriteUnicode(0,DBBranch,section,msgtext);
+ StrCopy(pc,opt_boxopts ); DBWriteDWord (0,DBBranch,section,boxopts);
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure SetMBRadioIcon(Dialog:HWND;h:THANDLE;id:dword;icon:uint_ptr);
+begin
+ SendDlgItemMessage(Dialog,id,BM_SETIMAGE,IMAGE_ICON,
+ LoadImage(h,MAKEINTRESOURCE(icon),IMAGE_ICON,16,16,0{LR_SHARED}));
+// SendDlgItemMessage(Dialog,id,BM_SETIMAGE,IMAGE_ICON,LoadIcon(0,icon));
+end;
+
+procedure SetMBRadioIcons(Dialog:HWND);
+var
+ h:THANDLE;
+begin
+ h:=LoadLibrary('user32.dll');
+// SetMBRadioIcon(IDC_MSGI_NONE,IDI_); //?
+ SetMBRadioIcon(Dialog,h,IDC_MSGI_ERROR,103{IDI_HAND});
+ SetMBRadioIcon(Dialog,h,IDC_MSGI_QUEST,102{IDI_QUESTION});
+ SetMBRadioIcon(Dialog,h,IDC_MSGI_WARN ,101{IDI_EXCLAMATION});
+ SetMBRadioIcon(Dialog,h,IDC_MSGI_INFO ,104{IDI_ASTERISK});
+ FreeLibrary(h);
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_MSG_RTL ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSG_RIGHT,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_MSGB_OK ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGB_OC ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGB_ARI,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGB_YNC,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGB_YN ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGB_RC ,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_MSGI_NONE ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGI_ERROR,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGI_QUEST,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGI_WARN ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MSGI_INFO ,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ MakeEditField(Dialog,IDC_MSG_TITLE);
+ MakeEditField(Dialog,IDC_MSG_TEXT);
+
+ SetMBRadioIcons(Dialog);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+ with tMessageAction(lParam) do
+ begin
+ SetDlgItemTextW(Dialog,IDC_MSG_TITLE,msgtitle);
+ SetDlgItemTextW(Dialog,IDC_MSG_TEXT ,msgtext);
+
+ SetEditFlags(Dialog,IDC_MSG_TITLE,EF_SCRIPT,ord((flags and ACF_MSG_TTL)<>0));
+ SetEditFlags(Dialog,IDC_MSG_TEXT ,EF_SCRIPT,ord((flags and ACF_MSG_TXT)<>0));
+
+ if (boxopts and MB_RTLREADING)<>0 then CheckDlgButton(Dialog,IDC_MSG_RTL ,BST_CHECKED);
+ if (boxopts and MB_RIGHT )<>0 then CheckDlgButton(Dialog,IDC_MSG_RIGHT,BST_CHECKED);
+
+ case boxopts and $0F of
+ MB_OKCANCEL : CheckDlgButton(Dialog,IDC_MSGB_OC ,BST_CHECKED);
+ MB_ABORTRETRYIGNORE : CheckDlgButton(Dialog,IDC_MSGB_ARI,BST_CHECKED);
+ MB_YESNOCANCEL : CheckDlgButton(Dialog,IDC_MSGB_YNC,BST_CHECKED);
+ MB_YESNO : CheckDlgButton(Dialog,IDC_MSGB_YN ,BST_CHECKED);
+ MB_RETRYCANCEL : CheckDlgButton(Dialog,IDC_MSGB_RC ,BST_CHECKED);
+// MB_CANCELTRYCONTINUE:
+ else
+ CheckDlgButton(Dialog,IDC_MSGB_OK,BST_CHECKED);
+ end;
+ case boxopts and $F0 of
+ MB_ICONERROR : CheckDlgButton(Dialog,IDC_MSGI_ERROR,BST_CHECKED);
+ MB_ICONQUESTION : CheckDlgButton(Dialog,IDC_MSGI_QUEST,BST_CHECKED);
+ MB_ICONWARNING : CheckDlgButton(Dialog,IDC_MSGI_WARN ,BST_CHECKED);
+ MB_ICONINFORMATION: CheckDlgButton(Dialog,IDC_MSGI_INFO ,BST_CHECKED);
+ else
+ CheckDlgButton(Dialog,IDC_MSGI_NONE,BST_CHECKED);
+ end;
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ SetDlgItemTextW(Dialog,IDC_MSG_TITLE,nil);
+ SetDlgItemTextW(Dialog,IDC_MSG_TEXT ,nil);
+ SetEditFlags(Dialog,IDC_MSG_TITLE,EF_ALL,0);
+ SetEditFlags(Dialog,IDC_MSG_TEXT ,EF_ALL,0);
+
+ CheckDlgButton(Dialog,IDC_MSGB_OK ,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_MSGI_NONE,BST_CHECKED);
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tMessageAction(lParam) do
+ begin
+ {mFreeMem(msgtitle); }msgtitle:=GetDlgText(Dialog,IDC_MSG_TITLE);
+ {mFreeMem(msgtext ); }msgtext :=GetDlgText(Dialog,IDC_MSG_TEXT);
+
+ if (GetEditFlags(Dialog,IDC_MSG_TITLE) and EF_SCRIPT)<>0 then flags:=flags or ACF_MSG_TTL;
+ if (GetEditFlags(Dialog,IDC_MSG_TEXT ) and EF_SCRIPT)<>0 then flags:=flags or ACF_MSG_TXT;
+
+ if IsDlgButtonChecked(Dialog,IDC_MSG_RTL )=BST_CHECKED then boxopts:=boxopts or MB_RTLREADING;
+ if IsDlgButtonChecked(Dialog,IDC_MSG_RIGHT)=BST_CHECKED then boxopts:=boxopts or MB_RIGHT;
+
+ if IsDlgButtonChecked(Dialog,IDC_MSGB_OC )=BST_CHECKED then boxopts:=boxopts or MB_OKCANCEL
+ else if IsDlgButtonChecked(Dialog,IDC_MSGB_ARI)=BST_CHECKED then boxopts:=boxopts or MB_ABORTRETRYIGNORE
+ else if IsDlgButtonChecked(Dialog,IDC_MSGB_YNC)=BST_CHECKED then boxopts:=boxopts or MB_YESNOCANCEL
+ else if IsDlgButtonChecked(Dialog,IDC_MSGB_YN )=BST_CHECKED then boxopts:=boxopts or MB_YESNO
+ else if IsDlgButtonChecked(Dialog,IDC_MSGB_RC )=BST_CHECKED then boxopts:=boxopts or MB_RETRYCANCEL
+ else{if IsDlgButtonChecked(Dialog,IDC_MSGB_OK )=BST_CHECKED then}boxopts:=boxopts or MB_OK;
+
+ if IsDlgButtonChecked(Dialog,IDC_MSGI_ERROR)=BST_CHECKED then boxopts:=boxopts or MB_ICONHAND
+ else if IsDlgButtonChecked(Dialog,IDC_MSGI_QUEST)=BST_CHECKED then boxopts:=boxopts or MB_ICONQUESTION
+ else if IsDlgButtonChecked(Dialog,IDC_MSGI_WARN )=BST_CHECKED then boxopts:=boxopts or MB_ICONWARNING
+ else if IsDlgButtonChecked(Dialog,IDC_MSGI_INFO )=BST_CHECKED then boxopts:=boxopts or MB_ICONINFORMATION
+ ;//else if IsDlgButtonChecked(Dialog,IDC_MSGI_NONE)=BST_CHECKED then ;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE,
+ BN_CLICKED: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ WM_HELP: begin
+ MessageBoxW(0,
+ TranslateW(
+ 'Text <last> replacing'#13#10+
+ 'by last result'#13#10#13#10+
+ 'Returns:'#13#10+
+ '--------'#13#10+
+ 'OK'#9'= 1'#13#10+
+ 'CANCEL'#9'= 2'#13#10+
+ 'ABORT'#9'= 3'#13#10+
+ 'RETRY'#9'= 4'#13#10+
+ 'IGNORE'#9'= 5'#13#10+
+ 'YES'#9'= 6'#13#10+
+ 'NO'#9'= 7'#13#10+
+ 'CLOSE'#9'= 8'),
+ TranslateW('MessageBox'),0);
+ result:=1;
+ end;
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tMessageAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTMESSAGEBOX',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='MessageBox';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_MESSAGE';
+ vc.Hash :=0;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_messagebox.rc b/plugins/Actman30/iac_messagebox.rc
new file mode 100644
index 0000000000..0bb2c7eedb
--- /dev/null
+++ b/plugins/Actman30/iac_messagebox.rc
@@ -0,0 +1,36 @@
+#include "i_cnst_message.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTMESSAGEBOX DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ RTEXT "Message title",-1, 2, 0, 164, 11, SS_CENTERIMAGE
+ EDITTEXT IDC_MSG_TITLE, 1, 12, 165, 12, ES_AUTOHSCROLL
+// ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+ RTEXT "Message text" ,-1, 2, 26, 164, 11, SS_CENTERIMAGE
+ EDITTEXT IDC_MSG_TEXT , 1, 38, 165, 12, ES_AUTOHSCROLL
+// ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+
+ AUTOCHECKBOX "RTL" , IDC_MSG_RTL , 1, 54, 160, 11
+ AUTOCHECKBOX "Right justifed text", IDC_MSG_RIGHT, 1, 67, 160, 11
+
+ GROUPBOX "Icons" , -1 , 0, 89, 167, 30, WS_GROUP
+ AUTORADIOBUTTON "Error" , IDC_MSGI_ERROR, 5, 98, 24, 20, BS_ICON
+ AUTORADIOBUTTON "Question", IDC_MSGI_QUEST, 31, 98, 24, 20, BS_ICON
+ AUTORADIOBUTTON "Warning" , IDC_MSGI_WARN , 57, 98, 24, 20, BS_ICON
+ AUTORADIOBUTTON "Info" , IDC_MSGI_INFO , 83, 98, 24, 20, BS_ICON
+ AUTORADIOBUTTON "None" , IDC_MSGI_NONE , 109, 98, 53, 20//, BS_ICON
+
+ GROUPBOX "Buttons" , -1, 0, 122, 167, 71, WS_GROUP
+ AUTORADIOBUTTON "OK" , IDC_MSGB_OK , 5, 131, 156, 10
+ AUTORADIOBUTTON "OK, Cancel" , IDC_MSGB_OC , 5, 141, 156, 10
+ AUTORADIOBUTTON "Abort, Retry, Ignore", IDC_MSGB_ARI, 5, 151, 156, 10
+ AUTORADIOBUTTON "Yes, No, Cancel" , IDC_MSGB_YNC, 5, 161, 156, 10
+ AUTORADIOBUTTON "Yes, No" , IDC_MSGB_YN , 5, 171, 156, 10
+ AUTORADIOBUTTON "Retry, Cancel" , IDC_MSGB_RC , 5, 181, 156, 10
+}
+
+IDI_MESSAGE ICON "ico\message.ico"
diff --git a/plugins/Actman30/iac_program.pas b/plugins/Actman30/iac_program.pas
new file mode 100644
index 0000000000..56e494b3d2
--- /dev/null
+++ b/plugins/Actman30/iac_program.pas
@@ -0,0 +1,491 @@
+unit iac_program;
+
+interface
+
+implementation
+
+uses
+ editwrapper,
+ windows, messages, commctrl,
+ global, iac_global, m_api, wrapper, syswin,
+ mirutils, common, dbsettings;
+
+{$include i_cnst_program.inc}
+{$resource iac_program.res}
+
+const
+ ACF_CURPATH = $00000001; // Current (not program) path
+ ACF_PRTHREAD = $00000002; // parallel Program
+ ACF_PRG_PRG = $00000004; // script for program path
+ ACF_PRG_ARG = $00000008; // script for program args
+
+const
+ opt_prg = 'program';
+ opt_args = 'arguments';
+ opt_time = 'time';
+ opt_show = 'show';
+const
+ ioArgs = 'args';
+ ioProgram = 'program';
+ ioCurrent = 'current';
+ ioParallel = 'parallel';
+ ioWait = 'wait';
+ ioFileVariable = 'modvariables';
+ ioArgVariable = 'argvariables';
+ ioWindow = 'window';
+ ioHidden = 'hidden';
+ ioMinimized = 'minimized';
+ ioMaximized = 'maximized';
+type
+ tProgramAction = class(tBaseAction)
+ private
+ prgname:pWideChar;
+ args :pWideChar;
+ show :dword;
+ time :dword;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+function replany(var str:pWideChar;aparam:LPARAM;alast:pWideChar):boolean;
+var
+ buf:array [0..31] of WideChar;
+ tmp:pWideChar;
+begin
+ if StrScanW(str,'<')<>nil then
+ begin
+ result:=true;
+ mGetMem(tmp,2048);
+ StrCopyW(tmp,str);
+ StrReplaceW(tmp,'<param>',IntToStr(buf,aparam));
+ StrReplaceW(tmp,'<last>' ,alast);
+
+ str:=tmp;
+ end
+ else
+ result:=false;
+end;
+
+//----- Object realization -----
+
+constructor tProgramAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ show :=0;
+ time :=0;
+ prgname:=nil;
+ args :=nil;
+end;
+
+destructor tProgramAction.Destroy;
+begin
+ mFreeMem(prgname);
+ mFreeMem(args);
+
+ inherited Destroy;
+end;
+{
+function tProgramAction.Clone:tBaseAction;
+begin
+ result:=tProgramAction.Create(0);
+ Duplicate(result);
+
+ tProgramAction(result).show :=show;
+ tProgramAction(result).time :=time;
+ StrDupW(tProgramAction(result).prgname,prgname);
+ StrDupW(tProgramAction(result).args ,args);
+end;
+}
+function tProgramAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ tmp,tmpp,lpath:PWideChar;
+ replPrg ,replArg :PWideChar;
+ replPrg1,replArg1:PWideChar;
+ pd:LPARAM;
+ vars1,vars2,prgs,argss:boolean;
+ buf:array [0..31] of WideChar;
+begin
+ result:=0;
+
+ if WorkData.ResultType=rtInt then
+ begin
+ StrDupW(pWideChar(WorkData.LastResult),IntToStr(buf,WorkData.LastResult));
+ WorkData.ResultType:=rtWide;
+ end;
+
+ replPrg:=prgname;
+ prgs :=replany(replPrg,WorkData.Parameter,pWideChar(WorkData.LastResult));
+
+ replArg:=args;
+ argss :=replany(replArg,WorkData.Parameter,pWideChar(WorkData.LastResult));
+
+ if ((flags and ACF_PRG_PRG)<>0) or
+ ((flags and ACF_PRG_ARG)<>0) then
+ begin
+ if CallService(MS_DB_CONTACT_IS,WorkData.Parameter,0)<>0 then
+ pd:=WorkData.Parameter
+ else
+ pd:=WndToContact(WaitFocusedWndChild(GetForegroundwindow){GetFocus});
+ if (pd=0) and (WorkData.Parameter<>0) then
+ pd:=WorkData.Parameter;
+ end;
+
+ if (flags and ACF_PRG_ARG)<>0 then
+ begin
+ vars2:=true;
+ tmp :=ParseVarString(replArg,pd,pWideChar(WorkData.LastResult));
+ end
+ else
+ begin
+ vars2:=false;
+ tmp :=replArg;
+ end;
+
+ if (flags and ACF_PRG_PRG)<>0 then
+ begin
+ vars1:=true;
+ tmpp :=ParseVarString(replPrg,pd,pWideChar(WorkData.LastResult));
+ end
+ else
+ begin
+ vars1:=false;
+ tmpp:=replPrg;
+ end;
+
+ if StrScanW(tmpp,'%')<>nil then
+ begin
+ mGetMem(replPrg1,8192*SizeOf(WideChar));
+ ExpandEnvironmentStringsW(tmpp,replPrg1,8191);
+ if vars1 then mFreeMem(tmpp);
+ if prgs then mFreeMem(replPrg);
+ tmpp :=replPrg1;
+ prgs :=false;
+ vars1:=true;
+ end;
+ if StrScanW(tmp,'%')<>nil then
+ begin
+ mGetMem(replArg1,8192*SizeOf(WideChar));
+ ExpandEnvironmentStringsW(tmp,replArg1,8191);
+ if vars2 then mFreeMem(tmp);
+ if argss then mFreeMem(replArg);
+ tmp :=replArg1;
+ argss:=false;
+ vars2:=true;
+ end;
+
+ if (flags and ACF_CURPATH)=0 then
+ lpath:=ExtractW(tmpp,false)
+ else
+ lpath:=nil;
+
+ if (flags and ACF_PRTHREAD)<>0 then
+ time:=0
+ else if time=0 then
+ time:=INFINITE;
+ WorkData.LastResult:=ExecuteWaitW(tmpp,tmp,lpath,show,time,@pd);
+ WorkData.ResultType:=rtInt;
+
+ if vars2 then mFreeMem(tmp);
+ if vars1 then mFreeMem(tmpp);
+
+ if prgs then mFreeMem(replPrg);
+ if argss then mFreeMem(replArg);
+
+ mFreeMem(lpath);
+end;
+
+procedure tProgramAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+ tmp:pWideChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_prg ); prgname:=DBReadUnicode(0,DBBranch,section,nil);
+ StrCopy(pc,opt_args); args :=DBReadUnicode(0,DBBranch,section,nil);
+ StrCopy(pc,opt_time); time :=DBReadDWord (0,DBBranch,section,0);
+ StrCopy(pc,opt_show); show :=DBReadDWord (0,DBBranch,section,SW_SHOW);
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ StrDupW(prgname,getText(HXML(node)));
+ StrDupW(args,getAttrValue(HXML(node),ioArgs));
+ if StrToInt(getAttrValue(HXML(node),ioCurrent))=1 then
+ flags:=flags or ACF_CURPATH;
+
+ if StrToInt(getAttrValue(HXML(node),ioParallel))=1 then
+ flags:=flags or ACF_PRTHREAD
+ else
+ time:=StrToInt(getAttrValue(HXML(node),ioWait));
+
+ if StrToInt(getAttrValue(HXML(node),ioFileVariable))=1 then
+ flags:=flags or ACF_PRG_PRG;
+
+ if StrToInt(getAttrValue(HXML(node),ioArgVariable))=1 then
+ flags:=flags or ACF_PRG_ARG;
+
+ tmp:=getAttrValue(HXML(node),ioWindow);
+ if lstrcmpiw(tmp,ioHidden )=0 then show:=SW_HIDE
+ else if lstrcmpiw(tmp,ioMinimized)=0 then show:=SW_SHOWMINIMIZED
+ else if lstrcmpiw(tmp,ioMaximized)=0 then show:=SW_SHOWMAXIMIZED
+ else show:=SW_SHOWNORMAL;
+ end;
+ end;
+{
+ 2: begin
+ UTF8ToWide(GetParamSectionStr(node,ioProgram),prgname);
+ UTF8ToWide(GetParamSectionStr(node,ioArgs ),args);
+ if GetParamSectionInt(node,ioCurrent)=1 then
+ flags:=flags or ACF_CURPATH;
+
+ if GetParamSectionInt(node,ioParallel)=1 then
+ flags:=flags or ACF_PRTHREAD
+ else
+ time:=GetParamSectionInt(node,ioWait);
+
+ if GetParamSectionInt(node,ioFileVariable)=1 then
+ flags:=flags or ACF_PRG_PRG;
+
+ if GetParamSectionInt(node,ioArgVariable)=1 then
+ flags:=flags or ACF_PRG_ARG;
+
+ pc:=GetParamSectionStr(node,ioWindow);
+ if lstrcmpi(pc,ioHidden )=0 then show:=SW_HIDE
+ else if lstrcmpi(pc,ioMinimized)=0 then show:=SW_SHOWMINIMIZED
+ else if lstrcmpi(pc,ioMaximized)=0 then show:=SW_SHOWMAXIMIZED
+ else show:=SW_SHOWNORMAL;
+ end;
+}
+ end;
+end;
+
+procedure tProgramAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_prg ); DBWriteUnicode(0,DBBranch,section,prgname);
+ StrCopy(pc,opt_args); DBWriteUnicode(0,DBBranch,section,args);
+ StrCopy(pc,opt_time); DBWriteDWord (0,DBBranch,section,time);
+ StrCopy(pc,opt_show); DBWriteDWord (0,DBBranch,section,show);
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure MakeFileEncList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+{
+ InsertString(wnd,0,'Ansi');
+ InsertString(wnd,1,'UTF8');
+ InsertString(wnd,2,'UTF8+sign');
+ InsertString(wnd,3,'UTF16');
+ InsertString(wnd,4,'UTF16+sign');
+}
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_FLAG_NORMAL,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_HIDDEN,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_MINIMIZE,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_MAXIMIZE,BST_UNCHECKED);
+
+ CheckDlgButton(Dialog,IDC_FLAG_CURPATH,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_CONTINUE,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_PARALLEL,BST_UNCHECKED);
+end;
+
+procedure FillFileName(Dialog:HWND;idc:integer);
+var
+ pw,ppw:pWideChar;
+begin
+ mGetMem(pw,1024*SizeOf(WideChar));
+ ppw:=GetDlgText(Dialog,idc);
+ if ShowDlgW(pw,ppw) then
+ begin
+ SetDlgItemTextW(Dialog,idc,pw);
+ SetEditFlags(Dialog,idc,EF_SCRIPT,0);
+ end;
+ mFreeMem(ppw);
+ mFreeMem(pw);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ MakeEditField(Dialog,IDC_EDIT_PRGPATH);
+ MakeEditField(Dialog,IDC_EDIT_PRGARGS);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ with tProgramAction(lParam) do
+ begin
+ SetDlgItemTextW(Dialog,IDC_EDIT_PRGPATH ,prgname);
+ SetDlgItemTextW(Dialog,IDC_EDIT_PRGARGS ,args);
+
+ SetEditFlags(Dialog,IDC_EDIT_PRGPATH,EF_SCRIPT,ord((flags and ACF_PRG_PRG)<>0));
+ SetEditFlags(Dialog,IDC_EDIT_PRGARGS,EF_SCRIPT,ord((flags and ACF_PRG_ARG)<>0));
+
+ SetDlgItemInt(Dialog,IDC_EDIT_PROCTIME,time,false);
+ case show of
+ SW_HIDE : CheckDlgButton(Dialog,IDC_FLAG_HIDDEN,BST_CHECKED);
+ SW_SHOWMINIMIZED: CheckDlgButton(Dialog,IDC_FLAG_MINIMIZE,BST_CHECKED);
+ SW_SHOWMAXIMIZED: CheckDlgButton(Dialog,IDC_FLAG_MAXIMIZE,BST_CHECKED);
+ else
+ {SW_SHOWNORMAL :} CheckDlgButton(Dialog,IDC_FLAG_NORMAL,BST_CHECKED);
+ end;
+ if (flags and ACF_CURPATH)<>0 then
+ CheckDlgButton(Dialog,IDC_FLAG_CURPATH,BST_CHECKED);
+ if (flags and ACF_PRTHREAD)<>0 then
+ CheckDlgButton(Dialog,IDC_FLAG_PARALLEL,BST_CHECKED)
+ else
+ CheckDlgButton(Dialog,IDC_FLAG_CONTINUE,BST_CHECKED);
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ SetDlgItemTextW(Dialog,IDC_EDIT_PRGPATH,nil);
+ SetDlgItemTextW(Dialog,IDC_EDIT_PRGARGS,nil);
+ SetEditFlags(Dialog,IDC_EDIT_PRGPATH,EF_ALL,0);
+ SetEditFlags(Dialog,IDC_EDIT_PRGARGS,EF_ALL,0);
+
+ CheckDlgButton(Dialog,IDC_FLAG_PARALLEL,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_NORMAL ,BST_CHECKED);
+ SetDlgItemInt(Dialog,IDC_EDIT_PROCTIME,0,false);
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tProgramAction(lParam) do
+ begin
+ {mFreeMem(prgname); }prgname:=GetDlgText(Dialog,IDC_EDIT_PRGPATH);
+ {mFreeMem(args ); }args :=GetDlgText(Dialog,IDC_EDIT_PRGARGS);
+{
+ p:=GetDlgText(IDC_EDIT_PRGPATH);
+ if p<>nil then
+ begin
+ CallService(MS_UTILS_PATHTORELATIVE,dword(p),dword(@buf));
+ StrDupW(prgname,@buf);
+ mFreeMem(p);
+ end;
+}
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_PARALLEL)=BST_CHECKED then
+ flags:=flags or ACF_PRTHREAD;
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_CURPATH)=BST_CHECKED then
+ flags:=flags or ACF_CURPATH;
+
+ time:=GetDlgItemInt(Dialog,IDC_EDIT_PROCTIME,pbool(nil)^,false);
+
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_MINIMIZE)=BST_CHECKED then
+ show:=SW_SHOWMINIMIZED
+ else if IsDlgButtonChecked(Dialog,IDC_FLAG_MAXIMIZE)=BST_CHECKED then
+ show:=SW_SHOWMAXIMIZED
+ else if IsDlgButtonChecked(Dialog,IDC_FLAG_HIDDEN)=BST_CHECKED then
+ show:=SW_HIDE
+ else //if IsDlgButtonChecked(Dialog,IDC_FLAG_NORMAL)=BST_CHECKED then
+ show:=SW_SHOWNORMAL;
+
+ if (GetEditFlags(Dialog,IDC_EDIT_PRGPATH) and EF_SCRIPT)<>0 then flags:=flags or ACF_PRG_PRG;
+ if (GetEditFlags(Dialog,IDC_EDIT_PRGARGS) and EF_SCRIPT)<>0 then flags:=flags or ACF_PRG_ARG;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_PROGRAM: begin
+ FillFileName(Dialog,IDC_EDIT_PRGPATH);
+ end;
+ end;
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_HELP: begin
+ MessageBoxW(0,
+ TranslateW('Text <last> replacing'#13#10+
+ 'by last result'#13#10#13#10+
+ 'Text <param> replacing'#13#10+
+ 'by parameter'),
+ TranslateW('Text'),0);
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tProgramAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTPROGRAM',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Program';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_PROGRAM';
+ vc.Hash :=0;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_program.rc b/plugins/Actman30/iac_program.rc
new file mode 100644
index 0000000000..0460c5c9ac
--- /dev/null
+++ b/plugins/Actman30/iac_program.rc
@@ -0,0 +1,31 @@
+#include "i_cnst_program.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTPROGRAM DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ GROUPBOX "Process options" , -1, 1, 4, 166, 46, WS_GROUP
+ AUTORADIOBUTTON "Parallel" , IDC_FLAG_PARALLEL, 4, 13, 161, 11
+ AUTORADIOBUTTON "Continued" , IDC_FLAG_CONTINUE, 4, 24, 161, 11
+ EDITTEXT IDC_EDIT_PROCTIME, 4, 36, 31, 11, ES_RIGHT | ES_NUMBER
+ LTEXT "Process time, ms", -1, 37, 36, 128, 11, SS_CENTERIMAGE
+
+ AUTOCHECKBOX "Current path" , IDC_FLAG_CURPATH, 4, 52, 161, 11
+
+ GROUPBOX "Window option" , -1, 1, 63, 166, 55, WS_GROUP
+ AUTORADIOBUTTON "Start normal" , IDC_FLAG_NORMAL , 4, 72, 162, 11
+ AUTORADIOBUTTON "Start hidden" , IDC_FLAG_HIDDEN , 4, 83, 162, 11
+ AUTORADIOBUTTON "Start minimized", IDC_FLAG_MINIMIZE, 4, 94, 162, 11
+ AUTORADIOBUTTON "Start maximized", IDC_FLAG_MAXIMIZE, 4, 105, 162, 11
+
+ RTEXT "Program path", -1, 1, 135, 160, 8
+ EDITTEXT IDC_EDIT_PRGPATH, 1, 144, 148, 12, ES_AUTOHSCROLL
+ PUSHBUTTON "..." , IDC_PROGRAM , 151, 144, 16, 12
+ RTEXT "Program args", -1, 1, 159, 160, 8
+ EDITTEXT IDC_EDIT_PRGARGS, 1, 168, 166, 12, ES_AUTOHSCROLL
+}
+
+IDI_PROGRAM ICON "ico\program.ico"
diff --git a/plugins/Actman30/iac_service.pas b/plugins/Actman30/iac_service.pas
new file mode 100644
index 0000000000..67a565c477
--- /dev/null
+++ b/plugins/Actman30/iac_service.pas
@@ -0,0 +1,1023 @@
+unit iac_service;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ global, iac_global,
+ m_api,
+ sedit,strans,mApiCardM,
+ mirutils,dbsettings, editwrapper,
+ syswin,wrapper,common;
+
+{$include i_cnst_service.inc}
+{$resource iac_service.res}
+
+const
+ ACF_PARNUM = $00000001; // Param is number
+ ACF_UNICODE = $00000002; // Param is Unicode string
+ ACF_CURRENT = $00000004; // Param is ignored, used current user handle
+ // from current message window
+ ACF_RESULT = $00000008; // Param is previous action result
+ ACF_PARAM = $00000010; // Param is Call parameter
+ ACF_STRUCT = $00000020;
+ ACF_PARTYPE = ACF_PARNUM or ACF_UNICODE or
+ ACF_CURRENT or ACF_RESULT or
+ ACF_PARAM or ACF_STRUCT;
+
+ ACF_RSTRING = $00010000; // Service result is string
+ ACF_RUNICODE = $00020000; // Service result is Widestring
+ ACF_RSTRUCT = $00040000; // Service result in structure
+ ACF_RFREEMEM = $00080000; // Need to free memory
+
+ ACF_SCRIPT_PARAM = $00001000;
+ ACF_SCRIPT_SERVICE = $00002000;
+ // dummy
+ ACF_STRING = 0;
+
+const
+ opt_service = 'service';
+ opt_flags2 = 'flags2';
+ opt_wparam = 'wparam';
+ opt_lparam = 'lparam';
+const
+ ioService = 'service';
+ ioType = 'type';
+ ioResult = 'result';
+ ioCurrent = 'current';
+ ioParam = 'param';
+ ioStruct = 'struct';
+ ioValue = 'value';
+ ioNumber = 'number';
+ ioUnicode = 'unicode';
+ ioVariables = 'variables';
+ ioWParam = 'WPARAM';
+ ioLParam = 'LPARAM';
+ ioOutput = 'OUTPUT';
+ ioFree = 'free';
+ ioAnsi = 'ansi';
+ ioInt = 'int';
+
+type
+ tServiceAction = class(tBaseAction)
+ private
+ service:PAnsiChar;
+ wparam :pWideChar;
+ lparam :pWideChar;
+ flags2 :dword;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tServiceAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+end;
+
+procedure ClearParam(flags:dword; var param);
+begin
+ if (flags and (ACF_CURRENT or ACF_RESULT or ACF_PARAM))=0 then
+ mFreeMem(pointer(param));
+end;
+
+destructor tServiceAction.Destroy;
+begin
+ mFreeMem(service);
+ ClearParam(flags ,wparam);
+ ClearParam(flags2,lparam);
+
+ inherited Destroy;
+end;
+{
+function tServiceAction.Clone:tBaseAction;
+begin
+ result:=tServiceAction.Create(0);
+ Duplicate(result);
+
+ tServiceAction(result).flags2 :=flags2;
+ StrDup(tServiceAction(result).service,service);
+
+ if (flags and (ACF_PARNUM or ACF_RESULT or ACF_PARAM))=0 then
+ StrDup(pAnsiChar(tServiceAction(result).wparam),pAnsiChar(wparam))
+ else if ((flags and ACF_PARNUM)<>0) and ((flags and ACF_SCRIPT_PARAM)<>0) then
+ StrDup(pAnsiChar(tServiceAction(result).wparam),pAnsiChar(wparam))
+ else
+ tServiceAction(result).wparam:=wparam;
+
+ if (flags2 and (ACF_PARNUM or ACF_RESULT or ACF_PARAM))=0 then
+ StrDup(pAnsiChar(tServiceAction(result).lparam),pAnsiChar(lparam))
+ else if ((flags2 and ACF_PARNUM)<>0) and ((flags and ACF_SCRIPT_PARAM)<>0) then
+ StrDup(pAnsiChar(tServiceAction(result).lparam),pAnsiChar(lparam))
+ else
+ tServiceAction(result).lparam:=lparam;
+end;
+}
+procedure PreProcess(flags:dword;var l_param:LPARAM;const WorkData:tWorkData);
+var
+ tmp1:pWideChar;
+begin
+ with WorkData do
+ begin
+ if (flags and ACF_STRUCT)<>0 then
+ begin
+ l_param:=uint_ptr(MakeStructure(pAnsiChar(l_param),Parameter,LastResult,ResultType))
+ end
+ else if (flags and ACF_PARAM)<>0 then
+ begin
+ l_param:=Parameter;
+ end
+ else if (flags and ACF_RESULT)<>0 then
+ begin
+ l_param:=LastResult;
+ end
+ else if (flags and ACF_CURRENT)<>0 then
+ begin
+ l_param:=WndToContact(WaitFocusedWndChild(GetForegroundwindow){GetFocus});
+ end
+ else
+ begin
+ if (flags and ACF_SCRIPT_PARAM)<>0 then
+ l_param:=uint_ptr(ParseVarString(pWideChar(l_param),Parameter));
+
+ tmp1:=pWideChar(l_param);
+ if (flags and ACF_PARNUM)=0 then
+ begin
+ if (flags and ACF_UNICODE)=0 then
+ WideToAnsi(tmp1,pAnsiChar(l_param),MirandaCP)
+ else
+ StrDupW(pWideChar(l_param),tmp1);
+ end
+ else
+ l_param:=NumToInt(tmp1);
+
+ if (flags and ACF_SCRIPT_PARAM)<>0 then
+ mFreeMem(tmp1);
+ end;
+ end;
+end;
+
+procedure PostProcess(flags:dword;var l_param:LPARAM; var WorkData:tWorkData);
+var
+ code:integer;
+ len:integer;
+ pc:pAnsiChar;
+begin
+ if (flags and ACF_STRUCT)<>0 then
+ begin
+ with WorkData do
+ begin
+ LastResult:=GetStructureResult(l_param,@code,@len);
+ case code of
+{
+ SST_LAST: begin
+ result:=LastResult;
+ end;
+}
+ SST_PARAM: begin //??
+ LastResult:=Parameter;
+ ResultType:=rtInt;
+ end;
+ SST_BYTE,SST_WORD,SST_DWORD,
+ SST_QWORD,SST_NATIVE: begin
+ ResultType:=rtInt;
+ end;
+ SST_BARR: begin
+ StrDup(pAnsiChar(pc),pAnsiChar(LastResult),len);
+ AnsiToWide(pAnsiChar(pc),PWideChar(LastResult),MirandaCP);
+ mFreeMem(pAnsiChar(pc));
+ ResultType:=rtWide;
+ end;
+ SST_WARR: begin
+ StrDupW(pWideChar(LastResult),pWideChar(LastResult),len);
+ ResultType:=rtWide;
+ end;
+ SST_BPTR: begin
+ AnsiToWide(pAnsiChar(LastResult),pWideChar(LastResult),MirandaCP);
+ ResultType:=rtWide;
+ end;
+ SST_WPTR: begin
+ StrDupW(pWideChar(LastResult),pWideChar(LastResult));
+ ResultType:=rtWide;
+ end;
+ end;
+ FreeStructure(l_param);
+ l_param:=0;
+ end
+ end;
+end;
+
+function tServiceAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ buf:array [0..255] of AnsiChar;
+ lservice:pAnsiChar;
+ lwparam,llparam:TLPARAM;
+ res:int_ptr;
+begin
+ result:=0;
+
+ lservice:=service;
+ lwparam :=TLPARAM(wparam);
+ llparam :=TLPARAM(lparam);
+ // Service name processing
+ if (flags and ACF_SCRIPT_SERVICE)<>0 then
+ lservice:=ParseVarString(lservice,WorkData.Parameter);
+
+ StrCopy(buf,lservice);
+ if StrPos(lservice,protostr)<>nil then
+ if CallService(MS_DB_CONTACT_IS,WorkData.Parameter,0)=0 then
+ begin
+ if (flags and ACF_SCRIPT_SERVICE)<>0 then
+ mFreeMem(lservice);
+ exit;
+ end
+ else
+ StrReplace(buf,protostr,GetContactProtoAcc(WorkData.Parameter));
+
+ if ServiceExists(buf)<>0 then
+ begin
+
+ PreProcess(flags ,lwparam,WorkData);
+ PreProcess(flags2,llparam,WorkData);
+
+ res:=CallServiceSync(buf,lwparam,llparam);
+ ClearResult(WorkData);
+
+ // result type processing
+ if (flags and ACF_RSTRING)<>0 then
+ begin
+//!! delete old or not?
+ if (flags and ACF_RUNICODE)=0 then
+ AnsiToWide(pAnsiChar(res),pWideChar(WorkData.LastResult),MirandaCP)
+ else
+ StrDupW(pWideChar(WorkData.LastResult),pWideChar(res));
+ WorkData.ResultType:=rtWide;
+
+ if (flags and ACF_RFREEMEM)<>0 then
+ mFreeMem(pAnsiChar(res)); //?? Miranda MM??
+ end
+ else if (flags and ACF_RSTRUCT)=0 then
+ WorkData.ResultType:=rtInt
+ else if (flags and ACF_RSTRUCT)<>0 then
+ begin
+ PostProcess(flags ,lwparam,WorkData);
+ PostProcess(flags2,llparam,WorkData);
+ end;
+
+ // free string (ansi+unicode) parameters
+ if ((flags and ACF_PARTYPE)=ACF_STRING) or
+ ((flags and ACF_PARTYPE)=ACF_UNICODE) then
+ mFreeMem(pointer(lwparam));
+ if ((flags2 and ACF_PARTYPE)=ACF_STRING) or
+ ((flags2 and ACF_PARTYPE)=ACF_UNICODE) then
+ mFreeMem(pointer(llparam));
+ end;
+ if (flags and ACF_SCRIPT_SERVICE)<>0 then
+ mFreeMem(lservice);
+end;
+
+procedure LoadParam(section:PAnsiChar;flags:dword; var param:pointer);
+begin
+ if (flags and (ACF_CURRENT or ACF_RESULT or ACF_PARAM))=0 then
+ begin
+ if (flags and ACF_STRUCT)<>0 then
+ param:=DBReadUTF8(0,DBBranch,section,nil)
+ else
+ param:=DBReadUnicode(0,DBBranch,section,nil);
+ end;
+end;
+
+function ReadParam(act:HXML; var param:pWideChar;isvar:boolean):dword;
+var
+ tmp:pWideChar;
+begin
+ result:=0;
+ if act=0 then
+ exit;
+ with xmlparser do
+ begin
+ tmp:=getAttrValue(act,ioType);
+ if lstrcmpiw(tmp,ioCurrent)=0 then result:=result or ACF_CURRENT
+ else if lstrcmpiw(tmp,ioResult )=0 then result:=result or ACF_RESULT
+ else if lstrcmpiw(tmp,ioParam )=0 then result:=result or ACF_PARAM
+ else if lstrcmpiw(tmp,ioStruct )=0 then
+ begin
+ result:=result or ACF_STRUCT;
+//!!!! param:=ReadStruct(act);
+ end
+ else
+ begin
+ StrDupW(pWideChar(param),getAttrValue(act,ioValue));
+
+ if lstrcmpiw(tmp,ioNumber )=0 then result:=result or ACF_PARNUM
+ else if lstrcmpiw(tmp,ioUnicode)=0 then result:=result or ACF_UNICODE;
+// else if lstrcmpiw(tmp,ioAnsi)=0 then;
+ end;
+ end;
+end;
+{
+function ReadParamINI(node:pointer;prefix:pAnsiChar;var param:pWideChar;isvar:boolean):dword;
+var
+ pc,pc1:pAnsiChar;
+ buf:array [0..63] of AnsiChar;
+begin
+ result:=0;
+ pc1:=StrCopyE(buf,prefix);
+ pc:=GetParamSectionStr(node,StrCopy(pc1,ioType));
+ if lstrcmpi(pc,ioCurrent)=0 then result:=result or ACF_CURRENT
+ else if lstrcmpi(pc,ioResult )=0 then result:=result or ACF_RESULT
+ else if lstrcmpi(pc,ioParam )=0 then result:=result or ACF_PARAM
+ else if lstrcmpi(pc,ioStruct )=0 then
+ begin
+ result:=result or ACF_STRUCT;
+//!!!! param:=ReadStruct(act);
+ end
+ else
+ begin
+ UTF8ToWide(GetParamSectionInt(node,StrCopy(pc1,ioValue)),param);
+
+ if lstrcmpi(pc,ioNumber )=0 then result:=result or ACF_PARNUM
+ else if lstrcmpi(pc,ioUnicode)=0 then result:=result or ACF_UNICODE;
+// else if lstrcmpi(pc,ioAnsi)=0 then;
+ end;
+end;
+}
+procedure tServiceAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+ sub:HXML;
+ tmp:pWideChar;
+begin
+ inherited Load(node,fmt);
+
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+
+ StrCopy(pc,opt_service); service:=DBReadString(0,DBBranch,section,nil);
+ StrCopy(pc,opt_flags2 ); flags2 :=DBReadDword (0,DBBranch,section);
+
+ StrCopy(pc,opt_wparam); LoadParam(section,flags ,pointer(wparam));
+ StrCopy(pc,opt_lparam); LoadParam(section,flags2,pointer(lparam));
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ FastWideToAnsi(getAttrValue(HXML(node),ioService),service);
+//!!!! StrDupW(service,getAttrValue(HXML(node),ioService));
+ if StrToInt(getAttrValue(HXML(node),ioVariables))=1 then
+ flags:=flags or ACF_SCRIPT_SERVICE;
+
+ sub:=getNthChild(HXML(node),ioWParam,0);
+ if StrToInt(getAttrValue(sub,ioVariables))=1 then
+ flags:=flags or ACF_SCRIPT_PARAM;
+ flags:=flags or ReadParam(sub,wparam,(flags and ACF_SCRIPT_PARAM)<>0);
+
+ sub:=getNthChild(HXML(node),ioLParam,0);
+ if StrToInt(getAttrValue(sub,ioVariables))=1 then
+ flags2:=flags2 or ACF_SCRIPT_PARAM;
+ flags2:=flags2 or ReadParam(sub,lparam,(flags2 and ACF_SCRIPT_PARAM)<>0);
+
+ sub:=getNthChild(HXML(node),ioOutput,0);
+ if StrToInt(getAttrValue(sub,ioFree))=1 then flags:=flags or ACF_RFREEMEM;
+
+ tmp:=getAttrValue(sub,ioType);
+ if lstrcmpiw(tmp,ioUnicode)=0 then flags:=flags or ACF_RUNICODE
+ else if lstrcmpiw(tmp,ioAnsi )=0 then flags:=flags or ACF_RSTRING
+ else if lstrcmpiw(tmp,ioStruct )=0 then flags:=flags or ACF_RSTRUCT
+ else if lstrcmpiw(tmp,ioInt )=0 then ;
+ end;
+ end;
+{
+ 2: begin
+ StrDup(service,GetParamSectionStr(node,ioService));
+//!!!! UTF8ToWide(GetParamSectionStr(node,ioService),service);
+ if GetParamSectionInt(node,ioVariables)=1 then
+ flags:=flags or ACF_SCRIPT_SERVICE;
+
+ if GetParamSectionInt(node,ioWParam+'.'+ioVariables))=1 then
+ flags:=flags or ACF_SCRIPT_PARAM;
+ flags:=flags or ReadParamINI(node,ioWParam+'.',wparam,(flags and ACF_SCRIPT_PARAM)<>0);
+
+ if GetParamSectionInt(node,ioLParam+'.'+ioVariables))=1 then
+ flags2:=flags2 or ACF_SCRIPT_PARAM;
+ flags2:=flags2 or ReadParamINI(node,ioLParam+'.',lparam,(flags2 and ACF_SCRIPT_PARAM)<>0);
+
+ if GetParamSectionInt(node,ioFree)=1 then flags:=flags or ACF_RFREEMEM;
+
+ pc:=GetParamSectionStr(node,ioType);
+ if lstrcmpi(pñ,ioUnicode)=0 then flags:=flags or ACF_RUNICODE
+ else if lstrcmpi(pñ,ioAnsi )=0 then flags:=flags or ACF_RSTRING
+ else if lstrcmpi(pñ,ioStruct )=0 then flags:=flags or ACF_RSTRUCT
+// else if lstrcmpi(pñ,ioInt )=0 then ;
+ end;
+}
+ end;
+end;
+
+procedure SaveParam(section:PAnsiChar;flags:dword; param:pointer);
+begin
+ if (flags and (ACF_CURRENT or ACF_RESULT or ACF_PARAM))=0 then
+ begin
+ if pointer(param)<>nil then
+ begin
+ if (flags and ACF_STRUCT)<>0 then
+ DBWriteUTF8(0,DBBranch,section,param)
+ else
+ DBWriteUnicode(0,DBBranch,section,param);
+ end;
+ end;
+end;
+
+procedure tServiceAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+
+ StrCopy(pc,opt_service); DBWriteString(0,DBBranch,section,service);
+ StrCopy(pc,opt_flags2 ); DBWriteDWord (0,DBBranch,section,flags2);
+
+ StrCopy(pc,opt_wparam); SaveParam(section,flags ,pointer(wparam));
+ StrCopy(pc,opt_lparam); SaveParam(section,flags2,pointer(lparam));
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+const
+ ptNumber = 0;
+ ptString = 1;
+ ptUnicode = 2;
+ ptCurrent = 3;
+ ptResult = 4;
+ ptParam = 5;
+ ptStruct = 6;
+const
+ sresInt = 0;
+ sresString = 1;
+ sresStruct = 2;
+
+procedure MakeResultTypeList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ InsertString(wnd,sresInt ,'Integer');
+ InsertString(wnd,sresString,'String');
+ InsertString(wnd,sresStruct,'Structure');
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure MakeParamTypeList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ InsertString(wnd,ptNumber ,'number value');
+ InsertString(wnd,ptString ,'ANSI string');
+ InsertString(wnd,ptUnicode,'Unicode string');
+ InsertString(wnd,ptCurrent,'current contact');
+ InsertString(wnd,ptResult ,'last result');
+ InsertString(wnd,ptParam ,'parameter');
+ InsertString(wnd,ptStruct ,'structure');
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+var
+ ApiCard:tmApiCard;
+
+function FixParam(Dialog:HWND;buf:PAnsiChar;flag:integer):integer;
+begin
+ if StrCmp(buf,Translate('hContact' ))=0 then result:=ptCurrent
+ else if StrCmp(buf,Translate('parameter' ))=0 then result:=ptParam
+ else if StrCmp(buf,Translate('result' ))=0 then result:=ptResult
+ else if StrCmp(buf,Translate('structure' ))=0 then result:=ptStruct
+ else if StrCmp(buf,Translate('Unicode text'))=0 then result:=ptUnicode
+ else
+ begin
+ if (buf[0] in ['0'..'9']) or ((buf[0]='-') and (buf[1] in ['0'..'9'])) or
+ ((buf[0]='$') and (buf[1] in sHexNum)) or
+ ((buf[0]='0') and (buf[1]='x') and (buf[2] in sHexNum)) then
+ result:=ptNumber
+ else
+ result:=ptString;
+ end;
+
+ CB_SelectData(Dialog,flag,result);
+// SendDlgItemMessage(Dialog,flag,CB_SETCURSEL,result,0);
+ SendMessage(Dialog,WM_COMMAND,(CBN_SELCHANGE shl 16) or flag,GetDlgItem(Dialog,flag));
+end;
+
+procedure ReloadService(Dialog:HWND;setvalue:boolean);
+var
+ pc:pAnsiChar;
+ buf,buf1:array [0..127] of AnsiChar;
+ wnd:hwnd;
+ i:integer;
+ struct:pAnsiChar;
+// bufw:array [0..MaxDescrLen] of WideChar;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_EDIT_SERVICE);
+ SendMessageA(wnd,CB_GETLBTEXT,SendMessage(wnd,CB_GETCURSEL,0,0),tlparam(@buf));
+ ApiCard.Service:=@buf;
+
+ pc:=ApiCard.FillParams(GetDlgItem(Dialog,IDC_EDIT_WPAR),true);
+ if pc<>nil then
+ begin
+ if GetDlgItemTextA(Dialog,IDC_EDIT_WPAR,buf1,SizeOf(buf1))>0 then
+ case FixParam(Dialog,@buf1,IDC_FLAG_WPAR) of
+ ptStruct: begin
+ if setvalue then
+ begin
+ struct:=pAnsiChar(SetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA,
+ long_ptr(StrDup(struct,StrScan(pc,'|')+1))));
+ mFreeMem(struct);
+ end;
+
+{ struct:=pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA));
+ mFreeMem(struct);
+ StrDup(struct,StrScan(pc,'|')+1);
+ SetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA,long_ptr(struct));
+// AnsiToWide(StrScan(pc,'|')+1,wstruct,MirandaCP);
+}
+ end;
+ end;
+ mFreeMem(pc);
+ end;
+
+ pc:=ApiCard.FillParams(GetDlgItem(Dialog,IDC_EDIT_LPAR),false);
+ if pc<>nil then
+ begin
+ if GetDlgItemTextA(Dialog,IDC_EDIT_LPAR,buf1,SizeOf(buf1))>0 then
+ case FixParam(Dialog,@buf1,IDC_FLAG_LPAR) of
+ ptStruct: begin
+ if setvalue then
+ begin
+ struct:=pAnsiChar(SetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA,
+ long_ptr(StrDup(struct,StrScan(pc,'|')+1))));
+ mFreeMem(struct);
+ end;
+{
+ struct:=pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA));
+ mFreeMem(struct);
+ StrDup(struct,StrScan(pc,'|')+1);
+ SetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA,long_ptr(struct));
+// AnsiToWide(StrScan(pc,'|')+1,lstruct,MirandaCP);
+}
+ end;
+ end;
+ mFreeMem(pc);
+ end;
+
+ pc:=ApiCard.ResultType;
+ i:=sresInt;
+ if pc<>nil then
+ begin
+ if lstrcmpia(pc,'struct')=0 then i:=sresStruct
+ else if lstrcmpia(pc,'str')=0 then
+ begin
+ i:=sresString;
+ CheckDlgButton(Dialog,IDC_RES_UNICODE,BST_UNCHECKED);
+ end
+ else if lstrcmpia(pc,'wide')=0 then
+ begin
+ i:=sresString;
+ CheckDlgButton(Dialog,IDC_RES_UNICODE,BST_CHECKED);
+ end;
+ mFreeMem(pc);
+ end;
+ CB_SelectData(Dialog,IDC_SRV_RESULT,i);
+// ApiCard.Show;
+end;
+
+// true - need to show structure
+function SetParam(Dialog:HWND; aflags:dword; id:integer; aparam:pWideChar):integer;
+var
+ wnd:HWND;
+begin
+ wnd:=GetDlgItem(Dialog,id);
+ if (aflags and ACF_PARAM)<>0 then
+ begin
+ EnableWindow(wnd,false);
+ result:=ptParam;
+ end
+ else if (aflags and ACF_RESULT)<>0 then
+ begin
+ EnableWindow(wnd,false);
+ result:=ptResult;
+ end
+ else if (aflags and ACF_CURRENT)<>0 then
+ begin
+ EnableWindow(wnd,false);
+ result:=ptCurrent;
+ end
+ else if (aflags and ACF_PARNUM)<>0 then
+ begin
+ result:=ptNumber;
+ SetDlgItemTextW(Dialog,id,aparam);
+ end
+ else if (aflags and ACF_STRUCT)<>0 then
+ begin
+ result:=ptStruct;
+ end
+ else if (aflags and ACF_UNICODE)<>0 then
+ begin
+ result:=ptUnicode;
+ SetDlgItemTextW(Dialog,id,aparam);
+ end
+ else
+ begin
+ result:=ptString;
+ SetDlgItemTextW(Dialog,id,aparam);
+ end;
+ SetEditFlags(wnd,EF_SCRIPT,ord((aflags and ACF_SCRIPT_PARAM)<>0));
+end;
+
+procedure ClearFields(Dialog:HWND);
+var
+ wnd:HWND;
+begin
+ ShowWindow(GetDlgItem(Dialog,IDC_WSTRUCT),SW_HIDE);
+ wnd:=GetDlgItem(Dialog,IDC_EDIT_WPAR);
+ ShowEditField (wnd,SW_SHOW);
+ EnableEditField(wnd,true);
+ SendMessage (wnd,CB_RESETCONTENT,0,0);
+//?? SetDlgItemTextW(Dialog,IDC_EDIT_WPAR,nil);
+ CB_SelectData(GetDlgItem(Dialog,IDC_FLAG_WPAR),ptNumber);
+ SetEditFlags(wnd,EF_ALL,0);
+
+ ShowWindow (GetDlgItem(Dialog,IDC_LSTRUCT),SW_HIDE);
+ wnd:=GetDlgItem(Dialog,IDC_EDIT_LPAR);
+ ShowEditField (wnd,SW_SHOW);
+ EnableEditField(wnd,true);
+ SendMessage (wnd,CB_RESETCONTENT,0,0);
+//?? SetDlgItemTextW(Dialog,IDC_EDIT_LPAR,nil);
+ CB_SelectData(GetDlgItem(Dialog,IDC_FLAG_LPAR),ptNumber);
+ SetEditFlags(wnd,EF_ALL,0);
+
+ ShowWindow(GetDlgItem(Dialog,IDC_RES_FREEMEM),SW_HIDE);
+ ShowWindow(GetDlgItem(Dialog,IDC_RES_UNICODE),SW_HIDE);
+ CheckDlgButton(Dialog,IDC_RES_FREEMEM,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_RES_UNICODE,BST_UNCHECKED);
+
+ CB_SelectData(Dialog,IDC_SRV_RESULT,sresInt);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+var
+ i:integer;
+ pc,pc1:pAnsiChar;
+ wnd,wnd1:HWND;
+ pcw:PWideChar;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_DESTROY: begin
+ ApiCard.Free;
+ pc:=pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA));
+ mFreeMem(pc);
+ pc:=pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA));
+ mFreeMem(pc);
+ end;
+
+ WM_INITDIALOG: begin
+ MakeResultTypeList(GetDlgItem(Dialog,IDC_SRV_RESULT));
+ MakeParamTypeList(GetDlgItem(Dialog,IDC_FLAG_WPAR));
+ MakeParamTypeList(GetDlgItem(Dialog,IDC_FLAG_LPAR));
+
+ TranslateDialogDefault(Dialog);
+
+//??
+ MakeEditField(Dialog,IDC_EDIT_SERVICE);
+ MakeEditField(Dialog,IDC_EDIT_WPAR);
+ MakeEditField(Dialog,IDC_EDIT_LPAR);
+
+ ApiCard:=CreateServiceCard(Dialog);
+ ApiCard.FillList(GetDlgItem(Dialog,IDC_EDIT_SERVICE),
+ DBReadByte(0,DBBranch,'SrvListMode'));
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ with tServiceAction(lParam) do
+ begin
+ if CB_SelectData(Dialog,IDC_EDIT_SERVICE,Hash(service,StrLen(service)))<>CB_ERR then
+// if SendDlgItemMessageA(Dialog,IDC_EDIT_SERVICE,CB_SELECTSTRING,twparam(-1),tlparam(service))<>CB_ERR then
+ ReloadService(Dialog,false)
+ else
+ SetDlgItemTextA(Dialog,IDC_EDIT_SERVICE,service);
+//!!
+ SetEditFlags(GetDlgItem(Dialog,IDC_EDIT_SERVICE),EF_SCRIPT,
+ ord((flags and ACF_SCRIPT_SERVICE)<>0));
+
+ // RESULT
+ if (flags and ACF_RSTRUCT)<>0 then
+ i:=sresStruct
+ else if (flags and ACF_RSTRING)<>0 then
+ begin
+ i:=sresString;
+ if (flags and ACF_RUNICODE)<>0 then CheckDlgButton(Dialog,IDC_RES_UNICODE,BST_CHECKED);
+ if (flags and ACF_RFREEMEM)<>0 then CheckDlgButton(Dialog,IDC_RES_FREEMEM,BST_CHECKED);
+ end
+ else
+ begin
+ i:=sresInt;
+ end;
+ CB_SelectData(Dialog,IDC_SRV_RESULT,i);
+
+ // WPARAM
+ i:=SetParam(Dialog,flags,IDC_EDIT_WPAR,pWideChar(wparam));
+ if i=ptStruct then
+ begin
+ ShowEditField(GetDlgItem(Dialog,IDC_EDIT_WPAR),SW_HIDE);
+ ShowWindow (GetDlgItem(Dialog,IDC_WSTRUCT ),SW_SHOW);
+
+{
+ p:=pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA));
+ mFreeMem(p);
+}
+ SetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA,
+ long_ptr(StrDup(pc,pAnsiChar(wparam))));
+ end;
+ CB_SelectData(GetDlgItem(Dialog,IDC_FLAG_WPAR),i);
+
+ // LPARAM
+ i:=SetParam(Dialog,flags2,IDC_EDIT_LPAR,pWideChar(lparam));
+ if i=ptStruct then
+ begin
+ ShowEditField(GetDlgItem(Dialog,IDC_EDIT_LPAR),SW_HIDE);
+ ShowWindow (GetDlgItem(Dialog,IDC_LSTRUCT ),SW_SHOW);
+
+{
+ p:=pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA));
+ mFreeMem(p);
+}
+ SetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA,
+ long_ptr(StrDup(pc,pAnsiChar(lparam))));
+ end;
+ CB_SelectData(GetDlgItem(Dialog,IDC_FLAG_LPAR),i);
+
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+ SetDlgItemTextW(Dialog,IDC_EDIT_SERVICE,nil);
+ SetDlgItemTextW(Dialog,IDC_EDIT_WPAR,'0');
+ SetDlgItemTextW(Dialog,IDC_EDIT_LPAR,'0');
+{
+ ShowWindow(GetDlgItem(Dialog,IDC_WSTRUCT),SW_HIDE);
+ ShowWindow(GetDlgItem(Dialog,IDC_LSTRUCT),SW_HIDE);
+}
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tServiceAction(lParam) do
+ begin
+ //WPARAM
+ wnd:=GetDlgItem(Dialog,IDC_EDIT_WPAR);
+ case CB_GetData(GetDlgItem(Dialog,IDC_FLAG_WPAR)) of
+ ptParam: begin
+ flags:=flags or ACF_PARAM
+ end;
+ ptResult: begin
+ flags:=flags or ACF_RESULT
+ end;
+ ptCurrent: begin
+ flags:=flags or ACF_CURRENT
+ end;
+ ptNumber: begin
+ flags:=flags or ACF_PARNUM;
+ wparam:=GetDlgText(wnd);
+ end;
+ ptStruct: begin
+ flags:=flags or ACF_STRUCT;
+ StrDup(pAnsiChar(wparam),
+ pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA)));
+ end;
+ ptUnicode: begin
+ flags:=flags or ACF_UNICODE;
+ wparam:=GetDlgText(wnd);
+ end;
+ ptString: wparam:=GetDlgText(wnd);
+ end;
+ if (GetEditFlags(wnd) and EF_SCRIPT)<>0 then
+ flags:=flags or ACF_SCRIPT_PARAM;
+
+ // LPARAM
+ wnd:=GetDlgItem(Dialog,IDC_EDIT_LPAR);
+ case CB_GetData(GetDlgItem(Dialog,IDC_FLAG_LPAR)) of
+ ptParam: begin
+ flags2:=flags2 or ACF_PARAM
+ end;
+ ptResult: begin
+ flags2:=flags2 or ACF_RESULT
+ end;
+ ptCurrent: begin
+ flags2:=flags2 or ACF_CURRENT
+ end;
+ ptNumber: begin
+ flags2:=flags2 or ACF_PARNUM;
+ lparam:=GetDlgText(wnd);
+ end;
+ ptStruct: begin
+ flags2:=flags2 or ACF_STRUCT;
+ StrDup(pAnsiChar(lparam),
+ pAnsiChar(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA)));
+ end;
+ ptUnicode: begin
+ flags2:=flags2 or ACF_UNICODE;
+ lparam:=GetDlgText(wnd);
+ end;
+ ptString: lparam:=GetDlgText(wnd);
+ end;
+ if (GetEditFlags(wnd) and EF_SCRIPT)<>0 then
+ flags2:=flags2 or ACF_SCRIPT_PARAM;
+
+ // RESULT
+ case CB_GetData(GetDlgItem(Dialog,IDC_SRV_RESULT)) of
+ sresString: begin
+ flags:=flags or ACF_RSTRING;
+ if IsDlgButtonChecked(Dialog,IDC_RES_UNICODE)=BST_CHECKED then
+ flags:=flags or ACF_RUNICODE;
+ if IsDlgButtonChecked(Dialog,IDC_RES_FREEMEM)=BST_CHECKED then
+ flags:=flags or ACF_RFREEMEM;
+ end;
+ sresStruct: flags:=flags or ACF_RSTRUCT;
+ end;
+
+ service:=ApiCard.NameFromList(GetDlgItem(Dialog,IDC_EDIT_SERVICE));
+//!!
+ if (GetEditFlags(Dialog,IDC_EDIT_SERVICE) and EF_SCRIPT)<>0 then
+ flags:=flags or ACF_SCRIPT_SERVICE;
+ end;
+ end;
+
+ WM_SHOWWINDOW: begin
+ // hide window by ShowWindow function
+ if (lParam=0) and (wParam=0) then
+ begin
+ pc:=pAnsiChar(SetWindowLongPtrW(GetDlgItem(Dialog,IDC_WSTRUCT),GWLP_USERDATA,0));
+ mFreeMem(pc);
+ pc:=pAnsiChar(SetWindowLongPtrW(GetDlgItem(Dialog,IDC_LSTRUCT),GWLP_USERDATA,0));
+ mFreeMem(pc);
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+{ CBN_EDITUPDATE,
+}
+ CBN_EDITCHANGE,
+ EN_CHANGE: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+
+ CBN_SELCHANGE: begin
+ case loword(wParam) of
+ IDC_SRV_RESULT: begin
+ i:=CB_GetData(lParam);
+ case i of
+ sresInt,sresStruct: begin
+ ShowWindow(GetDlgItem(Dialog,IDC_RES_FREEMEM),SW_HIDE);
+ ShowWindow(GetDlgItem(Dialog,IDC_RES_UNICODE),SW_HIDE);
+ end;
+ sresString: begin
+ ShowWindow(GetDlgItem(Dialog,IDC_RES_FREEMEM),SW_SHOW);
+ ShowWindow(GetDlgItem(Dialog,IDC_RES_UNICODE),SW_SHOW);
+ end;
+ end;
+ end;
+
+ IDC_FLAG_WPAR,IDC_FLAG_LPAR: begin
+ if loword(wParam)=IDC_FLAG_WPAR then
+ begin
+ wnd :=GetDlgItem(Dialog,IDC_EDIT_WPAR);
+ wnd1:=GetDlgItem(Dialog,IDC_WSTRUCT);
+ end
+ else
+ begin
+ wnd :=GetDlgItem(Dialog,IDC_EDIT_LPAR);
+ wnd1:=GetDlgItem(Dialog,IDC_LSTRUCT);
+ end;
+ i:=CB_GetData(GetDlgItem(Dialog,loword(wParam)));
+
+ if i=ptStruct then
+ begin
+ ShowEditField(wnd,SW_HIDE);
+ ShowWindow(wnd1,SW_SHOW);
+ end
+ else
+ begin
+ ShowEditField(wnd,SW_SHOW);
+ ShowWindow(wnd1,SW_HIDE);
+ if i in [ptCurrent,ptResult,ptParam] then
+ EnableEditField(wnd,false)
+ else
+ begin
+ if i=ptNumber then
+ begin
+ pcw:='0';
+ SendMessageW(wnd,WM_SETTEXT,0,TLParam(pcw));
+ end;
+ EnableEditField(wnd,true);
+ end;
+ end;
+ end;
+
+ IDC_EDIT_SERVICE: ReloadService(Dialog,true);
+ end;
+ if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_WSTRUCT, IDC_LSTRUCT: begin
+ pc:=pAnsiChar(GetWindowLongPtrW(lParam,GWLP_USERDATA));
+//!!!!
+ pc1:=EditStructure(pAnsiChar(pc),Dialog);
+ if pc1<>nil then
+ begin
+ mFreeMem(pc);
+ SetWindowLongPtrW(lParam,GWLP_USERDATA,long_ptr(pc1));
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+ else
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ end;
+ end;
+
+ WM_HELP: begin
+ pc:=ApiCard.NameFromList(GetDlgItem(Dialog,IDC_EDIT_SERVICE));
+ ApiCard.Service:=pc;
+ mFreeMem(pc);
+ ApiCard.Show;
+
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tServiceAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTSERVICE',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Service';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_SERVICE';
+ vc.Hash :=0;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_service.rc b/plugins/Actman30/iac_service.rc
new file mode 100644
index 0000000000..10160c5361
--- /dev/null
+++ b/plugins/Actman30/iac_service.rc
@@ -0,0 +1,32 @@
+#include "i_cnst_service.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTSERVICE DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ GROUPBOX "Result" , -1, 1, 0, 166, 64, WS_GROUP
+ RTEXT "Result type" , -1 , 4, 10, 159, 11
+ COMBOBOX IDC_SRV_RESULT , 4, 21, 159, 76, CBS_DROPDOWN | WS_VSCROLL | CBS_AUTOHSCROLL
+ AUTOCHECKBOX "Free memory" , IDC_RES_FREEMEM, 4, 38, 159, 11
+ AUTOCHECKBOX "Unicode string", IDC_RES_UNICODE, 4, 50, 159, 11
+
+ RTEXT "Service name", -1, 1, 68, 160, 8
+ COMBOBOX IDC_EDIT_SERVICE , 1, 78, 166, 96, CBS_DROPDOWN | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_SORT
+
+ RTEXT "wParam type", -1, 1, 101, 63, 14, SS_CENTERIMAGE
+ COMBOBOX IDC_FLAG_WPAR, 66, 101, 102, 56, CBS_DROPDOWNLIST | WS_VSCROLL
+// RTEXT "wParam" , -1, 1, 116, 160, 8
+ COMBOBOX IDC_EDIT_WPAR, 1, 116, 166, 76, CBS_DROPDOWN | WS_VSCROLL | CBS_AUTOHSCROLL
+ PUSHBUTTON "Structure" , IDC_WSTRUCT , 1, 116, 166, 14
+
+ RTEXT "lParam type", -1, 1, 142, 63, 14, SS_CENTERIMAGE
+ COMBOBOX IDC_FLAG_LPAR, 66, 142, 102, 56, CBS_DROPDOWNLIST | WS_VSCROLL
+// RTEXT "lParam" , -1, 1, 157, 160, 8
+ COMBOBOX IDC_EDIT_LPAR, 1, 157, 166, 76, CBS_DROPDOWN | WS_VSCROLL | CBS_AUTOHSCROLL
+ PUSHBUTTON "Structure" , IDC_LSTRUCT , 1, 157, 166, 14
+}
+
+IDI_SERVICE ICON "ico\service.ico"
diff --git a/plugins/Actman30/iac_settings.pas b/plugins/Actman30/iac_settings.pas
new file mode 100644
index 0000000000..bb2c8efe5a
--- /dev/null
+++ b/plugins/Actman30/iac_settings.pas
@@ -0,0 +1,157 @@
+unit iac_settings;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ global,iac_global, dlgshare, lowlevelc,
+ m_api, mirutils, dbsettings, common, wrapper;
+
+{$include i_cnst_settings.inc}
+{$resource iac_settings.res}
+
+
+//----- Support functions -----
+
+
+//----- Dialog realization -----
+
+procedure FillServiceModeList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ InsertString(wnd,0 ,'value');
+ InsertString(wnd,1 ,'name');
+ InsertString(wnd,2 ,'value (name)');
+ InsertString(wnd,3 ,'name ''value''');
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_CNT_FILTER,BST_UNCHECKED);
+ SetDlgItemTextW(Dialog,IDC_EDIT_FORMAT,'');
+
+ CheckDlgButton(Dialog,IDC_FR_FLAG,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ fCLformat:pWideChar;
+ lp:TLPARAM;
+ stat:integer;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ OptSetButtonIcon(GetDlgItem(Dialog,IDC_CNT_APPLY),ACI_APPLY);
+
+ OptSetButtonIcon(GetDlgItem(Dialog,IDC_SRV_APPLY),ACI_APPLY);
+ FillServiceModeList(GetDlgItem(Dialog,IDC_SERVICELIST));
+ end;
+
+ WM_ACT_SETVALUE: begin
+ ClearFields(Dialog);
+ end;
+
+ WM_ACT_RESET: begin
+ ClearFields(Dialog);
+ // Contact list settings
+ CheckDlgButton (Dialog,IDC_CNT_FILTER,DBReadByte(0,DBBranch,'CLfilter',BST_UNCHECKED));
+ fCLformat:=DBReadUnicode(0,DBBranch,'CLformat');
+ SetDlgItemTextW(Dialog,IDC_EDIT_FORMAT,fCLformat);
+ mFreeMem(fCLformat);
+
+ // Servicelist mode settings
+ CB_SelectData(Dialog,IDC_SERVICELIST,DBReadByte(0,DBBranch,'SrvListMode'));
+ end;
+
+ WM_SHOWWINDOW: begin
+ // Show window by ShowWindow function
+ if (lParam=0) and (wParam=1) then
+ begin
+ lp:=LV_GetLParam(MacroListWindow);
+ if (lp and ACF_FIRSTRUN)<>0 then
+ stat:=BST_CHECKED
+ else
+ stat:=BST_UNCHECKED;
+ CheckDlgButton(Dialog,IDC_FR_FLAG,stat);
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_SRV_APPLY: begin
+ DBWriteByte(0,DBBranch,'SrvListMode',
+ CB_GetData(GetDlgItem(Dialog,IDC_SERVICELIST)));
+ end;
+
+ IDC_CNT_APPLY: begin
+ fCLformat:=GetDlgText(Dialog,IDC_EDIT_FORMAT);
+ DBWriteUnicode(0,DBBranch,'CLformat',fCLformat);
+ mFreeMem(fCLformat);
+ end;
+
+ IDC_CNT_FILTER: begin
+ DBWriteByte(0,DBBranch,'CLfilter',IsDlgButtonChecked(Dialog,IDC_CNT_FILTER));
+ end;
+
+ IDC_FR_FLAG: begin
+ lp:=LV_GetLParam(MacroListWindow);
+ if IsDlgButtonChecked(Dialog,IDC_FR_FLAG)=BST_UNCHECKED then
+ lp:=lp and not ACF_FIRSTRUN
+ else
+ lp:=lp or ACF_FIRSTRUN;
+ LV_SetLParam(MacroListWindow,lp);
+
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ WM_HELP: begin
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=nil;
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_SETTINGS',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Settings';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_SETTINGS';
+ vc.Hash :=1;
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_settings.rc b/plugins/Actman30/iac_settings.rc
new file mode 100644
index 0000000000..957fba3088
--- /dev/null
+++ b/plugins/Actman30/iac_settings.rc
@@ -0,0 +1,26 @@
+#include "i_cnst_settings.inc"
+
+LANGUAGE 0,0
+
+IDD_SETTINGS DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ GROUPBOX "Contact list", -1, 1, 2, 166, 77, WS_GROUP
+ AUTOCHECKBOX "Active accounts only",IDC_CNT_FILTER, 4, 11, 160, 11
+ RTEXT "Contact list format",-1, 4, 24, 160, 11
+ EDITTEXT IDC_EDIT_FORMAT, 22, 38, 142, 12, ES_AUTOHSCROLL
+ CONTROL "Apply",IDC_CNT_APPLY,"MButtonClass",WS_TABSTOP,4,36,16,16,$18000000
+ CTEXT "You can use %name%, %uid%, %account% and %group% substitutes",-1, 4, 53, 160, 24
+
+ RTEXT "Service list format",-1, 0, 82, 166, 11
+ COMBOBOX IDC_SERVICELIST , 19, 94, 148, 96, CBS_DROPDOWNLIST | WS_VSCROLL
+ CONTROL "Apply",IDC_SRV_APPLY,"MButtonClass",WS_TABSTOP,1,93,16,16,$18000000
+
+ GROUPBOX "Current Macro", -1, 1, 116, 166, 28, WS_GROUP
+ AUTOCHECKBOX "Select for FirstRun",IDC_FR_FLAG, 4, 125, 160, 12
+// AUTOCHECKBOX "hContact in wParam" ,IDC_HC_WPAR, 4, 138, 160, 12
+}
+
+IDI_SETTINGS ICON "ico\settings.ico"
diff --git a/plugins/Actman30/iac_storage.pas b/plugins/Actman30/iac_storage.pas
new file mode 100644
index 0000000000..aaa7351452
--- /dev/null
+++ b/plugins/Actman30/iac_storage.pas
@@ -0,0 +1,292 @@
+unit iac_storage;
+
+interface
+
+implementation
+
+uses
+ windows, messages,
+ common, wrapper,
+ mirutils,m_api,dbsettings,
+ global,iac_global;
+
+{$include i_cnst_storage.inc}
+{$resource iac_storage.res}
+
+const
+ opt_number = 'number';
+const
+ ioNumber = 'number';
+ ioOper = 'oper';
+ ioCopy = 'copy';
+const
+ ACF_COPYFROM = $00000001;
+type
+ tStorageAction = class(tBaseAction)
+ Number:integer;
+
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tStorageAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ Number:=0;
+end;
+
+destructor tStorageAction.Destroy;
+begin
+
+ inherited Destroy;
+end;
+{
+function tStorageAction.Clone:tBaseAction;
+begin
+ result:=.Create(0);
+ Duplicate(result);
+
+end;
+}
+function tStorageAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ num:integer;
+ st,dt:pByte;
+ sv,dv:^uint_ptr;
+begin
+ result:=0;
+
+ if Number in [0..9] then
+ begin
+ // copy to slot
+ if (flags and ACF_COPYFROM)=0 then
+ begin
+ num:=Number;
+ st:=@WorkData.ResultType;
+ dt:=@WorkData.Storage[Number].rtype;
+ sv:=@WorkData.LastResult;
+ dv:=@WorkData.Storage[Number].value;
+ end
+ // copy from slot
+ else
+ begin
+ num:=-1;
+ dt:=@WorkData.ResultType;
+ st:=@WorkData.Storage[Number].rtype;
+ dv:=@WorkData.LastResult;
+ sv:=@WorkData.Storage[Number].value;
+ end;
+
+ ClearResult(WorkData,num);
+ dt^:=st^;
+
+ if WorkData.ResultType=rtInt then // Number
+ dv^:=sv^
+
+ else if WorkData.ResultType=rtWide then // Unicode
+ StrDupW(pWideChar(dv^),pWideChar(sv^))
+
+ else if WorkData.ResultType<>rtUnkn then // Ansi and UTF8
+ StrDup(pAnsiChar(dv^),pAnsiChar(sv^));
+ end;
+
+{
+ // copy to slot
+ if (flags and ACF_COPYFROM)=0 then
+ begin
+ if Number in [0..9] then
+ begin
+ ClearResult(WorkData,Number);
+ WorkData.Storage[Number].rtype:=WorkData.ResultType;
+
+ if WorkData.ResultType=rtInt then // Number
+ WorkData.Storage[Number].value:=WorkData.LastResult
+
+ else if WorkData.ResultType=rtWide then // Unicode
+ StrDupW(pWideChar(WorkData.Storage[Number].value),pWideChar(WorkData.LastResult))
+
+ else if WorkData.ResultType<>rtUnkn then // Ansi and UTF8
+ StrDup(pAnsiChar(WorkData.Storage[Number].value),pAnsiChar(WorkData.LastResult));
+
+ end;
+ end
+ // copy from slot
+ else
+ begin
+ if Number in [0..9] then
+ begin
+ ClearResult(WorkData);
+ WorkData.ResultType:=WorkData.Storage[Number].rtype;
+
+ if WorkData.ResultType=rtInt then // Number
+ WorkData.LastResult:=WorkData.Storage[Number].value
+
+ else if WorkData.ResultType=rtWide then // Unicode
+ StrDupW(pWideChar(WorkData.LastResult),pWideChar(WorkData.Storage[Number].value))
+
+ else if WorkData.ResultType<>rtUnkn then // Ansi and UTF8
+ StrDup(pAnsiChar(WorkData.LastResult),pAnsiChar(WorkData.Storage[Number].value));
+
+ end;
+ end;
+}
+end;
+
+procedure tStorageAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_number); Number:=DBReadByte(0,DBBranch,section,0);
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ if lstrcmpiw(getAttrValue(HXML(node),ioOper),ioCopy)=1 then
+ flags:=flags or ACF_COPYFROM;
+ Number:=StrToInt(getAttrValue(HXML(node),ioNumber));
+ end;
+ end;
+ end;
+end;
+
+procedure tStorageAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+ StrCopy(pc,opt_number); DBWriteByte(0,DBBranch,section,Number);
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure FillStorageCombo(wnd:HWND);
+var
+ i:integer;
+ buf:array [0..31] of AnsiChar;
+ p:pAnsiChar;
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+
+ p:=StrCopyE(buf,'Slot #')-1;
+ for i:=0 to 9 do
+ begin
+ p^:=AnsiChar(ORD('0')+i);
+ InsertString(wnd,i,buf);
+ end;
+
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure ClearFields(Dialog:HWND);
+begin
+ CheckDlgButton(Dialog,IDC_FLAG_TO ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_FLAG_FROM,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ FillStorageCombo(GetDlgItem(Dialog,IDC_STORAGELIST));
+ end;
+
+ WM_ACT_SETVALUE: begin
+ ClearFields(Dialog);
+ with tStorageAction(lParam) do
+ begin
+ if (flags and ACF_COPYFROM)=0 then
+ CheckDlgButton(Dialog,IDC_FLAG_TO ,BST_CHECKED)
+ else
+ CheckDlgButton(Dialog,IDC_FLAG_FROM,BST_CHECKED);
+
+ CB_SelectData(GetDlgItem(Dialog,IDC_STORAGELIST),Number);
+ end;
+ end;
+
+ WM_ACT_RESET: begin
+ ClearFields(Dialog);
+ CheckDlgButton(Dialog,IDC_FLAG_TO,BST_CHECKED);
+ CB_SelectData(GetDlgItem(Dialog,IDC_STORAGELIST),0);
+ end;
+
+ WM_ACT_SAVE: begin
+ with tStorageAction(lParam) do
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_FLAG_FROM)<>BST_UNCHECKED then
+ flags:=flags or ACF_COPYFROM;
+
+ Number:=CB_GetData(GetDlgItem(Dialog,IDC_STORAGELIST));
+ end;
+ end;
+{
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ end;
+ end;
+}
+ WM_HELP: begin
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tStorageAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTSTORAGE',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Storage';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_STORAGE';
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_storage.rc b/plugins/Actman30/iac_storage.rc
new file mode 100644
index 0000000000..6e4391e15c
--- /dev/null
+++ b/plugins/Actman30/iac_storage.rc
@@ -0,0 +1,16 @@
+#include "i_cnst_storage.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTSTORAGE DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ AUTORADIOBUTTON "LastResult to " , IDC_FLAG_TO , 1, 2, 166, 11, WS_GROUP
+ AUTORADIOBUTTON "LastResult from", IDC_FLAG_FROM , 1, 15, 166, 11
+
+ COMBOBOX IDC_STORAGELIST, 19, 30, 148, 128, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL
+}
+
+IDI_STORAGE ICON "ico\storage.ico"
diff --git a/plugins/Actman30/iac_text.pas b/plugins/Actman30/iac_text.pas
new file mode 100644
index 0000000000..e6a05d8fc0
--- /dev/null
+++ b/plugins/Actman30/iac_text.pas
@@ -0,0 +1,495 @@
+unit iac_text;
+
+interface
+
+implementation
+
+uses
+ windows, messages, commctrl,
+ global, iac_global, m_api, editwrapper,
+ dbsettings, common, io,
+ mirutils, syswin, wrapper;
+
+{$include i_cnst_text.inc}
+{$resource iac_text.res}
+
+const
+ BufferSize = 32768; // chars
+
+const
+ opt_text = 'text';
+const
+ ioVariables = 'variables';
+ ioText = 'text';
+ ioPost = 'post';
+const
+ ACF_TEXTSCRIPT = $00000001;
+ ACF_POSTPROCESS = $00000002;
+
+type
+ tTextAction = class(tBaseAction)
+ private
+ text: pWideChar;
+ public
+ constructor Create(uid:dword);
+ destructor Destroy; override;
+// function Clone:tBaseAction; override;
+ function DoAction(var WorkData:tWorkData):LRESULT; override;
+ procedure Save(node:pointer;fmt:integer); override;
+ procedure Load(node:pointer;fmt:integer); override;
+ end;
+
+//----- Support functions -----
+
+//----- Object realization -----
+
+constructor tTextAction.Create(uid:dword);
+begin
+ inherited Create(uid);
+
+ text:=nil;
+end;
+
+destructor tTextAction.Destroy;
+begin
+ mFreeMem(text);
+
+ inherited Destroy;
+end;
+{
+function tTextAction.Clone:tBaseAction;
+begin
+ result:=.Create(0);
+ Duplicate(result);
+
+end;
+}
+type
+ trec = record
+ text:PAnsiChar;
+ one, two:integer;
+ end;
+
+function GetFileString(fname:PAnsiChar;linenum:integer):pWideChar;
+var
+ pc,FileBuf,CurLine:PAnsiChar;
+ f:THANDLE;
+ NumLines, j:integer;
+begin
+ f:=Reset(fname);
+ if f<>INVALID_HANDLE_VALUE then
+ begin
+ j:=FileSize(f);
+ mGetMem(FileBuf,j+1);
+ BlockRead(f,FileBuf^,j);
+ while (FileBuf+j)^<' ' do dec(j);
+ (FileBuf+j+1)^:=#0;
+ CloseHandle(f);
+ pc:=FileBuf;
+ CurLine:=pc;
+ NumLines:=1;
+ while pc^<>#0 do // count number of lines
+ begin
+ if pc^=#13 then
+ begin
+ if linenum=NumLines then
+ break;
+ inc(pc);
+ if pc^=#10 then
+ inc(pc);
+ inc(NumLines);
+ CurLine:=pc;
+ end
+ else
+ inc(pc);
+ end;
+ if (linenum>NumLines) or (linenum=0) then //ls - lastline
+ else if linenum<0 then
+ begin
+ randomize;
+ j:=random(NumLines)+1;
+ pc:=FileBuf;
+ NumLines:=1;
+ CurLine:=pc;
+ repeat
+ if (pc^=#13) or (pc^=#0) then
+ begin
+ if j=NumLines then
+ break;
+ if pc^<>#0 then
+ begin
+ inc(pc);
+ if pc^=#10 then
+ inc(pc);
+ end;
+ inc(NumLines);
+ CurLine:=pc;
+ end
+ else
+ inc(pc);
+ until false;
+ end;
+ pc^:=#0;
+ StrReplace(CurLine,'\n',#13#10);
+ StrReplace(CurLine,'\t',#09);
+ AnsiToWide(CurLine,result,CP_ACP);
+ mFreeMem(FileBuf);
+ end
+ else
+ result:=nil;
+end;
+
+function Split(buf:PWideChar;macro:PWideChar;var r:trec):integer;
+type
+ tconv = packed record
+ case boolean of
+ false: (res:int);
+ true: (lo,hi:word);
+ end;
+var
+ i:integer;
+ p,pp,lp:pWideChar;
+ ls:array [0..511] of WideChar;
+begin
+ result:=0;
+ i:=StrIndexW(buf,macro);
+ if i>0 then
+ begin
+ dec(i);
+ p:=buf+i+StrLenW(macro);
+ pp:=p;
+ while (p^<>#0) and (p^<>')') do
+ inc(p);
+ ls[0]:=#0;
+ if p^<>#0 then // correct syntax
+ begin
+ lp:=ls;
+ while (pp<>p) and (pp^<>',') do // filename
+ begin
+ lp^:=pp^;
+ inc(lp);
+ inc(pp);
+ end;
+ lp^:=#0;
+ WideToAnsi(ls,r.text,MirandaCP);
+ r.one:=-1;
+ r.two:=-1;
+ if pp^=',' then
+ begin
+ inc(pp);
+ r.one:=StrToInt(pp);
+ while (pp<>p) and (pp^<>',') do inc(pp);
+ if pp^=',' then
+ begin
+ inc(pp);
+ r.two:=StrToInt(pp);
+ end;
+ end;
+ tconv(result).lo:=p-buf-i+1; // length
+ tconv(result).hi:=i; // position
+ end;
+ end;
+end;
+
+procedure PasteFileString(dst:pWideChar);
+var
+ i:integer;
+ lp:pWideChar;
+ buf:array [0..511] of AnsiChar;
+ r:trec;
+begin
+ repeat
+ i:=Split(dst,'^f(',r);
+ if i>0 then
+ begin
+ StrDeleteW(dst,i shr 16,loword(i));
+ ConvertFileName(r.text,buf);
+// CallService(MS_UTILS_PATHTOABSOLUTE,WPARAM(r.text),LPARAM(@buf));
+ lp:=GetFileString(@buf,r.one);
+ if lp<>nil then
+ begin
+ StrInsertW(lp,dst,i shr 16);
+ mFreeMem(lp);
+ end;
+ end
+ else
+ break;
+ until false;
+end;
+
+procedure PasteClipboard(dst:pWideChar);
+var
+ p:pWideChar;
+ fh:tHandle;
+begin
+ if StrPosW(dst,'^v')<>nil then
+ begin
+ if OpenClipboard(0) then
+ begin
+ fh:=GetClipboardData(cf_UnicodeText);
+ p:=GlobalLock(fh);
+ StrReplaceW(dst,'^v',p);
+ GlobalUnlock(fh);
+ CloseClipboard;
+ end
+ end
+end;
+
+procedure PasteSelectedText(dst:pWideChar);
+var
+ sel:integer;
+ buf:pWideChar;
+ wnd:HWND;
+begin
+ if StrPosW(dst,'^s')<>nil then
+ begin
+ wnd:=WaitFocusedWndChild(GetForegroundWindow){GetFocus};
+ if wnd<>0 then
+ begin
+ sel:=SendMessageW(wnd,EM_GETSEL,0,0);
+ if loword(sel)=(sel shr 16) then
+ StrReplaceW(dst,'^s',nil)
+ else
+ begin
+ buf:=GetDlgText(wnd,false);
+ buf[sel shr 16]:=#0;
+ StrReplaceW(dst,'^s',buf+loword(sel));
+ mFreeMem(buf);
+ end;
+ end
+ else
+ StrReplaceW(dst,'^s',nil);
+ end;
+end;
+
+function tTextAction.DoAction(var WorkData:tWorkData):LRESULT;
+var
+ buf:array [0..31] of WideChar;
+ w,tmp,last:pWideChar;
+begin
+ result:=0;
+
+ tmp:=text;
+ if (flags and ACF_POSTPROCESS)=0 then
+ if (flags and ACF_TEXTSCRIPT)<>0 then
+ begin
+ if WorkData.ResultType=rtInt then
+ last:=pWideChar(IntToStr(buf,WorkData.LastResult))
+ else
+ last:=pWideChar(WorkData.LastResult);
+
+ tmp:=ParseVarString(text,WorkData.Parameter,last);
+ end;
+
+ mGetMem (w ,BufferSize*SizeOf(WideChar));
+ FillChar(w^,BufferSize*SizeOf(WideChar),0);
+ StrCopyW(w,tmp);
+ if (flags and ACF_POSTPROCESS)=0 then
+ if (flags and ACF_TEXTSCRIPT)<>0 then
+ mFreeMem(tmp);
+
+ PasteClipboard(w); // ^v
+ PasteFileString(w); // ^f
+
+ PasteSelectedText(w); // ^s
+ // ^a - get ALL text?
+
+ if WorkData.ResultType=rtInt then
+ begin
+ StrReplaceW(w,'^l',IntToStr(buf,WorkData.LastResult)); // ^l
+ StrReplaceW(w,'^h',IntToHex(buf,WorkData.LastResult)); // ^h
+ end
+ else
+ begin
+ StrReplaceW(w,'^l',pWideChar(WorkData.LastResult));
+ StrReplaceW(w,'^h',IntToHex(buf,NumToInt(pWideChar(WorkData.LastResult))));
+ end;
+
+ StrReplaceW(w,'^t',#9); // ^t
+ StrReplaceW(w,'^e',nil); // ^e
+
+ if (flags and ACF_POSTPROCESS)<>0 then
+ if (flags and ACF_TEXTSCRIPT)<>0 then
+ begin
+ if WorkData.ResultType=rtInt then
+ last:=pWideChar(IntToStr(buf,WorkData.LastResult))
+ else
+ last:=pWideChar(WorkData.LastResult);
+
+ tmp:=ParseVarString(w,WorkData.Parameter,last);
+ mFreeMem(w);
+ w:=tmp;
+ end;
+
+ ClearResult(WorkData);
+ WorkData.LastResult:=uint_ptr(w);
+ WorkData.ResultType:=rtWide;
+end;
+
+procedure tTextAction.Load(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Load(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+
+ StrCopy(pc,opt_text); text:=DBReadUnicode(0,DBBranch,section,nil);
+ end;
+
+ 1: begin
+ with xmlparser do
+ begin
+ StrDupW(text,getText(HXML(node)));
+ if StrToInt(getAttrValue(HXML(node),ioVariables))=1 then
+ flags:=flags or ACF_TEXTSCRIPT;
+ if StrToInt(getAttrValue(HXML(node),ioPost))=1 then
+ flags:=flags or ACF_POSTPROCESS;
+ end;
+ end;
+{
+ 2: begin
+ UTF8ToWide(GetParamSectionInt(node,ioText),text);
+ if GetParamSectionInt(node,ioVariables)=1 then
+ flags:=flags or ACF_TEXTSCRIPT;
+ end;
+}
+ end;
+end;
+
+procedure tTextAction.Save(node:pointer;fmt:integer);
+var
+ section: array [0..127] of AnsiChar;
+ pc:pAnsiChar;
+begin
+ inherited Save(node,fmt);
+ case fmt of
+ 0: begin
+ pc:=StrCopyE(section,pAnsiChar(node));
+
+ StrCopy(pc,opt_text); DBWriteUnicode(0,DBBranch,section,text);
+ end;
+{
+ 1: begin
+ end;
+}
+ end;
+end;
+
+//----- Dialog realization -----
+
+procedure ClearFields(Dialog:HWND);
+begin
+ SetDlgItemTextW(Dialog,IDC_TXT_TEXT,nil);
+ SetEditFlags (Dialog,IDC_TXT_TEXT,EF_ALL,0);
+ CheckDlgButton (Dialog,IDC_TXT_POST,BST_UNCHECKED);
+end;
+
+function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ NoProcess:boolean=true;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ MakeEditField(Dialog,IDC_TXT_TEXT);
+ end;
+
+ WM_ACT_SETVALUE: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+
+ with tTextAction(lParam) do
+ begin
+ SetDlgItemTextW(Dialog,IDC_TXT_TEXT,text);
+ SetEditFlags(Dialog,IDC_TXT_TEXT,EF_SCRIPT,ord((flags and ACF_TEXTSCRIPT)<>0));
+ if (flags and ACF_POSTPROCESS)<>0 then
+ CheckDlgButton(Dialog,IDC_TXT_POST,BST_CHECKED);
+ end;
+ NoProcess:=false;
+ end;
+
+ WM_ACT_RESET: begin
+ NoProcess:=true;
+ ClearFields(Dialog);
+ NoProcess:=false;
+ end;
+
+ WM_ACT_SAVE: begin
+ with tTextAction(lParam) do
+ begin
+ flags:=0;
+
+ {mFreeMem(text); }text:=GetDlgText(Dialog,IDC_TXT_TEXT);
+ if (GetEditFlags(Dialog,IDC_TXT_TEXT) and EF_SCRIPT)<>0 then
+ flags:=flags or ACF_TEXTSCRIPT;
+
+ if IsDlgButtonChecked(Dialog,IDC_TXT_POST)=BST_CHECKED then
+ flags:=flags or ACF_POSTPROCESS;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ BN_CLICKED:
+ if loword(wParam)=IDC_TXT_POST then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+
+ EN_CHANGE: if not NoProcess then
+ SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ WM_HELP: begin
+ MessageBoxW(0,
+ TranslateW('^s - selected (and replaced) part'#13#10+
+ '^e - replaced by empty string'#13#10+
+ '^v - paste text from Clipboard'#13#10+
+ '^t - replaced by tabulation'#13#10+
+ '^l - replaced by last result as unicode'#13#10+
+ '^h - replaced by last result as hex'#13#10+
+ '^f(name[,str])'#13#10+
+ ' paste line from text file.'#13#10+
+ ' brackets contents must be w/o spaces'),
+ TranslateW('Text'),0);
+ result:=1;
+ end;
+
+ end;
+end;
+
+//----- Export/interface functions -----
+
+var
+ vc:tActModule;
+
+function CreateAction:tBaseAction;
+begin
+ result:=tTextAction.Create(vc.Hash);
+end;
+
+function CreateDialog(parent:HWND):HWND;
+begin
+ result:=CreateDialogW(hInstance,'IDD_ACTTEXT',parent,@DlgProc);
+end;
+
+procedure Init;
+begin
+ vc.Next :=ModuleLink;
+
+ vc.Name :='Text';
+ vc.Dialog :=@CreateDialog;
+ vc.Create :=@CreateAction;
+ vc.Icon :='IDI_TEXT';
+
+ ModuleLink :=@vc;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Actman30/iac_text.rc b/plugins/Actman30/iac_text.rc
new file mode 100644
index 0000000000..06399716c4
--- /dev/null
+++ b/plugins/Actman30/iac_text.rc
@@ -0,0 +1,14 @@
+#include "i_cnst_text.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTTEXT DIALOGEX 0, 0, 168, 200, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ EDITTEXT IDC_TXT_TEXT, 1, 4, 166, 12, ES_AUTOHSCROLL
+ AUTOCHECKBOX "Script process after",IDC_TXT_POST, 4, 18, 160, 11
+}
+
+IDI_TEXT ICON "ico\text.ico"
diff --git a/plugins/Actman30/ico/advance.ico b/plugins/Actman30/ico/advance.ico
new file mode 100644
index 0000000000..fa6c604542
--- /dev/null
+++ b/plugins/Actman30/ico/advance.ico
Binary files differ
diff --git a/plugins/Actman30/ico/apply.ico b/plugins/Actman30/ico/apply.ico
new file mode 100644
index 0000000000..80c3802c09
--- /dev/null
+++ b/plugins/Actman30/ico/apply.ico
Binary files differ
diff --git a/plugins/Actman30/ico/chain.ico b/plugins/Actman30/ico/chain.ico
new file mode 100644
index 0000000000..3a98b8ac30
--- /dev/null
+++ b/plugins/Actman30/ico/chain.ico
Binary files differ
diff --git a/plugins/Actman30/ico/contact.ico b/plugins/Actman30/ico/contact.ico
new file mode 100644
index 0000000000..8174fa221a
--- /dev/null
+++ b/plugins/Actman30/ico/contact.ico
Binary files differ
diff --git a/plugins/Actman30/ico/delete.ico b/plugins/Actman30/ico/delete.ico
new file mode 100644
index 0000000000..eea851da19
--- /dev/null
+++ b/plugins/Actman30/ico/delete.ico
Binary files differ
diff --git a/plugins/Actman30/ico/down.ico b/plugins/Actman30/ico/down.ico
new file mode 100644
index 0000000000..d4fdb83bbf
--- /dev/null
+++ b/plugins/Actman30/ico/down.ico
Binary files differ
diff --git a/plugins/Actman30/ico/export.ico b/plugins/Actman30/ico/export.ico
new file mode 100644
index 0000000000..ddddb59074
--- /dev/null
+++ b/plugins/Actman30/ico/export.ico
Binary files differ
diff --git a/plugins/Actman30/ico/format.ico b/plugins/Actman30/ico/format.ico
new file mode 100644
index 0000000000..ddddb59074
--- /dev/null
+++ b/plugins/Actman30/ico/format.ico
Binary files differ
diff --git a/plugins/Actman30/ico/import.ico b/plugins/Actman30/ico/import.ico
new file mode 100644
index 0000000000..481da4dbaf
--- /dev/null
+++ b/plugins/Actman30/ico/import.ico
Binary files differ
diff --git a/plugins/Actman30/ico/insert.ico b/plugins/Actman30/ico/insert.ico
new file mode 100644
index 0000000000..481da4dbaf
--- /dev/null
+++ b/plugins/Actman30/ico/insert.ico
Binary files differ
diff --git a/plugins/Actman30/ico/jump.ico b/plugins/Actman30/ico/jump.ico
new file mode 100644
index 0000000000..3a98b8ac30
--- /dev/null
+++ b/plugins/Actman30/ico/jump.ico
Binary files differ
diff --git a/plugins/Actman30/ico/message.ico b/plugins/Actman30/ico/message.ico
new file mode 100644
index 0000000000..fa6c604542
--- /dev/null
+++ b/plugins/Actman30/ico/message.ico
Binary files differ
diff --git a/plugins/Actman30/ico/new.ico b/plugins/Actman30/ico/new.ico
new file mode 100644
index 0000000000..73937210e0
--- /dev/null
+++ b/plugins/Actman30/ico/new.ico
Binary files differ
diff --git a/plugins/Actman30/ico/program.ico b/plugins/Actman30/ico/program.ico
new file mode 100644
index 0000000000..30c7df1875
--- /dev/null
+++ b/plugins/Actman30/ico/program.ico
Binary files differ
diff --git a/plugins/Actman30/ico/reload.ico b/plugins/Actman30/ico/reload.ico
new file mode 100644
index 0000000000..dc070c5083
--- /dev/null
+++ b/plugins/Actman30/ico/reload.ico
Binary files differ
diff --git a/plugins/Actman30/ico/rw.ico b/plugins/Actman30/ico/rw.ico
new file mode 100644
index 0000000000..d5927ebb08
--- /dev/null
+++ b/plugins/Actman30/ico/rw.ico
Binary files differ
diff --git a/plugins/Actman30/ico/service.ico b/plugins/Actman30/ico/service.ico
new file mode 100644
index 0000000000..ddddb59074
--- /dev/null
+++ b/plugins/Actman30/ico/service.ico
Binary files differ
diff --git a/plugins/Actman30/ico/settings.ico b/plugins/Actman30/ico/settings.ico
new file mode 100644
index 0000000000..ddddb59074
--- /dev/null
+++ b/plugins/Actman30/ico/settings.ico
Binary files differ
diff --git a/plugins/Actman30/ico/storage.ico b/plugins/Actman30/ico/storage.ico
new file mode 100644
index 0000000000..dc070c5083
--- /dev/null
+++ b/plugins/Actman30/ico/storage.ico
Binary files differ
diff --git a/plugins/Actman30/ico/test.ico b/plugins/Actman30/ico/test.ico
new file mode 100644
index 0000000000..345530ba76
--- /dev/null
+++ b/plugins/Actman30/ico/test.ico
Binary files differ
diff --git a/plugins/Actman30/ico/text.ico b/plugins/Actman30/ico/text.ico
new file mode 100644
index 0000000000..fa6c604542
--- /dev/null
+++ b/plugins/Actman30/ico/text.ico
Binary files differ
diff --git a/plugins/Actman30/ico/up.ico b/plugins/Actman30/ico/up.ico
new file mode 100644
index 0000000000..56fde31eda
--- /dev/null
+++ b/plugins/Actman30/ico/up.ico
Binary files differ
diff --git a/plugins/Actman30/inoutini.pas b/plugins/Actman30/inoutini.pas
new file mode 100644
index 0000000000..38dab2be45
--- /dev/null
+++ b/plugins/Actman30/inoutini.pas
@@ -0,0 +1,153 @@
+unit inoutini;
+
+interface
+
+uses windows, lowlevelc;
+
+{
+type
+ pINIioStruct = ^tINIioStruct;
+ tINIioStruct = record
+ storage,
+ section,
+ namespace:pAnsiChar;
+ end;
+}
+function Import(list:tMacroList;fname:PWideChar;aflags:dword):integer;
+
+implementation
+
+uses
+ io, common, m_api, question,
+ iac_global, global, memini;
+
+const
+ ioAction = 'Action';
+ ioClass = 'class';
+ ioName = 'name';
+ ioVolatile = 'volatile';
+const
+ imp_yes = 1;
+ imp_yesall = 2;
+ imp_no = 3;
+ imp_noall = 4;
+ imp_append = 5;
+
+function ImportAction(section:pointer):tBaseAction;
+var
+ pa:pActModule;
+begin
+ if section<>nil then
+ begin
+ pa:=GetLinkByName(GetParamSectionStr(section,ioClass,nil));
+ if pa<>nil then
+ begin
+ result:=pa.Create;
+ result.Load(section,2);
+ end
+ else
+ result:=tBaseAction(1);
+ end
+ else
+ result:=nil;
+end;
+
+function Import(list:tMacroList;fname:PWideChar;aflags:dword):integer;
+var
+ i:integer;
+ impact:integer;
+ buf:array [0..511] of WideChar;
+ oldid:dword;
+ arr:array [0..63] of tBaseAction;
+ act:tBaseAction;
+ p:pMacroRecord;
+ storage:pointer;
+ pc,pc1,ppc,ppc1:pAnsiChar;
+ pcw:pWideChar;
+begin
+ result:=0;
+
+ for i:=0 to list.Count-1 do
+ with list[i]^ do
+ if (flags and (ACF_IMPORT or ACF_ASSIGNED))=
+ (ACF_IMPORT or ACF_ASSIGNED) then
+ flags:=flags and not (ACF_IMPORT or ACF_OVERLOAD);
+
+ if (fname=nil) or (fname^=#0) then
+ exit;
+ storage:=OpenStorage(fname);
+ if storage=nil then
+ exit;
+
+ impact:=imp_yes;
+
+ pc:=GetSectionList(storage,''); // list with "empty" namespaces
+ ppc:=pc;
+ while pc^<>#0 do
+ begin
+ UTF8ToWide(pc,pcw);
+
+ p:=list.GetMacro(pcw);
+ oldid:=$FFFFFFFF;
+ if p<>nil then
+ begin
+ if (impact<>imp_yesall) and (impact<>imp_noall) then
+ begin
+ StrCopyW(buf,TranslateW('Action "$" exists, do you want to rewrite it?'));
+ impact:=ShowQuestion(StrReplaceW(buf,'$',pcw));
+ end;
+ if (impact=imp_yesall) or (impact=imp_yes) then
+ begin
+ oldid:=p^.id;
+ FreeMacro(p);
+ end;
+ end;
+ // if new or overwriting then read macro details/actions
+ if (p=nil) or (impact=imp_yesall) or (impact=imp_yes) or (impact=imp_append) then
+ begin
+ with List[list.NewMacro()]^ do
+ begin
+ if (p<>nil) and (oldid<>$FFFFFFFF) then // set old id to keep UseAction setting
+ begin
+ flags:=flags or ACF_IMPORT or ACF_OVERLOAD;
+ id:=oldid;
+ end
+ else
+ flags:=flags or ACF_IMPORT;
+
+ if GetParamInt(storage,pc,ioVolatile)=1 then flags:=flags or ACF_VOLATILE;
+ StrCopyW(descr,pcw,MacroNameLen-1);
+
+ // reading actions
+ ActionCount:=0; // amount of loaded
+ pc1:=GetSectionList(storage,pc);
+ ppc1:=pc1;
+ while pc1^<>#0 do
+ begin
+ act:=ImportAction(SearchSection(storage,pc1,pc));
+ if act=nil then
+ break;
+ if uint_ptr(act)<>1 then
+ begin
+ arr[ActionCount]:=act;
+ inc(ActionCount);
+ end;
+ end;
+ FreeSectionList(ppc1);
+ // moving actions to their place
+ if Actioncount>0 then
+ begin
+ GetMem(ActionList,SizeOf(tBaseAction)*ActionCount);
+ move(arr,ActionList^,SizeOf(tBaseAction)*ActionCount);
+ end;
+ inc(result);
+ end;
+ end;
+
+ end;
+ FreeSectionList(ppc);
+
+ CloseStorage(storage);
+end;
+
+end.
diff --git a/plugins/Actman30/inoutxml.pas b/plugins/Actman30/inoutxml.pas
new file mode 100644
index 0000000000..3a7aea25d4
--- /dev/null
+++ b/plugins/Actman30/inoutxml.pas
@@ -0,0 +1,155 @@
+unit inoutxml;
+
+interface
+
+uses windows, lowlevelc;
+
+function Import(list:tMacroList;fname:PWideChar;aflags:dword):integer;
+
+implementation
+
+uses
+ io, common, m_api, question,
+ iac_global, global;
+
+const
+ ioAction = 'Action';
+ ioClass = 'class';
+ ioName = 'name';
+ ioVolatile = 'volatile';
+const
+ imp_yes = 1;
+ imp_yesall = 2;
+ imp_no = 3;
+ imp_noall = 4;
+ imp_append = 5;
+
+function ImportAction(actnode:HXML):tBaseAction;
+var
+ pa:pActModule;
+ buf:array [0..127] of AnsiChar;
+begin
+ result:=nil;
+ if actnode=0 then exit;
+ with xmlparser do
+ begin
+ pa:=GetLinkByName(FastWideToAnsiBuf(getAttrValue(actnode,ioClass),buf));
+ if pa<>nil then
+ begin
+ result:=pa.Create;
+ result.Load(pointer(actnode),1);
+ end
+ else
+ result:=tBaseAction(1);
+ end;
+end;
+
+function Import(list:tMacroList;fname:PWideChar;aflags:dword):integer;
+var
+ f:THANDLE;
+ i,nodenum,actcnt:integer;
+ tmp,res:pWideChar;
+ root,actnode:HXML;
+ impact:integer;
+ buf:array [0..511] of WideChar;
+ oldid:dword;
+ arr:array [0..63] of tBaseAction;
+ act:tBaseAction;
+ p:pMacroRecord;
+begin
+ result:=0;
+
+ for i:=0 to list.Count-1 do
+ with list[i]^ do
+ if (flags and (ACF_IMPORT or ACF_ASSIGNED))=
+ (ACF_IMPORT or ACF_ASSIGNED) then
+ flags:=flags and not (ACF_IMPORT or ACF_OVERLOAD);
+
+ if (fname=nil) or (fname^=#0) then
+ exit;
+ i:=GetFSize(fname);
+ if i=0 then
+ exit;
+ mGetMem (res ,i+SizeOf(WideChar));
+ FillChar(res^,i+SizeOf(WideChar),0);
+ f:=Reset(fname);
+ BlockRead(f,res^,i);
+ CloseHandle(f);
+
+//MessageBoxW(0,res,'SRC',0);
+ xmlparser.cbSize:=SizeOf(XML_API_W);
+ CallService(MS_SYSTEM_GET_XI,0,lparam(@xmlparser));
+ with xmlparser do
+ begin
+ root:=parseString(ChangeUnicode(res),@i,nil);
+ nodenum:=0;
+ impact:=imp_yes;
+ repeat
+ actnode:=getNthChild(root,ioAction,nodenum);
+ if actnode=0 then break;
+//?? if StrCmpW(getName(actnode),ioAction)<>0 then break;
+ tmp:=getAttrValue(actnode,ioName);
+ if tmp<>nil then //!!
+ begin
+ p:=list.GetMacro(tmp);
+ oldid:=$FFFFFFFF;
+ if p<>nil then
+ begin
+ if (impact<>imp_yesall) and (impact<>imp_noall) then
+ begin
+ StrCopyW(buf,TranslateW('Action "$" exists, do you want to rewrite it?'));
+ impact:=ShowQuestion(StrReplaceW(buf,'$',tmp));
+ end;
+ if (impact=imp_yesall) or (impact=imp_yes) then
+ begin
+ oldid:=p^.id;
+ FreeMacro(p);
+ end;
+ end;
+ // if new or overwriting then read macro details/actions
+ if (p=nil) or (impact=imp_yesall) or (impact=imp_yes) or (impact=imp_append) then
+ begin
+ with List[list.NewMacro()]^ do
+ begin
+ if (p<>nil) and (oldid<>$FFFFFFFF) then // set old id to keep UseAction setting
+ begin
+ flags:=flags or ACF_IMPORT or ACF_OVERLOAD;
+ id:=oldid;
+ end
+ else
+ flags:=flags or ACF_IMPORT;
+ if StrToInt(getAttrValue(actnode,ioVolatile))=1 then flags:=flags or ACF_VOLATILE;
+ StrCopyW(descr,tmp,MacroNameLen-1);
+
+ // reading actions
+ actcnt:=0; // count in file
+ ActionCount:=0; // amount of loaded
+ repeat
+ act:=ImportAction(getChild(actnode,actcnt));
+ if act=nil then
+ break;
+ if uint_ptr(act)<>1 then
+ begin
+ arr[ActionCount]:=act;
+ inc(ActionCount);
+ end;
+ inc(actcnt);
+ until false;
+ // moving actions to their place
+ if Actioncount>0 then
+ begin
+ GetMem(ActionList,SizeOf(tBaseAction)*ActionCount);
+ move(arr,ActionList^,SizeOf(tBaseAction)*ActionCount);
+ end;
+ inc(result);
+ end;
+ end;
+ end;
+ inc(nodenum);
+ until false;
+ destroyNode(root);
+ end;
+ mFreeMem(res);
+end;
+
+end.
diff --git a/plugins/Actman30/lowlevelc.pas b/plugins/Actman30/lowlevelc.pas
new file mode 100644
index 0000000000..5c4d6b7965
--- /dev/null
+++ b/plugins/Actman30/lowlevelc.pas
@@ -0,0 +1,294 @@
+unit lowlevelc;
+
+interface
+
+uses
+ windows,
+ iac_global;
+
+const
+ ACF_ASSIGNED = $80000000; // action assigned
+ ACF_FIRSTRUN = $40000000; // FirstRun flag
+ ACF_USEDNOW = $20000000; // action in use (reserved)
+ ACF_VOLATILE = $10000000; // don't save in DB
+
+ ACF_TOSAVE = ACF_ASSIGNED or ACF_FIRSTRUN;
+type
+ pActionList = ^tActionList;
+ tActionList = array [0..1023] of tBaseAction;
+
+const
+ MacroNameLen = 64;
+type
+ pMacroRecord = ^tMacroRecord;
+ tMacroRecord = record
+ id :dword;
+ flags :dword; // ACF_* flags
+ descr :array [0..MacroNameLen-1] of WideChar;
+ ActionList :pActionList;
+ ActionCount:integer;
+ end;
+
+type // array dimension - just for indexing
+ pMacroList = ^taMacroList;
+ taMacroList = array [0..1023] of tMacroRecord;
+
+type
+ tMacroList = class
+ private
+ fMacroList:pMacroList;
+ fMacroCount:cardinal;
+
+ procedure ReallocMacroList;
+ function GetMacroElement(i:integer):pMacroRecord;
+ public
+
+ constructor Create(isize:cardinal);
+ destructor Destroy; override;
+
+ procedure Clear(filter:dword=0);
+ function Clone:tMacroList;
+ function NewMacro:cardinal;
+
+ function GetMacro(id:uint_ptr ):pMacroRecord; overload;
+ function GetMacro(name:pWideChar):pMacroRecord; overload;
+ function GetMacroNameById(id:dword):PWideChar;
+
+ property List[i:integer]:pMacroRecord read GetMacroElement; default;
+ property Count: cardinal read fMacroCount;
+ end;
+
+procedure FreeMacro(Macro:pMacroRecord;mask:dword=0);
+
+var
+ MacroList:tMacroList;
+
+
+implementation
+
+uses Common;
+
+const
+ MacroListPage = 8;
+
+
+function tMacroList.GetMacroElement(i:integer):pMacroRecord;
+begin
+ result:=@fMacroList[i];
+end;
+
+function tMacroList.GetMacro(id:uint_ptr):pMacroRecord;
+var
+ i:integer;
+begin
+ for i:=0 to fMacroCount-1 do
+ begin
+ if ((fMacroList^[i].flags and ACF_ASSIGNED)<>0) and
+ (id=fMacroList^[i].id) then
+ begin
+ result:=@(fMacroList^[i]);
+ exit;
+ end;
+ end;
+ result:=nil;
+end;
+
+function tMacroList.GetMacro(name:pWideChar):pMacroRecord;
+var
+ i:integer;
+begin
+ for i:=0 to fMacroCount-1 do
+ begin
+ if ((fMacroList^[i].flags and ACF_ASSIGNED)<>0) and
+ (StrCmpW(name,fMacroList^[i].descr)=0) then
+ begin
+ result:=@(fMacroList^[i]);
+ exit;
+ end;
+ end;
+ result:=nil;
+end;
+
+function tMacroList.GetMacroNameById(id:dword):PWideChar;
+var
+ p:pMacroRecord;
+begin
+ p:=GetMacro(id);
+ if p<>nil then
+ result:=@(p^.descr)
+ else
+ result:=nil;
+end;
+
+procedure FreeActionList(var src:pActionList; count:integer; mask:dword);
+var
+ i:integer;
+begin
+ for i:=0 to count-1 do
+ begin
+ if (mask=0) or ((src^[i].flags and mask)<>0) then
+ src^[i].Free;
+ end;
+ FreeMem(src);
+ src:=nil;
+end;
+
+procedure FreeMacro(Macro:pMacroRecord;mask:dword=0);
+begin
+ with Macro^ do
+ begin
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ flags:=0; // make Unassigned
+ FreeActionList(ActionList,ActionCount,mask);
+ ActionCount:=0;
+ end;
+ end;
+end;
+
+procedure tMacroList.Clear(filter:dword=0);
+var
+ i:integer;
+begin
+ for i:=0 to fMacroCount-1 do
+ begin
+ FreeMacro(@(fMacroList[i]),filter);
+ end;
+ fMacroCount:=0;
+ FreeMem(fMacroList);
+ fMacroList:=nil;
+end;
+
+destructor tMacroList.Destroy;
+begin
+ fMacroCount:=0;
+ FreeMem(fMacroList);
+ fMacroList:=nil;
+
+ inherited Destroy;
+end;
+
+function CloneActionList(src:pActionList;count:integer):pActionList;
+begin
+ if src=nil then
+ begin
+ result:=nil;
+ exit;
+ end;
+ GetMem(result ,count*SizeOf(tBaseAction));
+ move(src^,result^,count*SizeOf(tBaseAction))
+end;
+
+procedure CloneMacro(var dst:pMacroRecord; src:pMacroRecord);
+begin
+ if (src^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ move(src^,dst^,SizeOf(tMacroRecord));
+ dst^.ActionList:=CloneActionList(src^.ActionList,src^.ActionCount);
+ end;
+end;
+
+function tMacroList.Clone:tMacroList;
+var
+ src,dst:pMacroRecord;
+ i:integer;
+ cnt:integer;
+begin
+ result:=nil;
+
+ if fMacroList<>nil then
+ begin
+ cnt:=0;
+ for i:=0 to fMacroCount-1 do
+ if (fMacroList^[i].flags and ACF_ASSIGNED)<>0 then
+ inc(cnt);
+ if cnt>0 then
+ begin
+ result:=tMacroList.Create(cnt);
+
+ src:=pMacroRecord(self.fMacroList);
+ dst:=pMacroRecord(result.fMacroList);
+
+ while cnt>0 do
+ begin
+ if (src^.flags and ACF_ASSIGNED)<>0 then
+ begin
+ CloneMacro(dst,src);
+ inc(dst);
+ dec(cnt);
+ end;
+ inc(src);
+ end;
+ end;
+ end;
+ if result=nil then
+ result:=tMacroList.Create(0);
+end;
+
+procedure tMacroList.ReallocMacroList;
+var
+ i:cardinal;
+ tmp:pMacroList;
+begin
+ i:=(fMacroCount+MacroListPage)*SizeOf(tMacroRecord);
+ GetMem(tmp,i);
+ FillChar(tmp^,i,0);
+ if fMacroCount>0 then
+ begin
+ move(fMacroList^,tmp^,fMacroCount*SizeOf(tMacroRecord));
+ FreeMem(fMacroList);
+ end;
+ fMacroList:=tmp;
+ inc(fMacroCount,MacroListPage);
+end;
+
+constructor tMacroList.Create(isize:cardinal);
+begin
+ inherited Create;
+
+ if isize<MacroListPage then
+ fMacroCount:=MacroListPage
+ else
+ fMacroCount:=isize;
+ GetMem (fMacroList ,fMacroCount*SizeOf(tMacroRecord));
+ FillChar(fMacroList^,fMacroCount*SizeOf(tMacroRecord),0);
+end;
+
+procedure InitMacroValue(pMacro:pMacroRecord);
+var
+ tmp:int64;
+begin
+ with pMacro^ do
+ begin
+ StrCopyW(descr,NoDescription,MacroNameLen-1);
+ QueryPerformanceCounter(tmp);
+ id :=tmp and $FFFFFFFF;
+ flags :=ACF_ASSIGNED;
+ end;
+end;
+
+function tMacroList.NewMacro:cardinal;
+var
+ i:cardinal;
+ pMacro:pMacroRecord;
+begin
+ i:=0;
+ pMacro:=pMacroRecord(fMacroList);
+ while i<fMacroCount do
+ begin
+ if (pMacro^.flags and ACF_ASSIGNED)=0 then
+ begin
+ result:=i;
+ InitMacroValue(pMacro);
+ exit;
+ end;
+ inc(i);
+ inc(pMacro);
+ end;
+ // realloc
+ result:=fMacroCount;
+ ReallocMacroList;
+ InitMacroValue(@(fMacroList^[result]));
+end;
+
+end.
diff --git a/plugins/Actman30/m_actman.h b/plugins/Actman30/m_actman.h
new file mode 100644
index 0000000000..c900ba9c6c
--- /dev/null
+++ b/plugins/Actman30/m_actman.h
@@ -0,0 +1,96 @@
+#ifndef M_ACTMAN
+#define M_ACTMAN
+
+#define ACCF_DISABLED 0x10000000 // action disabled
+#define ACCF_EXPORT 0x08000000 // action to export
+#define ACCF_VOLATILE 0x04000000 // don't save in DB
+#define ACCF_IMPORTED ACF_EXPORT
+#define ACCF_FLAGS (ACCF_DISABLED | ACCF_EXPORT | ACCF_IMPORTED | ACCF_VOLATILE)
+#define ACCF_ID 0x02000000 // for MS_ACT_SELECT, lParam is ID (else name)
+#define ACCF_CLEAR 0x01000000 // clear other flags, else - set
+
+
+typedef struct{
+ WCHAR* Descr;
+ DWORD ID;
+ DWORD flags; // ACCF_* flags
+ } TChain, *PChain;
+
+// Service to get list of all configured actions;
+// wParam : 0
+// lParam : address of destination list variable (address of pointer to TChain)
+// Notes: first 4 bytes of list = size of TChain structure (to add new fields in future)
+// Return value: count of elements;
+#define MS_ACT_GETLIST "Actions/GetList"
+
+// Service to free list of all configured actions got with MS_ACT_GETLIST service call;
+// wParam : 0
+// lParam : list address (pointer to ACTION returned by MS_ACT_GETLIST)
+#define MS_ACT_FREELIST "Actions/FreeList"
+
+// Service to call action defined in wParam;
+// wParam: ID of an action (see ACTION.ActID) when calling MS_ACT_RUN
+// or description of an action (see ACTION.ActDescr) when calling MS_ACT_RUNGROUP
+// lParam: parameter (will be passed to action called)
+#define MS_ACT_RUNBYID "Actions/RunById"
+#define MS_ACT_RUNBYNAME "Actions/RunByName"
+
+// Event: action group list was changed: something was added or deleted
+// wParam: set of ACTM_* flags
+// lParam : 0
+#define ME_ACT_CHANGED "Actions/Changed"
+
+// Starts action with 2 parameters
+// wParam: 0
+// lParam: pointer to TAct_Param
+
+#define MS_ACT_RUNPARAMS "Actions/RunWithParams"
+typedef struct TAct_Param
+ {
+ DWORD flags; // 0 - ID, 1 - Name
+ DWORD ID; // Id or name
+ WPARAM wParam;
+ LPARAM lParam;
+ } TAct_Param, *PAct_Param;
+
+#define ACTM_NEW 0x00000001
+#define ACTM_DELETE 0x00000002
+#define ACTM_RELOAD 0x00000004
+#define ACTM_RENAME 0x00000008
+#define ACTM_SORT 0x00000010
+#define ACTM_ACT 0x10000000 // do not check, internal
+#define ACTM_ACTS 0x20000000 // do not check, internal
+#define ACTM_LOADED 0x80000000
+
+
+#define ACIO_EXPORT 0x00000001 // export, else - import
+#define ACIO_APPEND 0x00000002 // append file on export
+#define ACIO_ASKEXIST 0x00000004 // ask, if action exists on import
+#define ACIO_SELECTED 0x00000008 // export selected actions only
+
+// wParam: ACIO_* flags
+// lParam: Unicode file name
+// Return - true, if totally succesful
+#define MS_ACT_INOUT "Actions/ImpExp"
+
+
+//Event: Export actions
+// wParam - ACIO_* flags
+// lParam - unicode filename
+#define ME_ACT_INOUT "Actions/InOut"
+
+
+// Select/unselect specified action
+// wParam: set of ACCF_* consts
+// lParam: unicode action name / number
+// Return - -1 if unsuccesful
+#define MS_ACT_SELECT "Actions/Select"
+
+
+// Event: Action started/finished
+// wParam - Action status: 0 - started, 1 - finished
+// lParam - action id
+
+#define ME_ACT_ACTION "Actions/Action"
+
+#endif
diff --git a/plugins/Actman30/m_actman.inc b/plugins/Actman30/m_actman.inc
new file mode 100644
index 0000000000..5f0089a60c
--- /dev/null
+++ b/plugins/Actman30/m_actman.inc
@@ -0,0 +1,152 @@
+{$IFNDEF M_ACTMAN}
+{$DEFINE M_ACTMAN}
+
+// defined in interfaces.inc
+//const MIID_ACTMANAGER:MUUID='{9584DA04-FB4F-40c1-9325-E4F9CAAFCB5D}';
+
+const
+ AutoStartName:PWideChar = '#Autostart';
+const
+ // Get list service (full share)
+ ACCF_EXPORT = $08000000; // action to export (UA export)
+ ACCF_IMPORT = ACCF_EXPORT; // (UA import)
+
+type
+ pChain = ^tChain;
+ tChain = record
+ descr:pWideChar;
+ id :dword;
+ flags:dword; // ACCF_* flags ?? right now - just selection/overload
+ order:dword; // ??
+ end;
+
+const
+ {
+ wParam - 0
+ lParam - address of destination list variable (address of pointer to tChain)
+ if lParam=0, return just count of elements
+ Return - count of elements
+ Notes: first 4 bytes = size of TChain structure (to add new fields in future)
+ }
+ MS_ACT_GETLIST:PAnsiChar = 'Actions/GetList';
+ {
+ wParam - 0
+ lParam - list address (pointer to data returned by MS_ACT_GETLIST)
+ }
+ MS_ACT_FREELIST:PAnsiChar = 'Actions/FreeList';
+ {
+ wParam - id: dword
+ lParam - parameter
+ }
+ MS_ACT_RUNBYID :PAnsiChar = 'Actions/RunById';
+ {
+ wParam - unicode action name
+ lParam - parameter
+ }
+ MS_ACT_RUNBYNAME:PAnsiChar = 'Actions/RunByName';
+
+{ Starts action with 2 parameters
+ wParam: 0
+ lParam: pointer to TAct_Param
+}
+ MS_ACT_RUNPARAMS:PAnsiChar = 'Actions/RunWithParams';
+const
+ ACTP_BYNAME = 1; // id points on unicode name
+ ACTP_WAIT = 2; // waiting for macro finish
+ ACTP_NOTIFY = 4; // notify (raise event) for start/finish macro
+ ACTP_SAMETHREAD = 8; // execute macro in same thread (with finish waiting)
+ ACTP_KEEPRESULT = 16; // (internal) keep last result
+type
+ pAct_Param = ^tAct_Param;
+ tAct_Param = record
+ Id :uint_ptr; // Id or name
+ wParam:WPARAM;
+ lParam:LPARAM;
+ flags :dword; // ACTP_*
+ lPType:dword; // last result (in lParam) type
+ end;
+
+const
+ ACTM_NEW = $00000001; // new macros was added
+ ACTM_DELETE = $00000002; // some macros was deleted
+ ACTM_RENAME = $00000008; // possible, some macro names was changed
+ ACTM_SORT = $00000010; // possible, macro order in list was changed
+ ACTM_LOADED = $80000000; // All macros loaded and ready to work (at plugin start)
+
+ {
+ Event: action group list was changed: some was added or deleted
+ wParam - set of ACTM_* flags
+ lParam - 0
+ }
+ ME_ACT_CHANGED:PAnsiChar = 'Actions/Changed';
+
+ ACIO_EXPORT = $00000001; // export, else - import
+ ACIO_APPEND = $00000002; // append file on export
+ ACIO_ASKEXIST = $00000004; // ask, if action exists on import
+ ACIO_SELECTED = $00000008; // export selected actions only
+
+ {
+ wParam - ACIO_* flags
+ lParam - Unicode file name
+ Return - true, if totally succesful
+ }
+ MS_ACT_INOUT:PAnsiChar = 'Actions/ImpExp';
+
+ {
+ Event: Export actions
+ wParam - ACIO_* flags
+ lParam - unicode filename
+ }
+ ME_ACT_INOUT:PAnsiChar = 'Actions/InOut';
+
+ {
+ Select/unselect specified action
+ wParam - mask (bit 0 = ID if set/name; bit 1 = clear if set/set; bit 2 = get if set/set)
+ lParam - unicode action name / number
+ Return - 0 if unsuccesful
+ }
+ MS_ACT_SELECT:PAnsiChar = 'Actions/Select';
+
+ {
+ Event: Action started/finished
+ wParam - Action status: 0 - started, 1 - finished
+ lParam - action id
+ }
+ ME_ACT_ACTION:PAnsiChar = 'Actions/Action';
+
+//----- Scheduling part services -----
+
+const
+ {
+ Enable or disable tasks
+ wParam - 1/0 (enable/disable)
+ lParam - unicode task name
+ Note - works for all tasks with same started name
+ }
+ MS_ACT_TASKENABLE:PAnsiChar = 'Actions/TaskEnable';
+
+ {
+ Delete task
+ wParam - 0
+ lParam - unicode task name
+ Note - works for all tasks with same started name
+ }
+ MS_ACT_TASKDELETE:PAnsiChar = 'Actions/TaskDelete';
+
+ {
+ Set task repeat count
+ wParam - repeat count
+ lParam - unicode task name
+ Return - old repeat count value
+ Note - works for all tasks with same started name
+ }
+ MS_ACT_TASKCOUNT:PAnsiChar = 'Actions/TaskCount';
+
+ {
+ Event for task start
+ wParam - counter of call (from 0 to repeat count)
+ lParam - unicode task name
+ }
+ ME_ACT_BELL:PAnsiChar = 'Actions/Bell';
+
+{$ENDIF}
diff --git a/plugins/Actman30/make.bat b/plugins/Actman30/make.bat
new file mode 100644
index 0000000000..36cbb97ab5
--- /dev/null
+++ b/plugins/Actman30/make.bat
@@ -0,0 +1,18 @@
+@echo off
+set myopts=-dMiranda
+set dprname=actman.dpr
+
+for /R %%I in (*.rc) do ..\delphi\brcc32.exe %myopts% %%I -fo%%~npI.res >nul
+
+if /i '%1' == 'fpc' (
+ ..\FPC\bin\fpc.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else if /i '%1' == 'fpc64' (
+ ..\FPC\bin64\ppcrossx64.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else if /i '%1' == 'xe2' (
+ ..\XE2\BIN\dcc32.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else if /i '%1' == 'xe64' (
+ ..\XE2\BIN\dcc64.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else (
+ ..\delphi\dcc32 %myopts% %dprname% %1 %2 %3 %4 %5 %6 %7 %8 %9
+)
+del /Q /S *.res >nul
diff --git a/plugins/Actman30/options.rc b/plugins/Actman30/options.rc
new file mode 100644
index 0000000000..c37268666e
--- /dev/null
+++ b/plugins/Actman30/options.rc
@@ -0,0 +1,70 @@
+#include "i_const.inc"
+
+LANGUAGE 0,0
+
+IDD_ACTION DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ CONTROL "New" ,IDC_GROUP_NEW ,"MButtonClass",WS_TABSTOP,114, 1,16,16,$18000000 | WS_GROUP
+ CONTROL "Up" ,IDC_GROUP_UP ,"MButtonClass",WS_TABSTOP,114, 18,16,16,$18000000
+ CONTROL "Down" ,IDC_GROUP_DOWN ,"MButtonClass",WS_TABSTOP,114, 34,16,16,$18000000
+ CONTROL "Delete",IDC_GROUP_DELETE,"MButtonClass",WS_TABSTOP,114, 68,16,16,$18000000
+ CONTROL "Test" ,IDC_GROUP_TEST ,"MButtonClass",WS_TABSTOP,114, 85,16,16,$18000000
+ CONTROL "Export",IDC_GROUP_EXPORT,"MButtonClass",WS_TABSTOP,114,102,16,16,$18000000
+ CONTROL "Import",IDC_GROUP_IMPORT,"MButtonClass",WS_TABSTOP,114,119,16,16,$18000000
+
+ CONTROL "", IDC_MACRO_LIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP |
+ LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_REPORT | LVS_EDITLABELS,// | LVS_SINGLESEL,
+ 0, 2, 110, 132, WS_EX_CONTROLPARENT
+
+ CONTROL "", IDC_ACTION_LIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP |
+ LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS| LVS_REPORT | LVS_EDITLABELS,// | LVS_SINGLESEL
+ 0, 138, 110, 86, WS_EX_CONTROLPARENT
+
+ CONTROL "Help" ,IDC_ACTION_HELP ,"MButtonClass",WS_TABSTOP,114,138,16,16,$18000000 | WS_GROUP
+ CONTROL "New" ,IDC_ACTION_NEW ,"MButtonClass",WS_TABSTOP,114,156,16,16,$18000000
+ CONTROL "Up" ,IDC_ACTION_UP ,"MButtonClass",WS_TABSTOP,114,174,16,16,$18000000
+ CONTROL "Down" ,IDC_ACTION_DOWN ,"MButtonClass",WS_TABSTOP,114,190,16,16,$18000000
+ CONTROL "Delete",IDC_ACTION_DELETE,"MButtonClass",WS_TABSTOP,114,208,16,16,$18000000
+
+// PUSHBUTTON "Reset", IDC_RESET, 264, 2, 40, 12
+ GROUPBOX "" , -1, 132, 0, 172, 226
+
+ RTEXT "Action",IDC_STAT_ACTION, 135, 6, 63, 12, SS_CENTERIMAGE
+ CONTROL "", IDC_ACTION_TYPE, "ComboBoxEx32",
+ WS_TABSTOP | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST, 200, 6, 101, 96
+}
+/*
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,3,0,1
+ PRODUCTVERSION 0,9,0,0
+ FILEFLAGSMASK $3F
+ FILEOS 4
+ FILETYPE 2
+ FILESUBTYPE 0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "CompanyName",""
+ VALUE "Comments", "Plugin for managing different Miranda actions "0
+ VALUE "FileDescription", "Action manager for Miranda NG"0
+ VALUE "FileVersion", "0, 3, 0, 1 "0
+ VALUE "InternalName", "ActManager"0
+ VALUE "OriginalFilename", "actman.dll"0
+ VALUE "ProductName", "Action Manager Dynamic Link Library (DLL)"0
+ VALUE "ProductVersion", "0, 9, 0, 0 "0
+ VALUE "SpecialBuild", "18.11.2012 "0
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation",0,1200
+ END
+END
+*/ \ No newline at end of file
diff --git a/plugins/Actman30/question.pas b/plugins/Actman30/question.pas
new file mode 100644
index 0000000000..9e5f0d1b59
--- /dev/null
+++ b/plugins/Actman30/question.pas
@@ -0,0 +1,58 @@
+unit question;
+
+interface
+uses windows,messages;
+
+function ShowQuestion(ask:pWideChar):integer;
+
+implementation
+
+uses m_api;
+
+{$include i_const.inc}
+{$resource ask.res}
+
+const
+ imp_yes = 1;
+ imp_yesall = 2;
+ imp_no = 3;
+ imp_noall = 4;
+ imp_append = 5;
+
+function QuestionDlg(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
+var
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ SetDlgItemTextW(Dialog, IDC_ASK,pWideChar(lParam));
+ result:=1;
+ end;
+ WM_COMMAND: begin
+ case loword(wParam) of
+ IDOK : i:=imp_yes;
+ IDCANCEL : i:=imp_no;
+ IDC_YESALL: i:=imp_yesall;
+ IDC_NOALL : i:=imp_noall;
+ IDC_APPEND: i:=imp_append;
+ else
+ i:=0;
+ end;
+ if i<>0 then
+ begin
+ EndDialog(Dialog,i);
+ result:=1;
+ end;
+ end;
+ end;
+end;
+
+function ShowQuestion(ask:pWideChar):integer;
+begin
+ result:=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_ASK),0,
+ @QuestionDlg,TLPARAM(ask));
+end;
+
+end.
diff --git a/plugins/Actman30/readme.txt b/plugins/Actman30/readme.txt
new file mode 100644
index 0000000000..0d1c6108b4
--- /dev/null
+++ b/plugins/Actman30/readme.txt
@@ -0,0 +1,126 @@
+Note
+----
+'Actions' is action groups wich can be executed through services
+'Subactions' is single simple action like 'Call service', ' rum program' etc.
+
+Description
+-----------
+This service plugin can be used for defining, management and executing some
+actions.
+Action can be executed later through miranda service.
+
+Settings
+--------
+Main window consist of two parts. Left part is for action list and subaction list
+for selected action. Navigation buttons for action list and subaction list positioned near
+these lists.
+'New' - to add new list item
+'Delete' - to delete selected item
+'Reload' - to reload settings from DB
+'Test' - executes currently selected action
+'Up','Down' - for place selected subaction upper or lower current position
+With DblClick on ag list item you can rename this item
+
+When action list is not empty, in right side you can see combobox for subaction type selecting.
+At this moment only next types supported:
+ Open contact window
+ Call service
+ Execute program
+ Insert text
+ Advanced
+ Link to action
+ Profile
+ MessageBox
+
+-- Open contact window
+Just select needed contact from combobox.
+
+-- Call service
+This is one of hard to understand action type.
+wParam and lParam comboboxes in upper part are for parameter type.
+ 'number' - just integer number (decimal or hex started from $ sign)
+ 'ANSI string' - single-byte character string
+ 'Unicode string' - double-byte character string
+ 'Current contact' - mean what parameter is current user handle.
+ Current user is active window owner
+ 'Last result' - result from previous action or calling parameter
+ 'Parameter' - parameter from calling service
+ 'Structure' - parameter is structure which can be edited in options dialog
+ but will not saving changes in runtime.
+
+wParam and lParam in lower part are for values, passed to service.
+If service.ini file presents in plugins directory, you can press F1 to see short help
+notes for selected from combobox service name.
+Most upper part, 'result action' is for action, what we must to do with result:
+show in popup, in message window or paste into text.
+Option to translate result are: integer decimal value (signed or not), hex value or
+string value (Unicode or ANSI)
+'<proto>' in service name will be replaced by protocol name for contact handle in paremeter
+
+-- Execute program
+More hard for undestand are upper settings.
+Process settings: 'parallel' means executing next subaction or return from executing action
+immediately, 'continued' mean what next subaction will be only after finishing this program.
+Process time option is for waiting time after that runned process will be shutdowned.
+'Current path' mean what program will run with current directory as start directory.
+Window options are for starting window view: minimized, normal, maximized etc.
+Severl macros can be used in program name:
+<param> - parameter
+<last> - last result
+
+-- Insert text
+You can work with Clipboard or file/mesage window here.
+In field below action type combobox you can write some text which will be inserted
+into text field of miranda and other program.
+Or, that text can be writed to file or some text can be readed.
+If you want help for text formatting, you can press F1.
+You can use Variables plugin. If you want it, just mark checkbox. help button can
+get help notes for available variables and functions.
+
+-- Advanced
+Most ununderstable block. Upper group is conditions for operation executing.
+'Value' is value for comparing last subaction result with it.
+Next actions will be if condition is true:
+'Math' - mathematic operations with last result and presented in 'value' field value.
+After math calculations (or w/o it) can be used next operations:
+'Operation' block consist of several operations:
+ 'BREAK' - break action executing (and return for 'parent' action executing - if exist)
+ 'JUMP' - jump to subaction with selected name
+ 'NOP' - not operation
+
+As 'Math' alternative, you can use Variables plugin scripts.
+Script can be writed in text field below and checked by pressing 'Vars' button.
+Variables %subject% and %extratext% can be used in the script.
+
+-- Call chain
+Select action from combobox below. This action will be executed. After that next subaction
+will be executed.
+
+-- Database
+This subaction is for database reading/writing (see Operation block).
+Value and value type is for type of data, reading or writing from/to database.
+'Last result' mean that value is result of previous action.
+Group of radioboxes is for contact type.
+ 'Own settings' - all settings only for our contact (our profle settings)
+ 'Parameter' - settings for contact with handle, passed from start parameter
+ 'Last result' - contact handle is result of last action
+ 'Manual' - contact handle selected from combobox
+'<proto>' in module name will be replaced with contact protocol name
+
+-- MessageBox
+ Subaction uses for standard windows MessageBox showing. text <last> will be replaced
+by last result value.
+
+Using
+-----
+Executing action from option dialog is possible but not recommended.
+First way is assign action to button for toolbar (maybe through modern clist skin engine)
+Second way is assign action to hotkey (miranda core not so good for this now)
+Third way is to insert action into menu by other plugin.
+Pluginmaker Vasilich wrote his plugin (UserActions) which works with ActMan and gives
+access to ability to assign actions to some controls (menu, toolbar, hotkey).
+
+Byte/Word/DWord - numeric integer data
+byte/word pointers - pointers to some data (really, like ANSI/Unicode strings)
+byte/word array - array of mixed data (really, like ANSI/Unicode strings)
+last result/param - current working data = dword
diff --git a/plugins/Actman30/services.ini b/plugins/Actman30/services.ini
new file mode 100644
index 0000000000..1366cf950d
--- /dev/null
+++ b/plugins/Actman30/services.ini
@@ -0,0 +1,523 @@
+;Small Service list
+;if wparam or lparam consists of list, "|" is separator
+;in list: if translation not needed, just add space before help
+;numeric parameter format: number<space>help
+;'hContact' will setup "Current contact" feature
+;'structure' will setup "structure" feature
+;'Unicode' as first word will setup "Unicode text" feature
+; not sure what next are usable
+;'parameter' will setup "Parameter" feature
+;'result' will setup "last result" feature
+;if "return" starts from int/hex/str/struct then separator, result type will set
+
+
+;[Event:Event (name or constant]
+;alias=constant name
+;descr=text
+;plugin=placement (including "core" and empty = "unknown"
+;wparam=
+;lparam=
+
+;full: full structure, with aliases
+;short: smallest needed structure
+;descr: structure description
+;plugin: where defined
+
+[Service:CListFrames/HideALLFramesTB]
+alias=MS_CLIST_FRAMES_HIDEALLFRAMESTB
+wparam=0
+lparam=0
+return=int 0, if successful
+descr=Hide All Titlebars
+
+[Service:CListFrames/ShowALLFrames]
+alias=MS_CLIST_FRAMES_SHOWALLFRAMES
+wparam=0
+lparam=0
+return=int 0, if successful
+descr=Show All Frames
+
+[Service:CListFrames/ShowALLFramesTB]
+alias=MS_CLIST_FRAMES_SHOWALLFRAMESTB
+wparam=0
+lparam=0
+return=int 0, if successful
+descr=Show All Titlebars
+
+[Service:CList/MenuBuildContact]
+alias=MS_CLIST_MENUBUILDCONTACT
+wparam=hContact
+lparam=0
+return=int hMenu handle
+descr=Built the context menu for a specific contact. Menu should be DestroyMenu()ed after done
+
+[Service:CList/SetHideOffline]
+alias=MS_CLIST_SETHIDEOFFLINE
+wparam=0 Show All Users|1 Show only Online Users|-1 Toggle status
+lparam=0
+return=int 0, if successful
+descr=Change 'hide offline contacts' option value
+
+[Service:CList/SetStatusMode]
+alias=MS_CLIST_SETSTATUSMODE
+wparam=40071 Offline|40072 Online|40073 Away|40074 DND|40075 NA|40076 Occupied|40077 Free for Chat|40078 Invisible|40079 On the Phone|40080 Out to Lunch
+lparam=0
+return=int 0, if successful
+descr=Set global status
+
+[Service:CList/ShowHide]
+alias=MS_CLIST_SHOWHIDE
+wparam=0
+lparam=0
+return=int 0, if successful
+descr=Switch contactlist status
+
+[Service:CloseAction]
+wparam=0
+lparam=0
+descr=Closes Miranda
+
+[Service:Console/Show/Hide]
+wparam=0
+lparam=0
+plugin=Console (console.dll)
+Show or hide netlog console window
+
+[Service:DB/Contact/GetCount]
+alias=MS_DB_CONTACT_GETCOUNT
+wparam=0
+lparam=0
+return=int Value
+descr=Returns contact amount, excluding user account
+
+[Service:DB/Module/Delete]
+alias=MS_DB_MODULE_DELETE
+wparam=0
+lparam=Ansi Text
+descr=Removes all settings for the specified module
+
+[Service:DBEditorpp/Import]
+alias=MS_DBEDIT_IMPORT
+wparam=hContact
+lparam=Ansi Text
+return=int 0
+descr=Import settings/contacts from file
+plugin=Database Editor++ (dbeditorpp.dll)
+
+[Service:DBEditorpp/MenuCommand]
+alias=MS_DBEDIT_MENUCOMMAND
+wparam=0
+lparam=0
+return=int 0
+plugin=Database Editor++ (dbeditorpp.dll)
+descr=Opens or activate database editor
+
+[Service:FindAdd/FindAddCommand]
+alias=MS_FINDADDFINDADD
+wparam=0
+lparam=0
+return=int 0
+descr=Opens or activate user search dialog
+
+[Service:FtMgr/Show]
+wparam=0
+lparam=0
+return=int 0
+descr=displays File Transfer window
+
+[Service:Help/AboutCommand]
+wparam=0 on Desktop|parent window handle
+lparam=0
+descr=Show "About..." window
+
+[Service:Help/IndexCommand]
+wparam=0
+lparam=0
+descr=Open support (originaly - Miranda wiki) page
+
+[Service:Help/WebsiteCommand]
+wparam=0
+lparam=0
+descr=Go to Miranda Homepage
+
+[Service:Help/BugCommand]
+wparam=0
+lparam=0
+descr=Open bug report page
+
+[Service:History/ShowContactHistory]
+alias=MS_HISTORY_SHOWCONTACTHISTORY
+wparam=0 System|hContact
+lparam=0
+descr=Shows contact history or (wParam=0) system history
+
+[Service:History++/EmptyHistory]
+alias=MS_HPP_EMPTYHISTORY
+wparam=hContact
+lparam=0
+plugin=History++ (historypp.dll)
+descr=Erases contact's history. hContact can be NULL(0) to empty system history
+
+[Service:History++/ShowGlobalSearch]
+alias=MS_HPP_SHOWGLOBALSEARCH
+wparam=0
+lparam=0
+plugin=History++ (historypp.dll)
+descr=Show Global history search window. If already opened, bring it to front.
+
+[Service:Ignore/Ignore]
+alias=MS_IGNORE_IGNORE
+wparam=hContact
+lparam=-1 Ignore all|1 Ignore messages|2 Ignore URLs|3 Ignore files|4 Ignore User Online|5 Ignore requests|6 Ignore 'You were added'
+return=int 0, if successful
+descr=Ignore Contact
+
+[Service:Ignore/Unignore]
+alias=MS_IGNORE_UNIGNORE
+wparam=hContact
+lparam=-1 Ignore all|1 Ignore messages|2 Ignore URLs|3 Ignore files|4 Ignore User Online|5 Ignore requests|6 Ignore 'You were added'
+return=int 0, if successful
+descr=Unignore Contact
+
+[Service:Miranda/System/Restart]
+alias=MS_SYSTEM_RESTART
+wparam=0 restart in default profile or profile manager|1 restart with current profile
+lparam=0
+descr=Restarts Miranda
+
+[Service:mRadio/PlayStop]
+alias=MS_RADIO_PLAYSTOP
+wparam=hContact|Station name
+lparam=0 wParam is Handle|1 wParam is Ansi station name|2 wParam is Unicode station name
+descr=Starting or stopping radio station
+
+[Service:MyDetails/CicleThroughtProtocols]
+alias=MS_MYDETAILS_CICLE_THROUGHT_PROTOCOLS
+wparam=0 Stop cycle|1 Start cycle
+lparam=0
+return=int 0, if successful
+plugin=My Details (mydetails.dll)
+descr=Start/stops the cycling throught protocols
+
+[Service:MyDetails/SetMyAvatarUI]
+alias=MS_MYDETAILS_SETMYAVATARUI
+wparam=0
+lparam=0 All protocols|Protocol
+return=signed -2 if proto can't set this, -1 on protocol not found, else 0
+plugin=My Details (mydetails.dll)
+descr=Shows a dialog to set the avatar for all possible protocols
+
+[Service:MyDetails/ShowNextProtocol]
+alias=MS_MYDETAILS_SHOWNEXTPROTOCOL
+wparam=0
+lparam=0
+return=int 0, if successful
+plugin=My Details (mydetails.dll)
+descr=Shows the next protocol in the frame
+
+[Service:MyDetails/ShowPreviousProtocol]
+alias=MS_MYDETAILS_SHOWPREVIOUSPROTOCOL
+wparam=0
+lparam=0
+return=int 0, if successful
+plugin=My Details (mydetails.dll)
+descr=Shows the previous protocol in the frame
+
+[Service:Options/OptionsCommand]
+wparam=0
+lparam=0
+descr=Open Options dialog
+
+[Service:Opt/OpenOptions]
+alias=MS_OPT_OPENOPTIONS
+wparam=0
+lparam=structure|0|dword|b.ptr|b.ptr|b.ptr|
+return=int 0, if successful
+descr=Opens the options dialog, optionally at the specified page
+
+[Service:PackUpdater/CheckUpdates]
+wparam=0
+lparam=0
+plugin=Pack Updater (packupdater.dll)
+descr=Check for updates
+
+[Service:PackUpdater/EmptyFolder]
+wparam=0
+lparam=0 with confirmation| 1 - without confirmation
+plugin=Pack Updater (packupdater.dll)
+descr=Empty updater download folder
+
+[Service:Popup/EnableDisableMenuCommand]
+wparam=0
+lparam=0
+plugin=Popup Plus (popup.dll)
+descr=Enables or disables PopUp windows
+
+[Service:Popup/ShowMessage]
+alias=MS_POPUP_SHOWMESSAGE
+wparam=Ansi Text
+lparam=1 Warning|2 Notify|3 Error
+return=int 0, if successful
+plugin=YAPP or PopUp
+descr=Popup window
+
+[Service:Popup/ShowMessageW]
+alias=MS_POPUP_SHOWMESSAGEW
+wparam=Unicode Text
+lparam=1 Warning|2 Notify|3 Error
+return=int 0, if successful
+plugin=YAPP only
+descr=Popup window
+
+[Service:Popup/ToggleEnabled]
+wparam=0
+lparam=0
+plugin=YAPP (yapp.dll)
+descr=Enables or disables PopUp windows
+
+[Service:Proto/CallContactService]
+alias=MS_PROTO_CALLCONTACTSERVICE
+wparam=0
+lparam=structure|0|native|b.ptr|native|native|
+return=result of protocol service call
+descr=send a general request through the protocol chain for a contact
+
+[Service:Protos/ShowAccountManager]
+alias=MS_PROTO_SHOWACCMGR
+wparam=0
+lparam=0
+descr=displays the Account Manager
+
+[Service:QuickContacts/ShowDialog]
+alias=MS_QC_SHOW_DIALOG
+wparam=0
+lparam=0
+plugin=Quick Contacts (quickcontacts.dll)
+descr=Show the dialog to select the contact
+
+[Service:QuickSearch_PLUGIN/Show]
+wparam=0|filter text
+lparam=0 wParam is unicode|1 wParam is Ansi|2 Reserved
+plugin=Quick Search (Mod) (quicksearch.dll)
+descr=
+
+[Service:Skin/Sounds/Play]
+alias=MS_SKIN_PLAYSOUND
+wparam=0
+lparam=Name
+descr=Plays sound added through Skin/Sounds/AddNew. If sound not found, standard Windows sound plays
+
+[Service:SREMail/SendCommand]
+alias=MS_EMAIL_SENDEMAIL
+wparam=hContact
+lparam=0
+return=int 0, if successful
+descr=Send Email to contact
+
+[Service:SRFile/GetReceivedFilesFolder]
+alias=MS_FILE_GETRECEIVEDFILESFOLDER
+wparam=hContact
+lparam=structure|*b.arr 300|
+return=struct
+descr=Returns the received files folder for a contact
+
+[Service:SRFile/OpenContRecDir]
+wparam=hContact
+lparam=0
+descr=Open contact received file directory
+
+[Service:SRFile/SendCommand]
+alias=MS_FILE_SENDFILE
+wparam=hContact
+lparam=0
+return=int 0, if successful
+descr=Send file to contact.
+
+[Service:SRMsg/SendCommand]
+alias=MS_MSG_SENDMESSAGE
+wparam=hContact;parameter
+lparam=0
+descr=Opens message window for contact with handle in wparam
+
+[Service:StopSpam/RemoveTempContacts]
+alias=MS_STOPSPAM_REMTEMPCONTACTS
+wparam=0
+lparam=0
+return=int 0
+plugin=StopSpam (stopspam.dll)
+descr=remove all temporary contacts from db
+
+[Service:SV_Avatars/ContactOptions]
+alias=MS_AV_CONTACTOPTIONS
+wparam=hContact
+lparam=0
+plugin=Avatar service (AVS.dll)
+descr=Call avatar option dialog for contact
+
+[Service:SV_Avatars/SetAvatar]
+alias=MS_AV_SETAVATAR
+wparam=hContact
+lparam=0|Filename
+plugin=Avatar service (AVS.dll)
+descr=Set (and optionally protect) a local contact picture for the given hContact. If lParam = NIL, the service will open a file selection dialog.
+
+[Service:UserInfo/ShowDialog]
+alias=MS_USERINFO_SHOWDIALOG
+wparam=0 System|hContact
+lparam=0
+plugin=Extended UserInfo (uinfoex.dll)
+descr=Shows contact property window.
+
+[Service:Utils/OpenURL]
+alias=MS_UTILS_OPENURL
+wparam=0 Open URL in current window
+lparam=URL
+return=int 0
+descr=Open URL in default browser
+
+[Service:Versioninfo/GetInfo]
+alias=MS_VERSIONINFO_GETINFO
+wparam=0 With formating|1 Don't use formating
+lparam=structure|*b.ptr 0|
+plugin=VersionInfo
+return=int 0, if succesful
+descr=Returns a string containing the versioninfo post
+
+[Service:VersionInfo/MenuCommand]
+alias=MS_VERSIONINFO_MENU_COMMAND
+wparam=0
+lparam=0
+plugin=VersionInfo
+descr=Show or save (call default action) Modules version Info
+
+[Service:WATrack/ShowMusicInfo]
+alias=MS_WAT_SHOWMUSICINFO
+wparam=0
+lparam=0
+plugin=Winamp Track (watrack.dll)
+descr=Show popup or Info window with current music information.
+
+[Service:WATrack/MakeReport]
+alias=MS_WAT_MAKEREPORT
+wparam=log filename|
+lparam=report filename|
+return=int 0, if unsuccessful
+plugin=Winamp Track (watrack.dll)
+descr=Create report from log and run it (if option is set). If wParam or lParam is empty then file names from options are used.
+
+[Service:WhenWasIt/List/Show]
+alias=MS_WWI_LIST_SHOW
+wparam=0
+lparam=0
+plugin=WhenWasIt Birthday Reminder (whenwasit.dll)
+descr=display birthdays window
+
+[Service:<proto>/Bookmarks]
+wparam=0
+lparam=0
+plugin=Jabber
+descr=Manage Jabber Bookmarks
+
+[Service:<proto>/SetAwayMsg]
+alias=PS_SETAWAYMSG
+wparam=40071 Offline|40072 Online|40073 Away|40074 DND|40075 NA|40076 Occupied|40077 Free for Chat|40078 Invisible|40079 On the Phone|40080 Out to Lunch
+lparam=text
+return=int 0, if successful
+descr=Set status message
+
+[Service:<proto>/SetStatus]
+alias=PS_SETSTATUS
+wparam=40071 Offline|40072 Online|40073 Away|40074 DND|40075 NA|40076 Occupied|40077 Free for Chat|40078 Invisible|40079 On the Phone|40080 Out to Lunch
+lparam=0
+return=int 0, if successful
+descr=Set protocol status
+
+[Service:<proto>/SetXStatus]
+alias=PS_ICQ_SETCUSTOMSTATUS
+;alias=JS_SETXSTATUSEX
+wparam=0 None|1 Angry|2 Taking a bath|3 Tired|4 Party|5 Drinking beer|6 Thinking|7 Eating|8 Watching TV|9 Meeting|10 Coffee|11 Listening to music|12 Business|13 Shooting|14 Having fun|15 On the phone|16 Gaming|17 Studying|18 Shopping|19 Feeling sick|20 Sleeping|21 Surfing|22 Browsing|23 Working|24 Typing|25 Picnic|26 Cooking|27 Smoking|28 I'm high|29 On WC|30 To be or not to be|31 Watching pro7 on TV|32 Love
+lparam=0
+plugin=ICQ
+descr=Sets owner current custom status
+
+[Service:<proto>/ShowXStatusDetails]
+alias=MS_XSTATUS_SHOWDETAILS
+wparam=0|hContact
+lparam=0
+plugin=ICQ
+descr=Display XStatus detail
+
+[Event:Actions/Changed]
+alias=ME_ACT_CHANGED
+plugin=ActMan
+descr='action group list was changed: some was added or deleted'
+wparam=ACTM_NEW|ACTM_DELETE|ACTM_RELOAD|ACTM_RENAME|ACTM_SORT|ACTM_LOADED
+lparam=0
+
+[Event:CList/PreBuildContactMenu]
+alias=ME_CLIST_PREBUILDCONTACTMENU
+plugin=contact list
+descr='the context menu for a contact is about to be built'
+wparam=hContact
+lparam=0
+
+[Event:CList/DoubleClicked]
+alias=ME_CLIST_DOUBLECLICKED
+plugin=contact list
+descr='double click on the CList'
+wparam=hContact
+lparam=0
+
+[Event:DB/Contact/Added]
+alias=ME_DB_CONTACT_ADDED
+plugin=database driver
+descr='New contact added to database'
+wparam=hContact
+lparam=0
+
+[Event:DB/Contact/Deleted]
+alias=ME_DB_CONTACT_DELETED
+plugin=database driver
+descr='Contact deleting'
+wparam=hContact
+lparam=0
+
+[Structure:CCSDATA]
+; variant: Handle -> param
+full=0| \
+param (HANDLE) hContact| \
+b.ptr (const char *) szProtoService| \
+native (WPARAM) wParam| \
+native (LPARAM) lParam|
+short=0|param|b.ptr|native|native|
+descr=
+plugin=
+
+[Const:CALLSERVICE_NOTFOUND]
+value=$80000000
+value64=$8000000000000000
+;signed=0
+;plugin=core
+
+[Const:ID_STATUS_OFFLINE]
+value=40071
+[Const:ID_STATUS_ONLINE]
+value=40072
+[Const:ID_STATUS_AWAY]
+value=40073
+[Const:ID_STATUS_DND]
+value=40074
+[Const:ID_STATUS_NA]
+value=40075
+[Const:ID_STATUS_OCCUPIED]
+value=40076
+[Const:ID_STATUS_FREECHAT]
+value=40077
+[Const:ID_STATUS_INVISIBLE]
+value=40078
+[Const:ID_STATUS_ONTHEPHONE]
+value=40079
+[Const:ID_STATUS_OUTTOLUNCH]
+value=40080
+[Const:ID_STATUS_IDLE]
+value=40081
diff --git a/plugins/Actman30/tasks/i_opt_dlg.inc b/plugins/Actman30/tasks/i_opt_dlg.inc
new file mode 100644
index 0000000000..c8025c278d
--- /dev/null
+++ b/plugins/Actman30/tasks/i_opt_dlg.inc
@@ -0,0 +1,536 @@
+{}
+const
+ settings:HWND = 0;
+
+var
+ OldTableProc:pointer;
+ onactchanged:THANDLE;
+
+const
+ ACI_NEW :PAnsiChar = 'ACI_New';
+ ACI_DELETE :PAnsiChar = 'ACI_Delete';
+
+procedure CheckTaskList(Dialog:HWND;enable:boolean);
+begin
+ if not enable then
+ enable:=SendMessage(GetDlgItem(Dialog,IDC_TASK_NAME),LVM_GETITEMCOUNT,0,0)>0;
+
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_ABSOLUTE ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_DATEV ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_DAYSV ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_TIMEV ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_REPEAT ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_INTERVAL ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_BREAK ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_EVENT ),enable);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_ONCE ),enable);
+ if not enable then
+ begin
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DAYST),SW_HIDE);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DAYSV),SW_HIDE);
+ end;
+end;
+
+procedure FillTaskList(wnd:HWND);
+var
+ i:integer;
+ li:LV_ITEMW;
+begin
+ SendMessage(wnd,LVM_DELETEALLITEMS,0,0);
+ for i:=0 to MaxTasks-1 do
+ begin
+ with TaskList[i] do
+ begin
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ li.mask :=LVIF_TEXT+LVIF_PARAM;
+ li.iSubItem:=0;
+ li.iItem :=i;
+ li.lParam :=i;
+ li.pszText :=name;
+ li.iItem :=SendMessageW(wnd,LVM_INSERTITEMW,0,LPARAM(@li));
+ ListView_SetCheckState(wnd,li.iItem,(flags and ACF_DISABLED)=0);
+ end;
+ end;
+ end;
+ ListView_SetItemState(wnd,0,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+end;
+
+procedure ClearTaskData(Dialog:HWND);
+var
+ st:TSystemTime;
+begin
+ SendMessage(GetDlgItem(Dialog,IDC_TASK_ABSOLUTE),CB_SETCURSEL,0,0);
+ CheckDlgButton(Dialog,IDC_TASK_BREAK ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_TASK_EVENT ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_TASK_ONCE ,BST_UNCHECKED);
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_ONCE),false);
+
+ SetDlgItemInt(Dialog,IDC_TASK_DAYSV ,1,false);
+ SetDlgItemInt(Dialog,IDC_TASK_REPEAT,0,false);
+
+ FillChar(st,SizeOf(st),0);
+ SendDlgItemMessage(Dialog,IDC_TASK_TIMEV ,DTM_SETSYSTEMTIME,GDT_VALID,lParam(@st));
+ SendDlgItemMessage(Dialog,IDC_TASK_INTERVAL,DTM_SETSYSTEMTIME,GDT_VALID,lParam(@st));
+{
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DATET),SW_SHOW);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DATEV),SW_SHOW);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DAYST),SW_HIDE);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DAYSV),SW_HIDE);
+}
+end;
+
+procedure ShowDateType(Dialog:HWND;start:integer);
+var
+ sh1,sh2,sh3:integer;
+begin
+ case start of
+ 1: begin // start after
+ sh1:=SW_HIDE;
+ sh2:=SW_SHOW;
+ sh3:=SW_SHOW;
+ end;
+ 2: begin // start from
+ sh1:=SW_SHOW;
+ sh2:=SW_HIDE;
+ sh3:=SW_SHOW;
+ end;
+ else
+ begin
+// 3: begin // start immediately
+ sh1:=SW_HIDE;
+ sh2:=SW_HIDE;
+ sh3:=SW_HIDE;
+ end;
+ end;
+
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DATET),sh1);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DATEV),sh1);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DAYST),sh2);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_DAYSV),sh2);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_TIMET),sh3);
+ ShowWindow(GetDlgItem(Dialog,IDC_TASK_TIMEV),sh3);
+end;
+
+procedure ShowTaskData(Dialog:HWND; item:integer=-1);
+var
+ st:TSystemTime;
+ lwnd:HWND;
+ start:integer;
+begin
+ lwnd:=settings;
+ settings:=0;
+
+ ClearTaskData(Dialog);
+
+ with TaskList[LV_GetLParam(GetDlgItem(Dialog,IDC_TASK_NAME),item)] do
+ begin
+ // flags
+
+ if (flags and TCF_NONZEROBREAK)<>0 then
+ CheckDlgButton(Dialog,IDC_TASK_BREAK,BST_CHECKED);
+ if (flags and TCF_MAKEEVENT)<>0 then
+ CheckDlgButton(Dialog,IDC_TASK_EVENT,BST_CHECKED);
+ if (flags and TCF_EVENTONCE)<>0 then
+ CheckDlgButton(Dialog,IDC_TASK_ONCE,BST_CHECKED);
+
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_ONCE),
+ IsDlgButtonChecked(Dialog,IDC_TASK_EVENT)<>BST_UNCHECKED);
+
+ // action
+ CB_SelectData(GetDlgItem(Dialog,IDC_TASK_ACTION),action);
+ // times
+ FileTimeToSystemTime(starttime,st);
+
+ if (flags and TCF_IMMEDIATELY)<>0 then
+ begin
+ start:=3;
+ end
+ else if (flags and TCF_ABSOLUTE)<>0 then
+ begin
+ start:=2;
+ SendDlgItemMessage(Dialog,IDC_TASK_DATEV,DTM_SETSYSTEMTIME,GDT_VALID,lParam(@st))
+ end
+ else
+ begin
+ start:=1;
+ SetDlgItemInt(Dialog,IDC_TASK_DAYSV,dayoffset,false);
+ end;
+ CB_SelectData(GetDlgItem(Dialog,IDC_TASK_ABSOLUTE),start);
+
+ SendDlgItemMessage(Dialog,IDC_TASK_TIMEV,DTM_SETSYSTEMTIME,GDT_VALID,lParam(@st));
+
+ SetDlgItemInt(Dialog,IDC_TASK_REPEAT,count,true);
+
+ FileTimeToSystemTime(interval,st);
+ SendDlgItemMessage(Dialog,IDC_TASK_INTERVAL,DTM_SETSYSTEMTIME,GDT_VALID,lParam(@st));
+ SetDlgItemInt(Dialog,IDC_TASK_INTDAYS,intdays,false);
+ end;
+
+ ShowDateType(Dialog,start);
+
+ settings:=lwnd;
+end;
+
+procedure SaveTaskData(Dialog:HWND; item:integer=-1);
+var
+ wnd:HWND;
+ li:LV_ITEM;
+ st,st1:TSystemTime;
+ tmp:longbool;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_TASK_NAME);
+
+ if item<0 then
+ li.iItem:=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED) // LVNI_SELECTED
+ else
+ li.iItem:=item;
+
+ if li.iItem>=0 then
+ begin
+ li.mask :=LVIF_PARAM;
+ li.iSubItem :=0;
+ SendMessageW(wnd,LVM_GETITEMW,0,LPARAM(@li));
+
+ with TaskList[li.lParam] do
+ begin
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ flags:=ACF_ASSIGNED;
+ // flags
+ if ListView_GetCheckState(wnd,li.iItem)=0 then
+ flags:=flags or ACF_DISABLED;
+
+ if IsDlgButtonChecked(Dialog,IDC_TASK_BREAK)<>BST_UNCHECKED then
+ flags:=flags or TCF_NONZEROBREAK;
+ if IsDlgButtonChecked(Dialog,IDC_TASK_EVENT)<>BST_UNCHECKED then
+ begin
+ flags:=flags or TCF_MAKEEVENT;
+ if IsDlgButtonChecked(Dialog,IDC_TASK_ONCE )<>BST_UNCHECKED then
+ flags:=flags or TCF_EVENTONCE;
+ end;
+ // action
+ action:=CB_GetData(GetDlgItem(Dialog,IDC_TASK_ACTION));
+ // times
+ SendDlgItemMessage(Dialog,IDC_TASK_TIMEV,DTM_GETSYSTEMTIME,0,lParam(@st));
+
+ case CB_GetData(GetDlgItem(Dialog,IDC_TASK_ABSOLUTE)) of
+ 1: begin
+ dayoffset:=GetDlgItemInt(Dialog,IDC_TASK_DAYSV,tmp,false);
+ end;
+ 2: begin
+ flags:=flags or TCF_ABSOLUTE;
+ SendDlgItemMessage(Dialog,IDC_TASK_DATEV,DTM_GETSYSTEMTIME,0,lParam(@st1));
+ st.wYear :=st1.wYear;
+ st.wMonth :=st1.wMonth;
+ st.wDayOfWeek:=st1.wDayOfWeek;
+ st.wDay :=st1.wDay;
+ end;
+ 3: begin
+ flags:=flags or TCF_IMMEDIATELY;
+ end;
+ end;
+ SystemTimeToFileTime(st,starttime);
+
+ count:=GetDlgItemInt(Dialog,IDC_TASK_REPEAT,tmp,true);
+
+ SendDlgItemMessage(Dialog,IDC_TASK_INTERVAL,DTM_GETSYSTEMTIME,0,lParam(@st));
+ SystemTimeToFileTime(st,interval);
+ intdays:=GetDlgItemInt(Dialog,IDC_TASK_INTDAYS,tmp,false);
+ end;
+ end;
+ end;
+end;
+
+function NewTask(Dialog:HWND;item:integer=-1):integer;
+var
+ wnd:HWND;
+ li:LV_ITEMW;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_TASK_NAME);
+ if item<0 then
+ li.iItem :=SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED)+1
+ else
+ li.iItem :=item;
+ li.iSubItem:=0;
+ li.mask :=LVIF_TEXT + LVIF_PARAM;
+ li.lParam :=CreateNewTask;
+ li.pszText :=TranslateW('Task sample');
+ result:=SendMessageW(wnd,LVM_INSERTITEMW,0,LPARAM(@li));
+
+ ListView_SetCheckState(wnd,li.iItem,
+ (TaskList[li.lParam].flags and ACF_DISABLED)=0);
+ StrDupW(TaskList[li.lParam].name,li.pszText);
+
+ CheckTaskList(Dialog,true);
+
+ if li.iItem=0 then
+ Listview_SetItemState(wnd,0,LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+end;
+
+function DeleteTask(Dialog:HWND):integer;
+var
+ li:LV_ITEM;
+ wnd:HWND;
+ i:integer;
+begin
+ result:=0;
+ wnd:=GetDlgItem(Dialog,IDC_TASK_NAME);
+ for i:=ListView_GetItemCount(wnd)-1 downto 0 do
+ begin
+ if ListView_GetItemState(wnd,i,LVIS_SELECTED)<>0 then
+ begin
+ li.iItem :=i;
+ li.mask :=LVIF_PARAM;
+ li.iSubItem :=0;
+ SendMessageW(wnd,LVM_GETITEMW,0,LPARAM(@li));
+
+ TaskList[li.lParam].flags:=TaskList[li.lParam].flags and not ACF_ASSIGNED;
+
+ SendMessage(wnd,LVM_DELETEITEM,i,0);
+ end;
+ end;
+ Listview_SetItemState(wnd,0,LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+
+ CheckTaskList(Dialog,false);
+end;
+
+function NewHKTableProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_KEYDOWN: begin
+ if (lParam and (1 shl 30))=0 then
+ begin
+ case wParam of
+ VK_F2: begin
+ i:=SendMessage(Dialog,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ if i>=0 then
+ PostMessageW(Dialog,LVM_EDITLABELW,i,0);
+ exit;
+ end;
+
+ VK_INSERT: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_TASK_NEW,0);
+ exit;
+ end;
+
+ VK_DELETE: begin
+ PostMessage(GetParent(Dialog),WM_COMMAND,(BN_CLICKED shl 16)+IDC_TASK_DELETE,0);
+ exit;
+ end;
+ end;
+ end;
+ end;
+ end;
+ result:=CallWindowProc(OldTableProc,Dialog,hMessage,wParam,lParam);
+end;
+
+procedure FillStartTimeList(wnd:HWND);
+begin
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ CB_AddStrDataW(wnd,TranslateW('Starting after' ),1);
+ CB_AddStrDataW(wnd,TranslateW('Starting from' ),2);
+ CB_AddStrDataW(wnd,TranslateW('Start immediately'),3);
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+end;
+
+procedure FillActionList(wnd:HWND);
+var
+ ptr,ptr1:pChain;
+ i,cnt:integer;
+begin
+ cnt:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+ if cnt>0 then
+ begin
+ ptr1:=ptr;
+ inc(pbyte(ptr),4);
+ for i:=0 to cnt-1 do
+ begin
+ CB_AddStrDataW(wnd,ptr^.descr,ptr^.id);
+ inc(ptr);
+ end;
+
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+ end;
+end;
+
+function ActListChange(wParam:WPARAM;lParam:LPARAM):integer; cdecl;
+begin
+ result:=0;
+ if settings<>0 then
+ FillActionList(GetDlgItem(settings,IDC_TASK_ACTION));
+end;
+
+procedure SetIcons(Dialog:HWND);
+var
+ ti:TTOOLINFOW;
+ hwndTooltip:HWND;
+begin
+ hwndTooltip:=CreateWindowW(TOOLTIPS_CLASS,nil,TTS_ALWAYSTIP,
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ Dialog,0,hInstance,nil);
+
+ FillChar(ti,SizeOf(ti),0);
+ ti.cbSize :=sizeof(TOOLINFO);
+ ti.uFlags :=TTF_IDISHWND or TTF_SUBCLASS;
+ ti.hwnd :=dialog;
+ ti.hinst :=hInstance;
+{
+ ti.uId :=GetDlgItem(Dialog,IDC_EVENT_HELP);
+ ti.lpszText:=TranslateW('Help');
+ SendMessage(ti.uId,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+}
+ ti.uId :=GetDlgItem(Dialog,IDC_TASK_NEW);
+ ti.lpszText:=TranslateW('New');
+ SetButtonIcon(ti.uId,ACI_NEW);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+
+ ti.uId :=GetDlgItem(Dialog,IDC_TASK_DELETE);
+ ti.lpszText:=TranslateW('Delete');
+ SetButtonIcon(ti.uId,ACI_DELETE);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,LPARAM(@ti));
+end;
+
+function DlgProcOpt(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ wnd:HWND;
+ lv:LV_COLUMNW;
+ li:LV_ITEMW;
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_CLOSE: begin
+ UnhookEvent(onactchanged);
+ settings:=0;
+ end;
+
+ WM_INITDIALOG: begin
+ settings:=0;
+ wnd:=GetDlgItem(Dialog,IDC_TASK_NAME);
+ SendMessage(wnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_CHECKBOXES,LVS_EX_CHECKBOXES);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ zeromemory(@lv,sizeof(lv));
+ lv.mask:=LVCF_WIDTH;
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW ,0,tlparam(@lv));
+ SendMessageW(wnd,LVM_SETCOLUMNWIDTH,0,LVSCW_AUTOSIZE_USEHEADER);
+
+ CreateUpDownControl(
+ WS_CHILD+WS_BORDER+WS_VISIBLE+UDS_ARROWKEYS+UDS_SETBUDDYINT+UDS_ALIGNRIGHT,
+ 190,112,14,18,
+ Dialog, IDC_TASK_UPDOWN, hInstance, GetDlgItem(Dialog,IDC_TASK_REPEAT),
+ 10000, -1, 0);
+
+ OldTableProc:=pointer(SetWindowLongPtrW(wnd,GWL_WNDPROC,LONG_PTR(@NewHKTableProc)));
+ TranslateDialogDefault(Dialog);
+
+ SetIcons(Dialog);
+
+ FillActionList(GetDlgItem(Dialog,IDC_TASK_ACTION));
+ FillStartTimeList(GetDlgItem(Dialog,IDC_TASK_ABSOLUTE));
+ FillTaskList(wnd);
+ CheckTaskList(Dialog,false);
+ onactchanged:=HookEvent(ME_ACT_CHANGED,@ActListChange);
+ settings:=Dialog;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ CBN_SELCHANGE: begin
+ ShowDateType(Dialog,CB_GetData(lParam));
+ end;
+
+ EN_CHANGE: begin
+ end;
+
+ BN_CLICKED: begin
+ case loword(wParam) of
+ IDC_TASK_NEW : NewTask(Dialog);
+ IDC_TASK_DELETE: DeleteTask(Dialog);
+
+ IDC_TASK_EVENT: begin
+ EnableWindow(GetDlgItem(Dialog,IDC_TASK_ONCE),
+ IsDlgButtonChecked(Dialog,IDC_TASK_EVENT)<>BST_UNCHECKED);
+ end;
+ end;
+ end;
+ end;
+ if settings<>0 then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ WM_NOTIFY: begin
+ case integer(PNMHdr(lParam)^.code) of
+ PSN_APPLY: begin
+ SaveTaskData(Dialog);
+ SaveTasks;
+ SetAllTasks;
+ end;
+
+ DTN_DATETIMECHANGE: begin
+ if settings<>0 then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ NM_DBLCLK: begin
+ if PNMListView(lParam)^.iItem>=0 then
+ PostMessageW(PNMHdr(lParam)^.hWndFrom,LVM_EDITLABELW,
+ PNMListView(lParam)^.iItem,0);
+ end;
+
+ LVN_ITEMCHANGED: begin
+ if PNMLISTVIEW(lParam)^.uChanged=LVIF_STATE then
+ begin
+ i:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_FOCUSED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_FOCUSED);
+
+ if i>0 then // old focus
+ SaveTaskData(Dialog,PNMLISTVIEW(lParam)^.iItem)
+ else if i<0 then // new focus
+ begin
+ ShowTaskData(Dialog,PNMLISTVIEW(lParam)^.iItem);
+ end
+ else if (settings<>0) and
+ ((PNMLISTVIEW(lParam)^.uOldState or PNMLISTVIEW(lParam)^.uNewState)=$3000) then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ LVN_ENDLABELEDITW: begin
+ with PLVDISPINFOW(lParam)^ do
+ begin
+ if item.pszText<>nil then
+ begin
+ item.mask:=LVIF_TEXT;
+ SendMessageW(hdr.hWndFrom,LVM_SETITEMW,0,TLPARAM(@item));
+
+ li.iItem :=item.iItem;
+ li.mask :=LVIF_PARAM;
+ li.iSubItem :=0;
+ SendMessageW(hdr.hWndFrom,LVM_GETITEMW,0,TLPARAM(@li));
+ with TaskList[li.lParam] do
+ begin
+ mFreeMem(name);
+ StrDupW (name,item.pszText);
+ end;
+ end;
+ end;
+ result:=1;
+ end;
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/tasks/i_options.inc b/plugins/Actman30/tasks/i_options.inc
new file mode 100644
index 0000000000..527e8d0c88
--- /dev/null
+++ b/plugins/Actman30/tasks/i_options.inc
@@ -0,0 +1,99 @@
+{}
+const
+ opt_task :PAnsiChar = 'Task';
+ opt_tasks :PAnsiChar = 'Tasks';
+ opt_count :PAnsiChar = 'numtasks';
+
+ opt_name :PAnsiChar = 'name';
+ opt_flags :PAnsiChar = 'flags';
+ opt_action :PAnsiChar = 'action';
+ opt_repeat :PAnsiChar = 'repeat';
+ opt_days :PAnsiChar = 'dayoffset';
+ opt_intdays :PAnsiChar = 'intdays';
+
+ opt_time_lo :PAnsiChar = 'starttime_lo';
+ opt_time_hi :PAnsiChar = 'starttime_hi';
+ opt_interval_lo:PAnsiChar = 'interval_lo';
+ opt_interval_hi:PAnsiChar = 'interval_hi';
+ opt_lastcall_lo:PAnsiChar = 'lastcall_lo';
+ opt_lastcall_hi:PAnsiChar = 'lastcall_hi';
+
+procedure SaveTasks;
+var
+ section:array [0..63] of AnsiChar;
+ p,p1:PAnsiChar;
+ i,amount:integer;
+begin
+ DBDeleteGroup(0,DBBranch,opt_tasks);
+ amount:=0;
+ p1:=StrCopyE(section,opt_tasks);
+ p1^:='/'; inc(p1);
+ p1:=StrCopyE(p1,opt_task);
+ for i:=0 to MaxTasks-1 do
+ begin
+ if (TaskList[i].flags and ACF_ASSIGNED)=0 then
+ continue;
+
+ p:=StrEnd(IntToStr(p1,amount));
+ p^:='/'; inc(p);
+ with TaskList[i] do
+ begin
+ StrCopy(p,opt_flags ); DBWriteDWord (0,DBBranch,section,flags);
+ StrCopy(p,opt_name ); DBWriteUnicode(0,DBBranch,section,name);
+ StrCopy(p,opt_action); DBWriteDWord (0,DBBranch,section,action);
+ StrCopy(p,opt_repeat); DBWriteWord (0,DBBranch,section,count);
+ StrCopy(p,opt_days ); DBWriteByte (0,DBBranch,section,dayoffset);
+ //systemtime to filetime if needs
+ StrCopy(p,opt_time_lo ); DBWriteDWord(0,DBBranch,section,starttime.dwLowDateTime);
+ StrCopy(p,opt_time_hi ); DBWriteDWord(0,DBBranch,section,starttime.dwHighDateTime);
+ StrCopy(p,opt_interval_lo); DBWriteDWord(0,DBBranch,section,interval .dwLowDateTime);
+ StrCopy(p,opt_interval_hi); DBWriteDWord(0,DBBranch,section,interval .dwHighDateTime);
+ StrCopy(p,opt_intdays ); DBWriteByte (0,DBBranch,section,intdays);
+ StrCopy(p,opt_lastcall_lo); DBWriteDWord(0,DBBranch,section,lastcall .dwLowDateTime);
+ StrCopy(p,opt_lastcall_hi); DBWriteDWord(0,DBBranch,section,lastcall .dwHighDateTime);
+ end;
+ inc(amount);
+ end;
+ DBWriteByte(0,DBBranch,opt_count,amount);
+end;
+
+function LoadTasks:integer;
+var
+ section:array [0..63] of AnsiChar;
+ p,p1:PAnsiChar;
+ i:integer;
+begin
+ MaxTasks:=DBReadByte(0,DBBranch,opt_count);
+ result:=MaxTasks;
+ if MaxTasks>0 then
+ begin
+ GetMem (TaskList ,MaxTasks*SizeOf(tTaskRec));
+ FillChar(TaskList^,MaxTasks*SizeOf(tTaskRec),0);
+ p1:=StrCopyE(section,opt_tasks);
+ p1^:='/'; inc(p1);
+ p1:=StrCopyE(p1,opt_task);
+ for i:=0 to MaxTasks-1 do
+ begin
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p);
+
+ with TaskList[i] do
+ begin
+ StrCopy(p,opt_flags ); flags :=DBReadDWord (0,DBBranch,section);
+ StrCopy(p,opt_name ); name :=DBReadUnicode(0,DBBranch,section);
+ StrCopy(p,opt_action); action :=DBReadDWord (0,DBBranch,section);
+ StrCopy(p,opt_days ); dayoffset:=DBReadByte (0,DBBranch,section);
+ StrCopy(p,opt_repeat); count :=Shortint(DBReadWord(0,DBBranch,section));
+
+ StrCopy(p,opt_time_lo ); starttime.dwLowDateTime :=DBReadDWord(0,DBBranch,section);
+ StrCopy(p,opt_time_hi ); starttime.dwHighDateTime:=DBReadDWord(0,DBBranch,section);
+ StrCopy(p,opt_interval_lo); interval .dwLowDateTime :=DBReadDWord(0,DBBranch,section);
+ StrCopy(p,opt_interval_hi); interval .dwHighDateTime:=DBReadDWord(0,DBBranch,section);
+ StrCopy(p,opt_intdays ); intdays:=DBReadByte(0,DBBranch,section);
+ StrCopy(p,opt_lastcall_lo); lastcall .dwLowDateTime :=DBReadDWord(0,DBBranch,section);
+ StrCopy(p,opt_lastcall_hi); lastcall .dwHighDateTime:=DBReadDWord(0,DBBranch,section);
+ // filetime to systemtime if needs
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/tasks/i_service.inc b/plugins/Actman30/tasks/i_service.inc
new file mode 100644
index 0000000000..376e75cba0
--- /dev/null
+++ b/plugins/Actman30/tasks/i_service.inc
@@ -0,0 +1,87 @@
+{}
+// wParam: 1/0 (enable/disable), lParam = task name
+// works for all tasks with same started name
+function TaskEnable(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ i,j:integer;
+begin
+ result:=0;
+ if lParam=0 then exit;
+ j:=StrLenW(pWideChar(lParam));
+
+ for i:=0 to MaxTasks-1 do
+ begin
+ if (TaskList[i].flags and ACF_ASSIGNED)<>0 then
+ begin
+ if StrCmpW(TaskList[i].name,pWideChar(lParam),j)=0 then
+ begin
+ if wParam=0 then // disable
+ begin
+ if (TaskList[i].flags and ACF_DISABLED)=0 then
+ begin
+ inc(result);
+ TaskList[i].flags:=TaskList[i].flags or ACF_DISABLED;
+ if TaskList[i].timer<>0 then
+ begin
+ KillTimer(0,TaskList[i].timer);
+ TaskList[i].timer:=0;
+ end;
+ end;
+ end
+ else
+ begin
+ if (TaskList[i].flags and ACF_DISABLED)<>0 then
+ begin
+ inc(result);
+ TaskList[i].flags:=TaskList[i].flags and not ACF_DISABLED;
+ SetTask(TaskList[i]);
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+function TaskDelete(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ i,j:integer;
+begin
+ result:=0;
+ if lParam=0 then exit;
+ j:=StrLenW(pWideChar(lParam));
+
+ for i:=0 to MaxTasks-1 do
+ begin
+ if (TaskList[i].flags and ACF_ASSIGNED)<>0 then
+ begin
+ if StrCmpW(TaskList[i].name,pWideChar(lParam),j)=0 then
+ begin
+ TaskList[i].flags:=TaskList[i].flags and not ACF_ASSIGNED;
+ end;
+ end;
+ end;
+end;
+
+function TaskCount(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ i,j:integer;
+begin
+ result:=0;
+ if lParam=0 then exit;
+ j:=StrLenW(pWideChar(lParam));
+
+ for i:=0 to MaxTasks-1 do
+ begin
+ with TaskList[i] do
+ begin
+ if (flags and ACF_ASSIGNED)<>0 then
+ begin
+ if StrCmpW(name,pWideChar(lParam),j)=0 then
+ begin
+ result:=count;
+ count:=wParam;
+ end;
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/tasks/i_task.inc b/plugins/Actman30/tasks/i_task.inc
new file mode 100644
index 0000000000..2c860db85f
--- /dev/null
+++ b/plugins/Actman30/tasks/i_task.inc
@@ -0,0 +1,242 @@
+{}
+const
+ ACF_ASSIGNED = $80000000; // Task assigned
+ ACF_DISABLED = $10000000; // Task disabled
+
+ TCF_ABSOLUTE = $00000001;
+ TCF_IMMEDIATELY = $00000002;
+ TCF_NONZEROBREAK = $00000004;
+ TCF_MAKEEVENT = $00000008;
+ TCF_EVENTONCE = $00000010;
+
+const
+ WM_RESETTASKS = WM_USER+1312;
+ WM_FIRSTTASK = WM_USER+1313;
+ WM_LASTTASK = WM_FIRSTTASK+1000;
+
+type
+ pTaskRec = ^tTaskRec;
+ tTaskRec = record
+ // option values
+ flags :dword;
+ name :PWideChar; // name for task
+ action :dword; // assigned action
+ intdays, // interval,days
+ dayoffset :integer; //!! offset, days
+ starttime, // task starttime
+ interval :TFileTime; // interval for repeat
+ count :integer; // repeat count
+ // support values
+ lastcall :TFileTime; // last timer event time
+ nextcall :TFileTime; // ?? next start time?
+ // runtime values
+ timer :uint_ptr; // timer handle
+ curcount :integer; // repeat count
+ inprocess :bool; // starting processing
+ inaction :bool; // timer event processing
+ end;
+ pTaskList = ^tTaskList;
+ tTaskList = array [0..1023] of tTaskRec;
+
+var
+ TaskList:pTaskList = nil;
+ MaxTasks:integer = 0;
+
+procedure TimerProc(wnd:HWND;uMsg:uint;idEvent:uint_ptr;dwTime:dword); stdcall;
+var
+ ltime:uint;
+ i:integer;
+ res:int_ptr;
+ st:tSystemTime;
+begin
+ for i:=0 to MaxTasks-1 do
+ begin
+ with TaskList[i] do
+ begin
+ if (flags and (ACF_ASSIGNED or ACF_DISABLED))=ACF_ASSIGNED then
+ if timer=idEvent then
+ begin
+ inaction:=true;
+ if ((flags and TCF_MAKEEVENT)<>0) and
+ (((flags and TCF_EVENTONCE) =0) or (curcount=count)) then
+ NotifyEventHooks(hevent,count-curcount,lParam(name));
+
+ GetLocalTime(st);
+ SystemTimeToFileTime(st,lastcall);
+
+ res:=CallService(MS_ACT_RUNBYID,action,0);
+
+ if ((res<>0) and ((flags and TCF_NONZEROBREAK)<>0)) or // non-zero result
+ (count=0) or (curcount=0) then // no need to repeat or all repeats done
+ begin
+ KillTimer(0,idEvent);
+ timer:=0;
+ flags:=flags or ACF_DISABLED;
+ end
+ else
+ begin
+ if (count<>0) and (count=curcount) then // next timer - repeat interval
+ begin
+ KillTimer(0,idEvent);
+ FileTimeToSystemTime(interval,st);
+ ltime:={st.wMilliseconds+}st.wSecond*1000+st.wMinute*1000*60+st.wHour*60*60*1000;
+ timer:=SetTimer(0,0,ltime,@TimerProc);
+ if count=-1 then
+ curcount:=1;
+ end;
+ if count>0 then
+ dec(curcount);
+ end;
+ inaction:=false;
+ break;
+ end;
+ end;
+ end;
+end;
+
+procedure SetTask(var task:tTaskRec);
+var
+ ltime:uint;
+ uli1,uli2:ULARGE_INTEGER;
+ sft:tFileTime;
+ st:tSystemTime;
+ dif:int64;
+begin
+ task.inprocess:=true;
+ // Check task time
+ if (task.flags and TCF_IMMEDIATELY)<>0 then
+ begin
+ FileTimeToSystemTime(task.interval,st);
+ ltime:={st.wMilliseconds+}st.wSecond*1000+st.wMinute*1000*60+
+ st.wHour*60*60*1000;
+ end
+ else if (task.flags and TCF_ABSOLUTE)<>0 then
+ begin
+ uli1.LowPart :=task.starttime.dwLowDateTime;
+ uli1.HighPart:=task.starttime.dwHighDateTime;
+ GetLocalTime(st);
+ SystemTimeToFileTime(st,sft);
+ uli2.LowPart :=sft.dwLowDateTime;
+ uli2.HighPart:=sft.dwHighDateTime;
+ dif:=uli1.QuadPart-uli2.QuadPart;
+ if dif>0 then // time in future
+ ltime:=dif div 10000 // 100ns to 1 ms
+ else // was in past
+ begin
+ task.flags:=task.flags or ACF_DISABLED;
+ exit;
+ end;
+ end
+ else
+ begin
+ // days+hours+minutes+seconds+millseconds
+ FileTimeToSystemTime(task.starttime,st);
+ ltime:={st.wMilliseconds+}st.wSecond*1000+st.wMinute*1000*60+
+ st.wHour*60*60*1000+task.dayoffset*24*60*60*1000;
+ end;
+ // set timer
+ task.curcount:=task.count;
+ task.timer :=SetTimer(0,0,ltime,@TimerProc);
+
+ if (task.flags and TCF_IMMEDIATELY)<>0 then
+ TimerProc(0,WM_TIMER,task.timer,0);
+ task.inprocess:=false;
+end;
+
+procedure SetAllTasks;
+var
+ i:integer;
+begin
+ for i:=0 to MaxTasks-1 do
+ begin
+ if (TaskList[i].flags and ACF_ASSIGNED)<>0 then
+ begin
+ if (TaskList[i].flags and ACF_DISABLED)=0 then
+ SetTask(TaskList[i])
+ else if TaskList[i].timer<>0 then
+ begin
+ KillTimer(0,TaskList[i].timer);
+ TaskList[i].timer:=0;
+ end;
+ end;
+ end;
+end;
+
+procedure StopAllTasks;
+var
+ i:integer;
+begin
+ for i:=0 to MaxTasks-1 do
+ begin
+ if (TaskList[i].flags and (ACF_ASSIGNED or ACF_DISABLED))=ACF_ASSIGNED then
+ if TaskList[i].timer<>0 then
+ begin
+ KillTimer(0,TaskList[i].timer);
+ TaskList[i].timer:=0;
+ end;
+ end;
+end;
+
+procedure ClearTasks;
+var
+ i:integer;
+begin
+ for i:=0 to MaxTasks-1 do
+ begin
+ with TaskList[i] do
+ begin
+//!! if (flags and ACF_ASSIGNED)<>0 then
+ mFreeMem(name);
+ end;
+ end;
+ FreeMem(TaskList);
+ MaxTasks:=0;
+end;
+
+function CreateNewTask:integer;
+var
+ i:integer;
+ tmp:pTaskList;
+ st:tSystemTime;
+begin
+ result:=-1;
+ // if list is not empty, search for hole
+ if MaxTasks>0 then
+ begin
+ for i:=0 to MaxTasks-1 do
+ begin
+ if (TaskList[i].flags and ACF_ASSIGNED)=0 then
+ begin
+ FillChar(TaskList[i],SizeOf(tTaskRec),0);
+ result:=i;
+ break;
+ end;
+ end;
+ end;
+ if result<0 then
+ begin
+ // not found or empty list
+ i:=(MaxTasks+16)*SizeOf(tTaskRec);
+ GetMem (tmp ,i);
+ FillChar(tmp^,i,0);
+ if MaxTasks>0 then
+ begin
+ move(TaskList^,tmp^,MaxTasks*SizeOf(tTaskRec));
+ FreeMem(TaskList);
+ end;
+ TaskList:=tmp;
+ result:=MaxTasks;
+ inc(MaxTasks,16);
+ end;
+ with TaskList^[result] do
+ begin
+ flags:=flags or ACF_ASSIGNED or ACF_DISABLED or TCF_ABSOLUTE;
+ GetLocalTime(st);
+ SystemTimeToFileTime(st,starttime);
+ //!!! CHEAT
+ st.wHour :=0;
+ st.wMinute:=0;
+ st.wSecond:=1;
+ SystemTimeToFileTime(st,interval);
+ end;
+end;
diff --git a/plugins/Actman30/tasks/i_tconst.inc b/plugins/Actman30/tasks/i_tconst.inc
new file mode 100644
index 0000000000..f4df810d32
--- /dev/null
+++ b/plugins/Actman30/tasks/i_tconst.inc
@@ -0,0 +1,27 @@
+{resource constants}
+const
+ IDD_TASKS = 2030;
+
+ IDC_TASK_NAME = 1025;
+
+ IDC_TASK_DATET = 1026;
+ IDC_TASK_DATEV = 1027;
+ IDC_TASK_DAYST = 1028;
+ IDC_TASK_DAYSV = 1029;
+ IDC_TASK_TIMET = 1030;
+ IDC_TASK_TIMEV = 1031;
+
+ IDC_TASK_REPEAT = 1032;
+ IDC_TASK_BREAK = 1034;
+ IDC_TASK_INTERVAL = 1035;
+ IDC_TASK_EVENT = 1036;
+ IDC_TASK_ONCE = 1037;
+ IDC_TASK_UPDOWN = 1038;
+ IDC_TASK_ABSOLUTE = 1039;
+
+ IDC_TASK_ACTION = 1040;
+
+ IDC_TASK_INTDAYS = 1041;
+
+ IDC_TASK_NEW = 1050;
+ IDC_TASK_DELETE = 1051;
diff --git a/plugins/Actman30/tasks/scheduler.pas b/plugins/Actman30/tasks/scheduler.pas
new file mode 100644
index 0000000000..8edf794f77
--- /dev/null
+++ b/plugins/Actman30/tasks/scheduler.pas
@@ -0,0 +1,76 @@
+unit scheduler;
+
+interface
+
+implementation
+
+uses
+ windows, commctrl, messages,
+ mirutils, common, dbsettings, m_api, wrapper,
+ global;
+
+{$R tasks.res}
+
+{$include m_actman.inc}
+
+var
+ hevent: THANDLE;
+
+{$include i_task.inc}
+{$include i_tconst.inc}
+{$include i_options.inc}
+{$include i_opt_dlg.inc}
+{$include i_service.inc}
+
+// ------------ base interface functions -------------
+
+procedure Init;
+begin
+
+ if LoadTasks=0 then
+ begin
+ MaxTasks:=8;
+ GetMem (TaskList ,MaxTasks*SizeOf(tTaskRec));
+ FillChar(TaskList^,MaxTasks*SizeOf(tTaskRec),0);
+ end
+ else
+ SetAllTasks;
+
+ CreateServiceFunction(MS_ACT_TASKCOUNT ,@TaskCount);
+ CreateServiceFunction(MS_ACT_TASKENABLE,@TaskEnable);
+ CreateServiceFunction(MS_ACT_TASKDELETE,@TaskDelete);
+
+ hevent:=CreateHookableEvent(ME_ACT_BELL);
+
+end;
+
+procedure DeInit;
+begin
+ DestroyHookableEvent(hevent);
+ StopAllTasks;
+ ClearTasks;
+end;
+
+function AddOptionPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ result:=0;
+ tmpl:=PAnsiChar(IDD_TASKS);
+ proc:=@DlgProcOpt;
+ name:='Scheduler';
+end;
+
+var
+ amLink:tActionLink;
+
+procedure InitLink;
+begin
+ amLink.Next :=ActionLink;
+ amLink.Init :=@Init;
+ amLink.DeInit :=@DeInit;
+ amLink.AddOption:=@AddOptionPage;
+ ActionLink :=@amLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Actman30/tasks/tasks.rc b/plugins/Actman30/tasks/tasks.rc
new file mode 100644
index 0000000000..2bc558fbc3
--- /dev/null
+++ b/plugins/Actman30/tasks/tasks.rc
@@ -0,0 +1,47 @@
+#include "i_tconst.inc"
+
+LANGUAGE 0,0
+
+IDD_TASKS DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ CONTROL "", IDC_TASK_NAME, "SysListView32",
+ WS_BORDER | WS_TABSTOP |
+ LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_REPORT | LVS_EDITLABELS,// | LVS_SINGLESEL,
+ 2, 2, 130, 174, WS_EX_CONTROLPARENT
+
+ CTEXT "Action",-1 , 140, 2, 160, 12, SS_CENTERIMAGE
+ COMBOBOX IDC_TASK_ACTION, 140, 14, 160, 128, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL
+
+ GROUPBOX "Start" , -1, 138, 30, 164, 54
+
+ COMBOBOX IDC_TASK_ABSOLUTE, 142, 40, 156, 60, CBS_DROPDOWNLIST | WS_VSCROLL
+
+ CTEXT "Date", IDC_TASK_DATET, 140, 54, 76, 12, SS_CENTERIMAGE
+ CONTROL "Date", IDC_TASK_DATEV, "SysDateTimePick32", WS_TABSTOP, 150, 66, 56, 14
+
+ CTEXT "Days", IDC_TASK_DAYST, 140, 54, 76, 12, SS_CENTERIMAGE
+ EDITTEXT IDC_TASK_DAYSV, 162, 66, 32, 14
+
+ CTEXT "Time", IDC_TASK_TIMET, 220, 54, 76, 12, SS_CENTERIMAGE
+ CONTROL "Time", IDC_TASK_TIMEV, "SysDateTimePick32", WS_TABSTOP|$09, 230, 66, 56, 14
+
+ GROUPBOX "Repeat" , -1, 138, 88, 164, 88
+
+ CTEXT "Repeat, times", -1, 140, 98, 70, 14, SS_CENTERIMAGE
+ EDITTEXT IDC_TASK_REPEAT, 155, 114, 40, 14
+
+ CTEXT "Interval", -1, 212, 98, 84, 14, SS_CENTERIMAGE
+ EDITTEXT IDC_TASK_INTDAYS, 212, 114, 24, 14
+ CONTROL "Interval", IDC_TASK_INTERVAL, "SysDateTimePick32", WS_TABSTOP|$09, 240, 114, 56, 14
+
+ AUTOCHECKBOX "Break on non-zero result", IDC_TASK_BREAK, 142, 132, 156, 14
+ AUTOCHECKBOX "Send event on start time", IDC_TASK_EVENT, 142, 146, 156, 14
+ AUTOCHECKBOX "Send event just once" , IDC_TASK_ONCE , 142, 160, 156, 14
+
+ CONTROL "New" ,IDC_TASK_NEW ,"MButtonClass",WS_TABSTOP, 2,178,16,16,$18000000
+ CONTROL "Delete",IDC_TASK_DELETE,"MButtonClass",WS_TABSTOP,22,178,16,16,$18000000
+// CONTROL "Help" ,IDC_EVENT_HELP ,"MButtonClass",WS_TABSTOP,42,164,16,16,$18000000
+}
diff --git a/plugins/Actman30/ua/action.ico b/plugins/Actman30/ua/action.ico
new file mode 100644
index 0000000000..9e4c60d9d3
--- /dev/null
+++ b/plugins/Actman30/ua/action.ico
Binary files differ
diff --git a/plugins/Actman30/ua/i_inoutjson.inc b/plugins/Actman30/ua/i_inoutjson.inc
new file mode 100644
index 0000000000..61879200a1
--- /dev/null
+++ b/plugins/Actman30/ua/i_inoutjson.inc
@@ -0,0 +1,355 @@
+{}
+var
+ jsonparser:TJSONSERVICEINTERFACE;
+
+const
+ ioAction :PWideChar = 'Action';
+ ioUA :PWideChar = 'UA';
+
+ ioName :PWideChar = 'name';
+
+ ioTwoState :PWideChar = 'twostate';
+ ioSaveState :PWideChar = 'savestate';
+
+ ioHotkey :PWideChar = 'Hotkey';
+ ioToolbar :PWideChar = 'Toolbar';
+ ioTabSRMM :PWideChar = 'TabSRMM';
+ ioMenuItem :PWideChar = 'Menu';
+
+ ioTooltip :PWideChar = 'tooltip';
+ ioTooltipPressed :PWideChar = 'tt_pressed';
+
+ ioType :PWideChar = 'type';
+ ioMenuPopup :PWideChar = 'Popup';
+ ioMenuName :PWideChar = 'Name';
+ ioMenuShow :PWideChar = 'Show';
+ ioMenuUsed :PWideChar = 'Used';
+ ioMenuSeparated :PWideChar = 'Separated';
+
+
+function ImportMenuItems(node:JSONNODE;var MenuItem:tUAMenuItem):integer;
+begin
+ result:=0;
+
+ with jsonparser do
+ begin
+ with MenuItem do
+ begin
+ menu_opt:=0;
+ // popup
+ StrDupW(szMenuPopup,getAttrValue(node,ioMenuPopup));
+ // name
+ StrDupW(szMenuNameVars,getAttrValue(node,ioMenuName));
+ // show
+ StrDupW(szMenuShowWhenVars,getAttrValue(node,ioMenuShow));
+ // used
+ if StrToInt(getAttrValue(node,ioMenuUsed))<>0 then
+ menu_opt:=menu_opt or UAF_MENUUSE;
+ // separated
+ if StrToInt(getAttrValue(node,ioMenuSeparated))<>0 then
+ menu_opt:=menu_opt or UAF_MENUSEP;
+ end;
+ end;
+end;
+
+function ImportUAction(actnode:JSONNODE;var UA:tMyActionItem):integer;
+var
+ num,i:integer;
+ sub:JSONNODE;
+begin
+ result:=0;
+ if actnode=0 then exit;
+
+ with jsonparser do
+ begin
+ // we don't need that node as is, just it's child for UA
+// actnode:=GetNthChild(actnode,ioUA,0);
+
+ UA.flags:=0;
+ // ----- Common -----
+ if StrToInt(getAttrValue(actnode,ioTwoState))<>0 then
+ UA.flags:=UA.flags or UAF_2STATE;
+
+ if StrToInt(getAttrValue(actnode,ioSaveState))<>0 then
+ UA.flags:=UA.flags or UAF_SAVESTATE;
+
+ // sub:=AddChild(actnode,ioRegister,nil);
+ if StrToInt(getAttrValue(actnode,ioHotkey))<>0 then
+ UA.flags:=UA.flags or UAF_REGHOTKEY;
+ if StrToInt(getAttrValue(actnode,ioToolbar))<>0 then
+ UA.flags:=UA.flags or UAF_REGTTBB;
+ if StrToInt(getAttrValue(actnode,ioTabSRMM))<>0 then
+ UA.flags:=UA.flags or UAF_REGTABB;
+
+ // ----- Hotkey -----
+ // nothing
+
+ // ----- Modern CList toolbar -----
+ // source - ANSI text
+ sub:=GetNthChild(actnode,ioToolbar,0);
+ WideToAnsi(GetAttrValue(sub,ioTooltip ),UA.szTTBTooltip ,MirandaCP);
+ WideToAnsi(GetAttrValue(sub,ioTooltipPressed),UA.szTTBTooltipPressed,MirandaCP);
+
+ // ----- TabSRMM toolbar -----
+ sub:=GetNthChild(actnode,ioTabSRMM,0);
+ StrDupW(UA.szTabBTooltip ,getAttrValue(sub,ioTooltip));
+ StrDupW(UA.szTabBTooltipPressed,getAttrValue(sub,ioTooltipPressed));
+
+ // ----- Menus -----
+ num:=0;
+ repeat
+ sub:=getNextChild(actnode,ioMenuItem,@num);
+ if sub=0 then break;
+
+ i:=StrToInt(getAttrValue(sub,ioType));
+ ImportMenuItems(sub,
+ UA.UAMenuItem[tMenuType(i)]);
+ until false;
+ end;
+end;
+
+function Import(fname:PWideChar;aflags:dword):integer;
+var
+ i,j,act:integer;
+ root,actnode:JSONNODE;
+ pcw,res:pWideChar;
+ f:THANDLE;
+ num,num1:integer;
+ ptr,ptr1:pChain;
+begin
+ result:=0;
+
+ if (fname=nil) or (fname^=#0) then
+ exit;
+ i:=GetFSize(fname);
+ if i=0 then
+ exit;
+
+ num:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ if num=0 then exit;
+ ptr1:=ptr;
+
+ mGetMem (res ,i+SizeOf(WideChar));
+ FillChar(res^,i+SizeOf(WideChar),0);
+ f:=Reset(fname);
+ BlockRead(f,res^,i);
+ CloseHandle(f);
+
+ CallService(MS_JSON_GETINTERFACE,0,lparam(@jsonparser));
+ with jsonparser do
+ begin
+ root:=parseString(ChangeUnicode(res),@i,nil);
+ j:=0;
+ repeat
+ actnode:=getNthChild(root,ioAction,j);
+ if actnode=0 then break;
+ // search id by name?
+ pcw:=GetAttrValue(actnode,ioName);
+ ptr:=ptr1;
+ inc(pbyte(ptr),4);
+ for i:=0 to num-1 do
+ begin
+ if (ptr.flags and ACCF_IMPORTED)<>0 then
+ begin
+ if StrCmpw(pcw,ptr.descr)=0 then
+ begin
+ // delete old UA for overwrited actions
+ if (ptr.flags and ACCF_OVERLOAD)<>0 then
+ begin
+ for act:=0 to HIGH(UActionList) do
+ begin
+ if ptr.id=UActionList[act].dwActID then
+ begin
+ DeleteUAction(act,true);
+ break;
+ end;
+ end;
+ end;
+ num1:=AddUAction(-1,ptr);
+ ImportUAction(getNthChild(actnode,ioUA,0),UActionList[num1]);
+ break;
+ end;
+ end;
+ inc(ptr);
+ end;
+
+ inc(j);
+ until false;
+
+ DestroyNode(root);
+ end;
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ mFreeMem(res);
+ result:=1;
+ if settings<>0 then
+ begin
+ FillActionList(settings);
+ ShowAction(settings,-1);
+ end;
+end;
+
+//--------------------------
+
+function ExportMenuItems(node:JSONNODE;MenuItem:tUAMenuItem):HXML;
+begin
+ with jsonparser do
+ begin
+ result:=AddChild(node,ioMenuItem,nil);
+ with MenuItem do
+ begin
+ // popup
+ if (szMenuPopup<>nil) and (szMenuPopup^<>#0) then
+ AddAttr(result,ioMenuPopup,szMenuPopup);
+ // name
+ if (szMenuNameVars<>nil) and (szMenuNameVars^<>#0) then
+ AddAttr(result,ioMenuName,szMenuNameVars);
+ // show
+ if (szMenuShowWhenVars<>nil) and (szMenuShowWhenVars^<>#0) then
+ AddAttr(result,ioMenuShow,szMenuShowWhenVars);
+ // used
+ AddAttrInt(result,ioMenuUsed,ord((menu_opt AND UAF_MENUUSE)<>0));
+ // separated
+ AddAttrInt(result,ioMenuSeparated,ord((menu_opt AND UAF_MENUSEP)<>0));
+ end;
+ end;
+end;
+
+procedure WriteUAction(root:JSONNODE;id:dword;name:pWideChar);
+var
+ i:integer;
+ lmenu:tMenuType;
+ pc:pWideChar;
+ actnode,sub:JSONNODE;
+ UA:pMyActionItem;
+begin
+ with jsonparser do
+ begin
+ for i:=0 to HIGH(UActionList) do
+ begin
+ if UActionList[i].dwActID=id then
+ begin
+ UA:=@UActionList[i];
+ actnode:=getChildByAttrValue(root,ioAction,ioName,name);
+ if actnode=0 then break;
+ // we don't need that node as is, just it's child for UA
+ actnode:=addChild(actnode,ioUA,nil);
+
+ // ----- Common -----
+ AddAttrInt(actnode,ioTwoState ,ORD((UA.flags and UAF_2STATE )<>0));
+ AddAttrInt(actnode,ioSaveState,ORD((UA.flags and UAF_SAVESTATE)<>0));
+
+ // sub:=AddChild(actnode,ioRegister,nil);
+ AddAttrInt(actnode,ioHotkey ,ORD((UA.flags and UAF_REGHOTKEY)<>0));
+ AddAttrInt(actnode,ioToolbar,ORD((UA.flags and UAF_REGTTBB )<>0));
+ AddAttrInt(actnode,ioTabSRMM,ORD((UA.flags and UAF_REGTABB )<>0));
+
+ // ----- Hotkey -----
+ // nothing
+
+ // ----- Modern CList toolbar -----
+ // source - ANSI text
+ if ((UA.szTTBTooltip <>nil) and (UA.szTTBTooltip^ <>#0)) or
+ ((UA.szTTBTooltipPressed<>nil) and (UA.szTTBTooltipPressed^<>#0)) then
+ begin
+ sub:=AddChild(actnode,ioToolbar,nil);
+ if (UA.szTTBTooltip<>nil) and (UA.szTTBTooltip^<>#0) then
+ begin
+ AnsiToWide(UA.szTTBTooltip,pc,MirandaCP);
+ AddAttr(sub,ioTooltip,pc);
+ mFreeMem(pc);
+ end;
+ if (UA.szTTBTooltipPressed<>nil) and (UA.szTTBTooltipPressed^<>#0) then
+ begin
+ AnsiToWide(UA.szTTBTooltipPressed,pc,MirandaCP);
+ AddAttr(sub,ioTooltipPressed,pc);
+ mFreeMem(pc);
+ end;
+ end;
+
+ // ----- TabSRMM toolbar -----
+ if ((UA.szTabBTooltip <>nil) and (UA.szTabBTooltip^ <>#0)) or
+ ((UA.szTabBTooltipPressed<>nil) and (UA.szTabBTooltipPressed^<>#0)) then
+ begin
+ sub:=AddChild(actnode,ioTabSRMM,nil);
+ if (UA.szTabBTooltip<>nil) and (UA.szTabBTooltip^<>#0) then
+ AddAttr(sub,ioTooltip,UA.szTabBTooltip);
+ if (UA.szTabBTooltipPressed<>nil) and (UA.szTabBTooltipPressed^<>#0) then
+ AddAttr(sub,ioTooltipPressed,UA.szTabBTooltipPressed);
+ end;
+
+ // ----- Menus -----
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ sub:=ExportMenuItems(actnode,UA.UAMenuItem[lmenu]);
+ AddAttrInt(sub,ioType,ORD(lmenu));
+ end;
+
+ break;
+ end;
+ end;
+ end;
+end;
+
+function Export(fname:pWideChar;aflags:dword):integer;
+var
+ i,num:integer;
+ f:THANDLE;
+ root:JSONNODE;
+ res:pWideChar;
+ ptr,ptr1:pChain;
+begin
+ result:=0;
+ CallService(MS_JSON_GETINTERFACE,0,lparam(@jsonparser));
+ with jsonparser do
+ begin
+ // we need append file, not rewrite
+ i:=GetFSize(fname);
+ if i=0 then exit;
+
+ mGetMem (res ,i+SizeOf(WideChar));
+ FillChar(res^,i+SizeOf(WideChar),0);
+ f:=Reset(fname);
+ BlockRead(f,res^,i);
+ CloseHandle(f);
+ root:=parseString(res,@i,nil);
+ mFreeMem(res);
+
+ num:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ if num>0 then
+ begin
+ ptr1:=ptr;
+ inc(pbyte(ptr),4);
+ for i:=0 to num-1 do
+ begin
+ if ((aflags and ACIO_SELECTED)=0) or
+ ((ptr.flags and ACCF_EXPORT)<>0) then
+ begin
+ WriteUAction(root,ptr.id,ptr.descr);
+ end;
+ inc(ptr);
+ end;
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ end;
+
+ res:=toString(root,@i);
+
+ f:=Rewrite(fname);
+ BlockWrite(f,res^,i*SizeOf(WideChar));
+ CloseHandle(f);
+ xmlparser.FreeMem(res);
+ DestroyNode(root);
+ end;
+ result:=1;
+end;
+
+function ActInOut(wParam:WPARAM;lParam:LPARAM):int_ptr; cdecl;
+begin
+ if (wParam and ACIO_EXPORT)=0 then
+ begin
+ result:=Import(pWideChar(lParam),wParam);
+ end
+ else
+ begin
+ result:=Export(pWideChar(lParam),wParam);
+ end;
+end;
diff --git a/plugins/Actman30/ua/i_inoutxm.inc b/plugins/Actman30/ua/i_inoutxm.inc
new file mode 100644
index 0000000000..a052a5a0e0
--- /dev/null
+++ b/plugins/Actman30/ua/i_inoutxm.inc
@@ -0,0 +1,357 @@
+{}
+var
+ xmlparser:XML_API_W;
+
+const
+ ioAction :PWideChar = 'Action';
+ ioUA :PWideChar = 'UA';
+
+ ioName :PWideChar = 'name';
+
+ ioTwoState :PWideChar = 'twostate';
+ ioSaveState :PWideChar = 'savestate';
+
+ ioHotkey :PWideChar = 'Hotkey';
+ ioToolbar :PWideChar = 'Toolbar';
+ ioTabSRMM :PWideChar = 'TabSRMM';
+ ioMenuItem :PWideChar = 'Menu';
+
+ ioTooltip :PWideChar = 'tooltip';
+ ioTooltipPressed :PWideChar = 'tt_pressed';
+
+ ioType :PWideChar = 'type';
+ ioMenuPopup :PWideChar = 'Popup';
+ ioMenuName :PWideChar = 'Name';
+ ioMenuShow :PWideChar = 'Show';
+ ioMenuUsed :PWideChar = 'Used';
+ ioMenuSeparated :PWideChar = 'Separated';
+
+
+function ImportMenuItems(node:HXML;var MenuItem:tUAMenuItem):integer;
+begin
+ result:=0;
+
+ with xmlparser do
+ begin
+ with MenuItem do
+ begin
+ menu_opt:=0;
+ // popup
+ StrDupW(szMenuPopup,getAttrValue(node,ioMenuPopup));
+ // name
+ StrDupW(szMenuNameVars,getAttrValue(node,ioMenuName));
+ // show
+ StrDupW(szMenuShowWhenVars,getAttrValue(node,ioMenuShow));
+ // used
+ if StrToInt(getAttrValue(node,ioMenuUsed))<>0 then
+ menu_opt:=menu_opt or UAF_MENUUSE;
+ // separated
+ if StrToInt(getAttrValue(node,ioMenuSeparated))<>0 then
+ menu_opt:=menu_opt or UAF_MENUSEP;
+ end;
+ end;
+end;
+
+function ImportUAction(actnode:HXML;var UA:tMyActionItem):integer;
+var
+ num,i:integer;
+ sub:HXML;
+begin
+ result:=0;
+ if actnode=0 then exit;
+
+ with xmlparser do
+ begin
+ // we don't need that node as is, just it's child for UA
+// actnode:=GetNthChild(actnode,ioUA,0);
+
+ UA.flags:=0;
+ // ----- Common -----
+ if StrToInt(getAttrValue(actnode,ioTwoState))<>0 then
+ UA.flags:=UA.flags or UAF_2STATE;
+
+ if StrToInt(getAttrValue(actnode,ioSaveState))<>0 then
+ UA.flags:=UA.flags or UAF_SAVESTATE;
+
+ // sub:=AddChild(actnode,ioRegister,nil);
+ if StrToInt(getAttrValue(actnode,ioHotkey))<>0 then
+ UA.flags:=UA.flags or UAF_REGHOTKEY;
+ if StrToInt(getAttrValue(actnode,ioToolbar))<>0 then
+ UA.flags:=UA.flags or UAF_REGTTBB;
+ if StrToInt(getAttrValue(actnode,ioTabSRMM))<>0 then
+ UA.flags:=UA.flags or UAF_REGTABB;
+
+ // ----- Hotkey -----
+ // nothing
+
+ // ----- Modern CList toolbar -----
+ // source - ANSI text
+ sub:=GetNthChild(actnode,ioToolbar,0);
+ WideToAnsi(GetAttrValue(sub,ioTooltip ),UA.szTTBTooltip ,MirandaCP);
+ WideToAnsi(GetAttrValue(sub,ioTooltipPressed),UA.szTTBTooltipPressed,MirandaCP);
+
+ // ----- TabSRMM toolbar -----
+ sub:=GetNthChild(actnode,ioTabSRMM,0);
+ StrDupW(UA.szTabBTooltip ,getAttrValue(sub,ioTooltip));
+ StrDupW(UA.szTabBTooltipPressed,getAttrValue(sub,ioTooltipPressed));
+
+ // ----- Menus -----
+ num:=0;
+ repeat
+ sub:=getNextChild(actnode,ioMenuItem,@num);
+ if sub=0 then break;
+
+ i:=StrToInt(getAttrValue(sub,ioType));
+ ImportMenuItems(sub,
+ UA.UAMenuItem[tMenuType(i)]);
+ until false;
+ end;
+end;
+
+function Import(fname:PWideChar;aflags:dword):integer;
+var
+ i,j,act:integer;
+ root,actnode:HXML;
+ pcw,res:pWideChar;
+ f:THANDLE;
+ num,num1:integer;
+ ptr,ptr1:pChain;
+begin
+ result:=0;
+
+ if (fname=nil) or (fname^=#0) then
+ exit;
+ i:=GetFSize(fname);
+ if i=0 then
+ exit;
+
+ num:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ if num=0 then exit;
+ ptr1:=ptr;
+
+ mGetMem (res ,i+SizeOf(WideChar));
+ FillChar(res^,i+SizeOf(WideChar),0);
+ f:=Reset(fname);
+ BlockRead(f,res^,i);
+ CloseHandle(f);
+
+ xmlparser.cbSize:={XML_API_SIZEOF_V1;//}SizeOf(XML_API_W);
+ CallService(MS_SYSTEM_GET_XI,0,lparam(@xmlparser));
+ with xmlparser do
+ begin
+ root:=parseString(ChangeUnicode(res),@i,nil);
+ j:=0;
+ repeat
+ actnode:=getNthChild(root,ioAction,j);
+ if actnode=0 then break;
+ // search id by name?
+ pcw:=GetAttrValue(actnode,ioName);
+ ptr:=ptr1;
+ inc(pbyte(ptr),4);
+ for i:=0 to num-1 do
+ begin
+ if (ptr.flags and ACF_SELECTED)<>0 then
+ begin
+ if StrCmpw(pcw,ptr.descr)=0 then
+ begin
+ // delete old UA for overwrited actions
+ if (ptr.flags and ACF_OVERLOAD)<>0 then
+ begin
+ for act:=0 to HIGH(UActionList) do
+ begin
+ if ptr.id=UActionList[act].dwActID then
+ begin
+ DeleteUAction(act,true);
+ break;
+ end;
+ end;
+ end;
+ num1:=AddUAction(-1,ptr);
+ ImportUAction(getNthChild(actnode,ioUA,0),UActionList[num1]);
+ break;
+ end;
+ end;
+ inc(ptr);
+ end;
+
+ inc(j);
+ until false;
+
+ DestroyNode(root);
+ end;
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ mFreeMem(res);
+ result:=1;
+ if settings<>0 then
+ begin
+ FillActionList(settings);
+ ShowAction(settings,-1);
+ end;
+end;
+
+//--------------------------
+
+function ExportMenuItems(node:HXML;const MenuItem:tUAMenuItem):HXML;
+begin
+ with xmlparser do
+ begin
+ result:=AddChild(node,ioMenuItem,nil);
+ with MenuItem do
+ begin
+ // popup
+ if (szMenuPopup<>nil) and (szMenuPopup^<>#0) then
+ AddAttr(result,ioMenuPopup,szMenuPopup);
+ // name
+ if (szMenuNameVars<>nil) and (szMenuNameVars^<>#0) then
+ AddAttr(result,ioMenuName,szMenuNameVars);
+ // show
+ if (szMenuShowWhenVars<>nil) and (szMenuShowWhenVars^<>#0) then
+ AddAttr(result,ioMenuShow,szMenuShowWhenVars);
+ // used
+ AddAttrInt(result,ioMenuUsed,ord((menu_opt AND UAF_MENUUSE)<>0));
+ // separated
+ AddAttrInt(result,ioMenuSeparated,ord((menu_opt AND UAF_MENUSEP)<>0));
+ end;
+ end;
+end;
+
+procedure WriteUAction(root:HXML;id:dword;name:pWideChar);
+var
+ i:integer;
+ lmenu:tMenuType;
+ pc:pWideChar;
+ actnode,sub:HXML;
+ UA:pMyActionItem;
+begin
+ with xmlparser do
+ begin
+ for i:=0 to HIGH(UActionList) do
+ begin
+ if UActionList[i].dwActID=id then
+ begin
+ UA:=@UActionList[i];
+ actnode:=getChildByAttrValue(root,ioAction,ioName,name);
+ if actnode=0 then break;
+ // we don't need that node as is, just it's child for UA
+ actnode:=addChild(actnode,ioUA,nil);
+
+ // ----- Common -----
+ AddAttrInt(actnode,ioTwoState ,ORD((UA.flags and UAF_2STATE )<>0));
+ AddAttrInt(actnode,ioSaveState,ORD((UA.flags and UAF_SAVESTATE)<>0));
+
+ // sub:=AddChild(actnode,ioRegister,nil);
+ AddAttrInt(actnode,ioHotkey ,ORD((UA.flags and UAF_REGHOTKEY)<>0));
+ AddAttrInt(actnode,ioToolbar,ORD((UA.flags and UAF_REGTTBB )<>0));
+ AddAttrInt(actnode,ioTabSRMM,ORD((UA.flags and UAF_REGTABB )<>0));
+
+ // ----- Hotkey -----
+ // nothing
+
+ // ----- Modern CList toolbar -----
+ // source - ANSI text
+ if ((UA.szTTBTooltip <>nil) and (UA.szTTBTooltip^ <>#0)) or
+ ((UA.szTTBTooltipPressed<>nil) and (UA.szTTBTooltipPressed^<>#0)) then
+ begin
+ sub:=AddChild(actnode,ioToolbar,nil);
+ if (UA.szTTBTooltip<>nil) and (UA.szTTBTooltip^<>#0) then
+ begin
+ AnsiToWide(UA.szTTBTooltip,pc,MirandaCP);
+ AddAttr(sub,ioTooltip,pc);
+ mFreeMem(pc);
+ end;
+ if (UA.szTTBTooltipPressed<>nil) and (UA.szTTBTooltipPressed^<>#0) then
+ begin
+ AnsiToWide(UA.szTTBTooltipPressed,pc,MirandaCP);
+ AddAttr(sub,ioTooltipPressed,pc);
+ mFreeMem(pc);
+ end;
+ end;
+
+ // ----- TabSRMM toolbar -----
+ if ((UA.szTabBTooltip <>nil) and (UA.szTabBTooltip^ <>#0)) or
+ ((UA.szTabBTooltipPressed<>nil) and (UA.szTabBTooltipPressed^<>#0)) then
+ begin
+ sub:=AddChild(actnode,ioTabSRMM,nil);
+ if (UA.szTabBTooltip<>nil) and (UA.szTabBTooltip^<>#0) then
+ AddAttr(sub,ioTooltip,UA.szTabBTooltip);
+ if (UA.szTabBTooltipPressed<>nil) and (UA.szTabBTooltipPressed^<>#0) then
+ AddAttr(sub,ioTooltipPressed,UA.szTabBTooltipPressed);
+ end;
+
+ // ----- Menus -----
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ sub:=ExportMenuItems(actnode,UA.UAMenuItem[lmenu]);
+ AddAttrInt(sub,ioType,ORD(lmenu));
+ end;
+
+ break;
+ end;
+ end;
+ end;
+end;
+
+function Export(fname:pWideChar;aflags:dword):integer;
+var
+ i,num:integer;
+ f:THANDLE;
+ root:HXML;
+ res:pWideChar;
+ ptr,ptr1:pChain;
+begin
+ result:=0;
+ xmlparser.cbSize:={XML_API_SIZEOF_V1;//}SizeOf(XML_API_W);
+ CallService(MS_SYSTEM_GET_XI,0,lparam(@xmlparser));
+ with xmlparser do
+ begin
+ // we need append file, not rewrite
+ i:=GetFSize(fname);
+ if i=0 then exit;
+
+ mGetMem (res ,i+SizeOf(WideChar));
+ FillChar(res^,i+SizeOf(WideChar),0);
+ f:=Reset(fname);
+ BlockRead(f,res^,i);
+ CloseHandle(f);
+ root:=parseString(res,@i,nil);
+ mFreeMem(res);
+
+ num:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ if num>0 then
+ begin
+ ptr1:=ptr;
+ inc(pbyte(ptr),4);
+ for i:=0 to num-1 do
+ begin
+ if ((aflags and ACIO_SELECTED)=0) or
+ ((ptr.flags and ACCF_EXPORT)<>0) then
+ begin
+ WriteUAction(root,ptr.id,ptr.descr);
+ end;
+ inc(ptr);
+ end;
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ end;
+
+ res:=toString(root,@i);
+
+ f:=Rewrite(fname);
+ BlockWrite(f,res^,i*SizeOf(WideChar));
+ CloseHandle(f);
+ xmlparser.FreeMem(res);
+ DestroyNode(root);
+ end;
+ result:=1;
+end;
+
+function ActInOut(wParam:WPARAM;lParam:LPARAM):int_ptr; cdecl;
+begin
+ if (wParam and ACIO_EXPORT)=0 then
+ begin
+ result:=Import(pWideChar(lParam),wParam);
+ end
+ else
+ begin
+ result:=Export(pWideChar(lParam),wParam);
+ end;
+end;
diff --git a/plugins/Actman30/ua/i_opt_dlg.inc b/plugins/Actman30/ua/i_opt_dlg.inc
new file mode 100644
index 0000000000..b7ff28483a
--- /dev/null
+++ b/plugins/Actman30/ua/i_opt_dlg.inc
@@ -0,0 +1,572 @@
+{}
+const
+ settings:HWND = 0;
+const
+ NumControls = 17;
+
+ IDsArray:array [0..NumControls-1] of integer =(
+ // Menu settings controls
+ IDC_UA_SEPARATE ,IDC_UA_POPUPT ,IDC_UA_POPUPV,
+ IDC_UA_VARNAMEST,IDC_UA_VARNAMESV,IDC_UA_VARNAMESH,
+ IDC_UA_SHOWVART ,IDC_UA_SHOWVARV ,IDC_UA_SHOWVARH,
+ IDC_UA_TWOSTATE ,IDC_UA_SAVSTATE ,IDC_UA_COMMON,
+ // toolbar settings controls
+ IDC_UA_TTNORMALT,IDC_UA_TTNORMALV,IDC_UA_TTPRESSEDT,IDC_UA_TTPRESSEDV,
+ IDC_UA_GLOBAL
+ );
+
+ // Show-hide controls by place type
+ SHArray:array [0..NumTypes-1, 0..NumControls-1] of integer = (
+ // CList Modern toolbar
+ (SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE,SW_HIDE,SW_HIDE, SW_SHOW,SW_SHOW,SW_SHOW,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,SW_SHOW, SW_HIDE),
+ // TabSRMM toolbar
+ (SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE,SW_HIDE,SW_HIDE,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW),
+ // Core Hotkey
+ (SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE,SW_HIDE,SW_HIDE,
+ SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE,SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE),
+ // Main menu
+ (SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_HIDE,SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE),
+ // Contact menu
+ (SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_HIDE,SW_HIDE,SW_HIDE,SW_HIDE, SW_SHOW),
+ // Tray menu
+ (SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_HIDE,SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE),
+ // Protocol menu
+ (SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_HIDE,SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE),
+ // Status menu
+ (SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW, SW_SHOW,SW_SHOW,SW_SHOW,
+ SW_SHOW,SW_SHOW,SW_SHOW, SW_HIDE,SW_HIDE,SW_HIDE,SW_HIDE, SW_HIDE)
+ );
+ // additional show/hide controls check by Variables installings (1 - need to check)
+ SHVarArray:array [0..NumControls-1] of byte = (
+ 0,0,0, 0,0,1, 1,1,1,
+ 0,0,0,0,0,0,0, 0);
+ // additional enable/disable controls check (1 - always enable)
+ EnDisArray:array [0..NumControls-1] of byte = (
+ 0,0,0, 0,0,0, 0,0,0,
+ 1,1,1,0,0,0,0, 1);
+
+var
+ hIC:THANDLE;
+
+procedure CheckPlacesAbility;
+var
+ i:integer;
+begin
+ for i:=0 to NumTypes-1 do
+ begin
+ with NamesArray[i] do
+ begin
+ enable:=(service=nil) or (ServiceExists(service)<>0);
+ end;
+ end;
+end;
+
+// Show or hide option items
+procedure SetupControls(Dialog:HWND;atype:integer;item:integer=-1);
+var
+ i: cardinal;
+ typ:integer;
+ wnd,wnd1:HWND;
+ enable:boolean;
+begin
+ if atype<0 then
+ begin
+ for i:=0 to NumControls-1 do
+ begin
+ ShowWindow(GetDlgItem(Dialog,IDsArray[i]),SW_HIDE);
+ end;
+ end
+ else
+ begin
+ wnd1:=GetDlgItem(Dialog,IDC_UA_PLACELIST);
+ if item<0 then
+ item:=SendMessage(wnd1,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
+ enable:=ListView_GetCheckState(wnd1,item)<>0;
+
+ for i:=0 to NumControls-1 do
+ begin
+ typ:=SHArray[LoByte(atype)+HiByte(atype)][i];
+ if typ=SW_SHOW then
+ if (SHVarArray[i]<>0) and (not IsVarsInstalled) then
+ typ:=SW_HIDE;
+ wnd:=GetDlgItem(Dialog,IDsArray[i]);
+ ShowWindow(wnd,typ);
+ EnableWindow(wnd,enable or (EnDisArray[i]<>0));
+ end;
+
+ // common settings
+ EnableWindow(GetDlgItem(Dialog,IDC_UA_SAVSTATE),
+ IsDlgButtonChecked(Dialog,IDC_UA_TWOSTATE)<>BST_UNCHECKED);
+
+ // personal settings
+ case LoByte(atype) of
+ uaTTB, uaTAB: begin
+ enable:=false;
+ if IsDlgButtonChecked(Dialog,IDC_UA_TWOSTATE)<>BST_UNCHECKED then
+ if IsWindowEnabled(GetDlgItem(Dialog,IDC_UA_TTNORMALV)) then
+ enable:=true;
+ EnableWindow(GetDlgItem(Dialog,IDC_UA_TTPRESSEDV),enable);
+ end;
+ end;
+ end;
+end;
+
+// Clear all screen buttons/text fields (reset)
+procedure ClearControls(Dialog:HWND);
+var
+ s:HWND;
+begin
+ s:=settings;
+ settings:=0;
+ CheckDlgButton (Dialog,IDC_UA_TWOSTATE ,BST_UNCHECKED);
+ CheckDlgButton (Dialog,IDC_UA_SAVSTATE ,BST_UNCHECKED);
+
+ CheckDlgButton (Dialog,IDC_UA_SEPARATE ,BST_UNCHECKED);
+ SetDlgItemTextW(Dialog,IDC_UA_POPUPV ,nil);
+ SetDlgItemTextW(Dialog,IDC_UA_VARNAMESV,nil);
+ SetDlgItemTextW(Dialog,IDC_UA_SHOWVARV ,nil);
+ settings:=s;
+end;
+
+procedure ShowSubAction(Dialog:HWND;aType:integer;item:integer=-1);
+var
+ UA:pMyActionItem;
+ s:HWND;
+begin
+ s:=settings;
+ settings:=0;
+ ClearControls(Dialog);
+
+ // get UAction number
+ item:=LV_GetLParam(GetDlgItem(Dialog,IDC_UA_ACTIONLIST),item);
+
+ UA:=@UActionList[item];
+
+ // common settings
+ if (UA.flags and UAF_2STATE)<>0 then
+ CheckDlgButton(Dialog,IDC_UA_TWOSTATE,BST_CHECKED);
+
+ if (UA.flags and UAF_SAVESTATE)<>0 then
+ CheckDlgButton(Dialog,IDC_UA_SAVSTATE,BST_CHECKED);
+
+ if (UA.flags and UAF_GLOBAL)=0 then
+ CheckDlgButton(Dialog,IDC_UA_GLOBAL,BST_CHECKED);
+
+ // Show real UA settings
+ case LoByte(aType) of
+ uaTTB: begin // CList modern toolbar
+ SetDlgItemTextA(Dialog,IDC_UA_TTNORMALV ,UA.szTTBTooltip);
+ SetDlgItemTextA(Dialog,IDC_UA_TTPRESSEDV,UA.szTTBTooltipPressed);
+ SetDlgItemTextW(Dialog,IDC_UA_SHOWVARV ,UA.szTTBShowWhenVars);
+ end;
+
+ uaTAB: begin // TabSRMM toolbar
+ SetDlgItemTextW(Dialog,IDC_UA_TTNORMALV ,UA.szTabBTooltip);
+ SetDlgItemTextW(Dialog,IDC_UA_TTPRESSEDV,UA.szTabBTooltipPressed);
+ end;
+
+ uaMenu: begin
+ with UA.UAMenuItem[tMenuType(HiByte(aType))] do
+ begin
+ if (menu_opt and UAF_MENUSEP)<>0 then
+ CheckDlgButton(Dialog,IDC_UA_SEPARATE,BST_CHECKED);
+ SetDlgItemTextW(Dialog,IDC_UA_POPUPV ,szMenuPopup);
+ SetDlgItemTextW(Dialog,IDC_UA_VARNAMESV,szMenuNameVars);
+ SetDlgItemTextW(Dialog,IDC_UA_SHOWVARV ,szMenuShowWhenVars);
+ end;
+ end;
+
+ uaHotkey: begin // Hotkey
+ // Settings in Customize/Hotkeys
+ end;
+ end;
+ SetupControls(Dialog,aType,-1);
+ settings:=s;
+end;
+
+function isPlaceActive(idx,place:integer):boolean;
+begin
+ result:=false;
+ with UActionList[idx] do
+ case LoByte(place) of
+ uaTTB : result:=(flags and UAF_REGTTBB)<>0;
+ uaTAB : result:=(flags and UAF_REGTABB)<>0;
+ uaHotkey : result:=(flags and UAF_REGHOTKEY)<>0;
+ uaMenu: begin
+ result:=(UAMenuItem[tMenuType(HiByte(place))].menu_opt and UAF_MENUUSE)<>0
+ end;
+ end;
+end;
+
+procedure ShowAction(Dialog:HWND;item:integer=-1);
+var
+ i,j:integer;
+ wnd:HWND;
+ li:LV_ITEMW;
+ buf:array [0..255] of WideChar;
+ lset:HWND;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_UA_PLACELIST);
+ SendMessage(wnd,LVM_DELETEALLITEMS,0,0);
+ j:=LV_GetLParam(GetDlgItem(Dialog,IDC_UA_ACTIONLIST),item);
+ if j>=0 then
+ begin
+ with UActionList[j] do
+ begin
+ lset:=settings;
+ settings:=0;
+ // make "places" list
+ for i:=0 to NumTypes-1 do
+ begin
+ with NamesArray[i] do
+ begin
+ if enable then // cached ability flag
+ begin
+ li.mask :=LVIF_TEXT+LVIF_PARAM;
+ li.iSubItem:=0;
+ li.iItem :=i;
+ li.lParam :=atype; //!!!!!! need to add subtype
+ li.pszText :=TranslateW(FastAnsiToWideBuf(name,buf));
+ li.iItem :=SendMessageW(wnd,LVM_INSERTITEMW,0,LPARAM(@li));
+
+ ListView_SetCheckState(wnd,li.iItem,isPlaceActive(j,atype));
+ end;
+ end;
+ end;
+ ListView_SetItemState(wnd,0,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+ // show first selected "place"
+ ShowSubAction(Dialog,LV_GetLParam(wnd));
+ settings:=lset;
+ end;
+ end
+ else
+ begin
+ ClearControls(Dialog);
+ SetupControls(Dialog,-1,-1);
+ end;
+end;
+
+procedure SetChangedFlag(Dialog:HWND);
+var
+ num,atype:integer;
+begin
+ num :=LV_GetLParam(GetDlgItem(Dialog,IDC_UA_ACTIONLIST),-1);
+ atype:=LV_GetLParam(GetDlgItem(Dialog,IDC_UA_PLACELIST ),-1);
+ UActionList[num].UAMenuItem[tMenuType(HiByte(atype))].changed:=true;
+end;
+
+procedure SaveMenuSubAction(Dialog:HWND;var MenuItem:tUAMenuItem);
+begin
+ with MenuItem do
+ begin
+ mFreeMem(szMenuPopup ); szMenuPopup :=GetDlgText(Dialog,IDC_UA_POPUPV);
+ mFreeMem(szMenuNameVars ); szMenuNameVars :=GetDlgText(Dialog,IDC_UA_VARNAMESV);
+ mFreeMem(szMenuShowWhenVars); szMenuShowWhenVars:=GetDlgText(Dialog,IDC_UA_SHOWVARV);
+ menu_opt:=0;
+ if IsDlgButtonchecked(Dialog,IDC_UA_SEPARATE)<>BST_UNCHECKED then
+ menu_opt:=menu_opt or UAF_MENUSEP;
+ end;
+end;
+
+procedure SetPlaceActive(idx,place:integer;active:boolean);
+begin
+ with UActionList[idx] do
+ case LoByte(place) of
+ uaTTB : if active then flags:=flags or UAF_REGTTBB else flags:=flags and not UAF_REGTTBB;
+ uaTAB : if active then flags:=flags or UAF_REGTABB else flags:=flags and not UAF_REGTABB;
+ uaHotkey: if active then flags:=flags or UAF_REGHOTKEY else flags:=flags and not UAF_REGHOTKEY;
+ uaMenu :
+ with UAMenuItem[tMenuType(HiByte(place))] do
+ if active then menu_opt:=menu_opt or UAF_MENUUSE
+ else menu_opt:=menu_opt and not UAF_MENUUSE;
+ end;
+end;
+
+procedure SaveAction(Dialog:HWND;item:integer=-1;atype:integer=-1);
+var
+ i,num:integer;
+ wnd:HWND;
+begin
+ num:=LV_GetLParam(GetDlgItem(Dialog,IDC_UA_ACTIONLIST),item);
+ if num<0 then exit;
+
+ wnd:=GetDlgItem(Dialog,IDC_UA_PLACELIST);
+ atype:=LV_GetLParam(wnd,atype);
+ with UActionList[num] do
+ begin
+ // main flags
+ flags:=flags and not UAF_USING;
+ // common section
+ if IsDlgButtonChecked(Dialog,IDC_UA_TWOSTATE)<>BST_UNCHECKED then
+ flags:=flags or UAF_2STATE
+ else
+ flags:=flags and not UAF_2STATE;
+
+ if IsDlgButtonChecked(Dialog,IDC_UA_SAVSTATE)<>BST_UNCHECKED then
+ flags:=flags or UAF_SAVESTATE
+ else
+ flags:=flags and not UAF_SAVESTATE;
+
+ if IsDlgButtonChecked(Dialog,IDC_UA_GLOBAL)=BST_UNCHECKED then
+ flags:=flags or UAF_GLOBAL
+ else
+ flags:=flags and not UAF_GLOBAL;
+
+ // custom data
+ case LoByte(atype) of
+ uaTTB: begin // CList modern toolbar
+ mFreeMem(szTTBTooltip ); szTTBTooltip :=GetDlgText(Dialog,IDC_UA_TTNORMALV ,true);
+ mFreeMem(szTTBTooltipPressed); szTTBTooltipPressed:=GetDlgText(Dialog,IDC_UA_TTPRESSEDV,true);
+ mFreeMem(szTTBShowWhenVars ); szTTBShowWhenVars :=GetDlgText(Dialog,IDC_UA_SHOWVARV);
+ end;
+
+ uaTAB: begin // TabSRMM toolbar
+ mFreeMem(szTabBTooltip ); szTabBTooltip :=GetDlgText(Dialog,IDC_UA_TTNORMALV);
+ mFreeMem(szTabBTooltipPressed); szTabBTooltipPressed:=GetDlgText(Dialog,IDC_UA_TTPRESSEDV);
+ end;
+
+ uaMenu: SaveMenuSubAction(Dialog,UAMenuItem[tMenuType(HiByte(atype))]);
+
+ uaHotkey: begin // Hotkey
+ // Settings in Customize/Hotkeys
+ end;
+ end;
+ for i:=0 to SendMessage(wnd,LVM_GETITEMCOUNT,0,0)-1 do
+ begin
+ SetPlaceActive(num,LV_GetLParam(wnd,i),ListView_GetCheckState(wnd,i)<>0);
+ end;
+ //just after Action (not place) changes
+ if item<0 then
+ SaveUA(num);
+ end;
+end;
+
+function CompareItem(lParam1,lParam2:LPARAM;SortType:LPARAM):int; stdcall;
+begin
+ result:=UActionList[lParam1].wSortIndex-UActionList[lParam2].wSortIndex;
+end;
+
+procedure FillActionList(wnd:HWND);
+var
+ i:integer;
+ li:LV_ITEMW;
+ il:HIMAGELIST;
+ lmenu:tMenuType;
+begin
+ wnd:=GetDlgItem(wnd,IDC_UA_ACTIONLIST);
+ SendMessage(wnd,LVM_DELETEALLITEMS,0,0);
+
+ il:=ImageList_Create(16,16,ILC_COLOR32 or ILC_MASK,0,1);
+ for i:=0 to HIGH(UActionList) do
+ begin
+ li.mask :=LVIF_TEXT+LVIF_PARAM+LVIF_IMAGE;
+ li.iSubItem:=0;
+ li.iItem :=i;
+ li.lParam :=i;
+ li.pszText :=UActionList[i].szActDescr;
+ li.iImage:=ImageList_AddIcon(il,
+ HICON(CallService(MS_SKIN2_GETICONBYHANDLE,0,LPARAM(UActionList[i].hIcolibIcon))));
+ li.iItem :=SendMessageW(wnd,LVM_INSERTITEMW,0,LPARAM(@li));
+
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ UActionList[i].UAMenuItem[lmenu].changed:=false;
+ end;
+ ImageList_Destroy(SendMessage(wnd,LVM_SETIMAGELIST,LVSIL_SMALL,il));
+
+ SendMessage(wnd,LVM_SORTITEMS,0,LPARAM(@CompareItem));
+
+ ListView_SetItemState(wnd,0,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED);
+end;
+
+// refresh icons in UA list (at least)
+function IconChanged(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ i:integer;
+ li:LV_ITEMW;
+ il:HIMAGELIST;
+ wnd:HWND;
+begin
+ result:=0;
+ wnd:=GetDlgItem(settings,IDC_UA_ACTIONLIST);
+
+ il:=ImageList_Create(16,16,ILC_COLOR32 or ILC_MASK,0,1);
+ for i:=0 to HIGH(UActionList) do
+ begin
+ li.mask :=LVIF_IMAGE;
+ li.iSubItem:=0;
+ li.iItem :=i;
+ li.iImage:=ImageList_AddIcon(il,
+ HICON(CallService(MS_SKIN2_GETICONBYHANDLE,0,TLPARAM(UActionList[i].hIcolibIcon))));
+ SendMessageW(wnd,LVM_SETITEM,0,TLPARAM(@li));
+ end;
+ ImageList_Destroy(SendMessage(wnd,LVM_SETIMAGELIST,LVSIL_SMALL,il));
+//!!refresh?
+end;
+
+function DlgProcOpt(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ wnd:HWND;
+ lv:LV_COLUMNW;
+ i:integer;
+begin
+ result:=0;
+ case hMessage of
+ WM_CLOSE: begin
+ settings:=0;
+ UnhookEvent(hIC);
+ end;
+
+ WM_INITDIALOG: begin
+ settings:=0;
+ TranslateDialogDefault(Dialog);
+
+ wnd:=GetDlgItem(Dialog,IDC_UA_PLACELIST);
+ SendMessage(wnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_CHECKBOXES,LVS_EX_CHECKBOXES);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ zeromemory(@lv,sizeof(lv));
+ lv.mask:=LVCF_WIDTH;
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW ,0,tlparam(@lv));
+ SendMessageW(wnd,LVM_SETCOLUMNWIDTH,0,LVSCW_AUTOSIZE_USEHEADER);
+
+ wnd:=GetDlgItem(Dialog,IDC_UA_ACTIONLIST);
+// SendMessage(wnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_CHECKBOXES,LVS_EX_CHECKBOXES);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ zeromemory(@lv,sizeof(lv));
+ lv.mask:=LVCF_WIDTH;
+ lv.cx :=110;
+ SendMessageW(wnd,LVM_INSERTCOLUMNW ,0,tlparam(@lv));
+ SendMessageW(wnd,LVM_SETCOLUMNWIDTH,0,LVSCW_AUTOSIZE_USEHEADER);
+ FillActionList(Dialog);
+ ShowAction(Dialog,-1);
+
+// if isVarsInstalled then
+ begin
+ SendDlgItemMessage(Dialog,IDC_UA_VARNAMESH,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_VARS_GETSKINITEM,0,VSI_HELPICON));
+ SendDlgItemMessage(Dialog,IDC_UA_SHOWVARH,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_VARS_GETSKINITEM,0,VSI_HELPICON));
+// SendDlgItemMessage(Dialog,IDC_UA_VARNAMESH,BUTTONSETASFLATBTN,0,0);
+// SendDlgItemMessage(Dialog,IDC_UA_SHOWVARH ,BUTTONSETASFLATBTN,0,0);
+ end;
+
+ settings:=Dialog;
+ hIC:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE: begin
+ if settings<>0 then
+ begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ if loword(wParam)=IDC_UA_POPUPV then
+ SetChangedFlag(Dialog);
+ end;
+ end;
+
+ BN_CLICKED: begin
+ if settings<>0 then
+ begin
+ case loword(wParam) of
+ IDC_UA_TWOSTATE: begin
+ SetupControls(Dialog,
+ LV_GetLParam(GetDlgItem(Dialog,IDC_UA_PLACELIST)),-1);
+ {
+ EnableWindow(GetDlgItem(Dialog,IDC_UA_TTPRESSEDV),
+ IsDlgButtonChecked(Dialog,IDC_UA_TWOSTATE)<>BST_UNCHECKED);
+ }
+ if IsDlgButtonChecked(Dialog,IDC_UA_TWOSTATE)=BST_UNCHECKED then
+ DeleteIcolibIconP(
+ UActionList[LV_GetLParam(GetDlgItem(Dialog,IDC_UA_ACTIONLIST),-1)])
+ else
+ AddIcolibIconP(
+ UActionList[LV_GetLParam(GetDlgItem(Dialog,IDC_UA_ACTIONLIST),-1)]);
+
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ IDC_UA_VARNAMESH: ShowVarHelp(Dialog,IDC_UA_VARNAMESV);
+ IDC_UA_SHOWVARH : ShowVarHelp(Dialog,IDC_UA_SHOWVARV);
+
+//was commented. why?
+ IDC_UA_SAVSTATE,
+ IDC_UA_GLOBAL: SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+
+ IDC_UA_SEPARATE: begin
+ SetChangedFlag(Dialog);
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ case integer(PNMHdr(lParam)^.code) of
+ PSN_APPLY: begin
+ SaveAction(Dialog);
+ SaveUAs;
+ FillChar(arMenuRec[0],Length(arMenuRec)*SizeOf(tuaMenuRecA),0);
+ for i:=0 to HIGH(UActionList) do
+ begin
+ SetAllActionUsers(UActionList[i],false);
+ end;
+ end;
+
+ LVN_ITEMCHANGED: begin
+ if settings=0 then exit;
+ if PNMLISTVIEW(lParam)^.uChanged=LVIF_STATE then
+ begin
+ i:=(PNMLISTVIEW(lParam)^.uOldState and LVNI_FOCUSED)-
+ (PNMLISTVIEW(lParam)^.uNewState and LVNI_FOCUSED);
+
+ if i>0 then // old focus
+ begin
+ if wParam=IDC_UA_ACTIONLIST then
+ SaveAction(Dialog,PNMLISTVIEW(lParam)^.iItem)
+ else //if wParam=IDC_UA_PLACELIST then
+ SaveAction(Dialog,-1,PNMLISTVIEW(lParam)^.iItem);
+ end
+ else if i<0 then // new focus
+ begin
+ if wParam=IDC_UA_ACTIONLIST then
+ ShowAction(Dialog,PNMLISTVIEW(lParam)^.iItem)
+ else//if wParam=IDC_UA_PLACELIST then
+ ShowSubAction(Dialog,
+ LV_GetLParam(GetDlgItem(Dialog,IDC_UA_PLACELIST),
+ PNMLISTVIEW(lParam)^.iItem));
+ end
+ else if (settings<>0) and
+ ((PNMLISTVIEW(lParam)^.uOldState or PNMLISTVIEW(lParam)^.uNewState)=$3000) then
+ begin
+ // which type
+ wnd:=GetDlgItem(Dialog,IDC_UA_PLACELIST);
+ if PNMLISTVIEW(lParam)^.iItem<>
+ SendMessage(wnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED) then
+ ListView_SetItemState(wnd,PNMLISTVIEW(lParam)^.iItem,
+ LVIS_FOCUSED or LVIS_SELECTED,
+ LVIS_FOCUSED or LVIS_SELECTED)
+ else
+ SetupControls(Dialog,LV_GetLParam(wnd,PNMLISTVIEW(lParam)^.iItem),
+ PNMLISTVIEW(lParam)^.iItem);
+
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Actman30/ua/i_options.inc b/plugins/Actman30/ua/i_options.inc
new file mode 100644
index 0000000000..977ff7891b
--- /dev/null
+++ b/plugins/Actman30/ua/i_options.inc
@@ -0,0 +1,252 @@
+{}
+const
+ opt_TTBTooltip :pAnsiChar = 'MTBTooltip';
+ opt_TTBTooltipPressed :pAnsiChar = 'MTBTooltipPressed';
+ opt_TTBShowWhenVars :pAnsiChar = 'MTBVarStr';
+
+ opt_TabBTooltip :pAnsiChar = 'TabBTooltip';
+ opt_TabBTooltipPressed:pAnsiChar = 'TabBTooltipPressed';
+
+ opt_MenuPopup :pAnsiChar = 'MenuPopup';
+ opt_MenuNameVars :pAnsiChar = 'MenuName';
+ opt_MenuShowWhenVars:pAnsiChar = 'MenuVarStr';
+ opt_MenuOptions :pAnsiChar = 'MenuOptions';
+
+{}
+procedure DeleteUASettings(idx:integer);
+var
+ setting:array [0..63] of AnsiChar;
+ p,pm:pAnsiChar;
+ lmenu:tMenuType;
+begin
+ with UActionList[idx] do
+ begin
+ p:=GetUABranch(setting,dwActID);
+ if p<>nil then
+ begin
+ p:=StrCopyE(p,opt_UA);
+ p^:='/'; inc(p);
+{!!
+ p^:='*'; inc(p); p^:=#0;
+ DBDeleteGroup(0,DBBranch,setting);
+!!}
+ StrCopy(p,opt_Flags); DBDeleteSetting(0,DBBranch,setting);
+
+ StrCopy(p,opt_TTBTooltip ); DBDeleteSetting(0,DBBranch,setting);
+ StrCopy(p,opt_TTBTooltipPressed ); DBDeleteSetting(0,DBBranch,setting);
+ StrCopy(p,opt_TTBShowWhenVars ); DBDeleteSetting(0,DBBranch,setting);
+
+ StrCopy(p,opt_TabBTooltip ); DBDeleteSetting(0,DBBranch,setting);
+ StrCopy(p,opt_TabBTooltipPressed); DBDeleteSetting(0,DBBranch,setting);
+
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ pm:=p;
+ pm^:=AnsiChar(ORD(lmenu)+ORD('0')); inc(pm);
+ pm^:='_'; inc(pm);
+ StrCopy(pm,opt_MenuPopup ); DBDeleteSetting(0,DBBranch,setting);
+ StrCopy(pm,opt_MenuNameVars ); DBDeleteSetting(0,DBBranch,setting);
+ StrCopy(pm,opt_MenuShowWhenVars); DBDeleteSetting(0,DBBranch,setting);
+ StrCopy(pm,opt_MenuOptions ); DBDeleteSetting(0,DBBranch,setting);
+ end;
+ end;
+ end;
+end;
+
+procedure addSaveUA(setting:pAnsiChar;txt:pWideChar); overload;
+begin
+ if (txt=nil) or (txt^=#0) then DBDeleteSetting(0,DBBranch,setting)
+ else DBWriteUnicode(0,DBBranch,setting,txt);
+end;
+
+procedure addSaveUA(setting:pAnsiChar;txt:pAnsiChar); overload;
+begin
+ if (txt=nil) or (txt^=#0) then DBDeleteSetting(0,DBBranch,setting)
+ else DBWriteString(0,DBBranch,setting,txt);
+end;
+
+procedure SaveUA(idx:integer);
+var
+ setting:array [0..63] of AnsiChar;
+ p,pm:pAnsiChar;
+ lmenu:tMenuType;
+begin
+ with UActionList[idx] do
+ begin
+ p:=GetUABranch(setting,dwActID);
+ if p<>nil then
+ begin
+ p:=StrCopyE(p,opt_UA);
+ p^:='/'; inc(p);
+
+ StrCopy(p,opt_Flags); DBWriteDWord(0,DBBranch,setting,
+ flags and not (UAF_REALTIME OR UAF_SPECIAL));
+
+ StrCopy(p,opt_TTBTooltip ); addSaveUA(setting,szTTBTooltip);
+ StrCopy(p,opt_TTBTooltipPressed); addSaveUA(setting,szTTBTooltipPressed);
+ StrCopy(p,opt_TTBShowWhenVars ); addSaveUA(setting,szTTBShowWhenVars);
+
+ StrCopy(p,opt_TabBTooltip ); addSaveUA(setting,szTabBTooltip);
+ StrCopy(p,opt_TabBTooltipPressed); addSaveUA(setting,szTabBTooltipPressed);
+
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ pm:=p;
+ pm^:=AnsiChar(ORD(lmenu)+ORD('0')); inc(pm);
+ pm^:='_'; inc(pm);
+ with UAMenuItem[lmenu] do
+ begin
+ StrCopy(pm,opt_MenuPopup ); addSaveUA(setting,szMenuPopup);
+ StrCopy(pm,opt_MenuNameVars ); addSaveUA(setting,szMenuNameVars);
+ StrCopy(pm,opt_MenuShowWhenVars); addSaveUA(setting,szMenuShowWhenVars);
+ StrCopy(pm,opt_MenuOptions ); DBWriteWord(0,DBBranch,setting,menu_opt);
+ end;
+ end;
+ end;
+ end;
+end;
+
+procedure SaveUAs;
+var
+ i:integer;
+begin
+ for i:=0 to HIGH(UActionList) do
+ SaveUA(i);
+end;
+
+function LoadUA(idx:integer):integer;
+var
+ setting:array [0..63] of AnsiChar;
+ p,pm:pAnsiChar;
+ lmenu:tMenuType;
+begin
+ result:=0;
+ with UActionList[idx] do
+ begin
+ p:=GetUABranch(setting,dwActID);
+ if p<>nil then
+ begin
+ p:=StrCopyE(p,opt_UA);
+ p^:='/'; inc(p);
+
+ StrCopy(p,opt_Flags);
+ flags:=DBReadDWord(0,DBBranch,setting,dword(UAF_SPECIAL));
+ if flags=dword(UAF_SPECIAL) then // no settings
+ begin
+ flags:=0;
+ exit;
+ end;
+ // no need to use previous "pressed" state
+ if (flags and UAF_SAVESTATE)=0 then
+ flags:=flags and not UAF_PRESSED;
+
+ flags:=flags and not UAF_REALTIME;
+ result:=1;
+
+ StrCopy(p,opt_TTBTooltip ); szTTBTooltip :=DBReadString (0,DBBranch,setting);
+ StrCopy(p,opt_TTBTooltipPressed); szTTBTooltipPressed:=DBReadString (0,DBBranch,setting);
+ StrCopy(p,opt_TTBShowWhenVars ); szTTBShowWhenVars :=DBReadUnicode(0,DBBranch,setting);
+
+ StrCopy(p,opt_TabBTooltip ); szTabBTooltip :=DBReadUnicode(0,DBBranch,setting);
+ StrCopy(p,opt_TabBTooltipPressed); szTabBTooltipPressed:=DBReadUnicode(0,DBBranch,setting);
+
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ pm:=p;
+ pm^:=AnsiChar(ORD(lmenu)+ORD('0')); inc(pm);
+ pm^:='_'; inc(pm);
+ with UAMenuItem[lmenu] do
+ begin
+ StrCopy(pm,opt_MenuPopup ); szMenuPopup :=DBReadUnicode(0,DBBranch,setting);
+ StrCopy(pm,opt_MenuNameVars ); szMenuNameVars :=DBReadUnicode(0,DBBranch,setting);
+ StrCopy(pm,opt_MenuShowWhenVars); szMenuShowWhenVars:=DBReadUnicode(0,DBBranch,setting);
+ StrCopy(pm,opt_MenuOptions ); menu_opt :=DBReadWord (0,DBBranch,setting);
+ end;
+ end;
+ end;
+ end;
+end;
+(*
+function LoadUAs:integer;
+{
+var
+ section:array [0..63] of AnsiChar;
+ p:PAnsiChar;
+ i:integer;
+}
+begin
+ result:=0;
+{
+ MaxTasks:=DBReadByte(0,opt_tasks,opt_count);
+ result:=MaxTasks;
+ if MaxTasks>0 then
+ begin
+ GetMem (TaskList ,MaxTasks*SizeOf(tTaskRec));
+ FillChar(TaskList^,MaxTasks*SizeOf(tTaskRec),0);
+ for i:=0 to MaxTasks-1 do
+ begin
+ p:=StrEnd(IntToStr(section,i));
+ with TaskList[i] do
+ begin
+ StrCopy(p,opt_flags ); flags :=DBReadDWord (0,opt_tasks,section);
+ StrCopy(p,opt_name ); name :=DBReadUnicode(0,opt_tasks,section);
+ StrCopy(p,opt_action); action :=DBReadDWord (0,opt_tasks,section);
+ end;
+ end;
+ end;
+}
+end;
+*)
+procedure SetAllActionUsers(var ActionItem:tMyActionItem; initial:boolean);
+var
+ luse:boolean;
+ lmenu:tMenuType;
+begin
+ if NamesArray[uaHotkey].enable then
+ begin
+ if (ActionItem.flags and UAF_REGHOTKEY)<>0 then
+ AddCoreHotkey(ActionItem)
+ else
+ DeleteCoreHotkey(ActionItem);
+ end;
+ if not initial then
+ begin
+ if NamesArray[uaTTB].enable then
+ begin
+ DeleteTTBButton(ActionItem); // no modify command there, just delete, then insert back
+ if (ActionItem.flags and UAF_REGTTBB)<>0 then
+ AddTTBButton(ActionItem);
+ end;
+
+ if NamesArray[uaTAB].enable then
+ begin
+ if (ActionItem.flags and UAF_REGTABB)<>0 then
+ AddTabBBButton(ActionItem)
+ else
+ DeleteTabBBButton(ActionItem);
+ end;
+ end;
+
+ luse:=false;
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ if NamesArray[uaMenu+ORD(lmenu)].enable then
+ begin
+ if (ActionItem.UAMenuItem[lmenu].menu_opt and UAF_MENUUSE)<>0 then
+ begin
+ luse:=true;
+ if ActionItem.UAMenuItem[lmenu].changed then
+ DeleteMenuItem(ActionItem,lmenu);
+ CreateMenuItem(ActionItem,lmenu);
+ end
+ else
+ DeleteMenuItem(ActionItem,lmenu);
+ end;
+ end;
+
+ if (not luse) and (ActionItem.hMenuService<>0) then
+ begin
+ DestroyServiceFunction(ActionItem.hMenuService);
+ ActionItem.hMenuService:=0;
+ end;
+end;
diff --git a/plugins/Actman30/ua/i_ua.inc b/plugins/Actman30/ua/i_ua.inc
new file mode 100644
index 0000000000..18cd78a9c7
--- /dev/null
+++ b/plugins/Actman30/ua/i_ua.inc
@@ -0,0 +1,219 @@
+{}
+function AddUAction(idx:integer; ptr:pChain):integer;
+var
+ buf:array [0..127] of AnsiChar;
+begin
+ if idx<0 then idx:=Length(UActionList);
+ if idx=Length(UActionList) then
+ SetLength(UActionList,Length(UActionList)+1);
+
+ FillChar(UActionList[idx],SizeOf(tMyActionItem),0);
+
+ with UActionList[idx] do
+ begin
+ // get Action settings
+ dwActID:=ptr^.id;
+ StrDupW(szActDescr,ptr^.descr);
+ wSortIndex:=idx;
+
+ // prepare for work
+ IntToStr(StrCopyE(buf,'Actions/Action_'),ptr^.id);
+ StrDup(szNameID,@buf);
+ AddIcolibIcon (UActionList[idx]);
+ end;
+
+ SetLength(arMenuRec,Length(UActionList)+1);
+ FillChar (arMenuRec[HIGH(arMenuRec)],SizeOf(tuaMenuRecA),0);
+ result:=idx;
+end;
+
+function CreateUActionList:integer;
+var
+ ptr,ptr1:pChain;
+ i:integer;
+begin
+ result:=CallService(MS_ACT_GETLIST,0,LPARAM(@ptr));
+ SetLength(UActionList,result);
+
+ SetLength(arMenuRec, result+1);
+ FillChar (arMenuRec[0],(result+1)*SizeOf(tuaMenuRecA),0);
+
+ if result>0 then
+ begin
+ ptr1:=ptr;
+ inc(pbyte(ptr),4);
+ for i:=0 to result-1 do
+ begin
+ AddUAction(i,ptr);
+ LoadUA(i); // just here coz at list changes for new we don't have settings
+ if (UActionList[i].flags and UAF_2STATE)<>0 then
+ AddIcolibIconP(UActionList[i]);
+ SetAllActionUsers(UActionList[i],true);
+ inc(ptr);
+ end;
+ CallService(MS_ACT_FREELIST,0,LPARAM(ptr1));
+ end;
+end;
+
+// "compact" means need to compact list/delete settings (Delete, not just exit)
+procedure DeleteUAction(num:integer;compact:boolean);
+var
+ ActionItem:pMyActionItem;
+ luse:boolean;
+ lmenu:tMenuType;
+begin
+ if compact then
+ DeleteUASettings(num);
+
+ ActionItem:=@UActionList[num];
+
+ DeleteIcolibIcon(ActionItem^);
+
+ if (ActionItem.flags and UAF_REGHOTKEY)<>0 then
+ DeleteCoreHotkey(ActionItem^);
+
+ if (ActionItem.flags and UAF_REGTTBB)<>0 then
+ DeleteTTBButton(ActionItem^);
+ mFreeMem(ActionItem.szTTBTooltip);
+ mFreeMem(ActionItem.szTTBTooltipPressed);
+ mFreeMem(ActionItem.szTTBShowWhenVars);
+
+ if (ActionItem.flags and UAF_REGTABB)<>0 then
+ DeleteTabBBButton(ActionItem^);
+ mFreeMem(ActionItem.szTabBTooltip);
+ mFreeMem(ActionItem.szTabBTooltipPressed);
+
+ luse:=false;
+ for lmenu:=main_menu to HIGH(tMenuType) do
+ begin
+ with ActionItem.UAMenuItem[lmenu] do
+ begin
+ if (menu_opt and UAF_MENUUSE)<>0 then
+ begin
+ luse:=true;
+ DeleteMenuItem(ActionItem^,lmenu);
+ end;
+ mFreeMem(szMenuPopup);
+ mFreeMem(szMenuNameVars);
+ mFreeMem(szMenuShowWhenVars);
+ end;
+ end;
+
+ if (not luse) and (ActionItem.hMenuService<>0) then
+ begin
+ DestroyServiceFunction(ActionItem.hMenuService);
+ ActionItem.hMenuService:=0;
+ end;
+
+ // Free Memory
+ mFreeMem(ActionItem.szNameID);
+ mFreeMem(ActionItem.szActDescr);
+
+ if compact then
+ begin
+ // compact list
+ if num<HIGH(UActionList) then
+ begin
+ move(UActionList[num+1],UActionList[num],(HIGH(UACtionList)-num)*SizeOf(tMyActionItem));
+ end;
+ SetLength(UActionList,Length(UActionList)-1);
+ end;
+end;
+
+function ActListChange(wParam:WPARAM;lParam:LPARAM):integer; cdecl;
+var
+ ptr,ptr1:pChain;
+ idx,i,j,count:integer;
+ bFound:boolean;
+begin
+ result:=0;
+
+ count:=CallService(MS_ACT_GETLIST,0,TLPARAM(@ptr));
+
+ if count>0 then
+ begin
+ ptr1:=ptr;
+ inc(pbyte(ptr),4);
+ if wParam<>0 then
+// if (wParam and (ACTM_NEW or ACTM_RENAME or ACTM_SORT or ACTM_DELETE))<>0 then
+ for i:=0 to count-1 do
+ begin
+ // search corresponding element
+ idx:=-1;
+ for j:=0 to HIGH(UActionList) do
+ begin
+ if UActionList[j].dwActID=ptr^.id then
+ begin
+ idx:=j;
+ break;
+ end;
+ end;
+ // if we have no item in list for this action - then add new one
+ if idx<0 then
+ begin
+ idx:=AddUAction(-1,ptr);
+ end
+ else
+ begin
+ if (wParam and ACTM_RENAME)<>0 then
+ begin
+ // check for time economy - no need to change ALL items
+ if StrCmpW(UActionList[idx].szActDescr,ptr^.descr)<>0 then
+ begin
+ mFreeMem(UActionList[idx].szActDescr);
+ StrDupW (UActionList[idx].szActDescr,ptr^.descr);
+ end;
+ end;
+ end;
+// not so necessary to check really
+// if (wParam and (ACTM_SORT or ACTM_DELETE or ACTM_NEW))<>0 then
+ UActionList[idx].wSortIndex:=i;
+
+ inc(ptr);
+ end;
+ end
+ else
+ ptr1:=nil;
+
+ // now search deleted items
+ if (wParam and ACTM_DELETE)<>0 then
+ begin
+ for j:=HIGH(UActionList) downto 0 do
+ begin
+ bFound:=false;
+ if count>0 then
+ begin
+ ptr:=ptr1;
+ inc(pbyte(ptr),4);
+ for i:=0 to count-1 do
+ begin
+ if UActionList[j].dwActID=ptr^.id then
+ begin
+ bFound:=true;
+ break;
+ end;
+ inc(ptr);
+ end;
+ end;
+ if not bFound then
+ DeleteUAction(j,true);
+ end;
+ end;
+
+ if count>0 then
+ CallService(MS_ACT_FREELIST,0,TLPARAM(ptr1));
+
+ // show changes in dialog
+ if settings<>0 then
+ begin
+ FillActionList(settings);
+ ShowAction(settings,-1);
+ end;
+
+ SaveUAs;
+ FillChar(arMenuRec[0],Length(arMenuRec)*SizeOf(tuaMenuRecA),0);
+ for i:=0 to HIGH(UActionList) do
+ begin
+ SetAllActionUsers(UActionList[i],false);
+ end;
+end;
diff --git a/plugins/Actman30/ua/i_uaplaces.inc b/plugins/Actman30/ua/i_uaplaces.inc
new file mode 100644
index 0000000000..0b8ee9468d
--- /dev/null
+++ b/plugins/Actman30/ua/i_uaplaces.inc
@@ -0,0 +1,832 @@
+{}
+(*
+const
+ MenuServices:array [tMenuType] of pAnsiChar = (
+ 'CList/AddMainMenuItem' {MS_CLIST_ADDMAINMENUITEM },
+ 'CList/AddContactMenuItem'{MS_CLIST_ADDCONTACTMENUITEM},
+ 'CList/AddTrayMenuItem' {MS_CLIST_ADDTRAYMENUITEM },
+ 'CList/AddProtoMenuItem' {MS_CLIST_ADDPROTOMENUITEM },
+ 'CList/AddStatusMenuItem' {MS_CLIST_ADDSTATUSMENUITEM }
+ );
+*)
+type
+ tuaMenuRec = record
+ hMenuRoot:HMENU;
+ position :integer;
+ end;
+ tuaMenuRecA = array [tMenuType] of tuaMenuRec;
+
+var
+ arMenuRec: array of tuaMenuRecA;
+
+//===== Support =====
+
+function ServiceCallWithLParam(wParam:WPARAM; lParam:LPARAM):int_ptr; cdecl;
+begin
+ result:=CallService(MS_ACT_RUNBYID, lParam, wParam);
+end;
+
+procedure SetTTBState(const ActionItem:tMyActionItem);
+var
+ lflag:integer;
+begin
+ if ActionItem.hTTBButton=0 then exit;
+ if (ActionItem.flags and UAF_2STATE)=0 then exit;
+
+ lflag:=CallService(MS_TTB_GETBUTTONSTATE,ActionItem.hTTBButton,0);
+ if lflag=TTBST_PUSHED then
+ begin
+ if (ActionItem.flags and (UAF_2STATE+UAF_PRESSED))<>(UAF_2STATE+UAF_PRESSED) then exit;
+ lflag:=TTBST_RELEASED;
+ end
+ else
+ begin
+ if (ActionItem.flags and (UAF_2STATE+UAF_PRESSED))=(UAF_2STATE+UAF_PRESSED) then exit;
+ if (ActionItem.flags and UAF_PRESSED)=0 then exit;
+ lflag:=TTBST_PUSHED;
+ end;
+ CallService(MS_TTB_SETBUTTONSTATE,ActionItem.hTTBButton,lflag);
+end;
+
+procedure SetTABState(hContact:THANDLE;const ActionItem:tMyActionItem;pressed:integer);
+var
+ tabb:BBButton;
+ pc:pWideChar;
+begin
+ FillChar(tabb,SizeOf(tabb),0);
+ tabb.cbSize :=SizeOf(tabb);
+ tabb.dwButtonID :=ActionItem.dwActID;
+ tabb.pszModuleName:=MODULE_NAME;
+
+ if pressed<>0 then
+ begin
+ pc:=ActionItem.szTabBTooltipPressed;
+ if pc=nil then pc:=ActionItem.szTabBTooltip;
+ tabb.hIcon:=ActionItem.hIcolibIconPressed;
+ tabb.bbbFlags:=BBSF_PUSHED;
+ end
+ else
+ begin
+ pc:=ActionItem.szTabBTooltip;
+ tabb.hIcon:=ActionItem.hIcolibIcon;
+ tabb.bbbFlags:=BBSF_RELEASED;
+ end;
+ if pc=nil then pc:=ActionItem.szActDescr;
+ tabb.szTooltip.w:=pc;
+ CallService(MS_BB_SETBUTTONSTATE,hContact,TLPARAM(@tabb));
+end;
+
+function IsLocalItem(const UAItem:tMyActionItem):boolean;
+begin
+ result:=((UAItem.flags and UAF_GLOBAL)=0) and
+ (UAItem.UAMenuItem[main_menu ].hMenuItem=0) and
+ (UAItem.UAMenuItem[tray_menu ].hMenuItem=0) and
+ (UAItem.UAMenuItem[proto_menu ].hMenuItem=0) and
+ (UAItem.UAMenuItem[status_menu].hMenuItem=0) and
+ (UAItem.hTTBButton=0);
+end;
+
+function ServiceCallWithFParam(wParam:WPARAM; lParam:LPARAM; fParam:LPARAM):int_ptr; cdecl;
+var
+ i:integer;
+ setting:array [0..63] of AnsiChar;
+ p:pAnsiChar;
+ cnt:THANDLE;
+ state:integer;
+begin
+ for i:=0 to HIGH(UActionList) do
+ begin
+ with UActionList[i] do
+ if dwActID=cardinal(fParam) then
+ if (flags and UAF_2STATE)<>0 then
+ begin
+ // sync buttons/menus
+ if IsLocalItem(UActionList[i]) then
+ begin
+ // if (flags and UAF_SAVESTATE)<>0 then
+ begin
+ state:=DBReadByte(lastContact,opt_ua,szNameID);
+ state:=state xor 1;
+ DBWriteByte(lastContact,opt_ua,szNameID,state);
+ cnt:=lastContact;
+ end;
+ end
+ else
+ begin
+ flags:=flags xor UAF_PRESSED;
+ // save "pressed" state
+ if (flags and UAF_SAVESTATE)<>0 then
+ begin
+ p:=GetUABranch(setting,dwActID);
+ if p<>nil then
+ begin
+ p:=StrCopyE(p,opt_ua);
+ p^:='/'; inc(p);
+ StrCopy(p,opt_flags);
+ DBWriteDWord(0,DBBranch,setting,flags and not UAF_REALTIME);
+ end;
+ end;
+
+ if hTTBButton<>0 then
+ SetTTBState(UActionList[i]);
+
+ cnt:=0;
+ state:=ORD(flags and UAF_PRESSED);
+ end;
+ if (flags and UAF_REGTABB)<>0 then
+ SetTABState(cnt,UActionList[i],state);
+
+ break;
+ end;
+ end;
+
+ result:=CallService(MS_ACT_RUNBYID, fParam, wParam);
+end;
+
+function AddIcolibIconP(var ActionItem:tMyActionItem):THANDLE;
+var
+ sid:TSKINICONDESC;
+ buf,buf1:array [0..63] of WideChar;
+begin
+ if (ActionItem.hIcolibIconPressed=0) or
+ (ActionItem.hIcolibIconPressed=ActionItem.hIcolibIcon) then
+ begin
+ // add icon for action to icolib
+ fillChar(sid,SizeOf(sid),0);
+ sid.cbSize :=sizeof(sid);
+ sid.szSection .w:=ICOLIB_ACTSECTION;
+ sid.szDefaultFile.w:=szMyPath;
+ sid.iDefaultIndex :=-IDI_ACTION;
+ sid.cx :=16;
+ sid.cy :=16;
+ sid.flags :=SIDF_ALL_UNICODE;
+ // icon "off"
+ StrCopyW(StrCopyEW(buf,ActionItem.szActDescr),' (pressed)');
+ sid.szDescription.w:=@buf;
+ StrCopy(StrCopyE(@buf1,ActionItem.szNameID),'_pressed');
+ sid.pszName :=@buf1;
+ ActionItem.hIcolibIconPressed:=Skin_AddIcon(@sid);
+ end;
+ result:=ActionItem.hIcolibIconPressed;
+end;
+
+function AddIcolibIcon(var ActionItem:tMyActionItem):THANDLE;
+var
+ sid:TSKINICONDESC;
+begin
+ if ActionItem.hIcolibIcon=0 then
+ begin
+ // add icon for action to icolib
+ fillChar(sid,SizeOf(sid),0);
+ sid.cbSize :=sizeof(sid);
+ sid.szSection .w:=ICOLIB_ACTSECTION;
+ sid.szDefaultFile.w:=szMyPath;
+ sid.iDefaultIndex :=-IDI_ACTION;
+ sid.cx :=16;
+ sid.cy :=16;
+ sid.flags :=SIDF_ALL_UNICODE;
+ // icon "on"
+ sid.szDescription.w:=ActionItem.szActDescr;
+ sid.pszName :=ActionItem.szNameID;
+ ActionItem.hIcolibIcon:=Skin_AddIcon(@sid);
+ end;
+ result:=ActionItem.hIcolibIcon;
+end;
+
+procedure DeleteIcolibIconP(var ActionItem:tMyActionItem);
+var
+ buf1:array [0..63] of WideChar;
+begin
+ if (ActionItem.hIcolibIconPressed<>0) and
+ (ActionItem.hIcolibIconPressed<>ActionItem.hIcolibIcon) then
+ begin
+ StrCopy(StrCopyE(@buf1,ActionItem.szNameID),'_pressed');
+ CallService(MS_SKIN2_REMOVEICON,0,LPARAM(@buf1));
+ ActionItem.hIcolibIconPressed:=ActionItem.hIcolibIcon;
+ end;
+end;
+
+procedure DeleteIcolibIcon(var ActionItem:tMyActionItem);
+begin
+ DeleteIcolibIconP(ActionItem);
+ CallService(MS_SKIN2_REMOVEICON,0,LPARAM(ActionItem.szNameID));
+ ActionItem.hIcolibIcon :=0;
+ ActionItem.hIcolibIconPressed:=0;
+end;
+
+//===== Really places =====
+
+//----- Hotkeys -----
+
+function AddCoreHotkey(var ActionItem:tMyActionItem):boolean;
+var
+ hkd:THOTKEYDESC;
+begin
+ if (ActionItem.flags and UAF_HKREGGED)=0 then
+ begin
+ FillChar(hkd,SizeOf(hkd),0);
+ hkd.cbSize := SizeOf(hkd); // HOTKEYDESC_SIZE_V1 for pre-0.9
+ hkd.dwFlags := HKD_UNICODE; // since 0.9 only
+ hkd.pszName := ActionItem.szNameID;
+ hkd.pszDescription.w:= ActionItem.szActDescr;
+ hkd.pszSection .w:= MODULE_NAME;
+ hkd.pszService := SERVICE_WITH_LPARAM_NAME;
+ hkd.lParam := ActionItem.dwActID;
+ result:=Hotkey_Register(@hkd)<>0;
+ if result then
+ ActionItem.flags:=ActionItem.flags or UAF_HKREGGED;
+ end
+ else
+ result:=true; //!!
+end;
+
+procedure DeleteCoreHotkey(var ActionItem:tMyActionItem);
+begin
+ if // bCoreHotkeyPresents and
+ // (ServiceExists(MS_HOTKEY_UNREGISTER)<>0) and
+ ((ActionItem.flags and UAF_HKREGGED)<>0) then
+ begin
+ CallService(MS_HOTKEY_UNREGISTER,0,LParam(ActionItem.szNameID));
+ ActionItem.flags:=ActionItem.flags and not UAF_HKREGGED;
+ end;
+end;
+
+//----- Common menu functions -----
+
+function AddRootMenuIcon(szPopupName:pWideChar):THANDLE;
+var
+ sid:TSKINICONDESC;
+begin
+ FillChar(sid,SizeOf(sid),0);
+ //first - register icon for root popup
+ sid.cbSize := sizeof(sid);
+ sid.szSection.w := ICOLIB_MNUSECTION;
+ sid.flags := SIDF_ALL_UNICODE;
+ sid.cx := 16;
+ sid.cy := 16;
+ sid.szDescription.w:= szPopupName;
+ sid.szDefaultFile.w:= szMyPath;
+ sid.iDefaultIndex := -IDI_ACTION;
+ WideToAnsi(szPopupName,sid.pszName);
+ result:=Skin_AddIcon(@sid);
+ mFreeMem(sid.pszName);
+end;
+
+procedure DeleteMenuItem(var ActionItem:tMyActionItem;mtype:tMenuType);
+var
+ i:integer;
+ hMenuRoot:THANDLE;
+ p:pMyActionItem;
+begin
+ with ActionItem.UAMenuItem[mtype] do
+ begin
+ if hMenuItem=0 then exit;
+ CallService(MO_REMOVEMENUITEM,hMenuItem,0);
+ hMenuItem:=0;
+ end;
+
+ hMenuRoot:=ActionItem.UAMenuItem[mtype].hMenuRoot;
+ if hMenuRoot<>0 then
+ begin
+ for i:=0 to HIGH(UActionList) do
+ begin
+ p:=@UActionList[i];
+ // presents somethere else
+ if (p<>@ActionItem) and (p.UAMenuItem[mtype].hMenuRoot=hMenuRoot) then
+ exit;
+ end;
+ // menu array cleanup now?
+ for i:=0 to HIGH(arMenuRec) do
+ begin
+ if arMenuRec[i][mtype].hMenuRoot=hMenuRoot then
+ begin
+ FillChar(arMenuRec[i][mtype],SizeOf(tuaMenuRec),0);
+// arMenuRec[i][mtype].hMenuRoot:=0;
+ break;
+ end;
+ end;
+ CallService(MO_REMOVEMENUITEM,hMenuRoot,0);
+ ActionItem.UAMenuItem[mtype].hMenuRoot:=0;
+ end;
+end;
+
+function GetMenuPosition(hMenu:HMENU;mtype:tMenuType;toset:boolean):integer;
+var
+ i:integer;
+begin
+ result:=0;
+ for i:=0 to HIGH(arMenuRec) do
+ begin
+ if arMenuRec[i][mtype].hMenuRoot=hMenu then
+ begin
+ if toset then
+ inc(arMenuRec[i][mtype].position,100000);
+ result:=arMenuRec[i][mtype].position;
+ break;
+ end;
+ end;
+end;
+
+function MakeMenuItem(mtype:tMenuType;clmi:PCListMenuItem):THANDLE;
+begin
+ case mtype of
+ main_menu : result:=Menu_AddMainMenuItem(clmi);
+ contact_menu: result:=Menu_AddContactMenuItem(clmi);
+ tray_menu : result:=Menu_AddTrayMenuItem(clmi);
+ proto_menu : result:=Menu_AddProtoMenuItem(clmi);
+ status_menu : result:=Menu_AddStatusMenuItem(clmi);
+ else
+ result:=0;
+ end;
+end;
+
+procedure CreateMenuItem(var ActionItem:tMyActionItem;mtype:tMenuType);
+var
+ i:integer;
+ ActItem:pMyActionItem;
+ ActMItem,UAMenuItem:pUAMenuItem;
+ clmi:TCListMenuItem;
+ res:boolean;
+ extra:pWideChar;
+begin
+{}
+ UAMenuItem:=@ActionItem.UAMenuItem[mtype];
+ if UAMenuItem.hMenuItem<>0 then exit;
+
+ // create popup menu
+{}{}
+ res:=true;
+ if (UAMenuItem.szMenuPopup<>nil) and (UAMenuItem.szMenuPopup^<>#0) then
+ begin
+ res:=false;
+ for i:=0 to HIGH(UActionList) do
+ begin
+ // try to find root popup with same name (if we already created one)
+ ActItem :=@UActionList[i];
+ ActMItem:=@ActItem.UAMenuItem[mtype];
+
+ if (ActMItem.szMenuPopup<>nil) and
+ (ActMItem.hMenuRoot<>0) and
+ ( (ActItem<>@ActionItem) and
+ (StrCmpW(ActMItem.szMenuPopup,UAMenuItem.szMenuPopup)=0) ) then
+ begin
+ UAMenuItem.hMenuRoot:=ActMItem.hMenuRoot;
+ res:=true;
+ break;
+ end;
+ end;
+ end;
+ // popup menu not found
+ if not res then
+ begin
+ FillChar(clmi,SizeOf(clmi),0);
+ clmi.cbSize:=SizeOf(clmi);
+ clmi.flags :=CMIF_UNICODE{ or CMIF_ICONFROMICOLIB};
+
+ if (UAMenuItem.szMenuPopup<>nil) and (UAMenuItem.szMenuPopup^<>#0) then
+ clmi.szName.w:=ParseVarString(UAMenuItem.szMenuPopup)
+ else
+ clmi.szName.w:=ActionItem.szActDescr;
+
+ clmi.hIcon :=AddRootMenuIcon(clmi.szName.w);
+ clmi.position:=ActionItem.wSortIndex*10;
+
+ // position in Root Menu
+ inc(clmi.position,GetMenuPosition(0,mtype,
+ (UAMenuItem.menu_opt and UAF_MENUSEP)<>0));
+
+ UAMenuItem.hMenuRoot:=MakeMenuItem(mtype,@clmi);
+ //CallService(MenuServices[mtype],0,LPARAM(@clmi));
+ if clmi.szName.w<>ActionItem.szActDescr then
+ mFreeMem(clmi.szName.w);
+
+ for i:=1 to HIGH(arMenuRec) do
+ begin
+ with arMenuRec[i][mtype] do
+ if hMenuRoot=0 then
+ begin
+// MenuName :=ActionItem.szActDescr;
+ hMenuRoot:=UAMenuItem.hMenuRoot;
+ break;
+ end;
+ end;
+
+ end;
+{}{}
+
+ // Now Menu Item preparing
+{}{}
+ FillChar(clmi,SizeOf(clmi),0);
+ clmi.cbSize:=SizeOf(clmi);
+ clmi.flags:=CMIF_UNICODE{ or CMIF_ICONFROMICOLIB};
+ if (ActionItem.flags and (UAF_2STATE+UAF_PRESSED))<>(UAF_2STATE+UAF_PRESSED) then
+ begin
+ clmi.hIcon:=ActionItem.hIcolibIcon;
+ extra:='0';
+ end
+ else
+ begin
+ clmi.hIcon:=ActionItem.hIcolibIconPressed;
+ clmi.flags:=CMIF_UNICODE {or CMIF_ICONFROMICOLIB }or CMIF_CHECKED;
+ extra:='1';
+ end;
+
+ with ActionItem.UAMenuItem[mtype] do
+ begin
+ if (szMenuNameVars<>nil) and (szMenuNameVars^<>#0) then
+ clmi.szName.w:=ParseVarString(szMenuNameVars,0,extra)
+ else
+ clmi.szName.w:=ActionItem.szActDescr;
+
+ if hMenuRoot<>0 then
+ begin
+ clmi.flags:=clmi.flags or CMIF_ROOTHANDLE;
+ clmi.szPopupName.w:=pWideChar(hMenuRoot);
+ end;
+ end;
+
+ clmi.pszService:=ActionItem.szNameID;
+ if ActionItem.hMenuService=0 then
+ ActionItem.hMenuService:=CreateServiceFunctionParam(
+ clmi.pszService,@ServiceCallWithFParam,ActionItem.dwActID);
+
+ clmi.position:=ActionItem.wSortIndex*10;
+{}{}
+ inc(clmi.position,GetMenuPosition(UAMenuItem.hMenuRoot,mtype,
+ (UAMenuItem.menu_opt and UAF_MENUSEP)<>0));
+
+ UAMenuItem.hMenuItem:=MakeMenuItem(mtype,@clmi);
+ //CallService(MenuServices[mtype],0,LPARAM(@clmi));
+ if clmi.szName.w<>ActionItem.szActDescr then
+ mFreeMem(clmi.szName.w);
+{}
+
+end;
+
+function PreBuildMenu(mtype:tMenuType;hContact:THANDLE=0):int;
+var
+ i:integer;
+ mi:TCListMenuItem;
+ p,extra:pWideChar;
+begin
+ result:=0;
+
+ FillChar(mi,SizeOf(mi),0);
+ mi.cbSize:=SizeOf(mi);
+
+ for i:=0 to HIGH(UActionList) do
+ begin
+ mi.flags:=CMIM_FLAGS;
+ p:=nil;
+ with UActionList[i] do
+ begin
+ with UAMenuItem[mtype] do
+ begin
+ if hMenuItem<>0 then // it means, we process that item here
+ begin
+ mi.szName.w:=nil;
+ // Show / hide
+ if isVarsInstalled then
+ begin
+ if (szMenuShowWhenVars<>nil) and (szMenuShowWhenVars^<>#0) then
+ begin
+ p:=ParseVarString(szMenuShowWhenVars,hContact);
+ if p<>nil then
+ begin
+ if StrCmpW(p,'1')<>0 then
+ mi.flags:=CMIM_FLAGS or CMIF_HIDDEN;
+ mFreeMem(p);
+ end;
+ end;
+ end;
+
+ // change if need to show only
+ // (popup can be used by many items, keep unchanged)
+ if (mi.flags and CMIF_HIDDEN)=0 then
+ begin
+ //!!!! icon (check for contact menu)
+ mi.flags:=mi.flags or CMIM_ICON or CMIM_FLAGS{ or CMIF_ICONFROMICOLIB};
+
+ if (mtype=contact_menu) and IsLocalItem(UActionList[i]) then
+ begin
+ lastContact:=hContact;
+ if ((flags and UAF_2STATE)<>0) and
+ (DBReadByte(hContact,opt_ua,szNameID)<>0) then
+ begin
+ mi.flags:=mi.flags or CMIF_CHECKED;
+ mi.hIcon:=hIcolibIconPressed;
+ extra:='1';
+ flags:=flags or UAF_PRESSED;
+ end
+ else
+ begin
+ mi.hIcon:=hIcolibIcon;
+ flags:=flags and not UAF_PRESSED;
+ extra:='0';
+ end;
+
+ end
+ else
+ begin
+ if (flags and (UAF_2STATE+UAF_PRESSED))=(UAF_2STATE+UAF_PRESSED) then
+ begin
+ mi.flags:=mi.flags or CMIF_CHECKED;
+ mi.hIcon:=hIcolibIconPressed;
+ extra:='1';
+ end
+ else
+ begin
+ mi.hIcon:=hIcolibIcon;
+ extra:='0';
+ end;
+ end;
+
+ // new name
+ mi.flags:=mi.flags or CMIM_NAME or CMIF_UNICODE;
+ if (szMenuNameVars<>nil) and (szMenuNameVars^<>#0) then
+ mi.szName.w:=ParseVarString(szMenuNameVars,hContact,extra);
+
+ if mi.szName.w=nil then
+ mi.szName.w:=szActDescr;
+ end;
+
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuItem,LPARAM(@mi));
+ if mi.szName.w<>szActDescr then
+ mFreeMem(mi.szName.w);
+ end;
+ end;
+ end;
+
+ end;
+end;
+
+function PreBuildMainMenu(wParam:WPARAM;lParam:LPARAM):int; cdecl;
+begin
+ result:=PreBuildMenu(main_menu,wParam);
+end;
+
+function PreBuildContactMenu(wParam:WPARAM;lParam:LPARAM):int; cdecl;
+begin
+ result:=PreBuildMenu(contact_menu,wParam);
+end;
+
+function PreBuildTrayMenu(wParam:WPARAM;lParam:LPARAM):int; cdecl;
+begin
+ result:=PreBuildMenu(tray_menu,wParam);
+end;
+
+//----- TopToolbar -----
+
+procedure AddTTBButton(var ActionItem:tMyActionItem);
+var
+ mtButton:TTBButton;
+ pc,pc1,pc2:pAnsiChar;
+ res:boolean;
+ p:pWideChar;
+begin
+ if not NamesArray[uaTTB].enable then exit;
+
+ if ActionItem.hTTBButton=0 then
+ begin
+ // Add or not
+ if isVarsInstalled then
+ begin
+ if (ActionItem.szTTBShowWhenVars<>nil) and (ActionItem.szTTBShowWhenVars^<>#0) then
+ begin
+ p:=ParseVarString(ActionItem.szTTBShowWhenVars);
+ if p<>nil then
+ begin
+ res:=StrCmpW(p,'1')<>0;
+ mFreeMem(p);
+ end
+ else
+ res:=true;
+ if res then
+ exit;
+ end;
+ end;
+
+ FillChar(mtButton,SizeOf(mtButton),0);
+ mtButton.cbSize :=SizeOf(mtButton);
+
+ mtButton.pszService:=TTB_SERVICE_NAME;//SERVICE_WITH_LPARAM_NAME;
+ mtButton.lParamUp :=ActionItem.dwActID;
+ mtButton.lParamDown:=ActionItem.dwActID;
+
+ mtButton.hIconUp:=ActionItem.hIcolibIcon;
+ mtButton.hIconDn:=ActionItem.hIcolibIconPressed;
+
+ WideToAnsi(ActionItem.szActDescr,pc);
+
+ if (ActionItem.flags and UAF_2STATE)<>0 then
+ mtButton.dwFlags:=TTBBF_VISIBLE or TTBBF_SHOWTOOLTIP{ or TTBBF_ASPUSHBUTTON}
+ else
+ mtButton.dwFlags:=TTBBF_VISIBLE or TTBBF_SHOWTOOLTIP;
+
+ if ActionItem.szTTBTooltip =nil then
+ pc1:=pc
+ else pc1:=ActionItem.szTTBTooltip;
+
+ if ((ActionItem.flags and UAF_2STATE)=0) or
+ (ActionItem.szTTBTooltipPressed=nil) then
+ pc2:=pc1
+ else
+ pc2:=ActionItem.szTTBTooltipPressed;
+
+ mtButton.Name :=pc;
+ mtButton.pszTooltipUp :=pc1;
+ mtButton.pszTooltipDn :=pc2;
+
+ ActionItem.hTTBButton:=TopToolbar_AddButton(@mtButton);
+ if ActionItem.hTTBButton=THANDLE(-1) then
+ ActionItem.hTTBButton:=0;
+ mFreeMem(pc);
+ end;
+end;
+
+procedure DeleteTTBButton(var ActionItem:tMyActionItem);
+begin
+ if ActionItem.hTTBButton<>0 then
+ begin
+ CallService(MS_TTB_REMOVEBUTTON,ActionItem.hTTBButton,0);
+ ActionItem.hTTBButton:=0;
+ end;
+end;
+
+function TTBServiceCall(wParam:WPARAM; lParam:LPARAM):int_ptr; cdecl;
+var
+ i,lflag:integer;
+begin
+ result:=0;
+ for i:=0 to HIGH(UActionList) do
+ begin
+ if TLPARAM(UActionList[i].dwActID)=lParam then
+ begin
+ with UActionList[i] do
+ begin
+ if (flags and UAF_2STATE)<>0 then
+ begin
+ if CallService(MS_TTB_GETBUTTONSTATE,hTTBButton,0)=TTBST_PUSHED then
+ begin
+ lflag:=TTBST_RELEASED;
+ end
+ else
+ begin
+ lflag:=TTBST_PUSHED;
+ end;
+ CallService(MS_TTB_SETBUTTONSTATE,hTTBButton,lflag);
+ end;
+ end;
+
+ result:=ServiceCallWithFParam(0,0,lParam);
+ break;
+ end;
+ end;
+end;
+
+function OnTTBLoaded(wParam:WPARAM;lParam:LPARAM):int; cdecl;
+var
+ i:integer;
+begin
+ result:=0;
+ for i:=HIGH(UActionList) downto 0 do
+ begin
+ if (UActionList[i].flags and UAF_REGTTBB)<>0 then
+ AddTTBButton(UActionList[i]);
+ end;
+end;
+
+//----- TabSRMM Toolbar -----
+
+const
+ TABTOOLBAR_INITPOS = 350;
+
+procedure AddTabBBButton(var ActionItem:tMyActionItem);
+var
+ tabb:BBButton;
+begin
+ if not NamesArray[uaTAB].enable then exit;
+
+ if (ActionItem.flags and UAF_TBREGGED)=0 then
+ begin
+ FillChar(tabb,SizeOf(tabb),0);
+ // register Tab ButtonBar button
+ tabb.cbSize :=SizeOf(tabb);
+ tabb.dwButtonID :=ActionItem.dwActID;
+ tabb.pszModuleName:=MODULE_NAME;
+ tabb.dwDefPos :=(TABTOOLBAR_INITPOS+ActionItem.wSortIndex*10) and $7FFF;
+ tabb.iButtonWidth :=0;
+ tabb.hIcon :=ActionItem.hIcolibIcon;
+ if (ActionItem.flags and UAF_2STATE)<>0 then
+ tabb.bbbFlags:=BBBF_ISIMBUTTON or BBBF_ISLSIDEBUTTON or
+ BBBF_ISCHATBUTTON or BBBF_ISPUSHBUTTON
+ else
+ tabb.bbbFlags:=BBBF_ISIMBUTTON or BBBF_ISLSIDEBUTTON or
+ BBBF_ISCHATBUTTON;
+
+ if ActionItem.szTabBTooltip<>nil then
+ tabb.szTooltip.w:=ActionItem.szTabBTooltip
+ else
+ tabb.szTooltip.w:=ActionItem.szActDescr;
+
+ if CallService(MS_BB_ADDBUTTON,0,LPARAM(@tabb))=0 then
+ ActionItem.flags:=ActionItem.flags or UAF_TBREGGED;
+ end;
+end;
+
+procedure DeleteTabBBButton(var ActionItem:tMyActionItem);
+var
+ tabb:BBButton;
+begin
+ if (ActionItem.flags and UAF_TBREGGED)<>0 then
+ begin
+ FillChar(tabb,SizeOf(tabb),0);
+ tabb.cbSize :=SizeOf(tabb);
+ tabb.dwButtonID :=ActionItem.dwActID;
+ tabb.pszModuleName:=MODULE_NAME;
+ CallService(MS_BB_REMOVEBUTTON,0,LPARAM(@tabb));
+ ActionItem.flags:=ActionItem.flags and not UAF_TBREGGED;
+ end;
+end;
+
+function OnTabButtonPressed(wParam:WPARAM;lParam:LPARAM):int; cdecl;
+var
+ cbcd:pCustomButtonClickData;
+// tabb:BBButton;
+// pc:pWideChar;
+ i:integer;
+begin
+ result:=0;
+ cbcd:=pointer(lParam);
+ if StrCmp(cbcd.pszModule,MODULE_NAME)<>0 then
+ exit;
+
+ for i:=0 to HIGH(UActionList) do
+ begin
+ with UActionList[i] do
+ begin
+ if cbcd.dwButtonId=dwActID then
+ begin
+{
+ FillChar(tabb,SizeOf(tabb),0);
+ tabb.cbSize :=SizeOf(tabb);
+ tabb.dwButtonID :=cbcd.dwButtonId;
+ tabb.pszModuleName:=MODULE_NAME;
+ if (flags and UAF_2STATE)<>0 then
+ begin
+ CallService(MS_BB_GETBUTTONSTATE,cbcd.hContact,TLPARAM(@tabb));
+ if IsLocalItem(UActionList[i]) then
+ begin
+ if DBReadByte(hContact,opt_ua,szNameID)<>0 then
+ end
+ else
+ begin
+ if (tabb.bbbFlags and BBSF_PUSHED)<>0 then
+ begin
+ pc:=szTabBTooltipPressed;
+ if pc=nil then pc:=szTabBTooltip;
+ tabb.hIcon:=hIcolibIconPressed;
+ end
+ else
+ begin
+ pc:=szTabBTooltip;
+ tabb.hIcon:=hIcolibIcon;
+ end;
+ if pc=nil then pc:=szActDescr;
+ tabb.szTooltip.w:=pc;
+ tabb.bbbFlags :=BBBF_ISIMBUTTON or BBBF_ISLSIDEBUTTON or
+ BBBF_ISCHATBUTTON or BBBF_ISPUSHBUTTON;
+ end
+ else
+ begin
+ tabb.hIcon:=hIcolibIcon;
+ tabb.szTooltip.w:=szTabBTooltip;
+ if tabb.szTooltip.w=nil then tabb.szTooltip.w:=szActDescr;
+ tabb.bbbFlags :=BBBF_ISIMBUTTON or BBBF_ISLSIDEBUTTON or
+ BBBF_ISCHATBUTTON;
+ end;
+
+ tabb.iButtonWidth:=0;
+ tabb.dwDefPos :=(TABTOOLBAR_INITPOS+wSortIndex*10) and $7FFF;
+ CallService(MS_BB_MODIFYBUTTON,0,TLPARAM(@tabb));
+}
+ ServiceCallWithFParam(cbcd.hContact,0,cbcd.dwButtonId);
+ result:=1;
+ break;
+ end;
+ end;
+ end;
+
+end;
+
+function OnTabBBLoaded(wParam:WPARAM;lParam:LPARAM):int; cdecl;
+var
+ i:integer;
+begin
+ result:=0;
+ for i:=HIGH(UActionList) downto 0 do
+ begin
+ if (UActionList[i].flags and UAF_REGTABB)<>0 then
+ AddTabBBButton(UActionList[i]);
+ end;
+end;
diff --git a/plugins/Actman30/ua/i_uavars.inc b/plugins/Actman30/ua/i_uavars.inc
new file mode 100644
index 0000000000..5b53cde26a
--- /dev/null
+++ b/plugins/Actman30/ua/i_uavars.inc
@@ -0,0 +1,121 @@
+{}
+const
+ MODULE_NAME = 'Actions';
+const
+ opt_groups:PAnsiChar = 'Group';
+ opt_ua :PAnsiChar = 'UA';
+ opt_id :PAnsiChar = 'id';
+ opt_flags :PAnsiChar = 'Flags';
+
+const
+ ICOLIB_ACTSECTION = MODULE_NAME+'/Registered actions';
+ ICOLIB_MNUSECTION = MODULE_NAME+'/Menu icons';
+
+ SERVICE_WITH_LPARAM_NAME = MODULE_NAME+'/CallAction';
+ TTB_SERVICE_NAME = MODULE_NAME+'/TTBAction';
+
+type
+ tMenuType = (main_menu,contact_menu,tray_menu,proto_menu,status_menu);
+ pUAMenuItem = ^tUAMenuItem;
+ tUAMenuItem = record
+ hMenuItem :THANDLE;
+ szMenuPopup :pWideChar;
+ szMenuNameVars :pWideChar;
+ szMenuShowWhenVars:pWideChar;
+ hMenuRoot :THANDLE;
+ menu_opt :dword;
+ changed :boolean;
+ end;
+type
+ pMyActionItem = ^tMyActionItem;
+ tMyActionItem = record
+ flags :dword;
+ dwActID :dword; // action ID
+ wSortIndex :word; // list/menu/toolbar order
+ // UseActions/Action_ID
+ szNameID :pAnsiChar; // uaction ID
+ szActDescr :pWideChar; // action name
+
+ hIcolibIcon,
+ hIcolibIconPressed :THANDLE;
+
+ hTTBButton :THANDLE; // TopToolbar button
+ szTTBTooltip :PAnsiChar;
+ szTTBTooltipPressed :PAnsiChar;
+ szTTBShowWhenVars :pWideChar;
+
+ szTabBTooltip :PWideChar; // TabSRMM toolbar button
+ szTabBTooltipPressed:PWideChar;
+
+ lastContact :THANDLE; // for contact menu
+ hMenuService :THANDLE; // common menu service
+ UAMenuItem :array [tMenuType] of tUAMenuItem;
+ end;
+
+const
+ UAF_NONE = 0;
+
+ UAF_REGHOTKEY = 1 shl 0; // hotkey
+ UAF_REGTTBB = 1 shl 1; // modern toolbar
+
+ UAF_REGTABB = 1 shl 5; // TabSRMM toolbar
+ UAF_USING = UAF_REGHOTKEY or UAF_REGTTBB or UAF_REGTABB;
+
+ UAF_2STATE = 1 shl 11; // Buttons/menu items are 2-state
+ UAF_PRESSED = 1 shl 12; // Button pressed/menu item selected
+ UAF_SAVESTATE = 1 shl 13; // Save or not "pressed" state
+ UAF_GLOBAL = 1 shl 14; // not contact related even if in contact menu only
+
+ // realtime, no save
+ UAF_HKREGGED = 1 shl 16; // hotkey registered
+ UAF_TBREGGED = 1 shl 17; // TabSRMM button registered
+ UAF_DISABLED = 1 shl 30; // action disabled atm
+ UAF_REALTIME = UAF_HKREGGED or UAF_TBREGGED or UAF_DISABLED;
+
+ UAF_SPECIAL = 1 shl 31; // for settings read
+
+ // menu options
+ UAF_MENUSEP = 1 shl 1; // menu item separated
+ UAF_MENUUSE = 1 shl 8; // use this menu
+
+type
+ tNameRec = record
+ name :PAnsiChar;
+ service:PAnsiChar;
+ mask :dword;
+ atype :word;
+ enable :boolean;
+ end;
+
+const
+ NumTypes = 8;
+const
+ uaTTB = 0;
+ uaTAB = 1;
+ uaHotkey = 2;
+ uaMenu = 3;
+
+const
+ NamesArray: array [0..NumTypes-1] of tNameRec = (
+ (name:'TopToolbar'; service:'TopToolBar/AddButton';
+ mask:UAF_REGTTBB ; atype:uaTTB; enable:false),
+ (name:'TabSRMM toolbar' ; service:'TabSRMM/ButtonsBar/AddButton';
+ mask:UAF_REGTABB ; atype:uaTAB; enable:false),
+ (name:'Core Hotkey' ; service:nil{MS_HOTKEY_REGISTER};
+ mask:UAF_REGHOTKEY; atype:uaHotkey; enable:false),
+ (name:'Main menu' ; service:nil;
+ mask:0; atype:uaMenu+(ORD(main_menu ) shl 8); enable:false),
+ (name:'Contact menu' ; service:nil;
+ mask:0; atype:uaMenu+(ORD(contact_menu) shl 8); enable:false),
+ (name:'Tray menu' ; service:'CList/AddTrayMenuItem';
+ mask:0; atype:uaMenu+(ORD(tray_menu ) shl 8); enable:false),
+ (name:'Protocol menus' ; service:'CList/AddProtoMenuItem';
+ mask:0; atype:uaMenu+(ORD(proto_menu ) shl 8); enable:false),
+ (name:'Status menu' ; service:'CList/AddStatusMenuItem';
+ mask:0; atype:uaMenu+(ORD(status_menu ) shl 8); enable:false)
+ );
+
+var
+ UActionList:array of tMyActionItem;
+var
+ szMyPath:array [0..MAX_PATH] of WideChar;
diff --git a/plugins/Actman30/ua/i_uconst.inc b/plugins/Actman30/ua/i_uconst.inc
new file mode 100644
index 0000000000..34dde3ee9e
--- /dev/null
+++ b/plugins/Actman30/ua/i_uconst.inc
@@ -0,0 +1,34 @@
+{resource constants}
+const
+ IDD_UA = 1031;
+
+ IDC_UA_ACTIONLIST = 1025;
+ IDC_UA_PLACELIST = 1026;
+
+ // menu settings
+ IDC_UA_SEPARATE = 1027;
+ IDC_UA_POPUPT = 1028;
+ IDC_UA_POPUPV = 1029;
+
+ IDC_UA_VARNAMEST = 1030;
+ IDC_UA_VARNAMESV = 1031;
+ IDC_UA_VARNAMESH = 1032;
+
+ IDC_UA_SHOWVART = 1033;
+ IDC_UA_SHOWVARV = 1034;
+ IDC_UA_SHOWVARH = 1035;
+
+ // toolbar settings
+ IDC_UA_TTNORMALT = 2028;
+ IDC_UA_TTNORMALV = 2029;
+ IDC_UA_TTPRESSEDT = 2030;
+ IDC_UA_TTPRESSEDV = 2031;
+
+ // common
+ IDC_UA_COMMON = 2000;
+ IDC_UA_TWOSTATE = 2001;
+ IDC_UA_SAVSTATE = 2002;
+
+ IDC_UA_GLOBAL = 2003;
+
+ IDI_ACTION = 101;
diff --git a/plugins/Actman30/ua/ua.pas b/plugins/Actman30/ua/ua.pas
new file mode 100644
index 0000000000..4aad8e1793
--- /dev/null
+++ b/plugins/Actman30/ua/ua.pas
@@ -0,0 +1,108 @@
+unit ua;
+
+interface
+
+implementation
+
+uses
+ windows, commctrl, messages,
+ mirutils, common, dbsettings, io, m_api, wrapper,
+ global;
+
+{$R ua.res}
+
+{$include m_actman.inc}
+
+{$include i_uconst.inc}
+{$include i_uavars.inc}
+
+// in - Action ID, out - action (group) number
+function GetUABranch(setting:pAnsiChar;id:cardinal):pAnsiChar;
+var
+ i:integer;
+ p,p1:pAnsiChar;
+begin
+ result:=nil;
+ p1:=StrCopyE(setting,opt_groups);
+ for i:=0 to CallService(MS_ACT_GETLIST,0,0)-1 do
+ begin
+ p:=StrEnd(IntToStr(p1,i));
+ p^:='/'; inc(p);
+ StrCopy(p,opt_id);
+ if DBReadDWord(0,DBBranch,setting)=id then
+ begin
+ p^:=#0;
+ result:=p;
+ break;
+ end;
+ end;
+end;
+
+var
+ amLink:tActionLink;
+
+{$include i_uaplaces.inc}
+{$include i_options.inc}
+{$include i_opt_dlg.inc}
+{$include i_ua.inc}
+{$include i_inoutxm.inc}
+
+// ------------ base interface functions -------------
+
+procedure Init;
+begin
+ GetModuleFileNameW(hInstance,szMyPath,MAX_PATH);
+
+ CreateServiceFunction(SERVICE_WITH_LPARAM_NAME,@ServiceCallWithLParam);
+ CreateServiceFunction(TTB_SERVICE_NAME ,@TTBServiceCall);
+ CheckPlacesAbility;
+
+ CreateUActionList;
+
+ HookEvent(ME_TTB_MODULELOADED ,@OnTTBLoaded);
+ HookEvent(ME_MSG_TOOLBARLOADED,@OnTabBBLoaded);
+ HookEvent(ME_MSG_BUTTONPRESSED,@OnTabButtonPressed);
+ HookEvent(ME_ACT_CHANGED ,@ActListChange);
+
+ HookEvent(ME_CLIST_PREBUILDMAINMENU , PreBuildMainMenu);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PreBuildContactMenu);
+ HookEvent(ME_CLIST_PREBUILDTRAYMENU , PreBuildTrayMenu);
+
+ HookEvent(ME_ACT_INOUT,@ActInOut);
+end;
+
+procedure DeInit;
+var
+ i:integer;
+begin
+ if Length(UActionList)>0 then
+ begin
+ for i:=HIGH(UActionList) downto 0 do
+ begin
+ DeleteUAction(i,false);
+ end;
+ SetLength(UActionList,0);
+ end;
+ SetLength(arMenuRec,0);
+end;
+
+function AddOptionPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ result:=0;
+ tmpl:=PAnsiChar(IDD_UA);
+ proc:=@DlgProcOpt;
+ name:='Use Actions';
+end;
+
+procedure InitLink;
+begin
+ amLink.Next :=ActionLink;
+ amLink.Init :=@Init;
+ amLink.DeInit :=@DeInit;
+ amLink.AddOption:=@AddOptionPage;
+ ActionLink :=@amLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Actman30/ua/ua.rc b/plugins/Actman30/ua/ua.rc
new file mode 100644
index 0000000000..76d8c0ad77
--- /dev/null
+++ b/plugins/Actman30/ua/ua.rc
@@ -0,0 +1,51 @@
+#include "i_uconst.inc"
+
+LANGUAGE 0,0
+
+IDD_UA DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ CTEXT "Action list",-1, 2,2,132,10, SS_CENTERIMAGE
+ CONTROL "", IDC_UA_ACTIONLIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP |
+ LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_REPORT | LVS_SINGLESEL,
+ 2, 12, 132, 212, WS_EX_CONTROLPARENT
+
+ CTEXT "Where to use",-1, 138,2,160,10, SS_CENTERIMAGE
+ CONTROL "", IDC_UA_PLACELIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP |
+ LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_REPORT | LVS_SINGLESEL,
+ 138, 12, 160, 74, WS_EX_CONTROLPARENT
+
+ GROUPBOX "Common" , IDC_UA_COMMON , 138, 88,160,38
+ AUTOCHECKBOX "2 state button/item" , IDC_UA_TWOSTATE, 140, 96,156,14, BS_LEFTTEXT | BS_RIGHT
+ AUTOCHECKBOX "Save button/item state", IDC_UA_SAVSTATE, 140,110,156,14, BS_LEFTTEXT | BS_RIGHT
+
+ AUTOCHECKBOX "Contact related", IDC_UA_GLOBAL, 138,128,160,14, BS_LEFTTEXT | BS_RIGHT
+
+ // Buttons settings block
+ RTEXT "Normal button tooltip",IDC_UA_TTNORMALT, 138,148,160,8
+ EDITTEXT IDC_UA_TTNORMALV, 138,158,160,12, ES_AUTOHSCROLL
+
+ RTEXT "Pressed button tooltip",IDC_UA_TTPRESSEDT, 138,172,160,8
+ EDITTEXT IDC_UA_TTPRESSEDV, 138,182,160,12, ES_AUTOHSCROLL
+
+ // Menu settings block
+ AUTOCHECKBOX "Separated",IDC_UA_SEPARATE, 138,142,160,14, BS_LEFTTEXT | BS_RIGHT
+
+ RTEXT "Root popup:",IDC_UA_POPUPT,138,158,80,12, SS_CENTERIMAGE
+ EDITTEXT IDC_UA_POPUPV, 218,158,80,12, ES_AUTOHSCROLL
+
+ RTEXT "Menu item name:",IDC_UA_VARNAMEST, 138,172,140,8
+ EDITTEXT IDC_UA_VARNAMESV, 138,182,140,12, ES_AUTOHSCROLL
+ CONTROL "V",IDC_UA_VARNAMESH,"MButtonClass",WS_TABSTOP, 282,180,16,16, $18000000
+
+ RTEXT "Show only if variables return 1",IDC_UA_SHOWVART, 138,200,140,8
+ EDITTEXT IDC_UA_SHOWVARV,138,210,140,12,ES_AUTOHSCROLL
+ CONTROL "V",IDC_UA_SHOWVARH,"MButtonClass",WS_TABSTOP, 282,208,16,16, $18000000
+
+}
+
+IDI_ACTION ICON "action.ico"