From e736ab21213b66669dde5d9a9003596706eee8bd Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 17 Jul 2012 08:44:50 +0000 Subject: CSList, CyrTranslit: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1002 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/CSList/src/Version.h | 22 + plugins/CSList/src/cslist.cpp | 1349 +++++++++++++++++++++++++++++++++++++++++ plugins/CSList/src/cslist.h | 665 ++++++++++++++++++++ plugins/CSList/src/legacy.h | 87 +++ plugins/CSList/src/resource.h | 49 ++ plugins/CSList/src/strpos.h | 70 +++ 6 files changed, 2242 insertions(+) create mode 100644 plugins/CSList/src/Version.h create mode 100644 plugins/CSList/src/cslist.cpp create mode 100644 plugins/CSList/src/cslist.h create mode 100644 plugins/CSList/src/legacy.h create mode 100644 plugins/CSList/src/resource.h create mode 100644 plugins/CSList/src/strpos.h (limited to 'plugins/CSList/src') diff --git a/plugins/CSList/src/Version.h b/plugins/CSList/src/Version.h new file mode 100644 index 0000000000..8206c5c61f --- /dev/null +++ b/plugins/CSList/src/Version.h @@ -0,0 +1,22 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 1 +#define __RELEASE_NUM 0 +#define __BUILD_NUM 5 + +#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM +#define __FILEVERSION_DOTS __MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM + +#define __STRINGIFY_IMPL(x) #x +#define __STRINGIFY(x) __STRINGIFY_IMPL(x) +#define __VERSION_STRING __STRINGIFY(__FILEVERSION_DOTS) + + + +#define __PLUGIN_NAME "Custom Status List mod" +#define __INTERNAL_NAME "CSList" +#define __FILENAME "CSList.dll" +#define __DESCRIPTION "This plugin offers simple management functions to keep your extra statuses on one place." +#define __AUTHOR "Mataes, jarvis" +#define __AUTHOREMAIL "mataes2007@gmail.com" +#define __AUTHORWEB "http://mataes.googlecode.com/svn/Miranda/Plugins/Cslist/" +#define __COPYRIGHT "© 2011-10 Mataes, 2009-2007 jarvis" diff --git a/plugins/CSList/src/cslist.cpp b/plugins/CSList/src/cslist.cpp new file mode 100644 index 0000000000..b8078ae1be --- /dev/null +++ b/plugins/CSList/src/cslist.cpp @@ -0,0 +1,1349 @@ +/* ======================================================================== + + Custom Status List + __________________ + + Custom Status List plugin for Miranda-IM (www.miranda-im.org) + Follower of Custom Status History List by HANAX + Copyright © 2006-2008 HANAX + Copyright © 2007-2009 jarvis + + 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 : $URL$ + Revision : $Rev$ + Last change on : $Date$ + Last change by : $Author$ + + ============================================================================ + + + DESCRIPTION: + + Offers List of your Custom Statuses. + +// ======================================================================== */ + +#include "cslist.h" +#include "strpos.h" +#include "legacy.h" + +SortedList *servicesList; +int hLangpack; + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { PLUGIN_GUUID, MIID_LAST }; + +PLUGININFOEX pluginInfoEx = +{ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + PLUGIN_GUUID +}; + +// ====[ MAIN ]=============================================================== + +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +{ + CSList::handle = hinstDLL; + return TRUE; +} + + +// ====[ PLUGIN INFO ]======================================================== + +extern "C" __declspec( dllexport ) PLUGININFOEX* MirandaPluginInfoEx( DWORD mirandaVersion ) +{ + CSList::dwMirandaVersion = mirandaVersion; + return &pluginInfoEx; +} + +// ====[ LOADER ]============================================================= + +extern "C" __declspec( dllexport ) int Load( ) +{ + mir_getLP(&pluginInfoEx); + servicesList = List_Create(0, 10); + + // support for ComboBoxEx + { + INITCOMMONCONTROLSEX icc; + icc.dwSize = sizeof(icc); + icc.dwICC = ICC_USEREX_CLASSES; + InitCommonControlsEx( &icc ); + } + + // set global variables + // we need 0.8.0.9 core which introduced accounts support for protocols + CSList::bAccountsSupported = ( CSList::dwMirandaVersion >= PLUGIN_MAKE_VERSION( 0, 8, 0, 9 )); + + // are we running under Unicode core? + { + char szVer[MAX_PATH]; + + CallService( MS_SYSTEM_GETVERSIONTEXT, MAX_PATH, ( LPARAM )szVer ); + _strlwr( szVer ); // make sure it is lowercase + + CSList::bUnicodeCore = ( strstr( szVer, "unicode" ) != NULL ); + } + + // TODO: Alerts with wrong combination of ANSI/Unicode Windows/core/plugin + + // create handler + cslist = new CSList( ); + + return FALSE; +} + + +// ====[ UNLOADER ]=========================================================== + +extern "C" __declspec( dllexport ) int Unload( void ) +{ + for (int i = servicesList->realCount-1; i >= 0; i--) + { + HANDLE *hService = (HANDLE *)servicesList->items[i]; + DestroyServiceFunction(hService); + } + List_Destroy(servicesList); + mir_free(servicesList); + delete cslist; + + return FALSE; +} + + +// ====[ FUN ]================================================================ + + +CSList::CSList( ) +{ + this->mainWindow = NULL; + this->initIcoLib( ); + this->hHookOnOptionsInit = HookEvent( ME_OPT_INITIALISE, this->initOptions ); + //this->hHookOnPluginsLoaded = HookEvent( ME_SYSTEM_MODULESLOADED, this->postLoading ); + this->hHookOnDBSettingChanged = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, this->respondDBChange ); + this->hHookOnStatusMenuBuild = HookEvent( ME_CLIST_PREBUILDSTATUSMENU, this->createMenuItems ); +} + + +CSList::~CSList( ) +{ + // unhook events, destroy functions + UnhookEvent( this->hHookOnStatusMenuBuild ); + UnhookEvent( this->hHookOnPluginsLoaded ); + UnhookEvent( this->hHookOnOptionsInit ); + UnhookEvent( this->hHookOnDBSettingChanged ); + DestroyServiceFunction( this->hServiceShowList ); + + // clear IcoLib + for ( int i = 0; i < SIZEOF(forms); i++ ) + { + char iconName[64]; + mir_snprintf(iconName, SIZEOF(iconName), "%s_%s", __INTERNAL_NAME, forms[i].pszIconIcoLib); + CallService( MS_SKIN2_REMOVEICON, 0, ( LPARAM )iconName ); + } +} + + +int CSList::postLoading( WPARAM wparam, LPARAM lparam ) +{ + //cslist->registerHotkeys( ); + cslist->initIcoLib( ); // for < 0.7, but probably useless though :/ + return FALSE; +} + + +void CSList::registerHotkeys(char buf[200], TCHAR* accName, int Number) +{ + HOTKEYDESC hotkey = { 0 }; + hotkey.cbSize = sizeof(hotkey); + hotkey.dwFlags = HKD_TCHAR; + hotkey.pszName = buf; + hotkey.ptszDescription = accName; + hotkey.ptszSection = LPGENT("Custom Status List"); + hotkey.pszService = buf; + hotkey.DefHotKey = HOTKEYCODE( HOTKEYF_CONTROL | HOTKEYF_SHIFT, '0'+Number ); + Hotkey_Register(&hotkey); +} + +int CSList::initOptions( WPARAM wparam, LPARAM lparam ) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.position = 955000000; + odp.hInstance = CSList::handle; + odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPTIONS ); + odp.pszTitle = MODULENAME; + odp.pfnDlgProc = CSOptionsProc; + odp.pszGroup = LPGEN("Status"); + odp.flags = ODPF_BOLDGROUPS; + Options_AddPage(wparam, &odp); + return FALSE; +} + + +int CSList::respondDBChange( WPARAM wparam, LPARAM lparam ) +{ + HANDLE hContact = ( HANDLE )wparam; + DBCONTACTWRITESETTING *cws = ( DBCONTACTWRITESETTING* )lparam; + + // if user changes his UIN or JID on any account + if (hContact == NULL && (!lstrcmpA(cws->szSetting, "UIN") || !lstrcmpA(cws->szSetting, "jid"))) + { + cslist->rebuildMenuItems(); + return 0; + } + + // own setting or not a status-related setting + else if ( hContact == NULL || lstrcmpA( cws->szSetting, "Status" )) + return 0; + + DWORD dwEasteredUin = getDword( "EasterEggedUIN", 0x0 ); + if ( dwEasteredUin == 0x0 ) // no spyed UIN found + return 0; + + DBVARIANT dbv = { 0 }; + DBGetContactSettingString( hContact, "Protocol", "p", &dbv ); + + DWORD dwUin = DBGetContactSettingDword( hContact, dbv.pszVal, "UIN", 0x0 ); + + if ( dwUin != 0x0 ) // if this is an ICQ user + if ( dwUin == dwEasteredUin ) // if spyed UIN is equivalent to this contact + if ( DBGetContactSettingWord( hContact, "UserOnline", "OldStatus", 0 ) == ID_STATUS_OFFLINE ) + if ( cws->value.wVal > ID_STATUS_OFFLINE ) + cslist->setStatus( IDC_CANCEL, NULL, ""); + + return FALSE; +} + + +int CSList::createMenuItems( WPARAM wparam, LPARAM lparam ) +{ + int ProtoCount = 0; + + ForAllProtocols(countProtos, &ProtoCount); + + if (ProtoCount == 0) + return FALSE; + + ForAllProtocols(addProtoStatusMenuItem, 0); + + return FALSE; +} + + +void CSList::rebuildMenuItems( ) +{ + CLIST_INTERFACE* pcli; + pcli = ( CLIST_INTERFACE* )CallService( MS_CLIST_RETRIEVE_INTERFACE, 0, 0 ); + if ( pcli && pcli->version > 4 ) + pcli->pfnReloadProtoMenus( ); +} + + +void CSList::setStatus( WORD code, StatusItem* item, char* protoName) +{ + if ( code == IDCLOSE ) + return; + + PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)protoName); + if (pdescr == NULL) + return; + int statusToSet = -1; + if (lstrcmpA(pdescr->szProtoName, "ICQ") == 0) + { + ICQ_CUSTOM_STATUS ics = {0}; + ics.cbSize = sizeof(ICQ_CUSTOM_STATUS); + ics.flags = CSSF_MASK_STATUS | CSSF_MASK_NAME | CSSF_MASK_MESSAGE | CSSF_TCHAR; + + if (code == IDC_CANCEL) + { + statusToSet = 0; + ics.ptszName = _T(""); + ics.ptszMessage = _T(""); + } + else if (code == IDOK && item != NULL) + { + statusToSet = item->iIcon + 1; + ics.ptszName = variables_parsedup(item->tszTitle, NULL, NULL); + ics.ptszMessage = variables_parsedup(item->tszMessage, NULL, NULL); + } + else return; + + ics.status = &statusToSet; + + char protoService[64]; + mir_snprintf(protoService, SIZEOF(protoService), "%s%s", protoName, PS_ICQ_SETCUSTOMSTATUSEX); + CallService(protoService, 0, (LPARAM)&ics); + } + if (lstrcmpA(pdescr->szProtoName, "JABBER") == 0) + { + JABBER_CUSTOM_STATUS ics = {0}; + ics.cbSize = sizeof(ICQ_CUSTOM_STATUS); + ics.flags = CSSF_MASK_STATUS | CSSF_MASK_NAME | CSSF_MASK_MESSAGE | CSSF_TCHAR; + + if (code == IDC_CANCEL) + { + statusToSet = 0; + ics.ptszMessage = _T(""); + } + else if (code == IDOK && item != NULL) + { + statusToSet = item->iIcon + 1; + ics.ptszMessage = variables_parsedup(item->tszMessage, NULL, NULL); + } + else return; + + ics.status = &statusToSet; + + char protoService[64]; + mir_snprintf(protoService, SIZEOF(protoService), "%s%s", protoName, JS_SETXSTATUSEX); + CallService(protoService, 0, (LPARAM)&ics); + } +} + +void CSList::initIcoLib( ) +{ + // init icons of buttons + TCHAR tszFile[MAX_PATH]; + GetModuleFileName( CSList::handle, tszFile, MAX_PATH ); + + SKINICONDESC sid = { 0 }; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszDefaultFile = tszFile; + sid.flags = SIDF_ALL_TCHAR; + sid.cx = sid.cy = 16; + sid.ptszSection = _T(MODULENAME); + + for (int i=0; i < SIZEOF(forms); i++ ) { + char szSettingName[64]; + mir_snprintf( szSettingName, SIZEOF(szSettingName), "%s_%s", __INTERNAL_NAME, forms[i].pszIconIcoLib ); + + sid.pszName = szSettingName; + sid.ptszDescription = forms[i].ptszDescr; + sid.iDefaultIndex = -forms[i].iconNoIcoLib; + forms[i].hIcoLibItem = Skin_AddIcon(&sid); + } +} + + +INT_PTR CSList::showList(WPARAM wparam, LPARAM lparam, LPARAM param) +{ + cslist->mainWindow = new CSWindow((char*)param); + ForkThread(&cslist->mainWindow->showWindow, cslist->mainWindow); + return 0; +} + + +void CSList::closeList( HWND hwnd ) +{ + ForkThread( &cslist->mainWindow->closeWindow, hwnd ); + delete cslist->mainWindow; + cslist->mainWindow = NULL; +} + + +void CSList::ForAllProtocols( pForAllProtosFunc pFunc, void* arg ) +{ + int protoCount; + PROTOACCOUNT** pdesc; + CallService( MS_PSEUDO_PROTO_PROTOACCSENUM, ( WPARAM )&protoCount, ( LPARAM )&pdesc ); + + for ( int i = 0; i < protoCount; i++ ) + { + if (lstrcmpA(pdesc[i]->szProtoName, "ICQ") == 0) + { + DWORD uin = 0; + uin = DBGetContactSettingDword(NULL, pdesc[i]->szModuleName, "UIN", 0); + if (uin == 0) + continue; + } + else if (lstrcmpA(pdesc[i]->szProtoName, "JABBER") == 0) + { + DBVARIANT dbv = {0}; + DBGetContactSettingTString(NULL, pdesc[i]->szModuleName, "jid", &dbv); + if (dbv.ptszVal == _T("")) + continue; + } + else + continue; + pFunc(pdesc[i]->szModuleName , arg); + } +} + + +void CSList::addProtoStatusMenuItem( char* protoName, void* arg ) +{ + char buf[200]; + PROTOACCOUNT* pdescr; + pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)protoName); + if (pdescr == NULL) + return; + + HANDLE hService; + mir_snprintf(buf, SIZEOF(buf), "CSList/ShowList/%s", protoName); + if (!ServiceExists(buf)) + hService = CreateServiceFunctionParam(buf, CSList::showList, (LPARAM)protoName); + List_Insert(servicesList, hService, servicesList->realCount); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_TCHAR; + if (ServiceExists(MS_SKIN2_GETICON)) + mi.icolibItem = (HANDLE)LoadIconExEx("icon", IDI_CSLIST); + else + mi.hIcon = LoadIconExEx("icon", IDI_CSLIST); + mi.ptszName = _T(MODULENAME); + mi.position = 2000040000; + mi.pszService = buf; + mi.ptszPopupName = pdescr->tszAccountName; + Menu_AddStatusMenuItem(&mi); + + cslist->registerHotkeys(buf, pdescr->tszAccountName, pdescr->iOrder); +} + + +void CSList::countProtos( char* protoName, void* arg ) +{ + int* protosEnabled = (int*)arg; + *protosEnabled = ( *protosEnabled )++; +} + + +void CSList::countPlusModProtos( char* protoName, void* arg ) +{ + int* protosExtraEnabled = ( int* )arg; + if ( DBGetContactSettingDword( NULL, protoName, "NonStandartXstatus", 0 ) || + DBGetContactSettingDword( NULL, protoName, "NonStandardXstatus", 0 )) + *protosExtraEnabled = ( *protosExtraEnabled )++; +} + +void CSList::importCustomStatusUIStatusesFromAllProtos( char* protoName, void* arg ) +{ + int* result = ( int* )arg; + + for ( int i = 1; i <= 37; i++ ) + { + DBVARIANT dbv = { 0 }; + char bufTitle[32], bufMessage[32]; + StatusItem* si = new StatusItem( ); + + si->iIcon = i - 1; + + mir_snprintf( bufTitle, 32, "XStatus%luName", i ); + DBGetContactSettingTString( NULL, protoName, bufTitle, &dbv ); + lstrcpy( si->tszTitle, dbv.ptszVal ); + + mir_snprintf( bufMessage, 32, "XStatus%luMsg", i ); + DBGetContactSettingTString( NULL, protoName, bufMessage, &dbv ); + lstrcpy( si->tszMessage, dbv.ptszVal ); + + if ( lstrlen( si->tszTitle ) || lstrlen( si->tszMessage )) + { + cslist->mainWindow->itemslist->list->add( si ); + cslist->mainWindow->bSomethingChanged = TRUE; + } + else + delete si; + + if ( *result == IDYES ) + { + DBDeleteContactSetting( NULL, protoName, bufTitle ); + DBDeleteContactSetting( NULL, protoName, bufMessage ); + } + } + cslist->mainWindow->listview->reinitItems( cslist->mainWindow->itemslist->list->getListHead( )); +} + + +CSWindow::CSWindow(char* protoName) +{ + this->protoName = protoName; + this->handle = NULL; + this->bExtraIcons = getByte( "AllowExtraIcons", DEFAULT_ALLOW_EXTRA_ICONS ); + this->itemslist = new CSItemsList(this->protoName); + this->listview = NULL; + this->addModifyDlg = NULL; + this->bSomethingChanged = FALSE; + this->filterString = NULL; +} + + +CSWindow::~CSWindow( ) +{ + delete this->itemslist; + SAFE_FREE( ( void** )&this->filterString ); +} + + +void CSWindow::showWindow( void* arg ) +{ + CSWindow* csw = ( CSWindow* )arg; + + while ( csw == NULL ) + SleepEx( 10, FALSE ); + + DialogBoxParam( CSList::handle, MAKEINTRESOURCE( IDD_CSLIST ), NULL, ( DLGPROC )CSWindowProc, ( LPARAM )csw ); +} + + +void CSWindow::closeWindow( void* arg ) +{ + HWND hwnd = ( HWND )arg; + EndDialog( hwnd, FALSE ); +} + + +void CSWindow::initIcons() +{ + PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)protoName); + if (pdescr == NULL) + return; + + if (lstrcmpA(pdescr->szProtoName, "ICQ") == 0) + { + DWORD uin = 0; + uin = DBGetContactSettingDword(NULL, pdescr->szModuleName, "UIN", 0); + if (uin != 0) + { + this->icons = ImageList_Create( 16, 16, IsWinVerXPPlus( ) ? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, XSTATUS_COUNT_EXTENDED, 0 ); + if ( this->icons ) + { + for ( int i = 0; i < ( ( this->bExtraIcons ) ? XSTATUS_COUNT_EXTENDED : XSTATUS_COUNT ); i++ ) + { + char szTemp[MAX_PATH]; + mir_snprintf(szTemp, SIZEOF(szTemp), "%s_xstatus%d", protoName, i); + ImageList_AddIcon( this->icons, ( HICON )CallService( MS_SKIN2_GETICON, 0, ( LPARAM )szTemp )); + } + } + } + } + else if (lstrcmpA(pdescr->szProtoName, "JABBER") == 0) + { + DBVARIANT dbv = {0}; + DBGetContactSettingTString(NULL, pdescr->szModuleName, "jid", &dbv); + if (dbv.ptszVal != _T("")) + { + this->icons = ImageList_Create( 16, 16, IsWinVerXPPlus( ) ? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, MOODS_COUNT, 0 ); + if ( this->icons ) + { + for ( int i = 0; i < MOODS_COUNT; i++ ) + { + char szTemp[MAX_PATH]; + mir_snprintf(szTemp, SIZEOF(szTemp), "%s_%s", protoName, moods_names[i].szTag); + ImageList_AddIcon( this->icons, ( HICON )CallService( MS_SKIN2_GETICON, 0, ( LPARAM )szTemp )); + } + } + } + } +} + + +void CSWindow::deinitIcons( ) +{ + ImageList_Destroy( this->icons ); +} + + +void CSWindow::initButtons( ) +{ + for (int i = 0; i < SIZEOF(forms); i++) + { + if ( forms[i].idc < 0 ) + continue; + + SendDlgItemMessage( this->handle, forms[i].idc, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadIconExEx( forms[i].pszIconIcoLib, forms[i].iconNoIcoLib )); + SendDlgItemMessage( this->handle, forms[i].idc, BUTTONSETASFLATBTN, TRUE, 0 ); //maybe set as BUTTONSETDEFAULT? + SendDlgItemMessage( this->handle, forms[i].idc, BUTTONADDTOOLTIP, ( WPARAM )TranslateTS(forms[i].ptszTitle), BATF_TCHAR ); + } +} + +void CSWindow::loadWindowPosition( ) +{ + RECT rect = { 0 }; + int width = GetSystemMetrics( SM_CXSCREEN ); + int height = GetSystemMetrics( SM_CYSCREEN ); + GetWindowRect( this->handle, &rect ); + int x, y, defX, defY; + defX = x = ( width + 1 - ( rect.right - rect.left )) >> 1; + defY = y = ( height + 1 - ( rect.bottom - rect.top )) >> 1; + if ( getByte( "RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION )) + { + x = getWord( "PositionX", defX ); + y = getWord( "PositionY", defY ); + } + if ( x > width || y > height || x < 0 || y < 0 ) + { + x = defX; + y = defY; + } + + MoveWindow( this->handle, + x, y, + ( rect.right - rect.left ), + ( rect.bottom - rect.top ), + TRUE ); +} + + +void CSWindow::toggleEmptyListMessage( ) +{ + HWND hwnd = GetDlgItem( this->handle, IDC_NO_ITEMS ); + ShowWindow( hwnd, ( ListView_GetItemCount( this->listview->handle ) > 0 ) ? FALSE : TRUE ); + SetForegroundWindow( hwnd ); + hwnd = GetDlgItem( this->handle, IDC_ADD_SAMPLE ); + ShowWindow( hwnd, ( ListView_GetItemCount( this->listview->handle ) > 0 ) ? FALSE : TRUE ); + SetForegroundWindow( hwnd ); +} + + +BOOL CSWindow::itemPassedFilter( ListItem< StatusItem >* li ) +{ + TCHAR filter[MAX_PATH]; + GetDlgItemText( this->handle, IDC_FILTER_FIELD, filter, MAX_PATH ); + + if ( lstrlen( filter )) + { + TCHAR title[EXTRASTATUS_TITLE_LIMIT], message[EXTRASTATUS_MESSAGE_LIMIT]; + lstrcpy( title, li->item->tszTitle ); lstrcpy( message, li->item->tszMessage ); + if ( strpos( _tcslwr( title ), _tcslwr( filter )) == -1 ) + if ( strpos( _tcslwr( message ), _tcslwr( filter )) == -1 ) + return FALSE; + } + + return TRUE; +} + + +void CSWindow::toggleFilter( ) +{ + HWND hFilter = GetDlgItem( this->handle, IDC_FILTER_FIELD ); + BOOL isEnabled = !IsWindowEnabled( hFilter ) ? TRUE : FALSE; // ! = + isEnabled = !isEnabled in one + EnableWindow( hFilter, isEnabled ); + ShowWindow( hFilter, isEnabled ); + CheckDlgButton( this->handle, IDC_FILTER, isEnabled ); + SetForegroundWindow( hFilter ); + if ( isEnabled ) + SetFocus( hFilter ); + else + { + TCHAR filterText[255]; + GetDlgItemText(this->handle, IDC_FILTER_FIELD, filterText, SIZEOF(filterText)); + if ( lstrlen( filterText ) > 0 ) + SetDlgItemText( this->handle, IDC_FILTER_FIELD, TEXT( "" )); + } +} + + +BOOL CSWindow::toggleButtons( ) +{ + int selection = ListView_GetSelectedItemMacro( this->listview->handle ); + BOOL validSelection = ( selection >= 0 && ( unsigned int )selection < this->itemslist->list->getCount( )) ? TRUE : FALSE; + BOOL filterEnabled = IsWindowVisible( GetDlgItem( this->handle, IDC_FILTER_FIELD )); + BOOL somethingChanged = this->bSomethingChanged; + + EnableWindow( GetDlgItem( this->handle, IDC_ADD ), !filterEnabled ); + EnableWindow( GetDlgItem( this->handle, IDC_MODIFY ), validSelection && !filterEnabled ); + EnableWindow( GetDlgItem( this->handle, IDC_REMOVE ), validSelection && !filterEnabled ); + EnableWindow( GetDlgItem( this->handle, IDC_FAVOURITE ), validSelection && !filterEnabled ); + EnableWindow( GetDlgItem( this->handle, IDC_UNDO ), somethingChanged && !filterEnabled ); + EnableWindow( GetDlgItem( this->handle, IDC_IMPORT ), !filterEnabled ); +// EnableWindow( GetDlgItem( this->handle, IDC_GLOBAL ), !filterEnabled ); + EnableWindow( GetDlgItem( this->handle, IDOK ), validSelection ); + + return validSelection; +} + + +CSAMWindow::CSAMWindow( WORD action, CSWindow* parent ) +{ + this->action = action; + this->parent = parent; + this->bChanged = FALSE; + this->hCombo = this->hMessage = NULL; + + if ( this->action == IDC_ADD ) + this->item = new StatusItem( ); + else + this->item = new StatusItem( *this->parent->itemslist->list->get( this->parent->listview->getPositionInList( )) ); + +} + + +CSAMWindow::~CSAMWindow( ) +{ + if ( ! this->bChanged ) + delete this->item; +} + + +void CSAMWindow::exec( ) +{ + DialogBoxParam( CSList::handle, MAKEINTRESOURCE( IDD_ADDMODIFY ), NULL, ( DLGPROC )CSAMWindowProc, ( LPARAM )this ); +} + + +void CSAMWindow::setCombo() +{ + PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)this->parent->protoName); + if (pdescr == NULL) + return; + + if (lstrcmpA(pdescr->szProtoName, "ICQ") == 0) + { + DWORD uin = 0; + uin = DBGetContactSettingDword(NULL, pdescr->szModuleName, "UIN", 0); + if (uin != 0) + { + SendMessage( this->hCombo, CBEM_SETIMAGELIST, 0, ( LPARAM )this->parent->icons ); + for ( int i = 0; i < ( ( this->parent->bExtraIcons ) ? XSTATUS_COUNT_EXTENDED : XSTATUS_COUNT ); i++ ) + { + COMBOBOXEXITEM cbi = { 0 }; + cbi.mask = CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; + cbi.pszText = TranslateTS(xstatus_names[i].ptszTitle); + cbi.iImage = xstatus_names[i].iId - 1; + cbi.iItem = i; + cbi.iSelectedImage = i; + SendMessage( this->hCombo, CBEM_INSERTITEM, 0, ( LPARAM )&cbi ); + } + SendMessage( this->hCombo, CB_SETCURSEL, 0, 0 ); // first 0 sets selection to top + } + } + else if (lstrcmpA(pdescr->szProtoName, "JABBER") == 0) + { + DBVARIANT dbv = {0}; + DBGetContactSettingTString(NULL, pdescr->szModuleName, "jid", &dbv); + if (dbv.ptszVal != _T("")) + { + SendMessage( this->hCombo, CBEM_SETIMAGELIST, 0, ( LPARAM )this->parent->icons ); + for ( int i = 0; i < MOODS_COUNT; i++ ) + { + COMBOBOXEXITEM cbi = { 0 }; + cbi.mask = CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; + cbi.pszText = TranslateTS(moods_names[i].ptszTitle); + cbi.iImage = moods_names[i].iId - 1; + cbi.iItem = i; + cbi.iSelectedImage = i; + SendMessage( this->hCombo, CBEM_INSERTITEM, 0, ( LPARAM )&cbi ); + } + SendMessage( this->hCombo, CB_SETCURSEL, 0, 0 ); // first 0 sets selection to top + } + } +} + +void CSAMWindow::fillDialog( ) +{ + if ( this->action == IDC_ADD ) + { + SetWindowText( this->handle, TranslateT("Add new item")); + SetDlgItemText( this->handle, IDOK, TranslateT("Add")); + } + else + { + SetWindowText( this->handle, TranslateT("Modify item")); + SetDlgItemText( this->handle, IDOK, TranslateT("Modify")); + } + + SendMessage( this->hCombo, CB_SETCURSEL, this->item->iIcon, 0 ); + SetDlgItemText( this->handle, IDC_MESSAGE, this->item->tszMessage ); +} + + +void CSAMWindow::checkFieldLimit( WORD action, WORD item ) +{ + BOOL type = ( item == IDC_MESSAGE ) ? TRUE : FALSE; + unsigned int limit = type ? EXTRASTATUS_MESSAGE_LIMIT : EXTRASTATUS_TITLE_LIMIT; + + if ( action == EN_CHANGE ) + { + TCHAR* ptszInputText = (TCHAR*)mir_alloc((limit + 8) * sizeof(TCHAR)); + + GetDlgItemText( this->handle, item, ptszInputText, limit + 8 ); + + if ( _tcslen( ptszInputText ) > limit ) + { +#if ( WINVER >= 0x501 ) + TCHAR tszPopupTip[MAX_PATH]; + EDITBALLOONTIP ebt = { 0 }; + ebt.cbStruct = sizeof(ebt); + ebt.pszTitle = TranslateT("Warning"); + mir_sntprintf(tszPopupTip, SIZEOF(tszPopupTip), TranslateT("This field doesn't accept string longer than %d characters. The string will be truncated."), limit); + ebt.pszText = tszPopupTip; + ebt.ttiIcon = TTI_WARNING; + SendMessage( GetDlgItem( this->handle, item ), EM_SHOWBALLOONTIP, 0, ( LPARAM )&ebt ); +#endif + TCHAR* ptszOutputText = (TCHAR*)mir_alloc((limit + 1) * sizeof(TCHAR)); + GetDlgItemText( this->handle, item, ptszOutputText, limit + 1 ); + SetDlgItemText( this->handle, item, ptszOutputText ); + mir_free( ptszOutputText ); + } + mir_free( ptszInputText ); + } +} + + +void CSAMWindow::checkItemValidity() +{ + COMBOBOXEXITEM cbi = { 0 }; + cbi.mask = CBEIF_IMAGE; + cbi.iItem = SendDlgItemMessage( this->handle, IDC_COMBO, CB_GETCURSEL, 0, 0 ); + SendDlgItemMessage( this->handle, IDC_COMBO, CBEM_GETITEM, 0, ( LPARAM )&cbi ); + + if ( this->item->iIcon != cbi.iImage ) + ( this->item->iIcon = cbi.iImage ) && ( this->bChanged = TRUE ); + + TCHAR tszInputMessage[EXTRASTATUS_MESSAGE_LIMIT]; + + GetDlgItemText( this->handle, IDC_MESSAGE, tszInputMessage, EXTRASTATUS_MESSAGE_LIMIT ); + + PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)this->parent->protoName); + if (pdescr == NULL) + return; + + if (lstrcmpA(pdescr->szProtoName, "ICQ") == 0) + { + int i = SendMessage(this->hCombo, CB_GETCURSEL, 0, 0); + lstrcpy(this->item->tszTitle, TranslateTS(xstatus_names[i].ptszTitle)); + } + if (lstrcmpA(pdescr->szProtoName, "JABBER") == 0) + { + int i = SendMessage(this->hCombo, CB_GETCURSEL, 0, 0); + lstrcpy(this->item->tszTitle, TranslateTS(moods_names[i].ptszTitle)); + } + if ( lstrcmp( this->item->tszMessage, tszInputMessage )) + ( lstrcpy( this->item->tszMessage, tszInputMessage )) && ( this->bChanged = TRUE ); +} + + +CSListView::CSListView( HWND hwnd, CSWindow* parent ) +{ + this->handle = hwnd; + this->parent = parent; + +#if (_WIN32_WINNT >= 0x501) + LVGROUP lg = { 0 }; + lg.cbSize = sizeof(LVGROUP); + lg.mask = LVGF_HEADER | LVGF_GROUPID; + + lg.pszHeader = TranslateT("Favourites"); + lg.iGroupId = 0; + ListView_InsertGroup( this->handle, -1, &lg ); + + lg.pszHeader = TranslateT("Regular statuses"); + lg.iGroupId = 1; + ListView_InsertGroup( this->handle, -1, &lg ); + ListView_EnableGroupView( this->handle, TRUE ); +#endif + + LVCOLUMN lvc = { 0 }; + lvc.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = 0x00; + lvc.pszText = TEXT( "" ); + lvc.cx = 0x16; + SendMessage( this->handle, LVM_INSERTCOLUMN, 0, ( LPARAM )&lvc ); + lvc.pszText = TranslateT("Title"); + lvc.cx = 0x64; + SendMessage( this->handle, LVM_INSERTCOLUMN, 1, ( LPARAM )&lvc ); + lvc.pszText = TranslateT("Message"); + lvc.cx = 0xa8; + SendMessage( this->handle, LVM_INSERTCOLUMN, 2, ( LPARAM )&lvc ); + +// ListView_SetExtendedListViewStyle( this->handle, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP ); +#if (_WIN32_IE >= 0x0400) + ListView_SetExtendedListViewStyleEx( this->handle, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP | LVS_EX_INFOTIP ); +#endif + ListView_SetImageList( this->handle, this->parent->icons, LVSIL_SMALL ); +} + + +void CSListView::addItem( StatusItem* item, int itemNumber ) +{ + LVITEM lvi = { 0 }; + lvi.mask = LVIF_IMAGE | LVIF_GROUPID | LVIF_PARAM; + lvi.cchTextMax = 256; + lvi.iItem = ListView_GetItemCount( this->handle ); + lvi.lParam = itemNumber; +#if ( WINVER >= 0x501 ) + lvi.iGroupId = ( item->bFavourite == TRUE ) ? 0 : 1; +#endif + + // first column + lvi.iSubItem = 0; + lvi.iImage = item->iIcon; // use selected xicon + SendMessage( this->handle, LVM_INSERTITEM, 0, ( LPARAM )&lvi ); + + // second column + lvi.mask = LVIF_TEXT; + lvi.iSubItem = 1; + lvi.pszText = item->tszTitle; + SendMessage( this->handle, LVM_SETITEM, 0, ( LPARAM )&lvi ); + + // third column + lvi.iSubItem = 2; + lvi.pszText = item->tszMessage; + SendMessage( this->handle, LVM_SETITEM, 0, ( LPARAM )&lvi ); +} + + +void CSListView::initItems( ListItem< StatusItem >* items ) +{ + ListItem< StatusItem >* help = items; + for ( int i = 0; help != NULL; help = help->next, i++ ) + if ( parent->itemPassedFilter( help )) + addItem( help->item, i ); +} + + +void CSListView::reinitItems( ListItem< StatusItem >* items ) +{ + EnableWindow( this->handle, FALSE ); + this->removeItems( ); + this->initItems( items ); + EnableWindow( this->handle, TRUE ); +} + + +void CSListView::removeItems( ) +{ + ListView_DeleteAllItems( this->handle ); +} + + +int CSListView::getPositionInList( ) +{ + LVITEM lvi = { 0 }; + lvi.iItem = ListView_GetSelectedItemMacro( this->parent->listview->handle ); + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + ListView_GetItem( this->parent->listview->handle, &lvi ); + return lvi.lParam; +} + + +void CSListView::setFullFocusedSelection( int selection ) +{ + ListView_SetItemState( this->handle, -1, 0, LVIS_SELECTED ); + ListView_EnsureVisible( this->handle, selection, FALSE ); + ListView_SetItemState( this->handle, selection, LVIS_SELECTED, LVIS_SELECTED ); + ListView_SetItemState( this->handle, selection, LVIS_FOCUSED , LVIS_FOCUSED ); + SetFocus( this->handle ); +} + + +// ====[ THREAD FORK ]======================================================== + +void ForkThread( pThreadFunc pFunc, void* arg ) +{ + mir_forkthread( pFunc, arg ); +} + + +// ====[ LIST MANAGEMENT ]==================================================== + +CSItemsList::CSItemsList(char* protoName) +{ + this->list = new List< StatusItem >( this->compareItems ); + this->loadItems(protoName); +} + + +CSItemsList::~CSItemsList( ) +{ + delete this->list; +} + + +int CSItemsList::compareItems( const StatusItem* p1, const StatusItem* p2 ) +{ + int favRes = 0, icoRes = 0, ttlRes = 0, msgRes = 0; + + if ( p1->bFavourite < p2->bFavourite ) + favRes = 1; + else if ( p1->bFavourite > p2->bFavourite ) + favRes = -1; + + int result; + if ( p1->iIcon > p2->iIcon ) + icoRes = 1; + else if ( p1->iIcon < p2->iIcon ) + icoRes = -1; + + result = lstrcmp( p1->tszTitle, p2->tszTitle ); + ttlRes = result; + + result = lstrcmp( p1->tszMessage, p2->tszMessage ); + msgRes = result; + + if ( !icoRes && !ttlRes && !msgRes ) + return 0; + + if ( favRes != 0 ) + return favRes; + if ( icoRes != 0 ) + return icoRes; + if ( ttlRes != 0 ) + return ttlRes; + if ( msgRes != 0 ) + return msgRes; + + return 0; +} + + +void CSItemsList::loadItems(char* protoName) +{ + char dbSetting[32]; + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName); + unsigned int itemsCount = getWord(dbSetting, DEFAULT_ITEMS_COUNT); + + for (unsigned int i = 1; i <= itemsCount; i++) + { + StatusItem* item = new StatusItem(); + DBVARIANT dbv = {DBVT_TCHAR}; + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i); + item->iIcon = getByte(dbSetting, DEFAULT_ITEM_ICON); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i); + getTString(dbSetting, &dbv); + lstrcpy(item->tszTitle, dbv.ptszVal); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i); + getTString(dbSetting, &dbv); + lstrcpy(item->tszMessage, dbv.ptszVal); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i); + item->bFavourite = (BOOL)getByte(dbSetting, DEFAULT_ITEM_IS_FAVOURITE); + this->list->add(item); + } +} + + +void CSItemsList::saveItems(char* protoName) +{ + unsigned int i; + char dbSetting[32]; + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName); + unsigned int oldItemsCount = getWord(dbSetting, DEFAULT_ITEMS_COUNT); + + for (i = 1; i <= this->list->getCount(); i++) + { + StatusItem* item = this->list->get( i - 1 ); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i); + setByte(dbSetting, item->iIcon); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i); + setTString(dbSetting, item->tszTitle); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i); + setTString(dbSetting, item->tszMessage); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i); + setByte(dbSetting, item->bFavourite); + } + + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName); + setWord(dbSetting, this->list->getCount()); + + for ( ; i <= oldItemsCount; i++) + { + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i); + deleteSetting(dbSetting); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i); + deleteSetting(dbSetting); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i); + deleteSetting(dbSetting); + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i); + deleteSetting(dbSetting); + } +} + + +// ====[ PROCEDURES ]========================================================= + +INT_PTR CALLBACK CSWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ + CSWindow* csw = ( CSWindow* )GetWindowLongPtr( hwnd, GWLP_USERDATA ); + + switch ( message ) + { + + case WM_INITDIALOG: + csw = ( CSWindow* )lparam; + SetWindowLongPtr( hwnd, GWLP_USERDATA, lparam ); + csw->handle = hwnd; + csw->initIcons(); + csw->initButtons( ); + csw->listview = new CSListView( GetDlgItem( hwnd, IDC_CSLIST ), csw ); + csw->listview->initItems( csw->itemslist->list->getListHead( )); + csw->toggleButtons( ); + csw->toggleEmptyListMessage( ); + csw->loadWindowPosition( ); + SetWindowText(hwnd, TranslateT(MODULENAME)); + TranslateDialogDefault(hwnd); + return TRUE; + + case WM_COMMAND: + switch ( LOWORD( wparam )) + { + case IDC_MODIFY: + case IDC_ADD: + csw->addModifyDlg = new CSAMWindow( LOWORD( wparam ), csw ); + csw->addModifyDlg->exec( ); + if ( csw->addModifyDlg->bChanged ) + { + if ( LOWORD( wparam ) == IDC_MODIFY ) + csw->itemslist->list->remove( csw->listview->getPositionInList( )); + + int selection = csw->itemslist->list->add( csw->addModifyDlg->item ); + csw->bSomethingChanged = TRUE; + csw->listview->reinitItems( csw->itemslist->list->getListHead( )); + csw->listview->setFullFocusedSelection( selection ); + csw->toggleButtons( ); + csw->toggleEmptyListMessage( ); + } + delete csw->addModifyDlg; + break; + + case IDC_REMOVE: + if ( getByte( "ConfirmDeletion", DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION )) + if ( MessageBox( hwnd, TranslateT("Do you really want to delete selected item?"), TranslateT(MODULENAME), MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION ) == IDNO ) + break; + csw->itemslist->list->remove( csw->listview->getPositionInList( )); + csw->bSomethingChanged = TRUE; + csw->listview->reinitItems( csw->itemslist->list->getListHead( )); + csw->toggleButtons( ); + csw->toggleEmptyListMessage( ); + break; + + case IDC_FAVOURITE: + { + int selection = csw->listview->getPositionInList( ); + StatusItem* f = new StatusItem( *csw->itemslist->list->get( selection )); + f->bFavourite = ! f->bFavourite; + csw->itemslist->list->remove( selection ); + selection = csw->itemslist->list->add( f ); + csw->bSomethingChanged = TRUE; + csw->listview->reinitItems( csw->itemslist->list->getListHead( )); + csw->listview->setFullFocusedSelection( selection ); + csw->toggleButtons( ); + } + break; + + case IDC_UNDO: + { + csw->itemslist->list->destroy( ); + csw->itemslist->loadItems(csw->protoName); + csw->bSomethingChanged = FALSE; + csw->listview->reinitItems( csw->itemslist->list->getListHead( )); + csw->toggleButtons( ); + csw->toggleEmptyListMessage( ); + break; + } + + case IDC_IMPORT: + { + int result = getByte( "DeleteAfterImport", DEFAULT_PLUGIN_DELETE_AFTER_IMPORT ); + if ( result == TRUE ) + result = IDYES; + else + { + result = MessageBox( hwnd, TranslateT("Do you want old database entries to be deleted after Import?"), + TranslateT(MODULENAME), MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONQUESTION ); + if ( result == IDCANCEL ) break; + } + + CSList::ForAllProtocols( CSList::importCustomStatusUIStatusesFromAllProtos, ( void* )&result ); + csw->bSomethingChanged = TRUE; + csw->toggleButtons( ); + csw->toggleEmptyListMessage( ); + } + break; + + case IDC_FILTER: + csw->toggleFilter( ); + csw->toggleButtons( ); + break; + + case IDC_FILTER_FIELD: + if ( HIWORD( wparam ) == EN_CHANGE ) + csw->listview->reinitItems( csw->itemslist->list->getListHead( )); + break; + + case IDCLOSE: // close and save, no custom status + case IDCANCEL: // close and save, no custom status + case IDC_CANCEL: // close and save, cancel custom status + case IDOK: // close and save, set selected custom status + if ( LOWORD( wparam ) == IDOK && csw->toggleButtons( )) + cslist->setStatus(IDOK, csw->itemslist->list->get(csw->listview->getPositionInList()), csw->protoName); + if ( LOWORD( wparam ) == IDC_CANCEL ) + cslist->setStatus(IDC_CANCEL, NULL, csw->protoName); + if ( csw->bSomethingChanged ) + if (csw->itemslist!=NULL) + csw->itemslist->saveItems(csw->protoName); + csw->saveWindowPosition( csw->handle ); + delete csw->listview; + csw->deinitIcons( ); + cslist->closeList( hwnd ); + break; + + } + return FALSE; + + case WM_NOTIFY: + if ( wparam == IDC_CSLIST ) + { + NMHDR* pnmh = ( NMHDR* )lparam; + switch ( pnmh->code ) + { + + case NM_DBLCLK: + PostMessage( hwnd, WM_COMMAND, IDOK, 0L ); + break; + + case LVN_ITEMCHANGED: + case NM_CLICK: + csw->toggleButtons( ); + break; + + } + } + return FALSE; + + case WM_CTLCOLORSTATIC: + SetTextColor( ( HDC )wparam, RGB( 174, 174, 174 )); + if ( ( ( HWND )lparam == GetDlgItem( hwnd, IDC_NO_ITEMS )) || + ( ( HWND )lparam == GetDlgItem( hwnd, IDC_ADD_SAMPLE )) ) + return ( BOOL )GetStockObject( WHITE_BRUSH ); + return FALSE; + } + return FALSE; +} + + +INT_PTR CALLBACK CSAMWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ + CSAMWindow* csamw = ( CSAMWindow* )GetWindowLongPtr( hwnd, GWLP_USERDATA ); + + switch ( message ) + { + + case WM_INITDIALOG: + { + csamw = ( CSAMWindow* )lparam; + SetWindowLongPtr( hwnd, GWLP_USERDATA, lparam ); + csamw->handle = hwnd; + EnableWindow( csamw->parent->handle, FALSE ); + csamw->hCombo = GetDlgItem( hwnd, IDC_COMBO ); + csamw->hMessage = GetDlgItem( hwnd, IDC_MESSAGE ); + csamw->setCombo(); + csamw->fillDialog(); + TranslateDialogDefault(hwnd); + } + break; + + case WM_COMMAND: + switch ( LOWORD( wparam )) + { + case IDC_MESSAGE: + csamw->checkFieldLimit( HIWORD( wparam ), LOWORD( wparam )); + break; + case IDOK: + csamw->checkItemValidity( ); + case IDCANCEL: + EnableWindow( csamw->parent->handle, TRUE ); + EndDialog( hwnd, LOWORD( wparam )); + break; + + } + break; + + } + return FALSE; +} + + +INT_PTR CALLBACK CSOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ + switch ( message ) + { + + case WM_INITDIALOG: + { + CheckDlgButton( hwnd, IDC_CONFIRM_DELETION, + getByte( "ConfirmDeletion", DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION ) ? + BST_CHECKED : BST_UNCHECKED ); + + CheckDlgButton( hwnd, IDC_DELETE_AFTER_IMPORT, + getByte( "DeleteAfterImport", DEFAULT_PLUGIN_DELETE_AFTER_IMPORT ) ? + BST_CHECKED : BST_UNCHECKED ); + + CheckDlgButton( hwnd, IDC_REMEMBER_POSITION, + getByte( "RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION ) ? + BST_CHECKED : BST_UNCHECKED ); + + unsigned int protosExtraEnabled = 1; + + CSList::ForAllProtocols( CSList::countPlusModProtos, ( void* )&protosExtraEnabled ); + + if ( protosExtraEnabled ) // some protocol(s) allow(s) use of extra icons + { + EnableWindow( GetDlgItem( hwnd, IDC_ALLOW_EXTRA_ICONS ), TRUE ); + CheckDlgButton( hwnd, IDC_ALLOW_EXTRA_ICONS, getByte( "AllowExtraIcons", + DEFAULT_ALLOW_EXTRA_ICONS )); + } + + TranslateDialogDefault(hwnd); + } + return TRUE; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lparam )->code ) + { + + case PSN_APPLY: + { + setByte( "ConfirmDeletion", IsDlgButtonChecked( hwnd, IDC_CONFIRM_DELETION ) ? 1 : 0 ); + setByte( "DeleteAfterImport", IsDlgButtonChecked( hwnd, IDC_DELETE_AFTER_IMPORT ) ? 1 : 0 ); + setByte( "AllowExtraIcons", IsDlgButtonChecked( hwnd, IDC_ALLOW_EXTRA_ICONS ) ? 1 : 0 ); + setByte( "RememberWindowPosition", IsDlgButtonChecked( hwnd, IDC_REMEMBER_POSITION ) ? 1 : 0 ); + + cslist->rebuildMenuItems( ); + } + break; + + } + return TRUE; + + } + return FALSE; +} + + +// ====[ HELPERS ]============================================================ + +HICON LoadIconExEx( const char* IcoLibName, int NonIcoLibIcon ) +{ + if ( ServiceExists( MS_SKIN2_GETICON )) { + char szSettingName[64]; + mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", __INTERNAL_NAME, IcoLibName); + return ( HICON )CallService( MS_SKIN2_GETICON, 0, ( LPARAM )szSettingName ); + } + else + return ( HICON )LoadImage( cslist->handle, MAKEINTRESOURCE( NonIcoLibIcon ), IMAGE_ICON, 0, 0, 0 ); +} diff --git a/plugins/CSList/src/cslist.h b/plugins/CSList/src/cslist.h new file mode 100644 index 0000000000..7a4f0f8e75 --- /dev/null +++ b/plugins/CSList/src/cslist.h @@ -0,0 +1,665 @@ +/* ======================================================================== + + Custom Status List + __________________ + + Custom Status List plugin for Miranda-IM (www.miranda-im.org) + Follower of Custom Status History List by HANAX + Copyright © 2006-2008 HANAX + Copyright © 2007-2009 jarvis + + 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 : $URL$ + Revision : $Rev$ + Last change on : $Date$ + Last change by : $Author$ + + ============================================================================ + + + DESCRIPTION: + + Offers List of your Custom Statuses. + + ============================================================================ + +// ====[ INCLUDES AND DEFINITIONS ]======================================== */ + +#ifndef __CSLIST_H +#define __CSLIST_H 1 + + +#define WINVER 0x501 +#define _WIN32_WINNT 0x501 +#define _WIN32_IE 0x600 + +#define MIRANDA_VER 0x0A00 + +#pragma warning( disable: 4996 ) +#pragma comment( lib, "comctl32.lib" ) + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ====[ BASIC DEFINITIONS ]================================================== + +#include "resource.h" +#include "version.h" + +#define MODULENAME "Custom Status List" + +// {C8CC7414-6507-4AF6-925A-83C1D2F7BE8C} +#define PLUGIN_GUUID { 0xc8cc7414, 0x6507, 0x4af6, { 0x92, 0x5a, 0x83, 0xc1, 0xd2, 0xf7, 0xbe, 0x8c } } + +// ====[ LIMITS ]============================================================= + +#define EXTRASTATUS_TITLE_LIMIT 64 // limit of chars for extra status title +#define EXTRASTATUS_MESSAGE_LIMIT 2048 // limit of chars for extra status message +#define XSTATUS_COUNT 32 +#define XSTATUS_COUNT_EXTENDED 37 +#define MOODS_COUNT 84 + +// ====[ SERVICES ]=========================================================== + +#define MS_PSEUDO_PROTO_PROTOACCSENUM ( CSList::bAccountsSupported ? MS_PROTO_ENUMACCOUNTS : MS_PROTO_ENUMPROTOCOLS ) + +// ====[ DEFAULT DB VALUES ]================================================== + +#define DEFAULT_ICQ_XSTATUS_ENABLED 1 +#define DEFAULT_PLUGIN_SHOW_RELNOTES 0 +#define DEFAULT_PLUGIN_SHOW_NONSTANDARD_XSTATUSES 1 +#define DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION 1 +#define DEFAULT_PLUGIN_DELETE_AFTER_IMPORT 0 +#define DEFAULT_ITEMS_COUNT 0 +#define DEFAULT_ITEM_ICON 0 +#define DEFAULT_ITEM_IS_FAVOURITE 0 +#define DEFAULT_ALLOW_EXTRA_ICONS 1 +#define DEFAULT_REMEMBER_WINDOW_POSITION 1 + + +// ====[ FUNCTION MACROS ]==================================================== + +// set which row is selected (cannot be only focused, but fully selected - second param ;)) +#define ListView_GetSelectedItemMacro( hwnd ) ListView_GetNextItem( hwnd, -1, LVNI_FOCUSED | LVNI_SELECTED ); +#ifndef ListView_SetSelectionMark + #define ListView_SetSelectionMark( x, y ) 0 +#endif + +#define getByte( setting, error ) DBGetContactSettingByte( NULL, __INTERNAL_NAME, setting, error ) +#define setByte( setting, value ) DBWriteContactSettingByte( NULL, __INTERNAL_NAME, setting, value ) +#define getWord( setting, error ) DBGetContactSettingWord( NULL, __INTERNAL_NAME, setting, error ) +#define setWord( setting, value ) DBWriteContactSettingWord( NULL, __INTERNAL_NAME, setting, value ) +#define getDword( setting, error ) DBGetContactSettingDword( NULL, __INTERNAL_NAME, setting, error ) +#define setDword( setting, value ) DBWriteContactSettingDword( NULL, __INTERNAL_NAME, setting, value ) +#define getTString( setting, dest ) DBGetContactSettingTString( NULL, __INTERNAL_NAME, setting, dest ) +#define setTString( setting, value ) DBWriteContactSettingTString( NULL, __INTERNAL_NAME, setting, value ) +#define deleteSetting( setting ) DBDeleteContactSetting( NULL, __INTERNAL_NAME, setting ) + +// -- +typedef void (__cdecl *pForAllProtosFunc)( char*, void* ); + + +// ====[ STRUCTURES ]========================================================= + +struct StatusItem { // list item structure + int iIcon; + TCHAR tszTitle[EXTRASTATUS_TITLE_LIMIT]; + TCHAR tszMessage[EXTRASTATUS_MESSAGE_LIMIT]; + BOOL bFavourite; + + StatusItem() + { + this->iIcon = 0; + lstrcpy(this->tszTitle, _T("")); + lstrcpy(this->tszMessage, _T("")); + this->bFavourite = FALSE; + } + + StatusItem( const StatusItem& p ) + { + this->iIcon = p.iIcon; + lstrcpy( this->tszTitle, p.tszTitle ); + lstrcpy( this->tszMessage, p.tszMessage ); + this->bFavourite = p.bFavourite; + } + + ~StatusItem( ) + { + } +}; + +static struct CSForm { // icons + buttons + int idc; + TCHAR* ptszTitle; + TCHAR* ptszDescr; + char* pszIconIcoLib; + int iconNoIcoLib; + HANDLE hIcoLibItem; + +} forms[] = { + + { -1, LPGENT( "Main Menu" ), LPGENT( "Main Icon" ), "icon", IDI_CSLIST, NULL }, + { IDC_ADD, LPGENT( "Add new item" ), LPGENT( "Add" ), "add", IDI_ADD, NULL }, + { IDC_MODIFY, LPGENT( "Modify selected item" ), LPGENT( "Modify" ), "modify", IDI_MODIFY, NULL }, + { IDC_REMOVE, LPGENT( "Delete selected item" ), LPGENT( "Remove" ), "remove", IDI_REMOVE, NULL }, + { IDC_FAVOURITE, LPGENT( "Set/unset current item as favorite" ), LPGENT( "Favourite" ), "favourite", IDI_FAVOURITE, NULL }, + { IDC_UNDO, LPGENT( "Undo changes" ), LPGENT( "Undo changes" ), "undo", IDI_UNDO, NULL }, + { IDC_IMPORT, LPGENT( "Import statuses from database" ), LPGENT( "Import" ), "import", IDI_IMPORT, NULL }, + { IDC_FILTER, LPGENT( "Filter list" ), LPGENT( "Filter" ), "filter", IDI_FILTER, NULL }, + { IDCLOSE, LPGENT( "Close without changing custom status" ), LPGENT( "No change" ), "nochng", IDI_CLOSE, NULL }, + { IDC_CANCEL, LPGENT( "Clear custom status (reset to None) and close" ), LPGENT( "Clear" ), "clear", IDI_UNSET, NULL }, + { IDOK, LPGENT( "Set custom status to selected one and close" ), LPGENT( "Set" ), "apply", IDI_APPLY, NULL }, +}; + +static struct CSXstatus { // combobox xstatus icons + int iId; + TCHAR* ptszTitle; + +} xstatus_names[] = { + + { 1, LPGENT( "Angry" ) }, + { 2, LPGENT( "Taking a bath" ) }, + { 3, LPGENT( "Tired" ) }, + { 4, LPGENT( "Party" ) }, + { 5, LPGENT( "Drinking beer" ) }, + { 6, LPGENT( "Thinking" ) }, + { 7, LPGENT( "Eating" ) }, + { 8, LPGENT( "Watching TV" ) }, + { 9, LPGENT( "Meeting" ) }, + { 10, LPGENT( "Coffee" ) }, + { 11, LPGENT( "Listening to music" ) }, + { 12, LPGENT( "Business" ) }, + { 13, LPGENT( "Shooting" ) }, + { 14, LPGENT( "Having fun" ) }, + { 15, LPGENT( "On the phone" ) }, + { 16, LPGENT( "Gaming" ) }, + { 17, LPGENT( "Studying" ) }, + { 18, LPGENT( "Shopping" ) }, + { 19, LPGENT( "Feeling sick" ) }, + { 20, LPGENT( "Sleeping" ) }, + { 21, LPGENT( "Surfing" ) }, + { 22, LPGENT( "Browsing" ) }, + { 23, LPGENT( "Working" ) }, + { 24, LPGENT( "Typing" ) }, + { 25, LPGENT( "Picnic" ) }, + { 26, LPGENT( "PDA" ) }, + { 27, LPGENT( "On the phone" ) }, + { 28, LPGENT( "I'm high" ) }, + { 29, LPGENT( "On WC" ) }, + { 30, LPGENT( "To be or not to be" ) }, + { 31, LPGENT( "Watching pro7 on TV" ) }, + { 32, LPGENT( "Love" ) }, + { 33, LPGENT( "Searching" ) }, + { 34, LPGENT( "Amorous" ) }, // I don't understand why this falls when 2 same named items appear O_o + { 35, LPGENT( "Journal" ) }, // edit: ..and now I REALLY don't understand why it's working now x)) + { 36, LPGENT( "Sex" ) }, + { 37, LPGENT( "Smoking" ) }, // -||- +}; + +static struct CSMoods { // combobox moods icons + int iId; + TCHAR* ptszTitle; + char* szTag; +} moods_names[] = { + { 1, LPGENT("Afraid"), "afraid" }, + { 2, LPGENT("Amazed"), "amazed" }, + { 3, LPGENT("Amorous"), "amorous" }, + { 4, LPGENT("Angry"), "angry" }, + { 5, LPGENT("Annoyed"), "annoyed" }, + { 6, LPGENT("Anxious"), "anxious" }, + { 7, LPGENT("Aroused"), "aroused" }, + { 8, LPGENT("Ashamed"), "ashamed" }, + { 9, LPGENT("Bored"), "bored" }, + { 10, LPGENT("Brave"), "brave" }, + { 11, LPGENT("Calm"), "calm" }, + { 12, LPGENT("Cautious"), "cautious" }, + { 13, LPGENT("Cold"), "cold" }, + { 14, LPGENT("Confident"), "confident" }, + { 15, LPGENT("Confused"), "confused" }, + { 16, LPGENT("Contemplative"),"contemplative" }, + { 17, LPGENT("Contented"), "contented" }, + { 18, LPGENT("Cranky"), "cranky" }, + { 19, LPGENT("Crazy"), "crazy" }, + { 20, LPGENT("Creative"), "creative" }, + { 21, LPGENT("Curious"), "curious" }, + { 22, LPGENT("Dejected"), "dejected" }, + { 23, LPGENT("Depressed"), "depressed" }, + { 24, LPGENT("Disappointed"), "disappointed" }, + { 25, LPGENT("Disgusted"), "disgusted" }, + { 26, LPGENT("Dismayed"), "dismayed" }, + { 27, LPGENT("Distracted"), "distracted" }, + { 28, LPGENT("Embarrassed"), "embarrassed" }, + { 29, LPGENT("Envious"), "envious" }, + { 30, LPGENT("Excited"), "excited" }, + { 31, LPGENT("Flirtatious"), "flirtatious" }, + { 32, LPGENT("Frustrated"), "frustrated" }, + { 33, LPGENT("Grateful"), "grateful" }, + { 34, LPGENT("Grieving"), "grieving" }, + { 35, LPGENT("Grumpy"), "grumpy" }, + { 36, LPGENT("Guilty"), "guilty" }, + { 37, LPGENT("Happy"), "happy" }, + { 38, LPGENT("Hopeful"), "hopeful" }, + { 39, LPGENT("Hot"), "hot" }, + { 40, LPGENT("Humbled"), "humbled" }, + { 41, LPGENT("Humiliated"), "humiliated" }, + { 42, LPGENT("Hungry"), "hungry" }, + { 43, LPGENT("Hurt"), "hurt" }, + { 44, LPGENT("Impressed"), "impressed" }, + { 45, LPGENT("In awe"), "in_awe" }, + { 46, LPGENT("In love"), "in_love" }, + { 47, LPGENT("Indignant"), "indignant" }, + { 48, LPGENT("Interested"), "interested" }, + { 49, LPGENT("Intoxicated"), "intoxicated" }, + { 50, LPGENT("Invincible"), "invincible" }, + { 51, LPGENT("Jealous"), "jealous" }, + { 52, LPGENT("Lonely"), "lonely" }, + { 53, LPGENT("Lost"), "lost" }, + { 54, LPGENT("Lucky"), "lucky" }, + { 55, LPGENT("Mean"), "mean" }, + { 56, LPGENT("Moody"), "moody" }, + { 57, LPGENT("Nervous"), "nervous" }, + { 58, LPGENT("Neutral"), "neutral" }, + { 59, LPGENT("Offended"), "offended" }, + { 60, LPGENT("Outraged"), "outraged" }, + { 61, LPGENT("Playful"), "playful" }, + { 62, LPGENT("Proud"), "proud" }, + { 63, LPGENT("Relaxed"), "relaxed" }, + { 64, LPGENT("Relieved"), "relieved" }, + { 65, LPGENT("Remorseful"), "remorseful" }, + { 66, LPGENT("Restless"), "restless" }, + { 67, LPGENT("Sad"), "sad" }, + { 68, LPGENT("Sarcastic"), "sarcastic" }, + { 69, LPGENT("Satisfied"), "satisfied" }, + { 70, LPGENT("Serious"), "serious" }, + { 71, LPGENT("Shocked"), "shocked" }, + { 72, LPGENT("Shy"), "shy" }, + { 73, LPGENT("Sick"), "sick" }, + { 74, LPGENT("Sleepy"), "sleepy" }, + { 75, LPGENT("Spontaneous"), "spontaneous" }, + { 76, LPGENT("Stressed"), "stressed" }, + { 77, LPGENT("Strong"), "strong" }, + { 78, LPGENT("Surprised"), "surprised" }, + { 79, LPGENT("Thankful"), "thankful" }, + { 80, LPGENT("Thirsty"), "thirsty" }, + { 81, LPGENT("Tired"), "tired" }, + { 82, LPGENT("Undefined"), "undefined" }, + { 83, LPGENT("Weak"), "weak" }, + { 84, LPGENT("Worried"), "worried" }, +}; +// ====[ MY BITCHY LIST IMPLEMENTATION x)) ]================================== +// TODO: Optimize it all x)) + +template< class T > struct ListItem +{ + T* item; + ListItem* next; + + ListItem( ) + { + this->item = NULL; + this->next = NULL; + } + + ~ListItem( ) + { + delete this->item; + } + + ListItem( StatusItem* si ) + { + this->item = si; + this->next = NULL; + } + + ListItem( const ListItem& p ) + { + this->item = p.item; + this->next = NULL; + } +}; + + +template< class T > struct List +{ +private: + ListItem< T >* items; + unsigned int count; + +public: + typedef int ( *compareFunc )( const T* p1, const T* p2 ); + compareFunc compare; + + List( compareFunc compFnc ) + { + this->items = NULL; + this->count = 0; + this->compare = compFnc; + } + + ~List( ) + { + this->destroy( ); + } + + ListItem< T >* getListHead( ) + { + return items; + } + + unsigned int getCount( ) + { + return count; + } + + int add( T* csi ) + { + int position = 0; + ListItem< T >* item = new ListItem< T >( csi ); + if ( this->items == NULL ) + this->items = item; + else + { + ListItem< T >* help = item; + item->next = items; + while ( help->next != NULL ) + { + int cmp = compare( item->item, help->next->item ); + if ( cmp == 1 ) + help = help->next; + else if ( cmp == 0 ) + { + delete item; + return -1; + } + else + break; + position++; + } + if ( help != item ) + { + item->next = help->next; + help->next = item; + } + else + items = item; + } + this->count++; + return position; + } + + int remove( const unsigned int item ) + { + int position = 0; + if ( item < 0 || item >= this->count ) + return -1; + + ListItem< T >* help = items; + ListItem< T >* removed; + if ( item == 0 ) + { + items = items->next; + removed = help; + } + else + { + for ( unsigned int i = 0; i < item - 1; i++ ) + { + help = help->next; + position++; + } + removed = help->next; + help->next = help->next->next; + } + delete removed; + this->count--; + return position; + } + + T* get( const unsigned int item ) + { + ListItem< T >* help = items; + for ( unsigned int i = 0; i < item; i++ ) + help = help->next; + return help->item; + } + + T* operator[]( const unsigned int item ) + { + return get( item ); + } + + void destroy( ) + { + while ( this->count > 0 ) + this->remove( 0 ); + } +}; + + +// ====[ CLASSING -- FUNNY STUFF :) ]========================================= + +struct CSList; +struct CSWindow; +struct CSAMWindow; +struct CSItemsList; +struct CSListView; + +// -------- + +struct CSListView +{ + HWND handle; + CSWindow* parent; + + CSListView( HWND, CSWindow* ); + + void addItem( StatusItem* item, int itemNumber ); + void initItems( ListItem< StatusItem >* items ); + void reinitItems( ListItem< StatusItem >* items ); + void removeItems( ); + int getPositionInList( ); + void setFullFocusedSelection( int selection ); +}; + + +struct CSItemsList +{ + List< StatusItem >* list; + + static int compareItems( const StatusItem* p1, const StatusItem* p2 ); + void loadItems(char* protoName); + void saveItems(char* protoName); + + CSItemsList(char* protoName); + ~CSItemsList(); +}; + + +struct CSAMWindow +{ + WORD action; + StatusItem* item; + CSWindow* parent; + BOOL bChanged; + + HWND handle; + HWND hCombo; + HWND hMessage; + + CSAMWindow( WORD action, CSWindow* parent ); + ~CSAMWindow( ); + + void exec( ); + void setCombo( ); + void fillDialog( ); + void checkFieldLimit( WORD action, WORD item ); + void checkItemValidity(); +}; + + +struct CSWindow +{ + HWND handle; + BOOL bExtraIcons; + CSItemsList* itemslist; + CSListView* listview; + CSAMWindow* addModifyDlg; + HIMAGELIST icons; + BOOL bSomethingChanged; + TCHAR* filterString; + char* protoName; + CSWindow(char* protoName); + ~CSWindow(); + + void initIcons( ); + void deinitIcons( ); + void initButtons( ); + static void __cdecl showWindow( void* arg ); + static void __cdecl closeWindow( void* arg ); + void loadWindowPosition( ); + BOOL toggleButtons( ); + void toggleEmptyListMessage( ); + void toggleFilter( ); + BOOL itemPassedFilter( ListItem< StatusItem >* li ); + + void __inline saveWindowPosition( HWND hwnd ) + { + if ( getByte( "RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION ) == TRUE ) + { + RECT rect = { 0 }; + GetWindowRect( hwnd, &rect ); + setWord( "PositionX", rect.left ); + setWord( "PositionY", rect.top ); + } + } +}; + + +struct CSList +{ + // global variables + static HINSTANCE handle; + static DWORD dwMirandaVersion; + static BOOL bUnicodeCore; + static BOOL bAccountsSupported; + + // class components + CSWindow* mainWindow; + + // events + HANDLE hHookOnPluginsLoaded; + HANDLE hHookOnOptionsInit; + HANDLE hHookOnDBSettingChanged; + HANDLE hHookOnStatusMenuBuild; + + // services + HANDLE hServiceShowList; + + CSList( ); + ~CSList( ); + + // event functions + static int postLoading( WPARAM, LPARAM ); + static int initOptions( WPARAM, LPARAM ); + static int respondDBChange( WPARAM, LPARAM ); + static int createMenuItems( WPARAM, LPARAM ); + + // service functions + static INT_PTR __cdecl showList(WPARAM, LPARAM, LPARAM); + void closeList( HWND ); + + // protocols enumeration related functions + static void ForAllProtocols( pForAllProtosFunc pFunc, void* arg ); + static void __cdecl addProtoStatusMenuItem( char* protoName, void* arg ); + static void __cdecl countProtos( char* protoName, void* arg ); + static void __cdecl countPlusModProtos( char* protoName, void* arg ); + static void __cdecl importCustomStatusUIStatusesFromAllProtos( char* protoName, void* arg ); + + // other functions + void initIcoLib( ); + void registerHotkeys(char buf[200], TCHAR* accName, int Number); + void rebuildMenuItems( ); + void setStatus(WORD code, StatusItem* item, char* protoName); +}; + +HINSTANCE CSList::handle = NULL; +DWORD CSList::dwMirandaVersion = 0x00000000; +BOOL CSList::bUnicodeCore = FALSE; +BOOL CSList::bAccountsSupported = FALSE; + +// ====[ GLOBALS ]============================================================ + +CSList* cslist = NULL; + +// ====[ INIT STUFF ]========================================================= + +BOOL WINAPI DllMain( HINSTANCE, DWORD, LPVOID ); + +extern "C" __declspec( dllexport ) PLUGININFOEX* MirandaPluginInfoEx( DWORD ); + +extern "C" __declspec( dllexport ) int Load(void); +extern "C" __declspec( dllexport ) int Unload( void ); + + +// ====[ THREAD FORK ]======================================================== + +void ForkThread( pThreadFunc pFunc, void* arg ); + + +// ====[ PROCEDURES ]========================================================= + +INT_PTR CALLBACK CSWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); +INT_PTR CALLBACK CSAMWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); +INT_PTR CALLBACK CSRNWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); +INT_PTR CALLBACK CSOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); + + +// ====[ HELPERS ]============================================================ + +HICON LoadIconExEx( const char*, int ); + +void __fastcall SAFE_FREE(void** p) +{ + if (*p) + { + free(*p); + *p = NULL; + } +} + + +#endif /* __CSLIST_H */ diff --git a/plugins/CSList/src/legacy.h b/plugins/CSList/src/legacy.h new file mode 100644 index 0000000000..8ef63089d7 --- /dev/null +++ b/plugins/CSList/src/legacy.h @@ -0,0 +1,87 @@ +/* + + FILE INFO: Legacy functions of older Custom Status List versions + +*/ + +int cslist_import_v2_status_items( ); +int cslist_parse_row( TCHAR *row, int ord ); + +int cslist_import_v2_status_items( ) +{ + // get DB string, parse to statuses, add by helpItem + DBVARIANT dbv = { DBVT_TCHAR }; + int parseResult; + int dbLoadResult; + const TCHAR* rowDelim = _T( "" ); // new line + TCHAR *row = NULL; + + dbLoadResult = getTString( "listhistory", &dbv ); + if ( dbv.ptszVal ) + { + int i = getByte( "ItemsCount", DEFAULT_ITEMS_COUNT ); + row = _tcstok( dbv.ptszVal, rowDelim ); + while( row != NULL ) { + i++; + // process current row.. + parseResult = cslist_parse_row( row, i ); + // ..and go to the other, while some remains + row = _tcstok( NULL, rowDelim ); + } + setByte( "ItemsCount", i ); + } + //free( rowDelim ); + //free( row ); + return 0; +} + +int cslist_parse_row( TCHAR *row, int ord ) // parse + helpItem +{ + int pIconInt; + TCHAR pIcon[4], pTitle[EXTRASTATUS_TITLE_LIMIT+2], pMsg[EXTRASTATUS_MESSAGE_LIMIT+2], pFav[4]; + TCHAR scanfFormat[64]; + + lstrcpy( pTitle, _T( "" )); + lstrcpy( pMsg, _T( "" )); + + // database row format: "%2[^]%64[^]%2048[^]%2[^]" + + mir_sntprintf( + scanfFormat, + sizeof( scanfFormat ), + _T( "%%%d[^]%%%d[^]%%%d[^]%%%d[^]" ), // %% makes %, %d makes number :) + 2, + EXTRASTATUS_TITLE_LIMIT, + EXTRASTATUS_MESSAGE_LIMIT, + 2 + ); + + _tcscanf( row, scanfFormat, pIcon, pTitle, pMsg, pFav ); + + if ( lstrlen( pTitle ) + lstrlen( pMsg ) > 0 ) + { + char dbSetting[32]; + pIconInt = _ttoi( pIcon ); + mir_snprintf( dbSetting, sizeof( dbSetting ), "Item%dIcon", ord ); + setByte( dbSetting, pIconInt ); + mir_snprintf( dbSetting, sizeof( dbSetting ), "Item%dTitle", ord ); + setTString( dbSetting, pTitle ); + mir_snprintf( dbSetting, sizeof( dbSetting ), "Item%dMessage", ord ); + setTString( dbSetting, pMsg ); + mir_snprintf( dbSetting, sizeof( dbSetting ), "Item%dFavourite", ord ); + setByte( dbSetting, 0 ); + } + else { + return FALSE; + } + return TRUE; +} + + +void MessageBoxInt( int value1, int value2 ) +{ + TCHAR buf1[64], buf2[64]; + mir_sntprintf( buf1, SIZEOF( buf1 ), TEXT( "%d" ), value1 ); + mir_sntprintf( buf2, SIZEOF( buf2 ), TEXT( "%d" ), value2 ); + MessageBox( NULL, buf2, buf1, MB_OK ); +} diff --git a/plugins/CSList/src/resource.h b/plugins/CSList/src/resource.h new file mode 100644 index 0000000000..cec164739d --- /dev/null +++ b/plugins/CSList/src/resource.h @@ -0,0 +1,49 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by cslist.rc +// +#define IDCLOSE 8 +#define IDC_CANCEL 9 +#define IDD_CSLIST 101 +#define IDD_ADDMODIFY 102 +#define IDD_OPTIONS 103 +#define IDI_CSLIST 121 +#define IDI_ADD 122 +#define IDI_MODIFY 123 +#define IDI_REMOVE 124 +#define IDI_FAVOURITE 125 +#define IDI_UNDO 126 +#define IDI_GLOBAL 127 +#define IDI_FILTER 128 +#define IDI_CLOSE 129 +#define IDI_UNSET 130 +#define IDI_APPLY 131 +#define IDI_IMPORT 132 +#define IDC_CSLIST 1001 +#define IDC_FILTER_FIELD 1011 +#define IDC_ADD_SAMPLE 1012 +#define IDC_NO_ITEMS 1013 +#define IDC_ADD 1021 +#define IDC_MODIFY 1022 +#define IDC_REMOVE 1023 +#define IDC_FAVOURITE 1024 +#define IDC_UNDO 1025 +#define IDC_FILTER 1027 +#define IDC_COMBO 1041 +#define IDC_MESSAGE 1042 +#define IDC_CONFIRM_DELETION 1051 +#define IDC_DELETE_AFTER_IMPORT 1052 +#define IDC_IMPORT 1071 +#define IDC_ALLOW_EXTRA_ICONS 1204 +#define IDC_REMEMBER_POSITION 1207 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_CONTROL_VALUE 1209 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/CSList/src/strpos.h b/plugins/CSList/src/strpos.h new file mode 100644 index 0000000000..210bfddf0a --- /dev/null +++ b/plugins/CSList/src/strpos.h @@ -0,0 +1,70 @@ +/* + * strpos.c - Returns the offset of a string in a substring. + * + * Copyright (c) 2001, 2002 Andre Guibert de Bruet. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * You might want to place this next block in a header file somewhere: + */ + + +# ifndef TCHAR +# define TCHAR wchar_t +# endif /* TCHAR */ +# define STRING wchar_t * + + + + +int strpos( STRING haystack, STRING needle ) +{ + STRING pDest; + int position; + +#ifdef DEBUG_VERBOSE + TCHAR lpBuf[1024]; +#endif /* def DEBUG_VERBOSE */ + + pDest = (STRING) wcsstr( haystack, needle ); + + + if ( pDest ) + position = pDest - haystack; + else + { +#ifdef DEBUG_VERBOSE + printf( L"strpos(): Could not find '%s' in '%s'.\tFAIL.", needle, haystack ); +#endif /* def DEBUG_VERBOSE */ + return -1; + } + +#ifdef DEBUG_VERBOSE + printf( L"strpos(): Found '%s' at position: %d.\t\tOK.", needle, position ); +#endif /* def DEBUG_VERBOSE */ + + return position; +} -- cgit v1.2.3