/* Scriver Copyright (c) 2000-12 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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 "stdafx.h" #ifndef TTI_NONE #define TTI_NONE 0 #endif const char *filename = "scriver.log"; void logInfo(const char *fmt, ...) { SYSTEMTIME time; char *str; va_list vararg; int strsize; FILE *flog = fopen(filename, "at"); if (flog != NULL) { GetLocalTime(&time); va_start(vararg, fmt); str = (char*)malloc(strsize = 2048); while (mir_vsnprintf(str, strsize, fmt, vararg) == -1) str = (char*)realloc(str, strsize += 2048); va_end(vararg); fprintf(flog, "%04d-%02d-%02d %02d:%02d:%02d,%03d [%s]", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds, "INFO"); fprintf(flog, " %s\n", str); free(str); fclose(flog); } } int GetRichTextLength(HWND hwnd, int codepage, BOOL inBytes) { GETTEXTLENGTHEX gtl; gtl.codepage = codepage; if (inBytes) { gtl.flags = GTL_NUMBYTES; } else { gtl.flags = GTL_NUMCHARS; } gtl.flags |= GTL_PRECISE | GTL_USECRLF; return (int)SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); } char* GetRichTextUtf(HWND hwnd) { int textBufferSize = GetRichTextLength(hwnd, CP_UTF8, TRUE); if (textBufferSize == 0) return NULL; textBufferSize++; char *textBuffer = (char*)mir_alloc(textBufferSize); GETTEXTEX gt = { 0 }; gt.cb = textBufferSize; gt.flags = GT_USECRLF; gt.codepage = CP_UTF8; SendMessage(hwnd, EM_GETTEXTEX, (WPARAM)>, (LPARAM)textBuffer); return textBuffer; } int SetRichText(HWND hwnd, const wchar_t *text) { SETTEXTEX st; st.flags = ST_DEFAULT; st.codepage = 1200; SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)text); return GetRichTextLength(hwnd, 1200, FALSE); } int SetRichTextRTF(HWND hwnd, const char *text) { SETTEXTEX st; st.flags = ST_DEFAULT; st.codepage = CP_UTF8; SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)text); return GetRichTextLength(hwnd, 1200, FALSE); } static DWORD CALLBACK RichTextStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb) { static DWORD dwRead; char **ppText = (char**)dwCookie; if (*ppText == NULL) { *ppText = (char*)mir_alloc(cb + 1); memcpy(*ppText, pbBuff, cb); (*ppText)[cb] = 0; *pcb = cb; dwRead = cb; } else { char *p = (char*)mir_alloc(dwRead + cb + 1); memcpy(p, *ppText, dwRead); memcpy(p + dwRead, pbBuff, cb); p[dwRead + cb] = 0; mir_free(*ppText); *ppText = p; *pcb = cb; dwRead += cb; } return 0; } char* GetRichTextRTF(HWND hwnd) { if (hwnd == 0) return NULL; char *pszText = NULL; EDITSTREAM stream = { 0 }; stream.pfnCallback = RichTextStreamCallback; stream.dwCookie = (DWORD_PTR)&pszText; // pass pointer to pointer SendMessage(hwnd, EM_STREAMOUT, SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE | (CP_UTF8 << 16), (LPARAM)&stream); return pszText; // pszText contains the text } void rtrimText(wchar_t *text) { static wchar_t szTrimString[] = L":;,.!?\'\"><()[]- \r\n"; size_t iLen = mir_wstrlen(text) - 1; while (wcschr(szTrimString, text[iLen])) { text[iLen] = '\0'; iLen--; } } wchar_t* limitText(wchar_t *text, int limit) { size_t len = mir_wstrlen(text); if (len > g_dat.limitNamesLength) { wchar_t *ptszTemp = (wchar_t*)mir_alloc(sizeof(wchar_t) * (limit + 4)); wcsncpy(ptszTemp, text, limit + 1); wcsncpy(ptszTemp + limit, L"...", 4); return ptszTemp; } return text; } wchar_t* GetRichTextWord(HWND hwnd, POINTL *ptl) { long iCharIndex, start, end, iRes; wchar_t *pszWord = GetRichEditSelection(hwnd); if (pszWord == NULL) { iCharIndex = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)ptl); if (iCharIndex >= 0) { start = SendMessage(hwnd, EM_FINDWORDBREAK, WB_LEFT, iCharIndex); //-iChars; end = SendMessage(hwnd, EM_FINDWORDBREAK, WB_RIGHT, iCharIndex); //-iChars; if (end - start > 0) { TEXTRANGE tr; CHARRANGE cr; memset(&tr, 0, sizeof(TEXTRANGE)); pszWord = (wchar_t*)mir_alloc(sizeof(wchar_t) * (end - start + 1)); cr.cpMin = start; cr.cpMax = end; tr.chrg = cr; tr.lpstrText = pszWord; iRes = SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); if (iRes <= 0) { mir_free(pszWord); pszWord = NULL; } } } } if (pszWord != NULL) rtrimText(pszWord); return pszWord; } static DWORD CALLBACK StreamOutCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb) { MessageSendQueueItem *msi = (MessageSendQueueItem *)dwCookie; msi->sendBuffer = (char*)mir_realloc(msi->sendBuffer, msi->sendBufferSize + cb + 2); memcpy(msi->sendBuffer + msi->sendBufferSize, pbBuff, cb); msi->sendBufferSize += cb; *((wchar_t*)(msi->sendBuffer + msi->sendBufferSize)) = '\0'; *pcb = cb; return 0; } wchar_t *GetRichEditSelection(HWND hwnd) { CHARRANGE sel; SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); if (sel.cpMin == sel.cpMax) return NULL; MessageSendQueueItem msi; msi.sendBuffer = NULL; msi.sendBufferSize = 0; EDITSTREAM stream; memset(&stream, 0, sizeof(stream)); stream.pfnCallback = StreamOutCallback; stream.dwCookie = (DWORD_PTR)&msi; SendMessage(hwnd, EM_STREAMOUT, SF_TEXT | SF_UNICODE | SFF_SELECTION, (LPARAM)&stream); return (wchar_t*)msi.sendBuffer; } void AppendToBuffer(char *&buffer, size_t &cbBufferEnd, size_t &cbBufferAlloced, const char *fmt, ...) { va_list va; int charsDone; va_start(va, fmt); for (;;) { charsDone = mir_vsnprintf(buffer + cbBufferEnd, cbBufferAlloced - cbBufferEnd, fmt, va); if (charsDone >= 0) break; cbBufferAlloced += 1024; buffer = (char*)mir_realloc(buffer, cbBufferAlloced); } va_end(va); cbBufferEnd += charsDone; } int MeasureMenuItem(WPARAM, LPARAM lParam) { LPMEASUREITEMSTRUCT mis = (LPMEASUREITEMSTRUCT)lParam; if (mis->itemData != (ULONG_PTR)g_dat.hButtonIconList && mis->itemData != (ULONG_PTR)g_dat.hSearchEngineIconList && mis->itemData != (ULONG_PTR)g_dat.hChatButtonIconList) return FALSE; mis->itemWidth = max(0, GetSystemMetrics(SM_CXSMICON) - GetSystemMetrics(SM_CXMENUCHECK) + 4); mis->itemHeight = GetSystemMetrics(SM_CYSMICON) + 2; return TRUE; } int DrawMenuItem(WPARAM, LPARAM lParam) { int y; int id; LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->itemData != (ULONG_PTR)g_dat.hButtonIconList && dis->itemData != (ULONG_PTR)g_dat.hSearchEngineIconList && dis->itemData != (ULONG_PTR)g_dat.hChatButtonIconList) { return FALSE; } id = dis->itemID; if (id >= IDM_SEARCH_GOOGLE) { id -= IDM_SEARCH_GOOGLE; } y = (dis->rcItem.bottom - dis->rcItem.top - GetSystemMetrics(SM_CYSMICON)) / 2 + 1; if (dis->itemState & ODS_SELECTED) { if (dis->itemState & ODS_CHECKED) { RECT rc; rc.left = 2; rc.right = GetSystemMetrics(SM_CXSMICON) + 2; rc.top = y; rc.bottom = rc.top + GetSystemMetrics(SM_CYSMICON) + 2; FillRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT)); ImageList_DrawEx((HIMAGELIST)dis->itemData, id, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_SELECTED); } else ImageList_DrawEx((HIMAGELIST)dis->itemData, id, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_FOCUS); } else { if (dis->itemState & ODS_CHECKED) { HBRUSH hBrush; RECT rc; COLORREF menuCol, hiliteCol; rc.left = 0; rc.right = GetSystemMetrics(SM_CXSMICON) + 4; rc.top = y - 2; rc.bottom = rc.top + GetSystemMetrics(SM_CYSMICON) + 4; DrawEdge(dis->hDC, &rc, BDR_SUNKENOUTER, BF_RECT); InflateRect(&rc, -1, -1); menuCol = GetSysColor(COLOR_MENU); hiliteCol = GetSysColor(COLOR_3DHIGHLIGHT); hBrush = CreateSolidBrush(RGB ((GetRValue(menuCol) + GetRValue(hiliteCol)) / 2, (GetGValue(menuCol) + GetGValue(hiliteCol)) / 2, (GetBValue(menuCol) + GetBValue(hiliteCol)) / 2)); FillRect(dis->hDC, &rc, hBrush); DeleteObject(hBrush); ImageList_DrawEx((HIMAGELIST)dis->itemData, id, dis->hDC, 2, y, 0, 0, CLR_NONE, GetSysColor(COLOR_MENU), ILD_BLEND25); } else ImageList_DrawEx((HIMAGELIST)dis->itemData, id, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_NONE, ILD_NORMAL); } return TRUE; } // Code taken from http://www.geekhideout.com/urlcode.shtml /* Converts an integer value to its hex character*/ char to_hex(char code) { static char hex[] = "0123456789abcdef"; return hex[code & 15]; } /* Returns a url-encoded version of str */ /* IMPORTANT: be sure to free() the returned string after use */ char *url_encode(char *str) { char *pstr = str, *buf = (char*)mir_alloc(mir_strlen(str) * 3 + 1), *pbuf = buf; while (*pstr) { if ((48 <= *pstr && *pstr <= 57) ||//0-9 (65 <= *pstr && *pstr <= 90) ||//ABC...XYZ (97 <= *pstr && *pstr <= 122) ||//abc...xyz *pstr == '-' || *pstr == '_' || *pstr == '.') *pbuf++ = *pstr; else if (*pstr == ' ') *pbuf++ = '+'; else *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); pstr++; } *pbuf = '\0'; return buf; } void SearchWord(wchar_t *word, int engine) { char szURL[4096]; if (word && word[0]) { T2Utf wordUTF(word); ptrA wordURL(mir_urlEncode(wordUTF)); switch (engine) { case SEARCHENGINE_WIKIPEDIA: mir_snprintf(szURL, "http://en.wikipedia.org/wiki/%s", wordURL); break; case SEARCHENGINE_YAHOO: mir_snprintf(szURL, "http://search.yahoo.com/search?p=%s&ei=UTF-8", wordURL); break; case SEARCHENGINE_FOODNETWORK: mir_snprintf(szURL, "http://search.foodnetwork.com/search/delegate.do?fnSearchString=%s", wordURL); break; case SEARCHENGINE_BING: mir_snprintf(szURL, "http://www.bing.com/search?q=%s&form=OSDSRC", wordURL); break; case SEARCHENGINE_GOOGLE_MAPS: mir_snprintf(szURL, "http://maps.google.com/maps?q=%s&ie=utf-8&oe=utf-8", wordURL); break; case SEARCHENGINE_GOOGLE_TRANSLATE: mir_snprintf(szURL, "http://translate.google.com/?q=%s&ie=utf-8&oe=utf-8", wordURL); break; case SEARCHENGINE_YANDEX: mir_snprintf(szURL, "http://yandex.ru/yandsearch?text=%s", wordURL); break; case SEARCHENGINE_GOOGLE: default: mir_snprintf(szURL, "http://www.google.com/search?q=%s&ie=utf-8&oe=utf-8", wordURL); break; } Utils_OpenUrl(szURL); } } void SetSearchEngineIcons(HMENU hMenu, HIMAGELIST hImageList) { for (int i = 0; i < IDI_LASTICON - IDI_GOOGLE; i++) { MENUITEMINFO mii = { 0 }; mii.cbSize = sizeof(mii); mii.fMask = MIIM_BITMAP | MIIM_DATA; mii.hbmpItem = HBMMENU_CALLBACK; mii.dwItemData = (ULONG_PTR)hImageList; SetMenuItemInfo(hMenu, IDM_SEARCH_GOOGLE + i, FALSE, &mii); } } void GetContactUniqueId(CSrmmWindow *dat, char *buf, int maxlen) { ptrW id(Contact_GetInfo(CNF_UNIQUEID, dat->m_hContact, dat->m_szProto)); if (id != NULL) strncpy_s(buf, maxlen, _T2A(id), _TRUNCATE); } HWND CreateToolTip(HWND hwndParent, LPTSTR ptszText, LPTSTR ptszTitle, RECT *rect) { TOOLINFO ti = { 0 }; HWND hwndTT; hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndParent, NULL, g_hInst, NULL); SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_SUBCLASS | TTF_CENTERTIP; ti.hwnd = hwndParent; ti.hinst = g_hInst; ti.lpszText = ptszText; ti.rect = *rect; SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&ti); SendMessage(hwndTT, TTM_SETTITLE, TTI_NONE, (LPARAM)ptszTitle); return hwndTT; } void SetToolTipText(HWND hwndParent, HWND hwndTT, LPTSTR ptszText, LPTSTR ptszTitle) { TOOLINFO ti = { sizeof(ti) }; ti.hinst = g_hInst; ti.hwnd = hwndParent; ti.lpszText = ptszText; SendMessage(hwndTT, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); SendMessage(hwndTT, TTM_SETTITLE, TTI_NONE, (LPARAM)ptszTitle); } void SetToolTipRect(HWND hwndParent, HWND hwndTT, RECT *rect) { TOOLINFO ti = { sizeof(ti) }; ti.hinst = g_hInst; ti.hwnd = hwndParent; ti.rect = *rect; SendMessage(hwndTT, TTM_NEWTOOLRECT, 0, (LPARAM)&ti); } void SetButtonsPos(HWND hwndDlg, MCONTACT hContact, bool bShow) { HDWP hdwp = BeginDeferWindowPos(Srmm_GetButtonCount()); RECT rc; GetWindowRect(GetDlgItem(hwndDlg, IDC_SPLITTERY), &rc); POINT pt = { 0, rc.top }; ScreenToClient(hwndDlg, &pt); pt.y -= 20; int iLeftX = 2, iRightX = rc.right - rc.left - 2; int iGap = db_get_b(NULL, SRMMMOD, "ButtonsBarGap", 1); CustomButtonData *cbd; for (int i = 0; cbd = Srmm_GetNthButton(i); i++) { HWND hwndButton = GetDlgItem(hwndDlg, cbd->m_dwButtonCID); if (hwndButton == NULL) continue; if (cbd->m_dwButtonCID == IDC_ADD) if (!db_get_b(hContact, "CList", "NotOnList", 0)) { ShowWindow(hwndButton, SW_HIDE); continue; } ShowWindow(hwndButton, bShow ? SW_SHOW : SW_HIDE); int width = iGap + cbd->m_iButtonWidth; if (cbd->m_bRSided) { iRightX -= width; hdwp = DeferWindowPos(hdwp, hwndButton, NULL, iRightX, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } else { hdwp = DeferWindowPos(hdwp, hwndButton, NULL, iLeftX, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); iLeftX += width; } } EndDeferWindowPos(hdwp); }