/* Jabber Protocol Plugin for Miranda IM Copyright ( C ) 2002-04 Santithorn Bunchua Copyright ( C ) 2005-12 George Hazan Copyright ( C ) 2007-09 Maxim Mluhov Copyright ( C ) 2007-09 Victor Pavlychko 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 "jabber.h" #include "jabber_list.h" #include "jabber_iq.h" #include "jabber_caps.h" #include "jabber_privacy.h" #include "jabber_notes.h" static TCHAR *StrTrimCopy(TCHAR *str) { if (!str) return 0; while (*str && _istspace(*str)) ++str; if (!*str) return mir_tstrdup(str); TCHAR *res = mir_tstrdup(str); for (TCHAR *p = res + lstrlen(res) - 1; p >= res; --p) { if (_istspace(*p)) *p = 0; else break; } return res; } CNoteItem::CNoteItem() { m_szTitle = m_szFrom = m_szText = m_szTags = m_szTagsStr = NULL; } CNoteItem::CNoteItem(HXML hXml, TCHAR *szFrom) { m_szTitle = m_szFrom = m_szText = m_szTags = m_szTagsStr = NULL; SetData( XPathT(hXml, "title"), szFrom ? szFrom : XPathT(hXml, "@from"), XPathT(hXml, "text"), XPathT(hXml, "@tags")); } CNoteItem::~CNoteItem() { mir_free(m_szTitle); mir_free(m_szFrom); mir_free(m_szText); mir_free(m_szTags); mir_free(m_szTagsStr); } void CNoteItem::SetData(TCHAR *title, TCHAR *from, TCHAR *text, TCHAR *tags) { mir_free(m_szTitle); mir_free(m_szFrom); mir_free(m_szText); mir_free(m_szTags); mir_free(m_szTagsStr); m_szTitle = StrTrimCopy(title); m_szText = JabberStrFixLines(text); m_szFrom = StrTrimCopy(from); const TCHAR *szTags = tags; TCHAR *p = m_szTags = (TCHAR *)mir_alloc((lstrlen(szTags) + 2 /*for double zero*/) * sizeof(TCHAR)); TCHAR *q = m_szTagsStr = (TCHAR *)mir_alloc((lstrlen(szTags) + 1) * sizeof(TCHAR)); for ( ; szTags && *szTags; ++szTags) { if (_istspace(*szTags)) continue; if (*szTags == _T(',')) { *q++ = _T(','); *p++ = 0; continue; } *q++ = *p++ = *szTags; } q[0] = p[0] = p[1] = 0; } bool CNoteItem::HasTag(const TCHAR *szTag) { if (!szTag || !*szTag) return true; for (TCHAR *p = m_szTags; p && *p; p = p + lstrlen(p) + 1) if (!lstrcmp(p, szTag)) return true; return false; } int CNoteItem::cmp(const CNoteItem *p1, const CNoteItem *p2) { int ret = 0; if (ret = lstrcmp(p1->m_szTitle, p2->m_szTitle)) return ret; if (ret = lstrcmp(p1->m_szText, p2->m_szText)) return ret; if (ret = lstrcmp(p1->m_szTagsStr, p2->m_szTagsStr)) return ret; if (p1 < p2) return -1; if (p1 > p2) return 1; return 0; } void CNoteList::AddNote(HXML hXml, TCHAR *szFrom) { m_bIsModified = true; insert(new CNoteItem(hXml, szFrom)); } void CNoteList::LoadXml(HXML hXml) { destroy(); m_bIsModified = false; int count = xmlGetChildCount(hXml); for (int i = 0; i < count; ++i) { CNoteItem *pNote = new CNoteItem(xi.getChild(hXml, i)); if (pNote->IsNotEmpty()) insert(pNote); else delete pNote; } } void CNoteList::SaveXml(HXML hXmlParent) { m_bIsModified = false; CNoteList &me = *this; for (int i = 0; i < getCount(); ++i) { HXML hXmlItem = hXmlParent << XCHILD(_T("note")); hXmlItem << XATTR(_T("from"), me[i].GetFrom()) << XATTR(_T("tags"), me[i].GetTagsStr()); hXmlItem << XCHILD(_T("title"), me[i].GetTitle()); hXmlItem << XCHILD(_T("text"), me[i].GetText()); } } ///////////////////////////////////////////////////////////////////////////////////////// // Single note editor class CJabberDlgNoteItem : public CJabberDlgBase { typedef CJabberDlgBase CSuper; typedef void (CJabberProto::*TFnProcessNote)(CNoteItem *, bool ok); public: CJabberDlgNoteItem(CJabberDlgBase *parent, CNoteItem *pNote); CJabberDlgNoteItem(CJabberProto *proto, CNoteItem *pNote, TFnProcessNote fnProcess); protected: void OnInitDialog(); int Resizer(UTILRESIZECONTROL *urc); private: CNoteItem *m_pNote; TFnProcessNote m_fnProcess; CCtrlEdit m_txtTitle; CCtrlEdit m_txtText; CCtrlEdit m_txtTags; CCtrlButton m_btnOk; void btnOk_OnClick(CCtrlButton *) { TCHAR *szTitle = m_txtTitle.GetText(); TCHAR *szText = m_txtText.GetText(); TCHAR *szTags = m_txtTags.GetText(); TCHAR *szFrom = mir_tstrdup(m_pNote->GetFrom()); m_pNote->SetData(szTitle, szFrom, szText, szTags); mir_free(szTitle); mir_free(szText); mir_free(szTags); mir_free(szFrom); m_autoClose = false; if (m_fnProcess) (m_proto->*m_fnProcess)(m_pNote, true); EndDialog(m_hwnd, TRUE); } void OnClose() { if (m_fnProcess) (m_proto->*m_fnProcess)(m_pNote, false); CSuper::OnClose(); } }; CJabberDlgNoteItem::CJabberDlgNoteItem(CJabberDlgBase *parent, CNoteItem *pNote): CSuper(parent->GetProto(), IDD_NOTE_EDIT, parent->GetHwnd()), m_pNote(pNote), m_fnProcess(NULL), m_txtTitle(this, IDC_TXT_TITLE), m_txtText(this, IDC_TXT_TEXT), m_txtTags(this, IDC_TXT_TAGS), m_btnOk(this, IDOK) { m_btnOk.OnClick = Callback(this, &CJabberDlgNoteItem::btnOk_OnClick); } CJabberDlgNoteItem::CJabberDlgNoteItem(CJabberProto *proto, CNoteItem *pNote, TFnProcessNote fnProcess): CSuper(proto, IDD_NOTE_EDIT, NULL), m_pNote(pNote), m_fnProcess(fnProcess), m_txtTitle(this, IDC_TXT_TITLE), m_txtText(this, IDC_TXT_TEXT), m_txtTags(this, IDC_TXT_TAGS), m_btnOk(this, IDOK) { m_btnOk.OnClick = Callback(this, &CJabberDlgNoteItem::btnOk_OnClick); } void CJabberDlgNoteItem::OnInitDialog() { CSuper::OnInitDialog(); WindowSetIcon( m_hwnd, m_proto, "notes" ); if (m_fnProcess) { TCHAR buf[256]; if (m_fnProcess == &CJabberProto::ProcessIncomingNote) mir_sntprintf(buf, SIZEOF(buf), TranslateT("Incoming note from %s"), m_pNote->GetFrom()); else mir_sntprintf(buf, SIZEOF(buf), TranslateT("Send note to %s"), m_pNote->GetFrom()); SetWindowText(m_hwnd, buf); } m_txtTitle.SetText(m_pNote->GetTitle()); m_txtText.SetText(m_pNote->GetText()); m_txtTags.SetText(m_pNote->GetTagsStr()); } int CJabberDlgNoteItem::Resizer(UTILRESIZECONTROL *urc) { switch (urc->wId) { case IDC_TXT_TITLE: return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; case IDC_TXT_TEXT: return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; case IDC_ST_TAGS: case IDC_TXT_TAGS: return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; case IDOK: case IDCANCEL: return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; } return CSuper::Resizer(urc); } ///////////////////////////////////////////////////////////////////////////////////////// // Notebook window class CCtrlNotebookList: public CCtrlListBox { typedef CCtrlListBox CSuper; bool m_adding; HFONT m_hfntNormal, m_hfntSmall, m_hfntBold; public: CCtrlNotebookList( CDlgBase* dlg, int ctrlId ): CCtrlListBox( dlg, ctrlId ) {} void SetFonts(HFONT hfntNormal, HFONT hfntSmall, HFONT hfntBold) { m_hfntNormal = hfntNormal; m_hfntSmall = hfntSmall; m_hfntBold = hfntBold; } int AddString(TCHAR *text, LPARAM data=0) { m_adding = true; int idx = CCtrlListBox::AddString(text, data); m_adding = false; if (idx == LB_ERR) return idx; MEASUREITEMSTRUCT mis = {0}; mis.CtlType = ODT_LISTBOX; mis.CtlID = m_idCtrl; mis.itemID = idx; mis.itemData = data; OnMeasureItem(&mis); if (mis.itemHeight) SendMessage(m_hwnd, LB_SETITEMHEIGHT, idx, mis.itemHeight); return idx; } void OnInit() { CSuper::OnInit(); Subclass(); } LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_SIZE) { SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0); int cnt = GetCount(); for (int idx = 0; idx < cnt; ++idx) { MEASUREITEMSTRUCT mis = {0}; mis.CtlType = ODT_LISTBOX; mis.CtlID = m_idCtrl; mis.itemID = idx; mis.itemData = GetItemData(idx); OnMeasureItem(&mis); if (mis.itemHeight) SendMessage(m_hwnd, LB_SETITEMHEIGHT, idx, mis.itemHeight); } SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0); RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); } return CSuper::CustomWndProc(msg, wParam, lParam); } BOOL OnDrawItem(DRAWITEMSTRUCT *lps) { if (m_adding) return FALSE; if (lps->itemID == -1) return TRUE; if (!lps->itemData) return TRUE; HDC hdc = lps->hDC; CNoteItem *pNote = (CNoteItem *)lps->itemData; SetBkMode(hdc, TRANSPARENT); if (lps->itemState & ODS_SELECTED) { FillRect(hdc, &lps->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { FillRect(hdc, &lps->rcItem, GetSysColorBrush(COLOR_WINDOW)); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); } if (lps->itemID) { RECT rcTmp = lps->rcItem; rcTmp.bottom = rcTmp.top+1; FillRect(hdc, &rcTmp, GetSysColorBrush(COLOR_BTNSHADOW)); } RECT rc = lps->rcItem; rc.left += 5; rc.right -= 5; rc.top += 2; SelectObject(hdc, m_hfntBold); rc.top += DrawText(hdc, pNote->GetTitle(), -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); SelectObject(hdc, m_hfntNormal); if (pNote->GetFrom()) { TCHAR buf[256]; mir_sntprintf(buf, SIZEOF(buf), TranslateT("From: %s"), pNote->GetFrom()); rc.top += DrawText(hdc, buf, -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); } rc.top += DrawText(hdc, pNote->GetText(), -1, &rc, DT_NOPREFIX|DT_WORDBREAK|DT_EXPANDTABS|DT_END_ELLIPSIS); SelectObject(hdc, m_hfntSmall); rc.top += DrawText(hdc, pNote->GetTagsStr(), -1, &rc, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS); rc.top += 5; int h = min(255, max(0, rc.bottom - rc.top)); if (SendMessage(m_hwnd, LB_GETITEMHEIGHT, lps->itemID, 0) != h) SendMessage(m_hwnd, LB_SETITEMHEIGHT, lps->itemID, h); return TRUE; } BOOL OnMeasureItem(MEASUREITEMSTRUCT *lps) { if (m_adding) return FALSE; if (lps->itemID == -1) return TRUE; if (!lps->itemData) return TRUE; HDC hdc = GetDC(m_hwnd); CNoteItem *pNote = (CNoteItem *)lps->itemData; RECT rcTmp, rc; GetClientRect(m_hwnd, &rc); int maxHeight = rc.bottom - 10; rc.bottom = 0; SelectObject(hdc, m_hfntBold); rcTmp = rc; DrawText(hdc, pNote->GetTitle(), -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); lps->itemHeight += rcTmp.bottom; SelectObject(hdc, m_hfntNormal); if (pNote->GetFrom()) { TCHAR buf[256]; mir_sntprintf(buf, SIZEOF(buf), TranslateT("From: %s"), pNote->GetFrom()); rcTmp = rc; DrawText(hdc, buf, -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); lps->itemHeight += rcTmp.bottom; } rcTmp = rc; DrawText(hdc, pNote->GetText(), -1, &rcTmp, DT_NOPREFIX|DT_WORDBREAK|DT_EXPANDTABS|DT_END_ELLIPSIS|DT_CALCRECT); lps->itemHeight += rcTmp.bottom; SelectObject(hdc, m_hfntSmall); rcTmp = rc; DrawText(hdc, pNote->GetTagsStr(), -1, &rcTmp, DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_CALCRECT); lps->itemHeight += rcTmp.bottom; lps->itemHeight += 5; ReleaseDC(m_hwnd, hdc); lps->itemWidth = rc.right; lps->itemHeight = min(255, lps->itemHeight); // listbox can't make items taller then 255px return TRUE; } }; class CJabberDlgNotes : public CJabberDlgBase { typedef CJabberDlgBase CSuper; public: CJabberDlgNotes(CJabberProto *proto); void UpdateData(); protected: void OnInitDialog(); void OnClose(); void OnDestroy(); int Resizer(UTILRESIZECONTROL *urc); void OnProtoCheckOnline(WPARAM wParam, LPARAM lParam); void OnProtoRefresh(WPARAM wParam, LPARAM lParam); private: CCtrlMButton m_btnAdd; CCtrlMButton m_btnEdit; CCtrlMButton m_btnRemove; CCtrlNotebookList m_lstNotes; CCtrlTreeView m_tvFilter; CCtrlButton m_btnSave; HFONT m_hfntNormal, m_hfntSmall, m_hfntBold; void EnableControls() { m_btnSave.Enable(m_proto->m_bJabberOnline && m_proto->m_notes.IsModified()); m_btnEdit.Enable(m_lstNotes.GetCurSel() != LB_ERR); m_btnRemove.Enable(m_lstNotes.GetCurSel() != LB_ERR); } void InsertTag(HTREEITEM htiRoot, const TCHAR *tag, bool bSelect) { TVINSERTSTRUCT tvi = {0}; tvi.hParent = htiRoot; tvi.hInsertAfter = TVI_LAST; tvi.itemex.mask = TVIF_TEXT|TVIF_PARAM; tvi.itemex.pszText = (TCHAR *)tag; tvi.itemex.lParam = (LPARAM)mir_tstrdup(tag); HTREEITEM hti = m_tvFilter.InsertItem(&tvi); if (bSelect) m_tvFilter.SelectItem(hti); } void PopulateTags(HTREEITEM htiRoot, TCHAR *szActiveTag) { LIST tagSet(5, _tcscmp); for (int i = 0; i < m_proto->m_notes.getCount(); ++i) { TCHAR *tags = m_proto->m_notes[i].GetTags(); for (TCHAR *tag = tags; tag && *tag; tag = tag + lstrlen(tag) + 1) if (!tagSet.find(tag)) tagSet.insert(tag); } bool selected = false; for (int j = 0; j < tagSet.getCount(); ++j) { bool select = !lstrcmp(szActiveTag, tagSet[j]); selected |= select; InsertTag(htiRoot, tagSet[j], select); } if (!selected) m_tvFilter.SelectItem(htiRoot); tagSet.destroy(); } void RebuildTree() { TVITEMEX tvi = {0}; tvi.mask = TVIF_HANDLE|TVIF_PARAM; tvi.hItem = m_tvFilter.GetSelection(); m_tvFilter.GetItem(&tvi); TCHAR *szActiveTag = mir_tstrdup((TCHAR *)tvi.lParam); m_tvFilter.DeleteAllItems(); TVINSERTSTRUCT tvis = {0}; tvis.hParent = NULL; tvis.hInsertAfter = TVI_LAST; tvis.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE; tvis.itemex.stateMask = tvis.itemex.state = TVIS_BOLD|TVIS_EXPANDED; tvis.itemex.pszText = TranslateT("All tags"); tvis.itemex.lParam = NULL; PopulateTags(m_tvFilter.InsertItem(&tvis), szActiveTag); mir_free(szActiveTag); } void InsertItem(CNoteItem &item) { m_lstNotes.AddString((TCHAR *)item.GetTitle(), (LPARAM)&item); EnableControls(); } void ListItems(const TCHAR *tag) { m_lstNotes.ResetContent(); for (int i = 0; i < m_proto->m_notes.getCount(); ++i) if (m_proto->m_notes[i].HasTag(tag)) InsertItem(m_proto->m_notes[i]); EnableControls(); } void btnAdd_OnClick(CCtrlFilterListView *) { CNoteItem *pNote = new CNoteItem(); CJabberDlgNoteItem dlg(this, pNote); dlg.DoModal(); if (pNote->IsNotEmpty()) { m_proto->m_notes.insert(pNote); m_proto->m_notes.Modify(); UpdateData(); } else { delete pNote; return; } EnableControls(); } void btnEdit_OnClick(CCtrlFilterListView *) { int idx = m_lstNotes.GetCurSel(); if (idx != LB_ERR) { if (CNoteItem *pItem = (CNoteItem *)m_lstNotes.GetItemData(idx)) { CJabberDlgNoteItem dlg(this, pItem); if (dlg.DoModal()) { m_proto->m_notes.Modify(); RebuildTree(); } } } EnableControls(); } void btnRemove_OnClick(CCtrlFilterListView *) { int idx = m_lstNotes.GetCurSel(); if (idx != LB_ERR) { if (CNoteItem *pItem = (CNoteItem *)m_lstNotes.GetItemData(idx)) { m_lstNotes.DeleteString(idx); m_proto->m_notes.remove(pItem); } RebuildTree(); } EnableControls(); } void lstNotes_OnSelChange(CCtrlListBox *) { EnableControls(); } void tvFilter_OnDeleteItem(CCtrlTreeView::TEventInfo *e) { TCHAR *szText = (TCHAR *)e->nmtv->itemOld.lParam; mir_free(szText); EnableControls(); } void tvFilter_OnSelChanged(CCtrlTreeView::TEventInfo *e) { TCHAR *szText = (TCHAR *)e->nmtv->itemNew.lParam; ListItems(szText); EnableControls(); } void btnSave_OnClick(CCtrlButton *) { XmlNodeIq iq(_T("set")); HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); HXML storage = query << XCHILDNS(_T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES)); m_proto->m_notes.SaveXml(storage); m_proto->m_ThreadInfo->send(iq); EnableControls(); } }; CJabberDlgNotes::CJabberDlgNotes(CJabberProto *proto) : CSuper(proto, IDD_NOTEBOOK, NULL), m_btnAdd(this, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add")), m_btnEdit(this, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit")), m_btnRemove(this, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove")), m_lstNotes(this, IDC_LST_NOTES), m_tvFilter(this, IDC_TV_FILTER), m_btnSave(this, IDC_APPLY) { m_btnAdd.OnClick = Callback(this, &CJabberDlgNotes::btnAdd_OnClick); m_btnEdit.OnClick = Callback(this, &CJabberDlgNotes::btnEdit_OnClick); m_btnRemove.OnClick = Callback(this, &CJabberDlgNotes::btnRemove_OnClick); m_lstNotes.OnDblClick = Callback(this, &CJabberDlgNotes::btnEdit_OnClick); m_lstNotes.OnSelChange = Callback(this, &CJabberDlgNotes::lstNotes_OnSelChange); m_btnSave.OnClick = Callback(this, &CJabberDlgNotes::btnSave_OnClick); m_tvFilter.OnSelChanged = Callback(this, &CJabberDlgNotes::tvFilter_OnSelChanged); m_tvFilter.OnDeleteItem = Callback(this, &CJabberDlgNotes::tvFilter_OnDeleteItem); } void CJabberDlgNotes::UpdateData() { RebuildTree(); //ListItems(NULL); EnableControls(); } void CJabberDlgNotes::OnInitDialog() { CSuper::OnInitDialog(); WindowSetIcon( m_hwnd, m_proto, "notes" ); LOGFONT lf, lfTmp; m_hfntNormal = (HFONT)GetStockObject(DEFAULT_GUI_FONT); GetObject(m_hfntNormal, sizeof(lf), &lf); lfTmp = lf; lfTmp.lfWeight = FW_BOLD; m_hfntBold = CreateFontIndirect(&lfTmp); lfTmp = lf; lfTmp.lfHeight *= 0.8; m_hfntSmall = CreateFontIndirect(&lfTmp); m_lstNotes.SetFonts(m_hfntNormal, m_hfntSmall, m_hfntBold); Utils_RestoreWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "notesWnd_"); } void CJabberDlgNotes::OnClose() { if (m_proto->m_notes.IsModified()) { if (IDYES != MessageBox(m_hwnd, TranslateT("Notes are not saved, close this window without uploading data to server?"), TranslateT("Are you sure?"), MB_ICONWARNING|MB_YESNO|MB_DEFBUTTON2)) { m_lresult = TRUE; return; } } Utils_SaveWindowPosition(m_hwnd, NULL, m_proto->m_szModuleName, "notesWnd_"); DeleteObject(m_hfntSmall); DeleteObject(m_hfntBold); CSuper::OnClose(); } void CJabberDlgNotes::OnDestroy() { m_tvFilter.DeleteAllItems(); m_proto->m_pDlgNotes = NULL; CSuper::OnDestroy(); } void CJabberDlgNotes::OnProtoCheckOnline(WPARAM, LPARAM) { EnableControls(); } void CJabberDlgNotes::OnProtoRefresh(WPARAM, LPARAM) { } int CJabberDlgNotes::Resizer(UTILRESIZECONTROL *urc) { switch ( urc->wId ) { case IDC_TV_FILTER: return RD_ANCHORX_LEFT|RD_ANCHORY_HEIGHT; case IDC_LST_NOTES: return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; case IDC_APPLY: case IDCANCEL: return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; case IDC_ADD: case IDC_EDIT: case IDC_REMOVE: return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; } return CSuper::Resizer(urc); } ///////////////////////////////////////////////////////////////////////////////////////// // Launches the incoming note window void CJabberProto::ProcessIncomingNote(CNoteItem *pNote, bool ok) { if (ok && pNote->IsNotEmpty()) { m_notes.insert(pNote); XmlNodeIq iq(_T("set")); HXML query = iq << XQUERY( _T(JABBER_FEAT_PRIVATE_STORAGE)); HXML storage = query << XCHILDNS(_T("storage"), _T(JABBER_FEAT_MIRANDA_NOTES)); m_notes.SaveXml(storage); m_ThreadInfo->send(iq); } else { delete pNote; } } void CJabberProto::ProcessOutgoingNote(CNoteItem *pNote, bool ok) { if (!ok || !pNote->IsNotEmpty()) { delete pNote; return; } TCHAR buf[1024]; mir_sntprintf(buf, SIZEOF(buf), _T("Incoming note: %s\n\n%s\nTags: %s"), pNote->GetTitle(), pNote->GetText(), pNote->GetTagsStr()); JabberCapsBits jcb = GetResourceCapabilites( pNote->GetFrom(), TRUE ); if ( jcb & JABBER_RESOURCE_CAPS_ERROR ) jcb = JABBER_RESOURCE_CAPS_NONE; int nMsgId = SerialNext(); XmlNode m(_T("message")); m << XATTR(_T("type"), _T("chat")) << XATTR( _T("to"), pNote->GetFrom()) << XATTRID( nMsgId ); m << XCHILD(_T("body"), buf); HXML hXmlItem = m << XCHILDNS(_T("x"), _T(JABBER_FEAT_MIRANDA_NOTES)) << XCHILD(_T("note")); hXmlItem << XATTR(_T("tags"), pNote->GetTagsStr()); hXmlItem << XCHILD(_T("title"), pNote->GetTitle()); hXmlItem << XCHILD(_T("text"), pNote->GetText()); // message receipts XEP priority if ( jcb & JABBER_CAPS_MESSAGE_RECEIPTS ) m << XCHILDNS( _T("request"), _T(JABBER_FEAT_MESSAGE_RECEIPTS)); else if ( jcb & JABBER_CAPS_MESSAGE_EVENTS ) { HXML x = m << XCHILDNS( _T("x"), _T(JABBER_FEAT_MESSAGE_EVENTS)); x << XCHILD( _T("delivered")); x << XCHILD( _T("offline")); } else nMsgId = -1; m_ThreadInfo->send(m); delete pNote; } bool CJabberProto::OnIncomingNote(const TCHAR *szFrom, HXML hXml) { if (!m_options.AcceptNotes) return false; if (!szFrom || !hXml) return true; CNoteItem *pItem = new CNoteItem(hXml, (TCHAR *)szFrom); if (!pItem->IsNotEmpty()) { delete pItem; return true; } if (m_options.AutosaveNotes && HContactFromJID(szFrom)) { ProcessIncomingNote(pItem, true); return false; } CLISTEVENT cle = {0}; char szService[256]; mir_snprintf( szService, sizeof(szService),"%s%s", m_szModuleName, JS_INCOMING_NOTE_EVENT ); cle.cbSize = sizeof(CLISTEVENT); cle.hIcon = (HICON)LoadIconEx("notes"); cle.flags = CLEF_PROTOCOLGLOBAL|CLEF_TCHAR; cle.hDbEvent = (HANDLE)("test"); cle.lParam = (LPARAM)pItem; cle.pszService = szService; cle.ptszTooltip = TranslateT("Incoming note"); CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); return true; } INT_PTR __cdecl CJabberProto::OnIncomingNoteEvent(WPARAM, LPARAM lParam) { CLISTEVENT *pCle = (CLISTEVENT *)lParam; CNoteItem *pNote = (CNoteItem *)pCle->lParam; if ( !pNote ) return 0; CJabberDlgBase *pDlg = new CJabberDlgNoteItem(this, pNote, &CJabberProto::ProcessIncomingNote); pDlg->Show(); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // Menu handling INT_PTR __cdecl CJabberProto::OnMenuHandleNotes( WPARAM, LPARAM) { UI_SAFE_OPEN_EX(CJabberDlgNotes, m_pDlgNotes, pDlg); pDlg->UpdateData(); return 0; } INT_PTR __cdecl CJabberProto::OnMenuSendNote(WPARAM wParam, LPARAM) { if (!wParam) return 0; TCHAR szClientJid[ JABBER_MAX_JID_LEN ]; GetClientJID( JGetStringT( (HANDLE)wParam, "jid"), szClientJid, SIZEOF( szClientJid )); CNoteItem *pItem = new CNoteItem( NULL, szClientJid ); CJabberDlgBase *pDlg = new CJabberDlgNoteItem(this, pItem, &CJabberProto::ProcessOutgoingNote); pDlg->Show(); return 0; }