From a142d261af1f740156898be29c3724b8a517a77a Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 23 Feb 2015 19:08:20 +0000 Subject: DoRtfToTags fixed & moved into the core git-svn-id: http://svn.miranda-ng.org/main/trunk@12252 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- include/m_chat_int.h | 4 +- plugins/Scriver/scriver_10.vcxproj | 3 - plugins/Scriver/scriver_10.vcxproj.filters | 3 - plugins/Scriver/scriver_12.vcxproj | 3 - plugins/Scriver/scriver_12.vcxproj.filters | 3 - plugins/Scriver/src/chat/chat.h | 3 - plugins/Scriver/src/chat/message.cpp | 289 ----------------------------- plugins/Scriver/src/chat/window.cpp | 19 +- plugins/TabSRMM/src/chat/window.cpp | 3 +- src/core/stdchat/src/chat.h | 1 - src/core/stdchat/src/message.cpp | 285 ---------------------------- src/core/stdchat/src/window.cpp | 28 +-- src/miranda32_10.vcxproj | 3 + src/miranda32_10.vcxproj.filters | 3 + src/miranda32_12.vcxproj | 6 + src/miranda32_12.vcxproj.filters | 3 + src/modules/chat/chat.h | 3 +- src/modules/chat/chat_rtf.cpp | 206 ++++++++++++++++++++ src/modules/chat/manager.cpp | 1 + src/modules/chat/tools.cpp | 2 +- 20 files changed, 257 insertions(+), 614 deletions(-) delete mode 100644 plugins/Scriver/src/chat/message.cpp create mode 100644 src/modules/chat/chat_rtf.cpp diff --git a/include/m_chat_int.h b/include/m_chat_int.h index a98d682713..5fb3c5e424 100644 --- a/include/m_chat_int.h +++ b/include/m_chat_int.h @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef M_CHAT_INT_H__ #define M_CHAT_INT_H__ 1 +#include #include #define OPTIONS_FONTCOUNT 20 @@ -378,7 +379,7 @@ struct CHAT_MANAGER TCHAR* (*MakeTimeStamp)(TCHAR *pszStamp, time_t time); BOOL (*DoEventHook)(const TCHAR *pszID, const char *pszModule, int iType, const TCHAR *pszUID, const TCHAR* pszText, INT_PTR dwItem); - BOOL (*DoEventHookAsync)(HWND hwnd, const TCHAR *pszID, const char *pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, INT_PTR dwItem); + BOOL (*DoEventHookAsync)(HWND hwnd, const TCHAR *pszID, const char *pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, INT_PTR dwItem); BOOL (*DoSoundsFlashPopupTrayStuff)(SESSION_INFO *si, GCEVENT *gce, BOOL bHighlight, int bManyFix); BOOL (*DoTrayIcon)(SESSION_INFO *si, GCEVENT *gce); @@ -394,6 +395,7 @@ struct CHAT_MANAGER void (*ReloadSettings)(void); void (*ColorChooser)(SESSION_INFO *si, BOOL bFG, HWND hwndDlg, HWND hwndTarget, HWND hwndChooser); + int (*DoRtfToTags)(CMString &pszText, int iNumColors, COLORREF *pColors); int logPixelSY, logPixelSX; char *szActiveWndModule; diff --git a/plugins/Scriver/scriver_10.vcxproj b/plugins/Scriver/scriver_10.vcxproj index 5d468959be..c3d9ac9697 100644 --- a/plugins/Scriver/scriver_10.vcxproj +++ b/plugins/Scriver/scriver_10.vcxproj @@ -220,9 +220,6 @@ ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h diff --git a/plugins/Scriver/scriver_10.vcxproj.filters b/plugins/Scriver/scriver_10.vcxproj.filters index d4c413c760..e9eb42ac80 100644 --- a/plugins/Scriver/scriver_10.vcxproj.filters +++ b/plugins/Scriver/scriver_10.vcxproj.filters @@ -72,9 +72,6 @@ Source Files\chat - - Source Files\chat - Source Files\chat diff --git a/plugins/Scriver/scriver_12.vcxproj b/plugins/Scriver/scriver_12.vcxproj index c3ce7c7125..0159ca5a74 100644 --- a/plugins/Scriver/scriver_12.vcxproj +++ b/plugins/Scriver/scriver_12.vcxproj @@ -223,9 +223,6 @@ ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h diff --git a/plugins/Scriver/scriver_12.vcxproj.filters b/plugins/Scriver/scriver_12.vcxproj.filters index d4c413c760..e9eb42ac80 100644 --- a/plugins/Scriver/scriver_12.vcxproj.filters +++ b/plugins/Scriver/scriver_12.vcxproj.filters @@ -72,9 +72,6 @@ Source Files\chat - - Source Files\chat - Source Files\chat diff --git a/plugins/Scriver/src/chat/chat.h b/plugins/Scriver/src/chat/chat.h index 0c382107ea..ff3e798807 100644 --- a/plugins/Scriver/src/chat/chat.h +++ b/plugins/Scriver/src/chat/chat.h @@ -99,9 +99,6 @@ TCHAR* my_strstri(const TCHAR* s1, const TCHAR* s2) ; UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO *si, TCHAR* pszUID, TCHAR* pszWordText); void DestroyGCMenu(HMENU *hMenu, int iIndex); -// message.c -TCHAR* DoRtfToTags( char* pszRtfText, SESSION_INFO *si); - ////////////////////////////////////////////////////////////////////////////////// #define DEFLOGFILENAME _T("%miranda_logpath%\\%proto%\\%userid%.log") diff --git a/plugins/Scriver/src/chat/message.cpp b/plugins/Scriver/src/chat/message.cpp deleted file mode 100644 index fe57ca5b57..0000000000 --- a/plugins/Scriver/src/chat/message.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* -Chat module plugin for Miranda IM - -Copyright (C) 2003 Jörgen Persson -Copyright 2003-2009 Miranda ICQ/IM project, - -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" - -static void CreateColorMap(char* Text, int *pIndex, SESSION_INFO *si) -{ - static const char* lpszFmt = "\\red%[^ \x5b\\]\\green%[^ \x5b\\]\\blue%[^ \x5b;];"; - char szRed[10], szGreen[10], szBlue[10]; - - char *p1 = strstr(Text, "\\colortbl"); - if (!p1) - return; - - char *pEnd = strchr(p1, '}'); - char *p2 = strstr(p1, "\\red"); - - int iIndex = 1; - while (p2 && p2 < pEnd) { - if (sscanf(p2, lpszFmt, &szRed, &szGreen, &szBlue) > 0) { - MODULEINFO *pMod = pci->MM_FindModule(si->pszModule); - for (int i = 0; i < pMod->nColorCount; i++) - if (pMod->crColors[i] == RGB(atoi(szRed), atoi(szGreen), atoi(szBlue))) - pIndex[i] = iIndex; - } - iIndex++; - p1 = p2; - p1++; - p2 = strstr(p1, "\\red"); - } -} - -static int ReadInteger(const char *p, int *result) -{ - char temp[10]; - int i = 0; - while (isdigit(*p)) - temp[i++] = *p++; - temp[i] = 0; - - if (result != NULL) - *result = atoi(temp); - - return i; -} - -TCHAR* DoRtfToTags(char *pszText, SESSION_INFO *si) -{ - if (!pszText) - return FALSE; - - // create an index of colors in the module and map them to - // corresponding colors in the RTF color table - MODULEINFO *mi = pci->MM_FindModule(si->pszModule); - int *pIndex = (int *)mir_alloc(sizeof(int)*mi->nColorCount); - for (int i = 0; i < mi->nColorCount; i++) - pIndex[i] = -1; - - CreateColorMap(pszText, pIndex, si); - - // scan the file for rtf commands and remove or parse them - char *p1 = strstr(pszText, "\\pard"); - if (p1 == NULL) { - mir_free(pIndex); - return FALSE; - } - - p1 += 5; - - memmove(pszText, p1, mir_strlen(p1) + 1); - p1 = pszText; - - // iterate through all characters, if rtf control character found then take action - BOOL bJustRemovedRTF = TRUE; - BOOL bTextHasStarted = FALSE; - char InsertThis[50]; - - while (*p1 != '\0') { - InsertThis[0] = 0; - int iRemoveChars = 0; - - switch (*p1) { - case '\\': - if (!memcmp(p1, "\\cf", 3)) { // foreground color - int iCol; - iRemoveChars = 3 + ReadInteger(p1 + 3, &iCol); - bJustRemovedRTF = TRUE; - - // int iInd = RTFColorToIndex(pIndex, iCol, si); - // if (bTextHasStarted || iInd >= 0) - // mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%c%02u" : "%%C", iInd); - } - else if (!memcmp(p1, "\\highlight", 10)) { //background color - int iCol; - iRemoveChars = 10 + ReadInteger(p1 + 10, &iCol); - bJustRemovedRTF = TRUE; - - // int iInd = RTFColorToIndex(pIndex, iCol, si); - // if (bTextHasStarted || iInd >= 0) - // mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%f%02u" : "%%F", iInd); - } - else if (!memcmp(p1, "\\lang", 5)) { // language id - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 5 + ReadInteger(p1 + 5, NULL); - } - else if (!memcmp(p1, "\\par", 4)) { // newline - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 4; - strcpy(InsertThis, "\n"); - } - else if (!memcmp(p1, "\\line", 5)) { // newline - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 5; - strcpy(InsertThis, "\n"); - } - else if (!memcmp(p1, "\\bullet", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\xA2"); - } - else if (!memcmp(p1, "\\b", 2)) { //bold - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = (p1[2] != '0') ? 2 : 3; - mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[2] != '0') ? "%%b" : "%%B"); - } - else if (!memcmp(p1, "\\i", 2)) { // italics - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = (p1[2] != '0') ? 2 : 3; - mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[2] != '0') ? "%%i" : "%%I"); - } - else if (!memcmp(p1, "\\uc", 3)) { // number of Unicode chars - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 4; - } - else if (!memcmp(p1, "\\ul", 3)) { // underlined - bTextHasStarted = bJustRemovedRTF = TRUE; - if (p1[3] == 'n') - iRemoveChars = 7; - else if (p1[3] == '0') - iRemoveChars = 4; - else - iRemoveChars = 3; - mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[3] != '0' && p1[3] != 'n') ? "%%u" : "%%U"); - } - else if (p1[1] == 'f' && isdigit(p1[2])) { // unicode char - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 2 + ReadInteger(p1 + 2, NULL); - } - else if (!memcmp(p1, "\\tab", 4)) { // tab - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 4; - strcpy(InsertThis, " "); - } - else if (!memcmp(p1, "\\endash", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x93"); - } - else if (!memcmp(p1, "\\emdash", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x94"); - } - else if (!memcmp(p1, "\\lquote", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x98"); - } - else if (!memcmp(p1, "\\rquote", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x99"); - } - else if (!memcmp(p1, "\\ldblquote", 10)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 10; - strcpy(InsertThis, "\xe2\x80\x9c"); - } - else if (!memcmp(p1, "\\rdblquote", 10)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 10; - strcpy(InsertThis, "\xe2\x80\x9d"); - } - else if (p1[1] == '\\' || p1[1] == '{' || p1[1] == '}') { // escaped characters - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 2; - mir_snprintf(InsertThis, SIZEOF(InsertThis), "%c", p1[1]); - } - else if (p1[1] == '~') { // non-breaking space - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 2; - strcpy(InsertThis, "\xC2\xA0"); - } - else if (p1[1] == '\'') { // special character - char tmp[4], *p3 = tmp; - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - if (p1[2] != ' ' && p1[2] != '\\') { - *p3++ = p1[2]; - iRemoveChars = 3; - if (p1[3] != ' ' && p1[3] != '\\') { - *p3++ = p1[3]; - iRemoveChars++; - } - *p3 = 0; - sscanf(tmp, "%x", InsertThis); - InsertThis[1] = 0; - } - else iRemoveChars = 2; - } - else if (bJustRemovedRTF) { // remove unknown RTF command - int j = 1; - bJustRemovedRTF = TRUE; - while (p1[j] != ' ' && p1[j] != '\\' && p1[j] != '\0') - j++; - iRemoveChars = j; - } - break; - - case '{': // other RTF control characters - case '}': - iRemoveChars = 1; - break; - - case '\r': case '\n': - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 1; - break; - - case '%': // escape chat -> protocol control character - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 1; - mir_snprintf(InsertThis, SIZEOF(InsertThis), "%%%%"); - break; - case ' ': // remove spaces following a RTF command - if (bJustRemovedRTF) - iRemoveChars = 1; - bJustRemovedRTF = FALSE; - bTextHasStarted = TRUE; - break; - - default: // other text that should not be touched - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - break; - } - - // move the memory and paste in new commands instead of the old RTF - if (InsertThis[0] || iRemoveChars) { - memmove(p1 + mir_strlen(InsertThis), p1 + iRemoveChars, mir_strlen(p1) - iRemoveChars + 1); - memcpy(p1, InsertThis, mir_strlen(InsertThis)); - p1 += mir_strlen(InsertThis); - } - else p1++; - } - - mir_free(pIndex); - return mir_utf8decodeT(pszText); -} diff --git a/plugins/Scriver/src/chat/window.cpp b/plugins/Scriver/src/chat/window.cpp index a642d0719a..9e5bdf5861 100644 --- a/plugins/Scriver/src/chat/window.cpp +++ b/plugins/Scriver/src/chat/window.cpp @@ -1702,7 +1702,13 @@ LABEL_SHOWWINDOW: case IDOK: if (IsWindowEnabled(GetDlgItem(hwndDlg, IDOK))) { - char *pszRtf = GetRichTextRTF(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + ptrA pszRtf(GetRichTextRTF(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE))); + if (pszRtf == NULL) + break; + + MODULEINFO *mi = pci->MM_FindModule(si->pszModule); + if (mi == NULL) + break; TCmdList *cmdListNew = tcmdlist_last(si->cmdList); while (cmdListNew != NULL && cmdListNew->temporary) { @@ -1711,10 +1717,13 @@ LABEL_SHOWWINDOW: } si->cmdList = tcmdlist_append(si->cmdList, pszRtf, 20, FALSE); - TCHAR *ptszText = DoRtfToTags(pszRtf, si); - rtrimt(ptszText); - if (pci->MM_FindModule(si->pszModule)->bAckMsg) { + CMString ptszText(ptrT(mir_utf8decodeT(pszRtf))); + pci->DoRtfToTags(ptszText, mi->nColorCount, mi->crColors); + ptszText.Trim(); + ptszText.Replace(_T("%"), _T("%%")); + + if (mi->bAckMsg) { EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), FALSE); SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETREADONLY, TRUE, 0); } @@ -1723,8 +1732,6 @@ LABEL_SHOWWINDOW: EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, 0); - mir_free(pszRtf); - mir_free(ptszText); SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); } break; diff --git a/plugins/TabSRMM/src/chat/window.cpp b/plugins/TabSRMM/src/chat/window.cpp index db496d27a3..c580683474 100644 --- a/plugins/TabSRMM/src/chat/window.cpp +++ b/plugins/TabSRMM/src/chat/window.cpp @@ -2885,6 +2885,7 @@ INT_PTR CALLBACK RoomWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar DoRtfToTags(si->dat, ptszText, mi->nColorCount, mi->crColors); ptszText.Trim(); + ptszText.Replace(_T("%"), _T("%%")); if (mi && mi->bAckMsg) { Utils::enableDlgControl(hwndDlg, IDC_CHAT_MESSAGE, false); @@ -2902,7 +2903,7 @@ INT_PTR CALLBACK RoomWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar bool fSound = true; if (ptszText[0] == '/' || si->iType == GCW_SERVER) fSound = false; - pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText.GetBuffer(), 0); + pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, 0); mi->idleTimeStamp = time(0); mi->lastIdleCheck = 0; pci->SM_BroadcastMessage(si->pszModule, GC_UPDATESTATUSBAR, 0, 1, TRUE); diff --git a/src/core/stdchat/src/chat.h b/src/core/stdchat/src/chat.h index a368b899e4..f9e6b05de8 100644 --- a/src/core/stdchat/src/chat.h +++ b/src/core/stdchat/src/chat.h @@ -170,7 +170,6 @@ bool LoadMessageFont(LOGFONT *lf, COLORREF *colour); // message.c char* Message_GetFromStream(HWND hwndDlg, SESSION_INFO *si); -TCHAR* DoRtfToTags( char* pszRtfText, SESSION_INFO *si); BOOL TabM_AddTab(const TCHAR *pszID, const char* pszModule); BOOL TabM_RemoveAll(void); diff --git a/src/core/stdchat/src/message.cpp b/src/core/stdchat/src/message.cpp index c7d96fa2a5..943aa24055 100644 --- a/src/core/stdchat/src/message.cpp +++ b/src/core/stdchat/src/message.cpp @@ -22,291 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "chat.h" #include -static int RTFColorToIndex(int *pIndex, int iCol, SESSION_INFO *si) -{ - MODULEINFO *pMod = pci->MM_FindModule(si->pszModule); - for (int i = 0; i < pMod->nColorCount; i++) - if (pIndex[i] == iCol) - return i; - - return -1; -} - -static void CreateColorMap(char* Text, int *pIndex, SESSION_INFO *si) -{ - int iIndex = 1; - - static const char* lpszFmt = "\\red%[^ \x5b\\]\\green%[^ \x5b\\]\\blue%[^ \x5b;];"; - char szRed[10], szGreen[10], szBlue[10]; - - char *p1 = strstr(Text, "\\colortbl"); - if (!p1) - return; - - char *pEnd = strchr(p1, '}'); - char *p2 = strstr(p1, "\\red"); - - while (p2 && p2 < pEnd) { - if (sscanf(p2, lpszFmt, &szRed, &szGreen, &szBlue) > 0) { - MODULEINFO *pMod = pci->MM_FindModule(si->pszModule); - for (int i = 0; i < pMod->nColorCount; i++) - if (pMod->crColors[i] == RGB(atoi(szRed), atoi(szGreen), atoi(szBlue))) - pIndex[i] = iIndex; - } - iIndex++; - p1 = p2; - p1++; - p2 = strstr(p1, "\\red"); - } -} - -static int ReadInteger( const char* p, int* result ) -{ - char temp[10]; - int i=0; - while (isdigit(*p)) - temp[i++] = *p++; - temp[i] = 0; - - if ( result != NULL ) - *result = atoi( temp ); - - return i; -} - -TCHAR* DoRtfToTags(char* pszText, SESSION_INFO *si) -{ - char *p1; - int* pIndex; - int i, iRemoveChars, cp = CP_ACP; - char InsertThis[50]; - BOOL bJustRemovedRTF = TRUE; - BOOL bTextHasStarted = FALSE; - int iUcMode = 0; - - if (!pszText) - return FALSE; - - // create an index of colors in the module and map them to - // corresponding colors in the RTF color table - pIndex = (int *)mir_alloc(sizeof(int)* pci->MM_FindModule(si->pszModule)->nColorCount); - for (i = 0; i < pci->MM_FindModule(si->pszModule)->nColorCount; i++) - pIndex[i] = -1; - - CreateColorMap(pszText, pIndex, si); - - // scan the file for rtf commands and remove or parse them - p1 = strstr(pszText, "\\pard"); - if (p1 == NULL) { - mir_free(pIndex); - return FALSE; - } - - p1 += 5; - - memmove(pszText, p1, strlen(p1) + 1); - p1 = pszText; - - // iterate through all characters, if rtf control character found then take action - while (*p1 != '\0') { - InsertThis[0] = 0; - iRemoveChars = 0; - - switch (*p1) { - case '\\': - if (!memcmp(p1, "\\cf", 3)) { // foreground color - int iCol, iInd; - iRemoveChars = 3 + ReadInteger(p1 + 3, &iCol); - iInd = RTFColorToIndex(pIndex, iCol, si); - bJustRemovedRTF = TRUE; - -// if (bTextHasStarted || iInd >= 0) -// mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%c%02u" : "%%C", iInd); - } - else if (!memcmp(p1, "\\highlight", 10)) { //background color - int iCol, iInd; - iRemoveChars = 10 + ReadInteger(p1 + 10, &iCol); - iInd = RTFColorToIndex(pIndex, iCol, si); - bJustRemovedRTF = TRUE; - -// if (bTextHasStarted || iInd >= 0) -// mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%f%02u" : "%%F", iInd); - } - else if (!memcmp(p1, "\\lang", 5)) { // language id - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 5 + ReadInteger(p1 + 5, NULL); - } - else if (!memcmp(p1, "\\par", 4)) { // newline - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 4; - strcpy(InsertThis, "\n"); - } - else if (!memcmp(p1, "\\line", 5)) { // newline - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 5; - strcpy(InsertThis, "\n"); - } - else if (!memcmp(p1, "\\bullet", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\xA2"); - } - else if (!memcmp(p1, "\\b", 2)) { //bold - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = (p1[2] != '0') ? 2 : 3; - mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[2] != '0') ? "%%b" : "%%B"); - } - else if (!memcmp(p1, "\\i", 2)) { // italics - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = (p1[2] != '0') ? 2 : 3; - mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[2] != '0') ? "%%i" : "%%I"); - } - else if (!memcmp(p1, "\\uc", 3)) { // number of Unicode chars - bTextHasStarted = bJustRemovedRTF = TRUE; - iUcMode = p1[3] - '0'; - iRemoveChars = 4; - } - else if (!memcmp(p1, "\\ul", 3)) { // underlined - bTextHasStarted = bJustRemovedRTF = TRUE; - if (p1[3] == 'n') - iRemoveChars = 7; - else if (p1[3] == '0') - iRemoveChars = 4; - else - iRemoveChars = 3; - mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[3] != '0' && p1[3] != 'n') ? "%%u" : "%%U"); - } - else if (p1[1] == 'f' && isdigit(p1[2])) { // unicode char - bTextHasStarted = bJustRemovedRTF = TRUE; - iRemoveChars = 2 + ReadInteger(p1 + 2, NULL); - } - else if (!memcmp(p1, "\\tab", 4)) { // tab - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 4; - strcpy(InsertThis, " "); - } - else if (!memcmp(p1, "\\endash", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x93"); - } - else if (!memcmp(p1, "\\emdash", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x94"); - } - else if (!memcmp(p1, "\\lquote", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x98"); - } - else if (!memcmp(p1, "\\rquote", 7)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 7; - strcpy(InsertThis, "\xE2\x80\x99"); - } - else if (!memcmp(p1, "\\ldblquote", 10)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 10; - strcpy(InsertThis, "\xe2\x80\x9c"); - } - else if (!memcmp(p1, "\\rdblquote", 10)) { - bTextHasStarted = TRUE; - bJustRemovedRTF = TRUE; - iRemoveChars = 10; - strcpy(InsertThis, "\xe2\x80\x9d"); - } - else if (p1[1] == '\\' || p1[1] == '{' || p1[1] == '}') { // escaped characters - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 2; - mir_snprintf(InsertThis, SIZEOF(InsertThis), "%c", p1[1]); - } - else if (p1[1] == '~') { // non-breaking space - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 2; - strcpy(InsertThis, "\xC2\xA0"); - } - else if (p1[1] == '\'') { // special character - char tmp[4], *p3 = tmp; - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - if (p1[2] != ' ' && p1[2] != '\\') { - *p3++ = p1[2]; - iRemoveChars = 3; - if (p1[3] != ' ' && p1[3] != '\\') { - *p3++ = p1[3]; - iRemoveChars++; - } - *p3 = 0; - sscanf(tmp, "%x", InsertThis); - - InsertThis[1] = 0; - } - else iRemoveChars = 2; - } - else if (bJustRemovedRTF) { // remove unknown RTF command - int j = 1; - bJustRemovedRTF = TRUE; - while (p1[j] != ' ' && p1[j] != '\\' && p1[j] != '\0') - j++; - iRemoveChars = j; - } - break; - - case '{': // other RTF control characters - case '}': - iRemoveChars = 1; - break; - - case '\r': case '\n': - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 1; - break; - - case '%': // escape chat -> protocol control character - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - iRemoveChars = 1; - strcpy(InsertThis, "%%"); - break; - case ' ': // remove spaces following a RTF command - if (bJustRemovedRTF) - iRemoveChars = 1; - bJustRemovedRTF = FALSE; - bTextHasStarted = TRUE; - break; - - default: // other text that should not be touched - bTextHasStarted = TRUE; - bJustRemovedRTF = FALSE; - break; - } - - // move the memory and paste in new commands instead of the old RTF - if (InsertThis[0] || iRemoveChars) { - size_t len = strlen(InsertThis); - memmove(p1 + len, p1 + iRemoveChars, strlen(p1) - iRemoveChars + 1); - memcpy(p1, InsertThis, len); - p1 += len; - } - else p1++; - } - - mir_free(pIndex); - - return mir_utf8decodeW(pszText); -} - static DWORD CALLBACK Message_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb) { static DWORD dwRead; diff --git a/src/core/stdchat/src/window.cpp b/src/core/stdchat/src/window.cpp index 340ddcbe58..87309e530c 100644 --- a/src/core/stdchat/src/window.cpp +++ b/src/core/stdchat/src/window.cpp @@ -2366,20 +2366,22 @@ LABEL_SHOWWINDOW: case IDOK: if (IsWindowEnabled(GetDlgItem(hwndDlg, IDOK))) { - char *pszRtf = Message_GetFromStream(hwndDlg, si); + ptrA pszRtf(Message_GetFromStream(hwndDlg, si)); if (pszRtf == NULL) break; + + MODULEINFO *mi = pci->MM_FindModule(si->pszModule); + if (mi == NULL) + break; + pci->SM_AddCommand(si->ptszID, si->pszModule, pszRtf); - TCHAR *ptszText = DoRtfToTags(pszRtf, si); - TCHAR *p1 = _tcschr(ptszText, '\0'); - //remove trailing linebreaks - while (p1 > ptszText && (*p1 == '\0' || *p1 == '\r' || *p1 == '\n')) { - *p1 = '\0'; - p1--; - } + CMString ptszText(ptrT(mir_utf8decodeT(pszRtf))); + pci->DoRtfToTags(ptszText, mi->nColorCount, mi->crColors); + ptszText.Trim(); + ptszText.Replace(_T("%"), _T("%%")); - if (pci->MM_FindModule(si->pszModule)->bAckMsg) { + if (mi->bAckMsg) { EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), FALSE); SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, TRUE, 0); } @@ -2388,8 +2390,7 @@ LABEL_SHOWWINDOW: EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, 0); - mir_free(pszRtf); - mir_free(ptszText); + SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE)); } break; @@ -2452,9 +2453,8 @@ LABEL_SHOWWINDOW: break; case IDC_CHANMGR: - if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHANMGR))) - break; - pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, 0); + if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHANMGR))) + pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, 0); break; case IDC_FILTER: diff --git a/src/miranda32_10.vcxproj b/src/miranda32_10.vcxproj index 67b3612aa2..379307f8d3 100644 --- a/src/miranda32_10.vcxproj +++ b/src/miranda32_10.vcxproj @@ -295,6 +295,9 @@ ..\..\core\commonheaders.h + + ..\..\core\commonheaders.h + ..\..\core\commonheaders.h diff --git a/src/miranda32_10.vcxproj.filters b/src/miranda32_10.vcxproj.filters index 936cf562b1..84c3432d81 100644 --- a/src/miranda32_10.vcxproj.filters +++ b/src/miranda32_10.vcxproj.filters @@ -627,6 +627,9 @@ Modules\chat + + Modules\chat + diff --git a/src/miranda32_12.vcxproj b/src/miranda32_12.vcxproj index 7fb98bfb35..4fac9eb9df 100644 --- a/src/miranda32_12.vcxproj +++ b/src/miranda32_12.vcxproj @@ -302,6 +302,12 @@ ..\..\core\commonheaders.h + + ..\..\core\commonheaders.h + ..\..\core\commonheaders.h + ..\..\core\commonheaders.h + ..\..\core\commonheaders.h + ..\..\core\commonheaders.h diff --git a/src/miranda32_12.vcxproj.filters b/src/miranda32_12.vcxproj.filters index ad9071c053..c4857ab820 100644 --- a/src/miranda32_12.vcxproj.filters +++ b/src/miranda32_12.vcxproj.filters @@ -636,6 +636,9 @@ Modules\chat + + Modules\chat + diff --git a/src/modules/chat/chat.h b/src/modules/chat/chat.h index f393d629b3..a84ed5cf54 100644 --- a/src/modules/chat/chat.h +++ b/src/modules/chat/chat.h @@ -87,6 +87,7 @@ int LoadChatModule(void); void UnloadChatModule(void); // tools.c +int DoRtfToTags(CMString &pszText, int iNumColors, COLORREF *pColors); int GetTextPixelSize(TCHAR* pszText, HFONT hFont, BOOL bWidth); TCHAR *RemoveFormatting(const TCHAR* pszText); BOOL DoSoundsFlashPopupTrayStuff(SESSION_INFO *si, GCEVENT *gce, BOOL bHighlight, int bManyFix); @@ -96,7 +97,7 @@ int GetRichTextLength(HWND hwnd); BOOL IsHighlighted(SESSION_INFO *si, GCEVENT *pszText); UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO *si, TCHAR* pszUID, TCHAR* pszWordText); void DestroyGCMenu(HMENU *hMenu, int iIndex); -BOOL DoEventHookAsync(HWND hwnd, const TCHAR *pszID, const char *pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, INT_PTR dwItem); +BOOL DoEventHookAsync(HWND hwnd, const TCHAR *pszID, const char *pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, INT_PTR dwItem); BOOL DoEventHook(const TCHAR *pszID, const char *pszModule, int iType, const TCHAR *pszUID, const TCHAR* pszText, INT_PTR dwItem); BOOL IsEventSupported(int eventType); BOOL LogToFile(SESSION_INFO *si, GCEVENT *gce); diff --git a/src/modules/chat/chat_rtf.cpp b/src/modules/chat/chat_rtf.cpp new file mode 100644 index 0000000000..0758f8bff3 --- /dev/null +++ b/src/modules/chat/chat_rtf.cpp @@ -0,0 +1,206 @@ +/* +Chat module plugin for Miranda IM + +Copyright 2000-12 Miranda IM, 2012-15 Miranda NG 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 "..\..\core\commonheaders.h" + +#include "chat.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// convert rich edit code to bbcode (if wanted). Otherwise, strip all RTF formatting +// tags and return plain text + +static TCHAR tszRtfBreaks[] = _T(" \\\n\r"); + +static void CreateColorMap(CMString &Text, int iCount, COLORREF *pSrc, int *pDst) +{ + const TCHAR *pszText = Text; + int iIndex = 1, i = 0; + + static const TCHAR *lpszFmt = _T("\\red%[^ \x5b\\]\\green%[^ \x5b\\]\\blue%[^ \x5b;];"); + TCHAR szRed[10], szGreen[10], szBlue[10]; + + const TCHAR *p1 = _tcsstr(pszText, _T("\\colortbl")); + if (!p1) + return; + + const TCHAR *pEnd = _tcschr(p1, '}'); + + const TCHAR *p2 = _tcsstr(p1, _T("\\red")); + + for (i = 0; i < iCount; i++) + pDst[i] = -1; + + while (p2 && p2 < pEnd) { + if (_stscanf(p2, lpszFmt, &szRed, &szGreen, &szBlue) > 0) { + for (int i = 0; i < iCount; i++) { + if (pSrc[i] == RGB(_ttoi(szRed), _ttoi(szGreen), _ttoi(szBlue))) + pDst[i] = iIndex; + } + } + iIndex++; + p1 = p2; + p1++; + + p2 = _tcsstr(p1, _T("\\red")); + } +} + +static int GetRtfIndex(int iCol, int iCount, int *pIndex) +{ + for (int i = 0; i < iCount; i++) + if (pIndex[i] == iCol) + return i; + + return -1; +} + +int DoRtfToTags(CMString &pszText, int iNumColors, COLORREF *pColors) +{ + if (pszText.IsEmpty()) + return FALSE; + + // create an index of colors in the module and map them to + // corresponding colors in the RTF color table + int *pIndex = (int*)_alloca(iNumColors * sizeof(int)); + CreateColorMap(pszText, iNumColors, pColors, pIndex); + + // scan the file for rtf commands and remove or parse them + int idx = pszText.Find(_T("\\pard")); + if (idx == -1) { + if ((idx = pszText.Find(_T("\\ltrpar"))) == -1) + return FALSE; + idx += 7; + } + else idx += 5; + + bool bInsideColor = false, bInsideUl = false; + CMString res; + + // iterate through all characters, if rtf control character found then take action + for (const TCHAR *p = pszText.GetString() + idx; *p;) { + switch (*p) { + case '\\': + if (p[1] == '\\' || p[1] == '{' || p[1] == '}') { // escaped characters + res.AppendChar(p[1]); + p += 2; break; + } + if (p[1] == '~') { // non-breaking space + res.AppendChar(0xA0); + p += 2; break; + } + + if (!_tcsncmp(p, _T("\\cf"), 3)) { // foreground color + int iCol = _ttoi(p + 3); + int iInd = GetRtfIndex(iCol, iNumColors, pIndex); + bInsideColor = iInd > 0; + } + else if (!_tcsncmp(p, _T("\\highlight"), 10)) { //background color + TCHAR szTemp[20]; + int iCol = _ttoi(p + 10); + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%d"), iCol); + } + else if (!_tcsncmp(p, _T("\\line"), 5)) { // soft line break; + res.AppendChar('\n'); + } + else if (!_tcsncmp(p, _T("\\endash"), 7)) { + res.AppendChar(0x2013); + } + else if (!_tcsncmp(p, _T("\\emdash"), 7)) { + res.AppendChar(0x2014); + } + else if (!_tcsncmp(p, _T("\\bullet"), 7)) { + res.AppendChar(0x2022); + } + else if (!_tcsncmp(p, _T("\\ldblquote"), 10)) { + res.AppendChar(0x201C); + } + else if (!_tcsncmp(p, _T("\\rdblquote"), 10)) { + res.AppendChar(0x201D); + } + else if (!_tcsncmp(p, _T("\\lquote"), 7)) { + res.AppendChar(0x2018); + } + else if (!_tcsncmp(p, _T("\\rquote"), 7)) { + res.AppendChar(0x2019); + } + else if (!_tcsncmp(p, _T("\\b"), 2)) { //bold + res.Append((p[2] != '0') ? _T("[b]") : _T("[/b]")); + } + else if (!_tcsncmp(p, _T("\\i"), 2)) { // italics + res.Append((p[2] != '0') ? _T("[i]") : _T("[/i]")); + } + else if (!_tcsncmp(p, _T("\\strike"), 7)) { // strike-out + res.Append((p[7] != '0') ? _T("[s]") : _T("[/s]")); + } + else if (!_tcsncmp(p, _T("\\ul"), 3)) { // underlined + if (p[3] == 0 || _tcschr(tszRtfBreaks, p[3])) { + res.Append(_T("[u]")); + bInsideUl = true; + } + else if (!_tcsnccmp(p + 3, _T("none"), 4)) { + if (bInsideUl) + res.Append(_T("[/u]")); + bInsideUl = false; + } + } + else if (!_tcsncmp(p, _T("\\tab"), 4)) { // tab + res.AppendChar('\t'); + } + else if (p[1] == '\'') { // special character + if (p[2] != ' ' && p[2] != '\\') { + TCHAR tmp[10]; + + if (p[3] != ' ' && p[3] != '\\') { + _tcsncpy(tmp, p + 2, 3); + tmp[3] = 0; + } + else { + _tcsncpy(tmp, p + 2, 2); + tmp[2] = 0; + } + + // convert string containing char in hex format to int. + TCHAR *stoppedHere; + res.AppendChar(_tcstol(tmp, &stoppedHere, 16)); + } + } + + p++; // skip initial slash + p += _tcscspn(p, tszRtfBreaks); + if (*p == ' ') + p++; + break; + + case '{': // other RTF control characters + case '}': + p++; + break; + + default: // other text that should not be touched + res.AppendChar(*p++); + break; + } + } + + pszText = res; + return TRUE; +} diff --git a/src/modules/chat/manager.cpp b/src/modules/chat/manager.cpp index 7f59dd5f36..ca28cad9b6 100644 --- a/src/modules/chat/manager.cpp +++ b/src/modules/chat/manager.cpp @@ -1296,6 +1296,7 @@ INT_PTR SvcGetChatManager(WPARAM wParam, LPARAM lParam) ci.SetAllOffline = SetAllOffline; ci.AddEvent = AddEvent; ci.FindRoom = FindRoom; + ci.DoRtfToTags = DoRtfToTags; ci.Log_CreateRTF = Log_CreateRTF; ci.Log_CreateRtfHeader = Log_CreateRtfHeader; diff --git a/src/modules/chat/tools.cpp b/src/modules/chat/tools.cpp index 9fb25f75e8..6f06421591 100644 --- a/src/modules/chat/tools.cpp +++ b/src/modules/chat/tools.cpp @@ -607,7 +607,7 @@ BOOL LogToFile(SESSION_INFO *si, GCEVENT *gce) return TRUE; } -BOOL DoEventHookAsync(HWND hwnd, const TCHAR *pszID, const char *pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, INT_PTR dwItem) +BOOL DoEventHookAsync(HWND hwnd, const TCHAR *pszID, const char *pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, INT_PTR dwItem) { SESSION_INFO *si = ci.SM_FindSession(pszID, pszModule); if (si == NULL) -- cgit v1.2.3