PageRenderTime 79ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/miranda/plugins/tabsrmm/src/msglog.cpp

http://miranda.googlecode.com/
C++ | 1621 lines | 1376 code | 153 blank | 92 comment | 411 complexity | 0faaacae41faec7e0aa92d11e6b59549 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, LGPL-2.1
  1. /*
  2. * astyle --force-indent=tab=4 --brackets=linux --indent-switches
  3. * --pad=oper --one-line=keep-blocks --unpad=paren
  4. *
  5. * Miranda IM: the free IM client for Microsoft* Windows*
  6. *
  7. * Copyright 2000-2009 Miranda ICQ/IM project,
  8. * all portions of this codebase are copyrighted to the people
  9. * listed in contributors.txt.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 2
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * you should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  24. *
  25. * part of tabSRMM messaging plugin for Miranda.
  26. *
  27. * (C) 2005-2014 by silvercircle _at_ gmail _dot_ com and contributors
  28. *
  29. * $Id: msglog.cpp 14454 2014-01-10 16:38:59Z rainwater $
  30. *
  31. * implements the richedit based message log and the template parser
  32. *
  33. */
  34. #include "commonheaders.h"
  35. #include <mbstring.h>
  36. #pragma hdrstop
  37. extern void ReleaseRichEditOle(IRichEditOle *ole);
  38. extern void ImageDataInsertBitmap(IRichEditOle *ole, HBITMAP hBm);
  39. extern int CacheIconToBMP(struct TLogIcon *theIcon, HICON hIcon, COLORREF backgroundColor, int sizeX, int sizeY);
  40. extern void DeleteCachedIcon(struct TLogIcon *theIcon);
  41. struct TCpTable cpTable[] = {
  42. { 874, _T("Thai") },
  43. { 932, _T("Japanese") },
  44. { 936, _T("Simplified Chinese") },
  45. { 949, _T("Korean") },
  46. { 950, _T("Traditional Chinese") },
  47. { 1250, _T("Central European") },
  48. { 1251, _T("Cyrillic") },
  49. { 20866, _T("Cyrillic KOI8-R") },
  50. { 1252, _T("Latin I") },
  51. { 1253, _T("Greek") },
  52. { 1254, _T("Turkish") },
  53. { 1255, _T("Hebrew") },
  54. { 1256, _T("Arabic") },
  55. { 1257, _T("Baltic") },
  56. { 1258, _T("Vietnamese") },
  57. { 1361, _T("Korean (Johab)") },
  58. { -1, NULL}
  59. };
  60. static TCHAR *Template_MakeRelativeDate(struct TWindowData *dat, HANDLE hTimeZone, time_t check, int groupBreak, TCHAR code);
  61. static void ReplaceIcons(HWND hwndDlg, struct TWindowData *dat, LONG startAt, int fAppend, BOOL isSent);
  62. static time_t today;
  63. int g_groupBreak = TRUE;
  64. static TCHAR *szMyName = NULL;
  65. static TCHAR *szYourName = NULL;
  66. static int logPixelSY;
  67. static TCHAR szToday[22], szYesterday[22];
  68. char rtfFontsGlobal[MSGDLGFONTCOUNT + 2][RTFCACHELINESIZE];
  69. char *rtfFonts;
  70. LOGFONTA logfonts[MSGDLGFONTCOUNT + 2];
  71. COLORREF fontcolors[MSGDLGFONTCOUNT + 2];
  72. #define LOGICON_MSG 0
  73. #define LOGICON_URL 1
  74. #define LOGICON_FILE 2
  75. #define LOGICON_OUT 3
  76. #define LOGICON_IN 4
  77. #define LOGICON_STATUS 5
  78. #define LOGICON_ERROR 6
  79. static HICON Logicons[NR_LOGICONS];
  80. #define STREAMSTAGE_HEADER 0
  81. #define STREAMSTAGE_EVENTS 1
  82. #define STREAMSTAGE_TAIL 2
  83. #define STREAMSTAGE_STOP 3
  84. struct LogStreamData {
  85. int stage;
  86. HANDLE hContact;
  87. HANDLE hDbEvent, hDbEventLast;
  88. char *buffer;
  89. int bufferOffset, bufferLen;
  90. int eventsToInsert;
  91. int isEmpty;
  92. int isAppend;
  93. struct TWindowData *dlgDat;
  94. DBEVENTINFO *dbei;
  95. };
  96. __forceinline char *GetRTFFont(DWORD dwIndex)
  97. {
  98. return rtfFonts + (dwIndex * RTFCACHELINESIZE);
  99. }
  100. /*
  101. * remove any empty line at the end of a message to avoid some RichEdit "issues" with
  102. * the highlight code (individual background colors).
  103. * Doesn't touch the message for sure, but empty lines at the end are ugly anyway.
  104. */
  105. static void TrimMessage(TCHAR *msg)
  106. {
  107. size_t iLen = lstrlen(msg) - 1;
  108. size_t i = iLen;
  109. while (i && (msg[i] == '\r' || msg[i] == '\n')) {
  110. i--;
  111. }
  112. if (i < iLen)
  113. msg[i+1] = '\0';
  114. }
  115. void TSAPI CacheLogFonts()
  116. {
  117. int i;
  118. HDC hdc = GetDC(NULL);
  119. logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
  120. ReleaseDC(NULL, hdc);
  121. ZeroMemory((void *)logfonts, sizeof(LOGFONTA) * MSGDLGFONTCOUNT + 2);
  122. for (i = 0; i < MSGDLGFONTCOUNT; i++) {
  123. LoadLogfont(i, &logfonts[i], &fontcolors[i], FONTMODULE);
  124. wsprintfA(rtfFontsGlobal[i], "\\f%u\\cf%u\\b%d\\i%d\\ul%d\\fs%u", i, i, logfonts[i].lfWeight >= FW_BOLD ? 1 : 0, logfonts[i].lfItalic,logfonts[i].lfUnderline, 2 * abs(logfonts[i].lfHeight) * 74 / logPixelSY);
  125. }
  126. wsprintfA(rtfFontsGlobal[MSGDLGFONTCOUNT], "\\f%u\\cf%u\\b%d\\i%d\\fs%u", MSGDLGFONTCOUNT, MSGDLGFONTCOUNT, 0, 0, 0);
  127. _tcsncpy(szToday, CTranslator::get(CTranslator::GEN_LOG_TODAY), 20);
  128. _tcsncpy(szYesterday, CTranslator::get(CTranslator::GEN_LOG_YESTERDAY), 20);
  129. szToday[19] = szYesterday[19] = 0;
  130. /*
  131. * cache/create the info panel fonts
  132. */
  133. COLORREF clr;
  134. LOGFONTA lf;
  135. for (i = 0; i < IPFONTCOUNT; i++) {
  136. if (CInfoPanel::m_ipConfig.hFonts[i])
  137. DeleteObject(CInfoPanel::m_ipConfig.hFonts[i]);
  138. LoadLogfont(i + 100, &lf, &clr, FONTMODULE);
  139. //lf.lfHeight =-MulDiv(lf.lfHeight, logPixelSY, 72);
  140. lf.lfUnderline = 0;
  141. CInfoPanel::m_ipConfig.hFonts[i] = CreateFontIndirectA(&lf);
  142. CInfoPanel::m_ipConfig.clrs[i] = clr;
  143. }
  144. hdc = GetDC(PluginConfig.g_hwndHotkeyHandler);
  145. HFONT hOldFont = (HFONT)SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_NICK]);
  146. SIZE sz;
  147. GetTextExtentPoint32(hdc, _T("WMA"), 3, &sz);
  148. CInfoPanel::m_ipConfig.height1 = sz.cy;
  149. SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_UIN]);
  150. GetTextExtentPoint32(hdc, _T("WMA"), 3, &sz);
  151. CInfoPanel::m_ipConfig.height2 = sz.cy;
  152. SelectObject(hdc, hOldFont);
  153. ReleaseDC(PluginConfig.g_hwndHotkeyHandler, hdc);
  154. PluginConfig.hFontCaption = CInfoPanel::m_ipConfig.hFonts[IPFONTCOUNT - 1];
  155. PluginConfig.crIncoming = M->GetDword(FONTMODULE, "inbg", SRMSGDEFSET_BKGINCOLOUR);
  156. PluginConfig.crOutgoing = M->GetDword(FONTMODULE, "outbg", SRMSGDEFSET_BKGOUTCOLOUR);
  157. PluginConfig.crStatus = M->GetDword(FONTMODULE, "statbg", SRMSGDEFSET_BKGCOLOUR);
  158. PluginConfig.crOldIncoming = M->GetDword(FONTMODULE, "oldinbg", SRMSGDEFSET_BKGINCOLOUR);
  159. PluginConfig.crOldOutgoing = M->GetDword(FONTMODULE, "oldoutbg", SRMSGDEFSET_BKGOUTCOLOUR);
  160. }
  161. void FreeLogFonts()
  162. {
  163. int i;
  164. for (i = 0; i < IPFONTCOUNT; i++)
  165. if (CInfoPanel::m_ipConfig.hFonts[i])
  166. DeleteObject(CInfoPanel::m_ipConfig.hFonts[i]);
  167. }
  168. void TSAPI CacheMsgLogIcons()
  169. {
  170. Logicons[0] = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
  171. Logicons[1] = LoadSkinnedIcon(SKINICON_EVENT_URL);
  172. Logicons[2] = LoadSkinnedIcon(SKINICON_EVENT_FILE);
  173. Logicons[3] = PluginConfig.g_iconOut;
  174. Logicons[4] = PluginConfig.g_iconIn;
  175. Logicons[5] = PluginConfig.g_iconStatus;
  176. Logicons[6] = PluginConfig.g_iconErr;
  177. }
  178. static int TSAPI GetColorIndex(char *rtffont)
  179. {
  180. char *p;
  181. if ((p = strstr(rtffont, "\\cf")) != NULL)
  182. return atoi(p + 3);
  183. return 0;
  184. }
  185. static void AppendToBuffer(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
  186. {
  187. va_list va;
  188. int charsDone;
  189. va_start(va, fmt);
  190. for (;;) {
  191. charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
  192. if (charsDone >= 0)
  193. break;
  194. *cbBufferAlloced += 1024;
  195. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  196. }
  197. va_end(va);
  198. *cbBufferEnd += charsDone;
  199. }
  200. static int AppendUnicodeToBuffer(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, TCHAR * line, int mode)
  201. {
  202. DWORD textCharsCount = 0;
  203. char *d;
  204. int lineLen = (int)(wcslen(line)) * 9 + 8;
  205. if (*cbBufferEnd + lineLen > *cbBufferAlloced) {
  206. cbBufferAlloced[0] += (lineLen + 1024UL - lineLen % 1024UL);
  207. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  208. }
  209. d = *buffer + *cbBufferEnd;
  210. strcpy(d, "{\\uc1 ");
  211. d += 6;
  212. for (; *line; line++, textCharsCount++) {
  213. if (1) {
  214. if (*line == 127 && line[1] != 0) {
  215. TCHAR code = line[2];
  216. if (((code == '0' || code == '1') && line[3] == ' ') || (line[1] == 'c' && code == 'x')) {
  217. int begin = (code == '1');
  218. switch (line[1]) {
  219. case 'b':
  220. CopyMemory(d, begin ? "\\b " : "\\b0 ", begin ? 3 : 4);
  221. d += (begin ? 3 : 4);
  222. line += 3;
  223. continue;
  224. case 'i':
  225. CopyMemory(d, begin ? "\\i " : "\\i0 ", begin ? 3 : 4);
  226. d += (begin ? 3 : 4);
  227. line += 3;
  228. continue;
  229. case 'u':
  230. CopyMemory(d, begin ? "\\ul " : "\\ul0 ", begin ? 4 : 5);
  231. d += (begin ? 4 : 5);
  232. line += 3;
  233. continue;
  234. case 's':
  235. CopyMemory(d, begin ? "\\strike " : "\\strike0 ", begin ? 8 : 9);
  236. d += (begin ? 8 : 9);
  237. line += 3;
  238. continue;
  239. case 'c':
  240. begin = (code == 'x');
  241. CopyMemory(d, "\\cf", 3);
  242. if (begin) {
  243. d[3] = (char)line[3];
  244. d[4] = (char)line[4];
  245. d[5] = ' ';
  246. } else {
  247. char szTemp[10];
  248. int colindex = GetColorIndex(GetRTFFont(LOWORD(mode) ? (MSGFONTID_MYMSG + (HIWORD(mode) ? 8 : 0)) : (MSGFONTID_YOURMSG + (HIWORD(mode) ? 8 : 0))));
  249. _snprintf(szTemp, 4, "%02d", colindex);
  250. d[3] = szTemp[0];
  251. d[4] = szTemp[1];
  252. d[5] = ' ';
  253. }
  254. d += 6;
  255. line += (begin ? 6 : 3);
  256. continue;
  257. }
  258. }
  259. }
  260. }
  261. if (*line == '\r' && line[1] == '\n') {
  262. CopyMemory(d, "\\line ", 6);
  263. line++;
  264. d += 6;
  265. } else if (*line == '\n') {
  266. CopyMemory(d, "\\line ", 6);
  267. d += 6;
  268. } else if (*line == '\t') {
  269. CopyMemory(d, "\\tab ", 5);
  270. d += 5;
  271. } else if (*line == '\\' || *line == '{' || *line == '}') {
  272. *d++ = '\\';
  273. *d++ = (char) * line;
  274. } else if (*line < 128) {
  275. *d++ = (char) * line;
  276. } else
  277. d += sprintf(d, "\\u%d ?", *line);
  278. }
  279. strcpy(d, "}");
  280. d++;
  281. *cbBufferEnd = (int)(d - *buffer);
  282. return textCharsCount;
  283. }
  284. /*
  285. * same as above but does "\r\n"->"\\par " and "\t"->"\\tab " too
  286. */
  287. static int AppendToBufferWithRTF(int mode, char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
  288. {
  289. va_list va;
  290. int charsDone, i;
  291. va_start(va, fmt);
  292. for (;;) {
  293. charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
  294. if (charsDone >= 0)
  295. break;
  296. *cbBufferAlloced += 1024;
  297. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  298. }
  299. va_end(va);
  300. *cbBufferEnd += charsDone;
  301. for (i = *cbBufferEnd - charsDone; (*buffer)[i]; i++) {
  302. if (1) {
  303. if ((*buffer)[i] == '' && (*buffer)[i + 1] != 0) {
  304. char code = (*buffer)[i + 2];
  305. char tag = (*buffer)[i + 1];
  306. if (((code == '0' || code == '1') && (*buffer)[i + 3] == ' ') || (tag == 'c' && (code == 'x' || code == '0'))) {
  307. int begin = (code == '1');
  308. if (*cbBufferEnd + 5 > *cbBufferAlloced) {
  309. *cbBufferAlloced += 1024;
  310. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  311. }
  312. switch (tag) {
  313. case 'b':
  314. CopyMemory(*buffer + i, begin ? "\\b1 " : "\\b0 ", 4);
  315. continue;
  316. case 'i':
  317. CopyMemory(*buffer + i, begin ? "\\i1 " : "\\i0 ", 4);
  318. continue;
  319. case 'u':
  320. MoveMemory(*buffer + i + 2, *buffer + i + 1, *cbBufferEnd - i);
  321. CopyMemory(*buffer + i, begin ? "\\ul1 " : "\\ul0 ", 5);
  322. *cbBufferEnd += 1;
  323. continue;
  324. case 's':
  325. *cbBufferAlloced += 20;
  326. *buffer = (char *)realloc(*buffer, *cbBufferAlloced);
  327. MoveMemory(*buffer + i + 6, *buffer + i + 1, (*cbBufferEnd - i) + 1);
  328. CopyMemory(*buffer + i, begin ? "\\strike1 " : "\\strike0 ", begin ? 9 : 9);
  329. *cbBufferEnd += 5;
  330. continue;
  331. case 'c':
  332. begin = (code == 'x');
  333. CopyMemory(*buffer + i, "\\cf", 3);
  334. if (begin) {
  335. } else {
  336. char szTemp[10];
  337. int colindex = GetColorIndex(GetRTFFont(LOWORD(mode) ? (MSGFONTID_MYMSG + (HIWORD(mode) ? 8 : 0)) : (MSGFONTID_YOURMSG + (HIWORD(mode) ? 8 : 0))));
  338. _snprintf(szTemp, 4, "%02d", colindex);
  339. (*buffer)[i + 3] = szTemp[0];
  340. (*buffer)[i + 4] = szTemp[1];
  341. }
  342. continue;
  343. }
  344. }
  345. }
  346. }
  347. if ((*buffer)[i] == '\r' && (*buffer)[i + 1] == '\n') {
  348. if (*cbBufferEnd + 5 > *cbBufferAlloced) {
  349. *cbBufferAlloced += 1024;
  350. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  351. }
  352. MoveMemory(*buffer + i + 6, *buffer + i + 2, *cbBufferEnd - i - 1);
  353. CopyMemory(*buffer + i, "\\line ", 6);
  354. *cbBufferEnd += 4;
  355. } else if ((*buffer)[i] == '\n') {
  356. if (*cbBufferEnd + 6 > *cbBufferAlloced) {
  357. *cbBufferAlloced += 1024;
  358. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  359. }
  360. MoveMemory(*buffer + i + 6, *buffer + i + 1, *cbBufferEnd - i);
  361. CopyMemory(*buffer + i, "\\line ", 6);
  362. *cbBufferEnd += 5;
  363. } else if ((*buffer)[i] == '\t') {
  364. if (*cbBufferEnd + 5 > *cbBufferAlloced) {
  365. *cbBufferAlloced += 1024;
  366. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  367. }
  368. MoveMemory(*buffer + i + 5, *buffer + i + 1, *cbBufferEnd - i);
  369. CopyMemory(*buffer + i, "\\tab ", 5);
  370. *cbBufferEnd += 4;
  371. } else if ((*buffer)[i] == '\\' || (*buffer)[i] == '{' || (*buffer)[i] == '}') {
  372. if (*cbBufferEnd + 2 > *cbBufferAlloced) {
  373. *cbBufferAlloced += 1024;
  374. *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
  375. }
  376. MoveMemory(*buffer + i + 1, *buffer + i, *cbBufferEnd - i + 1);
  377. (*buffer)[i] = '\\';
  378. ++*cbBufferEnd;
  379. i++;
  380. }
  381. }
  382. return (int)(_mbslen((unsigned char *)*buffer + *cbBufferEnd));
  383. }
  384. static void Build_RTF_Header(char **buffer, int *bufferEnd, int *bufferAlloced, struct TWindowData *dat)
  385. {
  386. COLORREF colour;
  387. int i;
  388. char szTemp[30];
  389. LOGFONTA* logFonts = dat->pContainer->theme.logFonts;
  390. COLORREF* fontColors = dat->pContainer->theme.fontColors;
  391. TLogTheme *theme = &dat->pContainer->theme;
  392. // rtl
  393. if (dat->dwFlags & MWF_LOG_RTL)
  394. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
  395. else
  396. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
  397. for (i = 0; i < MSGDLGFONTCOUNT; i++)
  398. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\f%u\\fnil\\fcharset%u %s;}", i, logFonts[i].lfCharSet, logFonts[i].lfFaceName);
  399. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\f%u\\fnil\\fcharset%u %s;}", MSGDLGFONTCOUNT, logFonts[i].lfCharSet, "Arial");
  400. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "}{\\colortbl ");
  401. for (i = 0; i < MSGDLGFONTCOUNT; i++)
  402. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(fontColors[i]), GetGValue(fontColors[i]), GetBValue(fontColors[i]));
  403. if (GetSysColorBrush(COLOR_HOTLIGHT) == NULL)
  404. colour = RGB(0, 0, 255);
  405. else
  406. colour = GetSysColor(COLOR_HOTLIGHT);
  407. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  408. /* OnO: Create incoming and outcoming colours */
  409. colour = theme->inbg;
  410. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  411. colour = theme->outbg;
  412. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  413. colour = theme->bg;
  414. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  415. colour = theme->hgrid;
  416. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  417. colour = theme->oldinbg;
  418. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  419. colour = theme->oldoutbg;
  420. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  421. colour = theme->statbg;
  422. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  423. // custom template colors...
  424. for (i = 1; i <= 5; i++) {
  425. _snprintf(szTemp, 10, "cc%d", i);
  426. colour = theme->custom_colors[i - 1];
  427. if (colour == 0)
  428. colour = RGB(1, 1, 1);
  429. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
  430. }
  431. // bbcode colors...
  432. for (i = 0; i < Utils::rtf_ctable_size; i++)
  433. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(Utils::rtf_ctable[i].clr), GetGValue(Utils::rtf_ctable[i].clr), GetBValue(Utils::rtf_ctable[i].clr));
  434. /*
  435. * paragraph header
  436. */
  437. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "}");
  438. /*
  439. * indent:
  440. * real indent is set in msgdialog.c (DM_OPTIONSAPPLIED)
  441. */
  442. if (!(dat->dwFlags & MWF_LOG_INDENT))
  443. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\li%u\\ri%u\\fi%u\\tx%u", 2*15, 2*15, 0, 70 * 15);
  444. }
  445. //free() the return value
  446. static char *CreateRTFHeader(struct TWindowData *dat)
  447. {
  448. char *buffer;
  449. int bufferAlloced, bufferEnd;
  450. bufferEnd = 0;
  451. bufferAlloced = 1024;
  452. buffer = (char *) malloc(bufferAlloced);
  453. buffer[0] = '\0';
  454. Build_RTF_Header(&buffer, &bufferEnd, &bufferAlloced, dat);
  455. return buffer;
  456. }
  457. static void AppendTimeStamp(TCHAR *szFinalTimestamp, int isSent, char **buffer, int *bufferEnd, int *bufferAlloced, int skipFont,
  458. struct TWindowData *dat, int iFontIDOffset)
  459. {
  460. if (skipFont)
  461. AppendUnicodeToBuffer(buffer, bufferEnd, bufferAlloced, szFinalTimestamp, MAKELONG(isSent, dat->isHistory));
  462. else {
  463. AppendToBuffer(buffer, bufferEnd, bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset));
  464. AppendUnicodeToBuffer(buffer, bufferEnd, bufferAlloced, szFinalTimestamp, MAKELONG(isSent, dat->isHistory));
  465. }
  466. }
  467. //free() the return value
  468. static char *CreateRTFTail(struct TWindowData *dat)
  469. {
  470. char *buffer;
  471. int bufferAlloced, bufferEnd;
  472. bufferEnd = 0;
  473. bufferAlloced = 1024;
  474. buffer = (char *) malloc(bufferAlloced);
  475. buffer[0] = '\0';
  476. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}");
  477. return buffer;
  478. }
  479. int TSAPI DbEventIsShown(struct TWindowData *dat, DBEVENTINFO * dbei)
  480. {
  481. int heFlags;
  482. switch (dbei->eventType) {
  483. case EVENTTYPE_MESSAGE:
  484. return 1;
  485. case EVENTTYPE_FILE:
  486. return(dat->dwFlagsEx & MWF_SHOW_FILEEVENTS);
  487. }
  488. if (IsStatusEvent(dbei->eventType))
  489. return 1;
  490. heFlags = HistoryEvents_GetFlags(dbei->eventType);
  491. if (heFlags != -1)
  492. return (heFlags & HISTORYEVENTS_FLAG_SHOW_IM_SRMM) == HISTORYEVENTS_FLAG_SHOW_IM_SRMM;
  493. return 0;
  494. }
  495. static int DbEventIsForMsgWindow(DBEVENTINFO *dbei)
  496. {
  497. DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
  498. return et && ( et->flags & DETF_MSGWINDOW );
  499. }
  500. static char *Template_CreateRTFFromDbEvent(struct TWindowData *dat, HANDLE hContact, HANDLE hDbEvent, int prefixParaBreak, struct LogStreamData *streamData)
  501. {
  502. char *buffer, c;
  503. TCHAR ci, cc;
  504. TCHAR *szFinalTimestamp;
  505. int bufferAlloced, bufferEnd;
  506. size_t iTemplateLen, i = 0;
  507. DBEVENTINFO dbei = { 0 };
  508. int isSent = 0;
  509. int iFontIDOffset = 0;
  510. TCHAR *szTemplate;
  511. HANDLE hTimeZone;
  512. BOOL skipToNext = FALSE, showTime = TRUE, showDate = TRUE, skipFont = FALSE;
  513. struct tm event_time;
  514. TTemplateSet *this_templateset;
  515. BOOL isBold = FALSE, isItalic = FALSE, isUnderline = FALSE;
  516. DWORD dwEffectiveFlags;
  517. DWORD dwFormattingParams = MAKELONG(PluginConfig.m_FormatWholeWordsOnly, 0);
  518. BOOL fIsStatusChangeEvent = FALSE;
  519. TCHAR *msg, *formatted = NULL;
  520. int heFlags = -1;
  521. char *rtfMessage = NULL;
  522. bufferEnd = 0;
  523. bufferAlloced = 1024;
  524. buffer = (char *) malloc(bufferAlloced);
  525. buffer[0] = '\0';
  526. if (streamData->dbei != 0)
  527. dbei = *(streamData->dbei);
  528. else {
  529. dbei.cbSize = sizeof(dbei);
  530. dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM) hDbEvent, 0);
  531. if (dbei.cbBlob == -1) {
  532. free(buffer);
  533. return NULL;
  534. }
  535. dbei.pBlob = (PBYTE) malloc(dbei.cbBlob);
  536. CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
  537. if (!DbEventIsShown(dat, &dbei)) {
  538. free(dbei.pBlob);
  539. free(buffer);
  540. return NULL;
  541. }
  542. }
  543. if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT | DBEF_READ)))
  544. dat->cache->updateStats(TSessionStats::SET_LAST_RCV, lstrlenA((char *) dbei.pBlob));
  545. if (dbei.eventType != EVENTTYPE_MESSAGE && dbei.eventType != EVENTTYPE_FILE && !IsStatusEvent(dbei.eventType))
  546. heFlags = HistoryEvents_GetFlags(dbei.eventType);
  547. if (heFlags & HISTORYEVENTS_FLAG_DEFAULT)
  548. heFlags = -1;
  549. if (heFlags != -1)
  550. rtfMessage = HistoryEvents_GetRichText(hDbEvent, &dbei);
  551. if (rtfMessage == NULL) {
  552. msg = DbGetEventTextT(&dbei, dat->codePage);
  553. if (!msg) {
  554. free(dbei.pBlob);
  555. free(buffer);
  556. return NULL;
  557. }
  558. TrimMessage(msg);
  559. formatted = const_cast<TCHAR *>(Utils::FormatRaw(dat, msg, dwFormattingParams, isSent));
  560. mir_free(msg);
  561. }
  562. fIsStatusChangeEvent = (heFlags != -1 || IsStatusEvent(dbei.eventType));
  563. if (dat->isAutoRTL & 2) { // means: last \\par was deleted to avoid new line at end of log
  564. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
  565. dat->isAutoRTL &= ~2;
  566. }
  567. if (dat->dwFlags & MWF_LOG_RTL)
  568. dbei.flags |= DBEF_RTL;
  569. if (dbei.flags & DBEF_RTL)
  570. dat->isAutoRTL |= 1;
  571. dwEffectiveFlags = dat->dwFlags;
  572. dat->isHistory = (dbei.timestamp < dat->cache->getSessionStart() && (dbei.flags & DBEF_READ || dbei.flags & DBEF_SENT));
  573. iFontIDOffset = dat->isHistory ? 8 : 0; // offset into the font table for either history (old) or new events... (# of fonts per configuration set)
  574. isSent = (dbei.flags & DBEF_SENT);
  575. if (!isSent && (fIsStatusChangeEvent || dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei))) {
  576. CallService(MS_DB_EVENT_MARKREAD, (WPARAM)hContact, (LPARAM)hDbEvent);
  577. CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)hDbEvent);
  578. }
  579. g_groupBreak = TRUE;
  580. if (dwEffectiveFlags & MWF_DIVIDERWANTED) {
  581. static char szStyle_div[128] = "\0";
  582. if (szStyle_div[0] == 0)
  583. mir_snprintf(szStyle_div, 128, "\\f%u\\cf%u\\ul0\\b%d\\i%d\\fs%u", H_MSGFONTID_DIVIDERS, H_MSGFONTID_DIVIDERS, 0, 0, 5);
  584. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", H_MSGFONTID_DIVIDERS, H_MSGFONTID_DIVIDERS);
  585. dat->dwFlags &= ~MWF_DIVIDERWANTED;
  586. }
  587. if (dwEffectiveFlags & MWF_LOG_GROUPMODE && ((dbei.flags & (DBEF_SENT | DBEF_READ | DBEF_RTL)) == LOWORD(dat->iLastEventType)) && dbei.eventType == EVENTTYPE_MESSAGE && HIWORD(dat->iLastEventType) == EVENTTYPE_MESSAGE && (dbei.timestamp - dat->lastEventTime) < 86400) {
  588. g_groupBreak = FALSE;
  589. if ((time_t)dbei.timestamp > today && dat->lastEventTime < today) {
  590. g_groupBreak = TRUE;
  591. }
  592. }
  593. if (!streamData->isEmpty && g_groupBreak && (dwEffectiveFlags & MWF_LOG_GRID))
  594. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", MSGDLGFONTCOUNT + 4, MSGDLGFONTCOUNT + 4);
  595. if (dbei.flags & DBEF_RTL)
  596. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlpar");
  597. else
  598. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrpar");
  599. /* OnO: highlight start */
  600. if(fIsStatusChangeEvent)
  601. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d\\cf%d", MSGDLGFONTCOUNT + 7, MSGDLGFONTCOUNT + 7);
  602. else
  603. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d\\cf%d", MSGDLGFONTCOUNT + (dat->isHistory?5:1) + ((isSent) ? 1 : 0), MSGDLGFONTCOUNT + (dat->isHistory?5:1) + ((isSent) ? 1 : 0));
  604. streamData->isEmpty = FALSE;
  605. if (dat->isAutoRTL & 1) {
  606. if (dbei.flags & DBEF_RTL) {
  607. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrch\\rtlch");
  608. } else {
  609. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlch\\ltrch");
  610. }
  611. }
  612. /*
  613. * templated code starts here
  614. */
  615. if (dwEffectiveFlags & MWF_LOG_SHOWTIME) {
  616. hTimeZone = ((dat->dwFlags & MWF_LOG_LOCALTIME) && !isSent) ? dat->hTimeZone : NULL;
  617. time_t local_time = tmi.timeStampToTimeZoneTimeStamp(hTimeZone, dbei.timestamp);
  618. event_time = *gmtime(&local_time);
  619. }
  620. this_templateset = dbei.flags & DBEF_RTL ? dat->pContainer->rtl_templates : dat->pContainer->ltr_templates;
  621. if (fIsStatusChangeEvent)
  622. szTemplate = this_templateset->szTemplates[TMPL_STATUSCHG];
  623. else if (dbei.eventType == EVENTTYPE_ERRMSG)
  624. szTemplate = this_templateset->szTemplates[TMPL_ERRMSG];
  625. else {
  626. if (dwEffectiveFlags & MWF_LOG_GROUPMODE)
  627. szTemplate = isSent ? (g_groupBreak ? this_templateset->szTemplates[TMPL_GRPSTARTOUT] : this_templateset->szTemplates[TMPL_GRPINNEROUT]) :
  628. (g_groupBreak ? this_templateset->szTemplates[TMPL_GRPSTARTIN] : this_templateset->szTemplates[TMPL_GRPINNERIN]);
  629. else
  630. szTemplate = isSent ? this_templateset->szTemplates[TMPL_MSGOUT] : this_templateset->szTemplates[TMPL_MSGIN];
  631. }
  632. iTemplateLen = lstrlen(szTemplate);
  633. showTime = dwEffectiveFlags & MWF_LOG_SHOWTIME;
  634. showDate = dwEffectiveFlags & MWF_LOG_SHOWDATES;
  635. if (dat->hHistoryEvents) {
  636. if (dat->curHistory == dat->maxHistory) {
  637. MoveMemory(dat->hHistoryEvents, &dat->hHistoryEvents[1], sizeof(HANDLE) * (dat->maxHistory - 1));
  638. dat->curHistory--;
  639. }
  640. dat->hHistoryEvents[dat->curHistory++] = hDbEvent;
  641. }
  642. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ul0\\b0\\i0 ");
  643. while (i < iTemplateLen) {
  644. ci = szTemplate[i];
  645. if (ci == '%') {
  646. cc = szTemplate[i + 1];
  647. skipToNext = FALSE;
  648. skipFont = FALSE;
  649. /*
  650. * handle modifiers
  651. */
  652. while (cc == '#' || cc == '$' || cc == '&' || cc == '?' || cc == '\\') {
  653. switch (cc) {
  654. case '#':
  655. if (!dat->isHistory) {
  656. skipToNext = TRUE;
  657. goto skip;
  658. } else {
  659. i++;
  660. cc = szTemplate[i + 1];
  661. continue;
  662. }
  663. case '$':
  664. if (dat->isHistory) {
  665. skipToNext = TRUE;
  666. goto skip;
  667. } else {
  668. i++;
  669. cc = szTemplate[i + 1];
  670. continue;
  671. }
  672. case '&':
  673. i++;
  674. cc = szTemplate[i + 1];
  675. skipFont = TRUE;
  676. break;
  677. case '?':
  678. if (dwEffectiveFlags & MWF_LOG_NORMALTEMPLATES) {
  679. i++;
  680. cc = szTemplate[i + 1];
  681. continue;
  682. } else {
  683. i++;
  684. skipToNext = TRUE;
  685. goto skip;
  686. }
  687. case '\\':
  688. if (!(dwEffectiveFlags & MWF_LOG_NORMALTEMPLATES)) {
  689. i++;
  690. cc = szTemplate[i + 1];
  691. continue;
  692. } else {
  693. i++;
  694. skipToNext = TRUE;
  695. goto skip;
  696. }
  697. }
  698. }
  699. switch (cc) {
  700. case 'V':
  701. //AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\fs0\\\expnd-40 ~-%d-~", hDbEvent);
  702. break;
  703. case 'I': {
  704. if (dwEffectiveFlags & MWF_LOG_SHOWICONS) {
  705. int icon;
  706. if ((dwEffectiveFlags & MWF_LOG_INOUTICONS) && dbei.eventType == EVENTTYPE_MESSAGE)
  707. icon = isSent ? LOGICON_OUT : LOGICON_IN;
  708. else {
  709. switch (dbei.eventType) {
  710. case EVENTTYPE_FILE:
  711. icon = LOGICON_FILE;
  712. break;
  713. case EVENTTYPE_ERRMSG:
  714. icon = LOGICON_ERROR;
  715. break;
  716. default:
  717. icon = LOGICON_MSG;
  718. break;
  719. }
  720. if (fIsStatusChangeEvent)
  721. icon = LOGICON_STATUS;
  722. }
  723. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s\\fs1 #~#%01d%c%s ", GetRTFFont(MSGFONTID_SYMBOLS_IN), icon, isSent ? '>' : '<', GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
  724. } else
  725. skipToNext = TRUE;
  726. break;
  727. }
  728. case 'D': // long date
  729. if (showTime && showDate) {
  730. szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, (TCHAR)'D');
  731. AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
  732. } else
  733. skipToNext = TRUE;
  734. break;
  735. case 'E': // short date...
  736. if (showTime && showDate) {
  737. szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, (TCHAR)'E');
  738. AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
  739. } else
  740. skipToNext = TRUE;
  741. break;
  742. case 'a': // 12 hour
  743. case 'h': // 24 hour
  744. if (showTime) {
  745. if (skipFont)
  746. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, cc == 'h' ? "%02d" : "%2d", cc == 'h' ? event_time.tm_hour : (event_time.tm_hour > 12 ? event_time.tm_hour - 12 : event_time.tm_hour));
  747. else
  748. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, cc == 'h' ? "%s %02d" : "%s %2d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), cc == 'h' ? event_time.tm_hour : (event_time.tm_hour > 12 ? event_time.tm_hour - 12 : event_time.tm_hour));
  749. } else
  750. skipToNext = TRUE;
  751. break;
  752. case 'm': // minute
  753. if (showTime) {
  754. if (skipFont)
  755. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_min);
  756. else
  757. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_min);
  758. } else
  759. skipToNext = TRUE;
  760. break;
  761. case 's': //second
  762. if (showTime && dwEffectiveFlags & MWF_LOG_SHOWSECONDS) {
  763. if (skipFont)
  764. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_sec);
  765. else
  766. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_sec);
  767. } else
  768. skipToNext = TRUE;
  769. break;
  770. case 'p': // am/pm symbol
  771. if (showTime) {
  772. if (skipFont)
  773. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s", event_time.tm_hour > 11 ? "PM" : "AM");
  774. else
  775. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %s", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_hour > 11 ? "PM" : "AM");
  776. } else
  777. skipToNext = TRUE;
  778. break;
  779. case 'o': // month
  780. if (showTime && showDate) {
  781. if (skipFont)
  782. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_mon + 1);
  783. else
  784. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_mon + 1);
  785. } else
  786. skipToNext = TRUE;
  787. break;
  788. case'O': // month (name)
  789. if (showTime && showDate) {
  790. if (skipFont)
  791. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getMonth(event_time.tm_mon)),
  792. MAKELONG(isSent, dat->isHistory));
  793. else {
  794. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset));
  795. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getMonth(event_time.tm_mon)),
  796. MAKELONG(isSent, dat->isHistory));
  797. }
  798. } else
  799. skipToNext = TRUE;
  800. break;
  801. case 'd': // day of month
  802. if (showTime && showDate) {
  803. if (skipFont)
  804. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_mday);
  805. else
  806. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_mday);
  807. } else
  808. skipToNext = TRUE;
  809. break;
  810. case 'w': // day of week
  811. if (showTime && showDate) {
  812. if (skipFont)
  813. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getWeekday(event_time.tm_wday)), MAKELONG(isSent, dat->isHistory));
  814. else {
  815. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset));
  816. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getWeekday(event_time.tm_wday)), MAKELONG(isSent, dat->isHistory));
  817. }
  818. } else
  819. skipToNext = TRUE;
  820. break;
  821. case 'y': // year
  822. if (showTime && showDate) {
  823. if (skipFont)
  824. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%04d", event_time.tm_year + 1900);
  825. else
  826. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %04d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_year + 1900);
  827. } else
  828. skipToNext = TRUE;
  829. break;
  830. case 'R':
  831. case 'r': // long date
  832. if (showTime && showDate) {
  833. szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, cc);
  834. AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
  835. } else
  836. skipToNext = TRUE;
  837. break;
  838. case 't':
  839. case 'T':
  840. if (showTime) {
  841. szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, (TCHAR)((dwEffectiveFlags & MWF_LOG_SHOWSECONDS) ? cc : (TCHAR)'t'));
  842. AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
  843. } else
  844. skipToNext = TRUE;
  845. break;
  846. case 'S': { // symbol
  847. if (dwEffectiveFlags & MWF_LOG_SYMBOLS) {
  848. if ((dwEffectiveFlags & MWF_LOG_INOUTICONS) && dbei.eventType == EVENTTYPE_MESSAGE)
  849. c = isSent ? 0x37 : 0x38;
  850. else {
  851. switch (dbei.eventType) {
  852. case EVENTTYPE_MESSAGE:
  853. c = (char)0xaa;
  854. break;
  855. case EVENTTYPE_FILE:
  856. c = (char)0xcd;
  857. break;
  858. case EVENTTYPE_ERRMSG:
  859. c = (char)0x72;;
  860. break;
  861. default:
  862. c = (char)0xaa;
  863. break;
  864. }
  865. if (fIsStatusChangeEvent)
  866. c = 0x4e;
  867. }
  868. if (skipFont)
  869. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%c%s ", c, GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
  870. else
  871. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %c%s ", isSent ? GetRTFFont(MSGFONTID_SYMBOLS_OUT) : GetRTFFont(MSGFONTID_SYMBOLS_IN), c, GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
  872. } else
  873. skipToNext = TRUE;
  874. break;
  875. }
  876. case 'n': // hard line break
  877. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, dbei.flags & DBEF_RTL ? "\\rtlpar\\par\\rtlpar" : "\\par\\ltrpar");
  878. break;
  879. case 'l': // soft line break
  880. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\line");
  881. break;
  882. case 'N': { // nickname
  883. if (heFlags != -1 && !(heFlags & HISTORYEVENTS_FLAG_EXPECT_CONTACT_NAME_BEFORE))
  884. break;
  885. if (!skipFont)
  886. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset));
  887. if (isSent)
  888. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, szMyName, MAKELONG(isSent, dat->isHistory));
  889. else
  890. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, szYourName, MAKELONG(isSent, dat->isHistory));
  891. break;
  892. }
  893. case 'U': // UIN
  894. if (!skipFont)
  895. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset));
  896. if(!isSent)
  897. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, (wchar_t *)dat->cache->getUIN(), MAKELONG(isSent, dat->isHistory));
  898. else
  899. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, (wchar_t *)dat->myUin, MAKELONG(isSent, dat->isHistory));
  900. break;
  901. case 'e': // error message
  902. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(MSGFONTID_ERROR));
  903. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, (wchar_t *)dbei.szModule, MAKELONG(isSent, dat->isHistory));
  904. break;
  905. case 'M': { // message
  906. if (fIsStatusChangeEvent)
  907. dbei.eventType = EVENTTYPE_STATUSCHANGE;
  908. switch (dbei.eventType) {
  909. case EVENTTYPE_MESSAGE:
  910. case EVENTTYPE_ERRMSG:
  911. case EVENTTYPE_STATUSCHANGE: {
  912. if (fIsStatusChangeEvent || dbei.eventType == EVENTTYPE_ERRMSG) {
  913. if (dbei.eventType == EVENTTYPE_ERRMSG && dbei.cbBlob == 0)
  914. break;
  915. if (dbei.eventType == EVENTTYPE_ERRMSG) {
  916. if (!skipFont)
  917. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\line%s ", GetRTFFont(fIsStatusChangeEvent ? H_MSGFONTID_STATUSCHANGES : MSGFONTID_MYMSG));
  918. else
  919. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\line ");
  920. } else {
  921. if (!skipFont)
  922. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(fIsStatusChangeEvent ? H_MSGFONTID_STATUSCHANGES : MSGFONTID_MYMSG));
  923. }
  924. } else {
  925. if (!skipFont)
  926. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
  927. }
  928. if (rtfMessage != NULL) {
  929. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s", rtfMessage);
  930. } else {
  931. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, formatted, MAKELONG(isSent, dat->isHistory));
  932. }
  933. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s", "\\b0\\ul0\\i0 ");
  934. break;
  935. }
  936. case EVENTTYPE_FILE:
  937. if (!skipFont)
  938. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYMISC + iFontIDOffset : MSGFONTID_YOURMISC + iFontIDOffset));
  939. {
  940. char* szFileName = (char *)dbei.pBlob + sizeof(DWORD);
  941. char* szDescr = szFileName + lstrlenA(szFileName) + 1;
  942. TCHAR* tszFileName = DbGetEventStringT( &dbei, szFileName );
  943. if ( *szDescr != 0 ) {
  944. TCHAR* tszDescr = DbGetEventStringT( &dbei, szDescr );
  945. TCHAR buf[1000];
  946. mir_sntprintf( buf, SIZEOF(buf), _T("%s (%s)"), tszFileName, tszDescr );
  947. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, buf, 0 );
  948. mir_free( tszDescr );
  949. }
  950. else {
  951. AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, tszFileName, 0 );
  952. }
  953. mir_free( tszFileName );
  954. }
  955. break;
  956. }
  957. break;
  958. }
  959. case '*': // bold
  960. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, isBold ? "\\b0 " : "\\b ");
  961. isBold = !isBold;
  962. break;
  963. case '/': // italic
  964. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, isItalic ? "\\i0 " : "\\i ");
  965. isItalic = !isItalic;
  966. break;
  967. case '_': // italic
  968. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, isUnderline ? "\\ul0 " : "\\ul ");
  969. isUnderline = !isUnderline;
  970. break;
  971. case '-': { // grid line
  972. TCHAR color = szTemplate[i + 2];
  973. if (color >= '0' && color <= '4') {
  974. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", MSGDLGFONTCOUNT + 8 + (color - '0'), MSGDLGFONTCOUNT + 7 + (color - '0'));
  975. i++;
  976. } else {
  977. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", MSGDLGFONTCOUNT + 4, MSGDLGFONTCOUNT + 4);
  978. }
  979. break;
  980. }
  981. case '~': // font break (switch to default font...)
  982. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
  983. break;
  984. case 'H': { // highlight
  985. TCHAR color = szTemplate[i + 2];
  986. if (color >= '0' && color <= '4') {
  987. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d", MSGDLGFONTCOUNT + 8 + (color - '0'));
  988. i++;
  989. } else
  990. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d", (MSGDLGFONTCOUNT + (dat->isHistory?5:1) + ((isSent) ? 1 : 0)));
  991. break;
  992. }
  993. case '|': // tab
  994. if (dwEffectiveFlags & MWF_LOG_INDENT)
  995. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\tab");
  996. else
  997. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " ");
  998. break;
  999. case 'f': { // font tag...
  1000. TCHAR code = szTemplate[i + 2];
  1001. int fontindex = -1;
  1002. switch (code) {
  1003. case 'd':
  1004. fontindex = isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset;
  1005. break;
  1006. case 'n':
  1007. fontindex = isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset;
  1008. break;
  1009. case 'm':
  1010. fontindex = isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset;
  1011. break;
  1012. case 'M':
  1013. fontindex = isSent ? MSGFONTID_MYMISC + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset;
  1014. break;
  1015. case 's':
  1016. fontindex = isSent ? MSGFONTID_SYMBOLS_OUT : MSGFONTID_SYMBOLS_IN;
  1017. break;
  1018. }
  1019. if (fontindex != -1) {
  1020. i++;
  1021. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(fontindex));
  1022. } else
  1023. skipToNext = TRUE;
  1024. break;
  1025. }
  1026. case 'c': { // font color (using one of the predefined 5 colors) or one of the standard font colors (m = message, d = date/time, n = nick)
  1027. TCHAR color = szTemplate[i + 2];
  1028. if (color >= '0' && color <= '4') {
  1029. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", MSGDLGFONTCOUNT + 8 + (color - '0'));
  1030. i++;
  1031. } else if (color == (TCHAR)'d') {
  1032. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset);
  1033. i++;
  1034. } else if (color == (TCHAR)'m') {
  1035. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset);
  1036. i++;
  1037. } else if (color == (TCHAR)'n') {
  1038. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset);
  1039. i++;
  1040. } else if (color == (TCHAR)'s') {
  1041. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_SYMBOLS_OUT : MSGFONTID_SYMBOLS_IN);
  1042. i++;
  1043. } else
  1044. skipToNext = TRUE;
  1045. break;
  1046. }
  1047. case '<': // bidi tag
  1048. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlmark\\rtlch ");
  1049. break;
  1050. case '>': // bidi tag
  1051. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrmark\\ltrch ");
  1052. break;
  1053. }
  1054. skip:
  1055. if (skipToNext) {
  1056. i++;
  1057. while (szTemplate[i] != '%' && i < iTemplateLen) i++;
  1058. } else
  1059. i += 2;
  1060. } else {
  1061. char temp[24];
  1062. mir_snprintf(temp, 24, "{\\uc1\\u%d?}", (int)ci);
  1063. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, temp);
  1064. i++;
  1065. }
  1066. }
  1067. if (dat->hHistoryEvents)
  1068. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, dat->szMicroLf, MSGDLGFONTCOUNT + 1 + ((isSent) ? 1 : 0), hDbEvent);
  1069. AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
  1070. if (streamData->dbei == 0)
  1071. free(dbei.pBlob);
  1072. HistoryEvents_ReleaseText(rtfMessage);
  1073. dat->iLastEventType = MAKELONG((dbei.flags & (DBEF_SENT | DBEF_READ | DBEF_RTL)), dbei.eventType);
  1074. dat->lastEventTime = dbei.timestamp;
  1075. return buffer;
  1076. }
  1077. static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
  1078. {
  1079. struct LogStreamData *dat = (struct LogStreamData *) dwCookie;
  1080. if (dat->buffer == NULL) {
  1081. dat->bufferOffset = 0;
  1082. switch (dat->stage) {
  1083. case STREAMSTAGE_HEADER:
  1084. if (dat->buffer) free(dat->buffer);
  1085. dat->buffer = CreateRTFHeader(dat->dlgDat);
  1086. dat->stage = STREAMSTAGE_EVENTS;
  1087. break;
  1088. case STREAMSTAGE_EVENTS:
  1089. if (dat->eventsToInsert) {
  1090. do {
  1091. if (dat->buffer) free(dat->buffer);
  1092. dat->buffer = Template_CreateRTFFromDbEvent(dat->dlgDat, dat->hContact, dat->hDbEvent, !dat->isEmpty, dat);
  1093. if (dat->buffer)
  1094. dat->hDbEventLast = dat->hDbEvent;
  1095. dat->hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) dat->hDbEvent, 0);
  1096. if (--dat->eventsToInsert == 0)
  1097. break;
  1098. } while (dat->buffer == NULL && dat->hDbEvent);
  1099. if (dat->buffer) {
  1100. //dat->isEmpty = 0;
  1101. break;
  1102. }
  1103. }
  1104. dat->stage = STREAMSTAGE_TAIL;
  1105. //fall through
  1106. case STREAMSTAGE_TAIL: {
  1107. if (dat->buffer) free(dat->buffer);
  1108. dat->buffer = CreateRTFTail(dat->dlgDat);
  1109. dat->stage = STREAMSTAGE_STOP;
  1110. break;
  1111. }
  1112. case STREAMSTAGE_STOP:
  1113. *pcb = 0;
  1114. return 0;
  1115. }
  1116. dat->bufferLen = lstrlenA(dat->buffer);
  1117. }
  1118. *pcb = min(cb, dat->bufferLen - dat->bufferOffset);
  1119. CopyMemory(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
  1120. dat->bufferOffset += *pcb;
  1121. if (dat->bufferOffset == dat->bufferLen) {
  1122. free(dat->buffer);
  1123. dat->buffer = NULL;
  1124. }
  1125. return 0;
  1126. }
  1127. static void SetupLogFormatting(struct TWindowData *dat)
  1128. {
  1129. if (dat->hHistoryEvents) {
  1130. mir_snprintf(dat->szMicroLf, sizeof(dat->szMicroLf), "%s", "\\v\\cf%d \\ ~-+%d+-~\\v0 ");
  1131. } else {
  1132. mir_snprintf(dat->szMicroLf, sizeof(dat->szMicroLf), "%s\\par\\ltrpar\\sl-1%s ", GetRTFFont(MSGDLGFONTCOUNT), GetRTFFont(MSGDLGFONTCOUNT));
  1133. }
  1134. }
  1135. void TSAPI StreamInEvents(HWND hwndDlg, HANDLE hDbEventFirst, int count, int fAppend, DBEVENTINFO *dbei_s)
  1136. {
  1137. EDITSTREAM stream = { 0 };
  1138. struct LogStreamData streamData = { 0 };
  1139. struct TWindowData *dat = (struct TWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1140. CHARRANGE oldSel, sel;
  1141. HWND hwndrtf;
  1142. LONG startAt = 0;
  1143. FINDTEXTEXA fi;
  1144. struct tm tm_now, tm_today;
  1145. time_t now;
  1146. SCROLLINFO si = {0}, *psi = &si;
  1147. POINT pt = {0};
  1148. BOOL wasFirstAppend = (dat->isAutoRTL & 2) ? TRUE : FALSE;
  1149. BOOL isSent;
  1150. /*
  1151. * calc time limit for grouping
  1152. */
  1153. hwndrtf = dat->hwndIEView ? dat->hwndIWebBrowserControl : GetDlgItem(hwndDlg, IDC_LOG);
  1154. si.cbSize = sizeof(si);
  1155. /*
  1156. if (IsWindow(hwndrtf)) {
  1157. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;;
  1158. GetScrollInfo(hwndrtf, SB_VERT, &si);
  1159. SendMessage(hwndrtf, EM_GETSCROLLPOS, 0, (LPARAM) &pt);
  1160. if (GetWindowLongPtr(hwndrtf, GWL_STYLE) & WS_VSCROLL)
  1161. psi = &si;
  1162. else
  1163. psi = NULL;
  1164. }
  1165. */
  1166. rtfFonts = dat->pContainer->theme.rtfFonts ? dat->pContainer->theme.rtfFonts : &(rtfFontsGlobal[0][0]);
  1167. now = time(NULL);
  1168. tm_now = *localtime(&now);
  1169. tm_today = tm_now;
  1170. tm_today.tm_hour = tm_today.tm_min = tm_today.tm_sec = 0;
  1171. today = mktime(&tm_today);
  1172. if (dat->hwndIEView != 0) {
  1173. IEVIEWEVENT event;
  1174. ZeroMemory(&event, sizeof(event));
  1175. event.cbSize = sizeof(IEVIEWEVENT);
  1176. event.hwnd = dat->hwndIEView;
  1177. event.hContact = dat->hContact;
  1178. event.dwFlags = (dat->dwFlags & MWF_LOG_RTL) ? IEEF_RTL : 0;
  1179. if (dat->sendMode & SMODE_FORCEANSI) {
  1180. event.dwFlags |= IEEF_NO_UNICODE;
  1181. event.codepage = dat->codePage;
  1182. } else
  1183. event.codepage = 0;
  1184. if (!fAppend) {
  1185. event.iType = IEE_CLEAR_LOG;
  1186. CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
  1187. }
  1188. event.iType = IEE_LOG_DB_EVENTS;
  1189. event.hDbEventFirst = hDbEventFirst;
  1190. event.count = count;
  1191. event.pszProto = dat->szProto;
  1192. CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
  1193. DM_ScrollToBottom(dat, 0, 0);
  1194. if (fAppend)
  1195. dat->hDbEventLast = hDbEventFirst;
  1196. else
  1197. dat->hDbEventLast = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)dat->hContact, 0);
  1198. return;
  1199. }
  1200. if (dat->hwndHPP != 0) {
  1201. IEVIEWEVENT event;
  1202. event.cbSize = sizeof(IEVIEWEVENT);
  1203. event.hwnd = dat->hwndHPP;
  1204. event.hContact = dat->hContact;
  1205. event.dwFlags = (dat->dwFlags & MWF_LOG_RTL) ? IEEF_RTL : 0;
  1206. if (dat->sendMode & SMODE_FORCEANSI) {
  1207. event.dwFlags |= IEEF_NO_UNICODE;
  1208. event.codepage = dat->codePage;
  1209. } else
  1210. event.codepage = 0;
  1211. if (!fAppend) {
  1212. event.iType = IEE_CLEAR_LOG;
  1213. CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&event);
  1214. }
  1215. event.iType = IEE_LOG_DB_EVENTS;
  1216. event.hDbEventFirst = hDbEventFirst;
  1217. event.count = count;
  1218. CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&event);
  1219. //SendMessage(hwndDlg, DM_FORCESCROLL, (WPARAM)&pt, (LPARAM)&si);
  1220. DM_ScrollToBottom(dat, 0, 0);
  1221. if (fAppend)
  1222. dat->hDbEventLast = hDbEventFirst;
  1223. else
  1224. dat->hDbEventLast = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)dat->hContact, 0);
  1225. return;
  1226. }
  1227. // separator strings used for grid lines, message separation and so on...
  1228. dat->clr_added = FALSE;
  1229. if (dat->szMicroLf[0] == 0)
  1230. SetupLogFormatting(dat);
  1231. szYourName = const_cast<TCHAR *>(dat->cache->getNick());
  1232. szMyName = dat->szMyNickname;
  1233. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, TRUE, 0);
  1234. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & oldSel);
  1235. streamData.hContact = dat->hContact;
  1236. streamData.hDbEvent = hDbEventFirst;
  1237. streamData.dlgDat = dat;
  1238. streamData.eventsToInsert = count;
  1239. streamData.isEmpty = fAppend ? GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOG)) == 0 : 1;
  1240. streamData.dbei = dbei_s;
  1241. stream.pfnCallback = LogStreamInEvents;
  1242. stream.dwCookie = (DWORD_PTR) & streamData;
  1243. streamData.isAppend = fAppend;
  1244. if (fAppend) {
  1245. GETTEXTLENGTHEX gtxl = {0};
  1246. gtxl.codepage = 1200;
  1247. gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
  1248. fi.chrg.cpMin = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
  1249. sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOG));
  1250. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & sel);
  1251. } else {
  1252. SetDlgItemText(hwndDlg, IDC_LOG, _T(""));
  1253. sel.cpMin = 0;
  1254. sel.cpMax = GetWindowTextLength(hwndrtf);
  1255. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) &sel);
  1256. fi.chrg.cpMin = 0;
  1257. dat->isAutoRTL = 0;
  1258. }
  1259. startAt = fi.chrg.cpMin;
  1260. SendMessage(hwndrtf, WM_SETREDRAW, FALSE, 0);
  1261. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM) & stream);
  1262. //SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM) & stream);
  1263. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & oldSel);
  1264. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, FALSE, 0);
  1265. dat->hDbEventLast = streamData.hDbEventLast;
  1266. if (dat->isAutoRTL & 1) {
  1267. SendMessage(hwndrtf, EM_SETBKGNDCOLOR, 0, LOWORD(dat->iLastEventType) & DBEF_SENT ? (fAppend?dat->pContainer->theme.outbg : dat->pContainer->theme.oldoutbg) :
  1268. (fAppend?dat->pContainer->theme.inbg : dat->pContainer->theme.oldinbg));
  1269. }
  1270. if (!(dat->isAutoRTL & 1)) {
  1271. GETTEXTLENGTHEX gtxl = {0};
  1272. PARAFORMAT2 pf2;
  1273. gtxl.codepage = 1200;
  1274. gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
  1275. ZeroMemory(&pf2, sizeof(PARAFORMAT2));
  1276. sel.cpMax = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
  1277. sel.cpMin = sel.cpMax - 1;
  1278. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & sel);
  1279. SendDlgItemMessage(hwndDlg, IDC_LOG, EM_REPLACESEL, FALSE, (LPARAM)_T(""));
  1280. dat->isAutoRTL |= 2;
  1281. }
  1282. if (streamData.dbei != 0)
  1283. isSent = (streamData.dbei->flags & DBEF_SENT) != 0;
  1284. else {
  1285. DBEVENTINFO dbei = {0};
  1286. dbei.cbSize = sizeof(dbei);
  1287. CallService(MS_DB_EVENT_GET, (WPARAM) hDbEventFirst, (LPARAM)&dbei);
  1288. isSent = (dbei.flags & DBEF_SENT) != 0;
  1289. }
  1290. ReplaceIcons(hwndDlg, dat, startAt, fAppend, isSent);
  1291. dat->clr_added = FALSE;
  1292. SendMessage(hwndDlg, DM_FORCESCROLL, (WPARAM)&pt, (LPARAM)psi);
  1293. SendDlgItemMessage(hwndDlg, IDC_LOG, WM_SETREDRAW, TRUE, 0);
  1294. InvalidateRect(GetDlgItem(hwndDlg, IDC_LOG), NULL, FALSE);
  1295. EnableWindow(GetDlgItem(hwndDlg, IDC_QUOTE), dat->hDbEventLast != NULL);
  1296. if (streamData.buffer) free(streamData.buffer);
  1297. }
  1298. static void ReplaceIcons(HWND hwndDlg, struct TWindowData *dat, LONG startAt, int fAppend, BOOL isSent)
  1299. {
  1300. FINDTEXTEXA fi;
  1301. CHARFORMAT2 cf2;
  1302. HWND hwndrtf;
  1303. IRichEditOle *ole;
  1304. TEXTRANGEA tr;
  1305. COLORREF crDefault;
  1306. struct TLogIcon theIcon;
  1307. char trbuffer[40];
  1308. DWORD dwScale = M->GetDword("iconscale", 0);
  1309. tr.lpstrText = trbuffer;
  1310. hwndrtf = GetDlgItem(hwndDlg, IDC_LOG);
  1311. fi.chrg.cpMin = startAt;
  1312. if (dat->clr_added) {
  1313. unsigned int length;
  1314. int index;
  1315. CHARRANGE cr;
  1316. fi.lpstrText = "##col##";
  1317. fi.chrg.cpMax = -1;
  1318. ZeroMemory((void *)&cf2, sizeof(cf2));
  1319. cf2.cbSize = sizeof(cf2);
  1320. cf2.dwMask = CFM_COLOR;
  1321. while (SendMessageA(hwndrtf, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) {
  1322. tr.chrg.cpMin = fi.chrgText.cpMin;
  1323. tr.chrg.cpMax = tr.chrg.cpMin + 18;
  1324. trbuffer[0] = 0;
  1325. SendMessageA(hwndrtf, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
  1326. trbuffer[18] = 0;
  1327. cr.cpMin = fi.chrgText.cpMin;
  1328. cr.cpMax = cr.cpMin + 18;
  1329. SendMessage(hwndrtf, EM_EXSETSEL, 0, (LPARAM)&cr);
  1330. SendMessageA(hwndrtf, EM_REPLACESEL, FALSE, (LPARAM)"");
  1331. length = (unsigned int)atol(&trbuffer[7]);
  1332. index = atol(&trbuffer[14]);
  1333. if (length > 0 && length < 20000 && index >= RTF_CTABLE_DEFSIZE && index < Utils::rtf_ctable_size) {
  1334. cf2.crTextColor = Utils::rtf_ctable[index].clr;
  1335. cr.cpMin = fi.chrgText.cpMin;
  1336. cr.cpMax = cr.cpMin + length;
  1337. SendMessage(hwndrtf, EM_EXSETSEL, 0, (LPARAM)&cr);
  1338. SendMessage(hwndrtf, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
  1339. }
  1340. }
  1341. }
  1342. fi.chrg.cpMin = startAt;
  1343. if (dat->dwFlags & MWF_LOG_SHOWICONS) {
  1344. BYTE bIconIndex = 0;
  1345. char bDirection = 0;
  1346. CHARRANGE cr;
  1347. fi.lpstrText = "#~#";
  1348. fi.chrg.cpMax = -1;
  1349. ZeroMemory((void *)&cf2, sizeof(cf2));
  1350. cf2.cbSize = sizeof(cf2);
  1351. cf2.dwMask = CFM_BACKCOLOR;
  1352. SendMessage(hwndrtf, EM_GETOLEINTERFACE, 0, (LPARAM)&ole);
  1353. while (SendMessageA(hwndrtf, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) {
  1354. cr.cpMin = fi.chrgText.cpMin;
  1355. cr.cpMax = fi.chrgText.cpMax + 2;
  1356. SendMessage(hwndrtf, EM_EXSETSEL, 0, (LPARAM)&cr);
  1357. tr.chrg.cpMin = fi.chrgText.cpMin + 3;
  1358. tr.chrg.cpMax = fi.chrgText.cpMin + 5;
  1359. SendMessageA(hwndrtf, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
  1360. bIconIndex = ((BYTE)trbuffer[0] - (BYTE)'0');
  1361. if (bIconIndex >= NR_LOGICONS) {
  1362. fi.chrg.cpMin = fi.chrgText.cpMax + 6;
  1363. continue;
  1364. }
  1365. bDirection = trbuffer[1];
  1366. SendMessage(hwndrtf, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
  1367. crDefault = cf2.crBackColor == 0 ? (true ? (bDirection == '>' ? (fAppend ? dat->pContainer->theme.outbg : dat->pContainer->theme.oldoutbg) :
  1368. (fAppend ? dat->pContainer->theme.inbg : dat->pContainer->theme.oldinbg)) : dat->pContainer->theme.bg) : cf2.crBackColor;
  1369. CacheIconToBMP(&theIcon, Logicons[bIconIndex], crDefault, dwScale, dwScale);
  1370. ImageDataInsertBitmap(ole, theIcon.hBmp);
  1371. DeleteCachedIcon(&theIcon);
  1372. fi.chrg.cpMin = cr.cpMax + 6;
  1373. }
  1374. ReleaseRichEditOle(ole);
  1375. }
  1376. /*
  1377. * do smiley replacing, using the service
  1378. */
  1379. if (PluginConfig.g_SmileyAddAvail) {
  1380. CHARRANGE sel;
  1381. SMADD_RICHEDIT3 smadd;
  1382. sel.cpMin = startAt;
  1383. sel.cpMax = -1;
  1384. ZeroMemory(&smadd, sizeof(smadd));
  1385. smadd.cbSize = sizeof(smadd);
  1386. smadd.hwndRichEditControl = GetDlgItem(hwndDlg, IDC_LOG);
  1387. smadd.Protocolname = const_cast<char *>(dat->cache->getActiveProto());
  1388. smadd.hContact = dat->cache->getActiveContact();
  1389. smadd.flags = isSent ? SAFLRE_OUTGOING : 0;
  1390. if (startAt > 0)
  1391. smadd.rangeToReplace = &sel;
  1392. else
  1393. smadd.rangeToReplace = NULL;
  1394. smadd.disableRedraw = TRUE;
  1395. if (dat->doSmileys)
  1396. CallService(MS_SMILEYADD_REPLACESMILEYS, TABSRMM_SMILEYADD_BKGCOLORMODE, (LPARAM)&smadd);
  1397. }
  1398. if (PluginConfig.m_MathModAvail) {
  1399. TMathRicheditInfo mathReplaceInfo;
  1400. CHARRANGE mathNewSel;
  1401. mathNewSel.cpMin = startAt;
  1402. mathNewSel.cpMax = -1;
  1403. mathReplaceInfo.hwndRichEditControl = GetDlgItem(hwndDlg, IDC_LOG);
  1404. if (startAt > 0) mathReplaceInfo.sel = & mathNewSel;
  1405. else mathReplaceInfo.sel = 0;
  1406. mathReplaceInfo.disableredraw = TRUE;
  1407. CallService(MATH_RTF_REPLACE_FORMULAE, 0, (LPARAM)&mathReplaceInfo);
  1408. }
  1409. if (dat->hHistoryEvents && dat->curHistory == dat->maxHistory) {
  1410. char szPattern[50];
  1411. FINDTEXTEXA fi;
  1412. _snprintf(szPattern, 40, "~-+%d+-~", (INT_PTR)dat->hHistoryEvents[0]);
  1413. fi.lpstrText = szPattern;
  1414. fi.chrg.cpMin = 0;
  1415. fi.chrg.cpMax = -1;
  1416. if (SendMessageA(hwndrtf, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) != 0) {
  1417. CHARRANGE sel;
  1418. sel.cpMin = 0;
  1419. sel.cpMax = 20;
  1420. SendMessage(hwndrtf, EM_SETSEL, 0, fi.chrgText.cpMax + 1);
  1421. SendMessageA(hwndrtf, EM_REPLACESEL, TRUE, (LPARAM)"");
  1422. }
  1423. }
  1424. }
  1425. /*
  1426. * NLS functions (for unicode version only) encoding stuff..
  1427. */
  1428. static BOOL CALLBACK LangAddCallback(LPTSTR str)
  1429. {
  1430. int i, count;
  1431. UINT cp;
  1432. cp = _ttoi(str);
  1433. count = sizeof(cpTable) / sizeof(cpTable[0]);
  1434. for (i = 0; i < count && cpTable[i].cpId != cp; i++);
  1435. if (i < count) {
  1436. AppendMenu(PluginConfig.g_hMenuEncoding, MF_STRING, cp, TranslateTS(cpTable[i].cpName));
  1437. }
  1438. return TRUE;
  1439. }
  1440. void TSAPI BuildCodePageList()
  1441. {
  1442. PluginConfig.g_hMenuEncoding = CreateMenu();
  1443. AppendMenu(PluginConfig.g_hMenuEncoding, MF_STRING, 500, CTranslator::get(CTranslator::GEN_LOG_USEDEFAULTCP));
  1444. AppendMenuA(PluginConfig.g_hMenuEncoding, MF_SEPARATOR, 0, 0);
  1445. EnumSystemCodePages(LangAddCallback, CP_INSTALLED);
  1446. }
  1447. static TCHAR *Template_MakeRelativeDate(struct TWindowData *dat, HANDLE hTimeZone, time_t check, int groupBreak, TCHAR code)
  1448. {
  1449. static TCHAR szResult[100];
  1450. const TCHAR *szFormat;
  1451. if ((code == (TCHAR)'R' || code == (TCHAR)'r') && check >= today) {
  1452. _tcscpy(szResult, szToday);
  1453. } else if ((code == (TCHAR)'R' || code == (TCHAR)'r') && check > (today - 86400)) {
  1454. _tcscpy(szResult, szYesterday);
  1455. } else {
  1456. if (code == 'D' || code == 'R')
  1457. szFormat = _T("D");
  1458. else if (code == 'T')
  1459. szFormat = _T("s");
  1460. else if (code == 't')
  1461. szFormat = _T("t");
  1462. else
  1463. szFormat = _T("d");
  1464. tmi.printTimeStamp(hTimeZone, check, szFormat, szResult, safe_sizeof(szResult), 0);
  1465. }
  1466. return szResult;
  1467. }