summaryrefslogtreecommitdiff
path: root/plugins/UserInfoEx/src/Flags/svc_flags.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/UserInfoEx/src/Flags/svc_flags.cpp')
-rw-r--r--plugins/UserInfoEx/src/Flags/svc_flags.cpp765
1 files changed, 765 insertions, 0 deletions
diff --git a/plugins/UserInfoEx/src/Flags/svc_flags.cpp b/plugins/UserInfoEx/src/Flags/svc_flags.cpp
new file mode 100644
index 0000000000..8999df2cca
--- /dev/null
+++ b/plugins/UserInfoEx/src/Flags/svc_flags.cpp
@@ -0,0 +1,765 @@
+/*
+UserinfoEx plugin for Miranda IM
+
+Copyright:
+ฉ 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol
+
+part of this code based on:
+Miranda IM Country Flags Plugin Copyright ฉ2006-2007 H. Herkenrath
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+===============================================================================
+
+File name : $HeadURL: https://userinfoex.googlecode.com/svn/trunk/Flags/svc_flags.cpp $
+Revision : $Revision: 187 $
+Last change on : $Date: 2010-09-08 16:05:54 +0400 (ะกั€, 08 ัะตะฝ 2010) $
+Last change by : $Author: ing.u.horn $
+
+===============================================================================
+*/
+
+#include "..\commonheaders.h"
+#include "svc_flags.h"
+#include "svc_flagsicons.h"
+#include "svc_countrylistext.h"
+
+#define M_ENABLE_SUBCTLS (WM_APP+1)
+
+FLAGSOPTIONS gFlagsOpts;
+
+/* Misc */
+int nCountriesCount;
+struct CountryListEntry *countries;
+static HANDLE *phExtraImageList = NULL; //return value(s) from MS_CLIST_EXTRA_ADD_ICON
+static HANDLE hExtraIconSvc = INVALID_HANDLE_VALUE;
+/* hook */
+static HANDLE hRebuildIconsHook = NULL;
+static HANDLE hApplyIconHook = NULL;
+static HANDLE hMsgWndEventHook = NULL;
+static HANDLE hIconsChangedHook = NULL;
+static HANDLE hSettingChangedHook = NULL;
+
+static HANDLE hExtraIconSvcHook = NULL;
+static HANDLE hOptInitHook = NULL;
+
+static int OnContactSettingChanged(WPARAM wParam,LPARAM lParam);
+
+/***********************************************************************************************************
+ * Buffered functions
+ ***********************************************************************************************************/
+
+struct BufferedCallData {
+ DWORD startTick;
+ UINT uElapse;
+ BUFFEREDPROC pfnBuffProc;
+ LPARAM lParam;
+ #ifdef _DEBUG
+ const char *pszProcName;
+ #endif
+};
+
+static UINT_PTR idBufferedTimer;
+static struct BufferedCallData *callList;
+static int nCallListCount;
+
+// always gets called in main message loop
+static void CALLBACK BufferedProcTimer(HWND hwnd, UINT msg, UINT idTimer, DWORD currentTick) {
+ int i;
+ struct BufferedCallData *buf;
+ UINT uElapsed, uElapseNext = USER_TIMER_MAXIMUM;
+ BUFFEREDPROC pfnBuffProc;
+ LPARAM lParam;
+ #ifdef _DEBUG
+ char szDbgLine[256];
+ const char *pszProcName;
+ #endif
+ UNREFERENCED_PARAMETER(msg);
+
+ for(i=0;i<nCallListCount;++i) {
+ /* find elapsed procs */
+ uElapsed=currentTick-callList[i].startTick; /* wraparound works */
+ if ((uElapsed+USER_TIMER_MINIMUM)>=callList[i].uElapse) {
+ /* call elapsed proc */
+ pfnBuffProc=callList[i].pfnBuffProc;
+ lParam=callList[i].lParam;
+ #ifdef _DEBUG
+ pszProcName=callList[i].pszProcName;
+ #endif
+ /* resize storage array */
+ if ((i+1)<nCallListCount)
+ MoveMemory(&callList[i],&callList[i+1],((nCallListCount-i-1)*sizeof(struct BufferedCallData)));
+ --nCallListCount;
+ --i; /* reiterate current */
+ if(nCallListCount) {
+ buf=(struct BufferedCallData*)mir_realloc(callList,nCallListCount*sizeof(struct BufferedCallData));
+ if(buf!=NULL) callList=buf;
+ } else {
+ mir_free(callList);
+ callList=NULL;
+ }
+ #ifdef _DEBUG
+ mir_snprintf(szDbgLine,sizeof(szDbgLine),"buffered call: %s(0x%X)\n",pszProcName,lParam); /* all ascii */
+ OutputDebugStringA(szDbgLine);
+ #endif
+ CallFunctionAsync((void (CALLBACK *)(void*))pfnBuffProc,(void*)lParam); /* compatible */
+ }
+ /* find next timer delay */
+ else if ((callList[i].uElapse-uElapsed)<uElapseNext)
+ uElapseNext=callList[i].uElapse-uElapsed;
+ }
+
+ /* set next timer */
+ if(nCallListCount) {
+ #ifdef _DEBUG
+ mir_snprintf(szDbgLine,sizeof(szDbgLine),"next buffered timeout: %ums\n",uElapseNext); /* all ascii */
+ OutputDebugStringA(szDbgLine);
+ #endif
+ idBufferedTimer=SetTimer(hwnd, idBufferedTimer, uElapseNext, (TIMERPROC)BufferedProcTimer); /* will be reset */
+ } else {
+ KillTimer(hwnd,idTimer);
+ idBufferedTimer=0;
+ #ifdef _DEBUG
+ OutputDebugStringA("empty buffered queue\n");
+ #endif
+ }
+}
+
+// assumes to be called in context of main thread
+#ifdef _DEBUG
+void _CallFunctionBuffered(BUFFEREDPROC pfnBuffProc,const char *pszProcName,LPARAM lParam,BOOL fAccumulateSameParam,UINT uElapse)
+#else
+void _CallFunctionBuffered(BUFFEREDPROC pfnBuffProc,LPARAM lParam,BOOL fAccumulateSameParam,UINT uElapse)
+#endif
+{
+ struct BufferedCallData *data=NULL;
+ int i;
+
+ /* find existing */
+ for(i=0;i<nCallListCount;++i)
+ if(callList[i].pfnBuffProc==pfnBuffProc)
+ if (!fAccumulateSameParam || callList[i].lParam==lParam) {
+ data=&callList[i];
+ break;
+ }
+ /* append new */
+ if(data==NULL) {
+ /* resize storage array */
+ data=(struct BufferedCallData*)mir_realloc(callList,(nCallListCount+1)*sizeof(struct BufferedCallData));
+ if(data==NULL) return;
+ callList=data;
+ data=&callList[nCallListCount];
+ ++nCallListCount;
+ }
+ /* set delay */
+ data->startTick=GetTickCount();
+ data->uElapse=uElapse;
+ data->lParam=lParam;
+ data->pfnBuffProc=pfnBuffProc;
+ #ifdef _DEBUG
+ { char szDbgLine[256];
+ data->pszProcName=pszProcName;
+ mir_snprintf(szDbgLine,sizeof(szDbgLine),"buffered queue: %s(0x%X)\n",pszProcName,lParam); /* all ascii */
+ OutputDebugStringA(szDbgLine);
+ if (!idBufferedTimer) {
+ mir_snprintf(szDbgLine,sizeof(szDbgLine),"next buffered timeout: %ums\n",uElapse); /* all ascii */
+ OutputDebugStringA(szDbgLine);
+ }
+ }
+ #endif
+ /* set next timer */
+ if(idBufferedTimer) uElapse=USER_TIMER_MINIMUM; /* will get recalculated */
+ idBufferedTimer=SetTimer(NULL,idBufferedTimer,uElapse,(TIMERPROC)BufferedProcTimer);
+}
+
+// assumes to be called in context of main thread
+void PrepareBufferedFunctions()
+{
+ idBufferedTimer=0;
+ nCallListCount=0;
+ callList=NULL;
+}
+
+// assumes to be called in context of main thread
+void KillBufferedFunctions()
+{
+ if(idBufferedTimer) KillTimer(NULL,idBufferedTimer);
+ nCallListCount=0;
+ mir_free(callList); /* does NULL check */
+}
+
+/***********************************************************************************************************
+ * service functions
+ ***********************************************************************************************************/
+
+static INT_PTR ServiceDetectContactOriginCountry(WPARAM wParam,LPARAM lParam)
+{
+ WORD countryNumber;
+ char *pszProto =
+ pszProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ /* UserinfoEx */
+ if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,USERINFO,SET_CONTACT_ORIGIN_COUNTRY,0))
+ return (INT_PTR)countryNumber;
+ else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,USERINFO,SET_CONTACT_COUNTRY,0))
+ return (INT_PTR)countryNumber;
+ else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,USERINFO,SET_CONTACT_COMPANY_COUNTRY,0))
+ return (INT_PTR)countryNumber;
+ /* fallback proto settings */
+ else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,pszProto,"Country",0))
+ return (INT_PTR)countryNumber;
+ else if (countryNumber = (int)DB::Setting::GetWord((HANDLE)wParam,pszProto,"CompanyCountry",0))
+ return (INT_PTR)countryNumber;
+ /* fallback ip detect
+ else if(countryNumber==0xFFFF && DBGetContactSettingByte(NULL,"Flags","UseIpToCountry",SETTING_USEIPTOCOUNTRY_DEFAULT)) {
+ countryNumber=ServiceIpToCountry(DBGetContactSettingDword((HANDLE)wParam,pszProto,"RealIP",0),0);
+ }*/
+
+ return (INT_PTR)0xFFFF;
+}
+
+/***********************************************************************************************************
+ * Clist Extra Image functions
+ ***********************************************************************************************************/
+
+static void CALLBACK SetExtraImage(LPARAM lParam) {
+ /* get contact's country */
+ int countryNumber = ServiceDetectContactOriginCountry((WPARAM)lParam,0);;
+ //use ExtraIconsService ?
+ if (myGlobals.ExtraIconsServiceExist) {
+ EXTRAICON ico;
+ ico.cbSize = sizeof(ico);
+ ico.hContact = (HANDLE)lParam;
+ ico.hExtraIcon = hExtraIconSvc;
+ ico.icoName = (char*)0; //preset
+ if(countryNumber!=0xFFFF || gFlagsOpts.bUseUnknownFlag) {
+ char szId[20];
+ mir_snprintf(szId, SIZEOF(szId), (countryNumber==0xFFFF)?"%s_0x%X":"%s_%i","flags",countryNumber); /* buffer safe */
+ ico.icoName = szId;
+ }
+ CallService(MS_EXTRAICON_SET_ICON, (WPARAM)&ico, 0);
+ }
+ //use Clist ExtraImageService
+ else if(gFlagsOpts.bShowExtraImgFlag) {
+ int index;
+ IconExtraColumn iec;
+ iec.cbSize = sizeof(iec);
+ iec.ColumnType = gFlagsOpts.idExtraColumn;
+ iec.hImage = INVALID_HANDLE_VALUE; //preset
+ /* get icon for contact */
+ if(phExtraImageList!=NULL) { /* too early? */
+ if(countryNumber!=0xFFFF || gFlagsOpts.bUseUnknownFlag) {
+ index = CountryNumberToIndex(countryNumber);
+ /* icon not add to clist extra image list? */
+ if(phExtraImageList[index]==INVALID_HANDLE_VALUE) {
+ HICON hIcon=LoadFlag(countryNumber); // Returned HICON SHOULDN'T be destroyed, it is managed by IcoLib
+ if(hIcon!=NULL) {
+ phExtraImageList[index]=(HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON,(WPARAM)hIcon,0);
+ Skin_ReleaseIcon(hIcon); /* does NULL check */
+ }
+ }
+ iec.hImage=phExtraImageList[index];
+ }
+ }
+ //Set icon for contact at needed column
+ CallService(MS_CLIST_EXTRA_SET_ICON,(WPARAM)lParam,(LPARAM)&iec);
+ }
+}
+
+static void CALLBACK RemoveExtraImages(LPARAM lParam) {
+ register HANDLE hContact;
+ //use ExtraIconsService ?
+ if (myGlobals.ExtraIconsServiceExist) {
+ EXTRAICON ico;
+ ico.cbSize = sizeof(ico);
+ ico.hExtraIcon = hExtraIconSvc;
+ ico.icoName = (char *)0; /* invalidate icon for contact*/
+ /* enum all contacts */
+ for (hContact = DB::Contact::FindFirst(); hContact != NULL; hContact = DB::Contact::FindNext(hContact)) {
+ ico.hContact = hContact;
+ CallService(MS_EXTRAICON_SET_ICON, (WPARAM)&ico, 0);
+ }
+ }
+ //use Clist ExtraImageService
+ else {
+ IconExtraColumn iec;
+ iec.cbSize = sizeof(iec);
+ iec.ColumnType = gFlagsOpts.idExtraColumn;
+ iec.hImage = INVALID_HANDLE_VALUE;
+ /* enum all contacts */
+ for (hContact = DB::Contact::FindFirst(); hContact != NULL; hContact = DB::Contact::FindNext(hContact)) {
+ /* invalidate icon for contact*/
+ CallService(MS_CLIST_EXTRA_SET_ICON,(WPARAM)hContact,(LPARAM)&iec);
+ }
+ }
+}
+
+// always call in context of main thread
+void EnsureExtraImages() //garantieren - sicherstellen - updaten
+{
+ register HANDLE hContact;
+ //use Clist ExtraImageService?
+ if (!myGlobals.ExtraIconsServiceExist) {
+ BYTE idExtraColumnNew = DB::Setting::GetByte(MODNAMEFLAGS,"ExtraImgFlagColumn",SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT);
+ if(idExtraColumnNew != gFlagsOpts.idExtraColumn) {
+ /* clear previous column */
+ RemoveExtraImages(0);
+ gFlagsOpts.idExtraColumn = idExtraColumnNew;
+ /* clear new column */
+ RemoveExtraImages(0);
+ }
+ }
+ /* enum all contacts */
+ for (hContact = DB::Contact::FindFirst(); hContact != NULL; hContact = DB::Contact::FindNext(hContact)) {
+ /* update icon */
+ CallFunctionBuffered(SetExtraImage,(LPARAM)hContact,TRUE,EXTRAIMAGE_REFRESHDELAY);
+ }
+}
+
+static void CALLBACK UpdateExtraImages(LPARAM lParam) {
+ if (!lParam)
+ RemoveExtraImages(0);
+ else EnsureExtraImages();
+
+/* if (!myGlobals.ExtraIconsServiceExist && !gFlagsOpts.bShowExtraImgFlag)
+ RemoveExtraImages();
+ else EnsureExtraImages(); */
+}
+
+//hookProc ME_CLIST_EXTRA_LIST_REBUILD
+static int OnCListRebuildIcons(WPARAM wParam,LPARAM lParam) {
+ OutputDebugStringA("REBUILD EXTRA\n");
+ //use ExtraIconsService ?
+ if(myGlobals.ExtraIconsServiceExist) return 0; //delete ?
+ //use Clist ExtraImageService
+ if(phExtraImageList!=NULL) {
+ /* invalidate icons */
+ for(int i=0;i<nCountriesCount;++i)
+ phExtraImageList[i]=INVALID_HANDLE_VALUE;
+ }
+ /* update column */
+ gFlagsOpts.idExtraColumn = DB::Setting::GetByte(MODNAMEFLAGS,"ExtraImgFlagColumn",SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT);
+ return 0;
+}
+
+//hookProc ME_CLIST_EXTRA_IMAGE_APPLY
+static int OnCListApplyIcons(WPARAM wParam,LPARAM lParam) {
+ //OutputDebugStringA("APPLY EXTRA\n");
+ if(myGlobals.ExtraIconsServiceExist || gFlagsOpts.bShowExtraImgFlag)
+ SetExtraImage((LPARAM)wParam); /* unbuffered */
+ return 0;
+}
+
+//hookProc (ME_DB_CONTACT_SETTINGCHANGED) - workaround for missing event from ExtraIconSvc
+static int OnExtraIconSvcChanged(WPARAM wParam,LPARAM lParam) {
+ DBCONTACTWRITESETTING *dbcws=(DBCONTACTWRITESETTING*)lParam;
+ if ((HANDLE)wParam!=NULL)return 0;
+ if (!lstrcmpA(dbcws->szModule, "ExtraIcons") &&
+ !lstrcmpA(dbcws->szSetting,"Slot_Flags")) {
+ BOOL bEnable;
+ switch (dbcws->value.type) {
+ case DBVT_BYTE:
+ bEnable = dbcws->value.bVal != (BYTE)-1;
+ break;
+ case DBVT_WORD:
+ bEnable = dbcws->value.wVal != (WORD)-1;
+ break;
+ case DBVT_DWORD:
+ bEnable = dbcws->value.dVal != (DWORD)-1;
+ break;
+ default:
+ bEnable = -1;
+ break;
+ }
+ if(bEnable == -1) {
+ return 0;
+ }
+ else if(bEnable && !hApplyIconHook) {
+ hApplyIconHook = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnCListApplyIcons);
+ }
+ else if (!bEnable && hApplyIconHook) {
+ UnhookEvent(hApplyIconHook); hApplyIconHook = NULL;
+ }
+ CallFunctionBuffered(UpdateExtraImages,(LPARAM)bEnable,FALSE,EXTRAIMAGE_REFRESHDELAY);
+ }
+ return 0;
+}
+
+VOID SvcFlagsEnableExtraIcons(BYTE bColumn, BOOLEAN bUpdateDB) {
+ if (!myGlobals.HaveCListExtraIcons) return;
+ gFlagsOpts.bShowExtraImgFlag = (bColumn!=((BYTE)-1));
+ if (bUpdateDB) {
+ if(gFlagsOpts.bShowExtraImgFlag) DB::Setting::WriteByte(MODNAMEFLAGS,"ExtraImgFlagColumn", bColumn);
+ DB::Setting::WriteByte(MODNAMEFLAGS,"ShowExtraImgFlag", bColumn!=(BYTE)-1);
+ }
+
+ // Flags is on
+ if (gFlagsOpts.bShowExtraImgFlag) {
+ //use ExtraIconsService ?
+ if(myGlobals.ExtraIconsServiceExist) {
+ if(hExtraIconSvc == INVALID_HANDLE_VALUE) {
+ char szId[20];
+ //get local langID for descIcon (try to use user local Flag as icon)
+ DWORD langid = 0;
+ int r = GetLocaleInfo(
+ LOCALE_USER_DEFAULT,
+ LOCALE_ICOUNTRY | LOCALE_RETURN_NUMBER ,
+ (LPTSTR)&langid, sizeof(langid)/sizeof(TCHAR));
+ if (!CallService(MS_UTILS_GETCOUNTRYBYNUMBER,langid,0)) langid = 1;
+
+ EXTRAICON_INFO ico = {0};
+ ico.cbSize = sizeof(ico);
+ ico.type = EXTRAICON_TYPE_ICOLIB;
+ ico.name = "Flags";
+ ico.description = "Flags (uinfoex)";
+ mir_snprintf(szId, SIZEOF(szId), (langid==0xFFFF)?"%s_0x%X":"%s_%i","flags",langid); /* buffer safe */
+ ico.descIcon = szId;
+ hExtraIconSvc=(HANDLE)CallService(MS_EXTRAICON_REGISTER, (WPARAM)&ico, 0);
+ if(hExtraIconSvc)
+ hExtraIconSvcHook = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnExtraIconSvcChanged);
+
+ }
+ }
+ //use Clist ExtraImageService
+ else {
+ if(phExtraImageList == NULL){
+ phExtraImageList = (HANDLE*)mir_alloc(nCountriesCount*sizeof(HANDLE));
+ /* invalidate icons */
+ if(phExtraImageList!=NULL)
+ for(int i=0;i<nCountriesCount;++i)
+ phExtraImageList[i]=INVALID_HANDLE_VALUE;
+ }
+ if (!hRebuildIconsHook) {
+ hRebuildIconsHook = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, OnCListRebuildIcons);
+ }
+ }
+ //init hooks
+ if (!hApplyIconHook) {
+ hApplyIconHook = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnCListApplyIcons);
+ }
+ if (!hSettingChangedHook) {
+ hSettingChangedHook = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged);
+ }
+ }
+ // Flags is off
+ else {
+ //use ExtraIconsService ?
+ if (myGlobals.ExtraIconsServiceExist) {
+ //nothing to do, until plugin has a hookable event for status
+ return;
+ }
+ //use Clist ExtraImageService
+ //unhook
+ if (hRebuildIconsHook) {
+ UnhookEvent(hRebuildIconsHook); hRebuildIconsHook = NULL;
+ }
+ if (hApplyIconHook) {
+ UnhookEvent(hApplyIconHook); hApplyIconHook = NULL;
+ }
+ if (hSettingChangedHook && !gFlagsOpts.bShowStatusIconFlag) {
+ UnhookEvent(hSettingChangedHook); hSettingChangedHook = NULL;
+ }
+ //SvcFlagsApplyCListIcons();
+ //RemoveExtraImages();
+ CallFunctionBuffered(RemoveExtraImages,0,FALSE,EXTRAIMAGE_REFRESHDELAY);
+ }
+}
+
+/***********************************************************************************************************
+ * message winsow status icon functions
+ ***********************************************************************************************************/
+
+MsgWndData::MsgWndData(HWND hwnd, HANDLE hContact) {
+ m_hwnd = hwnd;
+ m_hContact = hContact;
+ m_contryID = (int)ServiceDetectContactOriginCountry((WPARAM)m_hContact,0);
+ FlagsIconUpdate();
+}
+
+MsgWndData::~MsgWndData() {
+ FlagsIconUnset(); //check if realy need
+}
+
+void
+MsgWndData::FlagsIconSet() {
+ HICON hIcon = NULL;
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = MODNAMEFLAGS;
+ /* ensure status icon is registered */
+ if ( m_contryID!=0xFFFF || gFlagsOpts.bUseUnknownFlag) {
+ /* copy icon as status icon API will call DestroyIcon() on it */
+ hIcon = LoadFlagIcon(m_contryID);
+ sid.hIcon = (hIcon!=NULL)?CopyIcon(hIcon):NULL;
+ Skin_ReleaseIcon(hIcon); /* does NULL check */
+ hIcon = sid.hIcon;
+ sid.dwId = (DWORD)m_contryID;
+ sid.hIconDisabled = sid.hIcon/*NULL*/;
+ sid.szTooltip = Translate((char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,m_contryID,0));
+ sid.flags = 0;
+ if(CallService(MS_MSG_MODIFYICON,(WPARAM)m_hContact,(LPARAM)&sid) !=0) /* not yet registered? */
+ CallService(MS_MSG_ADDICON,0,(LPARAM)&sid);
+ }
+ sid.hIcon = NULL;
+ sid.szTooltip = NULL;
+ sid.hIconDisabled = NULL;
+ for(int i=0;i<nCountriesCount;++i) {
+ sid.dwId = (DWORD)countries[i].id;
+ sid.flags = (m_contryID==countries[i].id && hIcon!=NULL)? 0:MBF_HIDDEN;
+ CallService(MS_MSG_MODIFYICON,(WPARAM)m_hContact,(LPARAM)&sid);
+ }
+}
+
+void
+MsgWndData::FlagsIconUnset() {
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = MODNAMEFLAGS;
+ sid.dwId = (DWORD)m_contryID;
+ sid.flags = MBF_HIDDEN;
+ CallService(MS_MSG_MODIFYICON,(WPARAM)m_hContact,(LPARAM)&sid);
+ /* can't call MS_MSG_REMOVEICON here as the icon might be
+ * in use by other contacts simultanously, removing them all at exit */
+}
+
+static int CompareMsgWndData(const MsgWndData* p1, const MsgWndData* p2)
+{
+ return (int)((INT_PTR)p1->m_hContact - (INT_PTR)p2->m_hContact);
+}
+static LIST<MsgWndData> gMsgWndList(10, CompareMsgWndData);
+
+static int CompareIconListData(const IconList* p1, const IconList* p2)
+{
+ return (int)((INT_PTR)p1->m_ID - (INT_PTR)p2->m_ID);
+}
+static OBJLIST<IconList> gIListMW(10, CompareIconListData);
+
+IconList::IconList(StatusIconData *sid) {
+ m_StatusIconData.cbSize = sid->cbSize;
+ m_StatusIconData.szModule = mir_strdup(sid->szModule);
+ m_StatusIconData.dwId = sid->dwId;
+ m_StatusIconData.hIcon = CopyIcon(sid->hIcon);
+ m_StatusIconData.hIconDisabled = sid->hIconDisabled;
+ m_StatusIconData.flags = sid->flags;
+ m_StatusIconData.szTooltip = mir_strdup(sid->szTooltip);
+
+ m_ID = sid->dwId;
+ CallService(MS_MSG_ADDICON,0,(LPARAM)sid);
+
+}
+IconList::~IconList() {
+ mir_free(m_StatusIconData.szModule);
+ mir_free(m_StatusIconData.szTooltip);
+}
+// const char *pszName; // [Optional] Name of an icon registered with icolib to be used in GUI.
+static __inline int MessageAPI_AddIcon(const char* pszName, const char* szModul/*StatusIconData *sid*/,int ID, int flags, const char* szTooltip)
+{
+ HICON hIcon = Skin_GetIcon(pszName);
+
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = (char*)szModul;
+ sid.dwId = (DWORD)ID;
+ sid.hIcon = (hIcon!=NULL)?CopyIcon(hIcon):NULL;
+ Skin_ReleaseIcon(hIcon); /* does NULL check */
+// sid.hIconDisabled = sid.hIcon/*NULL*/;
+ sid.flags = 0;
+ sid.szTooltip = Translate((char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,ID,0));
+
+ int res = -1;
+ IconList* p = new IconList(&sid);
+ if (!p->m_ID)delete p;
+ else res = gIListMW.insert(p);
+ if(res == -1)delete p;
+ return res;
+}
+
+void CALLBACK UpdateStatusIcons(LPARAM lParam) {
+ if (!lParam) {
+ /* enum all opened message windows */
+ for (int i = 0; i < gMsgWndList.getCount(); i++)
+ gMsgWndList[i]->FlagsIconUpdate();
+ }
+ else {
+ int i = gMsgWndList.getIndex((MsgWndData*)&lParam);
+ if (i!= -1) gMsgWndList[i]->FlagsIconUpdate();
+ }
+}
+
+//hookProc ME_MSG_WINDOWEVENT
+static int OnMsgWndEvent(WPARAM wParam,LPARAM lParam) {
+ MessageWindowEventData *msgwe=(MessageWindowEventData*)lParam;
+ /* sanity check */
+ if(msgwe->hContact==NULL)
+ return 0;
+
+ switch(msgwe->uType) {
+ case MSG_WINDOW_EVT_OPENING:
+ {
+ MsgWndData* msgwnd = gMsgWndList.find((MsgWndData*)&msgwe->hContact);
+ if(msgwnd == NULL) {
+ msgwnd = new MsgWndData(msgwe->hwndWindow, msgwe->hContact);
+ gMsgWndList.insert(msgwnd);
+ }
+ }
+ break;
+
+ case MSG_WINDOW_EVT_CLOSE:
+ {
+ int i = gMsgWndList.getIndex((MsgWndData*)&msgwe->hContact);
+ if (i != -1) {
+ delete gMsgWndList[i];
+ gMsgWndList.remove(i);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+//hookProc ME_SKIN2_ICONSCHANGED
+static int OnStatusIconsChanged(WPARAM wParam,LPARAM lParam) {
+ if(myGlobals.MsgAddIconExist && gFlagsOpts.bShowStatusIconFlag)
+ CallFunctionBuffered(UpdateStatusIcons,0,FALSE,STATUSICON_REFRESHDELAY);
+ return 0;
+}
+
+/***********************************************************************************************************
+ * option page (not used yet)
+ ***********************************************************************************************************/
+static INT_PTR CALLBACK ExtraImgOptDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ return FALSE;
+}
+
+//hookProc ME_OPT_INITIALISE
+static int ExtraImgOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ return 0;
+}
+
+/***********************************************************************************************************
+ * misc functions
+ ***********************************************************************************************************/
+//hookProc ME_DB_CONTACT_SETTINGCHANGED
+static int OnContactSettingChanged(WPARAM wParam,LPARAM lParam) {
+ if ((HANDLE)wParam==NULL) return 0;
+ DBCONTACTWRITESETTING *dbcws=(DBCONTACTWRITESETTING*)lParam;
+
+ /* user details update */
+ if (/*!lstrcmpA(dbcws->szSetting,"RealIP") || */
+ !lstrcmpA(dbcws->szSetting,SET_CONTACT_COUNTRY) ||
+ !lstrcmpA(dbcws->szSetting,SET_CONTACT_ORIGIN_COUNTRY) ||
+ !lstrcmpA(dbcws->szSetting,SET_CONTACT_COMPANY_COUNTRY))
+ {
+ /* Extra Image */
+ if(myGlobals.HaveCListExtraIcons)
+ CallFunctionBuffered(SetExtraImage,(LPARAM)wParam,TRUE,EXTRAIMAGE_REFRESHDELAY);
+ /* Status Icon */
+ if(hMsgWndEventHook) {
+ int i = gMsgWndList.getIndex((MsgWndData*)&wParam);
+ if (i != -1) {
+ gMsgWndList[i]->ContryIDchange((int)ServiceDetectContactOriginCountry(wParam,0));
+ gMsgWndList[i]->FlagsIconUpdate();
+ }
+ }
+ }
+ return 0;
+}
+
+
+/***********************************************************************************************************
+ * module loading & unloading
+ ***********************************************************************************************************/
+
+/**
+ * This function initially loads all required stuff for Flags.
+ *
+ * @param none
+ *
+ * @return nothing
+ **/
+void SvcFlagsLoadModule()
+{
+ PrepareBufferedFunctions();
+ InitCountryListExt(); /* hack to replace core country list */
+ if(CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&nCountriesCount,(LPARAM)&countries))
+ nCountriesCount=0;
+ InitIcons(); /* load in iconlib */
+ //InitIpToCountry(); /* not implementet */
+ CreateServiceFunction(MS_FLAGS_DETECTCONTACTORIGINCOUNTRY,ServiceDetectContactOriginCountry);
+ //init settings
+ gFlagsOpts.bShowExtraImgFlag = DB::Setting::GetByte(MODNAMEFLAGS,"ShowExtraImgFlag", SETTING_SHOWEXTRAIMGFLAG_DEFAULT);
+ gFlagsOpts.bUseUnknownFlag = DB::Setting::GetByte(MODNAMEFLAGS,"UseUnknownFlag", SETTING_USEUNKNOWNFLAG_DEFAULT);
+ gFlagsOpts.idExtraColumn = DB::Setting::GetByte(MODNAMEFLAGS,"ExtraImgFlagColumn", SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT);
+ gFlagsOpts.bShowStatusIconFlag = DB::Setting::GetByte(MODNAMEFLAGS,"ShowStatusIconFlag", SETTING_SHOWSTATUSICONFLAG_DEFAULT);
+
+ hOptInitHook = HookEvent(ME_OPT_INITIALISE,ExtraImgOptInit);
+ hIconsChangedHook = HookEvent(ME_SKIN2_ICONSCHANGED,OnStatusIconsChanged);
+}
+
+/**
+ * This function is called by Miranda just after loading all system modules.
+ *
+ * @param none
+ *
+ * @return nothing
+ **/
+void SvcFlagsOnModulesLoaded() {
+ //use ExtraIconsService ?
+ if ( myGlobals.ExtraIconsServiceExist) {
+ SvcFlagsEnableExtraIcons(DB::Setting::GetByte(SET_CLIST_EXTRAICON_FLAGS2, 0), FALSE);
+ }
+ //use Clist ExtraImageService
+ else {
+ SvcFlagsEnableExtraIcons(gFlagsOpts.bShowExtraImgFlag? gFlagsOpts.idExtraColumn : -1, FALSE);
+ }
+ /* Status Icon */
+ if(myGlobals.MsgAddIconExist)
+ hMsgWndEventHook = HookEvent(ME_MSG_WINDOWEVENT, OnMsgWndEvent);
+}
+
+/**
+ * This function unloads the module.
+ *
+ * @param none
+ *
+ * @return nothing
+ **/
+void SvcFlagsUnloadModule() {
+ KillBufferedFunctions();
+ //Uninit ExtraImg
+ UnhookEvent(hRebuildIconsHook);
+ UnhookEvent(hApplyIconHook);
+ UnhookEvent(hIconsChangedHook);
+ UnhookEvent(hExtraIconSvcHook);
+ mir_free(phExtraImageList); /* does NULL check */
+ //Uninit message winsow
+ UnhookEvent(hMsgWndEventHook);
+ for(int i = 0; i < gMsgWndList.getCount(); i++) {
+ //this should not happen
+ delete gMsgWndList[i];
+ gMsgWndList.remove(i);
+ }
+ gMsgWndList.destroy();
+ gIListMW.destroy();
+ //Uninit misc
+ UnhookEvent(hSettingChangedHook);
+ UnhookEvent(hOptInitHook);
+ UninitIcons();
+
+ //UninitIpToCountry(); /* not implementet */
+}
+