summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/UserInfoEx/src/classPsTree.cpp1955
-rw-r--r--plugins/UserInfoEx/src/ctrl_edit.cpp741
-rw-r--r--plugins/UserInfoEx/src/ex_import/classExImContactBase.cpp1075
-rw-r--r--plugins/UserInfoEx/src/ex_import/svc_ExImINI.cpp1049
-rw-r--r--plugins/UserInfoEx/src/mir_string.cpp266
-rw-r--r--plugins/UserInfoEx/src/svc_timezone.cpp156
6 files changed, 2628 insertions, 2614 deletions
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);
+}