summaryrefslogtreecommitdiff
path: root/plugins/SRMM/msglog.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2012-06-23 19:20:55 +0000
committerGeorge Hazan <george.hazan@gmail.com>2012-06-23 19:20:55 +0000
commit1c51a6e0409bbfd61383a942636d6766154b5225 (patch)
treedcc4e9573aace0028c3dd8bd580a35560fc77882 /plugins/SRMM/msglog.cpp
parent9e0c64767759da86499f245083239575d947b5e9 (diff)
srmm plusified
git-svn-id: http://svn.miranda-ng.org/main/trunk@583 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/SRMM/msglog.cpp')
-rw-r--r--plugins/SRMM/msglog.cpp645
1 files changed, 645 insertions, 0 deletions
diff --git a/plugins/SRMM/msglog.cpp b/plugins/SRMM/msglog.cpp
new file mode 100644
index 0000000000..e32c98ae50
--- /dev/null
+++ b/plugins/SRMM/msglog.cpp
@@ -0,0 +1,645 @@
+/*
+Copyright 2000-2010 Miranda IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+extern HANDLE hIconLibItem[];
+
+static int logPixelSY;
+#define LOGICON_MSG_IN 0
+#define LOGICON_MSG_OUT 1
+#define LOGICON_MSG_NOTICE 2
+static PBYTE pLogIconBmpBits[3];
+static int logIconBmpSize[ SIZEOF(pLogIconBmpBits) ];
+
+#define STREAMSTAGE_HEADER 0
+#define STREAMSTAGE_EVENTS 1
+#define STREAMSTAGE_TAIL 2
+#define STREAMSTAGE_STOP 3
+struct LogStreamData
+{
+ int stage;
+ HANDLE hContact;
+ HANDLE hDbEvent, hDbEventLast;
+ char *buffer;
+ int bufferOffset, bufferLen;
+ int eventsToInsert;
+ int isEmpty;
+ struct SrmmWindowData *dlgDat;
+};
+
+static char szSep2[40], szSep2_RTL[50];
+
+static void AppendToBuffer(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone;
+
+ va_start(va, fmt);
+ for (;;) {
+ charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
+ if (charsDone >= 0)
+ break;
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) mir_realloc(*buffer, *cbBufferAlloced);
+ }
+ va_end(va);
+ *cbBufferEnd += charsDone;
+}
+
+static const TCHAR *bbcodes[] = { _T("[b]"), _T("[i]"), _T("[u]"), _T("[s]"), _T("[/b]"), _T("[/i]"), _T("[/u]"), _T("[/s]") };
+static const char *bbcodefmt[] = { "\\b ", "\\i ", "\\ul ", "\\strike ", "\\b0 ", "\\i0 ", "\\ul0 ", "\\strike0 " };
+
+static int AppendToBufferWithRTF(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, TCHAR* line)
+{
+ DWORD textCharsCount = 0;
+ char *d;
+ int lineLen;
+
+ if (line == NULL)
+ return 0;
+
+ lineLen = (int)_tcslen(line) * 9 + 8;
+ if (*cbBufferEnd + lineLen > *cbBufferAlloced)
+ {
+ cbBufferAlloced[0] += (lineLen + 1024 - lineLen % 1024);
+ *buffer = (char *) mir_realloc(*buffer, *cbBufferAlloced);
+ }
+
+ d = *buffer + *cbBufferEnd;
+ strcpy(d, "{\\uc1 ");
+ d += 6;
+
+ for (; *line; line++, textCharsCount++)
+ {
+ if (*line == '\r' && line[1] == '\n')
+ {
+ memcpy(d, "\\par ", 5);
+ line++;
+ d += 5;
+ }
+ else if (*line == '\n') {
+ memcpy(d, "\\par ", 5);
+ d += 5;
+ }
+ else if (*line == '\t')
+ {
+ memcpy(d, "\\tab ", 5);
+ d += 5;
+ }
+ else if (*line == '\\' || *line == '{' || *line == '}')
+ {
+ *d++ = '\\';
+ *d++ = (char) *line;
+ }
+ else if (*line == '[' && (g_dat->flags & SMF_SHOWFORMAT))
+ {
+ int i, found = 0;
+ for (i = 0; i < SIZEOF(bbcodes); ++i)
+ {
+ if (line[1] == bbcodes[i][1])
+ {
+ size_t lenb = _tcslen(bbcodes[i]);
+ if (!_tcsnicmp(line, bbcodes[i], lenb))
+ {
+ size_t len = strlen(bbcodefmt[i]);
+ memcpy(d, bbcodefmt[i], len);
+ d += len;
+ line += lenb - 1;
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ if (!_tcsnicmp(line, _T("[url"), 4))
+ {
+ TCHAR* tag = _tcschr(line + 4, ']');
+ if (tag)
+ {
+ TCHAR *tagu = (line[4] == '=') ? line + 5 : tag + 1;
+ TCHAR *tage = _tcsstr(tag, _T("[/url]"));
+ if (!tage) tage = _tcsstr(tag, _T("[/URL]"));
+ if (tage)
+ {
+ *tag = 0;
+ *tage = 0;
+ d += sprintf(d, "{\\field{\\*\\fldinst HYPERLINK \"%s\"}{\\fldrslt %s}}", mir_t2a(tagu), mir_t2a(tag + 1));
+// d += sprintf(d, "{\\field{\\*\\fldinst HYPERLINK \"%s\"}{\\fldrslt \\ul\\cf%d %s}}", mir_t2a(tagu), msgDlgFontCount, mir_t2a(tag + 1));
+ line = tage + 5;
+ found = 1;
+ }
+ }
+ }
+ else if (!_tcsnicmp(line, _T("[color="), 7))
+ {
+ TCHAR* tag = _tcschr(line + 7, ']');
+ if (tag)
+ {
+ line = tag;
+ found = 1;
+ }
+ }
+ else if (!_tcsnicmp(line, _T("[/color]"), 8))
+ {
+ line += 7;
+ found = 1;
+ }
+ }
+ if (!found)
+ {
+ if (*line < 128) *d++ = (char) *line;
+ else d += sprintf(d, "\\u%d ?", *line);
+ }
+ }
+ else if (*line < 128) *d++ = (char) *line;
+ else d += sprintf(d, "\\u%d ?", *line);
+ }
+
+ *(d++) = '}';
+ *d = 0;
+
+ *cbBufferEnd = (int) (d - *buffer);
+ return textCharsCount;
+}
+
+#define FONT_FORMAT "{\\f%u\\fnil\\fcharset%u %S;}"
+
+static char *CreateRTFHeader(struct SrmmWindowData *dat)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+ int i;
+ LOGFONT lf;
+ COLORREF colour;
+ HDC hdc;
+
+ hdc = GetDC(NULL);
+ logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(NULL, hdc);
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) mir_alloc(bufferAlloced);
+ buffer[0] = '\0';
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
+
+ for (i = 0; i < msgDlgFontCount; i++) {
+ LoadMsgDlgFont(i, &lf, NULL);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, FONT_FORMAT, i, lf.lfCharSet, lf.lfFaceName);
+ }
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}{\\colortbl ");
+ for (i = 0; i < msgDlgFontCount; i++) {
+ LoadMsgDlgFont(i, NULL, &colour);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ }
+ if (GetSysColorBrush(COLOR_HOTLIGHT) == NULL)
+ colour = RGB(0, 0, 255);
+ else
+ colour = GetSysColor(COLOR_HOTLIGHT);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}");
+ //AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}\\pard");
+ return buffer;
+}
+
+//mir_free() the return value
+static char *CreateRTFTail(struct SrmmWindowData *dat)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) mir_alloc(bufferAlloced);
+ buffer[0] = '\0';
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}");
+ return buffer;
+}
+
+//return value is static
+static char *SetToStyle(int style)
+{
+ static char szStyle[128];
+ LOGFONT lf;
+
+ LoadMsgDlgFont(style, &lf, NULL);
+ wsprintfA(szStyle, "\\f%u\\cf%u\\b%d\\i%d\\fs%u", style, style, lf.lfWeight >= FW_BOLD ? 1 : 0, lf.lfItalic, 2 * abs(lf.lfHeight) * 74 / logPixelSY);
+ return szStyle;
+}
+
+int DbEventIsForMsgWindow(DBEVENTINFO *dbei)
+{
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
+ return et && ( et->flags & DETF_MSGWINDOW );
+}
+
+int DbEventIsShown(DBEVENTINFO * dbei, struct SrmmWindowData *dat)
+{
+ switch (dbei->eventType) {
+ case EVENTTYPE_MESSAGE:
+ return 1;
+ case EVENTTYPE_JABBER_CHATSTATES:
+ case EVENTTYPE_JABBER_PRESENCE:
+ case EVENTTYPE_STATUSCHANGE:
+ case EVENTTYPE_FILE:
+ return (dbei->flags & DBEF_READ) == 0;
+ }
+ return DbEventIsForMsgWindow(dbei);
+}
+
+//mir_free() the return value
+static char *CreateRTFFromDbEvent(struct SrmmWindowData *dat, HANDLE hContact, HANDLE hDbEvent, struct LogStreamData *streamData)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+ DBEVENTINFO dbei = { 0 };
+ int showColon = 0;
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM) hDbEvent, 0);
+ if (dbei.cbBlob == -1)
+ return NULL;
+ dbei.pBlob = (PBYTE) mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
+ if (!DbEventIsShown(&dbei, dat)) {
+ mir_free(dbei.pBlob);
+ return NULL;
+ }
+ if (!(dbei.flags & DBEF_SENT) && (dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei)))
+ {
+ CallService(MS_DB_EVENT_MARKREAD, (WPARAM) hContact, (LPARAM) hDbEvent);
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM) hContact, (LPARAM) hDbEvent);
+ }
+ else if (dbei.eventType == EVENTTYPE_STATUSCHANGE || dbei.eventType == EVENTTYPE_JABBER_CHATSTATES || dbei.eventType == EVENTTYPE_JABBER_PRESENCE) {
+ CallService(MS_DB_EVENT_MARKREAD, (WPARAM) hContact, (LPARAM) hDbEvent);
+ }
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) mir_alloc(bufferAlloced);
+ buffer[0] = '\0';
+
+ if (!dat->bIsAutoRTL && !streamData->isEmpty)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
+
+ if (dbei.flags & DBEF_RTL) {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlpar");
+ dat->bIsAutoRTL = TRUE;
+ }
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrpar");
+
+ streamData->isEmpty = 0;
+
+ if (dat->bIsAutoRTL) {
+ if(dbei.flags & DBEF_RTL) {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrch\\rtlch");
+ }else{
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlch\\ltrch");
+ }
+ }
+
+ if (g_dat->flags&SMF_SHOWICONS) {
+ int i;
+
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ if (dbei.flags & DBEF_SENT) {
+ i = LOGICON_MSG_OUT;
+ }
+ else {
+ i = LOGICON_MSG_IN;
+ }
+ break;
+ case EVENTTYPE_JABBER_CHATSTATES:
+ case EVENTTYPE_JABBER_PRESENCE:
+ case EVENTTYPE_STATUSCHANGE:
+ case EVENTTYPE_FILE:
+ default:
+ i = LOGICON_MSG_NOTICE;
+ break;
+ }
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\f0\\fs14");
+ while (bufferAlloced - bufferEnd < logIconBmpSize[i])
+ bufferAlloced += 1024;
+ buffer = (char *) mir_realloc(buffer, bufferAlloced);
+ CopyMemory(buffer + bufferEnd, pLogIconBmpBits[i], logIconBmpSize[i]);
+ bufferEnd += logIconBmpSize[i];
+ }
+ if (g_dat->flags & SMF_SHOWTIME)
+ {
+ const TCHAR* szFormat;
+ TCHAR str[64];
+
+ if (g_dat->flags & SMF_SHOWSECS)
+ szFormat = g_dat->flags & SMF_SHOWDATE ? _T("d s") : _T("s");
+ else
+ szFormat = g_dat->flags & SMF_SHOWDATE ? _T("d t") : _T("t");
+
+ tmi.printTimeStamp(NULL, dbei.timestamp, szFormat, str, SIZEOF(str), 0);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, str);
+ showColon = 1;
+ }
+ if (!(g_dat->flags&SMF_HIDENAMES) && dbei.eventType != EVENTTYPE_STATUSCHANGE && dbei.eventType != EVENTTYPE_JABBER_CHATSTATES && dbei.eventType != EVENTTYPE_JABBER_PRESENCE) {
+ TCHAR* szName;
+ CONTACTINFO ci = {0};
+
+ if (dbei.flags & DBEF_SENT) {
+ ci.cbSize = sizeof(ci);
+ ci.szProto = dbei.szModule;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ // CNF_DISPLAY always returns a string type
+ szName = ci.pszVal;
+ }
+ }
+ else szName = ( TCHAR* ) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, szName);
+ showColon = 1;
+ if (ci.pszVal)
+ mir_free(ci.pszVal);
+ }
+
+ if (showColon)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s :", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
+
+ switch (dbei.eventType) {
+ default:
+ case EVENTTYPE_MESSAGE:
+ {
+ TCHAR* msg = DbGetEventTextT( &dbei, CP_ACP );
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYMSG : MSGFONTID_YOURMSG));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, msg);
+
+ mir_free(msg);
+ break;
+ }
+ case EVENTTYPE_JABBER_CHATSTATES:
+ case EVENTTYPE_JABBER_PRESENCE:
+ case EVENTTYPE_STATUSCHANGE:
+ {
+ TCHAR *msg, *szName;
+ CONTACTINFO ci = {0};
+
+ if (dbei.flags & DBEF_SENT) {
+ ci.cbSize = sizeof(ci);
+ ci.hContact = NULL;
+ ci.szProto = dbei.szModule;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ // CNF_DISPLAY always returns a string type
+ szName = ci.pszVal;
+ }
+ }
+ else szName = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(MSGFONTID_NOTICE));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, szName);
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, _T(" "));
+
+ msg = DbGetEventTextT( &dbei, CP_ACP );
+ if ( msg ) {
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, msg);
+ mir_free( msg );
+ }
+ mir_free(ci.pszVal);
+ break;
+ }
+ case EVENTTYPE_FILE:
+ {
+ char* filename = (char*)dbei.pBlob + sizeof(DWORD);
+ char* descr = filename + strlen( filename ) + 1;
+ TCHAR* ptszFileName = DbGetEventStringT( &dbei, filename );
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " %s ", SetToStyle(MSGFONTID_NOTICE));
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced,
+ (dbei.flags & DBEF_SENT) ? TranslateT("File sent") : TranslateT("File received"));
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, ": ");
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, ptszFileName);
+ mir_free( ptszFileName );
+
+ if ( *descr != 0 ) {
+ TCHAR* ptszDescr = DbGetEventStringT( &dbei, descr );
+ AppendToBuffer( &buffer, &bufferEnd, &bufferAlloced, " (" );
+ AppendToBufferWithRTF(&buffer, &bufferEnd, &bufferAlloced, ptszDescr);
+ AppendToBuffer( &buffer, &bufferEnd, &bufferAlloced, ")" );
+ mir_free( ptszDescr );
+ }
+ break;
+ } }
+
+ if(dat->bIsAutoRTL)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
+
+ mir_free(dbei.pBlob);
+ return buffer;
+}
+
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ struct LogStreamData *dat = (struct LogStreamData *) dwCookie;
+
+ if (dat->buffer == NULL)
+ {
+ dat->bufferOffset = 0;
+ switch (dat->stage)
+ {
+ case STREAMSTAGE_HEADER:
+ dat->buffer = CreateRTFHeader(dat->dlgDat);
+ dat->stage = STREAMSTAGE_EVENTS;
+ break;
+
+ case STREAMSTAGE_EVENTS:
+ if (dat->eventsToInsert)
+ {
+ do
+ {
+ dat->buffer = CreateRTFFromDbEvent(dat->dlgDat, dat->hContact, dat->hDbEvent, dat);
+ if (dat->buffer)
+ dat->hDbEventLast = dat->hDbEvent;
+ dat->hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) dat->hDbEvent, 0);
+ if (--dat->eventsToInsert == 0)
+ break;
+ } while (dat->buffer == NULL && dat->hDbEvent);
+ if (dat->buffer)
+ {
+ dat->isEmpty = 0;
+ break;
+ }
+ }
+ dat->stage = STREAMSTAGE_TAIL;
+ //fall through
+ case STREAMSTAGE_TAIL:
+ dat->buffer = CreateRTFTail(dat->dlgDat);
+ dat->stage = STREAMSTAGE_STOP;
+ break;
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
+ }
+ dat->bufferLen = (int)strlen(dat->buffer);
+ }
+ *pcb = min(cb, dat->bufferLen - dat->bufferOffset);
+ CopyMemory(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
+ dat->bufferOffset += *pcb;
+ if (dat->bufferOffset == dat->bufferLen)
+ {
+ mir_free(dat->buffer);
+ dat->buffer = NULL;
+ }
+ return 0;
+}
+
+void StreamInEvents(HWND hwndDlg, HANDLE hDbEventFirst, int count, int fAppend)
+{
+ EDITSTREAM stream = {0};
+ struct LogStreamData streamData = {0};
+ struct SrmmWindowData *dat = (struct SrmmWindowData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ CHARRANGE oldSel, sel;
+ POINT scrollPos;
+ BOOL bottomScroll = TRUE;
+
+ HWND hwndLog = GetDlgItem(hwndDlg, IDC_LOG);
+
+ SendMessage(hwndLog, WM_SETREDRAW, FALSE, 0);
+ SendMessage(hwndLog, EM_EXGETSEL, 0, (LPARAM) & oldSel);
+ streamData.hContact = dat->hContact;
+ streamData.hDbEvent = hDbEventFirst;
+ streamData.dlgDat = dat;
+ streamData.eventsToInsert = count;
+ streamData.isEmpty = !fAppend || GetWindowTextLength(hwndLog) == 0;
+ stream.pfnCallback = LogStreamInEvents;
+ stream.dwCookie = (DWORD_PTR)&streamData;
+
+ if (!streamData.isEmpty)
+ {
+ bottomScroll = (GetFocus() != hwndLog);
+ if (bottomScroll && (GetWindowLongPtr(hwndLog, GWL_STYLE) & WS_VSCROLL))
+ {
+ SCROLLINFO si = {0};
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
+ GetScrollInfo(hwndLog, SB_VERT, &si);
+ bottomScroll = (si.nPos + (int)si.nPage) >= si.nMax;
+ }
+ if (!bottomScroll)
+ SendMessage(hwndLog, EM_GETSCROLLPOS, 0, (LPARAM) & scrollPos);
+ }
+ if (fAppend)
+ {
+ sel.cpMin = sel.cpMax = -1;
+ SendMessage(hwndLog, EM_EXSETSEL, 0, (LPARAM) & sel);
+ }
+
+ strcpy(szSep2, fAppend ? "\\par\\sl0" : "\\sl1000");
+ strcpy(szSep2_RTL, fAppend ? "\\rtlpar\\rtlmark\\par\\sl1000" : "\\sl1000");
+
+ SendMessage(hwndLog, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM) & stream);
+ if (bottomScroll)
+ {
+ sel.cpMin = sel.cpMax = -1;
+ SendMessage(hwndLog, EM_EXSETSEL, 0, (LPARAM) & sel);
+ if (GetWindowLongPtr(hwndLog, GWL_STYLE) & WS_VSCROLL)
+ {
+ SendMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0);
+ PostMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0);
+ }
+ }
+ else
+ {
+ SendMessage(hwndLog, EM_EXSETSEL, 0, (LPARAM) & oldSel);
+ SendMessage(hwndLog, EM_SETSCROLLPOS, 0, (LPARAM) & scrollPos);
+ }
+
+ SendMessage(hwndLog, WM_SETREDRAW, TRUE, 0);
+ if (bottomScroll)
+ RedrawWindow(hwndLog, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+
+ dat->hDbEventLast = streamData.hDbEventLast;
+}
+
+#define RTFPICTHEADERMAXSIZE 78
+void LoadMsgLogIcons(void)
+{
+ HICON hIcon;
+ HBITMAP hBmp, hoBmp;
+ HDC hdc, hdcMem;
+ BITMAPINFOHEADER bih = { 0 };
+ int widthBytes, i;
+ RECT rc;
+ HBRUSH hBkgBrush;
+ int rtfHeaderSize;
+ PBYTE pBmpBits;
+
+ hBkgBrush = CreateSolidBrush(DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR));
+ bih.biSize = sizeof(bih);
+ bih.biBitCount = 24;
+ bih.biCompression = BI_RGB;
+ bih.biHeight = 10;
+ bih.biPlanes = 1;
+ bih.biWidth = 10;
+ widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4;
+ rc.top = rc.left = 0;
+ rc.right = bih.biWidth;
+ rc.bottom = bih.biHeight;
+ hdc = GetDC(NULL);
+ hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight);
+ hdcMem = CreateCompatibleDC(hdc);
+ pBmpBits = (PBYTE) mir_alloc(widthBytes * bih.biHeight);
+
+ for (i = 0; i < SIZEOF(pLogIconBmpBits); i++) {
+ hIcon = Skin_GetIconByHandle(hIconLibItem[i]);
+ pLogIconBmpBits[i] = (PBYTE) mir_alloc(RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2);
+ //I can't seem to get binary mode working. No matter.
+ rtfHeaderSize = sprintf((char*)pLogIconBmpBits[i], "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, bih.biWidth, bih.biHeight);
+ hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp);
+ FillRect(hdcMem, &rc, hBkgBrush);
+ DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, NULL, DI_NORMAL);
+ CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0);
+
+ SelectObject(hdcMem, hoBmp);
+ GetDIBits(hdc, hBmp, 0, bih.biHeight, pBmpBits, (BITMAPINFO *) & bih, DIB_RGB_COLORS);
+ {
+ int n;
+ for (n = 0; n < sizeof(BITMAPINFOHEADER); n++)
+ sprintf((char*)pLogIconBmpBits[i] + rtfHeaderSize + n * 2, "%02X", ((PBYTE) & bih)[n]);
+ for (n = 0; n < widthBytes * bih.biHeight; n += 4)
+ sprintf((char*)pLogIconBmpBits[i] + rtfHeaderSize + (bih.biSize + n) * 2, "%02X%02X%02X%02X", pBmpBits[n], pBmpBits[n + 1], pBmpBits[n + 2], pBmpBits[n + 3]);
+ }
+ logIconBmpSize[i] = rtfHeaderSize + (bih.biSize + widthBytes * bih.biHeight) * 2 + 1;
+ pLogIconBmpBits[i][logIconBmpSize[i] - 1] = '}';
+ }
+ mir_free(pBmpBits);
+ DeleteDC(hdcMem);
+ DeleteObject(hBmp);
+ ReleaseDC(NULL, hdc);
+ DeleteObject(hBkgBrush);
+}
+
+void FreeMsgLogIcons(void)
+{
+ int i;
+ for (i = 0; i < SIZEOF(pLogIconBmpBits); i++)
+ mir_free(pLogIconBmpBits[i]);
+}