extern "C" int __declspec(dllexport) Load(void) { mir_getLP(&pluginInfo); mir_getCLI(); HookEvent(ME_SYSTEM_MODULESLOADED, MirandaLoaded); Icon_Register(g_hInstance, MOD_NAME, iconList, _countof(iconList), "nas"); InitCommonControls(); InitOptions(); // must be called before we hook CallService if (db_get_b(NULL, MOD_NAME, DB_SETTINGSVER, 0) < 1) { // change all %nas_message% variables to %extratext% if it wasn't done before TCString Str = db_get_s(NULL, MOD_NAME, "PopupsFormat", _T("")); if (Str.GetLen()) db_set_ts(NULL, MOD_NAME, "PopupsFormat", Str.Replace(_T("nas_message"), _T("extratext"))); Str = db_get_s(NULL, MOD_NAME, "ReplyPrefix", _T("")); if (Str.GetLen()) db_set_ts(NULL, MOD_NAME, "ReplyPrefix", Str.Replace(_T("nas_message"), _T("extratext"))); } if (db_get_b(NULL, MOD_NAME, DB_SETTINGSVER, 0) < 2) { // disable autoreply for not-on-list contacts, as such contact may be a spam bot db_set_b(NULL, MOD_NAME, ContactStatusToDBSetting(0, DB_ENABLEREPLY, 0, INVALID_CONTACT_ID), 0); db_set_b(NULL, MOD_NAME, DB_SETTINGSVER, 2); } return 0; }
void ShowPopup(SHOWPOPUP_DATA *sd) { TCString PopupText; if (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_SHOWPREVCLIENT)) { mir_sntprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s (was %s)"), (const TCHAR*)sd->MirVer, (const TCHAR*)sd->OldMirVer); PopupText.ReleaseBuffer(); } else { mir_sntprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s"), (const TCHAR*)sd->MirVer); PopupText.ReleaseBuffer(); } PLUGIN_DATA *pdata = (PLUGIN_DATA*)calloc(1, sizeof(PLUGIN_DATA)); POPUPDATAT ppd = {0}; ppd.lchContact = sd->hContact; char *szProto = GetContactProto(sd->hContact); pdata->hIcon = ppd.lchIcon = Finger_GetClientIcon(sd->MirVer, false); _ASSERT(ppd.lchIcon); if (!ppd.lchIcon || (DWORD)ppd.lchIcon == CALLSERVICE_NOTFOUND) { // if we didn't succeed retrieving client icon, show the usual status icon instead ppd.lchIcon = LoadSkinnedProtoIcon(szProto, db_get_w(sd->hContact, szProto, "Status", ID_STATUS_OFFLINE)); pdata->hIcon = NULL; } _tcsncpy(ppd.lptzContactName, (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)sd->hContact, GCDNF_TCHAR), lengthof(ppd.lptzContactName) - 1); _tcsncpy(ppd.lptzText, PopupText, lengthof(ppd.lptzText) - 1); ppd.colorBack = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFBGCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_BGCOLOUR)); ppd.colorText = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFTEXTCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_TEXTCOLOUR)); ppd.PluginWindowProc = PopupWndProc; pdata->PopupLClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_LCLICK_ACTION); pdata->PopupRClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_RCLICK_ACTION); ppd.iSeconds = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_POPUPDELAY); ppd.PluginData = pdata; PUAddPopupT(&ppd); }
TCDynStr::TCDynStr(const TCString& str,uint pos,uint count) /**************************************************************************** * * Function: TCDynStr::TCDynStr * Parameters: str - TCString to copy from * pos - Starting position in the string * count - Number of characters to copy * * Description: Constructs a string from another string, starting at the * position 'pos' and including 'count' characters. * ****************************************************************************/ { CHECK(str.valid()); if (pos > str.length()) pos = str.length(); if (count > str.length() - pos) count = str.length() - pos; len = count+1; size = computeSize(len); if ((text = new char[size]) != NULL) { memcpy(text,(const char *)str+pos,len); text[count] = '\0'; // Null terminate the string } }
void CMsgTree::UpdateItem(int ID) // updates item title, and expanded/collapsed state for groups { COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl(); int Order = TreeCtrl->IDToOrder(ID); if (Order != -1) { CBaseTreeItem* TreeItem = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; TCString NewTitle; TVITEM tvi; tvi.mask = TVIF_HANDLE | TVIF_TEXT; tvi.hItem = TreeItem->hItem; tvi.pszText = NewTitle.GetBuffer(TREEITEMTITLE_MAXLEN); tvi.cchTextMax = TREEITEMTITLE_MAXLEN; TreeView_GetItem(hTreeView, &tvi); if (TreeItem->Title != (const TCHAR*)tvi.pszText) { TreeCtrl->SetModified(true); NMMSGTREE nm = { 0 }; nm.ItemNew = TreeItem; nm.hdr.code = MTN_ITEMRENAMED; nm.hdr.hwndFrom = hTreeView; nm.hdr.idFrom = GetDlgCtrlID(hTreeView); SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm); } tvi.mask = TVIF_HANDLE | TVIF_TEXT; tvi.pszText = TreeItem->Title; TreeView_SetItem(hTreeView, &tvi); TreeView_Expand(hTreeView, tvi.hItem, (TreeItem->Flags & TIF_EXPANDED) ? TVE_EXPAND : TVE_COLLAPSE); } }
void ShowPopup(SHOWPOPUP_DATA *sd) { TCString PopupText; if (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_SHOWPREVCLIENT)) { mir_snwprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s (was %s)"), (const wchar_t*)sd->MirVer, (const wchar_t*)sd->OldMirVer); PopupText.ReleaseBuffer(); } else { mir_snwprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s"), (const wchar_t*)sd->MirVer); PopupText.ReleaseBuffer(); } PLUGIN_DATA *pdata = (PLUGIN_DATA*)calloc(1, sizeof(PLUGIN_DATA)); POPUPDATAT ppd = { 0 }; ppd.lchContact = sd->hContact; char *szProto = GetContactProto(sd->hContact); pdata->hIcon = ppd.lchIcon = Finger_GetClientIcon(sd->MirVer, false); _ASSERT(ppd.lchIcon); if (!ppd.lchIcon || (INT_PTR)ppd.lchIcon == CALLSERVICE_NOTFOUND) { // if we didn't succeed retrieving client icon, show the usual status icon instead ppd.lchIcon = Skin_LoadProtoIcon(szProto, db_get_w(sd->hContact, szProto, "Status", ID_STATUS_OFFLINE)); pdata->hIcon = nullptr; } wcsncpy(ppd.lptzContactName, Clist_GetContactDisplayName(sd->hContact), _countof(ppd.lptzContactName) - 1); wcsncpy(ppd.lptzText, PopupText, _countof(ppd.lptzText) - 1); ppd.colorBack = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFBGCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_BGCOLOUR)); ppd.colorText = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFTEXTCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_TEXTCOLOUR)); ppd.PluginWindowProc = PopupWndProc; pdata->PopupLClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_LCLICK_ACTION); pdata->PopupRClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_RCLICK_ACTION); ppd.iSeconds = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_POPUPDELAY); ppd.PluginData = pdata; PUAddPopupT(&ppd); }
TCString CContactSettings::GetMsgFormat(int Flags, int *pOrder, char *szProtoOverride) // returns the requested message; sets Order to the order of the message in the message tree, if available; or to -1 otherwise. // szProtoOverride is needed only to get status message of the right protocol when the ICQ contact is on list, but not with the same // protocol on which it requests the message - this way we can still get contact details. { TCString Message = NULL; if (pOrder) *pOrder = -1; if (Flags & GMF_PERSONAL) // try getting personal message (it overrides global) Message = db_get_s(hContact, MOD_NAME, StatusToDBSetting(Status, DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPERSONAL), (TCHAR*)NULL); if (Flags & (GMF_LASTORDEFAULT | GMF_PROTOORGLOBAL | GMF_TEMPORARY) && Message.IsEmpty()) { char *szProto = szProtoOverride ? szProtoOverride : (hContact ? GetContactProto(hContact) : NULL); // we mustn't pass here by GMF_TEMPORARY flag, as otherwise we'll handle GMF_TEMPORARY | GMF_PERSONAL combination incorrectly, // which is supposed to get only per-contact messages, and at the same time also may be used with NULL contact to get the global status message if (Flags & (GMF_LASTORDEFAULT | GMF_PROTOORGLOBAL)) Message = CProtoSettings(szProto).GetMsgFormat(Flags, pOrder); else if (!hContact) { // handle global temporary message too if (g_ProtoStates[szProto].TempMsg.IsSet()) Message = g_ProtoStates[szProto].TempMsg; } } return Message; }
int CMPlugin::Load() { HookEvent(ME_SYSTEM_MODULESLOADED, MirandaLoaded); DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &g_hMainThread, THREAD_SET_CONTEXT, false, 0); InitOptions(); if (db_get_b(NULL, MODULENAME, DB_SETTINGSVER, 0) < 1) { TCString Str; Str = db_get_s(NULL, MODULENAME, DB_IGNORESUBSTRINGS, L""); if (Str.GetLen()) // fix incorrect regexp from v0.1.1.0 db_set_ws(NULL, MODULENAME, DB_IGNORESUBSTRINGS, Str.Replace(L"/Miranda[0-9A-F]{8}/", L"/[0-9A-F]{8}(\\W|$)/")); db_set_b(NULL, MODULENAME, DB_SETTINGSVER, 1); } return 0; }
extern "C" int __declspec(dllexport) Load(void) { mir_getLP( &pluginInfo ); HookEvent(ME_SYSTEM_MODULESLOADED, MirandaLoaded); DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &g_hMainThread, THREAD_SET_CONTEXT, false, 0); InitOptions(); if (db_get_b(NULL, MOD_NAME, DB_SETTINGSVER, 0) < 1) { TCString Str; Str = db_get_s(NULL, MOD_NAME, DB_IGNORESUBSTRINGS, _T("")); if (Str.GetLen()) // fix incorrect regexp from v0.1.1.0 db_set_ts(NULL, MOD_NAME, DB_IGNORESUBSTRINGS, Str.Replace(_T("/Miranda[0-9A-F]{8}/"), _T("/[0-9A-F]{8}(\\W|$)/"))); db_set_b(NULL, MOD_NAME, DB_SETTINGSVER, 1); } return 0; }
TCSubStr::TCSubStr(const TCString& str,uint pos,uint count) /**************************************************************************** * * Function: TCSubStr::TCSubStr * Parameters: str - TCString to copy from * pos - Starting position in the string * count - Number of characters to copy * * Description: Constructs a TCSubStr from another string, starting at the * position 'pos' and including 'count' characters. * ****************************************************************************/ { CHECK(str.valid()); if (pos > str.length()) pos = str.length(); if (count > str.length() - pos) count = str.length() - pos; len = count+1; text = (char *)((const char *)str + pos); }
int PcreCheck(TCString Str, int StartingID) { // StartingID specifies the pattern from which to start checking, i.e. the check starts from the next pattern after the one that has ID == StartingID int I; if (StartingID == -1) { I = 0; } else { for (I = 0; I < PcreCompileData.GetSize(); I++) { if (PcreCompileData[I].ID == StartingID) { I++; break; } } } for (; I < PcreCompileData.GetSize(); I++) { if (PcreCompileData[I].pPcre) { int Res = pcre16_exec(PcreCompileData[I].pPcre, PcreCompileData[I].pExtra, Str, Str.GetLen() - 1, 0, PCRE_NOTEMPTY | PCRE_NO_UTF8_CHECK, NULL, 0); if (Res >= 0) { return PcreCompileData[I].ID; } } else { if (_tcsstr(Str.ToLower(), PcreCompileData[I].Pattern.ToLower())) { return PcreCompileData[I].ID; } } } return -1; }
TCString DBGetContactSettingAsString(MCONTACT hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue) { // also converts numeric values to a string DBVARIANT dbv = {0}; int iRes = db_get_ws(hContact, szModule, szSetting, &dbv); TCString Result; if (!iRes && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR)) { Result = dbv.ptszVal; } else if (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD) { long value = (dbv.type == DBVT_DWORD) ? dbv.dVal : (dbv.type == DBVT_WORD ? dbv.wVal : dbv.bVal); _ultot(value, Result.GetBuffer(64), 10); Result.ReleaseBuffer(); } else Result = szDefaultValue; if (!iRes) db_free(&dbv); return Result; }
TCString VariablesEscape(TCString Str) { if (!Str.GetLen()) { return _T(""); } enum eState { ST_TEXT, ST_QUOTE }; eState State = ST_QUOTE; TCString Result(_T("`")); const TCHAR *p = Str; while (*p) { if (*p == '`') { if (State == ST_TEXT) { Result += _T("````"); State = ST_QUOTE; } else { Result += _T("``"); } } else { Result += *p; State = ST_TEXT; } p++; } if (State == ST_QUOTE) { Result.GetBuffer()[Result.GetLen() - 1] = '\0'; Result.ReleaseBuffer(); } else { Result += '`'; } return Result; }
static LRESULT CALLBACK MsgTreeSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { CMsgTree *dat = CWndUserData(GetParent(hWnd)).GetMsgTree(); switch (Msg) { case UM_MSGTREE_UPDATE: // returns TRUE if updated { bool Modified = dat->MsgTreePage.GetModified(); TCString WndTitle; if (Modified) { WndTitle.GetBuffer(256); HWND hCurWnd = hWnd; do { hCurWnd = GetParent(hCurWnd); } while (hCurWnd && !GetWindowText(hCurWnd, WndTitle, 256)); WndTitle.ReleaseBuffer(); } if (!Modified || MessageBox(GetParent(hWnd), TCString(TranslateT("You've made changes to multiple message trees at a time.\r\nDo you want to leave changes in \"")) + WndTitle + TranslateT("\" dialog?\r\nPress Yes to leave changes in this dialog, or No to discard its changes and save changes of the other message tree instead."), WndTitle + _T(" - ") + TranslateT("New Away System"), MB_ICONQUESTION | MB_YESNO) == IDNO) { COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); TCString OldTitle, OldMsg, NewTitle, NewMsg; int OldOrder = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hWnd))); if (OldOrder != -1) { CBaseTreeItem* ItemOld = (OldOrder <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OldOrder)] : (CBaseTreeItem*)&TreeCtrl->Value[OldOrder]; OldTitle = ItemOld->Title; if (!(ItemOld->Flags & TIF_ROOTITEM)) OldMsg = ((CTreeItem*)ItemOld)->User_Str1; } dat->UpdateLock++; dat->MsgTreePage.DBToMemToPage(); dat->UpdateLock--; NMMSGTREE nm = { 0 }; int Order = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hWnd))); if (Order != -1) { nm.ItemNew = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; NewTitle = nm.ItemNew->Title; if (!(nm.ItemNew->Flags & TIF_ROOTITEM)) NewMsg = ((CTreeItem*)nm.ItemNew)->User_Str1; } if (OldTitle.IsEmpty()) OldTitle = _T(""); // to be sure that NULL will be equal to "" in the latter comparisons if (OldMsg.IsEmpty()) OldMsg = _T(""); if (NewTitle.IsEmpty()) NewTitle = _T(""); if (NewMsg.IsEmpty()) NewMsg = _T(""); if (OldTitle != (const TCHAR*)NewTitle || OldMsg != (const TCHAR*)NewMsg) { // probably it's better to leave nm.ItemOld = NULL, to prevent accidental rewriting of it with old data from an edit control etc. nm.hdr.code = MTN_SELCHANGED; nm.hdr.hwndFrom = hWnd; nm.hdr.idFrom = GetDlgCtrlID(hWnd); SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm); } return true; } } return false; case WM_KEYDOWN: switch (wParam) { case VK_DELETE: dat->DeleteSelectedItem(); break; case VK_INSERT: dat->AddMessage(); break; } break; case WM_RBUTTONDOWN: SetFocus(hWnd); { TVHITTESTINFO hitTest; hitTest.pt.x = (short)LOWORD(lParam); hitTest.pt.y = (short)HIWORD(lParam); TreeView_HitTest(hWnd, &hitTest); if (hitTest.hItem && hitTest.flags & TVHT_ONITEM) TreeView_SelectItem(hWnd, hitTest.hItem); return DefWindowProc(hWnd, Msg, wParam, lParam); } break; case WM_CONTEXTMENU: { TVHITTESTINFO ht; ht.pt.x = GET_X_LPARAM(lParam); ht.pt.y = GET_Y_LPARAM(lParam); TVITEM tvi = { 0 }; if (ht.pt.x == -1 && ht.pt.y == -1) { // use selected item if (tvi.hItem = TreeView_GetSelection(hWnd)) { TreeView_EnsureVisible(hWnd, tvi.hItem); RECT rc; TreeView_GetItemRect(hWnd, tvi.hItem, &rc, true); ht.pt.x = rc.left; ht.pt.y = rc.bottom; } } else { ScreenToClient(hWnd, &ht.pt); TreeView_HitTest(hWnd, &ht); if (ht.hItem && ht.flags & TVHT_ONITEM) { tvi.hItem = ht.hItem; } } if (tvi.hItem) { COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); tvi.mask = TVIF_HANDLE | TVIF_PARAM; TreeView_GetItem(hWnd, &tvi); int Order = TreeCtrl->IDToOrder(tvi.lParam); if (Order >= 0) { HMENU hMenu; if (TreeCtrl->Value[Order].Flags & TIF_GROUP) hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MSGTREE_CATEGORYMENU)); else hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MSGTREE_MESSAGEMENU)); _ASSERT(hMenu); HMENU hPopupMenu = GetSubMenu(hMenu, 0); TranslateMenu(hPopupMenu); ClientToScreen(hWnd, &ht.pt); struct { int ItemID, IconID; } MenuItems[] = { IDM_MSGTREEMENU_NEWMESSAGE, IMGLIST_NEWMESSAGE, IDM_MSGTREEMENU_NEWCATEGORY, IMGLIST_NEWCATEGORY, IDM_MSGTREEMENU_DELETE, IMGLIST_DELETE }; MENUITEMINFO mii = { 0 }; mii.cbSize = sizeof(mii); mii.fMask = MIIM_BITMAP | MIIM_DATA | MIIM_STATE | MIIM_CHECKMARKS; mii.hbmpItem = HBMMENU_CALLBACK; int i; for (i = 0; i < _countof(MenuItems); i++) { // set icons mii.dwItemData = MenuItems[i].IconID; SetMenuItemInfo(hPopupMenu, MenuItems[i].ItemID, false, &mii); } mii.fMask = MIIM_STATE; mii.fState = MFS_CHECKED; for (i = 0; i < _countof(SettingsList); i++) // set checkmarks if (TreeCtrl->Value[Order].ID == dat->MsgTreePage.GetValue(SettingsList[i].DBSetting)) SetMenuItemInfo(hPopupMenu, SettingsList[i].MenuItemID, false, &mii); int MenuResult = TrackPopupMenu(hPopupMenu, TPM_RIGHTBUTTON | TPM_RETURNCMD, ht.pt.x, ht.pt.y, 0, hWnd, NULL); switch (MenuResult) { case IDM_MSGTREEMENU_NEWMESSAGE: dat->AddMessage(); break; case IDM_MSGTREEMENU_NEWCATEGORY: dat->AddCategory(); break; case IDM_MSGTREEMENU_RENAME: TreeView_EditLabel(hWnd, tvi.hItem); break; case IDM_MSGTREEMENU_DELETE: dat->DeleteSelectedItem(); break; case IDR_MSGTREEMENU_DEF_ONL: case IDR_MSGTREEMENU_DEF_AWAY: case IDR_MSGTREEMENU_DEF_NA: case IDR_MSGTREEMENU_DEF_OCC: case IDR_MSGTREEMENU_DEF_DND: case IDR_MSGTREEMENU_DEF_FFC: case IDR_MSGTREEMENU_DEF_INV: case IDR_MSGTREEMENU_DEF_OTP: case IDR_MSGTREEMENU_DEF_OTL: for (int i = 0; i < _countof(SettingsList); i++) { if (SettingsList[i].MenuItemID == MenuResult) { dat->SetDefMsg(SettingsList[i].Status, tvi.lParam); break; } } } DestroyMenu(hMenu); return 0; } } } break; case WM_MEASUREITEM: { LPMEASUREITEMSTRUCT lpmi = (LPMEASUREITEMSTRUCT)lParam; if (lpmi->CtlType == ODT_MENU) { lpmi->itemWidth = max(0, GetSystemMetrics(SM_CXSMICON) - GetSystemMetrics(SM_CXMENUCHECK) + 4); lpmi->itemHeight = GetSystemMetrics(SM_CYSMICON) + 2; return true; } } break; case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->CtlType == ODT_MENU) { ImageList_DrawEx(dat->hImageList, dis->itemData, dis->hDC, 2, (dis->rcItem.bottom + dis->rcItem.top - GetSystemMetrics(SM_CYSMICON)) / 2 + 1, 0, 0, GetSysColor(COLOR_WINDOW), CLR_NONE, ILD_NORMAL); return true; } } break; } return CallWindowProc(dat->OrigTreeViewProc, hWnd, Msg, wParam, lParam); }
TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring, int ID) { TCString Result(_T("")); sPcreCompileData s = {0}; int NewID = PcreCompileData.AddElem(s); PcreCompileData[NewID].ID = ID; if (hPcreDLL && !bAddAsUsualSubstring) { const char *Err; int ErrOffs; int Flags = PCRE_CASELESS; if (Regexp[0] == '/') { TCString OrigRegexp = Regexp; Regexp = Regexp.Right(Regexp.GetLen() - 1); TCHAR *pRegexpEnd = (TCHAR*)Regexp + Regexp.GetLen(); TCHAR *p = _tcsrchr(Regexp.GetBuffer(), '/'); if (!p) { Regexp = OrigRegexp; } else { *p = 0; Flags = 0; while (++p < pRegexpEnd) { switch (*p) { case 'i': Flags |= PCRE_CASELESS; break; case 'm': Flags |= PCRE_MULTILINE; break; case 's': Flags |= PCRE_DOTALL; break; case 'x': Flags |= PCRE_EXTENDED; break; case 'A': Flags |= PCRE_ANCHORED; break; case 'f': Flags |= PCRE_FIRSTLINE; break; case 'D': Flags |= PCRE_DOLLAR_ENDONLY; break; case 'U': Flags |= PCRE_UNGREEDY; break; case 'X': Flags |= PCRE_EXTRA; break; default: // Result += LogMessage(Translate("Warning, unknown pattern modifier '%c':\n"), *p ); break; } } } Regexp.ReleaseBuffer(); } PcreCompileData[NewID].pPcre = pcre_compile(WCHAR2UTF8(Regexp).GetData(), PCRE_UTF8 | PCRE_NO_UTF8_CHECK | Flags, &Err, &ErrOffs, NULL); if (PcreCompileData[NewID].pPcre) { PcreCompileData[NewID].pExtra = NULL; if (pcre_study) PcreCompileData[NewID].pExtra = pcre_study(PcreCompileData[NewID].pPcre, 0, &Err); } else { // Result += LogMessage(TranslateT("Syntax error in regexp\n%s\nat offset %d: %s."), (TCHAR*)Regexp, ErrOffs, (TCHAR*)ANSI2TCHAR(Err)) + _T("\n\n"); PcreCompileData[NewID].Pattern = Regexp; } } else PcreCompileData[NewID].Pattern = Regexp; return Result; }
TCDynStr operator * (const TCString& s1,uint count) { CHECK(s1.valid()); TCDynStr s(s1); return s *= count; }
TCDynStr operator + (const char *s1,const TCString& s2) { CHECK(s1 != NULL && s2.valid()); TCDynStr s(s1); return s += s2; }
TCDynStr operator + (const TCString& s1,const TCString& s2) { CHECK(s1.valid() && s2.valid()); TCDynStr s(s1); return s += s2; }
int ContactSettingChanged(WPARAM hContact, LPARAM lParam) { DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; if (lstrcmpA(cws->szSetting, DB_MIRVER)) return 0; SHOWPOPUP_DATA sd = {0}; char *szProto = GetContactProto(hContact); if (g_PreviewOptPage) sd.MirVer = _T("Miranda NG ICQ 0.93.5.3007"); else { if (!hContact) // exit if hContact == NULL and it's not a popup preview return 0; _ASSERT(szProto); if (!strcmp(szProto, META_PROTO)) // workaround for metacontacts return 0; sd.MirVer = db_get_s(hContact, szProto, DB_MIRVER, _T("")); if (sd.MirVer.IsEmpty()) return 0; } sd.OldMirVer = db_get_s(hContact, MOD_NAME, DB_OLDMIRVER, _T("")); db_set_ts(hContact, MOD_NAME, DB_OLDMIRVER, sd.MirVer); // we have to write it here, because we modify sd.OldMirVer and sd.MirVer to conform our settings later if (sd.OldMirVer.IsEmpty()) // looks like it's the right way to do return 0; COptPage PopupOptPage; if (g_PreviewOptPage) PopupOptPage = *g_PreviewOptPage; else { PopupOptPage = g_PopupOptPage; PopupOptPage.DBToMem(); } MCONTACT hContactOrMeta = (hContact) ? db_mc_getMeta(hContact) : 0; if (!hContactOrMeta) hContactOrMeta = hContact; if (hContact && db_get_b(hContactOrMeta, "CList", "Hidden", 0)) return 0; int PerContactSetting = hContact ? db_get_b(hContact, MOD_NAME, DB_CCN_NOTIFY, NOTIFY_USEGLOBAL) : NOTIFY_ALWAYS; // NOTIFY_ALWAYS for preview if (PerContactSetting == NOTIFY_USEGLOBAL && hContactOrMeta != hContact) // subcontact setting has a priority over a metacontact setting PerContactSetting = db_get_b(hContactOrMeta, MOD_NAME, DB_CCN_NOTIFY, NOTIFY_USEGLOBAL); if (PerContactSetting && (PerContactSetting == NOTIFY_ALMOST_ALWAYS || PerContactSetting == NOTIFY_ALWAYS || !PopupOptPage.GetValue(IDC_POPUPOPTDLG_USESTATUSNOTIFYFLAG) || !(db_get_dw(hContactOrMeta, "Ignore", "Mask1", 0) & 0x8))) { // check if we need to notify at all sd.hContact = hContact; sd.PopupOptPage = &PopupOptPage; if (!PopupOptPage.GetValue(IDC_POPUPOPTDLG_VERCHGNOTIFY) || !PopupOptPage.GetValue(IDC_POPUPOPTDLG_SHOWVER)) { if (bFingerprintExists) { LPCTSTR ptszOldClient = Finger_GetClientDescr(sd.OldMirVer); LPCTSTR ptszClient = Finger_GetClientDescr(sd.MirVer); if (ptszOldClient && ptszClient) { if (PerContactSetting != NOTIFY_ALMOST_ALWAYS && PerContactSetting != NOTIFY_ALWAYS && !PopupOptPage.GetValue(IDC_POPUPOPTDLG_VERCHGNOTIFY) && !_tcscmp(ptszClient, ptszOldClient)) return 0; if (!PopupOptPage.GetValue(IDC_POPUPOPTDLG_SHOWVER)) { sd.MirVer = ptszClient; sd.OldMirVer = ptszOldClient; } } } } if (sd.MirVer == (const TCHAR*)sd.OldMirVer) { _ASSERT(hContact); return 0; } if (PerContactSetting == NOTIFY_ALWAYS || (PopupOptPage.GetValue(IDC_POPUPOPTDLG_POPUPNOTIFY) && (g_PreviewOptPage || PerContactSetting == NOTIFY_ALMOST_ALWAYS || -1 == PcreCheck(sd.MirVer)))) { ShowPopup(&sd); SkinPlaySound(CLIENTCHANGED_SOUND); } } if (hContact) { TCString ClientName; if (PopupOptPage.GetValue(IDC_POPUPOPTDLG_SHOWPREVCLIENT) && sd.OldMirVer.GetLen()) { mir_sntprintf(ClientName.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("%s (was %s)"), (const TCHAR*)sd.MirVer, (const TCHAR*)sd.OldMirVer); ClientName.ReleaseBuffer(); } else ClientName = sd.MirVer; } _ASSERT(sd.MirVer.GetLen()); // save the last known MirVer value even if the new one is empty return 0; }
void CProtoSettings::SetMsgFormat(int Flags, TCString Message) { if (Flags & (SMF_TEMPORARY | SMF_PERSONAL) && g_AutoreplyOptPage.GetDBValueCopy(IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON) && GetMsgFormat(Flags & (SMF_TEMPORARY | SMF_PERSONAL)) != (const TCHAR*)Message) ResetSettingsOnStatusChange(szProto); if (Flags & SMF_TEMPORARY) { _ASSERT(!Status || Status == g_ProtoStates[szProto].Status); g_ProtoStates[szProto].TempMsg = (szProto || Message != NULL) ? Message : CProtoSettings(NULL, Status).GetMsgFormat(GMF_LASTORDEFAULT); } if (Flags & SMF_PERSONAL) { // set a "personal" message for a protocol. also it's used to set global status message (hContact = NULL). // if Message == NULL, then we'll use the "default" message - i.e. it's either the global message for szProto != NULL (we delete the per-proto DB setting), or it's just a default message for a given status for szProto == NULL. g_ProtoStates[szProto].TempMsg.Unset(); CString DBSetting(ProtoStatusToDBSetting(DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPROTOMSGS)); if (Message != NULL) db_set_ts(NULL, MOD_NAME, DBSetting, Message); else { if (!szProto) db_set_ts(NULL, MOD_NAME, DBSetting, CProtoSettings(NULL, Status).GetMsgFormat(GMF_LASTORDEFAULT)); // global message can't be NULL; we can use an empty string instead if it's really necessary else db_unset(NULL, MOD_NAME, DBSetting); } } if (Flags & SMF_LAST) { COptPage MsgTreeData(g_MsgTreePage); COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE); TreeCtrl->DBToMem(CString(MOD_NAME)); int RecentGroupID = GetRecentGroupID(Status); if (RecentGroupID == -1) { // we didn't find the group, it also means that we're using per status messages; so we need to create it TreeCtrl->Value.AddElem(CTreeItem(Status ? pcli->pfnGetStatusModeDescription(Status, 0) : MSGTREE_RECENT_OTHERGROUP, g_Messages_RecentRootID, RecentGroupID = TreeCtrl->GenerateID(), TIF_GROUP)); TreeCtrl->SetModified(true); } int i; // try to find an identical message in the same group (to prevent saving multiple identical messages), // or at least if we'll find an identical message somewhere else, then we'll use its title for our new message TCString Title(_T("")); for (i = 0; i < TreeCtrl->Value.GetSize(); i++) { if (!(TreeCtrl->Value[i].Flags & TIF_GROUP) && TreeCtrl->Value[i].User_Str1 == (const TCHAR*)Message) { if (TreeCtrl->Value[i].ParentID == RecentGroupID) { // found it in the same group int GroupOrder = TreeCtrl->IDToOrder(RecentGroupID); TreeCtrl->Value.MoveElem(i, (GroupOrder >= 0) ? (GroupOrder + 1) : 0); // now move it to the top of recent messages list TreeCtrl->SetModified(true); break; // no reason to search for anything else } if (Title.IsEmpty()) // it's not in the same group, but at least we'll use its title Title = TreeCtrl->Value[i].Title; } } if (i == TreeCtrl->Value.GetSize()) { // we didn't find an identical message in the same group, so we'll add our new message here if (Title.IsEmpty()) { // didn't find a title for our message either if (Message.GetLen() > MRM_MAX_GENERATED_TITLE_LEN) Title = Message.Left(MRM_MAX_GENERATED_TITLE_LEN - 3) + _T("..."); else Title = Message; TCHAR *p = Title.GetBuffer(); while (*p) { // remove "garbage" if (!(p = _tcspbrk(p, _T("\r\n\t")))) break; *p++ = ' '; } Title.ReleaseBuffer(); } int GroupOrder = TreeCtrl->IDToOrder(RecentGroupID); TreeCtrl->Value.InsertElem(CTreeItem(Title, RecentGroupID, TreeCtrl->GenerateID(), 0, Message), (GroupOrder >= 0) ? (GroupOrder + 1) : 0); TreeCtrl->SetModified(true); } // now clean up here int MRMNum = 0; int MaxMRMNum = g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_RECENTMSGSCOUNT); for (i = 0; i < TreeCtrl->Value.GetSize(); i++) { if (TreeCtrl->Value[i].ParentID == RecentGroupID) { // found a child of our group if (TreeCtrl->Value[i].Flags & TIF_GROUP || ++MRMNum > MaxMRMNum) { // what groups are doing here?! :)) TreeCtrl->Value.RemoveElem(i); TreeCtrl->SetModified(true); i--; } } } // if we're saving recent messages per status, then remove any messages that were left at the recent messages' root if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSMRM)) { for (i = 0; i < TreeCtrl->Value.GetSize(); i++) { if (TreeCtrl->Value[i].ParentID == g_Messages_RecentRootID) { if (!(TreeCtrl->Value[i].Flags & TIF_GROUP)) { TreeCtrl->Value.RemoveElem(i); TreeCtrl->SetModified(true); i--; } } } } TreeCtrl->MemToDB(CString(MOD_NAME)); } }
// returns the requested message; sets Order to the order of the message in the message tree, if available; or to -1 otherwise. TCString CProtoSettings::GetMsgFormat(int Flags, int *pOrder) { TCString Message = NULL; if (pOrder) *pOrder = -1; if (Flags & GMF_TEMPORARY) { _ASSERT(!Status || Status == g_ProtoStates[szProto].Status); if (g_ProtoStates[szProto].TempMsg.IsSet()) { Message = g_ProtoStates[szProto].TempMsg; Flags &= ~GMF_PERSONAL; // don't allow personal message to overwrite our NULL temporary message } } if (Flags & GMF_PERSONAL && Message == NULL) // try getting personal message (it overrides global) Message = db_get_s(NULL, MOD_NAME, ProtoStatusToDBSetting(DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPROTOMSGS), (TCHAR*)NULL); if (Flags & GMF_PROTOORGLOBAL && Message == NULL) { Message = CProtoSettings().GetMsgFormat(GMF_PERSONAL | (Flags & GMF_TEMPORARY), pOrder); return (Message == NULL) ? _T("") : Message; // global message can't be NULL } if (Flags & GMF_LASTORDEFAULT && Message == NULL) { // try to get the last or default message, depending on current settings COptPage MsgTreeData(g_MsgTreePage); COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE); TreeCtrl->DBToMem(CString(MOD_NAME)); Message = NULL; if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_USELASTMSG)) { // if using last message by default... Message = db_get_s(NULL, MOD_NAME, ProtoStatusToDBSetting(DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPROTOMSGS), (TCHAR*)NULL); // try per-protocol message first if (Message.IsEmpty()) { Message = NULL; // to be sure it's NULL, not "" - as we're checking 'Message == NULL' later int RecentGroupID = GetRecentGroupID(Status); if (RecentGroupID != -1) { for (int i = 0; i < TreeCtrl->Value.GetSize(); i++) { // find first message in the group if (TreeCtrl->Value[i].ParentID == RecentGroupID && !(TreeCtrl->Value[i].Flags & TIF_GROUP)) { Message = TreeCtrl->Value[i].User_Str1; if (pOrder) *pOrder = i; break; } } } } } // else, if using default message by default... if (Message == NULL) { // ...or we didn't succeed retrieving the last message // get default message for this status int DefMsgID = -1; static struct { int DBSetting, Status; } DefMsgDlgItems[] = { IDS_MESSAGEDLG_DEF_ONL, ID_STATUS_ONLINE, IDS_MESSAGEDLG_DEF_AWAY, ID_STATUS_AWAY, IDS_MESSAGEDLG_DEF_NA, ID_STATUS_NA, IDS_MESSAGEDLG_DEF_OCC, ID_STATUS_OCCUPIED, IDS_MESSAGEDLG_DEF_DND, ID_STATUS_DND, IDS_MESSAGEDLG_DEF_FFC, ID_STATUS_FREECHAT, IDS_MESSAGEDLG_DEF_INV, ID_STATUS_INVISIBLE, IDS_MESSAGEDLG_DEF_OTP, ID_STATUS_ONTHEPHONE, IDS_MESSAGEDLG_DEF_OTL, ID_STATUS_OUTTOLUNCH }; for (int i = 0; i < SIZEOF(DefMsgDlgItems); i++) { if (DefMsgDlgItems[i].Status == Status) { DefMsgID = MsgTreeData.GetDBValue(DefMsgDlgItems[i].DBSetting); break; } } if (DefMsgID == -1) DefMsgID = MsgTreeData.GetDBValue(IDS_MESSAGEDLG_DEF_AWAY); // use away message for unknown statuses int Order = TreeCtrl->IDToOrder(DefMsgID); // this will return -1 in any case if something goes wrong if (Order >= 0) Message = TreeCtrl->Value[Order].User_Str1; if (pOrder) *pOrder = Order; } if (Message == NULL) Message = _T(""); // last or default message can't be NULL.. otherwise ICQ won't reply to status message requests and won't notify us of status message requests at all } return Message; }
INT_PTR srvVariablesHandler(WPARAM, LPARAM lParam) { ARGUMENTSINFO *ai = (ARGUMENTSINFO*)lParam; ai->flags = AIF_DONTPARSE; TCString Result; if (!mir_tstrcmp(ai->targv[0], VAR_AWAYSINCE_TIME)) { GetTimeFormat(LOCALE_USER_DEFAULT, 0, g_ProtoStates[VarParseData.szProto].AwaySince, (ai->argc > 1 && *ai->targv[1]) ? ai->targv[1] : _T("H:mm"), Result.GetBuffer(256), 256); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_AWAYSINCE_DATE)) { GetDateFormat(LOCALE_USER_DEFAULT, 0, g_ProtoStates[VarParseData.szProto].AwaySince, (ai->argc > 1 && *ai->targv[1]) ? ai->targv[1] : NULL, Result.GetBuffer(256), 256); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_STATDESC)) { Result = (VarParseData.Flags & VPF_XSTATUS) ? STR_XSTATUSDESC : pcli->pfnGetStatusModeDescription(g_ProtoStates[VarParseData.szProto].Status, 0); } else if (!mir_tstrcmp(ai->targv[0], VAR_MYNICK)) { if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_MYNICKPERPROTO) && VarParseData.szProto) Result = db_get_s(NULL, VarParseData.szProto, "Nick", (TCHAR*)NULL); if (Result == NULL) Result = pcli->pfnGetContactDisplayName(NULL, 0); if (Result == NULL) Result = TranslateT("Stranger"); } else if (!mir_tstrcmp(ai->targv[0], VAR_REQUESTCOUNT)) { mir_sntprintf(Result.GetBuffer(16), 16, _T("%d"), db_get_w(ai->fi->hContact, MOD_NAME, DB_REQUESTCOUNT, 0)); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_MESSAGENUM)) { mir_sntprintf(Result.GetBuffer(16), 16, _T("%d"), db_get_w(ai->fi->hContact, MOD_NAME, DB_MESSAGECOUNT, 0)); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_TIMEPASSED)) { ULARGE_INTEGER ul_AwaySince, ul_Now; SYSTEMTIME st; GetLocalTime(&st); SystemTimeToFileTime(&st, (LPFILETIME)&ul_Now); SystemTimeToFileTime(g_ProtoStates[VarParseData.szProto].AwaySince, (LPFILETIME)&ul_AwaySince); ul_Now.QuadPart -= ul_AwaySince.QuadPart; ul_Now.QuadPart /= 10000000; // now it's in seconds Result.GetBuffer(256); if (ul_Now.LowPart >= 7200) // more than 2 hours mir_sntprintf(Result, 256, TranslateT("%d hours"), ul_Now.LowPart / 3600); else if (ul_Now.LowPart >= 120) // more than 2 minutes mir_sntprintf(Result, 256, TranslateT("%d minutes"), ul_Now.LowPart / 60); else mir_sntprintf(Result, 256, TranslateT("%d seconds"), ul_Now.LowPart); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_PREDEFINEDMESSAGE)) { ai->flags = 0; // reset AIF_DONTPARSE flag if (ai->argc != 2) return NULL; COptPage MsgTreeData(g_MsgTreePage); COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE); TreeCtrl->DBToMem(CString(MOD_NAME)); for (int i = 0; i < TreeCtrl->Value.GetSize(); i++) { if (!(TreeCtrl->Value[i].Flags & TIF_GROUP) && !mir_tstrcmpi(TreeCtrl->Value[i].Title, ai->targv[1])) { Result = TreeCtrl->Value[i].User_Str1; break; } } if (Result == NULL) // if we didn't find a message with specified title return NULL; // return it now, as later we change NULL to "" } else if (!mir_tstrcmp(ai->targv[0], VAR_PROTOCOL)) { if (VarParseData.szProto) { CString AnsiResult; CallProtoService(VarParseData.szProto, PS_GETNAME, 256, (LPARAM)AnsiResult.GetBuffer(256)); AnsiResult.ReleaseBuffer(); Result = _A2T(AnsiResult); } if (Result == NULL) // if we didn't find a message with specified title return NULL; // return it now, as later we change NULL to "" } TCHAR *szResult = (TCHAR*)malloc((Result.GetLen() + 1) * sizeof(TCHAR)); if (!szResult) return NULL; mir_tstrcpy(szResult, (Result != NULL) ? Result : _T("")); return (INT_PTR)szResult; }