summaryrefslogtreecommitdiff
path: root/Plugins/smr
diff options
context:
space:
mode:
Diffstat (limited to 'Plugins/smr')
-rw-r--r--Plugins/smr/Docs/langpack_smr.txt45
-rw-r--r--Plugins/smr/Docs/smr_changelog.txt61
-rw-r--r--Plugins/smr/Docs/smr_readme.txt8
-rw-r--r--Plugins/smr/Docs/smr_version.txt1
-rw-r--r--Plugins/smr/ZIP/doit.bat84
-rw-r--r--Plugins/smr/commons.h93
-rw-r--r--Plugins/smr/m_smr.h70
-rw-r--r--Plugins/smr/options.cpp155
-rw-r--r--Plugins/smr/options.h77
-rw-r--r--Plugins/smr/poll.cpp868
-rw-r--r--Plugins/smr/poll.h62
-rw-r--r--Plugins/smr/resource.h74
-rw-r--r--Plugins/smr/resource.rc163
-rw-r--r--Plugins/smr/sdk/m_updater.h146
-rw-r--r--Plugins/smr/smr.cpp276
-rw-r--r--Plugins/smr/smr.dsp186
-rw-r--r--Plugins/smr/smr.dsw29
-rw-r--r--Plugins/smr/status.cpp63
-rw-r--r--Plugins/smr/status.h42
-rw-r--r--Plugins/smr/status_msg.cpp89
-rw-r--r--Plugins/smr/status_msg.h46
21 files changed, 2638 insertions, 0 deletions
diff --git a/Plugins/smr/Docs/langpack_smr.txt b/Plugins/smr/Docs/langpack_smr.txt
new file mode 100644
index 0000000..0a0dc4f
--- /dev/null
+++ b/Plugins/smr/Docs/langpack_smr.txt
@@ -0,0 +1,45 @@
+; Status Message Retriever
+; Author: Pescuma
+
+; Contact Menu
+
+[Enable Status Message Check]
+[Disable Status Message Check]
+
+
+; Group in options
+
+[Status Msg Retrieve]
+
+
+; Options
+
+[General]
+
+[ Retrieve ]
+[Retrieve status messages every]
+[minutes]
+[Retrieve on status change]
+[Also retrieve after]
+[seconds after status change]
+
+[ Clear ]
+[Clear message on status change]
+[Always clear message if status does not support messages]
+[(even for contacts with msg check disabled)]
+
+[ XStatus ]
+[If contact has XStatus set:]
+[Retrieve as usual]
+[Clear]
+[Clear only if XStatus message is set]
+[Set to XStatus Name]
+[Set to XStatus Message]
+[Set to XStatus Name: XStatus Message]
+
+
+[Protocols]
+
+[Get status messages for these protocols:]
+[This feature is mainly for use with protocols that store status messages on server rather then in database (like ICQ). Don't enable it for MSN or Jabber - they already save the status message in database and won't work correctly if you enable this.]
+
diff --git a/Plugins/smr/Docs/smr_changelog.txt b/Plugins/smr/Docs/smr_changelog.txt
new file mode 100644
index 0000000..d7da3da
--- /dev/null
+++ b/Plugins/smr/Docs/smr_changelog.txt
@@ -0,0 +1,61 @@
+Status Message Retriever
+
+Changelog:
+
+. 1.0.0.7
+ * Fix for crash
+
+. 1.0.0.6
+ * Fix for crash at startup
+
+. 1.0.0.5
+ * Now uses tabs from core in options
+ * Options are now expert only
+
+. 1.0.0.4
+ + Added support for Miranda 0.8
+
+. 1.0.0.3
+ * Fix for services
+ + Added more info text
+
+. 1.0.0.2
+ + If XStatus name and message are the same, show only one (and not Name: message)
+
+. 1.0.0.1
+ * Try to fix bug on thread finish
+ + Don't check contacts on invisible list
+ + Options in XP style
+
+. 1.0.0.0
+ * Only save retrieved status message if needed
+ + Langpack file
+ + Changed version number to reflect that the plugin is ready
+
+. 0.0.1.6
+ * Bugfix to freezing
+
+. 0.0.1.5
+ * Bugfix in poll
+ * Bugfix in xstatus code
+
+. 0.0.1.4
+ + Deal with XStatus
+ * Tabbed options dialog
+
+. 0.0.1.3
+ + Option to always clear status message
+ * Fixed error detection
+ * Online check if check on timer enabled also
+
+. 0.0.1.2
+ + New logic to handle requests. Should work better for ICQ, but messages will take longer to arrive.
+
+. 0.0.1.1
+ + Updater support
+ + More options
+ + A lot of changes in polling code
+ * Bugfix in contact menu option
+
+. 0.0.1.0
+ + Initial version \ No newline at end of file
diff --git a/Plugins/smr/Docs/smr_readme.txt b/Plugins/smr/Docs/smr_readme.txt
new file mode 100644
index 0000000..bb6d8c6
--- /dev/null
+++ b/Plugins/smr/Docs/smr_readme.txt
@@ -0,0 +1,8 @@
+Status Message Retriever plugin
+-------------------------------
+
+This is a plugin that retrieves status messages based on timer and on status change. It is made for protocols that store the status message at the client, like ICQ does.
+
+Please, do not enable this for MSN nor Jabber, because it can cause bad side effects (these protocols handle status message internally and smr can break things).
+
+To report bugs/make suggestions, go to the forum thread: http://forums.miranda-im.org/showthread.php?t=7560
diff --git a/Plugins/smr/Docs/smr_version.txt b/Plugins/smr/Docs/smr_version.txt
new file mode 100644
index 0000000..5db2c73
--- /dev/null
+++ b/Plugins/smr/Docs/smr_version.txt
@@ -0,0 +1 @@
+Status Message Retriever 1.0.0.7 \ No newline at end of file
diff --git a/Plugins/smr/ZIP/doit.bat b/Plugins/smr/ZIP/doit.bat
new file mode 100644
index 0000000..95860cd
--- /dev/null
+++ b/Plugins/smr/ZIP/doit.bat
@@ -0,0 +1,84 @@
+@echo off
+
+rem Batch file to build and upload files
+rem
+rem TODO: Integration with FL
+
+set name=smr
+
+rem To upload, this var must be set here or in other batch
+rem set ftp=ftp://<user>:<password>@<ftp>/<path>
+
+echo Building %name% ...
+
+msdev ..\%name%.dsp /MAKE "%name% - Win32 Release" /REBUILD
+
+echo Generating files for %name% ...
+
+del *.zip
+del *.dll
+del *.txt
+copy ..\Docs\%name%_changelog.txt
+copy ..\Docs\%name%_version.txt
+copy ..\Docs\%name%_readme.txt
+mkdir Plugins
+cd Plugins
+del /Q *.*
+copy ..\..\..\..\bin\release\Plugins\%name%.dll
+cd ..
+mkdir Docs
+cd Docs
+del /Q *.*
+copy ..\..\Docs\%name%_readme.txt
+copy ..\..\Docs\langpack_%name%.txt
+rem copy ..\..\Docs\helppack_%name%.txt
+copy ..\..\m_%name%.h
+cd ..
+mkdir src
+cd src
+del /Q *.*
+copy ..\..\*.h
+copy ..\..\*.cpp
+copy ..\..\*.rc
+copy ..\..\*.dsp
+copy ..\..\*.dsw
+mkdir Docs
+cd Docs
+del /Q *.*
+copy ..\..\..\Docs\*.*
+cd ..
+cd ..
+
+"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%.zip Plugins Docs
+"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%_src.zip src\*.*
+
+cd Plugins
+del /Q *.*
+cd ..
+rmdir Plugins
+cd Docs
+del /Q *.*
+cd ..
+rmdir Docs
+cd src
+del /Q *.*
+cd Docs
+del /Q *.*
+cd ..
+rmdir Docs
+cd ..
+rmdir src
+
+if "%ftp%"=="" GOTO END
+
+echo Going to upload files...
+pause
+
+"C:\Program Files\FileZilla\FileZilla.exe" -u .\%name%.zip %ftp% -overwrite -close
+"C:\Program Files\FileZilla\FileZilla.exe" -u .\%name%_changelog.txt %ftp% -overwrite -close
+"C:\Program Files\FileZilla\FileZilla.exe" -u .\%name%_version.txt %ftp% -overwrite -close
+"C:\Program Files\FileZilla\FileZilla.exe" -u .\%name%_readme.txt %ftp% -overwrite -close
+
+:END
+
+echo Done.
diff --git a/Plugins/smr/commons.h b/Plugins/smr/commons.h
new file mode 100644
index 0000000..d23afa6
--- /dev/null
+++ b/Plugins/smr/commons.h
@@ -0,0 +1,93 @@
+/*
+Copyright (C) 2005 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __COMMONS_H__
+# define __COMMONS_H__
+
+
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+
+
+// Miranda headers
+#define MIRANDA_VER 0x0700
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_clist.h>
+#include <m_ignore.h>
+#include <m_contacts.h>
+#include <m_message.h>
+#include <m_userinfo.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_database.h>
+#include <m_options.h>
+#include <m_utils.h>
+#include <m_updater.h>
+
+#include "../utils/mir_dblists.h"
+#include "../utils/mir_memory.h"
+#include "../utils/mir_options.h"
+#include "../utils/mir_log.h"
+
+#include "resource.h"
+#include "m_smr.h"
+#include "poll.h"
+#include "status_msg.h"
+#include "status.h"
+#include "options.h"
+
+
+#define MODULE_NAME "StatusMsgRetriver"
+
+
+// Global Variables
+extern HINSTANCE hInst;
+extern PLUGINLINK *pluginLink;
+
+
+#define INITIAL_TIMER 5000
+#define ONLINE_TIMER 5000
+#define UPDATE_DELAY 4000
+#define ERROR_DELAY 15000
+#define POOL_DELAY 1000
+#define WAIT_TIME 5000
+
+
+#define MAX_REGS(_A_) ( sizeof(_A_) / sizeof(_A_[0]) )
+
+
+// See if a protocol service exists
+__inline static int ProtoServiceExists(const char *szModule,const char *szService)
+{
+ char str[MAXMODULELABELLENGTH];
+ strcpy(str,szModule);
+ strcat(str,szService);
+ return ServiceExists(str);
+}
+
+
+
+
+#endif // __COMMONS_H__
diff --git a/Plugins/smr/m_smr.h b/Plugins/smr/m_smr.h
new file mode 100644
index 0000000..5cee0d7
--- /dev/null
+++ b/Plugins/smr/m_smr.h
@@ -0,0 +1,70 @@
+/*
+Copyright (C) 2005 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __M_SMR_H__
+# define __M_SMR_H__
+
+
+#define MIID_STATUS_MESSAGE_RETRIEVER { 0xbdfc508a, 0x3c73, 0x40d4, { 0x9f, 0x15, 0xf0, 0xbe, 0xb5, 0xab, 0x72, 0x78 } }
+
+
+/*
+Return TRUE is smr is enabled for this protocol
+If is enabled, status message is kept under CList\StatusMsg db key in user data
+
+wParam: protocol name
+lParam: ignored
+*/
+#define MS_SMR_ENABLED_FOR_PROTOCOL "SMR/MsgRetrievalEnabledForProtocol"
+
+
+/*
+Return TRUE is smr is enabled for this contact and its protocol (smr can be disabled per user,
+if protocol is enabled)
+If is enabled, status message is kept under CList\StatusMsg db key in user data
+
+wParam: hContact
+lParam: ignored
+*/
+#define MS_SMR_ENABLED_FOR_CONTACT "SMR/MsgRetrievalEnabledForUser"
+
+
+/*
+Enable status message retrieval for a contact
+
+wParam: hContact
+lParam: ignored
+*/
+#define MS_SMR_ENABLE_CONTACT "SMR/EnableContactMsgRetrieval"
+
+
+/*
+Disable status message retrieval for a contact
+
+wParam: hContact
+lParam: ignored
+*/
+#define MS_SMR_DISABLE_CONTACT "SMR/DisableContactMsgRetrieval"
+
+
+
+
+
+#endif // __M_SMR_H__
diff --git a/Plugins/smr/options.cpp b/Plugins/smr/options.cpp
new file mode 100644
index 0000000..958c8b0
--- /dev/null
+++ b/Plugins/smr/options.cpp
@@ -0,0 +1,155 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#include "options.h"
+
+
+
+// Prototypes /////////////////////////////////////////////////////////////////////////////////////
+
+HANDLE hOptHook = NULL;
+
+
+Options opts;
+
+static BOOL CALLBACK OptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK GeneralOptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK ProtocolsOptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+
+// Functions //////////////////////////////////////////////////////////////////////////////////////
+
+
+// Initializations needed by options
+void LoadOptions()
+{
+ opts.poll_check_on_timer = DBGetContactSettingByte(NULL, MODULE_NAME, OPT_CHECK_ONTIMER, TRUE);
+ opts.poll_check_on_status_change = DBGetContactSettingByte(NULL, MODULE_NAME, OPT_CHECK_ONSTATUSCHANGE, TRUE);
+ opts.poll_check_on_status_change_timer = DBGetContactSettingByte(NULL, MODULE_NAME, OPT_CHECK_ONSTATUSCHANGETIMER, TRUE);
+ opts.poll_timer_check = DBGetContactSettingWord(NULL, MODULE_NAME, OPT_CHECK_ONTIMER_TIMER, 10);
+ opts.poll_timer_status = DBGetContactSettingWord(NULL, MODULE_NAME, OPT_CHECK_ONSTATUSTIMER_TIMER, 15);
+ opts.poll_clear_on_status_change = DBGetContactSettingByte(NULL, MODULE_NAME, OPT_CLEAR_ONSTATUSCHANGE, TRUE);
+ opts.always_clear = DBGetContactSettingByte(NULL, MODULE_NAME, OPT_ALWAYS_CLEAR, TRUE);
+ opts.when_xstatus = (XStatusAction) DBGetContactSettingWord(NULL, MODULE_NAME, OPT_WHEN_XSTATUS, Clear);
+
+ PollSetTimer();
+}
+
+int InitOptionsCallback(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp,sizeof(odp));
+ odp.cbSize=sizeof(odp);
+ odp.position=0;
+ odp.hInstance=hInst;
+ odp.ptszGroup = TranslateT("Status");
+ odp.ptszTitle = TranslateT("Status Msg Retrieve");
+ odp.flags = ODPF_BOLDGROUPS | ODPF_EXPERTONLY;
+
+ odp.ptszTab = TranslateT("General");
+ odp.pfnDlgProc = GeneralOptionsDlgProc;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT_GENERAL);
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+ odp.ptszTab = TranslateT("Protocols");
+ odp.pfnDlgProc = ProtocolsOptionsDlgProc;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT_PROTOCOLS);
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+ return 0;
+}
+
+
+void InitOptions()
+{
+ LoadOptions();
+
+ hOptHook = HookEvent(ME_OPT_INITIALISE, InitOptionsCallback);
+}
+
+// Deinitializations needed by options
+void DeInitOptions()
+{
+ UnhookEvent(hOptHook);
+}
+
+
+// General page
+
+static OptPageControl generalControls[] = {
+ { NULL, CONTROL_CHECKBOX, IDC_CHECK_ONTIMER, OPT_CHECK_ONTIMER, (BYTE) TRUE },
+ { NULL, CONTROL_CHECKBOX, IDC_CHECK_ONSTATUS, OPT_CHECK_ONSTATUSCHANGE, (BYTE) TRUE },
+ { NULL, CONTROL_CHECKBOX, IDC_CHECK_ONSTATUSTIMER, OPT_CHECK_ONSTATUSCHANGETIMER, (BYTE) TRUE },
+ { NULL, CONTROL_CHECKBOX, IDC_CLEAR_ON_STATUS, OPT_CLEAR_ONSTATUSCHANGE, (BYTE) TRUE },
+ { NULL, CONTROL_CHECKBOX, IDC_ALWAYS_CLEAR, OPT_ALWAYS_CLEAR, (BYTE) TRUE },
+ { NULL, CONTROL_SPIN, IDC_CHECK_ONTIMER_TIMER, OPT_CHECK_ONTIMER_TIMER, (WORD) 10, IDC_CHECK_ONTIMER_TIMER_SPIN, (WORD) 1, (WORD) 255 },
+ { NULL, CONTROL_SPIN, IDC_CHECK_ONSTATUSTIMER_TIMER, OPT_CHECK_ONSTATUSTIMER_TIMER, (WORD) 15, IDC_CHECK_ONSTATUSTIMER_TIMER_SPIN, (WORD) 1, (WORD) 255 },
+ { NULL, CONTROL_COMBO, IDC_XSTATUS, OPT_WHEN_XSTATUS, (WORD) Clear }
+};
+
+
+static BOOL CALLBACK GeneralOptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ SendDlgItemMessage(hwndDlg, IDC_XSTATUS, CB_ADDSTRING, 0, (LONG) TranslateT("Retrieve as usual"));
+ SendDlgItemMessage(hwndDlg, IDC_XSTATUS, CB_ADDSTRING, 0, (LONG) TranslateT("Clear"));
+ SendDlgItemMessage(hwndDlg, IDC_XSTATUS, CB_ADDSTRING, 0, (LONG) TranslateT("Clear only if XStatus message is set"));
+ SendDlgItemMessage(hwndDlg, IDC_XSTATUS, CB_ADDSTRING, 0, (LONG) TranslateT("Set to XStatus Name"));
+ SendDlgItemMessage(hwndDlg, IDC_XSTATUS, CB_ADDSTRING, 0, (LONG) TranslateT("Set to XStatus Message"));
+ SendDlgItemMessage(hwndDlg, IDC_XSTATUS, CB_ADDSTRING, 0, (LONG) TranslateT("Set to XStatus Name: XStatus Message"));
+ break;
+ }
+ }
+
+ return SaveOptsDlgProc(generalControls, MAX_REGS(generalControls), MODULE_NAME, hwndDlg, msg, wParam, lParam);
+}
+
+
+// Protocols page
+
+BOOL AllowProtocol(const char *proto)
+{
+ if (!ProtoServiceExists(proto, PS_GETSTATUS))
+ return FALSE;
+
+ if (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ return FALSE;
+
+ if ((CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGRECV) == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static OptPageControl protocolControls[] = {
+ { NULL, CONTROL_PROTOCOL_LIST, IDC_PROTOCOLS, OPT_PROTOCOL_GETMSG, FALSE, (int)AllowProtocol }
+};
+
+
+static BOOL CALLBACK ProtocolsOptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return SaveOptsDlgProc(protocolControls, MAX_REGS(protocolControls), MODULE_NAME, hwndDlg, msg, wParam, lParam);
+}
+
diff --git a/Plugins/smr/options.h b/Plugins/smr/options.h
new file mode 100644
index 0000000..a853700
--- /dev/null
+++ b/Plugins/smr/options.h
@@ -0,0 +1,77 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __OPTIONS_H__
+# define __OPTIONS_H__
+
+
+#include "commons.h"
+
+#include <windows.h>
+
+#define OPT_CHECK_ONTIMER "CheckOnTimer"
+#define OPT_CHECK_ONSTATUSCHANGE "CheckOnStatusChange"
+#define OPT_CHECK_ONSTATUSCHANGETIMER "CheckOnStatusChangeTimer"
+#define OPT_CLEAR_ONSTATUSCHANGE "ClearOnStatusChange"
+#define OPT_CHECK_ONTIMER_TIMER "CheckOnTimerTimer"
+#define OPT_CHECK_ONSTATUSTIMER_TIMER "CheckOnStatusTimer"
+#define OPT_ALWAYS_CLEAR "AlwaysClear"
+#define OPT_WHEN_XSTATUS "WhenXStatus"
+#define OPT_CONTACT_GETMSG "MsgCheck"
+#define OPT_PROTOCOL_GETMSG "%sMsgCheck"
+
+typedef enum {
+ Normal = 0,
+ Clear,
+ ClearOnMessage,
+ SetToXStatusName,
+ SetToXStatusMessage,
+ SetToXStatusNameXStatusMessage,
+} XStatusAction;
+
+typedef struct
+{
+ BOOL poll_check_on_timer;
+ BOOL poll_check_on_status_change;
+ BOOL poll_check_on_status_change_timer;
+ BOOL poll_clear_on_status_change;
+ WORD poll_timer_check;
+ WORD poll_timer_status;
+ BOOL always_clear;
+ XStatusAction when_xstatus;
+} Options;
+
+extern Options opts;
+
+
+// Initializations needed by options
+void InitOptions();
+
+// Deinitializations needed by options
+void DeInitOptions();
+
+
+// Loads the options from DB
+// It don't need to be called, except in some rare cases
+void LoadOptions();
+
+
+
+#endif // __OPTIONS_H__
diff --git a/Plugins/smr/poll.cpp b/Plugins/smr/poll.cpp
new file mode 100644
index 0000000..f2fee48
--- /dev/null
+++ b/Plugins/smr/poll.cpp
@@ -0,0 +1,868 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#include "poll.h"
+
+
+// Prototypes ///////////////////////////////////////////////////////////////////////////
+
+static CRITICAL_SECTION update_cs;
+static CRITICAL_SECTION pause_cs;
+
+typedef struct
+{
+ SortedList *queue;
+ HANDLE hThread;
+ DWORD dwThreadID;
+ BOOL bThreadRunning;
+
+} ThreadQueue;
+
+ThreadQueue statusQueue;
+
+
+struct QueueItem
+{
+ HANDLE hContact;
+ DWORD check_time;
+ int type;
+};
+
+// Types
+#define STATUS_CHANGE 1
+#define STATUS_CHANGE_TIMER 2
+#define PROTOCOL_ONLINE 4
+#define POOL 8
+#define XSTATUS_CHANGE 16
+
+
+UINT_PTR hTimer = 0;
+
+void QueueAdd(HANDLE hContact, DWORD check_time, int type);
+void QueueRemove(HANDLE hContact);
+int QueueSortItems(void *i1, void *i2);
+
+
+VOID CALLBACK PollTimerAddContacts(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
+void PollAddAllContacts(int timer, const char *protocol, int type);
+
+DWORD WINAPI UpdateThread(LPVOID vParam);
+
+
+DWORD next_request_at = 0;
+void SetNextRequestAt(DWORD t);
+DWORD GetNextRequestAt(void);
+
+QueueItem *requested_item;
+
+
+// Functions ////////////////////////////////////////////////////////////////////////////
+
+
+void InitPoll()
+{
+ int queuesize = CallService(MS_DB_CONTACT_GETCOUNT, 0, 0);
+
+ // Init queue
+ ZeroMemory(&statusQueue, sizeof(statusQueue));
+ statusQueue.queue = List_Create(0, queuesize + 10);
+ statusQueue.queue->sortFunc = QueueSortItems;
+ statusQueue.bThreadRunning = TRUE;
+ statusQueue.hThread = CreateThread(NULL, 16000, UpdateThread, NULL, 0, &statusQueue.dwThreadID);
+
+ InitializeCriticalSection(&update_cs);
+ InitializeCriticalSection(&pause_cs);
+
+ requested_item = NULL;
+}
+
+
+void FreePoll()
+{
+ DWORD dwExitcode;
+ int steps;
+
+ // Stop queue
+ steps = 0;
+ statusQueue.bThreadRunning = FALSE;
+ ResumeThread(statusQueue.hThread);
+ do {
+ Sleep(100);
+ GetExitCodeThread(statusQueue.hThread, &dwExitcode);
+ steps++;
+ } while ( dwExitcode == STILL_ACTIVE && steps < 20 );
+ if (statusQueue.hThread)
+ CloseHandle(statusQueue.hThread);
+
+ // Delete cs
+ DeleteCriticalSection(&update_cs);
+ DeleteCriticalSection(&pause_cs);
+
+ // Free lists
+ List_DestroyFreeContents(statusQueue.queue);
+ mir_free(statusQueue.queue);
+}
+
+int UpdateDelay()
+{
+ int delay = max(50, DBGetContactSettingWord(NULL, MODULE_NAME, "UpdateDelay", UPDATE_DELAY));
+
+ return delay;
+}
+
+int ErrorDelay()
+{
+ int delay = max(50, DBGetContactSettingWord(NULL, MODULE_NAME, "ErrorDelay", ERROR_DELAY));
+
+ return delay;
+}
+
+int WaitTime()
+{
+ int delay = max(50, DBGetContactSettingWord(NULL, MODULE_NAME, "WaitTime", WAIT_TIME));
+
+ return delay;
+}
+
+// Return true if this protocol has to be checked
+BOOL PollCheckProtocol(const char *protocol)
+{
+ if (protocol == NULL)
+ return FALSE;
+
+ if (!ProtoServiceExists(protocol, PS_GETSTATUS))
+ return FALSE;
+
+ if (CallProtoService(protocol, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ return FALSE;
+
+ if ((CallProtoService(protocol, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGRECV) == 0)
+ return FALSE;
+
+ char setting[256];
+ mir_snprintf(setting, sizeof(setting), OPT_PROTOCOL_GETMSG, protocol);
+
+ return (BOOL) DBGetContactSettingByte(NULL, MODULE_NAME, setting, FALSE);
+}
+
+
+// Return true if this contact has to be checked
+BOOL PollCheckContact(HANDLE hContact)
+{
+ return !DBGetContactSettingByte(hContact,"CList","Hidden",0) &&
+ !DBGetContactSettingByte(hContact,"CList","NotOnList",0) &&
+ DBGetContactSettingByte(hContact,"CList","ApparentMode",0) != ID_STATUS_OFFLINE &&
+ DBGetContactSettingByte(hContact, MODULE_NAME, OPT_CONTACT_GETMSG, TRUE);
+}
+
+
+// Add a contact to the poll when the status of the contact has changed
+void PollStatusChangeAddContact(HANDLE hContact)
+{
+ char *proto = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ if (proto != NULL && PollCheckProtocol(proto))
+ {
+ // Delete some messages now (don't add to list...)
+ Check what = ProtocolStatusCheckMsg(hContact, proto);
+
+ if (what == Retrieve)
+ {
+ if (opts.poll_clear_on_status_change)
+ ClearStatusMessage(hContact);
+
+ if (opts.poll_check_on_status_change)
+ QueueAdd(hContact, GetTickCount(), STATUS_CHANGE);
+
+ if (opts.poll_check_on_status_change_timer)
+ QueueAdd(hContact, GetTickCount() + opts.poll_timer_status * 1000, STATUS_CHANGE_TIMER);
+ }
+ else if (what == UseXStatus || what == ClearXStatus)
+ {
+ PollXStatusChangeAddContact(hContact);
+ }
+ else
+ {
+ ProcessCheckNotToServer(what, hContact, proto);
+ }
+ }
+}
+
+// Check after some time, to allow proto to set all data about XStatus
+void PollXStatusChangeAddContact(HANDLE hContact)
+{
+ char *proto = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ if (proto != NULL && PollCheckProtocol(proto) && opts.when_xstatus != Normal)
+ {
+ QueueAdd(hContact, GetTickCount() + 200, XSTATUS_CHANGE);
+ }
+}
+
+void PollAddAllContactsTimer(int timer)
+{
+ PollAddAllContacts(timer, NULL, POOL);
+}
+
+void PollAddAllContactsProtoOnline(int timer, const char *protocol)
+{
+ PollAddAllContacts(timer, protocol, PROTOCOL_ONLINE);
+}
+
+void PollAddAllContacts(int timer, const char *protocol, int type)
+{
+ // Has to check?
+ if (protocol != NULL && !PollCheckProtocol(protocol))
+ return;
+
+ // Make list for next timer ...
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ char *proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+
+ if (proto != NULL && (protocol == NULL || strcmp(proto, protocol) == 0)
+ && (protocol != NULL || PollCheckProtocol(proto)))
+ {
+ if (type == PROTOCOL_ONLINE)
+ {
+ Check what = ProtocolStatusCheckMsg(hContact, proto);
+ ProcessCheckNotToServer(what, hContact, proto);
+ }
+
+ QueueAdd(hContact, GetTickCount() + timer, type);
+ }
+
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+VOID CALLBACK PollTimerAddContacts(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+ if (hTimer != NULL)
+ {
+ KillTimer(NULL, hTimer);
+ hTimer = NULL;
+ }
+
+ // Adds with half the timer because the real timer is the calling of this function.
+ // The timer passed here is the amout of time that it will wait to see if the user do not
+ // request the message by itself
+ PollAddAllContactsTimer(opts.poll_timer_check * 60000 / 3);
+
+ PollSetTimer();
+}
+
+
+void PollSetTimer(void)
+{
+ if (hTimer != NULL)
+ {
+ KillTimer(NULL, hTimer);
+ hTimer = NULL;
+ }
+
+ if (opts.poll_check_on_timer)
+ hTimer = SetTimer(NULL, 0, opts.poll_timer_check * 60000, PollTimerAddContacts);
+}
+
+
+// Remove a contact from the current poll
+void PollReceivedContactMessage(HANDLE hContact, BOOL from_network)
+{
+ QueueRemove(hContact);
+
+ if (from_network)
+ {
+ EnterCriticalSection(&update_cs);
+
+ if (requested_item != NULL && requested_item->hContact == hContact)
+ {
+ mir_free(requested_item);
+ requested_item = NULL;
+ }
+
+ LeaveCriticalSection(&update_cs);
+
+ SetNextRequestAt(GetTickCount() + UpdateDelay());
+ }
+}
+
+
+void QueueRemove(HANDLE hContact)
+{
+ EnterCriticalSection(&update_cs);
+
+ if (statusQueue.queue->items != NULL)
+ {
+ DWORD now = GetTickCount() + 5000; // 5secs error allowed
+
+ for (int i = statusQueue.queue->realCount - 1 ; i >= 0 ; i-- )
+ {
+ QueueItem *item = (QueueItem*) statusQueue.queue->items[i];
+
+ if (item->hContact == hContact)
+ {
+ // Remove old items and status changes
+ if ((item->type & ~STATUS_CHANGE_TIMER) || item->check_time <= now)
+ {
+ mir_free(item);
+ List_Remove(statusQueue.queue, i);
+ }
+ }
+ }
+ }
+
+ LeaveCriticalSection(&update_cs);
+}
+
+
+// Test if has to add an item
+BOOL QueueTestAdd(QueueItem *item)
+{
+ BOOL add = TRUE;
+
+ switch(item->type)
+ {
+ case XSTATUS_CHANGE:
+ {
+ // Remove ALL
+ int i;
+ for ( i = statusQueue.queue->realCount - 1 ; i >= 0 ; i-- )
+ {
+ QueueItem *tmp = (QueueItem *) statusQueue.queue->items[i];
+ if (tmp->hContact == item->hContact)
+ {
+ mir_free(tmp);
+ List_Remove(statusQueue.queue, i);
+ }
+ }
+ break;
+ }
+ case STATUS_CHANGE:
+ {
+ // Remove all, exept PROTOCOL_ONLINE
+ int i;
+ int test = ~PROTOCOL_ONLINE;
+ for ( i = statusQueue.queue->realCount - 1 ; i >= 0 ; i-- )
+ {
+ QueueItem *tmp = (QueueItem *) statusQueue.queue->items[i];
+ if (tmp->hContact == item->hContact)
+ {
+ if (tmp->type & test)
+ {
+ mir_free(tmp);
+ List_Remove(statusQueue.queue, i);
+ }
+ else
+ {
+ add = FALSE;
+ }
+ }
+ }
+
+ if (requested_item != NULL && requested_item->hContact == item->hContact)
+ {
+ add = FALSE;
+ }
+
+ break;
+ }
+ case STATUS_CHANGE_TIMER:
+ {
+ // Remove STATUS_CHANGE_TIMER and POOL
+ int i;
+ int test = STATUS_CHANGE_TIMER | POOL;
+ for ( i = statusQueue.queue->realCount - 1 ; i >= 0 ; i-- )
+ {
+ QueueItem *tmp = (QueueItem *) statusQueue.queue->items[i];
+ if (tmp->hContact == item->hContact)
+ {
+ if (tmp->type & test)
+ {
+ mir_free(tmp);
+ List_Remove(statusQueue.queue, i);
+ }
+ else if (tmp->type & PROTOCOL_ONLINE)
+ {
+ add = FALSE;
+ }
+ }
+ }
+ break;
+ }
+ case PROTOCOL_ONLINE:
+ {
+ // Remove ALL
+ int i;
+ for ( i = statusQueue.queue->realCount - 1 ; i >= 0 ; i-- )
+ {
+ QueueItem *tmp = (QueueItem *) statusQueue.queue->items[i];
+ if (tmp->hContact == item->hContact)
+ {
+ mir_free(tmp);
+ List_Remove(statusQueue.queue, i);
+ }
+ }
+ break;
+ }
+ //case POOL:
+ //{
+ // // Dont remove, allways add
+ // break;
+ //}
+ }
+
+ return add;
+}
+
+// Add an contact to the poll queue
+void QueueAdd(HANDLE hContact, DWORD check_time, int type)
+{
+ // Add this to thread...
+ QueueItem *item = (QueueItem *) mir_alloc0(sizeof(QueueItem));
+
+ if (item == NULL)
+ return;
+
+ item->hContact = hContact;
+ item->check_time = check_time;
+ item->type = type;
+
+ EnterCriticalSection(&update_cs);
+
+ if (QueueTestAdd(item))
+ {
+ List_InsertOrdered(statusQueue.queue, item);
+ }
+ else
+ {
+ mir_free(item);
+ }
+
+ LeaveCriticalSection(&update_cs);
+
+ ResumeThread(statusQueue.hThread);
+}
+
+
+// Itens with higher priority at end
+int QueueSortItems(void *i1, void *i2)
+{
+ return ((QueueItem*)i2)->check_time - ((QueueItem*)i1)->check_time;
+}
+
+// Returns if has to check that status
+Check ProtocolStatusCheckMsg(HANDLE hContact, const char *protocol)
+{
+ BOOL check = PollCheckContact(hContact);
+ int status = CallProtoService(protocol, PS_GETSTATUS, 0, 0);
+
+ // Exclude offline, connecting and invisible
+ if (status >= ID_STATUS_ONLINE && status <= ID_STATUS_OUTTOLUNCH && status != ID_STATUS_INVISIBLE)
+ {
+ // Status
+ int contact_status = DBGetContactSettingWord(hContact, protocol, "Status", 0);
+ int contact_xstatus = DBGetContactSettingByte(hContact, protocol, "XStatusId", 0);
+
+ // Check
+ if (opts.when_xstatus != Normal && contact_xstatus != 0)
+ {
+ // Use XStatus
+
+ bool has_xstatus_name = false;
+ bool has_xstatus_message = false;
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingString(hContact, protocol, "XStatusName", &dbv))
+ {
+ if (dbv.pszVal != NULL && dbv.pszVal[0] != '\0')
+ {
+ has_xstatus_name = true;
+ }
+ DBFreeVariant(&dbv);
+ }
+ if (!DBGetContactSettingString(hContact, protocol, "XStatusMsg", &dbv))
+ {
+ if (dbv.pszVal != NULL && dbv.pszVal[0] != '\0')
+ {
+ has_xstatus_message = true;
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ if (opts.when_xstatus == Clear
+ || (opts.when_xstatus == ClearOnMessage && has_xstatus_message) )
+ {
+ return (check || opts.always_clear) ? ClearMessage : DoNothing;
+ }
+ else if (opts.when_xstatus == SetToXStatusName
+ || opts.when_xstatus == SetToXStatusMessage
+ || opts.when_xstatus == SetToXStatusNameXStatusMessage)
+ {
+ return check ? UseXStatus : DoNothing;
+ }
+ }
+
+ // If get until this point, Use normal status message
+ DWORD protoStatusFlags = CallProtoService(protocol, PS_GETCAPS, PFLAGNUM_3, 0);
+ if (protoStatusFlags & Proto_Status2Flag(contact_status))
+ {
+ return check ? Retrieve : DoNothing;// here you know the proto named protocol supports status i
+ }
+ else
+ {
+ return (check || opts.always_clear) ? ClearMessage : DoNothing;
+ }
+ }
+ else // Protocol in a status that do not have to check msgs
+ {
+ return (check || opts.always_clear) ? ClearMessage : DoNothing;
+ }
+}
+
+// This should be called from outside the critical session
+void ProcessCheckNotToServer(Check what, HANDLE hContact, const char *protocol)
+{
+ switch(what)
+ {
+ case ClearMessage:
+ {
+ ClearStatusMessage(hContact);
+ PollReceivedContactMessage(hContact, FALSE);
+ break;
+ }
+ case UseXStatus:
+ {
+ bool has_xstatus_name = false;
+ bool has_xstatus_message = false;
+ char name[256];
+ char msg[256];
+ name[0] = '\0';
+ msg[0] = '\0';
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingString(hContact, protocol, "XStatusName", &dbv))
+ {
+ if (dbv.pszVal != NULL && dbv.pszVal[0] != '\0')
+ {
+ strncpy(name, dbv.pszVal, sizeof(name));
+ name[sizeof(name)-1] = '\0';
+ has_xstatus_name = true;
+ }
+ DBFreeVariant(&dbv);
+ }
+ if (!DBGetContactSettingString(hContact, protocol, "XStatusMsg", &dbv))
+ {
+ if (dbv.pszVal != NULL && dbv.pszVal[0] != '\0')
+ {
+ strncpy(msg, dbv.pszVal, sizeof(msg));
+ msg[sizeof(msg)-1] = '\0';
+ has_xstatus_message = true;
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ // SetToXStatusName
+ if (opts.when_xstatus == SetToXStatusName)
+ {
+ SetStatusMessage(hContact, name);
+ PollReceivedContactMessage(hContact, FALSE);
+ }
+
+ // SetToXStatusMessage
+ else if (opts.when_xstatus == SetToXStatusMessage)
+ {
+ SetStatusMessage(hContact, msg);
+ PollReceivedContactMessage(hContact, FALSE);
+ }
+
+ // SetToXStatusNameXStatusValue
+ else if (opts.when_xstatus == SetToXStatusNameXStatusMessage)
+ {
+ if (has_xstatus_name && has_xstatus_message)
+ {
+ if (strcmp(name, msg) == 0)
+ {
+ // Both are the same, use only one
+ SetStatusMessage(hContact, name);
+ }
+ else
+ {
+ char message[512];
+ mir_snprintf(message, sizeof(message), "%s: %s", name, msg);
+ SetStatusMessage(hContact, message);
+ }
+ }
+ else if (has_xstatus_name)
+ {
+ SetStatusMessage(hContact, name);
+ }
+ else if (has_xstatus_message)
+ {
+ SetStatusMessage(hContact, msg);
+ }
+ PollReceivedContactMessage(hContact, FALSE);
+ }
+ break;
+ }
+ }
+}
+
+
+DWORD WINAPI UpdateThread(LPVOID vParam)
+{
+ // Initial timer
+ Sleep(INITIAL_TIMER);
+
+ while (statusQueue.bThreadRunning)
+ {
+ // First remove all that are due and do not have to be pooled
+ EnterCriticalSection(&update_cs);
+
+ if (!List_HasItens(statusQueue.queue))
+ {
+ LeaveCriticalSection(&update_cs);
+ }
+ else
+ {
+ // Create a copy of the queue
+ SortedList *tmpQueue;
+ tmpQueue = List_Create(0, statusQueue.queue->realCount);
+ tmpQueue->sortFunc = QueueSortItems;
+
+ for (int i = statusQueue.queue->realCount - 1; i >= 0; i--)
+ {
+ QueueItem *qi = (QueueItem *) List_Pop(statusQueue.queue);
+
+ if (qi->check_time > GetTickCount())
+ {
+ List_Push(statusQueue.queue, qi);
+ break;
+ }
+ else
+ {
+ List_InsertOrdered(tmpQueue, qi);
+ }
+ }
+
+ LeaveCriticalSection(&update_cs);
+
+ if (!statusQueue.bThreadRunning)
+ break;
+
+ // See the itens that was copied
+ if (List_HasItens(tmpQueue))
+ {
+ for (int i = tmpQueue->realCount - 1; i >= 0; i--)
+ {
+ if (!statusQueue.bThreadRunning)
+ break;
+
+ QueueItem *qi = (QueueItem *) tmpQueue->items[i];
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)qi->hContact, 0);
+
+ if (proto == NULL || !PollCheckProtocol(proto))
+ {
+ List_Remove(tmpQueue, i);
+ mir_free(qi);
+ }
+ else
+ {
+ Check what = ProtocolStatusCheckMsg(qi->hContact, proto);
+
+ if (what != DoNothing && what != Retrieve)
+ {
+ ProcessCheckNotToServer(what, qi->hContact, proto);
+
+ List_Remove(tmpQueue, i);
+ mir_free(qi);
+ }
+ else if (what == DoNothing)
+ {
+ List_Remove(tmpQueue, i);
+ mir_free(qi);
+ }
+ }
+ }
+
+ if (!statusQueue.bThreadRunning)
+ break;
+
+ // See if has itens to be copied back
+ if (List_HasItens(tmpQueue))
+ {
+ EnterCriticalSection(&update_cs);
+ for (int i = tmpQueue->realCount - 1; i >= 0; i--)
+ {
+ QueueItem *qi = (QueueItem *) List_Pop(tmpQueue);
+ List_InsertOrdered(statusQueue.queue, qi);
+ }
+ LeaveCriticalSection(&update_cs);
+ }
+ }
+ }
+
+ if (!statusQueue.bThreadRunning)
+ break;
+
+ // Was to run yet?
+ DWORD test_timer = GetNextRequestAt();
+ if (test_timer > GetTickCount())
+ {
+ if (statusQueue.bThreadRunning)
+ Sleep(POOL_DELAY);
+ }
+ else
+ {
+ // Ok, lets check the message
+ EnterCriticalSection(&update_cs);
+
+ if (requested_item != NULL)
+ {
+ if (GetTickCount() < requested_item->check_time + WaitTime())
+ {
+ LeaveCriticalSection(&update_cs);
+
+ if (statusQueue.bThreadRunning)
+ Sleep(POOL_DELAY);
+ }
+ else
+ {
+ mir_free(requested_item);
+ requested_item = NULL;
+
+ LeaveCriticalSection(&update_cs);
+ }
+ }
+ else if (!List_HasItens(statusQueue.queue))
+ {
+ LeaveCriticalSection(&update_cs);
+
+ // Stop this one...
+ if (statusQueue.bThreadRunning)
+ SuspendThread(statusQueue.hThread);
+ }
+ else
+ {
+ // Get next job...
+
+ /*
+ * the thread is awake, processing the update queue one by one entry with a given delay
+ * of UPDATE_DELAY seconds. The delay ensures that no protocol will kick us because of
+ * flood protection(s)
+ */
+ QueueItem *qi = (QueueItem *) List_Peek(statusQueue.queue);
+
+ if (qi->check_time > GetTickCount())
+ {
+ LeaveCriticalSection(&update_cs);
+
+ if (statusQueue.bThreadRunning)
+ Sleep(POOL_DELAY);
+ }
+ else
+ {
+ qi = (QueueItem *) List_Pop(statusQueue.queue);
+
+ LeaveCriticalSection(&update_cs);
+
+ if (!statusQueue.bThreadRunning)
+ break;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)qi->hContact, 0);
+
+ if (proto == NULL || !PollCheckProtocol(proto))
+ {
+ mir_free(qi);
+ }
+ else
+ {
+ Check what = ProtocolStatusCheckMsg(qi->hContact, proto);
+
+ if (what == DoNothing)
+ {
+ mir_free(qi);
+ }
+ else if (what != Retrieve)
+ {
+ ProcessCheckNotToServer(what, qi->hContact, proto);
+ mir_free(qi);
+ }
+ else // if (what == Retrieve)
+ {
+ if (!statusQueue.bThreadRunning)
+ break;
+
+ int ret = CallContactService(qi->hContact,PSS_GETAWAYMSG,0,0);
+
+ if (ret != 0)
+ {
+ EnterCriticalSection(&update_cs);
+
+ requested_item = qi;
+ requested_item->check_time = GetTickCount();
+
+ LeaveCriticalSection(&update_cs);
+
+ if (statusQueue.bThreadRunning)
+ Sleep(POOL_DELAY);
+ }
+ else
+ {
+ EnterCriticalSection(&update_cs);
+
+ // Error, pause for a while
+ List_Push(statusQueue.queue, qi);
+
+ LeaveCriticalSection(&update_cs);
+
+ int delay = ErrorDelay();
+ SetNextRequestAt(GetTickCount() + delay);
+ if (statusQueue.bThreadRunning)
+ Sleep(delay);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+void SetNextRequestAt(DWORD t)
+{
+ EnterCriticalSection(&pause_cs);
+ next_request_at = t;
+ LeaveCriticalSection(&pause_cs);
+}
+
+DWORD GetNextRequestAt(void)
+{
+ EnterCriticalSection(&pause_cs);
+ DWORD ret = next_request_at;
+ LeaveCriticalSection(&pause_cs);
+
+ return ret;
+}
diff --git a/Plugins/smr/poll.h b/Plugins/smr/poll.h
new file mode 100644
index 0000000..3a29e6d
--- /dev/null
+++ b/Plugins/smr/poll.h
@@ -0,0 +1,62 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __POLL_H__
+# define __POLL_H__
+
+#include <windows.h>
+
+#include "commons.h"
+
+
+void InitPoll();
+void FreePoll();
+
+void PollSetTimer(void);
+
+BOOL PollCheckProtocol(const char *protocol);
+BOOL PollCheckContact(HANDLE hContact);
+
+typedef enum {
+ Retrieve,
+ DoNothing,
+ ClearMessage,
+ UseXStatus,
+ ClearXStatus
+} Check;
+Check ProtocolStatusCheckMsg(HANDLE hContact, const char *protocol);
+void ProcessCheckNotToServer(Check what, HANDLE hContact, const char *protocol);
+
+void PollReceivedContactMessage(HANDLE hContact, BOOL from_network);
+
+void PollStatusChangeAddContact(HANDLE hContact);
+void PollXStatusChangeAddContact(HANDLE hContact);
+void PollAddAllContactsTimer(int timer);
+void PollAddAllContactsProtoOnline(int timer, const char *protocol);
+
+
+
+
+
+
+
+
+
+#endif // __POLL_H__
diff --git a/Plugins/smr/resource.h b/Plugins/smr/resource.h
new file mode 100644
index 0000000..5cb6092
--- /dev/null
+++ b/Plugins/smr/resource.h
@@ -0,0 +1,74 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDI_HIST 101
+#define IDI_POPUP 102
+#define IDI_NOPOPUP 103
+#define IDI_EXT 104
+#define IDI_INT 105
+#define IDI_LIST 106
+#define IDI_URL 107
+#define IDB_LIST 108
+#define IDD_HISTORY 109
+#define IDD_OPT 110
+#define IDD_LIST 111
+#define IDD_OPT_NTF 112
+#define IDD_OPT_PROTOCOLS 114
+#define IDD_OPT_GENERAL 117
+#define IDD_OPTS 118
+#define IDR_PMENU 200
+#define IDC_PREVIEW 1000
+#define IDC_CHKDEFAULTCOL 1001
+#define IDC_DELAY 1002
+#define IDC_HISMAX 1003
+#define IDC_CHECK_ONTIMER_TIMER 1004
+#define IDC_CHECK_ONSTATUSTIMER_TIMER 1005
+#define IDC_FHIS 1011
+#define IDC_FLOG 1012
+#define IDC_LIST 1013
+#define IDC_IGNOREPOP 1014
+#define IDC_HISTORYLIST 1015
+#define IDC_IGNOREALL 1016
+#define IDC_COLLISTBACK 1017
+#define IDC_COLLISTTEXT 1018
+#define IDC_DP 1019
+#define IDC_HIDECMENUITEMS 1037
+#define IDC_CHECK_ONTIMER 1038
+#define IDC_CHECK_ONSTATUSTIMER 1039
+#define IDC_PROTOCOLS 1041
+#define IDC_DELAYINFINITE 1042
+#define IDC_LOGTOFILE 1043
+#define IDC_AUTOREFRESH 1044
+#define IDC_CLEARHIST 1045
+#define IDC_CLEARALLHIS 1048
+#define IDC_CHECK_MSG_TIMER_SPIN 1049
+#define IDC_CHECK_ONTIMER_TIMER_SPIN 1049
+#define IDC_CHECK_STATUS_TIMER_SPIN 1050
+#define IDC_CHECK_ONSTATUS_TIMER_SPIN 1050
+#define IDC_CHECK_ONSTATUSTIMER_TIMER_SPIN 1050
+#define IDC_CLEAR_ON_STATUS 1051
+#define IDC_RETRIEVE_ON_STATUS 1052
+#define IDC_CHECK_ONSTATUS 1052
+#define IDC_ALWAYS_CLEAR 1053
+#define IDC_XSTATUS 1054
+#define IDC_TAB 1056
+#define IDM_M1 40001
+#define IDM_M2 40003
+#define IDM_M3 40005
+#define IDM_M5 40007
+#define IDM_M4 40008
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_3D_CONTROLS 1
+#define _APS_NEXT_RESOURCE_VALUE 119
+#define _APS_NEXT_COMMAND_VALUE 40004
+#define _APS_NEXT_CONTROL_VALUE 1058
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Plugins/smr/resource.rc b/Plugins/smr/resource.rc
new file mode 100644
index 0000000..a972e73
--- /dev/null
+++ b/Plugins/smr/resource.rc
@@ -0,0 +1,163 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "resource.h"
+#include "winresrc.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_PROTOCOLS DIALOG DISCARDABLE 0, 0, 257, 164
+STYLE WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Get status messages for these protocols:",IDC_STATIC,10,
+ 9,236,9
+ CONTROL "List1",IDC_PROTOCOLS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER |
+ LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,10,21,236,90
+ LTEXT "This feature is mainly for use with protocols that store status messages on server rather then in database (like ICQ). Don't enable it for MSN or Jabber - they already save the status message in database and won't work correctly if you enable this.",
+ IDC_STATIC,10,114,236,47
+END
+
+IDD_OPT_GENERAL DIALOGEX 0, 0, 271, 167
+STYLE WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX " Retrieve ",IDC_STATIC,7,7,257,60
+ CONTROL "Retrieve status messages every",IDC_CHECK_ONTIMER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,20,119,10
+ EDITTEXT IDC_CHECK_ONTIMER_TIMER,137,20,31,12,ES_NUMBER | NOT
+ WS_BORDER,WS_EX_STATICEDGE
+ CONTROL "Spin1",IDC_CHECK_ONTIMER_TIMER_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS |
+ UDS_NOTHOUSANDS | UDS_HOTTRACK,157,18,11,11
+ LTEXT "minutes",IDC_STATIC,173,21,37,10
+ CONTROL "Retrieve on status change",IDC_CHECK_ONSTATUS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,34,216,10
+ CONTROL "Also retrieve after",IDC_CHECK_ONSTATUSTIMER,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,48,76,8
+ EDITTEXT IDC_CHECK_ONSTATUSTIMER_TIMER,93,47,31,12,ES_NUMBER |
+ NOT WS_BORDER,WS_EX_STATICEDGE
+ CONTROL "Spin2",IDC_CHECK_ONSTATUSTIMER_TIMER_SPIN,
+ "msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,119,42,11,
+ 10
+ LTEXT "seconds after status change",IDC_STATIC,130,48,99,10
+ GROUPBOX " Clear ",IDC_STATIC,7,70,257,53
+ CONTROL "Clear message on status change",IDC_CLEAR_ON_STATUS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,83,216,10
+ CONTROL "Always clear message if status does not support messages",
+ IDC_ALWAYS_CLEAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 15,97,216,10
+ LTEXT "(even for contacts with msg check disabled)",IDC_STATIC,
+ 28,108,204,10
+ GROUPBOX " XStatus ",IDC_STATIC,7,126,257,34
+ LTEXT "If contact has XStatus set:",IDC_STATIC,15,141,92,13
+ COMBOBOX IDC_XSTATUS,109,139,148,72,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_OPT_PROTOCOLS, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 254
+ VERTGUIDE, 10
+ VERTGUIDE, 246
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 161
+ END
+
+ IDD_OPT_GENERAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 264
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 160
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Canada) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""resource.h""\r\n"
+ "#include ""winresrc.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (Canada) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Plugins/smr/sdk/m_updater.h b/Plugins/smr/sdk/m_updater.h
new file mode 100644
index 0000000..371b743
--- /dev/null
+++ b/Plugins/smr/sdk/m_updater.h
@@ -0,0 +1,146 @@
+#ifndef _M_UPDATER_H
+#define _M_UPDATER_H
+
+// NOTES:
+// - For langpack updates, include a string of the following format in the langpack text file:
+// ";FLID: <file listing name> <version>"
+// version must be four numbers seperated by '.', in the range 0-255 inclusive
+// - Updater will disable plugins that are downloaded but were not active prior to the update (this is so that, if an archive contains e.g. ansi and
+// unicode versions, the correct plugin will be the only one active after the new version is installed)...so if you add a support plugin, you may need
+// to install an ini file to make the plugin activate when miranda restarts after the update
+// - Updater will replace all dlls that have the same internal shortName as a downloaded update dll (this is so that msn1.dll and msn2.dll, for example,
+// will both be updated) - so if you have a unicode and a non-unicode version of a plugin in your archive, you should make the internal names different (which will break automatic
+// updates from the file listing if there is only one file listing entry for both versions, unless you use the 'MS_UPDATE_REGISTER' service below)
+// - Updater will install all files in the root of the archive into the plugins folder, except for langpack files that contain the FLID string which go into the root folder (same
+// folder as miranda32.exe)...all folders in the archive will also be copied to miranda's root folder, and their contents transferred into the new folders. The only exception is a
+// special folder called 'root_files' - if there is a folder by that name in the archive, it's contents will also be copied into miranda's root folder - this is intended to be used
+// to install additional dlls etc that a plugin may require)
+
+// if you set Update.szUpdateURL to the following value when registering, as well as setting your beta site and version data,
+// Updater will ignore szVersionURL and pbVersionPrefix, and attempt to find the file listing URL's from the backend XML data.
+// for this to work, the plugin name in pluginInfo.shortName must match the file listing exactly (except for case)
+#define UPDATER_AUTOREGISTER "UpdaterAUTOREGISTER"
+// Updater will also use the backend xml data if you provide URL's that reference the miranda file listing for updates (so you can use that method
+// if e.g. your plugin shortName does not match the file listing) - it will grab the file listing id from the end of these URLs
+
+typedef struct Update_tag {
+ int cbSize;
+ char *szComponentName; // component name as it will appear in the UI (will be translated before displaying)
+
+ char *szVersionURL; // URL where the current version can be found (NULL to disable)
+ BYTE *pbVersionPrefix; // bytes occuring in VersionURL before the version, used to locate the version information within the URL data
+ // (note that this URL could point at a binary file - dunno why, but it could :)
+ int cpbVersionPrefix; // number of bytes pointed to by pbVersionPrefix
+ char *szUpdateURL; // URL where dll/zip is located
+ // set to UPDATER_AUTOREGISTER if you want Updater to find the file listing URLs (ensure plugin shortName matches file listing!)
+
+ char *szBetaVersionURL; // URL where the beta version can be found (NULL to disable betas)
+ BYTE *pbBetaVersionPrefix; // bytes occuring in VersionURL before the version, used to locate the version information within the URL data
+ int cpbBetaVersionPrefix; // number of bytes pointed to by pbVersionPrefix
+ char *szBetaUpdateURL; // URL where dll/zip is located
+
+ BYTE *pbVersion; // bytes of current version, used for comparison with those in VersionURL
+ int cpbVersion; // number of bytes pointed to by pbVersion
+
+ char *szBetaChangelogURL; // url for displaying changelog for beta versions
+} Update;
+
+// register a comonent with Updater
+//
+// wparam = 0
+// lparam = (LPARAM)&Update
+#define MS_UPDATE_REGISTER "Update/Register"
+
+// utility functions to create a version string from a DWORD or from pluginInfo
+// point buf at a buffer at least 16 chars wide - but note the version string returned may be shorter
+//
+__inline static char *CreateVersionString(DWORD version, char *buf) {
+ mir_snprintf(buf, 16, "%d.%d.%d.%d", (version >> 24) & 0xFF, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF);
+ return buf;
+}
+
+__inline static char *CreateVersionStringPlugin(PLUGININFO *pluginInfo, char *buf) {
+ return CreateVersionString(pluginInfo->version, buf);
+}
+
+
+// register the 'easy' way - use this method if you have no beta URL and the plugin is on the miranda file listing
+// NOTE: the plugin version string on the file listing must be the string version of the version in pluginInfo (i.e. 0.0.0.1,
+// four numbers between 0 and 255 inclusivem, so no letters, brackets, etc.)
+//
+// wParam = (int)fileID - this is the file ID from the file listing (i.e. the number at the end of the download link)
+// lParam = (PLUGININFO*)&pluginInfo
+#define MS_UPDATE_REGISTERFL "Update/RegisterFL"
+
+// this function can be used to 'unregister' components - useful for plugins that register non-plugin/langpack components and
+// may need to change those components on the fly
+// lParam = (char *)szComponentName
+#define MS_UPDATE_UNREGISTER "Update/Unregister"
+
+// this event is fired when the startup process is complete, but NOT if a restart is imminent
+// it is designed for status managment plugins to use as a trigger for beggining their own startup process
+// wParam = lParam = 0 (unused)
+// (added in version 0.1.6.0)
+#define ME_UPDATE_STARTUPDONE "Update/StartupDone"
+
+// this service can be used to enable/disable Updater's global status control
+// it can be called from the StartupDone event handler
+// wParam = (BOOL)enable
+// lParam = 0
+// (added in version 0.1.6.0)
+#define MS_UPDATE_ENABLESTATUSCONTROL "Update/EnableStatusControl"
+
+// An description of usage of the above service and event:
+// Say you are a status control plugin that normally sets protocol or global statuses in your ModulesLoaded event handler.
+// In order to make yourself 'Updater compatible', you would move the status control code from ModulesLoaded to another function,
+// say DoStartup. Then, in ModulesLoaded you would check for the existence of the MS_UPDATE_ENABLESTATUSCONTROL service.
+// If it does not exist, call DoStartup. If it does exist, hook the ME_UPDATE_STARTUPDONE event and call DoStartup from there. You may
+// also wish to call MS_UPDATE_ENABLESTATUSCONTROL with wParam == FALSE at this time, to disable Updater's own status control feature.
+
+// this service can be used to determine whether updates are possible for a component with the given name
+// wParam = 0
+// lParam = (char *)szComponentName
+// returns TRUE if updates are supported, FALSE otherwise
+#define MS_UPDATE_ISUPDATESUPPORTED "Update/IsUpdateSupported"
+
+#endif
+
+
+/////////////// Usage Example ///////////////
+
+#ifdef EXAMPLE_CODE
+
+// you need to #include "m_updater.h" and HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded) in your Load function...
+
+int OnModulesLoaded(WPARAM wParam, LPARAM lParam) {
+
+ Update update = {0}; // for c you'd use memset or ZeroMemory...
+ char szVersion[16];
+
+ update.cbSize = sizeof(Update);
+
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE *)CreateVersionString(&pluginInfo, szVersion);
+ update.cpbVersion = strlen((char *)update.pbVersion);
+
+ // these are the three lines that matter - the archive, the page containing the version string, and the text (or data)
+ // before the version that we use to locate it on the page
+ // (note that if the update URL and the version URL point to standard file listing entries, the backend xml
+ // data will be used to check for updates rather than the actual web page - this is not true for beta urls)
+ update.szUpdateURL = "http://scottellis.com.au:81/test/updater.zip";
+ update.szVersionURL = "http://scottellis.com.au:81/test/updater_test.html";
+ update.pbVersionPrefix = (BYTE *)"Updater version ";
+
+ update.cpbVersionPrefix = strlen((char *)update.pbVersionPrefix);
+
+ // do the same for the beta versions of the above struct members if you wish to allow beta updates from another URL
+
+ CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
+
+ // Alternatively, to register a plugin with e.g. file ID 2254 on the file listing...
+ // CallService(MS_UPDATE_REGISTERFL, (WPARAM)2254, (LPARAM)&pluginInfo);
+
+ return 0;
+}
+
+#endif
diff --git a/Plugins/smr/smr.cpp b/Plugins/smr/smr.cpp
new file mode 100644
index 0000000..94f4a9e
--- /dev/null
+++ b/Plugins/smr/smr.cpp
@@ -0,0 +1,276 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#include "commons.h"
+
+
+// Prototypes ///////////////////////////////////////////////////////////////////////////
+
+
+PLUGININFOEX pluginInfo={
+ sizeof(PLUGININFOEX),
+ "Status Message Retriever",
+ PLUGIN_MAKE_VERSION(1,0,0,7),
+ "Retrieve status message based on timer / status change",
+ "Ricardo Pescuma Domenecci, Tomasz Słotwiński",
+ "",
+ "© 2007 Ricardo Pescuma Domenecci, Tomasz Słotwiński",
+ "http://pescuma.mirandaim.ru/miranda/smr",
+ 0,
+ 0, //doesn't replace anything built-in
+ { 0x800a5c24, 0x737b, 0x499f, { 0x96, 0xa2, 0x40, 0x46, 0xda, 0xa8, 0x41, 0xb1 } } // {800A5C24-737B-499f-96A2-4046DAA841B1}
+};
+
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+HANDLE hEnableMenu = NULL;
+HANDLE hDisableMenu = NULL;
+HANDLE hModulesLoaded = NULL;
+HANDLE hPreBuildCMenu = NULL;
+
+int ModulesLoaded(WPARAM wParam, LPARAM lParam);
+
+int PreBuildContactMenu(WPARAM wParam,LPARAM lParam);
+
+int EnableContactMsgRetrieval(WPARAM wParam,LPARAM lParam);
+int DisableContactMsgRetrieval(WPARAM wParam,LPARAM lParam);
+int MsgRetrievalEnabledForUser(WPARAM wParam, LPARAM lParam);
+int MsgRetrievalEnabledForProtocol(WPARAM wParam, LPARAM lParam);
+
+
+// Functions ////////////////////////////////////////////////////////////////////////////
+
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+
+extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ pluginInfo.cbSize = sizeof(PLUGININFO);
+ return (PLUGININFO*) &pluginInfo;
+}
+
+
+extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ pluginInfo.cbSize = sizeof(PLUGININFOEX);
+ return &pluginInfo;
+}
+
+
+static const MUUID interfaces[] = { MIID_STATUS_MESSAGE_RETRIEVER, MIID_LAST };
+extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+
+extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) {
+ pluginLink = link;
+
+ init_mir_malloc();
+ init_list_interface();
+
+ CreateServiceFunction(MS_SMR_DISABLE_CONTACT, DisableContactMsgRetrieval);
+ CreateServiceFunction(MS_SMR_ENABLE_CONTACT, EnableContactMsgRetrieval);
+ CreateServiceFunction(MS_SMR_ENABLED_FOR_PROTOCOL, MsgRetrievalEnabledForProtocol);
+ CreateServiceFunction(MS_SMR_ENABLED_FOR_CONTACT, MsgRetrievalEnabledForUser);
+
+ // Add menu item to enable/disable status message check
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = 0;
+ mi.pszPopupName = NULL;
+
+ mi.position = 1000100020;
+ mi.ptszName = TranslateT("Disable Status Message Check");
+ mi.pszService = MS_SMR_DISABLE_CONTACT;
+ hDisableMenu = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ mi.position = 1000100020;
+ mi.ptszName = TranslateT("Enable Status Message Check");
+ mi.pszService = MS_SMR_ENABLE_CONTACT;
+ hEnableMenu = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ // hooks
+ hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+
+ // prebuild contact menu
+ hPreBuildCMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PreBuildContactMenu);
+
+ return 0;
+}
+
+extern "C" int __declspec(dllexport) Unload(void)
+{
+ FreeStatus();
+ FreeStatusMsgs();
+ FreePoll();
+ DeInitOptions();
+
+ UnhookEvent(hModulesLoaded);
+ UnhookEvent(hPreBuildCMenu);
+ return 0;
+}
+
+
+// Called when all the modules are loaded
+int ModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ InitPoll();
+ InitStatusMsgs();
+ InitStatus();
+ InitOptions();
+
+ // add our modules to the KnownModules list
+ CallService("DBEditorpp/RegisterSingleModule", (WPARAM) MODULE_NAME, 0);
+
+ // updater plugin support
+ if(ServiceExists(MS_UPDATE_REGISTER))
+ {
+ Update upd = {0};
+ char szCurrentVersion[30];
+
+ upd.cbSize = sizeof(upd);
+ upd.szComponentName = pluginInfo.shortName;
+
+ upd.szUpdateURL = UPDATER_AUTOREGISTER;
+
+ upd.szBetaVersionURL = "http://pescuma.org/miranda/smr_version.txt";
+ upd.szBetaChangelogURL = "http://pescuma.org/miranda/smr#Changelog";
+ upd.pbBetaVersionPrefix = (BYTE *)"Status Message Retriever ";
+ upd.cpbBetaVersionPrefix = strlen((char *)upd.pbBetaVersionPrefix);
+ upd.szBetaUpdateURL = "http://pescuma.org/miranda/smr.zip";
+
+ upd.pbVersion = (BYTE *)CreateVersionStringPlugin((PLUGININFO*) &pluginInfo, szCurrentVersion);
+ upd.cpbVersion = strlen((char *)upd.pbVersion);
+
+ CallService(MS_UPDATE_REGISTER, 0, (LPARAM)&upd);
+ }
+
+ return 0;
+}
+
+
+int EnableContactMsgRetrieval(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+
+ if (hContact != NULL)
+ DBWriteContactSettingByte(hContact, MODULE_NAME, OPT_CONTACT_GETMSG, TRUE);
+
+ return 0;
+}
+
+
+int DisableContactMsgRetrieval(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+
+ if (hContact != NULL)
+ DBWriteContactSettingByte(hContact, MODULE_NAME, OPT_CONTACT_GETMSG, FALSE);
+
+ return 0;
+}
+
+
+int PreBuildContactMenu(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+ char *proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+
+ if (proto == NULL || !PollCheckProtocol(proto))
+ {
+ // Hide both
+
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof(clmi);
+ clmi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hEnableMenu, (LPARAM)&clmi);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hDisableMenu, (LPARAM) &clmi);
+ }
+ else
+ {
+ // See what to show
+
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof(clmi);
+
+ if (DBGetContactSettingByte(hContact, MODULE_NAME, OPT_CONTACT_GETMSG, TRUE))
+ {
+ clmi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hEnableMenu, (LPARAM) &clmi);
+
+ clmi.flags = CMIM_FLAGS | CMIM_ICON;
+ clmi.hIcon = LoadSkinnedProtoIcon(proto, ID_STATUS_OFFLINE);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hDisableMenu, (LPARAM) &clmi);
+ }
+ else
+ {
+ clmi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hDisableMenu, (LPARAM) &clmi);
+
+ clmi.flags = CMIM_FLAGS | CMIM_ICON;
+ clmi.hIcon = LoadSkinnedProtoIcon(proto, ID_STATUS_ONLINE);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hEnableMenu, (LPARAM) &clmi);
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+Return TRUE is smr is enabled for this contact and its protocol (smr can be disabled per user,
+if protocol is enabled)
+If is enabled, status message is kept under CList\StatusMsg db key in user data
+
+wParam: hContact
+lParam: ignored
+*/
+int MsgRetrievalEnabledForUser(WPARAM wParam, LPARAM lParam)
+{
+ char *proto = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+
+ return proto != NULL && PollCheckProtocol(proto) && PollCheckContact((HANDLE) wParam);
+}
+
+
+/*
+Return TRUE is smr is enabled for this protocol
+If is enabled, status message is kept under CList\StatusMsg db key in user data
+
+wParam: protocol name
+lParam: ignored
+*/
+int MsgRetrievalEnabledForProtocol(WPARAM wParam, LPARAM lParam)
+{
+ char *proto = (char *) wParam;
+
+ return proto != NULL && PollCheckProtocol(proto);
+}
+
diff --git a/Plugins/smr/smr.dsp b/Plugins/smr/smr.dsp
new file mode 100644
index 0000000..8f1eab8
--- /dev/null
+++ b/Plugins/smr/smr.dsp
@@ -0,0 +1,186 @@
+# Microsoft Developer Studio Project File - Name="smr" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=smr - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "smr.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "smr.mak" CFG="smr - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "smr - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "smr - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "smr - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O1 /YX /FD /c
+# SUBTRACT BASE CPP /Fr
+# ADD CPP /nologo /G4 /MT /W3 /GX /O2 /Ob0 /I "../../include" /I "sdk" /D "WIN32" /D "W32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Fr /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x417 /d "NDEBUG"
+# ADD RSC /l 0x417 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 user32.lib shell32.lib wininet.lib gdi32.lib /nologo /base:"0x67100000" /dll /machine:I386 /filealign:0x200
+# SUBTRACT BASE LINK32 /pdb:none /map
+# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x32100000" /dll /map /machine:I386 /out:"..\..\bin\release\Plugins\smr.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# SUBTRACT LINK32 /profile /pdb:none
+
+!ELSEIF "$(CFG)" == "smr - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "smr___Win32_Debug"
+# PROP BASE Intermediate_Dir "smr___Win32_Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /G4 /MT /W3 /GX /O2 /Ob0 /I "../../include" /FR /YX /FD /c
+# ADD CPP /nologo /G4 /MTd /W3 /Gm /Gi /ZI /Od /I "../../include" /I "sdk" /D "WIN32" /D "W32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x417 /d "NDEBUG"
+# ADD RSC /l 0x417 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..bin\release\Plugins\smr.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# SUBTRACT BASE LINK32 /profile /pdb:none
+# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x32100000" /dll /incremental:yes /map /debug /machine:I386 /out:"..\..\bin\debug\Plugins\smr.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# SUBTRACT LINK32 /profile /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "smr - Win32 Release"
+# Name "smr - Win32 Debug"
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\commons.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_smr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\utils\mir_dblists.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\utils\mir_memory.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\utils\mir_options.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\options.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\poll.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\status.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\status_msg.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# End Group
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\utils\mir_dblists.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\utils\mir_memory.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\utils\mir_options.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\options.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\poll.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\smr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\status.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\status_msg.cpp
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/Plugins/smr/smr.dsw b/Plugins/smr/smr.dsw
new file mode 100644
index 0000000..3d9f8dd
--- /dev/null
+++ b/Plugins/smr/smr.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "smr"=".\smr.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/Plugins/smr/status.cpp b/Plugins/smr/status.cpp
new file mode 100644
index 0000000..cb0c51e
--- /dev/null
+++ b/Plugins/smr/status.cpp
@@ -0,0 +1,63 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#include "status.h"
+
+HANDLE hContactSettingChanged;
+
+static int ContactSettingChanged(WPARAM wParam, LPARAM lParam);
+
+
+
+
+void InitStatus()
+{
+ hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+}
+
+
+void FreeStatus()
+{
+ UnhookEvent(hContactSettingChanged);
+}
+
+
+static int ContactSettingChanged(WPARAM wParam, LPARAM lParam) {
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam;
+ HANDLE hContact = (HANDLE)wParam;
+ const char *proto = cws->szModule;
+
+ // Check contact status changed
+ if (hContact != NULL && proto != NULL)
+ {
+ if (strcmp(cws->szSetting, "Status") == 0)
+ {
+ PollStatusChangeAddContact(hContact);
+ }
+ else if (strcmp(cws->szSetting, "XStatusName") == 0
+ || strcmp(cws->szSetting, "XStatusMsg") == 0
+ || strcmp(cws->szSetting, "XStatusId") == 0)
+ {
+ PollXStatusChangeAddContact(hContact);
+ }
+ }
+
+ return 0;
+}
diff --git a/Plugins/smr/status.h b/Plugins/smr/status.h
new file mode 100644
index 0000000..1a62292
--- /dev/null
+++ b/Plugins/smr/status.h
@@ -0,0 +1,42 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __STATUS_H__
+# define __STATUS_H__
+
+#include <windows.h>
+
+#include "commons.h"
+
+
+void InitStatus();
+void FreeStatus();
+
+
+
+
+
+
+
+
+
+
+
+#endif // __STATUS_H__
diff --git a/Plugins/smr/status_msg.cpp b/Plugins/smr/status_msg.cpp
new file mode 100644
index 0000000..d67c8df
--- /dev/null
+++ b/Plugins/smr/status_msg.cpp
@@ -0,0 +1,89 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#include "status_msg.h"
+
+
+HANDLE hProtoAck = NULL;
+
+int ProtoAck(WPARAM wParam, LPARAM lParam);
+
+
+
+
+void InitStatusMsgs()
+{
+ hProtoAck = HookEvent(ME_PROTO_ACK, ProtoAck);
+}
+
+
+void FreeStatusMsgs()
+{
+ UnhookEvent(hProtoAck);
+}
+
+
+void ClearStatusMessage(HANDLE hContact)
+{
+ DBWriteContactSettingString(hContact, "CList", "StatusMsg", "");
+}
+
+
+void SetStatusMessage(HANDLE hContact, const TCHAR *msg)
+{
+ DBWriteContactSettingString(hContact, "CList", "StatusMsg", msg);
+}
+
+
+
+int ProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA*)lParam;
+
+ if (ack->type == ACKTYPE_STATUS)
+ {
+ WORD newStatus = (WORD)ack->lParam;
+ WORD oldStatus = (WORD)ack->hProcess;
+ char *proto = (char*)ack->szModule;
+
+ if ((oldStatus <= ID_STATUS_OFFLINE || oldStatus == ID_STATUS_INVISIBLE)
+ && newStatus > ID_STATUS_OFFLINE && newStatus != ID_STATUS_INVISIBLE
+ && PollCheckProtocol(proto))
+ {
+ if (opts.poll_check_on_status_change || opts.poll_check_on_status_change_timer)
+ PollAddAllContactsProtoOnline(ONLINE_TIMER, proto);
+ }
+ }
+ else if (ack->type == ACKTYPE_AWAYMSG)
+ {
+ char *proto = (char*)ack->szModule;
+
+ if (ack->result == ACKRESULT_SUCCESS && PollCheckProtocol(proto))
+ {
+ PollReceivedContactMessage(ack->hContact, TRUE);
+
+ // Only set if neede
+ if (ProtocolStatusCheckMsg(ack->hContact, proto) == Retrieve)
+ SetStatusMessage(ack->hContact, (const TCHAR *) ack->lParam);
+ }
+ }
+
+ return 0; //The protocol changed in a way we don't care.
+}
diff --git a/Plugins/smr/status_msg.h b/Plugins/smr/status_msg.h
new file mode 100644
index 0000000..ca30968
--- /dev/null
+++ b/Plugins/smr/status_msg.h
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2006 Ricardo Pescuma Domenecci
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+
+#ifndef __STATUS_MSG_H__
+# define __STATUS_MSG_H__
+
+#include <windows.h>
+
+#include "commons.h"
+
+
+void InitStatusMsgs();
+void FreeStatusMsgs();
+
+
+void ClearStatusMessage(HANDLE hContact);
+void SetStatusMessage(HANDLE hContact, const TCHAR *msg);
+
+
+
+
+
+
+
+
+
+
+
+#endif // __STATUS_MSG_H__