/* Plugin of Miranda IM for communicating with users of the AIM protocol. Copyright (c) 2008-2009 Boris Krasnovskiy Copyright (C) 2005-2006 Aaron Myles Landwehr 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, see . */ #include "aim.h" #include #include "m_extraicons.h" #include "theme.h" ///////////////////////////////////////////////////////////////////////////////////////// // Icons init struct _tag_iconList { const char* szDescr; const char* szName; int defIconID; const char* szSection; } static const iconList[] = { { LPGEN("ICQ"), "icq", IDI_ICQ }, { LPGEN("Add"), "add", IDI_ADD }, { LPGEN("Block"), "block", IDI_BLOCK }, { LPGEN("Profile"), "profile", IDI_PROFILE }, { LPGEN("AOL Mail"), "mail", IDI_MAIL }, { LPGEN("AIM Icon"), "aim", IDI_AIM }, { LPGEN("Hiptop"), "hiptop", IDI_HIPTOP }, { LPGEN("AOL Bot"), "bot", IDI_BOT }, { LPGEN("Admin"), "admin", IDI_ADMIN }, { LPGEN("Confirmed"), "confirm", IDI_CONFIRMED }, { LPGEN("Not Confirmed"), "uconfirm", IDI_UNCONFIRMED }, { LPGEN("Blocked list"), "away", IDI_AWAY }, { LPGEN("Idle"), "idle", IDI_IDLE }, { LPGEN("AOL"), "aol", IDI_AOL }, { LPGEN("Foreground Color"), "foreclr", IDI_FOREGROUNDCOLOR, LPGEN("Profile Editor") }, { LPGEN("Background Color"), "backclr", IDI_BACKGROUNDCOLOR, LPGEN("Profile Editor") }, { LPGEN("Bold"), "bold", IDI_BOLD, LPGEN("Profile Editor") }, { LPGEN("Not Bold"), "nbold", IDI_NBOLD, LPGEN("Profile Editor") }, { LPGEN("Italic"), "italic", IDI_ITALIC, LPGEN("Profile Editor") }, { LPGEN("Not Italic"), "nitalic", IDI_NITALIC, LPGEN("Profile Editor") }, { LPGEN("Underline"), "undrln", IDI_UNDERLINE, LPGEN("Profile Editor") }, { LPGEN("Not Underline"), "nundrln", IDI_NUNDERLINE, LPGEN("Profile Editor") }, { LPGEN("Subscript"), "sub_scrpt", IDI_SUBSCRIPT, LPGEN("Profile Editor") }, { LPGEN("Not Subscript"), "nsub_scrpt", IDI_NSUBSCRIPT, LPGEN("Profile Editor") }, { LPGEN("Superscript"), "sup_scrpt", IDI_SUPERSCRIPT, LPGEN("Profile Editor") }, { LPGEN("Not Superscript"), "nsup_scrpt", IDI_NSUPERSCRIPT, LPGEN("Profile Editor") }, { LPGEN("Normal Script"), "norm_scrpt", IDI_NORMALSCRIPT, LPGEN("Profile Editor") }, { LPGEN("Not Normal Script"), "nnorm_scrpt", IDI_NNORMALSCRIPT, LPGEN("Profile Editor") }, }; static HANDLE hIconLibItem[SIZEOF(iconList)]; void InitIcons(void) { TCHAR szFile[MAX_PATH]; GetModuleFileName(hInstance, szFile, SIZEOF(szFile)); char szSettingName[100]; char szSectionName[100]; SKINICONDESC sid = {0}; sid.cbSize = sizeof(SKINICONDESC); sid.ptszDefaultFile = szFile; sid.pszName = szSettingName; sid.pszSection = szSectionName; sid.flags = SIDF_PATH_TCHAR; for (int i = 0; i < SIZEOF(iconList); i++) { mir_snprintf(szSettingName, sizeof(szSettingName), "AIM_%s", iconList[i].szName); if (iconList[i].szSection) mir_snprintf(szSectionName, sizeof(szSectionName), "%s/%s/%s", LPGEN("Protocols"), LPGEN("AIM"), iconList[i].szSection); else mir_snprintf(szSectionName, sizeof(szSectionName), "%s/%s", LPGEN("Protocols"), LPGEN("AIM")); sid.pszDescription = (char*)iconList[i].szDescr; sid.iDefaultIndex = -iconList[i].defIconID; hIconLibItem[i] = Skin_AddIcon(&sid); } } HICON LoadIconEx(const char* name, bool big) { char szSettingName[100]; mir_snprintf(szSettingName, sizeof(szSettingName), "AIM_%s", name); return (HICON)CallService(MS_SKIN2_GETICON, big, (LPARAM)szSettingName); } HANDLE GetIconHandle(const char* name) { for (unsigned i=0; i < SIZEOF(iconList); i++) if (strcmp(iconList[i].szName, name) == 0) return hIconLibItem[i]; return NULL; } void ReleaseIconEx(const char* name, bool big) { char szSettingName[100]; mir_snprintf(szSettingName, sizeof(szSettingName ), "%s_%s", "AIM", name); CallService(big ? MS_SKIN2_RELEASEICONBIG : MS_SKIN2_RELEASEICON, 0, (LPARAM)szSettingName); } void WindowSetIcon(HWND hWnd, const char* name) { SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadIconEx( name, true )); SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadIconEx( name )); } void WindowFreeIcon(HWND hWnd) { CallService(MS_SKIN2_RELEASEICON, SendMessage(hWnd, WM_SETICON, ICON_BIG, 0), 0); CallService(MS_SKIN2_RELEASEICON, SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0), 0); } ///////////////////////////////////////////////////////////////////////////////////////// // Extra Icons extern OBJLIST g_Instances; static HANDLE bot_icon, icq_icon, aol_icon, hiptop_icon; static HANDLE admin_icon, confirmed_icon, unconfirmed_icon; static HANDLE hListRebuld, hIconApply; static HANDLE hExtraAT, hExtraES; static const char* extra_AT_icon_name[5] = { "uconfirm", "confirm", "icq", "aol", "admin", }; static const char* extra_ES_icon_name[2] = { "bot", "hiptop", }; static HANDLE extra_AT_icon_handle[5]; static HANDLE extra_ES_icon_handle[2]; static void load_extra_icons(void) { if (!ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) return; unsigned i; for (i = 0; i < SIZEOF(extra_AT_icon_handle); ++i) { extra_AT_icon_handle[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)LoadIconEx(extra_AT_icon_name[i]), 0); ReleaseIconEx(extra_AT_icon_name[i]); } for (i = 0; i < SIZEOF(extra_ES_icon_handle); ++i) { extra_ES_icon_handle[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)LoadIconEx(extra_ES_icon_name[i]), 0); ReleaseIconEx(extra_ES_icon_name[i]); } } static void set_extra_icon(HANDLE hContact, HANDLE hImage, int column_type) { IconExtraColumn iec; iec.cbSize = sizeof(iec); iec.hImage = hImage; iec.ColumnType = column_type; CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); } static void clear_AT_icon(HANDLE hContact) { if (hExtraAT) ExtraIcon_SetIcon(hExtraAT, hContact, (char*)NULL); else set_extra_icon(hContact, (HANDLE)-1, EXTRA_ICON_ADV2); } static void clear_ES_icon(HANDLE hContact) { if (hExtraES) ExtraIcon_SetIcon(hExtraES, hContact, (char*)NULL); else set_extra_icon(hContact, (HANDLE)-1, EXTRA_ICON_ADV3); } static void set_AT_icon(CAimProto* ppro, HANDLE hContact) { if (ppro->getByte(hContact, "ChatRoom", 0)) return; unsigned i = ppro->getByte(hContact, AIM_KEY_AC, 0) - 1; if (hExtraAT) { if (i < 5) { char name[64]; mir_snprintf(name, sizeof(name), "AIM_%s", extra_AT_icon_name[i]); ExtraIcon_SetIcon(hExtraAT, hContact, name); } else ExtraIcon_SetIcon(hExtraAT, hContact, (char*)NULL); } else set_extra_icon(hContact, i < 5 ? extra_AT_icon_handle[i] : (HANDLE)-1, EXTRA_ICON_ADV2); } static void set_ES_icon(CAimProto* ppro, HANDLE hContact) { if (ppro->getByte(hContact, "ChatRoom", 0)) return; unsigned i = ppro->getByte(hContact, AIM_KEY_ET, 0) - 1; if (hExtraES) { if (i < 2) { char name[64]; mir_snprintf(name, sizeof(name), "AIM_%s", extra_ES_icon_name[i]); ExtraIcon_SetIcon(hExtraES, hContact, name); } else ExtraIcon_SetIcon(hExtraES, hContact, (char*)NULL); } else set_extra_icon(hContact, i < 2 ? extra_ES_icon_handle[i] : (HANDLE)-1, EXTRA_ICON_ADV3); } void set_contact_icon(CAimProto* ppro, HANDLE hContact) { if (!ppro->getByte(AIM_KEY_AT, 0)) set_AT_icon(ppro, hContact); if (!ppro->getByte(AIM_KEY_ES, 0)) set_ES_icon(ppro, hContact); } static int OnExtraIconsRebuild(WPARAM /*wParam*/, LPARAM /*lParam*/) { load_extra_icons(); return 0; } static int OnExtraIconsApply(WPARAM wParam, LPARAM /*lParam*/) { if (!ServiceExists(MS_CLIST_EXTRA_SET_ICON)) return 0; HANDLE hContact = (HANDLE)wParam; CAimProto *ppro = NULL; for (int i = 0; i < g_Instances.getCount(); ++i) { if (g_Instances[i].is_my_contact(hContact)) { ppro = &g_Instances[i]; break; } } if (ppro) set_contact_icon(ppro, hContact); return 0; } void remove_AT_icons(CAimProto* ppro) { if (!ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) return; HANDLE hContact = db_find_first(); while (hContact) { if (ppro->is_my_contact(hContact) && !ppro->getByte(hContact, "ChatRoom", 0)) clear_AT_icon(hContact); hContact = db_find_next(hContact); } } void remove_ES_icons(CAimProto* ppro) { if (!ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) return; HANDLE hContact = db_find_first(); while (hContact) { if (ppro->is_my_contact(hContact) && !ppro->getByte(hContact, "ChatRoom", 0)) clear_ES_icon(hContact); hContact = db_find_next(hContact); } } void add_AT_icons(CAimProto* ppro) { HANDLE hContact = db_find_first(); while (hContact) { if (ppro->is_my_contact(hContact)) set_AT_icon(ppro, hContact); hContact = db_find_next(hContact); } } void add_ES_icons(CAimProto* ppro) { HANDLE hContact = db_find_first(); while (hContact) { if (ppro->is_my_contact(hContact)) set_ES_icon(ppro, hContact); hContact = db_find_next(hContact); } } void InitExtraIcons(void) { hExtraAT = ExtraIcon_Register("aimaccounttype", LPGEN("AIM Account Type"), "AIM_aol"); hExtraES = ExtraIcon_Register("aimextstatus", LPGEN("AIM Extended Status"), "AIM_hiptop"); if (hExtraAT == NULL) { hListRebuld = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, OnExtraIconsRebuild); hIconApply = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnExtraIconsApply); } } void DestroyExtraIcons(void) { UnhookEvent(hIconApply); UnhookEvent(hListRebuld); } ///////////////////////////////////////////////////////////////////////////////////////// // Themes #define MGPROC(x) GetProcAddress(themeAPIHandle,x) HMODULE themeAPIHandle = NULL; // handle to uxtheme.dll HANDLE (WINAPI *MyOpenThemeData)(HWND,LPCWSTR) = 0; HRESULT (WINAPI *MyCloseThemeData)(HANDLE) = 0; HRESULT (WINAPI *MyDrawThemeBackground)(HANDLE,HDC,int,int,const RECT *,const RECT *) = 0; void InitThemeSupport(void) { if (!IsWinVerXPPlus()) return; themeAPIHandle = GetModuleHandleA("uxtheme"); if (themeAPIHandle) { MyOpenThemeData = (HANDLE (WINAPI *)(HWND,LPCWSTR))MGPROC("OpenThemeData"); MyCloseThemeData = (HRESULT (WINAPI *)(HANDLE))MGPROC("CloseThemeData"); MyDrawThemeBackground = (HRESULT (WINAPI *)(HANDLE,HDC,int,int,const RECT *,const RECT *))MGPROC("DrawThemeBackground"); } } void DestroyThemeSupport(void) { DestroyExtraIcons(); } ///////////////////////////////////////////////////////////////////////////////////////// // OnPreBuildContactMenu int CAimProto::OnPreBuildContactMenu(WPARAM wParam,LPARAM /*lParam*/) { HANDLE hContact = (HANDLE)wParam; bool isChatRoom = getByte(hContact, "ChatRoom", 0) != 0; CLISTMENUITEM mi; ZeroMemory(&mi,sizeof(mi)); mi.cbSize = sizeof(mi); //see if we should add the html away message context menu items mi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; if (getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) != ID_STATUS_AWAY || isChatRoom) mi.flags |= CMIF_HIDDEN; CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hHTMLAwayContextMenuItem,(LPARAM)&mi); mi.flags = CMIM_FLAGS | CMIF_NOTONLINE; if (getBuddyId(hContact, 1) || state == 0 || isChatRoom) mi.flags |= CMIF_HIDDEN; CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hAddToServerListContextMenuItem,(LPARAM)&mi); DBVARIANT dbv; if (!getString(hContact, AIM_KEY_SN, &dbv)) { mi.flags = CMIM_NAME | CMIM_FLAGS; switch(pd_mode) { case 1: mi.pszName = LPGEN("&Block"); break; case 2: mi.pszName = LPGEN("&Unblock"); break; case 3: mi.pszName = (char*)(allow_list.find_id(dbv.pszVal) ? LPGEN("&Block") : LPGEN("&Unblock")); break; case 4: mi.pszName = (char*)(block_list.find_id(dbv.pszVal) ? LPGEN("&Unblock") : LPGEN("&Block")); break; default: mi.pszName = LPGEN("&Block"); mi.flags |= CMIF_HIDDEN; break; } CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hBlockContextMenuItem, (LPARAM)&mi); DBFreeVariant(&dbv); } return 0; } void CAimProto::InitMainMenus(void) { //Do not put any services below HTML get away message!!! char service_name[200]; CLISTMENUITEM mi = {0}; mi.cbSize = sizeof(mi); HGENMENU hRoot = MO_GetProtoRootMenu(m_szModuleName); if (hRoot == NULL) { mi.flags = CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; mi.icolibItem = GetIconHandle("aim"); mi.ptszName = m_tszUserName; mi.hParentMenu = HGENMENU_ROOT; mi.popupPosition = 500090000; mi.position = 500090000; hRoot = hMenuRoot = Menu_AddProtoMenuItem(&mi); } else { RemoveMainMenus(); hMenuRoot = NULL; } mi.pszService = service_name; mi.hParentMenu = hRoot; mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/ManageAccount"); CreateProtoService("/ManageAccount", &CAimProto::ManageAccount); mi.position = 201001; mi.icolibItem = GetIconHandle("aim"); mi.pszName = LPGEN("Manage Account"); hMainMenu[0] = Menu_AddProtoMenuItem(&mi); mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/InstantIdle"); CreateProtoService("/InstantIdle",&CAimProto::InstantIdle); mi.position = 201002; mi.icolibItem = GetIconHandle("idle"); mi.pszName = LPGEN("Instant Idle"); hMainMenu[1] = Menu_AddProtoMenuItem(&mi); mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/JoinChatRoom"); CreateProtoService("/JoinChatRoom", &CAimProto::JoinChatUI); mi.position = 201003; mi.icolibItem = GetIconHandle("aol"); mi.pszName = LPGEN( "Join Chat Room" ); hMainMenu[2] = Menu_AddProtoMenuItem(&mi); } void CAimProto::InitContactMenus(void) { //Do not put any services below HTML get away message!!! char service_name[200]; CLISTMENUITEM mi = {0}; mi.cbSize = sizeof(mi); mi.pszService = service_name; mi.pszContactOwner = m_szModuleName; mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/GetHTMLAwayMsg"); CreateProtoService("/GetHTMLAwayMsg",&CAimProto::GetHTMLAwayMsg); mi.position = -2000006000; mi.icolibItem = GetIconHandle("away"); mi.pszName = LPGEN("Read &HTML Away Message"); mi.flags = CMIF_NOTOFFLINE | CMIF_HIDDEN | CMIF_ICONFROMICOLIB; hHTMLAwayContextMenuItem = Menu_AddContactMenuItem(&mi); mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/GetProfile"); CreateProtoService("/GetProfile", &CAimProto::GetProfile); mi.position = -2000005090; mi.icolibItem = GetIconHandle("profile"); mi.pszName = LPGEN("Read Profile"); mi.flags = CMIF_NOTOFFLINE | CMIF_ICONFROMICOLIB; hReadProfileMenuItem = Menu_AddContactMenuItem(&mi); mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/AddToServerList"); CreateProtoService("/AddToServerList", &CAimProto::AddToServerList); mi.position = -2000005080; mi.icolibItem = GetIconHandle("add"); mi.pszName = LPGEN("Add To Server List"); mi.flags = CMIF_NOTONLINE | CMIF_HIDDEN | CMIF_ICONFROMICOLIB; hAddToServerListContextMenuItem = Menu_AddContactMenuItem(&mi); mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/BlockCommand"); CreateProtoService("/BlockCommand", &CAimProto::BlockBuddy); mi.position = -2000005060; mi.icolibItem = GetIconHandle("block"); mi.pszName = LPGEN("&Block"); mi.flags = CMIF_ICONFROMICOLIB | CMIF_HIDDEN; hBlockContextMenuItem = Menu_AddContactMenuItem(&mi); } void CAimProto::RemoveMainMenus(void) { if (hMenuRoot) CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)hMenuRoot, 0); } void CAimProto::RemoveContactMenus(void) { CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hHTMLAwayContextMenuItem, 0); CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hReadProfileMenuItem, 0); CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hAddToServerListContextMenuItem, 0); CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hBlockContextMenuItem, 0); }