From 15cb1c735a559b88c7ede033510d8f106eb9e314 Mon Sep 17 00:00:00 2001 From: Rozhuk Ivan Date: Wed, 26 Nov 2014 23:06:03 +0000 Subject: UInfoEx: code cleanup, req for review git-svn-id: http://svn.miranda-ng.org/main/trunk@11108 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/UserInfoEx/src/classPsTree.cpp | 1955 ++++++++++---------- plugins/UserInfoEx/src/ctrl_edit.cpp | 741 ++++---- .../src/ex_import/classExImContactBase.cpp | 1075 +++++------ plugins/UserInfoEx/src/ex_import/svc_ExImINI.cpp | 1049 ++++++----- plugins/UserInfoEx/src/mir_string.cpp | 266 +-- plugins/UserInfoEx/src/svc_timezone.cpp | 156 +- 6 files changed, 2628 insertions(+), 2614 deletions(-) (limited to 'plugins') diff --git a/plugins/UserInfoEx/src/classPsTree.cpp b/plugins/UserInfoEx/src/classPsTree.cpp index f0d763ee9e..aecab3b6a7 100644 --- a/plugins/UserInfoEx/src/classPsTree.cpp +++ b/plugins/UserInfoEx/src/classPsTree.cpp @@ -1,978 +1,977 @@ -/* -UserinfoEx plugin for Miranda IM - -Copyright: -© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol - -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 "commonheaders.h" - -/*********************************************************************************************************** - * construction and destruction - ***********************************************************************************************************/ - -/** - * name: CPsTree - * class: CPsTree - * desc: constructor - * param: none - * return: none - **/ -CPsTree::CPsTree(LPPS pPs) -{ - _hWndTree = NULL; - _hImages = NULL; - - _pItems = NULL; - _numItems = 0; - _curItem = -1; - _dwFlags = 0; - _hLabelEdit = NULL; - _hDragItem = NULL; - _isDragging = FALSE; - _pPs = pPs; -} - -/** - * name: ~CPsTree - * class: CPsTree - * desc: frees up all memory, used by the tree control - * return: nothing - **/ -CPsTree::~CPsTree() -{ - if (_hLabelEdit) - { - DestroyWindow(_hLabelEdit); - _hLabelEdit = NULL; - } - if (_pItems) - { - for (int i = 0; i < _numItems; i++) - { - if (_pItems[i]) - { - delete _pItems[i]; - _pItems[i] = NULL; - } - } - MIR_FREE(_pItems); - _pItems = NULL; - _numItems = NULL; - } - ImageList_Destroy(_hImages); - _hImages = NULL; -} - -/** - * name: CPsTree - * class: CPsTree - * desc: constructor - * param: none - * return: none - **/ -BYTE CPsTree::Create(HWND hWndTree, CPsHdr* pPsh) -{ - BYTE rc; - - if (hWndTree && pPsh->_hImages && pPsh->_pPages && pPsh->_numPages) - { - _hWndTree = hWndTree; - _hImages = pPsh->_hImages; - _pItems = pPsh->_pPages; - _numItems = pPsh->_numPages; - _dwFlags = pPsh->_dwFlags; - - TreeView_SetImageList(_hWndTree, _hImages, TVSIL_NORMAL); - TreeView_SetItemHeight(_hWndTree, TreeView_GetItemHeight(_hWndTree) + 4); - SetUserData(_hWndTree, this); - rc = TRUE; - } - else - { - rc = FALSE; - } - return rc; -} - -/** - * name: AddDummyItem - * class: CPsTree - * desc: insert an empty tree item group - * param: pszGroup - utf8 encoded string of the item to add - * return: index of the new item or -1 if failed to add - **/ -int CPsTree::AddDummyItem(LPCSTR pszGroup) -{ - if (mir_stricmp(pszGroup, TREE_ROOTITEM)) - { - CPsHdr psh; - psh._hContact = _pPs->hContact; - psh._pszProto = _pPs->pszProto; - psh._hImages = _hImages; - psh._pPages = _pItems; - psh._numPages = _numItems; - - OPTIONSDIALOGPAGE odp = { sizeof(odp) }; - odp.hInstance = ghInst; - odp.flags = ODPF_TCHAR; - odp.ptszTitle = mir_utf8decodeT(pszGroup); - - INT_PTR rc = UserInfo_AddPage((WPARAM)&psh, &odp); - mir_free(odp.ptszTitle); - if (!rc) { - _pItems = psh._pPages; - _numItems = psh._numPages; - return _numItems - 1; - } - } - return -1; -} - -/** - * name: InitTreeItems() - * desc: initialize the tree control's datastructure - * param: needWidth - width to expand the tree by - * return: TRUE if initialization is ok, FALSE otherwise - **/ -BYTE CPsTree::InitTreeItems(LPWORD needWidth) -{ - int i; - DBVARIANT dbv; - - if (!_hWndTree || !_pItems) - { - return FALSE; - } - - if (!DB::Setting::GetUString(NULL, MODNAME, SET_LASTITEM, &dbv)) - { - _curItem = FindItemIndexByName(dbv.pszVal); - db_free(&dbv); - } - - // init the groups - if ((_dwFlags & PSTVF_GROUPS) || (!_pPs->hContact && myGlobals.CanChangeDetails)) - { - LPSTR pszGroup; - - // set treeview styles - TreeView_SetIndent(_hWndTree, 3); - SetWindowLongPtr(_hWndTree, GWL_STYLE, GetWindowLongPtr(_hWndTree, GWL_STYLE)|TVS_HASBUTTONS); - - // init the iParent member for all the items - for (i = 0; i < _numItems; i++) - { - if (_pItems[i] && (pszGroup = _pItems[i]->ParentItemName()) != NULL) - { - int iParent = FindItemIndexByName(pszGroup); - - // need to add an empty parent item - if (iParent == -1) - iParent = AddDummyItem(pszGroup); - - _pItems[i]->Parent(iParent); - mir_free(pszGroup); - } - } - } - - if (needWidth) - { - *needWidth = 0; - } - ShowWindow(_hWndTree, SW_HIDE); - for (i = 0; i < _numItems; i++) - { - if (_pItems[i]->State() != DBTVIS_INVISIBLE) - { - ShowItem(i, needWidth); - } - } - ShowWindow(_hWndTree, SW_SHOW); - return TRUE; -} - -/*********************************************************************************************************** - * finding items - ***********************************************************************************************************/ - -/** - * name: FindItemIndexByHandle - * class: CPsTree - * desc: returns the treeitem with specified handle - * param: hItem - handle of the treeview's treeitem - * return: HTREEITEM if item exists or NULL otherwise - **/ -int CPsTree::FindItemIndexByHandle(HTREEITEM hItem) -{ - int i; - for (i = 0; i < _numItems; i++) - { - if (_pItems[i] && hItem == _pItems[i]->Hti()) - { - return i; - } - } - return -1; -} - -/** - * name: FindItemIndexByHandle - * class: CPsTree - * desc: returns the treeitem with specified handle - * param: hItem - handle of the treeview's treeitem - * return: HTREEITEM if item exists or NULL otherwise - **/ -int CPsTree::FindItemIndexByName(LPCSTR pszName) -{ - int i; - for (i = 0; i < _numItems; i++) - { - if (_pItems[i] && _pItems[i]->HasName(pszName)) - { - return i; - } - } - return -1; -} - -/** - * name: FindItemByHandle - * class: CPsTree - * desc: returns the treeitem with specified handle - * param: hItem - handle of the treeview's treeitem - * return: HTREEITEM if item exists or NULL otherwise - **/ -CPsTreeItem* CPsTree::FindItemByHandle(HTREEITEM hItem) -{ - int i; - - if ((i = FindItemIndexByHandle(hItem)) > -1) - { - return _pItems[i]; - } - return NULL; -} - -/** - * name: FindItemByName - * class: CPsTree - * desc: returns the treeitem with specified name - * param: pszName - name of the item to search for - * return: HTREEITEM if item exists or NULL otherwise - **/ -CPsTreeItem* CPsTree::FindItemByName(LPCSTR pszName) -{ - int i; - - if ((i = FindItemIndexByName(pszName)) > -1) - { - return _pItems[i]; - } - return NULL; -} - -/** - * name: FindItemByHandle - * class: CPsTree - * desc: returns the treeitem with specified handle - * param: hItem - handle of the treeview's treeitem - * return: HTREEITEM if item exists or NULL otherwise - **/ -CPsTreeItem* CPsTree::FindItemByResource(HINSTANCE hInst, int idDlg) -{ - int i; - for (i = 0; i < _numItems; i++) - { - if (_pItems[i] && _pItems[i]->Inst() == hInst && _pItems[i]->DlgId() == idDlg) - { - return _pItems[i]; - } - } - return NULL; -} - - -/** - * name: FindItemHandleByName - * class: CPsTree - * desc: returns the treeitem with specified name - * param: pszName - name of the item to search for - * return: HTREEITEM if item exists or NULL otherwise - **/ -HTREEITEM CPsTree::FindItemHandleByName(LPCSTR pszName) -{ - int i; - - if ((i = FindItemIndexByName(pszName)) > -1) - { - return _pItems[i]->Hti(); - } - return NULL; -} - -/*********************************************************************************************************** - * public methods - ***********************************************************************************************************/ - - -/** - * name: HideItem - * class: CPsTree - * desc: is called if icolib's icons have changed - * param: iPageIndex - the index of the treeitem in the array. - * return: nothing - **/ -void CPsTree::HideItem(const int iPageIndex) -{ - if (IsIndexValid(iPageIndex)) - { - TreeView_DeleteItem(_hWndTree, _pItems[iPageIndex]->Hti()); - _pItems[iPageIndex]->Hti(0); - _dwFlags |= PSTVF_STATE_CHANGED; - } -} - -/** - * name: ShowItem - * class: CPsTree - * desc: displays on of the items in the treeview - * param: iPageIndex - the index of the treeitem in the array. - * needWidth - gives and takes the width, the treeview must have to show all items properly - * return: TRUE if item was added successfully, FALSE otherwise - **/ -HTREEITEM CPsTree::ShowItem(const int iPageIndex, LPWORD needWidth) -{ - TVINSERTSTRUCT tvii; - CPsTreeItem *pti; - - // check parameters - if (!_hWndTree || - !IsIndexValid(iPageIndex) || - !(pti = _pItems[iPageIndex]) || - !pti->Name() || - !pti->Label()) - { - MsgErr(GetParent(_hWndTree), LPGENT("Due to a parameter error, one of the treeitems can't be added!")); - return NULL; - } - // item is visible at the moment - if ((tvii.itemex.hItem = pti->Hti()) == NULL) - { - RECT rc; - const int iParent = pti->Parent(); - - // init the rest of the treeitem - tvii.hParent = IsIndexValid(iParent) ? ShowItem(iParent, needWidth) : NULL; - tvii.hInsertAfter = (_dwFlags & PSTVF_SORTTREE) ? TVI_SORT : TVI_LAST; - tvii.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE; - tvii.itemex.pszText = pti->Label(); - tvii.itemex.state = pti->State() == DBTVIS_EXPANDED ? TVIS_EXPANDED : 0; - tvii.itemex.stateMask = TVIS_EXPANDED; - tvii.itemex.lParam = iPageIndex; - // set images - if ((tvii.itemex.iImage = tvii.itemex.iSelectedImage = pti->Image()) != -1) - { - tvii.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE; - } - // insert item into tree if set visible - if ((tvii.itemex.hItem = TreeView_InsertItem(_hWndTree, &tvii)) == NULL) - { - MsgErr(GetParent(_hWndTree), LPGENT("A fatal error occurred on adding a property sheet page!\nDialog creation aborted!")); - return NULL; - } - pti->Hti(tvii.itemex.hItem); - // calculate width of treeview - if (needWidth && TreeView_GetItemRect(_hWndTree, pti->Hti(), &rc, TRUE) && rc.right > *needWidth) - { - *needWidth = (WORD)rc.right; - } - } - return tvii.itemex.hItem; -} - -/** - * name: MoveItem() - * class: CPsTree - * desc: moves a treeitem and its children to a new position - * param: pPs - datastructure of the propertysheetpage - * hItem - the HTREEITEM to move - * hInsertAfter - the HTREEITEM to insert hItem after - * bAsChild - tells, whether to try to add hItem as child of hInsertAfter or not - * return: handle to new (moved) treeitem if successful or NULL otherwise - **/ -HTREEITEM CPsTree::MoveItem(HTREEITEM hItem, HTREEITEM hInsertAfter, BYTE bAsChild) -{ - TVINSERTSTRUCT tvis; - HTREEITEM hParent, hChild, hNewItem; - int iItemIndex; - - if (!hItem || !hInsertAfter) - return NULL; - if (hItem == hInsertAfter) - return hItem; - - switch ((ULONG_PTR)hInsertAfter) { - case TVI_ROOT: - case TVI_FIRST: - case TVI_LAST: - hParent = NULL; - bAsChild = FALSE; - break; - default: - hParent = TreeView_GetParent(_hWndTree, hInsertAfter); - break; - } - // do not move a parent next to its own children! - if (hItem == hParent) - return hItem; - // get detailed information about the item to move - if (FAILED(iItemIndex = FindItemIndexByHandle(hItem))) - return hItem; - - // item should be inserted as the first child of an existing root item - if (bAsChild) { - tvis.hParent = hInsertAfter; - tvis.hInsertAfter = (_dwFlags & PSTVF_SORTTREE) ? TVI_SORT : ((bAsChild == 2) ? TVI_LAST : TVI_FIRST); - } - // item should be inserted after an existing item - else { - tvis.hParent = hParent; - tvis.hInsertAfter = hInsertAfter; - } - - // don't move subitems of a protocol to root as this would mean them not to be unique anymore - if (!_pPs->hContact && (_pItems[iItemIndex]->Flags() & PSPF_PROTOPREPENDED) && !tvis.hParent) - return hItem; - - // prepare the insert structure - tvis.itemex.mask = TVIF_PARAM|TVIF_TEXT; - tvis.itemex.state = TVIS_EXPANDED; - tvis.itemex.stateMask = TVIS_EXPANDED; - tvis.itemex.pszText = _pItems[iItemIndex]->Label(); - tvis.itemex.lParam = (LPARAM)iItemIndex; - if ((tvis.itemex.iImage = tvis.itemex.iSelectedImage = _pItems[iItemIndex]->Image()) >= 0) - tvis.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE; - - // insert the item - if (!(hNewItem = TreeView_InsertItem(_hWndTree, &tvis))) - return hItem; - // update handle pointer in the page structure - _pItems[iItemIndex]->Hti(hNewItem); - // get the index of the parent - _pItems[iItemIndex]->Parent(FindItemIndexByHandle(tvis.hParent)); - // move children - hInsertAfter = hNewItem; - while (hChild = TreeView_GetChild(_hWndTree, hItem)) { - MoveItem(hChild, hInsertAfter, 2); - } - // delete old tree - TreeView_DeleteItem(_hWndTree, hItem); - _dwFlags |= PSTVF_POS_CHANGED; - - TreeView_SelectItem(_hWndTree, hNewItem); - TreeView_Expand(_hWndTree, hNewItem, TVE_EXPAND); - return hNewItem; -} - -/** - * name: SaveItemsState - * class: CPsTree - * desc: saves the tree's visible items to database - * param: pszGroup - name of the parent item of the current subtree - * hRootItem - the root of the current subtree - * iItem - index of the current item for position saving - * return: 0 on success or 1 otherwise - **/ -WORD CPsTree::SaveItemsState(LPCSTR pszGroup, HTREEITEM hRootItem, int& iItem) -{ - TVITEMEX tvi; - WORD numErrors = 0; - - tvi.mask = TVIF_CHILDREN|TVIF_STATE|TVIF_PARAM; - tvi.state = 0; - tvi.stateMask = TVIS_EXPANDED; - tvi.lParam = (LPARAM)-1; - - // save all visible items - for (tvi.hItem = TreeView_GetChild(_hWndTree, hRootItem); - TreeView_GetItem(_hWndTree, &tvi); - tvi.hItem = TreeView_GetNextSibling(_hWndTree, tvi.hItem)) - { - numErrors += _pItems[tvi.lParam]->DBSaveItemState(pszGroup, iItem++, tvi.state, _dwFlags); - if (tvi.cChildren) numErrors += SaveItemsState(_pItems[tvi.lParam]->Name(), tvi.hItem, iItem); - } - return numErrors; -} - -/** - * name: SaveState - * class: CPsTree - * desc: saves the current tree to database - * param: none - * return: nothing - **/ -void CPsTree::SaveState() -{ - CPsTreeItem *pti = CurrentItem(); - - if (_hWndTree && (_dwFlags & (PSTVF_LABEL_CHANGED|PSTVF_POS_CHANGED|PSTVF_STATE_CHANGED))) { - SHORT i; - int iItem = 0; - - // save all visible items - WORD numErrors = SaveItemsState(TREE_ROOTITEM, TVGN_ROOT, iItem); - - // save all invisible items of the current subtree - for (i = 0; i < _numItems; i++) { - if (!_pItems[i]->Hti()) { - LPSTR pszGroup; - - if (!IsIndexValid(_pItems[i]->Parent()) || !(pszGroup = _pItems[_pItems[i]->Parent()]->Name())) - pszGroup = TREE_ROOTITEM; - numErrors += _pItems[i]->DBSaveItemState(pszGroup, iItem++, DBTVIS_INVISIBLE, _dwFlags); - } - } - // remove changed flags - RemoveFlags(PSTVF_STATE_CHANGED|PSTVF_LABEL_CHANGED|PSTVF_POS_CHANGED); - } - - // save current selected item - if (pti) db_set_utf(NULL, MODNAME, SET_LASTITEM, pti->Name()); - else db_unset(NULL, MODNAME, SET_LASTITEM); -} - -/** - * name: DBResetState - * class: CPsTree - * desc: delete all treesettings from database - * param: pszGroup - name of the parent item of the current subtree - * hRootItem - the root of the current subtree - * iItem - index of the current item for position saving - * return: 0 on success or 1 otherwise - **/ -void CPsTree::DBResetState() -{ - DB::CEnumList Settings; - - if (!Settings.EnumSettings(NULL, MODNAME)) - { - int i; - LPSTR s; - LPCSTR p; - INT_PTR c; - - p = (_pPs->pszProto[0]) ? _pPs->pszProto : "Owner"; - c = mir_strlen(p); - - for (i = 0; i < Settings.getCount(); i++) - { - s = Settings[i]; - - if (s && *s == '{' && !mir_strnicmp(s + 1, p, c)) - { - db_unset(NULL, MODNAME, s); - } - } - // keep only these flags - _dwFlags &= PSTVF_SORTTREE|PSTVF_GROUPS; - } -} - -/*********************************************************************************************************** - * public methods for handling label editing - ***********************************************************************************************************/ - -/** - * name: TPropsheetTree_LabelEditProc() - * desc: subclussproc of the label editcontrol - * return: 0 - **/ -static LRESULT CALLBACK TPropsheetTree_LabelEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) -{ - switch(uMsg) { - case WM_KEYDOWN: - switch(wParam) { - case VK_RETURN: - return ((CPsTree*)GetUserData(hwnd))->EndLabelEdit(TRUE); - case VK_TAB: - case VK_ESCAPE: - return ((CPsTree*)GetUserData(hwnd))->EndLabelEdit(FALSE); - } - break; - - case WM_KILLFOCUS: - ((CPsTree*)GetUserData(hwnd))->EndLabelEdit(FALSE); - break; - - case WM_GETDLGCODE: - return DLGC_WANTALLKEYS | mir_callNextSubclass(hwnd, TPropsheetTree_LabelEditProc, uMsg, wParam, lParam ); - } - return mir_callNextSubclass(hwnd, TPropsheetTree_LabelEditProc, uMsg, wParam, lParam); -} - -/** - * name: BeginLabelEdit - * class: CPsTree - * desc: begins the labeledit mode - * param: hItem - handle of the treeitm whose label to edit - * return: 0 - **/ -int CPsTree::BeginLabelEdit(HTREEITEM hItem) -{ - CPsTreeItem* pti; - - // tree is readonly - if (db_get_b(NULL, MODNAME, SET_PROPSHEET_READONLYLABEL, 0)) - return 0; - - // get item text - if (!hItem && !(hItem = TreeView_GetSelection(_hWndTree))) - return 0; - if (pti = FindItemByHandle(hItem)) - { - RECT rc, rcTree; - - // create the edit control - GetClientRect(_hWndTree, &rcTree); - TreeView_GetItemRect(_hWndTree, hItem, &rc, TRUE); - _hLabelEdit = CreateWindowEx(WS_EX_NOPARENTNOTIFY|WS_EX_CLIENTEDGE, - _T( "EDIT" ), - pti->Label(), - WS_VISIBLE|ES_AUTOHSCROLL|WS_CHILD, - rc.left, rc.top, - rcTree.right - rc.left, rc.bottom - rc.top, - _hWndTree, - NULL, - ghInst, - NULL ); - if (_hLabelEdit) - { - _hDragItem = hItem; - SetUserData(_hLabelEdit, this); - mir_subclassWindow(_hLabelEdit, TPropsheetTree_LabelEditProc); - SendMessage(_hLabelEdit, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0 ); - Edit_SetSel(_hLabelEdit, 0, -1); - Edit_LimitText(_hLabelEdit, MAX_TINAME); - SetFocus(_hLabelEdit); - return 0; - } - } - return 1; -} - -/** - * name: EndLabelEdit - * class: CPsTree - * desc: exits the labeledit mode - * bSave - tell whether to save changes or not - * return: 0 - **/ -int CPsTree::EndLabelEdit(const BYTE bSave) -{ - TCHAR szEdit[MAX_TINAME]; - TVITEM tvi; - WORD cchEdit; - - if (bSave && (cchEdit = Edit_GetText(_hLabelEdit, szEdit, MAX_TINAME)) > 0) - { - tvi.hItem = _hDragItem; - tvi.mask = TVIF_TEXT|TVIF_HANDLE; - tvi.pszText = szEdit; - if (TreeView_SetItem(_hWndTree, &tvi)) - { - CPsTreeItem* pti; - if (pti = FindItemByHandle(_hDragItem)) - { - pti->Rename(szEdit); - } - _dwFlags |= PSTVF_LABEL_CHANGED; - } - } - DestroyWindow(_hLabelEdit); - _hLabelEdit = NULL; - _hDragItem = NULL; - return 0; -} - -/*********************************************************************************************************** - * public methods for handling other commands - ***********************************************************************************************************/ - -void CPsTree::PopupMenu() -{ - HMENU hPopup; - MENUITEMINFO mii; - TVHITTESTINFO hti; - TVITEM tvi; - POINT pt; - int iItem, i; - - // init popup menu - if (!(hPopup = CreatePopupMenu())) - return; - ZeroMemory(&mii, sizeof(MENUITEMINFO)); - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STRING|MIIM_ID; - - // get cursor postion - GetCursorPos(&pt); - hti.pt = pt; - ScreenToClient(_hWndTree, &hti.pt); - - tvi.mask = TVIF_PARAM|TVIF_CHILDREN; - // find treeitem under cursor - TreeView_HitTest(_hWndTree, &hti); - if (hti.flags & (TVHT_ONITEM|TVHT_ONITEMRIGHT)) { - tvi.hItem = hti.hItem; - TreeView_GetItem(_hWndTree, &tvi); - - if (!db_get_b(NULL, MODNAME, SET_PROPSHEET_READONLYLABEL, FALSE)) { - mii.dwTypeData = TranslateT("Rename Item"); - mii.wID = 32001; - InsertMenuItem(hPopup, 0, FALSE, &mii); - } - - // do not allow hiding groups - if (tvi.cChildren) { - mii.fMask |= MIIM_STATE; - mii.fState = MFS_DISABLED; - } - mii.dwTypeData = TranslateT("Hide Item"); - mii.wID = 32000; - InsertMenuItem(hPopup, 0, FALSE, &mii); - } - else { - // add hidden items to menu - mii.wID = 0; - for (i = 0; i < _numItems; i++) { - if (!_pItems[i]->Hti()) { - mii.dwTypeData = _pItems[i]->Label(); - mii.wID = 100 + i; - InsertMenuItem(hPopup, 0, FALSE, &mii); - } - } - // add headline - if (mii.wID > 0) { - mii.fMask |= MIIM_STATE; - mii.fState = MFS_DISABLED; - mii.dwTypeData = TranslateT("Show Items:"); - mii.wID = 0; - InsertMenuItem(hPopup, 0, TRUE, &mii); - mii.fMask |= MIIM_FTYPE; - mii.fType = MFT_SEPARATOR; - InsertMenuItem(hPopup, 1, TRUE, &mii); - InsertMenuItem(hPopup, ++i, TRUE, &mii); - } - mii.fMask &= ~(MIIM_FTYPE|MIIM_STATE); - mii.dwTypeData = TranslateT("Reset to defaults"); - mii.wID = 32004; - InsertMenuItem(hPopup, ++i, TRUE, &mii); - } - // show the popup menu - iItem = TrackPopupMenu(hPopup, TPM_RETURNCMD, pt.x, pt.y, 0, _hWndTree, NULL); - DestroyMenu(hPopup); - - switch (iItem) { - // hide the item - case 32000: - HideItem(tvi.lParam); - break; - // rename the item - case 32001: - BeginLabelEdit(tvi.hItem); - break; - // reset current tree - case 32004: - DBResetState(); - break; - // show a hidden item - default: - if ((iItem -= 100) >= 0 && ShowItem(iItem, NULL)) - AddFlags(PSTVF_STATE_CHANGED|PSTVF_POS_CHANGED); - break; - } -} - -/*********************************************************************************************************** - * public event handlers - ***********************************************************************************************************/ - -/** - * name: OnIconsChanged - * class: CPsTree - * desc: is called if icolib's icons have changed - * param: none - * return: nothing - **/ -void CPsTree::OnIconsChanged() -{ - for (int i = 0; i < _numItems; i++) { - _pItems[i]->OnIconsChanged(this); - } -} - -/** - * name: OnInfoChanged - * class: CPsTree - * desc: contact information have changed and pages need an update - * param: none - * return: TRUE if any page holds changed information - **/ -BYTE CPsTree::OnInfoChanged() -{ - PSHNOTIFY pshn; - int i; - BYTE bChanged = 0; - - pshn.hdr.idFrom = 0; - pshn.hdr.code = PSN_INFOCHANGED; - for (i = 0; i < _numItems; i++) { - pshn.hdr.hwndFrom = _pItems[i]->Wnd(); - if (pshn.hdr.hwndFrom != NULL) { - pshn.lParam = (LPARAM)_pItems[i]->hContact(); - SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn); - if (PSP_CHANGED == GetWindowLongPtr(pshn.hdr.hwndFrom, DWLP_MSGRESULT)) - bChanged |= 1; - else - _pItems[i]->RemoveFlags(PSPF_CHANGED); - } - } - return bChanged; -} - -/** - * name: OnSelChanging - * class: CPsTree - * desc: the displayed page is up to change - * param: none - * return: nothing - **/ -BYTE CPsTree::OnSelChanging() -{ - CPsTreeItem *pti = CurrentItem(); - - if (pti != NULL) { - TreeView_SetItemState(_hWndTree, pti->Hti(), 0, TVIS_SELECTED); - if (pti->Wnd() != NULL) { - PSHNOTIFY pshn; - - pshn.hdr.code = PSN_KILLACTIVE; - pshn.hdr.hwndFrom = pti->Wnd(); - pshn.hdr.idFrom = 0; - pshn.lParam = (LPARAM)pti->hContact(); - if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn)) { - SetWindowLongPtr(_pPs->hDlg, DWLP_MSGRESULT, TRUE); - return TRUE; - } - } - } - return FALSE; -} - -/** - * name: OnSelChanged - * class: CPsTree - * desc: it handles the change of displayed page - * param: lpnmtv - notification structure - * return: nothing - **/ -void CPsTree::OnSelChanged(LPNMTREEVIEW lpnmtv) -{ - CPsTreeItem *oldPage = CurrentItem(); - CPsTreeItem *pti; - - _curItem = (int)lpnmtv->itemNew.lParam; - if (pti = CurrentItem()) { - if (pti->Wnd() == NULL) { - pti->CreateWnd(_pPs); - } - } - // hide old page even if new item has no valid one - if (oldPage && oldPage->Wnd() != NULL) - ShowWindow(oldPage->Wnd(), SW_HIDE); - if (pti) - ShowWindow(pti->Wnd(), SW_SHOW); - if (lpnmtv->action != TVC_BYMOUSE) - SetFocus(_hWndTree); -} - -/** - * name: OnCancel - * class: CPsTree - * desc: asks pages to reset their information - * param: none - * return: nothing - **/ -void CPsTree::OnCancel() -{ - PSHNOTIFY pshn; - int i; - - pshn.hdr.idFrom = 0; - pshn.hdr.code = PSN_RESET; - for (i = 0; i < _numItems; i++) { - pshn.hdr.hwndFrom = _pItems[i]->Wnd(); - if (pshn.hdr.hwndFrom && (_pItems[i]->Flags() & PSPF_CHANGED)) { - pshn.lParam = (LPARAM)_pItems[i]->hContact(); - SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn); - } - } -} - -/** - * name: OnApply - * class: CPsTree - * desc: saves settings of all pages - * param: none - * return: 0 if ready to continue, 1 if need to abort - **/ -int CPsTree::OnApply() -{ - CPsTreeItem *pti = CurrentItem(); - - if (pti != NULL) { - PSHNOTIFY pshn; - int i; - - pshn.hdr.idFrom = 0; - pshn.hdr.code = PSN_KILLACTIVE; - pshn.hdr.hwndFrom = pti->Wnd(); - if (!SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn)) { - // save everything to database - pshn.hdr.code = PSN_APPLY; - for (i = 0; i < _numItems; i++) { - pshn.lParam = (LPARAM)_pItems[i]->hContact(); - if (_pItems[i] && _pItems[i]->Wnd() && _pItems[i]->Flags() & PSPF_CHANGED) { - pshn.hdr.hwndFrom = _pItems[i]->Wnd(); - if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn) == PSNRET_INVALID_NOCHANGEPAGE) { - CPsTreeItem *pti; - if (pti = CurrentItem()) - ShowWindow(pti->Wnd(), SW_HIDE); - _curItem = i; - ShowWindow(_pItems[i]->Wnd(), SW_SHOW); - return 1; - } - _pItems[i]->RemoveFlags(PSPF_CHANGED); - } - } - return 0; - } - } - return 1; -} +/* +UserinfoEx plugin for Miranda IM + +Copyright: +© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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 "commonheaders.h" + +/*********************************************************************************************************** + * construction and destruction + ***********************************************************************************************************/ + +/** + * name: CPsTree + * class: CPsTree + * desc: constructor + * param: none + * return: none + **/ +CPsTree::CPsTree(LPPS pPs) +{ + _hWndTree = NULL; + _hImages = NULL; + + _pItems = NULL; + _numItems = 0; + _curItem = -1; + _dwFlags = 0; + _hLabelEdit = NULL; + _hDragItem = NULL; + _isDragging = FALSE; + _pPs = pPs; +} + +/** + * name: ~CPsTree + * class: CPsTree + * desc: frees up all memory, used by the tree control + * return: nothing + **/ +CPsTree::~CPsTree() +{ + if (_hLabelEdit) + { + DestroyWindow(_hLabelEdit); + _hLabelEdit = NULL; + } + if (_pItems) + { + for (int i = 0; i < _numItems; i++) + { + if (_pItems[i]) + { + delete _pItems[i]; + _pItems[i] = NULL; + } + } + MIR_FREE(_pItems); + _pItems = NULL; + _numItems = NULL; + } + ImageList_Destroy(_hImages); + _hImages = NULL; +} + +/** + * name: CPsTree + * class: CPsTree + * desc: constructor + * param: none + * return: none + **/ +BYTE CPsTree::Create(HWND hWndTree, CPsHdr* pPsh) +{ + BYTE rc; + + if (hWndTree && pPsh->_hImages && pPsh->_pPages && pPsh->_numPages) + { + _hWndTree = hWndTree; + _hImages = pPsh->_hImages; + _pItems = pPsh->_pPages; + _numItems = pPsh->_numPages; + _dwFlags = pPsh->_dwFlags; + + TreeView_SetImageList(_hWndTree, _hImages, TVSIL_NORMAL); + TreeView_SetItemHeight(_hWndTree, TreeView_GetItemHeight(_hWndTree) + 4); + SetUserData(_hWndTree, this); + rc = TRUE; + } + else + { + rc = FALSE; + } + return rc; +} + +/** + * name: AddDummyItem + * class: CPsTree + * desc: insert an empty tree item group + * param: pszGroup - utf8 encoded string of the item to add + * return: index of the new item or -1 if failed to add + **/ +int CPsTree::AddDummyItem(LPCSTR pszGroup) +{ + if (mir_stricmp(pszGroup, TREE_ROOTITEM)) + { + CPsHdr psh; + psh._hContact = _pPs->hContact; + psh._pszProto = _pPs->pszProto; + psh._hImages = _hImages; + psh._pPages = _pItems; + psh._numPages = _numItems; + + OPTIONSDIALOGPAGE odp = { sizeof(odp) }; + odp.hInstance = ghInst; + odp.flags = ODPF_TCHAR; + odp.ptszTitle = mir_utf8decodeT(pszGroup); + + INT_PTR rc = UserInfo_AddPage((WPARAM)&psh, &odp); + mir_free(odp.ptszTitle); + if (!rc) { + _pItems = psh._pPages; + _numItems = psh._numPages; + return _numItems - 1; + } + } + return -1; +} + +/** + * name: InitTreeItems() + * desc: initialize the tree control's datastructure + * param: needWidth - width to expand the tree by + * return: TRUE if initialization is ok, FALSE otherwise + **/ +BYTE CPsTree::InitTreeItems(LPWORD needWidth) +{ + int i; + DBVARIANT dbv; + + if (!_hWndTree || !_pItems) + { + return FALSE; + } + + if (!DB::Setting::GetUString(NULL, MODNAME, SET_LASTITEM, &dbv)) + { + _curItem = FindItemIndexByName(dbv.pszVal); + db_free(&dbv); + } + + // init the groups + if ((_dwFlags & PSTVF_GROUPS) || (!_pPs->hContact && myGlobals.CanChangeDetails)) + { + LPSTR pszGroup; + + // set treeview styles + TreeView_SetIndent(_hWndTree, 3); + SetWindowLongPtr(_hWndTree, GWL_STYLE, GetWindowLongPtr(_hWndTree, GWL_STYLE)|TVS_HASBUTTONS); + + // init the iParent member for all the items + for (i = 0; i < _numItems; i++) + { + if (_pItems[i] && (pszGroup = _pItems[i]->ParentItemName()) != NULL) + { + int iParent = FindItemIndexByName(pszGroup); + + // need to add an empty parent item + if (iParent == -1) + iParent = AddDummyItem(pszGroup); + + _pItems[i]->Parent(iParent); + mir_free(pszGroup); + } + } + } + + if (needWidth) + { + *needWidth = 0; + } + ShowWindow(_hWndTree, SW_HIDE); + for (i = 0; i < _numItems; i++) + { + if (_pItems[i]->State() != DBTVIS_INVISIBLE) + { + ShowItem(i, needWidth); + } + } + ShowWindow(_hWndTree, SW_SHOW); + return TRUE; +} + +/*********************************************************************************************************** + * finding items + ***********************************************************************************************************/ + +/** + * name: FindItemIndexByHandle + * class: CPsTree + * desc: returns the treeitem with specified handle + * param: hItem - handle of the treeview's treeitem + * return: HTREEITEM if item exists or NULL otherwise + **/ +int CPsTree::FindItemIndexByHandle(HTREEITEM hItem) +{ + int i; + for (i = 0; i < _numItems; i++) + { + if (_pItems[i] && hItem == _pItems[i]->Hti()) + { + return i; + } + } + return -1; +} + +/** + * name: FindItemIndexByHandle + * class: CPsTree + * desc: returns the treeitem with specified handle + * param: hItem - handle of the treeview's treeitem + * return: HTREEITEM if item exists or NULL otherwise + **/ +int CPsTree::FindItemIndexByName(LPCSTR pszName) +{ + int i; + for (i = 0; i < _numItems; i++) + { + if (_pItems[i] && _pItems[i]->HasName(pszName)) + { + return i; + } + } + return -1; +} + +/** + * name: FindItemByHandle + * class: CPsTree + * desc: returns the treeitem with specified handle + * param: hItem - handle of the treeview's treeitem + * return: HTREEITEM if item exists or NULL otherwise + **/ +CPsTreeItem* CPsTree::FindItemByHandle(HTREEITEM hItem) +{ + int i; + + if ((i = FindItemIndexByHandle(hItem)) > -1) + { + return _pItems[i]; + } + return NULL; +} + +/** + * name: FindItemByName + * class: CPsTree + * desc: returns the treeitem with specified name + * param: pszName - name of the item to search for + * return: HTREEITEM if item exists or NULL otherwise + **/ +CPsTreeItem* CPsTree::FindItemByName(LPCSTR pszName) +{ + int i; + + if ((i = FindItemIndexByName(pszName)) > -1) + { + return _pItems[i]; + } + return NULL; +} + +/** + * name: FindItemByHandle + * class: CPsTree + * desc: returns the treeitem with specified handle + * param: hItem - handle of the treeview's treeitem + * return: HTREEITEM if item exists or NULL otherwise + **/ +CPsTreeItem* CPsTree::FindItemByResource(HINSTANCE hInst, int idDlg) +{ + int i; + for (i = 0; i < _numItems; i++) + { + if (_pItems[i] && _pItems[i]->Inst() == hInst && _pItems[i]->DlgId() == idDlg) + { + return _pItems[i]; + } + } + return NULL; +} + + +/** + * name: FindItemHandleByName + * class: CPsTree + * desc: returns the treeitem with specified name + * param: pszName - name of the item to search for + * return: HTREEITEM if item exists or NULL otherwise + **/ +HTREEITEM CPsTree::FindItemHandleByName(LPCSTR pszName) +{ + int i; + + if ((i = FindItemIndexByName(pszName)) > -1) + { + return _pItems[i]->Hti(); + } + return NULL; +} + +/*********************************************************************************************************** + * public methods + ***********************************************************************************************************/ + + +/** + * name: HideItem + * class: CPsTree + * desc: is called if icolib's icons have changed + * param: iPageIndex - the index of the treeitem in the array. + * return: nothing + **/ +void CPsTree::HideItem(const int iPageIndex) +{ + if (IsIndexValid(iPageIndex)) + { + TreeView_DeleteItem(_hWndTree, _pItems[iPageIndex]->Hti()); + _pItems[iPageIndex]->Hti(0); + _dwFlags |= PSTVF_STATE_CHANGED; + } +} + +/** + * name: ShowItem + * class: CPsTree + * desc: displays on of the items in the treeview + * param: iPageIndex - the index of the treeitem in the array. + * needWidth - gives and takes the width, the treeview must have to show all items properly + * return: TRUE if item was added successfully, FALSE otherwise + **/ +HTREEITEM CPsTree::ShowItem(const int iPageIndex, LPWORD needWidth) +{ + TVINSERTSTRUCT tvii; + CPsTreeItem *pti; + + // check parameters + if (!_hWndTree || + !IsIndexValid(iPageIndex) || + !(pti = _pItems[iPageIndex]) || + !pti->Name() || + !pti->Label()) + { + MsgErr(GetParent(_hWndTree), LPGENT("Due to a parameter error, one of the treeitems can't be added!")); + return NULL; + } + // item is visible at the moment + if ((tvii.itemex.hItem = pti->Hti()) == NULL) + { + RECT rc; + const int iParent = pti->Parent(); + + // init the rest of the treeitem + tvii.hParent = IsIndexValid(iParent) ? ShowItem(iParent, needWidth) : NULL; + tvii.hInsertAfter = (_dwFlags & PSTVF_SORTTREE) ? TVI_SORT : TVI_LAST; + tvii.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE; + tvii.itemex.pszText = pti->Label(); + tvii.itemex.state = pti->State() == DBTVIS_EXPANDED ? TVIS_EXPANDED : 0; + tvii.itemex.stateMask = TVIS_EXPANDED; + tvii.itemex.lParam = iPageIndex; + // set images + if ((tvii.itemex.iImage = tvii.itemex.iSelectedImage = pti->Image()) != -1) + { + tvii.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE; + } + // insert item into tree if set visible + if ((tvii.itemex.hItem = TreeView_InsertItem(_hWndTree, &tvii)) == NULL) + { + MsgErr(GetParent(_hWndTree), LPGENT("A fatal error occurred on adding a property sheet page!\nDialog creation aborted!")); + return NULL; + } + pti->Hti(tvii.itemex.hItem); + // calculate width of treeview + if (needWidth && TreeView_GetItemRect(_hWndTree, pti->Hti(), &rc, TRUE) && rc.right > *needWidth) + { + *needWidth = (WORD)rc.right; + } + } + return tvii.itemex.hItem; +} + +/** + * name: MoveItem() + * class: CPsTree + * desc: moves a treeitem and its children to a new position + * param: pPs - datastructure of the propertysheetpage + * hItem - the HTREEITEM to move + * hInsertAfter - the HTREEITEM to insert hItem after + * bAsChild - tells, whether to try to add hItem as child of hInsertAfter or not + * return: handle to new (moved) treeitem if successful or NULL otherwise + **/ +HTREEITEM CPsTree::MoveItem(HTREEITEM hItem, HTREEITEM hInsertAfter, BYTE bAsChild) +{ + TVINSERTSTRUCT tvis; + HTREEITEM hParent, hChild, hNewItem; + int iItemIndex; + + if (!hItem || !hInsertAfter) + return NULL; + if (hItem == hInsertAfter) + return hItem; + + switch ((ULONG_PTR)hInsertAfter) { + case TVI_ROOT: + case TVI_FIRST: + case TVI_LAST: + hParent = NULL; + bAsChild = FALSE; + break; + default: + hParent = TreeView_GetParent(_hWndTree, hInsertAfter); + break; + } + // do not move a parent next to its own children! + if (hItem == hParent) + return hItem; + // get detailed information about the item to move + if (FAILED(iItemIndex = FindItemIndexByHandle(hItem))) + return hItem; + + // item should be inserted as the first child of an existing root item + if (bAsChild) { + tvis.hParent = hInsertAfter; + tvis.hInsertAfter = (_dwFlags & PSTVF_SORTTREE) ? TVI_SORT : ((bAsChild == 2) ? TVI_LAST : TVI_FIRST); + } + // item should be inserted after an existing item + else { + tvis.hParent = hParent; + tvis.hInsertAfter = hInsertAfter; + } + + // don't move subitems of a protocol to root as this would mean them not to be unique anymore + if (!_pPs->hContact && (_pItems[iItemIndex]->Flags() & PSPF_PROTOPREPENDED) && !tvis.hParent) + return hItem; + + // prepare the insert structure + tvis.itemex.mask = TVIF_PARAM|TVIF_TEXT; + tvis.itemex.state = TVIS_EXPANDED; + tvis.itemex.stateMask = TVIS_EXPANDED; + tvis.itemex.pszText = _pItems[iItemIndex]->Label(); + tvis.itemex.lParam = (LPARAM)iItemIndex; + if ((tvis.itemex.iImage = tvis.itemex.iSelectedImage = _pItems[iItemIndex]->Image()) >= 0) + tvis.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE; + + // insert the item + if (!(hNewItem = TreeView_InsertItem(_hWndTree, &tvis))) + return hItem; + // update handle pointer in the page structure + _pItems[iItemIndex]->Hti(hNewItem); + // get the index of the parent + _pItems[iItemIndex]->Parent(FindItemIndexByHandle(tvis.hParent)); + // move children + hInsertAfter = hNewItem; + while (hChild = TreeView_GetChild(_hWndTree, hItem)) { + MoveItem(hChild, hInsertAfter, 2); + } + // delete old tree + TreeView_DeleteItem(_hWndTree, hItem); + _dwFlags |= PSTVF_POS_CHANGED; + + TreeView_SelectItem(_hWndTree, hNewItem); + TreeView_Expand(_hWndTree, hNewItem, TVE_EXPAND); + return hNewItem; +} + +/** + * name: SaveItemsState + * class: CPsTree + * desc: saves the tree's visible items to database + * param: pszGroup - name of the parent item of the current subtree + * hRootItem - the root of the current subtree + * iItem - index of the current item for position saving + * return: 0 on success or 1 otherwise + **/ +WORD CPsTree::SaveItemsState(LPCSTR pszGroup, HTREEITEM hRootItem, int& iItem) +{ + TVITEMEX tvi; + WORD numErrors = 0; + + tvi.mask = TVIF_CHILDREN|TVIF_STATE|TVIF_PARAM; + tvi.state = 0; + tvi.stateMask = TVIS_EXPANDED; + tvi.lParam = (LPARAM)-1; + + // save all visible items + for (tvi.hItem = TreeView_GetChild(_hWndTree, hRootItem); + TreeView_GetItem(_hWndTree, &tvi); + tvi.hItem = TreeView_GetNextSibling(_hWndTree, tvi.hItem)) + { + numErrors += _pItems[tvi.lParam]->DBSaveItemState(pszGroup, iItem++, tvi.state, _dwFlags); + if (tvi.cChildren) numErrors += SaveItemsState(_pItems[tvi.lParam]->Name(), tvi.hItem, iItem); + } + return numErrors; +} + +/** + * name: SaveState + * class: CPsTree + * desc: saves the current tree to database + * param: none + * return: nothing + **/ +void CPsTree::SaveState() +{ + CPsTreeItem *pti = CurrentItem(); + + if (_hWndTree && (_dwFlags & (PSTVF_LABEL_CHANGED|PSTVF_POS_CHANGED|PSTVF_STATE_CHANGED))) { + SHORT i; + int iItem = 0; + + // save all visible items + WORD numErrors = SaveItemsState(TREE_ROOTITEM, TVGN_ROOT, iItem); + + // save all invisible items of the current subtree + for (i = 0; i < _numItems; i++) { + if (!_pItems[i]->Hti()) { + LPSTR pszGroup; + + if (!IsIndexValid(_pItems[i]->Parent()) || !(pszGroup = _pItems[_pItems[i]->Parent()]->Name())) + pszGroup = TREE_ROOTITEM; + numErrors += _pItems[i]->DBSaveItemState(pszGroup, iItem++, DBTVIS_INVISIBLE, _dwFlags); + } + } + // remove changed flags + RemoveFlags(PSTVF_STATE_CHANGED|PSTVF_LABEL_CHANGED|PSTVF_POS_CHANGED); + } + + // save current selected item + if (pti) db_set_utf(NULL, MODNAME, SET_LASTITEM, pti->Name()); + else db_unset(NULL, MODNAME, SET_LASTITEM); +} + +/** + * name: DBResetState + * class: CPsTree + * desc: delete all treesettings from database + * param: pszGroup - name of the parent item of the current subtree + * hRootItem - the root of the current subtree + * iItem - index of the current item for position saving + * return: 0 on success or 1 otherwise + **/ +void CPsTree::DBResetState() +{ + DB::CEnumList Settings; + + if (!Settings.EnumSettings(NULL, MODNAME)) + { + int i; + LPSTR s; + LPCSTR p; + INT_PTR c; + + p = (_pPs->pszProto[0]) ? _pPs->pszProto : "Owner"; + c = mir_strlen(p); + + for (i = 0; i < Settings.getCount(); i++) + { + s = Settings[i]; + + if (s && *s == '{' && !mir_strnicmp(s + 1, p, c)) + { + db_unset(NULL, MODNAME, s); + } + } + // keep only these flags + _dwFlags &= PSTVF_SORTTREE|PSTVF_GROUPS; + } +} + +/*********************************************************************************************************** + * public methods for handling label editing + ***********************************************************************************************************/ + +/** + * name: TPropsheetTree_LabelEditProc() + * desc: subclussproc of the label editcontrol + * return: 0 + **/ +static LRESULT CALLBACK TPropsheetTree_LabelEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + switch(uMsg) { + case WM_KEYDOWN: + switch(wParam) { + case VK_RETURN: + return ((CPsTree*)GetUserData(hwnd))->EndLabelEdit(TRUE); + case VK_TAB: + case VK_ESCAPE: + return ((CPsTree*)GetUserData(hwnd))->EndLabelEdit(FALSE); + } + break; + + case WM_KILLFOCUS: + ((CPsTree*)GetUserData(hwnd))->EndLabelEdit(FALSE); + break; + + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS | mir_callNextSubclass(hwnd, TPropsheetTree_LabelEditProc, uMsg, wParam, lParam ); + } + return mir_callNextSubclass(hwnd, TPropsheetTree_LabelEditProc, uMsg, wParam, lParam); +} + +/** + * name: BeginLabelEdit + * class: CPsTree + * desc: begins the labeledit mode + * param: hItem - handle of the treeitm whose label to edit + * return: 0 + **/ +int CPsTree::BeginLabelEdit(HTREEITEM hItem) +{ + CPsTreeItem* pti; + + // tree is readonly + if (db_get_b(NULL, MODNAME, SET_PROPSHEET_READONLYLABEL, 0)) + return 0; + + // get item text + if (!hItem && !(hItem = TreeView_GetSelection(_hWndTree))) + return 0; + if (pti = FindItemByHandle(hItem)) + { + RECT rc, rcTree; + + // create the edit control + GetClientRect(_hWndTree, &rcTree); + TreeView_GetItemRect(_hWndTree, hItem, &rc, TRUE); + _hLabelEdit = CreateWindowEx(WS_EX_NOPARENTNOTIFY|WS_EX_CLIENTEDGE, + _T( "EDIT" ), + pti->Label(), + WS_VISIBLE|ES_AUTOHSCROLL|WS_CHILD, + rc.left, rc.top, + rcTree.right - rc.left, rc.bottom - rc.top, + _hWndTree, + NULL, + ghInst, + NULL ); + if (_hLabelEdit) + { + _hDragItem = hItem; + SetUserData(_hLabelEdit, this); + mir_subclassWindow(_hLabelEdit, TPropsheetTree_LabelEditProc); + SendMessage(_hLabelEdit, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0 ); + Edit_SetSel(_hLabelEdit, 0, -1); + Edit_LimitText(_hLabelEdit, MAX_TINAME); + SetFocus(_hLabelEdit); + return 0; + } + } + return 1; +} + +/** + * name: EndLabelEdit + * class: CPsTree + * desc: exits the labeledit mode + * bSave - tell whether to save changes or not + * return: 0 + **/ +int CPsTree::EndLabelEdit(const BYTE bSave) +{ + TCHAR szEdit[MAX_TINAME]; + TVITEM tvi; + WORD cchEdit; + + if (bSave && (cchEdit = Edit_GetText(_hLabelEdit, szEdit, MAX_TINAME)) > 0) + { + tvi.hItem = _hDragItem; + tvi.mask = TVIF_TEXT|TVIF_HANDLE; + tvi.pszText = szEdit; + if (TreeView_SetItem(_hWndTree, &tvi)) + { + CPsTreeItem* pti; + if (pti = FindItemByHandle(_hDragItem)) + { + pti->Rename(szEdit); + } + _dwFlags |= PSTVF_LABEL_CHANGED; + } + } + DestroyWindow(_hLabelEdit); + _hLabelEdit = NULL; + _hDragItem = NULL; + return 0; +} + +/*********************************************************************************************************** + * public methods for handling other commands + ***********************************************************************************************************/ + +void CPsTree::PopupMenu() +{ + HMENU hPopup; + MENUITEMINFO mii; + TVHITTESTINFO hti; + TVITEM tvi; + POINT pt; + int iItem, i; + + // init popup menu + if (!(hPopup = CreatePopupMenu())) + return; + ZeroMemory(&mii, sizeof(MENUITEMINFO)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING|MIIM_ID; + + // get cursor postion + GetCursorPos(&pt); + hti.pt = pt; + ScreenToClient(_hWndTree, &hti.pt); + + tvi.mask = TVIF_PARAM|TVIF_CHILDREN; + // find treeitem under cursor + TreeView_HitTest(_hWndTree, &hti); + if (hti.flags & (TVHT_ONITEM|TVHT_ONITEMRIGHT)) { + tvi.hItem = hti.hItem; + TreeView_GetItem(_hWndTree, &tvi); + + if (!db_get_b(NULL, MODNAME, SET_PROPSHEET_READONLYLABEL, FALSE)) { + mii.dwTypeData = TranslateT("Rename Item"); + mii.wID = 32001; + InsertMenuItem(hPopup, 0, FALSE, &mii); + } + + // do not allow hiding groups + if (tvi.cChildren) { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + mii.dwTypeData = TranslateT("Hide Item"); + mii.wID = 32000; + InsertMenuItem(hPopup, 0, FALSE, &mii); + } + else { + // add hidden items to menu + mii.wID = 0; + for (i = 0; i < _numItems; i++) { + if (!_pItems[i]->Hti()) { + mii.dwTypeData = _pItems[i]->Label(); + mii.wID = 100 + i; + InsertMenuItem(hPopup, 0, FALSE, &mii); + } + } + // add headline + if (mii.wID > 0) { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + mii.dwTypeData = TranslateT("Show Items:"); + mii.wID = 0; + InsertMenuItem(hPopup, 0, TRUE, &mii); + mii.fMask |= MIIM_FTYPE; + mii.fType = MFT_SEPARATOR; + InsertMenuItem(hPopup, 1, TRUE, &mii); + InsertMenuItem(hPopup, ++i, TRUE, &mii); + } + mii.fMask &= ~(MIIM_FTYPE|MIIM_STATE); + mii.dwTypeData = TranslateT("Reset to defaults"); + mii.wID = 32004; + InsertMenuItem(hPopup, ++i, TRUE, &mii); + } + // show the popup menu + iItem = TrackPopupMenu(hPopup, TPM_RETURNCMD, pt.x, pt.y, 0, _hWndTree, NULL); + DestroyMenu(hPopup); + + switch (iItem) { + // hide the item + case 32000: + HideItem(tvi.lParam); + break; + // rename the item + case 32001: + BeginLabelEdit(tvi.hItem); + break; + // reset current tree + case 32004: + DBResetState(); + break; + // show a hidden item + default: + if ((iItem -= 100) >= 0 && ShowItem(iItem, NULL)) + AddFlags(PSTVF_STATE_CHANGED|PSTVF_POS_CHANGED); + break; + } +} + +/*********************************************************************************************************** + * public event handlers + ***********************************************************************************************************/ + +/** + * name: OnIconsChanged + * class: CPsTree + * desc: is called if icolib's icons have changed + * param: none + * return: nothing + **/ +void CPsTree::OnIconsChanged() +{ + for (int i = 0; i < _numItems; i++) { + _pItems[i]->OnIconsChanged(this); + } +} + +/** + * name: OnInfoChanged + * class: CPsTree + * desc: contact information have changed and pages need an update + * param: none + * return: TRUE if any page holds changed information + **/ +BYTE CPsTree::OnInfoChanged() +{ + PSHNOTIFY pshn; + int i; + BYTE bChanged = 0; + + pshn.hdr.idFrom = 0; + pshn.hdr.code = PSN_INFOCHANGED; + for (i = 0; i < _numItems; i++) { + pshn.hdr.hwndFrom = _pItems[i]->Wnd(); + if (pshn.hdr.hwndFrom != NULL) { + pshn.lParam = (LPARAM)_pItems[i]->hContact(); + SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn); + if (PSP_CHANGED == GetWindowLongPtr(pshn.hdr.hwndFrom, DWLP_MSGRESULT)) + bChanged |= 1; + else + _pItems[i]->RemoveFlags(PSPF_CHANGED); + } + } + return bChanged; +} + +/** + * name: OnSelChanging + * class: CPsTree + * desc: the displayed page is up to change + * param: none + * return: nothing + **/ +BYTE CPsTree::OnSelChanging() +{ + CPsTreeItem *pti = CurrentItem(); + + if (pti != NULL) { + TreeView_SetItemState(_hWndTree, pti->Hti(), 0, TVIS_SELECTED); + if (pti->Wnd() != NULL) { + PSHNOTIFY pshn; + + pshn.hdr.code = PSN_KILLACTIVE; + pshn.hdr.hwndFrom = pti->Wnd(); + pshn.hdr.idFrom = 0; + pshn.lParam = (LPARAM)pti->hContact(); + if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn)) { + SetWindowLongPtr(_pPs->hDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + } + return FALSE; +} + +/** + * name: OnSelChanged + * class: CPsTree + * desc: it handles the change of displayed page + * param: lpnmtv - notification structure + * return: nothing + **/ +void CPsTree::OnSelChanged(LPNMTREEVIEW lpnmtv) +{ + CPsTreeItem *oldPage = CurrentItem(); + CPsTreeItem *pti; + + _curItem = (int)lpnmtv->itemNew.lParam; + if (pti = CurrentItem()) { + if (pti->Wnd() == NULL) { + pti->CreateWnd(_pPs); + } + } + // hide old page even if new item has no valid one + if (oldPage && oldPage->Wnd() != NULL) + ShowWindow(oldPage->Wnd(), SW_HIDE); + if (pti) + ShowWindow(pti->Wnd(), SW_SHOW); + if (lpnmtv->action != TVC_BYMOUSE) + SetFocus(_hWndTree); +} + +/** + * name: OnCancel + * class: CPsTree + * desc: asks pages to reset their information + * param: none + * return: nothing + **/ +void CPsTree::OnCancel() +{ + PSHNOTIFY pshn; + int i; + + pshn.hdr.idFrom = 0; + pshn.hdr.code = PSN_RESET; + for (i = 0; i < _numItems; i++) { + pshn.hdr.hwndFrom = _pItems[i]->Wnd(); + if (pshn.hdr.hwndFrom && (_pItems[i]->Flags() & PSPF_CHANGED)) { + pshn.lParam = (LPARAM)_pItems[i]->hContact(); + SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn); + } + } +} + +/** + * name: OnApply + * class: CPsTree + * desc: saves settings of all pages + * param: none + * return: 0 if ready to continue, 1 if need to abort + **/ +int CPsTree::OnApply() +{ + CPsTreeItem *pti = CurrentItem(); + PSHNOTIFY pshn; + int i; + + if (pti == NULL) + return 1; + + pshn.hdr.idFrom = 0; + pshn.hdr.code = PSN_KILLACTIVE; + pshn.hdr.hwndFrom = pti->Wnd(); + if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn)) + return 1; + // save everything to database + pshn.hdr.code = PSN_APPLY; + for (i = 0; i < _numItems; i++) { + if (_pItems[i] && _pItems[i]->Wnd() && _pItems[i]->Flags() & PSPF_CHANGED) { + pshn.lParam = (LPARAM)_pItems[i]->hContact(); + pshn.hdr.hwndFrom = _pItems[i]->Wnd(); + if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn) == PSNRET_INVALID_NOCHANGEPAGE) { + CPsTreeItem *pti; + if (pti = CurrentItem()) + ShowWindow(pti->Wnd(), SW_HIDE); + _curItem = i; + ShowWindow(_pItems[i]->Wnd(), SW_SHOW); + return 1; + } + _pItems[i]->RemoveFlags(PSPF_CHANGED); + } + } + return 0; +} diff --git a/plugins/UserInfoEx/src/ctrl_edit.cpp b/plugins/UserInfoEx/src/ctrl_edit.cpp index 1b4ecac93e..71e5f5e0de 100644 --- a/plugins/UserInfoEx/src/ctrl_edit.cpp +++ b/plugins/UserInfoEx/src/ctrl_edit.cpp @@ -1,371 +1,372 @@ -/* -UserinfoEx plugin for Miranda IM - -Copyright: -© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol - -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 "commonheaders.h" - -/** - * This function creates a CEditCtrl object. - * - * @param hDlg - HWND of the owning propertysheet page - * @param idCtrl - the ID of the dialog control to associate with this class's instance - * @param pszSetting - the database setting to be handled by this class - * @param dbType - the expected data type of the setting - * - * @return This static method returns the pointer of the created object. - **/ -CBaseCtrl* CEditCtrl::CreateObj(HWND hDlg, WORD idCtrl, LPCSTR pszSetting, BYTE dbType) -{ - CEditCtrl *ctrl = NULL; - - ctrl = new CEditCtrl(hDlg, idCtrl, USERINFO, pszSetting); - if (ctrl) { - ctrl->_dbType = dbType; - } - return (ctrl); -} - -/** - * This function creates a CEditCtrl object. - * - * @param hDlg - HWND of the owning propertysheet page - * @param idCtrl - the ID of the dialog control to associate with this class's instance - * @param pszModule - the database module to be handled by this class - * @param pszSetting - the database setting to be handled by this class - * @param dbType - the expected data type of the setting - * - * @return This static method returns the pointer of the created object. - **/ -CBaseCtrl* CEditCtrl::CreateObj(HWND hDlg, WORD idCtrl, LPCSTR pszModule, LPCSTR pszSetting, BYTE dbType) -{ - CEditCtrl *ctrl = NULL; - - ctrl = new CEditCtrl(hDlg, idCtrl, pszModule, pszSetting); - if (ctrl) { - ctrl->_dbType = dbType; - } - return (ctrl); -} - -/** - * - * - **/ -CEditCtrl::CEditCtrl(HWND hDlg, WORD idCtrl, LPCSTR pszModule, LPCSTR pszSetting) - : CBaseCtrl(hDlg, idCtrl, pszModule, pszSetting) -{ - SendDlgItemMessage(hDlg, idCtrl, EM_LIMITTEXT, 0x7fFFffFF, 0L); -} - -/** - * This method deletes the class object - * and all allocated memory of its members. - * - * @param none - * - * @return nothing - **/ -void CEditCtrl::Release() -{ - delete this; -} - -/* - * - * - */ -void CEditCtrl::OnReset() -{ -} - - -/** - * This method controls the changed bit for the control. - * - * @param hCtrl - HWND of the combobox - * @param hContact - HANDLE of the contact whose timezone to select - * @param pszProto - the contact's protocol - * - * @return nothing - **/ -BOOL CEditCtrl::OnInfoChanged(MCONTACT hContact, LPCSTR pszProto) -{ - if (!_Flags.B.hasChanged) - { - DBVARIANT dbv; - TCHAR szText[64]; - - _Flags.B.hasCustom = _Flags.B.hasProto = _Flags.B.hasMeta = 0; - _Flags.W |= DB::Setting::GetTStringCtrl(hContact, _pszModule, _pszModule, pszProto, _pszSetting, &dbv); - - EnableWindow(_hwnd, - !hContact || _Flags.B.hasCustom || !db_get_b(NULL, MODNAME, SET_PROPSHEET_PCBIREADONLY, 0)); - - MIR_FREE(_pszValue); - switch (dbv.type) - { - case DBVT_BYTE: - _itot_s(dbv.bVal, szText, SIZEOF(szText), 10); - SetWindowText(_hwnd, szText); - _pszValue = mir_tcsdup(szText); - break; - - case DBVT_WORD: - _itot_s(dbv.wVal, szText, SIZEOF(szText), 10); - SetWindowText(_hwnd, szText); - _pszValue = mir_tcsdup(szText); - break; - - case DBVT_DWORD: - _itot_s(dbv.dVal, szText, SIZEOF(szText), 10); - SetWindowText(_hwnd, szText); - _pszValue = mir_tcsdup(szText); - break; - - case DBVT_TCHAR: - if (dbv.ptszVal) - { - SetWindowText(_hwnd, dbv.ptszVal); - _pszValue = dbv.ptszVal; - break; - } - - default: - SetWindowText(_hwnd, _T("")); - db_free(&dbv); - break; - } - _Flags.B.hasChanged = 0; - } - return _Flags.B.hasChanged; -} - -/** - * This method writes the control's information to database - * - * @param hContact - HANDLE of the contact whose timezone to select - * @param pszProto - the contact's protocol - * - * @return nothing - **/ -void CEditCtrl::OnApply(MCONTACT hContact, LPCSTR pszProto) -{ - if (_Flags.B.hasChanged) - { - const char* pszModule = hContact ? _pszModule : pszProto; - - if (_Flags.B.hasCustom || !hContact) - { - DWORD cch = GetWindowTextLength(_hwnd); - - if (cch > 0) - { - LPTSTR val = (LPTSTR)mir_alloc((cch + 1) * sizeof(TCHAR)); - - if (GetWindowText(_hwnd, val, cch + 1) > 0) - { - DBVARIANT dbv; - - dbv.type = _dbType; - switch (_dbType) - { - case DBVT_BYTE: - dbv.bVal = (BYTE)_tcstol(val, NULL, 10); - break; - - case DBVT_WORD: - dbv.wVal = (WORD)_tcstol(val, NULL, 10); - break; - - case DBVT_DWORD: - dbv.dVal = (DWORD)_tcstol(val, NULL, 10); - break; - - case DBVT_TCHAR: - dbv.ptszVal = val; - break; - - default: - dbv.type = DBVT_DELETED; - - } - if (dbv.type != DBVT_DELETED) - { - if (!db_set(hContact, pszModule, _pszSetting, &dbv)) - { - if (!hContact) - { - _Flags.B.hasCustom = 0; - _Flags.B.hasProto = 1; - } - _Flags.B.hasChanged = 0; - - // save new value - MIR_FREE(_pszValue); - _pszValue = val; - val = NULL; - } - } - } - MIR_FREE(val); - } - } - if (_Flags.B.hasChanged) - { - db_unset(hContact, pszModule, _pszSetting); - - _Flags.B.hasChanged = 0; - - OnInfoChanged(hContact, pszProto); - } - InvalidateRect(_hwnd, NULL, TRUE); - } -} - -/** - * The user changed information stored in the control. - * - * @return nothing - **/ -void CEditCtrl::OnChangedByUser(WORD wChangedMsg) -{ - if ((wChangedMsg == EN_UPDATE) || (wChangedMsg == EN_CHANGE)) - { - const int cch = GetWindowTextLength(_hwnd); - - _Flags.B.hasChanged = mir_tcslen(_pszValue) != cch; - _Flags.B.hasCustom = (cch > 0); - - if (!_Flags.B.hasChanged && _Flags.B.hasCustom) { - BYTE need_free = 0; - LPTSTR szText; - - __try - { - szText = (LPTSTR)alloca((cch + 1) * sizeof(TCHAR)); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - szText = (LPTSTR)mir_alloc((cch + 1) * sizeof(TCHAR)); - need_free = 1; - } - - GetWindowText(_hwnd, szText, cch + 1); - _Flags.B.hasChanged = mir_tcscmp(_pszValue, szText); - - if (need_free) { - MIR_FREE(szText); - } - } - InvalidateRect(_hwnd, NULL, TRUE); - - if (_Flags.B.hasChanged) { - SendMessage(GetParent(GetParent(_hwnd)), PSM_CHANGED, 0, 0); - } - } -} - -/** - * Opens the url given in a editbox in the users default browser - **/ -void CEditCtrl::OpenUrl() -{ - int lenUrl = 1 + Edit_GetTextLength(_hwnd); - LPSTR szUrl; - BYTE need_free = 0; - - __try - { - szUrl = (LPSTR)alloca((8 + lenUrl) * sizeof(CHAR)); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - szUrl = (LPSTR)mir_alloc((8 + lenUrl) * sizeof(CHAR)); - need_free = 1; - } - if (szUrl && (GetWindowTextA(_hwnd, szUrl, lenUrl) > 0)) - { - CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl); - } - if (need_free) - { - MIR_FREE(szUrl); - } -} - -LRESULT CEditCtrl::LinkNotificationHandler(ENLINK* lnk) -{ - switch (lnk->msg) - { - case WM_SETCURSOR: - { - SetCursor(LoadCursor(NULL, IDC_HAND)); - SetWindowLongPtr(GetParent(_hwnd), DWLP_MSGRESULT, TRUE); - } - return TRUE; - - case WM_LBUTTONUP: - { - if (lnk) - { - TEXTRANGE tr; - BYTE need_free = 0; - - // do not call function if user selected some chars of the url string - SendMessage(_hwnd, EM_EXGETSEL, NULL, (LPARAM) &tr.chrg); - if (tr.chrg.cpMax == tr.chrg.cpMin) - { - // retrieve the url string - tr.chrg = lnk->chrg; - - __try - { - tr.lpstrText = (LPTSTR)alloca((tr.chrg.cpMax - tr.chrg.cpMin + 8) * sizeof(TCHAR)); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - tr.lpstrText = (LPTSTR)mir_alloc((tr.chrg.cpMax - tr.chrg.cpMin + 8) * sizeof(TCHAR)); - need_free = 1; - } - if (tr.lpstrText && (SendMessage(_hwnd, EM_GETTEXTRANGE, NULL, (LPARAM)&tr) > 0)) - { - if (_tcschr(tr.lpstrText, '@') != NULL && _tcschr(tr.lpstrText, ':') == NULL && _tcschr(tr.lpstrText, '/') == NULL) - { - MoveMemory(tr.lpstrText + (7*sizeof(TCHAR)), tr.lpstrText, (tr.chrg.cpMax - tr.chrg.cpMin + 1)*sizeof(TCHAR)); - CopyMemory(tr.lpstrText, _T("mailto:"), (7*sizeof(TCHAR))); - } - - LPSTR pszUrl = mir_t2a(tr.lpstrText); - if (pszUrl) - { - CallService(MS_UTILS_OPENURL, 1, (LPARAM)pszUrl); - mir_free(pszUrl); - } - } - if (need_free) - { - MIR_FREE(tr.lpstrText); - } - } - } - } - } - return FALSE; +/* +UserinfoEx plugin for Miranda IM + +Copyright: +© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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 "commonheaders.h" + +/** + * This function creates a CEditCtrl object. + * + * @param hDlg - HWND of the owning propertysheet page + * @param idCtrl - the ID of the dialog control to associate with this class's instance + * @param pszSetting - the database setting to be handled by this class + * @param dbType - the expected data type of the setting + * + * @return This static method returns the pointer of the created object. + **/ +CBaseCtrl* CEditCtrl::CreateObj(HWND hDlg, WORD idCtrl, LPCSTR pszSetting, BYTE dbType) +{ + CEditCtrl *ctrl = NULL; + + ctrl = new CEditCtrl(hDlg, idCtrl, USERINFO, pszSetting); + if (ctrl) { + ctrl->_dbType = dbType; + } + return (ctrl); +} + +/** + * This function creates a CEditCtrl object. + * + * @param hDlg - HWND of the owning propertysheet page + * @param idCtrl - the ID of the dialog control to associate with this class's instance + * @param pszModule - the database module to be handled by this class + * @param pszSetting - the database setting to be handled by this class + * @param dbType - the expected data type of the setting + * + * @return This static method returns the pointer of the created object. + **/ +CBaseCtrl* CEditCtrl::CreateObj(HWND hDlg, WORD idCtrl, LPCSTR pszModule, LPCSTR pszSetting, BYTE dbType) +{ + CEditCtrl *ctrl = NULL; + + ctrl = new CEditCtrl(hDlg, idCtrl, pszModule, pszSetting); + if (ctrl) { + ctrl->_dbType = dbType; + } + return (ctrl); +} + +/** + * + * + **/ +CEditCtrl::CEditCtrl(HWND hDlg, WORD idCtrl, LPCSTR pszModule, LPCSTR pszSetting) + : CBaseCtrl(hDlg, idCtrl, pszModule, pszSetting) +{ + SendDlgItemMessage(hDlg, idCtrl, EM_LIMITTEXT, 0x7fFFffFF, 0L); +} + +/** + * This method deletes the class object + * and all allocated memory of its members. + * + * @param none + * + * @return nothing + **/ +void CEditCtrl::Release() +{ + delete this; +} + +/* + * + * + */ +void CEditCtrl::OnReset() +{ +} + + +/** + * This method controls the changed bit for the control. + * + * @param hCtrl - HWND of the combobox + * @param hContact - HANDLE of the contact whose timezone to select + * @param pszProto - the contact's protocol + * + * @return nothing + **/ +BOOL CEditCtrl::OnInfoChanged(MCONTACT hContact, LPCSTR pszProto) +{ + if (!_Flags.B.hasChanged) + { + DBVARIANT dbv; + TCHAR szText[64]; + + _Flags.B.hasCustom = _Flags.B.hasProto = _Flags.B.hasMeta = 0; + _Flags.W |= DB::Setting::GetTStringCtrl(hContact, _pszModule, _pszModule, pszProto, _pszSetting, &dbv); + + EnableWindow(_hwnd, + !hContact || _Flags.B.hasCustom || !db_get_b(NULL, MODNAME, SET_PROPSHEET_PCBIREADONLY, 0)); + + MIR_FREE(_pszValue); + switch (dbv.type) + { + case DBVT_BYTE: + _itot_s(dbv.bVal, szText, SIZEOF(szText), 10); + SetWindowText(_hwnd, szText); + _pszValue = mir_tcsdup(szText); + break; + + case DBVT_WORD: + _itot_s(dbv.wVal, szText, SIZEOF(szText), 10); + SetWindowText(_hwnd, szText); + _pszValue = mir_tcsdup(szText); + break; + + case DBVT_DWORD: + _itot_s(dbv.dVal, szText, SIZEOF(szText), 10); + SetWindowText(_hwnd, szText); + _pszValue = mir_tcsdup(szText); + break; + + case DBVT_TCHAR: + if (dbv.ptszVal) + { + SetWindowText(_hwnd, dbv.ptszVal); + _pszValue = dbv.ptszVal; + break; + } + + default: + SetWindowText(_hwnd, _T("")); + db_free(&dbv); + break; + } + _Flags.B.hasChanged = 0; + } + return _Flags.B.hasChanged; +} + +/** + * This method writes the control's information to database + * + * @param hContact - HANDLE of the contact whose timezone to select + * @param pszProto - the contact's protocol + * + * @return nothing + **/ +void CEditCtrl::OnApply(MCONTACT hContact, LPCSTR pszProto) +{ + if (_Flags.B.hasChanged) + { + const char* pszModule = hContact ? _pszModule : pszProto; + + if (_Flags.B.hasCustom || !hContact) + { + DWORD cch = GetWindowTextLength(_hwnd); + + if (cch > 0) + { + LPTSTR val = (LPTSTR)mir_alloc((cch + 1) * sizeof(TCHAR)); + + if (GetWindowText(_hwnd, val, cch + 1) > 0) + { + DBVARIANT dbv; + + dbv.type = _dbType; + switch (_dbType) + { + case DBVT_BYTE: + dbv.bVal = (BYTE)_tcstol(val, NULL, 10); + break; + + case DBVT_WORD: + dbv.wVal = (WORD)_tcstol(val, NULL, 10); + break; + + case DBVT_DWORD: + dbv.dVal = (DWORD)_tcstol(val, NULL, 10); + break; + + case DBVT_TCHAR: + dbv.ptszVal = val; + break; + + default: + dbv.type = DBVT_DELETED; + + } + if (dbv.type != DBVT_DELETED) + { + if (!db_set(hContact, pszModule, _pszSetting, &dbv)) + { + if (!hContact) + { + _Flags.B.hasCustom = 0; + _Flags.B.hasProto = 1; + } + _Flags.B.hasChanged = 0; + + // save new value + MIR_FREE(_pszValue); + _pszValue = val; + val = NULL; + } + } + } + MIR_FREE(val); + } + } + if (_Flags.B.hasChanged) + { + db_unset(hContact, pszModule, _pszSetting); + + _Flags.B.hasChanged = 0; + + OnInfoChanged(hContact, pszProto); + } + InvalidateRect(_hwnd, NULL, TRUE); + } +} + +/** + * The user changed information stored in the control. + * + * @return nothing + **/ +void CEditCtrl::OnChangedByUser(WORD wChangedMsg) +{ + if ((wChangedMsg == EN_UPDATE) || (wChangedMsg == EN_CHANGE)) + { + const int cch = GetWindowTextLength(_hwnd); + + _Flags.B.hasChanged = mir_tcslen(_pszValue) != cch; + _Flags.B.hasCustom = (cch > 0); + + if (!_Flags.B.hasChanged && _Flags.B.hasCustom) { + BYTE need_free = 0; + LPTSTR szText; + + __try + { + szText = (LPTSTR)alloca((cch + 1) * sizeof(TCHAR)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + szText = (LPTSTR)mir_alloc((cch + 1) * sizeof(TCHAR)); + need_free = 1; + } + + if (szText != NULL) { + GetWindowText(_hwnd, szText, cch + 1); + _Flags.B.hasChanged = mir_tcscmp(_pszValue, szText); + if (need_free) + MIR_FREE(szText); + } else { + _Flags.B.hasChanged = 0; + } + } + InvalidateRect(_hwnd, NULL, TRUE); + + if (_Flags.B.hasChanged) + SendMessage(GetParent(GetParent(_hwnd)), PSM_CHANGED, 0, 0); + } +} + +/** + * Opens the url given in a editbox in the users default browser + **/ +void CEditCtrl::OpenUrl() +{ + int lenUrl = 1 + Edit_GetTextLength(_hwnd); + LPSTR szUrl; + BYTE need_free = 0; + + __try + { + szUrl = (LPSTR)alloca((8 + lenUrl) * sizeof(CHAR)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + szUrl = (LPSTR)mir_alloc((8 + lenUrl) * sizeof(CHAR)); + need_free = 1; + } + if (szUrl && (GetWindowTextA(_hwnd, szUrl, lenUrl) > 0)) + { + CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl); + } + if (need_free) + { + MIR_FREE(szUrl); + } +} + +LRESULT CEditCtrl::LinkNotificationHandler(ENLINK* lnk) +{ + switch (lnk->msg) + { + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL, IDC_HAND)); + SetWindowLongPtr(GetParent(_hwnd), DWLP_MSGRESULT, TRUE); + } + return TRUE; + + case WM_LBUTTONUP: + { + if (lnk) + { + TEXTRANGE tr; + BYTE need_free = 0; + + // do not call function if user selected some chars of the url string + SendMessage(_hwnd, EM_EXGETSEL, NULL, (LPARAM) &tr.chrg); + if (tr.chrg.cpMax == tr.chrg.cpMin) + { + // retrieve the url string + tr.chrg = lnk->chrg; + + __try + { + tr.lpstrText = (LPTSTR)alloca((tr.chrg.cpMax - tr.chrg.cpMin + 8) * sizeof(TCHAR)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + tr.lpstrText = (LPTSTR)mir_alloc((tr.chrg.cpMax - tr.chrg.cpMin + 8) * sizeof(TCHAR)); + need_free = 1; + } + if (tr.lpstrText && (SendMessage(_hwnd, EM_GETTEXTRANGE, NULL, (LPARAM)&tr) > 0)) + { + if (_tcschr(tr.lpstrText, '@') != NULL && _tcschr(tr.lpstrText, ':') == NULL && _tcschr(tr.lpstrText, '/') == NULL) + { + MoveMemory(tr.lpstrText + (7*sizeof(TCHAR)), tr.lpstrText, (tr.chrg.cpMax - tr.chrg.cpMin + 1)*sizeof(TCHAR)); + CopyMemory(tr.lpstrText, _T("mailto:"), (7*sizeof(TCHAR))); + } + + LPSTR pszUrl = mir_t2a(tr.lpstrText); + if (pszUrl) + { + CallService(MS_UTILS_OPENURL, 1, (LPARAM)pszUrl); + mir_free(pszUrl); + } + } + if (need_free) + { + MIR_FREE(tr.lpstrText); + } + } + } + } + } + return FALSE; } \ No newline at end of file diff --git a/plugins/UserInfoEx/src/ex_import/classExImContactBase.cpp b/plugins/UserInfoEx/src/ex_import/classExImContactBase.cpp index 71dd6bee93..ead8d33c9d 100644 --- a/plugins/UserInfoEx/src/ex_import/classExImContactBase.cpp +++ b/plugins/UserInfoEx/src/ex_import/classExImContactBase.cpp @@ -1,535 +1,540 @@ -/* -UserinfoEx plugin for Miranda IM - -Copyright: -© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol - -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 "..\commonheaders.h" - -/** - * name: CExImContactBase - * class: CExImContactBase - * desc: default constructor - * param: none - * return: nothing - **/ -CExImContactBase::CExImContactBase() -{ - _pszNick = NULL; - _pszDisp = NULL; - _pszGroup = NULL; - _pszProto = NULL; - _pszProtoOld = NULL; - _pszAMPro = NULL; - _pszUIDKey = NULL; - _dbvUIDHash = NULL; - ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); - _hContact = INVALID_CONTACT_ID; - _isNewContact = FALSE; -} - -/** - * name: ~CExImContactBase - * class: CExImContactBase - * desc: default denstructor - * param: none - * return: nothing - **/ -CExImContactBase::~CExImContactBase() -{ - MIR_FREE(_pszNick); - MIR_FREE(_pszDisp); - MIR_FREE(_pszGroup); - MIR_FREE(_pszProtoOld); - MIR_FREE(_pszProto); - MIR_FREE(_pszAMPro); - MIR_FREE(_pszUIDKey); - db_free(&_dbvUID); -} - -/** - * name: fromDB - * class: CExImContactBase - * desc: get contact information from database - * param: hContact - handle to contact whose information to read - * return: TRUE if successful or FALSE otherwise - **/ -BYTE CExImContactBase::fromDB(MCONTACT hContact) -{ - BYTE ret = FALSE; - BYTE isChatRoom = FALSE; - LPSTR pszProto; - LPCSTR uidSetting; - DBVARIANT dbv; - - _hContact = hContact; - _dbvUIDHash = 0; - MIR_FREE(_pszProtoOld); - MIR_FREE(_pszProto); - MIR_FREE(_pszAMPro); - MIR_FREE(_pszNick); - MIR_FREE(_pszDisp); - MIR_FREE(_pszGroup); - MIR_FREE(_pszUIDKey); - db_free(&_dbvUID); - ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); - - // OWNER - if (!_hContact) return TRUE; - - // Proto - if (!(pszProto = DB::Contact::Proto(_hContact))) return FALSE; - _pszProto = mir_strdup(pszProto); - - // AM_BaseProto - if (!DB::Setting::GetUString(NULL, pszProto, "AM_BaseProto", &dbv )) { - _pszAMPro = mir_strdup(dbv.pszVal); - db_free(&dbv); - } - - // unique id (for ChatRoom) - if (isChatRoom = db_get_b(_hContact, pszProto, "ChatRoom", 0)) { - uidSetting = "ChatRoomID"; - _pszUIDKey = mir_strdup(uidSetting); - if (!DB::Setting::GetAsIs(_hContact, pszProto, uidSetting, &_dbvUID)) { - ret = TRUE; - } - } - // unique id (normal) - else { - uidSetting = (LPCSTR)CallProtoService(pszProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0); - // valid - if (uidSetting != NULL && (INT_PTR)uidSetting != CALLSERVICE_NOTFOUND) { - _pszUIDKey = mir_strdup(uidSetting); - if (!DB::Setting::GetAsIs(_hContact, pszProto, uidSetting, &_dbvUID)) { - ret = TRUE; - } - } - // fails because the protocol is no longer installed - else { - // assert(ret == TRUE); - ret = TRUE; - } - } - - // nickname - if (!DB::Setting::GetUString(_hContact, pszProto, SET_CONTACT_NICK, &dbv)) { - _pszNick = mir_strdup(dbv.pszVal); - db_free(&dbv); - } - - if (_hContact && ret) { - // Clist Group - if (!DB::Setting::GetUString(_hContact, MOD_CLIST, "Group", &dbv)) { - _pszGroup = mir_strdup(dbv.pszVal); - db_free(&dbv); - } - // Clist DisplayName - if (!DB::Setting::GetUString(_hContact, MOD_CLIST, SET_CONTACT_MYHANDLE, &dbv)) { - _pszDisp = mir_strdup(dbv.pszVal); - db_free(&dbv); - } - } - return ret; -} - -/** - * name: fromIni - * class: CExImContactBase - * desc: get contact information from a row of a ini file - * param: row - the rows data - * return: TRUE if successful or FALSE otherwise - **/ -BYTE CExImContactBase::fromIni(LPSTR& row) -{ - LPSTR p1, p2 = NULL; - LPSTR pszUIDValue, pszUIDSetting, pszProto = NULL; - LPSTR pszBuf = &row[0]; - size_t cchBuf = strlen(row); - - MIR_FREE(_pszProtoOld); - MIR_FREE(_pszProto); - MIR_FREE(_pszAMPro); - MIR_FREE(_pszNick); - MIR_FREE(_pszDisp); - MIR_FREE(_pszGroup); - MIR_FREE(_pszUIDKey); - db_free(&_dbvUID); - ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); - _dbvUIDHash = 0; - - // read uid value - if (cchBuf > 10 && (p1 = mir_strrchr(pszBuf, '*{')) && (p2 = mir_strchr(p1, '}*')) && p1 + 2 < p2) { - pszUIDValue = p1 + 1; - *p1 = *(p2 - 1) = 0; - - // insulate the uid setting from buffer pointer - if (cchBuf > 0 && (p1 = mir_strrchr(pszBuf, '*<')) && (p2 = mir_strchr(p1, '>*')) && p1 + 2 < p2) { - pszUIDSetting = p1 + 1; - *p1 = *(p2 - 1) = 0; - - // insulate the protocol name from buffer pointer - if (cchBuf > 0 && (p1 = mir_strrchr(pszBuf, '*(')) && (p2 = mir_strchr(p1, ')*')) && p1 + 2 < p2) { - pszProto = p1 + 1; - *(--p1) = *(p2 - 1) = 0; - - // DBVT_DWORD - if (strspn(pszUIDValue, "0123456789") == mir_strlen(pszUIDValue)) { - _dbvUID.dVal = _atoi64(pszUIDValue); - _dbvUID.type = DBVT_DWORD; - } - else { - // DBVT_UTF8 - _dbvUID.pszVal = mir_strdup(pszUIDValue); - _dbvUID.type = DBVT_UTF8; - } - _pszUIDKey = mir_strdup(pszUIDSetting); - _pszProto = mir_strdup(pszProto); - } //end insulate the protocol name from buffer pointer - } //end insulate the uid setting from buffer pointer - } //end read uid value - - // create valid nickname - _pszNick = mir_strdup(pszBuf); - size_t i = strlen(_pszNick)-1; - while (i > 0 && (_pszNick[i] == ' ' || _pszNick[i] == '\t')) { - _pszNick[i] = 0; - i--; - } - // finally try to find contact in contact list - findHandle(); - return FALSE; -} - -/** - * name: toDB - * class: CExImContactBase - * desc: searches the database for a contact representing the one - * identified by this class or creates a new one if it was not found - * param: hMetaContact - a meta contact to add this contact to - * return: handle of the contact if successful - **/ -MCONTACT CExImContactBase::toDB() -{ - // create new contact if none exists - if (_hContact == INVALID_CONTACT_ID && _pszProto && _pszUIDKey && _dbvUID.type != DBVT_DELETED) { - PROTOACCOUNT* pszAccount = 0; - if (NULL == (pszAccount = ProtoGetAccount( _pszProto ))) { - //account does not exist - return _hContact = INVALID_CONTACT_ID; - } - if (!IsAccountEnabled(pszAccount)) { - ; - } - // create new contact - _hContact = DB::Contact::Add(); - if (!_hContact) { - return _hContact = INVALID_CONTACT_ID; - } - // Add the protocol to the new contact - if (CallService(MS_PROTO_ADDTOCONTACT, _hContact, (LPARAM)_pszProto)) { - DB::Contact::Delete(_hContact); - return _hContact = INVALID_CONTACT_ID; - } - // write uid to protocol module - if (db_set(_hContact, _pszProto, _pszUIDKey, &_dbvUID)) { - DB::Contact::Delete(_hContact); - return _hContact = INVALID_CONTACT_ID; - } - // write nick and display name - if (_pszNick) db_set_utf(_hContact, _pszProto, SET_CONTACT_NICK, _pszNick); - if (_pszDisp) db_set_utf(_hContact, MOD_CLIST, SET_CONTACT_MYHANDLE, _pszDisp); - - // add group - if (_pszGroup) { - ptrT ptszGroup( mir_utf8decodeT(_pszGroup)); - db_set_ts(_hContact, MOD_CLIST, "Group", ptszGroup); - if ( Clist_GroupExists(ptszGroup) == NULL) { - HANDLE hGroup = Clist_CreateGroup(NULL, NULL); - if (hGroup) { - // renaming twice is stupid but the only way to avoid error dialog telling shit like - // a group with that name does exist - CallService(MS_CLIST_GROUPRENAME, (WPARAM)hGroup, (LPARAM)ptszGroup); - } - } - } - } - return _hContact; -} - -/** - * name: toIni - * class: CExImContactBase - * desc: writes the line to an opened ini file which identifies the contact - * whose information are stored in this class - * param: file - pointer to the opened file - * return: nothing - **/ -void CExImContactBase::toIni(FILE* file, int modCount) -{ - // getting dbeditor++ NickFromHContact(hContact) - static char name[512] = ""; - char* ret = 0; - - if (_hContact){ - int loaded = _pszUIDKey ? 1 : 0; - if (_pszProto == NULL || !loaded) { - if (_pszProto){ - if (_pszNick) - mir_snprintf(name, sizeof(name),"%s (%s)", _pszNick, _pszProto); - else - mir_snprintf(name, sizeof(name),"(UNKNOWN) (%s)", _pszProto); - } - else - mir_snprintf(name, sizeof(name),"(UNKNOWN)"); - } - else { - // Proto loadet - GetContactName(hContact,pszProto,0) - LPSTR pszCI = NULL; - CONTACTINFO ci; - ZeroMemory(&ci, sizeof(ci)); - - ci.cbSize = sizeof(ci); - ci.hContact = _hContact; - ci.szProto = _pszProto; - ci.dwFlag = CNF_DISPLAY; - - if (!GetContactInfo(NULL, (LPARAM) &ci)) { - // CNF_DISPLAY always returns a string type - pszCI = (LPSTR)ci.pszVal; - } - LPSTR pszUID = uid2String(FALSE); - if (_pszUIDKey && pszUID) - mir_snprintf(name, sizeof(name), "%s *(%s)*<%s>*{%s}*", pszCI, _pszProto, _pszUIDKey, pszUID); - else - mir_snprintf(name, sizeof(name), "%s (%s)", pszCI, _pszProto); - - mir_free(pszCI); - mir_free(pszUID); - } // end else (Proto loadet) - - // it is not the best solution (but still works if only basic modules export) - need rework - if (modCount > 3) - fprintf(file, "CONTACT: %s\n", name); - else - fprintf(file, "FROM CONTACT: %s\n", name); - - } // end *if (_hContact) - else { - fprintf(file, "SETTINGS:\n"); - } -} - -BYTE CExImContactBase::compareUID(DBVARIANT *dbv) -{ - DWORD hash = 0; - switch (dbv->type) { - case DBVT_BYTE: - if (dbv->bVal == _dbvUID.bVal) { - _dbvUID.type = dbv->type; - return TRUE; - } - break; - case DBVT_WORD: - if (dbv->wVal == _dbvUID.wVal) { - _dbvUID.type = dbv->type; - return TRUE; - } - break; - case DBVT_DWORD: - if (dbv->dVal == _dbvUID.dVal) { - _dbvUID.type = dbv->type; - return TRUE; - } - break; - case DBVT_ASCIIZ: - hash = hashSetting_M2(dbv->pszVal); - case DBVT_WCHAR: - if (!hash) hash = hashSettingW_M2((const char *)dbv->pwszVal); - case DBVT_UTF8: - if (!hash) { - LPWSTR tmp = mir_utf8decodeW(dbv->pszVal); - hash = hashSettingW_M2((const char *)tmp); - mir_free(tmp); - } - if (hash == _dbvUIDHash) return TRUE; - break; - case DBVT_BLOB: //'n' cpbVal and pbVal are valid - if (_dbvUID.type == dbv->type && - _dbvUID.cpbVal == dbv->cpbVal && - memcmp(_dbvUID.pbVal, dbv->pbVal, dbv->cpbVal) == 0) { - return TRUE; - } - break; - default: - return FALSE; - } - return FALSE; -} - -LPSTR CExImContactBase::uid2String(BYTE bPrependType) -{ - CHAR szUID[MAX_PATH]; - LPSTR ptr = szUID; - - switch (_dbvUID.type) { - case DBVT_BYTE: //'b' bVal and cVal are valid - if (bPrependType) *ptr++ = 'b'; - _itoa(_dbvUID.bVal, ptr, 10); - break; - case DBVT_WORD: //'w' wVal and sVal are valid - if (bPrependType) *ptr++ = 'w'; - _itoa(_dbvUID.wVal, ptr, 10); - break; - case DBVT_DWORD: //'d' dVal and lVal are valid - if (bPrependType) *ptr++ = 'd'; - _itoa(_dbvUID.dVal, ptr, 10); - break; - case DBVT_WCHAR: //'u' pwszVal is valid - { - LPSTR r = mir_utf8encodeW(_dbvUID.pwszVal); - if (bPrependType) { - LPSTR t = (LPSTR)mir_alloc(strlen(r)+2); - t[0] = 'u'; - strcpy(t+1, r); - mir_free(r); - r = t; - } - return r; - } - case DBVT_UTF8: //'u' pszVal is valid - { - if (bPrependType) *ptr++ = 'u'; - mir_strncpy(ptr, _dbvUID.pszVal, SIZEOF(szUID)-1); - } - break; - case DBVT_ASCIIZ: { - LPSTR r = mir_utf8encode(_dbvUID.pszVal); - if (bPrependType) { - LPSTR t = (LPSTR)mir_alloc(strlen(r)+2); - t[0] = 's'; - strcpy(t+1, r); - mir_free(r); - r = t; - } - return r; - } - case DBVT_BLOB: //'n' cpbVal and pbVal are valid - { - if (bPrependType) { //True = XML - INT_PTR baselen = mir_base64_encode_bufsize(_dbvUID.cpbVal); - LPSTR t = (LPSTR)mir_alloc(baselen + 5 + bPrependType); - assert(t != NULL); - if ( mir_base64_encodebuf(_dbvUID.pbVal, _dbvUID.cpbVal, t + bPrependType, baselen)) { - t[baselen + bPrependType] = 0; - if (bPrependType) t[0] = 'n'; - return t; - } - mir_free(t); - return NULL; - } - else { //FALSE = INI - WORD j; - INT_PTR baselen = (_dbvUID.cpbVal * 3); - LPSTR t = (LPSTR)mir_alloc(3 + baselen); - ZeroMemory(t, (3 + baselen)); - for (j = 0; j < _dbvUID.cpbVal; j++) { - mir_snprintf((t + bPrependType + (j * 3)), 4,"%02X ", (BYTE)_dbvUID.pbVal[j]); - } - if (t){ - if (bPrependType) t[0] = 'n'; - return t; - } - else { - mir_free(t); - return NULL; - } - } - break; - } - default: - return NULL; - } - return mir_strdup(szUID); -} - -BYTE CExImContactBase::isMeta() const -{ - return DB::Module::IsMeta(_pszProto); -} - -BYTE CExImContactBase::isHandle(MCONTACT hContact) -{ - LPCSTR pszProto; - DBVARIANT dbv; - BYTE isEqual = FALSE; - - // owner contact ? - if (!_pszProto) return hContact == NULL; - - // compare protocols - pszProto = DB::Contact::Proto(hContact); - if (pszProto == NULL || (INT_PTR)pszProto == CALLSERVICE_NOTFOUND || lstrcmpA(pszProto, _pszProto)) - return FALSE; - - // compare uids - if (_pszUIDKey) { - // get uid - if (DB::Setting::GetAsIs(hContact, pszProto,_pszUIDKey, &dbv)) - return FALSE; - - isEqual = compareUID (&dbv); - db_free(&dbv); - } - // compare nicknames if no UID - else if (!DB::Setting::GetUString(hContact, _pszProto, SET_CONTACT_NICK, &dbv)) { - if (dbv.type == DBVT_UTF8 && dbv.pszVal && !mir_stricmp(dbv.pszVal,_pszNick)) { - LPTSTR ptszNick = mir_utf8decodeT(_pszNick); - LPTSTR ptszProto = mir_a2t(_pszProto); - int ans = MsgBox(NULL, MB_ICONQUESTION|MB_YESNO, LPGENT("Question"), LPGENT("contact identification"), - LPGENT("The contact %s(%s) has no unique ID in the vCard,\nbut there is a contact in your contact list with the same nick and protocol.\nDo you wish to use this contact?"), - ptszNick, ptszProto); - MIR_FREE(ptszNick); - MIR_FREE(ptszProto); - isEqual = ans == IDYES; - } - db_free(&dbv); - } - return isEqual; -} - -/** - * name: handle - * class: CExImContactBase - * desc: return the handle of the contact - * whose information are stored in this class - * param: none - * return: handle if successful, INVALID_HANDLE_VALUE otherwise - **/ -MCONTACT CExImContactBase::findHandle() -{ - for (MCONTACT hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) { - if (isHandle(hContact)) { - _hContact = hContact; - _isNewContact = FALSE; - return hContact; - } - } - _isNewContact = TRUE; - return _hContact = INVALID_CONTACT_ID; -} +/* +UserinfoEx plugin for Miranda IM + +Copyright: +© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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 "..\commonheaders.h" + +/** + * name: CExImContactBase + * class: CExImContactBase + * desc: default constructor + * param: none + * return: nothing + **/ +CExImContactBase::CExImContactBase() +{ + _pszNick = NULL; + _pszDisp = NULL; + _pszGroup = NULL; + _pszProto = NULL; + _pszProtoOld = NULL; + _pszAMPro = NULL; + _pszUIDKey = NULL; + _dbvUIDHash = NULL; + ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); + _hContact = INVALID_CONTACT_ID; + _isNewContact = FALSE; +} + +/** + * name: ~CExImContactBase + * class: CExImContactBase + * desc: default denstructor + * param: none + * return: nothing + **/ +CExImContactBase::~CExImContactBase() +{ + MIR_FREE(_pszNick); + MIR_FREE(_pszDisp); + MIR_FREE(_pszGroup); + MIR_FREE(_pszProtoOld); + MIR_FREE(_pszProto); + MIR_FREE(_pszAMPro); + MIR_FREE(_pszUIDKey); + db_free(&_dbvUID); + ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); +} + +/** + * name: fromDB + * class: CExImContactBase + * desc: get contact information from database + * param: hContact - handle to contact whose information to read + * return: TRUE if successful or FALSE otherwise + **/ +BYTE CExImContactBase::fromDB(MCONTACT hContact) +{ + BYTE ret = FALSE; + BYTE isChatRoom = FALSE; + LPSTR pszProto; + LPCSTR uidSetting; + DBVARIANT dbv; + + _hContact = hContact; + _dbvUIDHash = 0; + MIR_FREE(_pszProtoOld); + MIR_FREE(_pszProto); + MIR_FREE(_pszAMPro); + MIR_FREE(_pszNick); + MIR_FREE(_pszDisp); + MIR_FREE(_pszGroup); + MIR_FREE(_pszUIDKey); + db_free(&_dbvUID); + ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); + + // OWNER + if (!_hContact) return TRUE; + + // Proto + if (!(pszProto = DB::Contact::Proto(_hContact))) return FALSE; + _pszProto = mir_strdup(pszProto); + + // AM_BaseProto + if (!DB::Setting::GetUString(NULL, pszProto, "AM_BaseProto", &dbv )) { + _pszAMPro = mir_strdup(dbv.pszVal); + db_free(&dbv); + } + + // unique id (for ChatRoom) + if (isChatRoom = db_get_b(_hContact, pszProto, "ChatRoom", 0)) { + uidSetting = "ChatRoomID"; + _pszUIDKey = mir_strdup(uidSetting); + if (!DB::Setting::GetAsIs(_hContact, pszProto, uidSetting, &_dbvUID)) { + ret = TRUE; + } + } + // unique id (normal) + else { + uidSetting = (LPCSTR)CallProtoService(pszProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0); + // valid + if (uidSetting != NULL && (INT_PTR)uidSetting != CALLSERVICE_NOTFOUND) { + _pszUIDKey = mir_strdup(uidSetting); + if (!DB::Setting::GetAsIs(_hContact, pszProto, uidSetting, &_dbvUID)) { + ret = TRUE; + } + } + // fails because the protocol is no longer installed + else { + // assert(ret == TRUE); + ret = TRUE; + } + } + + // nickname + if (!DB::Setting::GetUString(_hContact, pszProto, SET_CONTACT_NICK, &dbv)) { + _pszNick = mir_strdup(dbv.pszVal); + db_free(&dbv); + } + + if (_hContact && ret) { + // Clist Group + if (!DB::Setting::GetUString(_hContact, MOD_CLIST, "Group", &dbv)) { + _pszGroup = mir_strdup(dbv.pszVal); + db_free(&dbv); + } + // Clist DisplayName + if (!DB::Setting::GetUString(_hContact, MOD_CLIST, SET_CONTACT_MYHANDLE, &dbv)) { + _pszDisp = mir_strdup(dbv.pszVal); + db_free(&dbv); + } + } + return ret; +} + +/** + * name: fromIni + * class: CExImContactBase + * desc: get contact information from a row of a ini file + * param: row - the rows data + * return: TRUE if successful or FALSE otherwise + **/ +BYTE CExImContactBase::fromIni(LPSTR& row) +{ + LPSTR p1, p2 = NULL; + LPSTR pszUIDValue, pszUIDSetting, pszProto = NULL; + LPSTR pszBuf = &row[0]; + size_t cchBuf = strlen(row); + + MIR_FREE(_pszProtoOld); + MIR_FREE(_pszProto); + MIR_FREE(_pszAMPro); + MIR_FREE(_pszNick); + MIR_FREE(_pszDisp); + MIR_FREE(_pszGroup); + MIR_FREE(_pszUIDKey); + db_free(&_dbvUID); + ZeroMemory(&_dbvUID, sizeof(DBVARIANT)); + _dbvUIDHash = 0; + + // read uid value + if (cchBuf > 10 && (p1 = mir_strrchr(pszBuf, '*{')) && (p2 = mir_strchr(p1, '}*')) && p1 + 2 < p2) { + pszUIDValue = p1 + 1; + *p1 = *(p2 - 1) = 0; + + // insulate the uid setting from buffer pointer + if (cchBuf > 0 && (p1 = mir_strrchr(pszBuf, '*<')) && (p2 = mir_strchr(p1, '>*')) && p1 + 2 < p2) { + pszUIDSetting = p1 + 1; + *p1 = *(p2 - 1) = 0; + + // insulate the protocol name from buffer pointer + if (cchBuf > 0 && (p1 = mir_strrchr(pszBuf, '*(')) && (p2 = mir_strchr(p1, ')*')) && p1 + 2 < p2) { + pszProto = p1 + 1; + *(--p1) = *(p2 - 1) = 0; + + // DBVT_DWORD + if (strspn(pszUIDValue, "0123456789") == mir_strlen(pszUIDValue)) { + _dbvUID.dVal = _atoi64(pszUIDValue); + _dbvUID.type = DBVT_DWORD; + } + else { + // DBVT_UTF8 + _dbvUID.pszVal = mir_strdup(pszUIDValue); + _dbvUID.type = DBVT_UTF8; + } + _pszUIDKey = mir_strdup(pszUIDSetting); + _pszProto = mir_strdup(pszProto); + } //end insulate the protocol name from buffer pointer + } //end insulate the uid setting from buffer pointer + } //end read uid value + + // create valid nickname + _pszNick = mir_strdup(pszBuf); + size_t i = strlen(_pszNick)-1; + while (i > 0 && (_pszNick[i] == ' ' || _pszNick[i] == '\t')) { + _pszNick[i] = 0; + i--; + } + // finally try to find contact in contact list + findHandle(); + return FALSE; +} + +/** + * name: toDB + * class: CExImContactBase + * desc: searches the database for a contact representing the one + * identified by this class or creates a new one if it was not found + * param: hMetaContact - a meta contact to add this contact to + * return: handle of the contact if successful + **/ +MCONTACT CExImContactBase::toDB() +{ + // create new contact if none exists + if (_hContact == INVALID_CONTACT_ID && _pszProto && _pszUIDKey && _dbvUID.type != DBVT_DELETED) { + PROTOACCOUNT* pszAccount = 0; + if (NULL == (pszAccount = ProtoGetAccount( _pszProto ))) { + //account does not exist + return _hContact = INVALID_CONTACT_ID; + } + if (!IsAccountEnabled(pszAccount)) { + ; + } + // create new contact + _hContact = DB::Contact::Add(); + if (!_hContact) { + return _hContact = INVALID_CONTACT_ID; + } + // Add the protocol to the new contact + if (CallService(MS_PROTO_ADDTOCONTACT, _hContact, (LPARAM)_pszProto)) { + DB::Contact::Delete(_hContact); + return _hContact = INVALID_CONTACT_ID; + } + // write uid to protocol module + if (db_set(_hContact, _pszProto, _pszUIDKey, &_dbvUID)) { + DB::Contact::Delete(_hContact); + return _hContact = INVALID_CONTACT_ID; + } + // write nick and display name + if (_pszNick) db_set_utf(_hContact, _pszProto, SET_CONTACT_NICK, _pszNick); + if (_pszDisp) db_set_utf(_hContact, MOD_CLIST, SET_CONTACT_MYHANDLE, _pszDisp); + + // add group + if (_pszGroup) { + ptrT ptszGroup( mir_utf8decodeT(_pszGroup)); + db_set_ts(_hContact, MOD_CLIST, "Group", ptszGroup); + if ( Clist_GroupExists(ptszGroup) == NULL) { + HANDLE hGroup = Clist_CreateGroup(NULL, NULL); + if (hGroup) { + // renaming twice is stupid but the only way to avoid error dialog telling shit like + // a group with that name does exist + CallService(MS_CLIST_GROUPRENAME, (WPARAM)hGroup, (LPARAM)ptszGroup); + } + } + } + } + return _hContact; +} + +/** + * name: toIni + * class: CExImContactBase + * desc: writes the line to an opened ini file which identifies the contact + * whose information are stored in this class + * param: file - pointer to the opened file + * return: nothing + **/ +void CExImContactBase::toIni(FILE* file, int modCount) +{ + // getting dbeditor++ NickFromHContact(hContact) + static char name[512] = ""; + char* ret = 0; + + if (_hContact){ + int loaded = _pszUIDKey ? 1 : 0; + if (_pszProto == NULL || !loaded) { + if (_pszProto){ + if (_pszNick) + mir_snprintf(name, sizeof(name),"%s (%s)", _pszNick, _pszProto); + else + mir_snprintf(name, sizeof(name),"(UNKNOWN) (%s)", _pszProto); + } + else + mir_snprintf(name, sizeof(name),"(UNKNOWN)"); + } + else { + // Proto loadet - GetContactName(hContact,pszProto,0) + LPSTR pszCI = NULL; + CONTACTINFO ci; + ZeroMemory(&ci, sizeof(ci)); + + ci.cbSize = sizeof(ci); + ci.hContact = _hContact; + ci.szProto = _pszProto; + ci.dwFlag = CNF_DISPLAY; + + if (!GetContactInfo(NULL, (LPARAM) &ci)) { + // CNF_DISPLAY always returns a string type + pszCI = (LPSTR)ci.pszVal; + } + LPSTR pszUID = uid2String(FALSE); + if (_pszUIDKey && pszUID) + mir_snprintf(name, sizeof(name), "%s *(%s)*<%s>*{%s}*", pszCI, _pszProto, _pszUIDKey, pszUID); + else + mir_snprintf(name, sizeof(name), "%s (%s)", pszCI, _pszProto); + + mir_free(pszCI); + mir_free(pszUID); + } // end else (Proto loadet) + + // it is not the best solution (but still works if only basic modules export) - need rework + if (modCount > 3) + fprintf(file, "CONTACT: %s\n", name); + else + fprintf(file, "FROM CONTACT: %s\n", name); + + } // end *if (_hContact) + else { + fprintf(file, "SETTINGS:\n"); + } +} + +BYTE CExImContactBase::compareUID(DBVARIANT *dbv) +{ + DWORD hash = 0; + switch (dbv->type) { + case DBVT_BYTE: + if (dbv->bVal == _dbvUID.bVal) { + _dbvUID.type = dbv->type; + return TRUE; + } + break; + case DBVT_WORD: + if (dbv->wVal == _dbvUID.wVal) { + _dbvUID.type = dbv->type; + return TRUE; + } + break; + case DBVT_DWORD: + if (dbv->dVal == _dbvUID.dVal) { + _dbvUID.type = dbv->type; + return TRUE; + } + break; + case DBVT_ASCIIZ: + hash = hashSetting_M2(dbv->pszVal); + case DBVT_WCHAR: + if (!hash) hash = hashSettingW_M2((const char *)dbv->pwszVal); + case DBVT_UTF8: + if (!hash) { + LPWSTR tmp = mir_utf8decodeW(dbv->pszVal); + hash = hashSettingW_M2((const char *)tmp); + mir_free(tmp); + } + if (hash == _dbvUIDHash) + return TRUE; + break; + case DBVT_BLOB: //'n' cpbVal and pbVal are valid + if (_dbvUID.type == dbv->type && + _dbvUID.cpbVal == dbv->cpbVal && + memcmp(_dbvUID.pbVal, dbv->pbVal, dbv->cpbVal) == 0) { + return TRUE; + } + break; + default: + return FALSE; + } + return FALSE; +} + +LPSTR CExImContactBase::uid2String(BYTE bPrependType) +{ + CHAR szUID[4096]; + LPSTR ptr = szUID; + LPSTR r; + SIZE_T baselen; + + switch (_dbvUID.type) { + case DBVT_BYTE: //'b' bVal and cVal are valid + if (bPrependType) + *ptr++ = 'b'; + _itoa(_dbvUID.bVal, ptr, 10); + break; + case DBVT_WORD: //'w' wVal and sVal are valid + if (bPrependType) + *ptr++ = 'w'; + _itoa(_dbvUID.wVal, ptr, 10); + break; + case DBVT_DWORD: //'d' dVal and lVal are valid + if (bPrependType) + *ptr++ = 'd'; + _itoa(_dbvUID.dVal, ptr, 10); + break; + case DBVT_WCHAR: //'u' pwszVal is valid + r = mir_utf8encodeW(_dbvUID.pwszVal); + if (r == NULL) + return NULL; + if (bPrependType == FALSE) + return r; + *ptr++ = 'u'; + mir_strncpy(ptr, r, sizeof(szUID) - 1); + mir_free(r); + break; + case DBVT_UTF8: //'u' pszVal is valid + if (bPrependType) + *ptr++ = 'u'; + mir_strncpy(ptr, _dbvUID.pszVal, sizeof(szUID) - 1); + break; + case DBVT_ASCIIZ: + r = mir_utf8encode(_dbvUID.pszVal); + if (r == NULL) + return NULL; + if (bPrependType == FALSE) + return r; + *ptr++ = 's'; + mir_strncpy(ptr, r, sizeof(szUID) - 1); + mir_free(r); + break; + case DBVT_BLOB: //'n' cpbVal and pbVal are valid + if (bPrependType) { //True = XML + baselen = mir_base64_encode_bufsize(_dbvUID.cpbVal); + r = (LPSTR)mir_alloc((baselen + 8)); + if (r == NULL) + return NULL; + ZeroMemory((r + baselen), 8); + ptr = r; + if (bPrependType) { // Allways true. + ptr[0] = 'n'; + ptr ++; + } + if (!mir_base64_encodebuf(_dbvUID.pbVal, _dbvUID.cpbVal, ptr, baselen)) { + mir_free(r); + return NULL; + } + return r; + } + else { //FALSE = INI + baselen = ((_dbvUID.cpbVal * 3) + 8); + r = (LPSTR)mir_alloc(baselen); + if (r == NULL) + return NULL; + ZeroMemory(r, baselen); + ptr = r; + if (bPrependType) { // XXX dead code. + ptr[0] = 'n'; + ptr ++; + } + for (SIZE_T j = 0; j < _dbvUID.cpbVal; j ++, ptr += 3) { + mir_snprintf(ptr, ((r + baselen) - ptr), "%02X ", (BYTE)_dbvUID.pbVal[j]); + } + return r; + } + break; + default: + return NULL; + } + return mir_strdup(szUID); +} + +BYTE CExImContactBase::isMeta() const +{ + return DB::Module::IsMeta(_pszProto); +} + +BYTE CExImContactBase::isHandle(MCONTACT hContact) +{ + LPCSTR pszProto; + DBVARIANT dbv; + BYTE isEqual = FALSE; + + // owner contact ? + if (!_pszProto) return hContact == NULL; + + // compare protocols + pszProto = DB::Contact::Proto(hContact); + if (pszProto == NULL || (INT_PTR)pszProto == CALLSERVICE_NOTFOUND || lstrcmpA(pszProto, _pszProto)) + return FALSE; + + // compare uids + if (_pszUIDKey) { + // get uid + if (DB::Setting::GetAsIs(hContact, pszProto,_pszUIDKey, &dbv)) + return FALSE; + + isEqual = compareUID (&dbv); + db_free(&dbv); + } + // compare nicknames if no UID + else if (!DB::Setting::GetUString(hContact, _pszProto, SET_CONTACT_NICK, &dbv)) { + if (dbv.type == DBVT_UTF8 && dbv.pszVal && !mir_stricmp(dbv.pszVal,_pszNick)) { + LPTSTR ptszNick = mir_utf8decodeT(_pszNick); + LPTSTR ptszProto = mir_a2t(_pszProto); + int ans = MsgBox(NULL, MB_ICONQUESTION|MB_YESNO, LPGENT("Question"), LPGENT("contact identification"), + LPGENT("The contact %s(%s) has no unique ID in the vCard,\nbut there is a contact in your contact list with the same nick and protocol.\nDo you wish to use this contact?"), + ptszNick, ptszProto); + MIR_FREE(ptszNick); + MIR_FREE(ptszProto); + isEqual = ans == IDYES; + } + db_free(&dbv); + } + return isEqual; +} + +/** + * name: handle + * class: CExImContactBase + * desc: return the handle of the contact + * whose information are stored in this class + * param: none + * return: handle if successful, INVALID_HANDLE_VALUE otherwise + **/ +MCONTACT CExImContactBase::findHandle() +{ + for (MCONTACT hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) { + if (isHandle(hContact)) { + _hContact = hContact; + _isNewContact = FALSE; + return hContact; + } + } + _isNewContact = TRUE; + return _hContact = INVALID_CONTACT_ID; +} diff --git a/plugins/UserInfoEx/src/ex_import/svc_ExImINI.cpp b/plugins/UserInfoEx/src/ex_import/svc_ExImINI.cpp index 458e41d901..7c126562fa 100644 --- a/plugins/UserInfoEx/src/ex_import/svc_ExImINI.cpp +++ b/plugins/UserInfoEx/src/ex_import/svc_ExImINI.cpp @@ -1,525 +1,524 @@ -/* -UserinfoEx plugin for Miranda IM - -Copyright: -© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol - -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. -*/ - -/** - * system & local includes: - **/ - -#include "..\commonheaders.h" - -/*********************************************************************************************************** - * exporting stuff - ***********************************************************************************************************/ - -/** - * name: ExportModule - * desc: write all settings from a database module to file - * param: hContact - handle of contact the module is owned from - * pszModule - name of the module to save - * file - file to write the settings to - * return nothing - **/ -static void ExportModule(MCONTACT hContact, LPCSTR pszModule, FILE* file) -{ - DB::CEnumList Settings; - - if (!Settings.EnumSettings(hContact, pszModule)) - { - DBVARIANT dbv; - LPSTR here; - WORD j; - int i; - LPSTR pszSetting; - //char tmp[32]; - - // print the module header.. - fprintf(file, "\n[%s]\n", pszModule); - - for (i = 0; i < Settings.getCount(); i++) - { - pszSetting = Settings[i]; - - if (!DB::Setting::GetAsIs(hContact, pszModule, pszSetting, &dbv)) - { - switch (dbv.type) - { - case DBVT_BYTE: - { - fprintf(file, "%s=b%u\n", pszSetting, dbv.bVal); - } - break; - - case DBVT_WORD: - { - fprintf(file, "%s=w%u\n", pszSetting, dbv.wVal); - } - break; - - case DBVT_DWORD: - { - fprintf(file, "%s=d%u\n", pszSetting, dbv.dVal); - } - break; - - case DBVT_ASCIIZ: - case DBVT_UTF8: - { - for (here = dbv.pszVal; here && *here; here++) - { - switch (*here) { - // convert \r to STX - case '\r': - *here = 2; - break; - - // convert \n to ETX - case '\n': - *here = 3; - } - } - if (dbv.type == DBVT_UTF8) - fprintf(file, "%s=u%s\n", pszSetting, dbv.pszVal); - else - fprintf(file, "%s=s%s\n", pszSetting, dbv.pszVal); - } - break; - - case DBVT_BLOB: - { - fprintf(file, "%s=n", pszSetting); - for (j = 0; j < dbv.cpbVal; j++) - { - fprintf(file, "%02X ", (BYTE)dbv.pbVal[j]); - } - fputc('\n', file); - } - break; - } - db_free(&dbv); - } - } - } -} - -/** - * name: ExportContact - * desc: Exports a certain contact to an ini file. - * param: hContact - contact to export or -1 to export all contacts - * pModules - module to export, NULL to export all modules of a contact - * file - ini file to write the contact to - **/ -static BYTE ExportContact(MCONTACT hContact, DB::CEnumList* pModules, FILE* file) -{ - CExImContactBase vcc; - - if (pModules) - { - if ((vcc = hContact) >= NULL) - { - int i; - LPSTR p; - - vcc.toIni(file, pModules->getCount()-1); - - for (i = 0; i < pModules->getCount(); i++) - { - p = (*pModules)[i]; - - /*Filter/ - if (mir_stricmp(p, "Protocol"))*/ - { - ExportModule(hContact, p, file); - } - } - return TRUE; - } - } - return FALSE; -} - -/** - * name: SvcExImINI_Export - * desc: Exports a certain contact or all contacts to an ini file. - * param: hContact - contact to export or -1 to export all contacts - * pszFileName - ini-filename to write the contact to - **/ -int SvcExImINI_Export(lpExImParam ExImContact, LPCSTR pszFileName) -{ - FILE* file; - errno_t err; - DB::CEnumList Modules; - SYSTEMTIME now; - MCONTACT hContact; - - if (!DlgExImModules_SelectModulesToExport(ExImContact, &Modules, NULL)) - { - if ((err = fopen_s(&file, pszFileName, "wt")) != NULL) - { - MsgErr(NULL, - LPGENT("The ini-file \"%s\"\nfor saving contact information could not be opened."), - pszFileName); - return 1; - } - - SetCursor(LoadCursor(NULL, IDC_WAIT)); - - // write header - GetLocalTime(&now); - fprintf(file, - ";DATE = %04d-%02d-%02d %02d:%02d:%02d\n\n", - now.wYear, now.wMonth, now.wDay, now.wHour, now.wMinute, now.wSecond - ); - - if (Modules.getCount() == 0) - { - Modules.EnumModules(); - } - - // hContact == -1 export entire db. - if (ExImContact->Typ != EXIM_CONTACT) - { - // Owner - ExportContact(NULL, &Modules, file); - fprintf(file, "\n\n"); - // Contacts - for (hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) - { - ExportContact(hContact, &Modules, file); - fprintf(file, "\n\n"); - } - } - // export only one contact - else - { - ExportContact(ExImContact->hContact, &Modules, file); - } - - if (file) - fclose(file); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - } - return 0; -} - -/*********************************************************************************************************** - * importing stuff - ***********************************************************************************************************/ - -LPSTR strnrchr(LPSTR string, int ch, DWORD len) -{ - LPSTR start = (LPSTR)string; - - string += len; /* find end of string */ - /* search towards front */ - while (--string != start && *string != (CHAR)ch); - if (*string == (CHAR)ch) /* char found ? */ - return ((LPSTR)string); - return(NULL); -} - -/** - * name: ImportreadLine - * desc: read exactly one line into a buffer and return its pointer. Size of buffer is managed. - * param: file - pointer to a file - * string - the string to write the read line to - * return: pointer to the buffer on success or NULL on error - **/ -static DWORD ImportreadLine(FILE* file, LPSTR &str) -{ - CHAR c; - DWORD l = 0; - BYTE bComment = 0; - - str[0] = 0; - while (!feof(file)) { - switch (c = fgetc(file)) { - case EOF: - // reading error - if (ferror(file)) { - MIR_FREE(str); - return 0; - } - // end of line & file - return l; - - case '\r': - case '\n': - // ignore empty lines - if (l == 0) { - bComment = 0; - continue; - } - return l; - - case ';': - // found a comment line - bComment |= l == 0; - case '\t': - case ' ': - // ignore space and tab at the beginning of the line - if (l == 0) break; - - default: - if (!bComment) { - str = mir_strncat_c(str, c); - l++; - } - break; - } - } - return 0; -} - -/** - * name: ImportFindContact - * desc: This function decodes the given line, which is already identified to be a contact line. - * The resulting information is matcht to the given hContact if it isn't NULL. - * Otherwise all existing contacts are matched. - * param: hContact - handle to contact to match or NULL to match all existing - * pszBuf - pointer to the buffer holding the string of the current line in the ini.-file - * cchBuf - character count of the buffer - * return: handle to the contact that matches the information or NULL if no match - **/ -static MCONTACT ImportFindContact(MCONTACT hContact, LPSTR &strBuf, BYTE bCanCreate) -{ - CExImContactBase vcc; - - vcc.fromIni(strBuf); - if (vcc.handle() != INVALID_CONTACT_ID) { - //if (vcc.isHandle(hContact)) - // return hContact; - return vcc.handle(); - } - else if (bCanCreate) - return vcc.toDB(); - - return vcc.handle(); -} - -/** - * name: ImportSetting - * desc: This function writes a line identified as a setting to the database - * param: hContact - handle to contact to match or NULL to match all existing - * pszModule - module to write the setting to - * strLine - string with the setting and its value to write to db - * return: 0 if writing was ok, 1 otherwise - **/ -int ImportSetting(MCONTACT hContact, LPCSTR pszModule, LPSTR &strLine) -{ - DBVARIANT dbv; - LPSTR end, value; - size_t numLines = 0; - size_t brk; - LPSTR pszLine = strLine; - - // check Module and filter "Protocol" - if (!pszModule || !*pszModule || mir_strncmp(pszModule,"Protocol",8) == 0) - return 1; - if ((end = value = mir_strchr(pszLine, '=')) == NULL) - return 1; - - // truncate setting string if it has spaces at the end - do { - if (end == pszLine) - return 1; - *(end--) = 0; - } - while (*end == '\t' || *end == ' ' || *end < 27); - - // skip spaces from the beginning of the value - do { - value++; - // if the value is empty, delete it from db - if (*value == '\0') - return db_unset(hContact, pszModule, pszLine); - } while (*value == '\t' || *value == ' '); - - // decode database type and value - switch (*(value++)) { - case 'b': - case 'B': - if (brk = strspn(value, "0123456789-")) - *(value + brk) = 0; - dbv.type = DBVT_BYTE; - dbv.bVal = (BYTE)atoi(value); - break; - case 'w': - case 'W': - if (brk = strspn(value, "0123456789-")) - *(value + brk) = 0; - dbv.type = DBVT_WORD; - dbv.wVal = (WORD)atoi(value); - break; - case 'd': - case 'D': - if (brk = strspn(value, "0123456789-")) - *(value + brk) = 0; - dbv.type = DBVT_DWORD; - dbv.dVal = (DWORD)_atoi64(value); - break; - case 's': - case 'S': - case 'u': - case 'U': - for (end = value; end && *end; end++) { - switch (*end) { - // convert STX back to \r - case 2: - *end = '\r'; - break; - // convert ETX back to \n - case 3: - *end = '\n'; - break; - } - } - switch (*(value - 1)) { - case 's': - case 'S': - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = value; - break; - case 'u': - case 'U': - dbv.type = DBVT_UTF8; - dbv.pszVal = value; - break; - } - break; - case 'n': - case 'N': - { - PBYTE dest; - dbv.type = DBVT_BLOB; - dbv.cpbVal = (WORD)mir_strlen(value) / 3; - dbv.pbVal = (PBYTE)value; - for ( dest = dbv.pbVal, value = strtok(value, " "); - value && *value; - value = strtok(NULL, " ")) - *(dest++) = (BYTE)strtol(value, NULL, 16); - *dest = 0; - break; - } - default: - dbv.type = DBVT_DELETED; - //return 1; - } - return db_set(hContact, pszModule, pszLine, &dbv); -} - -/** - * name: Import - * desc: This function imports an ini file - * param: hContact - handle to contact to match or NULL to match all existing - * file - module to write the setting to - * strLine - string with the setting and its value to write to db - * return: 0 if writing was ok, 1 otherwise - **/ -int SvcExImINI_Import(MCONTACT hContact, LPCSTR pszFileName) -{ - FILE *file; - MCONTACT hNewContact = INVALID_CONTACT_ID; - DWORD end, - numLines = 0; - CHAR szModule[MAXSETTING] = {0}; - WORD numContactsInFile = 0, // number of contacts in the inifile - numContactsAdded = 0; // number of contacts, that were added to the database - CHAR *strBuf = (CHAR *) mir_alloc(1); - *strBuf = 0; - - if (file = fopen(pszFileName, "rt")) { - SetCursor(LoadCursor(NULL, IDC_WAIT)); - - while (ImportreadLine(file, strBuf)) { - numLines++; - - // contact was found and imported - if (hContact != INVALID_CONTACT_ID && hNewContact != INVALID_CONTACT_ID) - break; - - // importing settings is only valid vor the main menu item - if (hContact == INVALID_CONTACT_ID) { - if (!strncmp(strBuf, "SETTINGS:", 9)) { - *szModule = 0; - hNewContact = NULL; - continue; - } - } - - // there are some modules of a contact (import only if contact exist) - if (!strncmp(strBuf, "FROM CONTACT:", 13)) { - strBuf = mir_strnerase(strBuf, 0, 13); - while (strBuf[0] == ' ' || strBuf[0] == '\t') - strBuf = mir_strnerase(strBuf, 0, 1); - - numContactsInFile++; - if ((hNewContact = ImportFindContact(hContact, strBuf, FALSE)) != INVALID_CONTACT_ID) - numContactsAdded++; - continue; - } - - // there is a contact to import / add - if (!strncmp(strBuf, "CONTACT:", 8)) { - strBuf = mir_strnerase(strBuf, 0, 8); - while (strBuf[0] == ' ' || strBuf[0] == '\t') - strBuf = mir_strnerase(strBuf, 0, 1); - - *szModule = 0; - numContactsInFile++; - if ((hNewContact = ImportFindContact(hContact, strBuf, TRUE)) != INVALID_CONTACT_ID) - numContactsAdded++; - continue; - } - - // read modules and settings only for valid contacts - if (hNewContact != INVALID_CONTACT_ID) { - // found a module line - if (strBuf[0] == '[' && (end = (strchr(strBuf, ']') - strBuf)) > 0) { - mir_strncpy(szModule, &strBuf[1], end); - continue; - } - // try to import a setting - ImportSetting(hNewContact, szModule, strBuf); - } - } //end while - fclose(file); - mir_free(strBuf); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - // the contact was not found in the file - if (numContactsInFile > 0 && !numContactsAdded) { - MsgErr(NULL, - LPGENT("None of the %d contacts, stored in the ini-file, match the selected contact!\nNothing will be imported"), - numContactsInFile); - } - // Import complete - else{ - MsgBox(NULL, MB_ICON_INFO, LPGENT("Import complete"), LPGENT("Some basic statistics"), - LPGENT("Added %d of %d contacts stored in the ini-file."), - numContactsAdded, numContactsInFile); - } - return 0; - } - MsgErr(NULL, - LPGENT("The ini-file \"%s\"\nfor reading contact information could not be opened."), - pszFileName); - return 1; -} +/* +UserinfoEx plugin for Miranda IM + +Copyright: +© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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. +*/ + +/** + * system & local includes: + **/ + +#include "..\commonheaders.h" + +/*********************************************************************************************************** + * exporting stuff + ***********************************************************************************************************/ + +/** + * name: ExportModule + * desc: write all settings from a database module to file + * param: hContact - handle of contact the module is owned from + * pszModule - name of the module to save + * file - file to write the settings to + * return nothing + **/ +static void ExportModule(MCONTACT hContact, LPCSTR pszModule, FILE* file) +{ + DB::CEnumList Settings; + + if (!Settings.EnumSettings(hContact, pszModule)) + { + DBVARIANT dbv; + LPSTR here; + WORD j; + int i; + LPSTR pszSetting; + //char tmp[32]; + + // print the module header.. + fprintf(file, "\n[%s]\n", pszModule); + + for (i = 0; i < Settings.getCount(); i++) + { + pszSetting = Settings[i]; + + if (!DB::Setting::GetAsIs(hContact, pszModule, pszSetting, &dbv)) + { + switch (dbv.type) + { + case DBVT_BYTE: + { + fprintf(file, "%s=b%u\n", pszSetting, dbv.bVal); + } + break; + + case DBVT_WORD: + { + fprintf(file, "%s=w%u\n", pszSetting, dbv.wVal); + } + break; + + case DBVT_DWORD: + { + fprintf(file, "%s=d%u\n", pszSetting, dbv.dVal); + } + break; + + case DBVT_ASCIIZ: + case DBVT_UTF8: + { + for (here = dbv.pszVal; here && *here; here++) + { + switch (*here) { + // convert \r to STX + case '\r': + *here = 2; + break; + + // convert \n to ETX + case '\n': + *here = 3; + } + } + if (dbv.type == DBVT_UTF8) + fprintf(file, "%s=u%s\n", pszSetting, dbv.pszVal); + else + fprintf(file, "%s=s%s\n", pszSetting, dbv.pszVal); + } + break; + + case DBVT_BLOB: + { + fprintf(file, "%s=n", pszSetting); + for (j = 0; j < dbv.cpbVal; j++) + { + fprintf(file, "%02X ", (BYTE)dbv.pbVal[j]); + } + fputc('\n', file); + } + break; + } + db_free(&dbv); + } + } + } +} + +/** + * name: ExportContact + * desc: Exports a certain contact to an ini file. + * param: hContact - contact to export or -1 to export all contacts + * pModules - module to export, NULL to export all modules of a contact + * file - ini file to write the contact to + **/ +static BYTE ExportContact(MCONTACT hContact, DB::CEnumList* pModules, FILE* file) +{ + CExImContactBase vcc; + + if (pModules) + { + if ((vcc = hContact) >= NULL) + { + int i; + LPSTR p; + + vcc.toIni(file, pModules->getCount()-1); + + for (i = 0; i < pModules->getCount(); i++) + { + p = (*pModules)[i]; + + /*Filter/ + if (mir_stricmp(p, "Protocol"))*/ + { + ExportModule(hContact, p, file); + } + } + return TRUE; + } + } + return FALSE; +} + +/** + * name: SvcExImINI_Export + * desc: Exports a certain contact or all contacts to an ini file. + * param: hContact - contact to export or -1 to export all contacts + * pszFileName - ini-filename to write the contact to + **/ +int SvcExImINI_Export(lpExImParam ExImContact, LPCSTR pszFileName) +{ + FILE* file; + errno_t err; + DB::CEnumList Modules; + SYSTEMTIME now; + MCONTACT hContact; + + if (!DlgExImModules_SelectModulesToExport(ExImContact, &Modules, NULL)) + { + if ((err = fopen_s(&file, pszFileName, "wt")) != NULL) + { + MsgErr(NULL, + LPGENT("The ini-file \"%s\"\nfor saving contact information could not be opened."), + pszFileName); + return 1; + } + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + // write header + GetLocalTime(&now); + fprintf(file, + ";DATE = %04d-%02d-%02d %02d:%02d:%02d\n\n", + now.wYear, now.wMonth, now.wDay, now.wHour, now.wMinute, now.wSecond + ); + + if (Modules.getCount() == 0) + { + Modules.EnumModules(); + } + + // hContact == -1 export entire db. + if (ExImContact->Typ != EXIM_CONTACT) + { + // Owner + ExportContact(NULL, &Modules, file); + fprintf(file, "\n\n"); + // Contacts + for (hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) + { + ExportContact(hContact, &Modules, file); + fprintf(file, "\n\n"); + } + } + // export only one contact + else + { + ExportContact(ExImContact->hContact, &Modules, file); + } + + fclose(file); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } + return 0; +} + +/*********************************************************************************************************** + * importing stuff + ***********************************************************************************************************/ + +LPSTR strnrchr(LPSTR string, int ch, DWORD len) +{ + LPSTR start = (LPSTR)string; + + string += len; /* find end of string */ + /* search towards front */ + while (--string != start && *string != (CHAR)ch); + if (*string == (CHAR)ch) /* char found ? */ + return ((LPSTR)string); + return(NULL); +} + +/** + * name: ImportreadLine + * desc: read exactly one line into a buffer and return its pointer. Size of buffer is managed. + * param: file - pointer to a file + * string - the string to write the read line to + * return: pointer to the buffer on success or NULL on error + **/ +static DWORD ImportreadLine(FILE* file, LPSTR &str) +{ + CHAR c; + DWORD l = 0; + BYTE bComment = 0; + + str[0] = 0; + while (!feof(file)) { + switch (c = fgetc(file)) { + case EOF: + // reading error + if (ferror(file)) { + MIR_FREE(str); + return 0; + } + // end of line & file + return l; + + case '\r': + case '\n': + // ignore empty lines + if (l == 0) { + bComment = 0; + continue; + } + return l; + + case ';': + // found a comment line + bComment |= l == 0; + case '\t': + case ' ': + // ignore space and tab at the beginning of the line + if (l == 0) break; + + default: + if (!bComment) { + str = mir_strncat_c(str, c); + l++; + } + break; + } + } + return 0; +} + +/** + * name: ImportFindContact + * desc: This function decodes the given line, which is already identified to be a contact line. + * The resulting information is matcht to the given hContact if it isn't NULL. + * Otherwise all existing contacts are matched. + * param: hContact - handle to contact to match or NULL to match all existing + * pszBuf - pointer to the buffer holding the string of the current line in the ini.-file + * cchBuf - character count of the buffer + * return: handle to the contact that matches the information or NULL if no match + **/ +static MCONTACT ImportFindContact(MCONTACT hContact, LPSTR &strBuf, BYTE bCanCreate) +{ + CExImContactBase vcc; + + vcc.fromIni(strBuf); + if (vcc.handle() != INVALID_CONTACT_ID) { + //if (vcc.isHandle(hContact)) + // return hContact; + return vcc.handle(); + } + else if (bCanCreate) + return vcc.toDB(); + + return vcc.handle(); +} + +/** + * name: ImportSetting + * desc: This function writes a line identified as a setting to the database + * param: hContact - handle to contact to match or NULL to match all existing + * pszModule - module to write the setting to + * strLine - string with the setting and its value to write to db + * return: 0 if writing was ok, 1 otherwise + **/ +int ImportSetting(MCONTACT hContact, LPCSTR pszModule, LPSTR &strLine) +{ + DBVARIANT dbv; + LPSTR end, value; + size_t numLines = 0; + size_t brk; + LPSTR pszLine = strLine; + + // check Module and filter "Protocol" + if (!pszModule || !*pszModule || mir_strncmp(pszModule,"Protocol",8) == 0) + return 1; + if ((end = value = mir_strchr(pszLine, '=')) == NULL) + return 1; + + // truncate setting string if it has spaces at the end + do { + if (end == pszLine) + return 1; + *(end--) = 0; + } + while (*end == '\t' || *end == ' ' || *end < 27); + + // skip spaces from the beginning of the value + do { + value++; + // if the value is empty, delete it from db + if (*value == '\0') + return db_unset(hContact, pszModule, pszLine); + } while (*value == '\t' || *value == ' '); + + // decode database type and value + switch (*(value++)) { + case 'b': + case 'B': + if (brk = strspn(value, "0123456789-")) + *(value + brk) = 0; + dbv.type = DBVT_BYTE; + dbv.bVal = (BYTE)atoi(value); + break; + case 'w': + case 'W': + if (brk = strspn(value, "0123456789-")) + *(value + brk) = 0; + dbv.type = DBVT_WORD; + dbv.wVal = (WORD)atoi(value); + break; + case 'd': + case 'D': + if (brk = strspn(value, "0123456789-")) + *(value + brk) = 0; + dbv.type = DBVT_DWORD; + dbv.dVal = (DWORD)_atoi64(value); + break; + case 's': + case 'S': + case 'u': + case 'U': + for (end = value; end && *end; end++) { + switch (*end) { + // convert STX back to \r + case 2: + *end = '\r'; + break; + // convert ETX back to \n + case 3: + *end = '\n'; + break; + } + } + switch (*(value - 1)) { + case 's': + case 'S': + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = value; + break; + case 'u': + case 'U': + dbv.type = DBVT_UTF8; + dbv.pszVal = value; + break; + } + break; + case 'n': + case 'N': + { + PBYTE dest; + dbv.type = DBVT_BLOB; + dbv.cpbVal = (WORD)mir_strlen(value) / 3; + dbv.pbVal = (PBYTE)value; + for ( dest = dbv.pbVal, value = strtok(value, " "); + value && *value; + value = strtok(NULL, " ")) + *(dest++) = (BYTE)strtol(value, NULL, 16); + *dest = 0; + break; + } + default: + dbv.type = DBVT_DELETED; + //return 1; + } + return db_set(hContact, pszModule, pszLine, &dbv); +} + +/** + * name: Import + * desc: This function imports an ini file + * param: hContact - handle to contact to match or NULL to match all existing + * file - module to write the setting to + * strLine - string with the setting and its value to write to db + * return: 0 if writing was ok, 1 otherwise + **/ +int SvcExImINI_Import(MCONTACT hContact, LPCSTR pszFileName) +{ + FILE *file; + MCONTACT hNewContact = INVALID_CONTACT_ID; + DWORD end, + numLines = 0; + CHAR szModule[MAXSETTING] = {0}; + WORD numContactsInFile = 0, // number of contacts in the inifile + numContactsAdded = 0; // number of contacts, that were added to the database + CHAR *strBuf = (CHAR *) mir_alloc(1); + *strBuf = 0; + + if (file = fopen(pszFileName, "rt")) { + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + while (ImportreadLine(file, strBuf)) { + numLines++; + + // contact was found and imported + if (hContact != INVALID_CONTACT_ID && hNewContact != INVALID_CONTACT_ID) + break; + + // importing settings is only valid vor the main menu item + if (hContact == INVALID_CONTACT_ID) { + if (!strncmp(strBuf, "SETTINGS:", 9)) { + *szModule = 0; + hNewContact = NULL; + continue; + } + } + + // there are some modules of a contact (import only if contact exist) + if (!strncmp(strBuf, "FROM CONTACT:", 13)) { + strBuf = mir_strnerase(strBuf, 0, 13); + while (strBuf[0] == ' ' || strBuf[0] == '\t') + strBuf = mir_strnerase(strBuf, 0, 1); + + numContactsInFile++; + if ((hNewContact = ImportFindContact(hContact, strBuf, FALSE)) != INVALID_CONTACT_ID) + numContactsAdded++; + continue; + } + + // there is a contact to import / add + if (!strncmp(strBuf, "CONTACT:", 8)) { + strBuf = mir_strnerase(strBuf, 0, 8); + while (strBuf[0] == ' ' || strBuf[0] == '\t') + strBuf = mir_strnerase(strBuf, 0, 1); + + *szModule = 0; + numContactsInFile++; + if ((hNewContact = ImportFindContact(hContact, strBuf, TRUE)) != INVALID_CONTACT_ID) + numContactsAdded++; + continue; + } + + // read modules and settings only for valid contacts + if (hNewContact != INVALID_CONTACT_ID) { + // found a module line + if (strBuf[0] == '[' && (end = (strchr(strBuf, ']') - strBuf)) > 0) { + mir_strncpy(szModule, &strBuf[1], end); + continue; + } + // try to import a setting + ImportSetting(hNewContact, szModule, strBuf); + } + } //end while + fclose(file); + mir_free(strBuf); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + + // the contact was not found in the file + if (numContactsInFile > 0 && !numContactsAdded) { + MsgErr(NULL, + LPGENT("None of the %d contacts, stored in the ini-file, match the selected contact!\nNothing will be imported"), + numContactsInFile); + } + // Import complete + else{ + MsgBox(NULL, MB_ICON_INFO, LPGENT("Import complete"), LPGENT("Some basic statistics"), + LPGENT("Added %d of %d contacts stored in the ini-file."), + numContactsAdded, numContactsInFile); + } + return 0; + } + MsgErr(NULL, + LPGENT("The ini-file \"%s\"\nfor reading contact information could not be opened."), + pszFileName); + return 1; +} diff --git a/plugins/UserInfoEx/src/mir_string.cpp b/plugins/UserInfoEx/src/mir_string.cpp index 206b16a609..778165cbc3 100644 --- a/plugins/UserInfoEx/src/mir_string.cpp +++ b/plugins/UserInfoEx/src/mir_string.cpp @@ -1,130 +1,136 @@ -/* -UserinfoEx plugin for Miranda IM - -Copyright: -© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol - -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 "commonheaders.h" - -char *mir_strncpy(char *pszDest, const char *pszSrc, const size_t cchDest) -{ - if (!pszDest || !pszSrc || !cchDest) - return NULL; - pszDest = strncpy(pszDest, pszSrc, cchDest-1); - pszDest[cchDest-1] = 0; - return pszDest; -} - -wchar_t *mir_wcsncpy(wchar_t *pszDest, const wchar_t *pszSrc, const size_t cchDest) -{ - if (!pszDest || !pszSrc || !cchDest) - return NULL; - pszDest = wcsncpy(pszDest, pszSrc, cchDest-1); - pszDest[cchDest-1] = 0; - return pszDest; -} - -char *mir_strncat(char *pszDest, const char *pszSrc, const size_t cchDest) -{ - if (!pszDest || !pszSrc || !cchDest) - return NULL; - strncat(pszDest, pszSrc, cchDest-1); - pszDest[cchDest-1] = 0; - return pszDest; -} - -wchar_t *mir_wcsncat(wchar_t *pszDest, const wchar_t *pszSrc, const size_t cchDest) -{ - if (!pszDest || !pszSrc || !cchDest) - return NULL; - pszDest = wcsncat(pszDest, pszSrc, cchDest-1); - pszDest[cchDest-1] = 0; - return pszDest; -} - -char *mir_strncat_c(char *pszDest, const char cSrc) -{ - size_t size = sizeof(char) * (strlen(pszDest) + 2); //cSrc = 1 + 1 forNULL temination - if (!pszDest) - pszDest = (char *) mir_alloc(size); - else - pszDest = (char *) mir_realloc(pszDest, size); - pszDest[size-2] = cSrc; - pszDest[size-1] = 0; - return pszDest; -} - -wchar_t *mir_wcsncat_c(wchar_t *pwszDest, const wchar_t wcSrc) { - size_t size = sizeof(wchar_t) * (wcslen(pwszDest) + 2); - if (!pwszDest) - pwszDest = (wchar_t *) mir_alloc(size); - else - pwszDest = (wchar_t *) mir_realloc(pwszDest, size); - pwszDest[size-2] = wcSrc; - pwszDest[size-1] = 0; - return pwszDest; -} - -char *mir_strnerase(char *pszDest, size_t sizeFrom, size_t sizeTo) { - char *pszReturn = NULL; - size_t sizeNew, sizeLen = strlen(pszDest); - if (sizeFrom >= 0 && sizeFrom < sizeLen && sizeTo >= 0 && sizeTo <= sizeLen && sizeFrom < sizeTo) { - sizeNew = sizeLen - (sizeTo - sizeFrom); - size_t sizeCopy = sizeNew - sizeFrom; - pszReturn = (char *) mir_alloc(sizeNew + 1); - memcpy(pszReturn, pszDest, sizeFrom); - memcpy(pszReturn + sizeFrom, pszDest + sizeTo, sizeCopy); - pszReturn[sizeNew] = 0; - } - - pszDest = (char *) mir_realloc(pszDest, sizeNew + 1); - pszDest = mir_strcpy(pszDest, pszReturn); - mir_free(pszReturn); - return pszDest; -} - -int mir_IsEmptyA(char *str) -{ - if (str == NULL || str[0] == 0) - return 1; - int i = 0; - while (str[i]) { - if (str[i]!=' ' && - str[i]!='\r' && - str[i]!='\n') - return 0; - i++; - } - return 1; -} - -int mir_IsEmptyW(wchar_t *str) -{ - if (str == NULL || str[0] == 0) - return 1; - int i = 0; - while (str[i]) { - if (str[i]!=' ' && - str[i]!='\r' && - str[i]!='\n') - return 0; - i++; - } - return 1; -} - +/* +UserinfoEx plugin for Miranda IM + +Copyright: +© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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 "commonheaders.h" + +char *mir_strncpy(char *pszDest, const char *pszSrc, const size_t cchDest) +{ + if (!pszDest || !pszSrc || !cchDest) + return NULL; + pszDest = strncpy(pszDest, pszSrc, cchDest-1); + pszDest[cchDest-1] = 0; + return pszDest; +} + +wchar_t *mir_wcsncpy(wchar_t *pszDest, const wchar_t *pszSrc, const size_t cchDest) +{ + if (!pszDest || !pszSrc || !cchDest) + return NULL; + pszDest = wcsncpy(pszDest, pszSrc, cchDest-1); + pszDest[cchDest-1] = 0; + return pszDest; +} + +char *mir_strncat(char *pszDest, const char *pszSrc, const size_t cchDest) +{ + if (!pszDest || !pszSrc || !cchDest) + return NULL; + strncat(pszDest, pszSrc, cchDest-1); + pszDest[cchDest-1] = 0; + return pszDest; +} + +wchar_t *mir_wcsncat(wchar_t *pszDest, const wchar_t *pszSrc, const size_t cchDest) +{ + if (!pszDest || !pszSrc || !cchDest) + return NULL; + pszDest = wcsncat(pszDest, pszSrc, cchDest-1); + pszDest[cchDest-1] = 0; + return pszDest; +} + +char *mir_strncat_c(char *pszDest, const char cSrc) +{ + char *pszRet; + size_t size = 2; + + if (pszDest != NULL) + size += strlen(pszDest); //cSrc = 1 + 1 forNULL temination + pszRet = (char *)mir_realloc(pszDest, (sizeof(char) * size)); + if (pszRet == NULL) + return NULL; + pszRet[size - 2] = cSrc; + pszRet[size - 1] = 0; + return pszRet; +} + +wchar_t *mir_wcsncat_c(wchar_t *pwszDest, const wchar_t wcSrc) { + wchar_t *pwszRet; + size_t size = 2; + + if (pwszDest != NULL) + size += wcslen(pwszDest); //cSrc = 1 + 1 forNULL temination + pwszRet = (wchar_t *)mir_realloc(pwszDest, (sizeof(wchar_t) * size)); + if (pwszRet == NULL) + return NULL; + pwszRet[size - 2] = wcSrc; + pwszRet[size - 1] = 0; + return pwszRet; +} + +char *mir_strnerase(char *pszDest, size_t sizeFrom, size_t sizeTo) { + char *pszReturn = NULL; + size_t sizeNew, sizeLen = strlen(pszDest); + if (sizeFrom >= 0 && sizeFrom < sizeLen && sizeTo >= 0 && sizeTo <= sizeLen && sizeFrom < sizeTo) { + sizeNew = sizeLen - (sizeTo - sizeFrom); + size_t sizeCopy = sizeNew - sizeFrom; + pszReturn = (char *) mir_alloc(sizeNew + 1); + memcpy(pszReturn, pszDest, sizeFrom); + memcpy(pszReturn + sizeFrom, pszDest + sizeTo, sizeCopy); + pszReturn[sizeNew] = 0; + } + + pszDest = (char *) mir_realloc(pszDest, sizeNew + 1); + pszDest = mir_strcpy(pszDest, pszReturn); + mir_free(pszReturn); + return pszDest; +} + +int mir_IsEmptyA(char *str) +{ + if (str == NULL || str[0] == 0) + return 1; + int i = 0; + while (str[i]) { + if (str[i]!=' ' && + str[i]!='\r' && + str[i]!='\n') + return 0; + i++; + } + return 1; +} + +int mir_IsEmptyW(wchar_t *str) +{ + if (str == NULL || str[0] == 0) + return 1; + int i = 0; + while (str[i]) { + if (str[i]!=' ' && + str[i]!='\r' && + str[i]!='\n') + return 0; + i++; + } + return 1; +} + diff --git a/plugins/UserInfoEx/src/svc_timezone.cpp b/plugins/UserInfoEx/src/svc_timezone.cpp index 8318e911bc..4b4ccd4053 100644 --- a/plugins/UserInfoEx/src/svc_timezone.cpp +++ b/plugins/UserInfoEx/src/svc_timezone.cpp @@ -1,76 +1,80 @@ -/* -UserinfoEx plugin for Miranda IM - -Copyright: -© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol - -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 "commonheaders.h" - -/*********************************************************************************************************** - * services - ***********************************************************************************************************/ - -/** -* This service function provides a TIME_ZONE_INFORMATION structure -* for the desired contact, in case the contact's timezone can be determined. -* parsed to new core tzi interface if present. -* -* @param wParam - HANDLE of the contact, to retrieve timezone information from. -* @param lParam - pointer to a TIME_ZONE_INFORMATION to fill. -* -* @retval 0 - success -* @retval 1 - failure -**/ - -INT_PTR GetContactTimeZoneInformation(WPARAM wParam,LPARAM lParam) -{ - //use new core tz interface - LPTIME_ZONE_INFORMATION pTimeZoneInformation = (LPTIME_ZONE_INFORMATION)lParam; - (*pTimeZoneInformation) = *tmi.getTzi(tmi.createByContact(wParam, 0, 0)); - return (pTimeZoneInformation == NULL); -} - -/** -* This function returns the contact's local time. -* -* @param wParam - HANDLE of the contact, to retrieve timezone information from. -* @param lParam - pointer to a systemtime structure -* -* @return TRUE or FALSE -**/ - -INT_PTR GetContactLocalTime(WPARAM wParam, LPARAM lParam) -{ - //use new core tz interface - LPSYSTEMTIME pSystemTime = (LPSYSTEMTIME)lParam; - return (INT_PTR)tmi.getTimeZoneTimeByContact(wParam, pSystemTime); -} - -/*********************************************************************************************************** - * initialization - ***********************************************************************************************************/ - -/** -* This function initially loads the module upon startup. -**/ - -void SvcTimezoneLoadModule() -{ - CreateServiceFunction(MS_USERINFO_TIMEZONEINFO, GetContactTimeZoneInformation); - CreateServiceFunction(MS_USERINFO_LOCALTIME, GetContactLocalTime); -} +/* +UserinfoEx plugin for Miranda IM + +Copyright: +© 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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 "commonheaders.h" + +/*********************************************************************************************************** + * services + ***********************************************************************************************************/ + +/** +* This service function provides a TIME_ZONE_INFORMATION structure +* for the desired contact, in case the contact's timezone can be determined. +* parsed to new core tzi interface if present. +* +* @param wParam - HANDLE of the contact, to retrieve timezone information from. +* @param lParam - pointer to a TIME_ZONE_INFORMATION to fill. +* +* @retval 0 - success +* @retval 1 - failure +**/ + +INT_PTR GetContactTimeZoneInformation(WPARAM wParam, LPARAM lParam) +{ + if (lParam == NULL) + return (1); + //use new core tz interface + LPTIME_ZONE_INFORMATION pTimeZoneInformation = tmi.getTzi(tmi.createByContact(wParam, 0, 0)); + if (pTimeZoneInformation == NULL) + return (1); + memcpy((void *)lParam, pTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION)); + return (0); +} + +/** +* This function returns the contact's local time. +* +* @param wParam - HANDLE of the contact, to retrieve timezone information from. +* @param lParam - pointer to a systemtime structure +* +* @return TRUE or FALSE +**/ + +INT_PTR GetContactLocalTime(WPARAM wParam, LPARAM lParam) +{ + //use new core tz interface + LPSYSTEMTIME pSystemTime = (LPSYSTEMTIME)lParam; + return (INT_PTR)tmi.getTimeZoneTimeByContact(wParam, pSystemTime); +} + +/*********************************************************************************************************** + * initialization + ***********************************************************************************************************/ + +/** +* This function initially loads the module upon startup. +**/ + +void SvcTimezoneLoadModule() +{ + CreateServiceFunction(MS_USERINFO_TIMEZONEINFO, GetContactTimeZoneInformation); + CreateServiceFunction(MS_USERINFO_LOCALTIME, GetContactLocalTime); +} -- cgit v1.2.3