From b99e1019f2d7403c8e2fd915cef82179415bd02a Mon Sep 17 00:00:00 2001 From: George Hazan Date: Wed, 30 May 2018 21:50:04 +0300 Subject: Extra icons (mir_app): - old reference system that used EI ids totally removed; - now HANDLE that is returned outside is a real pointer to EI; - old perversion with groups removed; - fixes #1394 (EI change require restart) --- src/mir_app/src/ei_baseIcon.cpp | 9 +- src/mir_app/src/ei_callbackIcon.cpp | 10 +- src/mir_app/src/ei_defaulticons.cpp | 16 +- src/mir_app/src/ei_extraIcon.cpp | 12 +- src/mir_app/src/ei_groupIcon.cpp | 27 +- src/mir_app/src/ei_icolibIcon.cpp | 12 +- src/mir_app/src/ei_options.cpp | 16 +- src/mir_app/src/ei_services.cpp | 132 +++--- src/mir_app/src/extraicons.h | 57 ++- src/mir_app/src/miranda.cpp | 10 +- src/mir_app/src/miranda.h | 2 +- src/mir_app/src/newplugins.cpp | 2 +- src/mir_app/src/proto_accs.cpp | 906 ++++++++++++++++++------------------ 13 files changed, 609 insertions(+), 602 deletions(-) (limited to 'src/mir_app') diff --git a/src/mir_app/src/ei_baseIcon.cpp b/src/mir_app/src/ei_baseIcon.cpp index 607d79cf8a..8876e90bc1 100644 --- a/src/mir_app/src/ei_baseIcon.cpp +++ b/src/mir_app/src/ei_baseIcon.cpp @@ -23,14 +23,14 @@ Boston, MA 02111-1307, USA. #include "extraicons.h" -BaseExtraIcon::BaseExtraIcon(int id, const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOKPARAM OnClick, LPARAM param) : +BaseExtraIcon::BaseExtraIcon(const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOKPARAM OnClick, LPARAM param) : ExtraIcon(name), - m_id(id), m_OnClick(OnClick), m_onClickParam(param), m_tszDescription(mir_wstrdup(description)), m_szDescIcon(mir_strdup(descIcon)) { + m_id = registeredExtraIcons.getCount() + 1; } BaseExtraIcon::~BaseExtraIcon() @@ -71,8 +71,7 @@ void BaseExtraIcon::onClick(MCONTACT hContact) int BaseExtraIcon::ClistSetExtraIcon(MCONTACT hContact, HANDLE hImage) { - ExtraIcon *tmp = extraIconsByHandle[m_id - 1]; - if (tmp != nullptr && tmp != this) - return tmp->ClistSetExtraIcon(hContact, hImage); + if (m_pParent) + return m_pParent->ClistSetExtraIcon(hContact, hImage); return Clist_SetExtraIcon(hContact, m_slot, hImage); } diff --git a/src/mir_app/src/ei_callbackIcon.cpp b/src/mir_app/src/ei_callbackIcon.cpp index c7cff67a09..d38c61289b 100644 --- a/src/mir_app/src/ei_callbackIcon.cpp +++ b/src/mir_app/src/ei_callbackIcon.cpp @@ -23,9 +23,9 @@ Boston, MA 02111-1307, USA. #include "extraicons.h" -CallbackExtraIcon::CallbackExtraIcon(int _id, const char *_name, const wchar_t *_description, const char *_descIcon, +CallbackExtraIcon::CallbackExtraIcon(const char *_name, const wchar_t *_description, const char *_descIcon, MIRANDAHOOK _RebuildIcons, MIRANDAHOOK _ApplyIcon, MIRANDAHOOKPARAM _OnClick, LPARAM _param) : - BaseExtraIcon(_id, _name, _description, _descIcon, _OnClick, _param), + BaseExtraIcon(_name, _description, _descIcon, _OnClick, _param), m_pfnRebuildIcons(_RebuildIcons), m_pfnApplyIcon(_ApplyIcon), m_needToRebuild(true) { } @@ -61,15 +61,15 @@ void CallbackExtraIcon::applyIcon(MCONTACT hContact) m_pfnApplyIcon(hContact, 0); } -int CallbackExtraIcon::setIcon(int id, MCONTACT hContact, HANDLE icon) +int CallbackExtraIcon::setIcon(MCONTACT hContact, HANDLE icon) { - if (!isEnabled() || hContact == 0 || id != m_id) + if (!isEnabled() || hContact == 0) return -1; return ClistSetExtraIcon(hContact, icon); } -int CallbackExtraIcon::setIconByName(int, MCONTACT, const char*) +int CallbackExtraIcon::setIconByName(MCONTACT, const char*) { return -1; } diff --git a/src/mir_app/src/ei_defaulticons.cpp b/src/mir_app/src/ei_defaulticons.cpp index 1a523d7a36..10ef3eeca1 100644 --- a/src/mir_app/src/ei_defaulticons.cpp +++ b/src/mir_app/src/ei_defaulticons.cpp @@ -25,8 +25,6 @@ Boston, MA 02111-1307, USA. #include "extraicons.h" -ExtraIcon* GetExtraIcon(HANDLE id); - //////////////////////////////////////////////////////////////////////////////////////// // DB extra icons @@ -61,11 +59,8 @@ static void SetVisibility(MCONTACT hContact, int apparentMode, bool clear) hIcolib = Skin_GetIconHandle(SKINICON_OTHER_VISIBLE_ALL); } - if (hIcolib != nullptr || clear) { - ExtraIcon *extra = GetExtraIcon(hExtraIcon); - if (extra) - extra->setIcon((INT_PTR)hExtraIcon, hContact, hIcolib); - } + if (hIcolib != nullptr || clear) + ExtraIcon_SetIcon(hExtraIcon, hContact, hIcolib); } static void SetGender(MCONTACT hContact, int gender, bool clear) @@ -90,11 +85,8 @@ static void SetGender(MCONTACT hContact, int gender, bool clear) else ico = nullptr; - if (ico != nullptr || clear) { - ExtraIcon *extra = GetExtraIcon(hExtraGender); - if (extra) - extra->setIconByName((INT_PTR)hExtraGender, hContact, ico); - } + if (ico != nullptr || clear) + ExtraIcon_SetIconByName(hExtraGender, hContact, ico); } struct Info diff --git a/src/mir_app/src/ei_extraIcon.cpp b/src/mir_app/src/ei_extraIcon.cpp index a0b0283fee..cf10d357e9 100644 --- a/src/mir_app/src/ei_extraIcon.cpp +++ b/src/mir_app/src/ei_extraIcon.cpp @@ -24,7 +24,7 @@ Boston, MA 02111-1307, USA. #include "extraicons.h" ExtraIcon::ExtraIcon(const char *name) : - m_szName(mir_strdup(name)), m_slot(-1), m_position(1000), m_hLangpack(0) + m_szName(mir_strdup(name)) { } @@ -62,6 +62,14 @@ bool ExtraIcon::isEnabled() const return m_slot >= 0; } +void ExtraIcon::doApply(MCONTACT hContact) +{ + if (m_pParent) + m_pParent->applyIcon(hContact); + else + applyIcon(hContact); +} + void ExtraIcon::applyIcons() { if (!isEnabled()) @@ -70,6 +78,6 @@ void ExtraIcon::applyIcons() for (auto &hContact : Contacts()) { // Clear to assert that it will be cleared Clist_SetExtraIcon(hContact, m_slot, INVALID_HANDLE_VALUE); - applyIcon(hContact); + doApply(hContact); } } diff --git a/src/mir_app/src/ei_groupIcon.cpp b/src/mir_app/src/ei_groupIcon.cpp index 36bbe8fea9..86442cc791 100644 --- a/src/mir_app/src/ei_groupIcon.cpp +++ b/src/mir_app/src/ei_groupIcon.cpp @@ -24,7 +24,7 @@ Boston, MA 02111-1307, USA. #include "extraicons.h" ExtraIconGroup::ExtraIconGroup(const char *_name) : - ExtraIcon(_name), m_setValidExtraIcon(false), m_insideApply(false), + ExtraIcon(_name), m_items(1) { db_set_resident(EI_MODULE_NAME, _name); @@ -95,24 +95,26 @@ void ExtraIconGroup::onClick(MCONTACT hContact) m_pCurrentItem->onClick(hContact); } -int ExtraIconGroup::setIcon(int id, MCONTACT hContact, HANDLE value) +int ExtraIconGroup::setIcon(MCONTACT, HANDLE) { - return internalSetIcon(id, hContact, (void*)value, false); + return -1; + // return internalSetIcon(hContact, (void*)value, false); } -int ExtraIconGroup::setIconByName(int id, MCONTACT hContact, const char *value) +int ExtraIconGroup::setIconByName(MCONTACT, const char*) { - return internalSetIcon(id, hContact, (void*)value, true); + return -1; + // return internalSetIcon(hContact, (void*)value, true); } -int ExtraIconGroup::internalSetIcon(int id, MCONTACT hContact, HANDLE value, bool bByName) +int ExtraIconGroup::internalSetIcon(ExtraIcon *pChild, MCONTACT hContact, HANDLE value, bool bByName) { if (m_insideApply) { for (auto &p : m_items) - if (p->getID() == id) { + if (p == pChild) { if (bByName) - return p->setIconByName(id, hContact, (const char*)value); - return p->setIcon(id, hContact, value); + return p->setIconByName(hContact, (const char*)value); + return p->setIcon(hContact, value); } return -1; @@ -121,7 +123,7 @@ int ExtraIconGroup::internalSetIcon(int id, MCONTACT hContact, HANDLE value, boo int currentPos = m_items.getCount(); int storePos = m_items.getCount(); for (int i = 0; i < m_items.getCount(); i++) { - if (m_items[i]->getID() == id) + if (m_items[i] == pChild) storePos = i; if (m_items[i] == m_pCurrentItem) @@ -137,14 +139,13 @@ int ExtraIconGroup::internalSetIcon(int id, MCONTACT hContact, HANDLE value, boo } // Ok, we have to set the icon, but we have to assert it is a valid icon - m_setValidExtraIcon = false; int ret; if (bByName) - ret = m_items[storePos]->setIconByName(id, hContact, (const char*)value); + ret = m_items[storePos]->setIconByName(hContact, (const char*)value); else - ret = m_items[storePos]->setIcon(id, hContact, (HANDLE)value); + ret = m_items[storePos]->setIcon(hContact, (HANDLE)value); if (storePos < currentPos) { if (m_setValidExtraIcon) diff --git a/src/mir_app/src/ei_icolibIcon.cpp b/src/mir_app/src/ei_icolibIcon.cpp index 31b6e0ef49..3935592e16 100644 --- a/src/mir_app/src/ei_icolibIcon.cpp +++ b/src/mir_app/src/ei_icolibIcon.cpp @@ -26,8 +26,8 @@ Boston, MA 02111-1307, USA. #include "IcoLib.h" -IcolibExtraIcon::IcolibExtraIcon(int _id, const char *_name, const wchar_t *_description, const char *_descIcon, MIRANDAHOOKPARAM _OnClick, LPARAM _param) : - BaseExtraIcon(_id, _name, _description, _descIcon, _OnClick, _param) +IcolibExtraIcon::IcolibExtraIcon(const char *_name, const wchar_t *_description, const char *_descIcon, MIRANDAHOOKPARAM _OnClick, LPARAM _param) : + BaseExtraIcon(_name, _description, _descIcon, _OnClick, _param) { db_set_resident(EI_MODULE_NAME, _name); } @@ -59,9 +59,9 @@ void IcolibExtraIcon::applyIcon(MCONTACT hContact) ClistSetExtraIcon(hContact, hImage); } -int IcolibExtraIcon::setIcon(int id, MCONTACT hContact, HANDLE hIcoLib) +int IcolibExtraIcon::setIcon(MCONTACT hContact, HANDLE hIcoLib) { - if (hContact == 0 || id != m_id) + if (hContact == 0) return -1; if (hIcoLib == INVALID_HANDLE_VALUE) @@ -83,9 +83,9 @@ int IcolibExtraIcon::setIcon(int id, MCONTACT hContact, HANDLE hIcoLib) return 0; } -int IcolibExtraIcon::setIconByName(int id, MCONTACT hContact, const char *icon) +int IcolibExtraIcon::setIconByName(MCONTACT hContact, const char *icon) { - if (hContact == 0 || id != m_id) + if (hContact == 0) return -1; if (icon == INVALID_HANDLE_VALUE) diff --git a/src/mir_app/src/ei_options.cpp b/src/mir_app/src/ei_options.cpp index 113c34c67a..54c1d627d2 100644 --- a/src/mir_app/src/ei_options.cpp +++ b/src/mir_app/src/ei_options.cpp @@ -265,6 +265,8 @@ public: ImageList_AddIcon(hImageList, hBlankIcon); for (auto &extra : registeredExtraIcons) { + extra->setID(registeredExtraIcons.indexOf(&extra) + 1); + HICON hIcon = IcoLib_GetIcon(extra->getDescIcon()); if (hIcon == nullptr) ImageList_AddIcon(hImageList, hBlankIcon); @@ -300,10 +302,9 @@ public: int *oldSlots = new int[registeredExtraIcons.getCount()]; int lastUsedSlot = -1; for (int i = 0; i < registeredExtraIcons.getCount(); i++) { - if (extraIconsByHandle[i] == registeredExtraIcons[i]) + if (registeredExtraIcons[i]->getType() != EXTRAICON_TYPE_GROUP) oldSlots[i] = registeredExtraIcons[i]->getSlot(); - else - // Remove old slot for groups to re-set images + else // Remove old slot for groups to re-set images oldSlots[i] = -1; lastUsedSlot = max(lastUsedSlot, registeredExtraIcons[i]->getSlot()); } @@ -322,7 +323,7 @@ public: tvi.hItem = ht; m_tree.GetItem(&tvi); - intlist*ids = (intlist*)tvi.lParam; + intlist *ids = (intlist*)tvi.lParam; if (ids == nullptr || ids->count < 1) continue; // ??? @@ -389,14 +390,9 @@ public: // Apply icons to new slots RebuildListsBasedOnGroups(groups); - for (auto &extra : extraIconsBySlot) { - if (extra->getType() != EXTRAICON_TYPE_GROUP) - if (oldSlots[((BaseExtraIcon *)extra)->getID() - 1] == extra->getSlot()) - continue; - + for (auto &extra : extraIconsBySlot) if (extra->isEnabled()) extra->applyIcons(); - } delete[] oldSlots; } diff --git a/src/mir_app/src/ei_services.cpp b/src/mir_app/src/ei_services.cpp index 354b0a8a72..60cb0e7567 100644 --- a/src/mir_app/src/ei_services.cpp +++ b/src/mir_app/src/ei_services.cpp @@ -35,16 +35,13 @@ int SortFunc(const ExtraIcon *p1, const ExtraIcon *p2) if (ret != 0) return ret; - int id1 = (p1->getType() != EXTRAICON_TYPE_GROUP) ? ((BaseExtraIcon*)p1)->getID() : 0; - int id2 = (p2->getType() != EXTRAICON_TYPE_GROUP) ? ((BaseExtraIcon*)p2)->getID() : 0; - return id1 - id2; + return p1->getID() - p2->getID(); } -LIST extraIconsByHandle(10), extraIconsBySlot(10, SortFunc); -LIST registeredExtraIcons(10); +LIST extraIconsBySlot(10, SortFunc); +LIST registeredExtraIcons(10, PtrKeySortT); -BOOL clistRebuildAlreadyCalled = FALSE; -BOOL clistApplyAlreadyCalled = FALSE; +static bool clistRebuildAlreadyCalled = false, clistApplyAlreadyCalled = false; // Functions //////////////////////////////////////////////////////////////////////////// @@ -87,24 +84,6 @@ int Clist_SetExtraIcon(MCONTACT hContact, int slot, HANDLE hImage) return 0; } -ExtraIcon* GetExtraIcon(HANDLE id) -{ - int i = (INT_PTR)id; - if (i < 1 || i > extraIconsByHandle.getCount()) - return nullptr; - - return extraIconsByHandle[i - 1]; -} - -ExtraIcon* GetExtraIconBySlot(int slot) -{ - for (auto &extra : extraIconsBySlot) - if (extra->getSlot() == slot) - return extra; - - return nullptr; -} - BaseExtraIcon* GetExtraIconByName(const char *name) { for (auto &extra : registeredExtraIcons) @@ -163,10 +142,8 @@ static ExtraIconGroup* IsInGroup(LIST &groups, BaseExtraIcon *ex void RebuildListsBasedOnGroups(LIST &groups) { - extraIconsByHandle.destroy(); - - for (auto &it : registeredExtraIcons) - extraIconsByHandle.insert(it); + for (auto &extra : registeredExtraIcons) + extra->setParent(nullptr); for (auto &extra : extraIconsBySlot) if (extra->getType() == EXTRAICON_TYPE_GROUP) @@ -175,18 +152,45 @@ void RebuildListsBasedOnGroups(LIST &groups) for (auto &group : groups) { for (auto &it : group->m_items) - extraIconsByHandle.put(it->getID()-1, group); + it->setParent(group); extraIconsBySlot.insert(group); } - for (auto &extra : extraIconsByHandle) - if (extra->getType() != EXTRAICON_TYPE_GROUP) + for (auto &extra : registeredExtraIcons) + if (extra->getParent() == nullptr) extraIconsBySlot.insert(extra); } /////////////////////////////////////////////////////////////////////////////// +static void ResetSlots(BaseExtraIcon *extra, ExtraIconGroup *group) +{ + int slot = 0, oldMaxSlot = -1; + for (auto &ex : extraIconsBySlot) { + if (ex->getSlot() < 0) + continue; + + int oldSlot = ex->getSlot(); + if (oldSlot > oldMaxSlot) + oldMaxSlot = oldSlot+1; + + ex->setSlot(slot++); + + if (clistApplyAlreadyCalled && (ex == group || ex == extra || oldSlot != slot)) + ex->applyIcons(); + } + + // slots were freed, we need to clear one or more items + if (extra == nullptr) + for (int i = slot; i < oldMaxSlot; i++) + for (auto &hContact : Contacts()) + Clist_SetExtraIcon(hContact, i, INVALID_HANDLE_VALUE); + + if (!g_bMirandaTerminated) + Clist_InitAutoRebuild(g_clistApi.hwndContactTree); +} + MIR_APP_DLL(void) KillModuleExtraIcons(int _hLang) { LIST arIcons(1); @@ -204,7 +208,7 @@ MIR_APP_DLL(void) KillModuleExtraIcons(int _hLang) LIST groups(1); LoadGroups(groups); RebuildListsBasedOnGroups(groups); - ExtraIcon_SetAll(); + ResetSlots(0, 0); for (auto &it : arIcons) delete it; @@ -214,7 +218,7 @@ MIR_APP_DLL(void) KillModuleExtraIcons(int _hLang) int ClistExtraListRebuild(WPARAM, LPARAM) { - clistRebuildAlreadyCalled = TRUE; + clistRebuildAlreadyCalled = true; ResetIcons(); @@ -229,10 +233,10 @@ int ClistExtraImageApply(WPARAM hContact, LPARAM) if (hContact == 0) return 0; - clistApplyAlreadyCalled = TRUE; + clistApplyAlreadyCalled = true; for (auto &it : extraIconsBySlot) - it->applyIcon(hContact); + it->doApply(hContact); return 0; } @@ -329,7 +333,6 @@ static void EI_PostCreate(BaseExtraIcon *extra, const char *name, int flags) extra->setSlot(slot); registeredExtraIcons.insert(extra); - extraIconsByHandle.insert(extra); LIST groups(1); LoadGroups(groups); @@ -348,17 +351,7 @@ static void EI_PostCreate(BaseExtraIcon *extra, const char *name, int flags) if (clistRebuildAlreadyCalled) extra->rebuildIcons(); - slot = 0; - for (auto &ex : extraIconsBySlot) { - if (ex->getSlot() < 0) - continue; - - int oldSlot = ex->getSlot(); - ex->setSlot(slot++); - - if (clistApplyAlreadyCalled && (ex == group || ex == extra || oldSlot != slot)) - extra->applyIcons(); - } + ResetSlots(extra, group); } } @@ -379,11 +372,10 @@ EXTERN_C MIR_APP_DLL(HANDLE) ExtraIcon_RegisterCallback(const char *name, const ptrW tszDesc(mir_a2u(description)); - int id = registeredExtraIcons.getCount() + 1; - BaseExtraIcon *extra = new CallbackExtraIcon(id, name, tszDesc, descIcon == nullptr ? "" : descIcon, RebuildIcons, ApplyIcon, OnClick, onClickParam); + BaseExtraIcon *extra = new CallbackExtraIcon(name, tszDesc, descIcon == nullptr ? "" : descIcon, RebuildIcons, ApplyIcon, OnClick, onClickParam); extra->m_hLangpack = GetPluginLangByInstance(GetInstByAddress(RebuildIcons)); EI_PostCreate(extra, name, flags); - return (HANDLE)id; + return extra; } EXTERN_C MIR_APP_DLL(HANDLE) ExtraIcon_RegisterIcolib(const char *name, const char *description, const char *descIcon, @@ -410,17 +402,16 @@ EXTERN_C MIR_APP_DLL(HANDLE) ExtraIcon_RegisterIcolib(const char *name, const ch if (clistRebuildAlreadyCalled) extra->rebuildIcons(); if (clistApplyAlreadyCalled) - extraIconsByHandle[extra->getID() - 1]->applyIcons(); + extra->applyIcons(); } - - return (HANDLE)extra->getID(); } - - int id = registeredExtraIcons.getCount() + 1; - extra = new IcolibExtraIcon(id, name, tszDesc, descIcon == nullptr ? "" : descIcon, OnClick, onClickParam); - extra->m_hLangpack = GetPluginLangByInstance(GetInstByAddress((void*)name)); - EI_PostCreate(extra, name, flags); - return (HANDLE)id; + else { + extra = new IcolibExtraIcon(name, tszDesc, descIcon == nullptr ? "" : descIcon, OnClick, onClickParam); + extra->m_hLangpack = GetPluginLangByInstance(GetInstByAddress((void*)name)); + EI_PostCreate(extra, name, flags); + } + + return extra; } /////////////////////////////////////////////////////////////////////////////// @@ -430,11 +421,14 @@ MIR_APP_DLL(int) ExtraIcon_SetIcon(HANDLE hExtraIcon, MCONTACT hContact, HANDLE if (hExtraIcon == nullptr || hContact == 0) return -1; - ExtraIcon *extra = GetExtraIcon(hExtraIcon); + BaseExtraIcon *extra = registeredExtraIcons.find((BaseExtraIcon*)hExtraIcon); if (extra == nullptr) return -1; - return extra->setIcon((INT_PTR)hExtraIcon, hContact, hImage); + if (extra->getParent()) + return extra->getParent()->internalSetIcon(extra, hContact, hImage, false); + + return extra->setIcon(hContact, hImage); } MIR_APP_DLL(int) ExtraIcon_SetIconByName(HANDLE hExtraIcon, MCONTACT hContact, const char *icoName) @@ -442,11 +436,14 @@ MIR_APP_DLL(int) ExtraIcon_SetIconByName(HANDLE hExtraIcon, MCONTACT hContact, c if (hExtraIcon == nullptr || hContact == 0) return -1; - ExtraIcon *extra = GetExtraIcon(hExtraIcon); + BaseExtraIcon *extra = registeredExtraIcons.find((BaseExtraIcon*)hExtraIcon); if (extra == nullptr) return -1; - return extra->setIconByName((INT_PTR)hExtraIcon, hContact, icoName); + if (extra->getParent()) + return extra->getParent()->internalSetIcon(extra, hContact, (HANDLE)icoName, true); + + return extra->setIconByName(hContact, icoName); } MIR_APP_DLL(int) ExtraIcon_Clear(HANDLE hExtraIcon, MCONTACT hContact) @@ -454,11 +451,14 @@ MIR_APP_DLL(int) ExtraIcon_Clear(HANDLE hExtraIcon, MCONTACT hContact) if (hExtraIcon == nullptr || hContact == 0) return -1; - ExtraIcon *extra = GetExtraIcon(hExtraIcon); + BaseExtraIcon *extra = registeredExtraIcons.find((BaseExtraIcon*)hExtraIcon); if (extra == nullptr) return -1; - return extra->setIcon((INT_PTR)hExtraIcon, hContact, nullptr); + if (extra->getParent()) + return extra->getParent()->internalSetIcon(extra, hContact, nullptr, false); + + return extra->setIcon(hContact, nullptr); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/mir_app/src/extraicons.h b/src/mir_app/src/extraicons.h index b15a9dd352..5c6a6b7a46 100644 --- a/src/mir_app/src/extraicons.h +++ b/src/mir_app/src/extraicons.h @@ -30,6 +30,8 @@ Boston, MA 02111-1307, USA. #define EXTRAICON_TYPE_GROUP -1 +class ExtraIconGroup; + ///////////////////////////////////////////////////////////////////////////////////////// // ExtraIcon - base class for all extra icons @@ -39,13 +41,21 @@ public: ExtraIcon(const char *name); virtual ~ExtraIcon(); + __forceinline int getID() const { return m_id; } + __forceinline void setID(int _id) { m_id = _id; } + + __forceinline ExtraIconGroup* getParent() const { return m_pParent; } + __forceinline void setParent(ExtraIconGroup *p) { m_pParent = p; } + + void doApply(MCONTACT hContact); + void applyIcons(); + virtual void rebuildIcons() = 0; - virtual void applyIcons(); virtual void applyIcon(MCONTACT hContact) = 0; virtual void onClick(MCONTACT hContact) = 0; - virtual int setIcon(int id, MCONTACT hContact, HANDLE icon) = 0; - virtual int setIconByName(int id, MCONTACT hContact, const char* icon) = 0; + virtual int setIcon(MCONTACT hContact, HANDLE icon) = 0; + virtual int setIconByName(MCONTACT hContact, const char* icon) = 0; virtual void storeIcon(MCONTACT, void*) {}; virtual const char *getName() const; @@ -63,13 +73,16 @@ public: virtual int ClistSetExtraIcon(MCONTACT hContact, HANDLE hImage) = 0; - int m_hLangpack; + int m_hLangpack = 0; protected: ptrA m_szName; - int m_slot; - int m_position; + int m_id = 0; + int m_slot = -1; + int m_position = 1000; + + ExtraIconGroup *m_pParent = nullptr; }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -78,11 +91,9 @@ protected: class BaseExtraIcon : public ExtraIcon { public: - BaseExtraIcon(int id, const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOKPARAM OnClick, LPARAM param); + BaseExtraIcon(const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOKPARAM OnClick, LPARAM param); virtual ~BaseExtraIcon(); - __forceinline int getID() const { return m_id; } - virtual const wchar_t* getDescription() const; virtual void setDescription(const wchar_t *desc); virtual const char* getDescIcon() const; @@ -95,7 +106,6 @@ public: virtual int ClistSetExtraIcon(MCONTACT hContact, HANDLE hImage); protected: - int m_id; ptrW m_tszDescription; ptrA m_szDescIcon; MIRANDAHOOKPARAM m_OnClick; @@ -108,7 +118,7 @@ protected: class CallbackExtraIcon : public BaseExtraIcon { public: - CallbackExtraIcon(int id, const char *name, const wchar_t *description, const char *descIcon, + CallbackExtraIcon(const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOK RebuildIcons, MIRANDAHOOK ApplyIcon, MIRANDAHOOKPARAM OnClick, LPARAM param); virtual ~CallbackExtraIcon(); @@ -117,8 +127,8 @@ public: virtual void rebuildIcons(); virtual void applyIcon(MCONTACT hContact); - virtual int setIcon(int id, MCONTACT hContact, HANDLE icon); - virtual int setIconByName(int id, MCONTACT hContact, const char* icon); + virtual int setIcon(MCONTACT hContact, HANDLE icon); + virtual int setIconByName(MCONTACT hContact, const char* icon); private: int (*m_pfnRebuildIcons)(WPARAM wParam, LPARAM lParam); @@ -133,7 +143,7 @@ private: class IcolibExtraIcon : public BaseExtraIcon { public: - IcolibExtraIcon(int id, const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOKPARAM OnClick, LPARAM param); + IcolibExtraIcon(const char *name, const wchar_t *description, const char *descIcon, MIRANDAHOOKPARAM OnClick, LPARAM param); virtual ~IcolibExtraIcon(); virtual int getType() const; @@ -141,8 +151,8 @@ public: virtual void rebuildIcons(); virtual void applyIcon(MCONTACT hContact); - virtual int setIcon(int id, MCONTACT hContact, HANDLE icon); - virtual int setIconByName(int id, MCONTACT hContact, const char* icon); + virtual int setIcon(MCONTACT hContact, HANDLE icon); + virtual int setIconByName(MCONTACT hContact, const char* icon); virtual void storeIcon(MCONTACT hContact, void *icon); }; @@ -151,8 +161,6 @@ public: class ExtraIconGroup : public ExtraIcon { - int internalSetIcon(int id, MCONTACT hContact, HANDLE icon, bool bByName); - public: ExtraIconGroup(const char *name); virtual ~ExtraIconGroup(); @@ -163,8 +171,8 @@ public: virtual void applyIcon(MCONTACT hContact); virtual void onClick(MCONTACT hContact); - virtual int setIcon(int id, MCONTACT hContact, HANDLE icon); - virtual int setIconByName(int id, MCONTACT hContact, const char *icon); + virtual int setIcon(MCONTACT hContact, HANDLE icon); + virtual int setIconByName(MCONTACT hContact, const char *icon); virtual const wchar_t* getDescription() const; virtual const char* getDescIcon() const; @@ -177,10 +185,12 @@ public: virtual int ClistSetExtraIcon(MCONTACT hContact, HANDLE hImage); + int internalSetIcon(ExtraIcon *pChild, MCONTACT hContact, HANDLE icon, bool bByName); + protected: ptrW m_tszDescription; - bool m_setValidExtraIcon; - bool m_insideApply; + bool m_setValidExtraIcon = false; + bool m_insideApply = false; ExtraIcon *m_pCurrentItem = nullptr; }; @@ -188,9 +198,8 @@ protected: ///////////////////////////////////////////////////////////////////////////////////////// extern LIST registeredExtraIcons; -extern LIST extraIconsByHandle, extraIconsBySlot; void RebuildListsBasedOnGroups(LIST &groups); -ExtraIcon * GetExtraIconBySlot(int slot); +extern LIST extraIconsBySlot; int ConvertToClistSlot(int slot); diff --git a/src/mir_app/src/miranda.cpp b/src/mir_app/src/miranda.cpp index 542c2ac55e..691d6847a3 100644 --- a/src/mir_app/src/miranda.cpp +++ b/src/mir_app/src/miranda.cpp @@ -51,7 +51,7 @@ ITaskbarList3 *pTaskbarInterface; HANDLE hOkToExitEvent, hModulesLoadedEvent; HANDLE hShutdownEvent, hPreShutdownEvent; DWORD hMainThreadId; -bool bModulesLoadedFired = false, bMirandaTerminated = false; +bool g_bModulesLoadedFired = false, g_bMirandaTerminated = false; int g_iIconX, g_iIconY, g_iIconSX, g_iIconSY; CMPlugin g_plugin; @@ -316,7 +316,7 @@ int WINAPI mir_main(LPTSTR cmdLine) int result = 0; if (LoadDefaultModules()) { - bMirandaTerminated = true; + g_bMirandaTerminated = true; NotifyEventHooks(hPreShutdownEvent, 0, 0); NotifyEventHooks(hShutdownEvent, 0, 0); UnloadDefaultModules(); @@ -326,7 +326,7 @@ int WINAPI mir_main(LPTSTR cmdLine) else { InitPathVar(); NotifyEventHooks(hModulesLoadedEvent, 0, 0); - bModulesLoadedFired = true; + g_bModulesLoadedFired = true; // ensure that the kernel hooks the SystemShutdownProc() after all plugins HookEvent(ME_SYSTEM_SHUTDOWN, SystemShutdownProc); @@ -364,7 +364,7 @@ int WINAPI mir_main(LPTSTR cmdLine) } else if (!dying) { dying++; - bMirandaTerminated = true; + g_bMirandaTerminated = true; NotifyEventHooks(hPreShutdownEvent, 0, 0); // this spins and processes the msg loop, objects and APC. @@ -398,7 +398,7 @@ int WINAPI mir_main(LPTSTR cmdLine) MIR_APP_DLL(bool) Miranda_IsTerminated() { - return bMirandaTerminated; + return g_bMirandaTerminated; } MIR_APP_DLL(bool) Miranda_OkToExit() diff --git a/src/mir_app/src/miranda.h b/src/mir_app/src/miranda.h index 3798094951..a381d71f3d 100644 --- a/src/mir_app/src/miranda.h +++ b/src/mir_app/src/miranda.h @@ -64,7 +64,7 @@ extern HANDLE hOkToExitEvent, hModulesLoadedEvent, hevLoadModule, hevUnloadModul extern HANDLE hAccListChanged; extern wchar_t mirandabootini[MAX_PATH]; extern struct pluginEntry *plugin_crshdmp, *plugin_service, *plugin_ssl, *plugin_clist; -extern bool bModulesLoadedFired; +extern bool g_bModulesLoadedFired, g_bMirandaTerminated; /**** newplugins.cpp *******************************************************************/ diff --git a/src/mir_app/src/newplugins.cpp b/src/mir_app/src/newplugins.cpp index f7f8b5814d..2be85d985e 100644 --- a/src/mir_app/src/newplugins.cpp +++ b/src/mir_app/src/newplugins.cpp @@ -507,7 +507,7 @@ LBL_Error: goto LBL_Error; CMPluginBase *ppb = ppe->m_pPlugin; - if (bModulesLoadedFired) { + if (g_bModulesLoadedFired) { if (CallPluginEventHook(ppb->getInst(), hModulesLoadedEvent, 0, 0) != 0) goto LBL_Error; diff --git a/src/mir_app/src/proto_accs.cpp b/src/mir_app/src/proto_accs.cpp index 39604d8da2..55cbcd8270 100644 --- a/src/mir_app/src/proto_accs.cpp +++ b/src/mir_app/src/proto_accs.cpp @@ -1,452 +1,454 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#include "stdafx.h" - -#include "clc.h" - -bool CheckProtocolOrder(void); -void BuildProtoMenus(); - -HICON Proto_GetIcon(PROTO_INTERFACE *ppro, int iconIndex); - -static bool bModuleInitialized = false; -static HANDLE hHooks[3]; - -static int CompareAccounts(const PROTOACCOUNT* p1, const PROTOACCOUNT* p2) -{ - return mir_strcmp(p1->szModuleName, p2->szModuleName); -} - -LIST accounts(10, CompareAccounts); - -///////////////////////////////////////////////////////////////////////////////////////// - -static int EnumDbModules(const char *szModuleName, void*) -{ - ptrA szProtoName(db_get_sa(0, szModuleName, "AM_BaseProto")); - if (szProtoName) { - if (!Proto_GetAccount(szModuleName)) { - PROTOACCOUNT *pa = new PROTOACCOUNT(szModuleName); - pa->szProtoName = szProtoName.detach(); - pa->tszAccountName = mir_a2u(szModuleName); - pa->bIsVisible = true; - pa->bIsEnabled = false; - pa->iOrder = accounts.getCount(); - accounts.insert(pa); - } - } - return 0; -} - -void LoadDbAccounts(void) -{ - int ver = db_get_dw(0, "Protocols", "PrVer", -1); - int count = db_get_dw(0, "Protocols", "ProtoCount", 0); - - for (int i = 0; i < count; i++) { - char buf[10]; - _itoa(i, buf, 10); - ptrA szModuleName(db_get_sa(0, "Protocols", buf)); - if (szModuleName == nullptr) - continue; - - PROTOACCOUNT *pa = Proto_GetAccount(szModuleName); - if (pa == nullptr) { - pa = new PROTOACCOUNT(szModuleName); - accounts.insert(pa); - } - - _itoa(OFFSET_VISIBLE + i, buf, 10); - pa->bIsVisible = db_get_dw(0, "Protocols", buf, 1) != 0; - - _itoa(OFFSET_PROTOPOS + i, buf, 10); - pa->iOrder = db_get_dw(0, "Protocols", buf, 1); - - if (ver >= 4) { - _itoa(OFFSET_NAME + i, buf, 10); - pa->tszAccountName = db_get_wsa(0, "Protocols", buf); - - _itoa(OFFSET_ENABLED + i, buf, 10); - pa->bIsEnabled = db_get_dw(0, "Protocols", buf, 1) != 0; - if (!pa->bIsEnabled && !mir_strcmp(pa->szModuleName, META_PROTO)) { - pa->bIsEnabled = true; - db_set_dw(0, "Protocols", buf, 1); - } - pa->szProtoName = db_get_sa(0, szModuleName, "AM_BaseProto"); - } - else pa->bIsEnabled = true; - - if (!pa->szProtoName) { - pa->szProtoName = mir_strdup(szModuleName); - db_set_s(0, szModuleName, "AM_BaseProto", pa->szProtoName); - } - - if (!pa->tszAccountName) - pa->tszAccountName = mir_a2u(szModuleName); - } - - if (CheckProtocolOrder()) - WriteDbAccounts(); - - int anum = accounts.getCount(); - db_enum_modules(EnumDbModules); - if (anum != accounts.getCount()) - WriteDbAccounts(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct enumDB_ProtoProcParam -{ - int arrlen; - char **pszSettingName; -}; - -static int enumDB_ProtoProc(const char* szSetting, void *lParam) -{ - if (szSetting) { - enumDB_ProtoProcParam* p = (enumDB_ProtoProcParam*)lParam; - - p->arrlen++; - p->pszSettingName = (char**)mir_realloc(p->pszSettingName, p->arrlen*sizeof(char*)); - p->pszSettingName[p->arrlen - 1] = mir_strdup(szSetting); - } - return 0; -} - -void WriteDbAccounts() -{ - // enum all old settings to delete - enumDB_ProtoProcParam param = { 0, nullptr }; - db_enum_settings(0, enumDB_ProtoProc, "Protocols", ¶m); - - // delete all settings - if (param.arrlen) { - for (int i = 0; i < param.arrlen; i++) { - db_unset(0, "Protocols", param.pszSettingName[i]); - mir_free(param.pszSettingName[i]); - } - mir_free(param.pszSettingName); - } - - // write new data - for (int i = 0; i < accounts.getCount(); i++) { - PROTOACCOUNT *pa = accounts[i]; - - char buf[20]; - _itoa(i, buf, 10); - db_set_s(0, "Protocols", buf, pa->szModuleName); - - _itoa(OFFSET_PROTOPOS + i, buf, 10); - db_set_dw(0, "Protocols", buf, pa->iOrder); - - _itoa(OFFSET_VISIBLE + i, buf, 10); - db_set_dw(0, "Protocols", buf, pa->bIsVisible); - - _itoa(OFFSET_ENABLED + i, buf, 10); - db_set_dw(0, "Protocols", buf, pa->bIsEnabled); - - _itoa(OFFSET_NAME + i, buf, 10); - db_set_ws(0, "Protocols", buf, pa->tszAccountName); - } - - db_unset(0, "Protocols", "ProtoCount"); - db_set_dw(0, "Protocols", "ProtoCount", accounts.getCount()); - db_set_dw(0, "Protocols", "PrVer", 4); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int OnContactDeleted(WPARAM hContact, LPARAM) -{ - if (hContact) { - PROTOACCOUNT *pa = Proto_GetAccount(hContact); - if (pa->IsEnabled() && pa->ppro) - pa->ppro->OnContactDeleted(hContact); - } - return 0; -} - -static int InitializeStaticAccounts(WPARAM, LPARAM) -{ - int count = 0; - - for (auto &pa : accounts) { - if (!pa->ppro || !pa->IsEnabled()) - continue; - - pa->ppro->OnModulesLoaded(); - - if (!pa->bOldProto) - count++; - } - - BuildProtoMenus(); - - if (count == 0 && !db_get_b(0, "FirstRun", "AccManager", 0)) { - db_set_b(0, "FirstRun", "AccManager", 1); - CallService(MS_PROTO_SHOWACCMGR, 0, 0); - } - // This is for pack creators with a profile with predefined accounts - else if (db_get_b(0, "FirstRun", "ForceShowAccManager", 0)) { - CallService(MS_PROTO_SHOWACCMGR, 0, 0); - db_unset(0, "FirstRun", "ForceShowAccManager"); - } - return 0; -} - -static int UninitializeStaticAccounts(WPARAM, LPARAM) -{ - // request permission to exit first - for (auto &pa : accounts) - if (pa->ppro && pa->IsEnabled()) - if (!pa->ppro->IsReadyToExit()) - return 1; - - // okay, all protocols are ready, exiting - for (auto &pa : accounts) - if (pa->ppro && pa->IsEnabled()) - pa->ppro->OnShutdown(); - - return 0; -} - -int LoadAccountsModule(void) -{ - bModuleInitialized = true; - - for (auto &pa : accounts) { - pa->bDynDisabled = !Proto_IsProtocolLoaded(pa->szProtoName); - if (pa->ppro) - continue; - - if (!pa->IsEnabled()) - continue; - - if (!ActivateAccount(pa, false)) - pa->bDynDisabled = true; - } - - hHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, InitializeStaticAccounts); - hHooks[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, UninitializeStaticAccounts); - hHooks[2] = HookEvent(ME_DB_CONTACT_DELETED, OnContactDeleted); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static HANDLE CreateProtoServiceEx(const char* szModule, const char* szService, MIRANDASERVICEOBJ pFunc, void* param) -{ - char tmp[100]; - mir_snprintf(tmp, "%s%s", szModule, szService); - return CreateServiceFunctionObj(tmp, pFunc, param); -} - -bool ActivateAccount(PROTOACCOUNT *pa, bool bIsDynamic) -{ - MBaseProto *ppd = Proto_GetProto(pa->szProtoName); - if (ppd == nullptr) - return false; - - if (ppd->fnInit == nullptr) - return false; - - PROTO_INTERFACE *ppi = ppd->fnInit(pa->szModuleName, pa->tszAccountName); - if (ppi == nullptr) - return false; - - pa->ppro = ppi; - if (ppi->m_hProtoIcon == nullptr) - ppi->m_hProtoIcon = IcoLib_IsManaged(Skin_LoadProtoIcon(pa->szModuleName, ID_STATUS_ONLINE)); - ppi->m_iDesiredStatus = ppi->m_iStatus = ID_STATUS_OFFLINE; - - if (bIsDynamic) { - if (bModulesLoadedFired) - pa->ppro->OnModulesLoaded(); - if (!db_get_b(0, "CList", "MoveProtoMenus", true)) - pa->ppro->OnBuildProtoMenu(); - pa->bDynDisabled = false; - } - return true; -} - -MIR_APP_DLL(int) Proto_GetAverageStatus(int *pAccountNumber) -{ - int netProtoCount = 0, averageMode = 0; - - for (auto &pa : accounts) { - if (!pa->IsVisible() || pa->IsLocked()) - continue; - - netProtoCount++; - if (averageMode == 0) - averageMode = pa->iRealStatus; - else if (averageMode > 0 && averageMode != pa->iRealStatus) { - averageMode = -1; - if (pAccountNumber == nullptr) - break; - } - } - - if (pAccountNumber) - *pAccountNumber = netProtoCount; - return averageMode; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct DeactivationThreadParam -{ - PROTO_INTERFACE *ppro; - pfnUninitProto fnUninit; - int flags; -}; - -pfnUninitProto GetProtocolDestructor(char *szProto); - -static void __cdecl DeactivationThread(DeactivationThreadParam *param) -{ - PROTO_INTERFACE *p = (PROTO_INTERFACE*)param->ppro; - p->SetStatus(ID_STATUS_OFFLINE); - - char *szModuleName = NEWSTR_ALLOCA(p->m_szModuleName); - - if (param->flags & DAF_DYNAMIC) { - while (!p->IsReadyToExit()) - SleepEx(100, TRUE); - - p->OnShutdown(); - } - - KillObjectThreads(p); // waits for them before terminating - KillObjectEventHooks(p); // untie an object from the outside world - - if (param->flags & DAF_ERASE) - p->OnErase(); - - if (param->fnUninit) - param->fnUninit(p); - - KillObjectServices(p); - - if (param->flags & DAF_ERASE) - EraseAccount(szModuleName); - - delete param; -} - -void DeactivateAccount(PROTOACCOUNT *pa, int flags) -{ - if (pa->hwndAccMgrUI) { - DestroyWindow(pa->hwndAccMgrUI); - pa->hwndAccMgrUI = nullptr; - pa->bAccMgrUIChanged = FALSE; - } - - if (flags & DAF_DYNAMIC) - NotifyEventHooks(hAccListChanged, PRAC_REMOVED, (LPARAM)pa); - else - pa->iIconBase = -1; - - if (pa->ppro == nullptr) { - if (flags & DAF_ERASE) - EraseAccount(pa->szModuleName); - return; - } - - DeactivationThreadParam *param = new DeactivationThreadParam; - param->ppro = pa->ppro; - param->fnUninit = GetProtocolDestructor(pa->szProtoName); - param->flags = flags; - pa->ppro = nullptr; - if (flags & DAF_FORK) - mir_forkThread(DeactivationThread, param); - else - DeactivationThread(param); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void KillModuleAccounts(HINSTANCE hInst) -{ - for (auto &pd : g_arProtos.rev_iter()) { - if (pd->hInst != hInst) - continue; - - for (auto &pa : accounts.rev_iter()) { - if (!mir_strcmp(pa->szProtoName, pd->szName)) { - pa->bDynDisabled = true; - DeactivateAccount(pa, DAF_DYNAMIC); - } - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void EraseAccount(const char *pszModuleName) -{ - // remove protocol contacts first - for (MCONTACT hContact = db_find_first(pszModuleName); hContact != 0;) { - MCONTACT hNext = db_find_next(hContact, pszModuleName); - db_delete_contact(hContact); - hContact = hNext; - } - - // remove all protocol settings - db_delete_module(0, pszModuleName); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void UnloadAccount(PROTOACCOUNT *pa, int flags) -{ - DeactivateAccount(pa, flags); - - // szModuleName should be freed only on a program's exit. - // otherwise many plugins dependand on static protocol names will crash! - // do NOT fix this 'leak', please - if (!(flags & DAF_DYNAMIC)) - delete pa; - else { - replaceStrW(pa->tszAccountName, 0); replaceStr(pa->szProtoName, 0); replaceStr(pa->szUniqueId, 0); - } -} - -void UnloadAccountsModule() -{ - if (!bModuleInitialized) - return; - - auto T = accounts.rev_iter(); - for (auto &it : T) { - UnloadAccount(it, 0); - accounts.remove(T.indexOf(&it)); - } - accounts.destroy(); - - for (auto &it : hHooks) - UnhookEvent(it); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#include "stdafx.h" + +#include "clc.h" + +bool CheckProtocolOrder(void); +void BuildProtoMenus(); + +HICON Proto_GetIcon(PROTO_INTERFACE *ppro, int iconIndex); + +static bool bModuleInitialized = false; +static HANDLE hHooks[3]; + +static int CompareAccounts(const PROTOACCOUNT* p1, const PROTOACCOUNT* p2) +{ + return mir_strcmp(p1->szModuleName, p2->szModuleName); +} + +LIST accounts(10, CompareAccounts); + +///////////////////////////////////////////////////////////////////////////////////////// + +static int EnumDbModules(const char *szModuleName, void*) +{ + ptrA szProtoName(db_get_sa(0, szModuleName, "AM_BaseProto")); + if (szProtoName) { + if (!Proto_GetAccount(szModuleName)) { + PROTOACCOUNT *pa = new PROTOACCOUNT(szModuleName); + pa->szProtoName = szProtoName.detach(); + pa->tszAccountName = mir_a2u(szModuleName); + pa->bIsVisible = true; + pa->bIsEnabled = false; + pa->iOrder = accounts.getCount(); + accounts.insert(pa); + } + } + return 0; +} + +void LoadDbAccounts(void) +{ + int ver = db_get_dw(0, "Protocols", "PrVer", -1); + int count = db_get_dw(0, "Protocols", "ProtoCount", 0); + + for (int i = 0; i < count; i++) { + char buf[10]; + _itoa(i, buf, 10); + ptrA szModuleName(db_get_sa(0, "Protocols", buf)); + if (szModuleName == nullptr) + continue; + + PROTOACCOUNT *pa = Proto_GetAccount(szModuleName); + if (pa == nullptr) { + pa = new PROTOACCOUNT(szModuleName); + accounts.insert(pa); + } + + _itoa(OFFSET_VISIBLE + i, buf, 10); + pa->bIsVisible = db_get_dw(0, "Protocols", buf, 1) != 0; + + _itoa(OFFSET_PROTOPOS + i, buf, 10); + pa->iOrder = db_get_dw(0, "Protocols", buf, 1); + + if (ver >= 4) { + _itoa(OFFSET_NAME + i, buf, 10); + pa->tszAccountName = db_get_wsa(0, "Protocols", buf); + + _itoa(OFFSET_ENABLED + i, buf, 10); + pa->bIsEnabled = db_get_dw(0, "Protocols", buf, 1) != 0; + if (!pa->bIsEnabled && !mir_strcmp(pa->szModuleName, META_PROTO)) { + pa->bIsEnabled = true; + db_set_dw(0, "Protocols", buf, 1); + } + pa->szProtoName = db_get_sa(0, szModuleName, "AM_BaseProto"); + } + else pa->bIsEnabled = true; + + if (!pa->szProtoName) { + pa->szProtoName = mir_strdup(szModuleName); + db_set_s(0, szModuleName, "AM_BaseProto", pa->szProtoName); + } + + if (!pa->tszAccountName) + pa->tszAccountName = mir_a2u(szModuleName); + } + + if (CheckProtocolOrder()) + WriteDbAccounts(); + + int anum = accounts.getCount(); + db_enum_modules(EnumDbModules); + if (anum != accounts.getCount()) + WriteDbAccounts(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct enumDB_ProtoProcParam +{ + int arrlen; + char **pszSettingName; +}; + +static int enumDB_ProtoProc(const char* szSetting, void *lParam) +{ + if (szSetting) { + enumDB_ProtoProcParam* p = (enumDB_ProtoProcParam*)lParam; + + p->arrlen++; + p->pszSettingName = (char**)mir_realloc(p->pszSettingName, p->arrlen*sizeof(char*)); + p->pszSettingName[p->arrlen - 1] = mir_strdup(szSetting); + } + return 0; +} + +void WriteDbAccounts() +{ + // enum all old settings to delete + enumDB_ProtoProcParam param = { 0, nullptr }; + db_enum_settings(0, enumDB_ProtoProc, "Protocols", ¶m); + + // delete all settings + if (param.arrlen) { + for (int i = 0; i < param.arrlen; i++) { + db_unset(0, "Protocols", param.pszSettingName[i]); + mir_free(param.pszSettingName[i]); + } + mir_free(param.pszSettingName); + } + + // write new data + for (int i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + + char buf[20]; + _itoa(i, buf, 10); + db_set_s(0, "Protocols", buf, pa->szModuleName); + + _itoa(OFFSET_PROTOPOS + i, buf, 10); + db_set_dw(0, "Protocols", buf, pa->iOrder); + + _itoa(OFFSET_VISIBLE + i, buf, 10); + db_set_dw(0, "Protocols", buf, pa->bIsVisible); + + _itoa(OFFSET_ENABLED + i, buf, 10); + db_set_dw(0, "Protocols", buf, pa->bIsEnabled); + + _itoa(OFFSET_NAME + i, buf, 10); + db_set_ws(0, "Protocols", buf, pa->tszAccountName); + } + + db_unset(0, "Protocols", "ProtoCount"); + db_set_dw(0, "Protocols", "ProtoCount", accounts.getCount()); + db_set_dw(0, "Protocols", "PrVer", 4); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int OnContactDeleted(WPARAM hContact, LPARAM) +{ + if (hContact) { + PROTOACCOUNT *pa = Proto_GetAccount(hContact); + if (pa->IsEnabled() && pa->ppro) + pa->ppro->OnContactDeleted(hContact); + } + return 0; +} + +static int InitializeStaticAccounts(WPARAM, LPARAM) +{ + int count = 0; + + for (auto &pa : accounts) { + if (!pa->ppro || !pa->IsEnabled()) + continue; + + pa->ppro->OnModulesLoaded(); + + if (!pa->bOldProto) + count++; + } + + BuildProtoMenus(); + + if (count == 0 && !db_get_b(0, "FirstRun", "AccManager", 0)) { + db_set_b(0, "FirstRun", "AccManager", 1); + CallService(MS_PROTO_SHOWACCMGR, 0, 0); + } + // This is for pack creators with a profile with predefined accounts + else if (db_get_b(0, "FirstRun", "ForceShowAccManager", 0)) { + CallService(MS_PROTO_SHOWACCMGR, 0, 0); + db_unset(0, "FirstRun", "ForceShowAccManager"); + } + return 0; +} + +static int UninitializeStaticAccounts(WPARAM, LPARAM) +{ + // request permission to exit first + for (auto &pa : accounts) + if (pa->ppro && pa->IsEnabled()) + if (!pa->ppro->IsReadyToExit()) + return 1; + + // okay, all protocols are ready, exiting + for (auto &pa : accounts) + if (pa->ppro && pa->IsEnabled()) + pa->ppro->OnShutdown(); + + return 0; +} + +int LoadAccountsModule(void) +{ + bModuleInitialized = true; + + for (auto &pa : accounts) { + pa->bDynDisabled = !Proto_IsProtocolLoaded(pa->szProtoName); + if (pa->ppro) + continue; + + if (!pa->IsEnabled()) + continue; + + if (!ActivateAccount(pa, false)) + pa->bDynDisabled = true; + } + + hHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, InitializeStaticAccounts); + hHooks[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, UninitializeStaticAccounts); + hHooks[2] = HookEvent(ME_DB_CONTACT_DELETED, OnContactDeleted); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static HANDLE CreateProtoServiceEx(const char* szModule, const char* szService, MIRANDASERVICEOBJ pFunc, void* param) +{ + char tmp[100]; + mir_snprintf(tmp, "%s%s", szModule, szService); + return CreateServiceFunctionObj(tmp, pFunc, param); +} + +bool ActivateAccount(PROTOACCOUNT *pa, bool bIsDynamic) +{ + MBaseProto *ppd = Proto_GetProto(pa->szProtoName); + if (ppd == nullptr) + return false; + + if (ppd->fnInit == nullptr) + return false; + + PROTO_INTERFACE *ppi = ppd->fnInit(pa->szModuleName, pa->tszAccountName); + if (ppi == nullptr) + return false; + + pa->ppro = ppi; + if (ppi->m_hProtoIcon == nullptr) + ppi->m_hProtoIcon = IcoLib_IsManaged(Skin_LoadProtoIcon(pa->szModuleName, ID_STATUS_ONLINE)); + ppi->m_iDesiredStatus = ppi->m_iStatus = ID_STATUS_OFFLINE; + + if (bIsDynamic) { + if (g_bModulesLoadedFired) + pa->ppro->OnModulesLoaded(); + if (!db_get_b(0, "CList", "MoveProtoMenus", true)) + pa->ppro->OnBuildProtoMenu(); + pa->bDynDisabled = false; + } + return true; +} + +MIR_APP_DLL(int) Proto_GetAverageStatus(int *pAccountNumber) +{ + int netProtoCount = 0, averageMode = 0; + + for (auto &pa : accounts) { + if (!pa->IsVisible() || pa->IsLocked()) + continue; + + netProtoCount++; + if (averageMode == 0) + averageMode = pa->iRealStatus; + else if (averageMode > 0 && averageMode != pa->iRealStatus) { + averageMode = -1; + if (pAccountNumber == nullptr) + break; + } + } + + if (pAccountNumber) + *pAccountNumber = netProtoCount; + return averageMode; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct DeactivationThreadParam +{ + PROTO_INTERFACE *ppro; + pfnUninitProto fnUninit; + int flags; +}; + +pfnUninitProto GetProtocolDestructor(char *szProto); + +static void __cdecl DeactivationThread(DeactivationThreadParam *param) +{ + PROTO_INTERFACE *p = (PROTO_INTERFACE*)param->ppro; + p->SetStatus(ID_STATUS_OFFLINE); + + char *szModuleName = NEWSTR_ALLOCA(p->m_szModuleName); + + if (param->flags & DAF_DYNAMIC) { + while (!p->IsReadyToExit()) + SleepEx(100, TRUE); + + p->OnShutdown(); + } + + KillObjectThreads(p); // waits for them before terminating + KillObjectEventHooks(p); // untie an object from the outside world + + if (param->flags & DAF_ERASE) + p->OnErase(); + + if (param->fnUninit) + param->fnUninit(p); + + KillObjectServices(p); + + if (param->flags & DAF_ERASE) + EraseAccount(szModuleName); + + delete param; +} + +void DeactivateAccount(PROTOACCOUNT *pa, int flags) +{ + if (pa->hwndAccMgrUI) { + DestroyWindow(pa->hwndAccMgrUI); + pa->hwndAccMgrUI = nullptr; + pa->bAccMgrUIChanged = FALSE; + } + + if (flags & DAF_DYNAMIC) + NotifyEventHooks(hAccListChanged, PRAC_REMOVED, (LPARAM)pa); + else + pa->iIconBase = -1; + + if (pa->ppro == nullptr) { + if (flags & DAF_ERASE) + EraseAccount(pa->szModuleName); + return; + } + + DeactivationThreadParam *param = new DeactivationThreadParam; + param->ppro = pa->ppro; + param->fnUninit = GetProtocolDestructor(pa->szProtoName); + param->flags = flags; + pa->ppro = nullptr; + if (flags & DAF_FORK) + mir_forkThread(DeactivationThread, param); + else + DeactivationThread(param); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void KillModuleAccounts(HINSTANCE hInst) +{ + for (auto &pd : g_arProtos.rev_iter()) { + if (pd->hInst != hInst) + continue; + + for (auto &pa : accounts.rev_iter()) { + if (!mir_strcmp(pa->szProtoName, pd->szName)) { + pa->bDynDisabled = true; + DeactivateAccount(pa, DAF_DYNAMIC); + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void EraseAccount(const char *pszModuleName) +{ + // remove protocol contacts first + for (MCONTACT hContact = db_find_first(pszModuleName); hContact != 0;) { + MCONTACT hNext = db_find_next(hContact, pszModuleName); + db_delete_contact(hContact); + hContact = hNext; + } + + // remove all protocol settings + db_delete_module(0, pszModuleName); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void UnloadAccount(PROTOACCOUNT *pa, int flags) +{ + DeactivateAccount(pa, flags); + + // szModuleName should be freed only on a program's exit. + // otherwise many plugins dependand on static protocol names will crash! + // do NOT fix this 'leak', please + if (!(flags & DAF_DYNAMIC)) + delete pa; + else { + replaceStrW(pa->tszAccountName, 0); + replaceStr(pa->szProtoName, 0); + replaceStr(pa->szUniqueId, 0); + } +} + +void UnloadAccountsModule() +{ + if (!bModuleInitialized) + return; + + auto T = accounts.rev_iter(); + for (auto &it : T) { + UnloadAccount(it, 0); + accounts.remove(T.indexOf(&it)); + } + accounts.destroy(); + + for (auto &it : hHooks) + UnhookEvent(it); +} -- cgit v1.2.3