summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2023-04-14 17:59:03 +0300
committerGeorge Hazan <ghazan@miranda.im>2023-04-14 17:59:03 +0300
commitf12d6a4000cfce521392200635d1cadc63dba934 (patch)
tree86d408068682d7b1e239877df857ac95f7f25297
parentaa5197082f1567e37b85911752b92a489d6515c3 (diff)
SRMM code unification
-rw-r--r--include/m_database.h4
-rw-r--r--include/m_srmm_int.h7
-rw-r--r--libs/win32/mir_app.libbin245744 -> 246684 bytes
-rw-r--r--libs/win64/mir_app.libbin242852 -> 243818 bytes
-rw-r--r--plugins/Scriver/src/msgdialog.cpp9
-rw-r--r--plugins/Scriver/src/msglog.cpp718
-rw-r--r--plugins/Scriver/src/msgs.cpp4
-rw-r--r--plugins/Scriver/src/msgs.h27
-rw-r--r--plugins/Scriver/src/msgutils.cpp5
-rw-r--r--plugins/TabSRMM/src/msgdlgutils.cpp3
-rw-r--r--plugins/TabSRMM/src/msglog.cpp464
-rw-r--r--plugins/TabSRMM/src/msgs.h74
-rw-r--r--src/core/stdmsg/src/chat_window.cpp104
-rw-r--r--src/core/stdmsg/src/msgdialog.cpp2
-rw-r--r--src/core/stdmsg/src/msglog.cpp857
-rw-r--r--src/core/stdmsg/src/msgs.h17
-rw-r--r--src/mir_app/src/db_events.cpp10
-rw-r--r--src/mir_app/src/mir_app.def2
-rw-r--r--src/mir_app/src/mir_app64.def2
-rw-r--r--src/mir_app/src/srmm_log_rtf.cpp25
20 files changed, 1153 insertions, 1181 deletions
diff --git a/include/m_database.h b/include/m_database.h
index a3e7a09af9..28e0d78c17 100644
--- a/include/m_database.h
+++ b/include/m_database.h
@@ -517,8 +517,8 @@ __forceinline MCONTACT DbGetAuthEventContact(DBEVENTINFO *dbei)
// Function returns a pointer to a string in the required format.
// This string should be freed by a call of mir_free
-EXTERN_C MIR_APP_DLL(char*) DbEvent_GetTextA(DBEVENTINFO *dbei, int codepage);
-EXTERN_C MIR_APP_DLL(wchar_t*) DbEvent_GetTextW(DBEVENTINFO *dbei, int codepage);
+EXTERN_C MIR_APP_DLL(char*) DbEvent_GetTextA(const DBEVENTINFO *dbei, int codepage);
+EXTERN_C MIR_APP_DLL(wchar_t*) DbEvent_GetTextW(const DBEVENTINFO *dbei, int codepage);
/////////////////////////////////////////////////////////////////////////////////////////
// Retrieves the event's icon
diff --git a/include/m_srmm_int.h b/include/m_srmm_int.h
index 27dc5d0ebf..9e3b8e0c7a 100644
--- a/include/m_srmm_int.h
+++ b/include/m_srmm_int.h
@@ -134,6 +134,10 @@ public:
virtual void UpdateOptions() {};
virtual INT_PTR Notify(WPARAM, LPARAM) { return 0; }
+
+ __inline CMsgDialog& GetDialog() const
+ { return m_pDlg;
+ }
};
typedef CSrmmLogWindow *(MIR_CDECL *pfnSrmmLogCreator)(CMsgDialog &pDlg);
@@ -149,10 +153,13 @@ class MIR_APP_EXPORT CRtfLogWindow : public CSrmmLogWindow
protected:
CCtrlRichEdit &m_rtf;
+ void InsertFileLink(CMStringA &buf, MEVENT hEvent, const DB::FILE_BLOB &blob);
+
public:
CRtfLogWindow(CMsgDialog &pDlg);
~CRtfLogWindow() override;
+ virtual void AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf) = 0;
virtual INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/win32/mir_app.lib b/libs/win32/mir_app.lib
index 2b977a54b5..89d18b715f 100644
--- a/libs/win32/mir_app.lib
+++ b/libs/win32/mir_app.lib
Binary files differ
diff --git a/libs/win64/mir_app.lib b/libs/win64/mir_app.lib
index 65574852bc..67a4e37d53 100644
--- a/libs/win64/mir_app.lib
+++ b/libs/win64/mir_app.lib
Binary files differ
diff --git a/plugins/Scriver/src/msgdialog.cpp b/plugins/Scriver/src/msgdialog.cpp
index 4c6c1f9af0..4112c792de 100644
--- a/plugins/Scriver/src/msgdialog.cpp
+++ b/plugins/Scriver/src/msgdialog.cpp
@@ -171,10 +171,6 @@ bool CMsgDialog::OnInitDialog()
m_nTypeMode = PROTOTYPE_SELFTYPING_OFF;
timerType.Start(1000);
- m_lastEventType = -1;
- m_lastEventTime = time(0);
- m_startTime = time(0);
-
m_bUseRtl = g_plugin.getByte(m_hContact, "UseRTL", 0) != 0;
PARAFORMAT2 pf2;
@@ -434,7 +430,7 @@ void CMsgDialog::onClick_Quote(CCtrlButton*)
if (!dbei)
return;
- if (DbEventIsMessageOrCustom(&dbei)) {
+ if (DbEventIsMessageOrCustom(dbei)) {
buffer = DbEvent_GetTextW(&dbei, CP_ACP);
if (buffer != nullptr) {
CMStringW quotedBuffer(GetQuotedTextW(buffer));
@@ -1077,7 +1073,7 @@ INT_PTR CMsgDialog::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam)
while (hDbEvent != 0) {
DBEVENTINFO dbei = {};
db_event_get(hDbEvent, &dbei);
- if (!(dbei.flags & DBEF_SENT) && DbEventIsMessageOrCustom(&dbei))
+ if (!(dbei.flags & DBEF_SENT) && DbEventIsMessageOrCustom(dbei))
g_clistApi.pfnRemoveEvent(m_hContact, hDbEvent);
hDbEvent = db_event_next(m_hContact, hDbEvent);
}
@@ -1140,7 +1136,6 @@ INT_PTR CMsgDialog::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam)
return TRUE;
case DM_REMAKELOG:
- m_lastEventType = -1;
if (wParam == 0 || wParam == m_hContact)
m_pLog->LogEvents(m_hDbEventFirst, -1, 0);
diff --git a/plugins/Scriver/src/msglog.cpp b/plugins/Scriver/src/msglog.cpp
index 5bd6e406f7..0359c1cdf7 100644
--- a/plugins/Scriver/src/msglog.cpp
+++ b/plugins/Scriver/src/msglog.cpp
@@ -45,20 +45,22 @@ struct LogStreamData
size_t bufferOffset, bufferLen;
int eventsToInsert;
int isFirst;
- CMsgDialog *dlgDat;
+ class CLogWindow *pLog;
GlobalMessageData *gdat;
- EventData *events;
+ DB::EventInfo *dbei;
};
-bool DbEventIsCustomForMsgWindow(const DBEVENTINFO *dbei)
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);
+
+bool DbEventIsCustomForMsgWindow(const DBEVENTINFO &dbei)
{
- DBEVENTTYPEDESCR *et = DbEvent_GetType(dbei->szModule, dbei->eventType);
+ DBEVENTTYPEDESCR *et = DbEvent_GetType(dbei.szModule, dbei.eventType);
return et && (et->flags & DETF_MSGWINDOW);
}
-bool DbEventIsMessageOrCustom(const DBEVENTINFO* dbei)
+bool DbEventIsMessageOrCustom(const DBEVENTINFO &dbei)
{
- return dbei->eventType == EVENTTYPE_MESSAGE || DbEventIsCustomForMsgWindow(dbei);
+ return dbei.eventType == EVENTTYPE_MESSAGE || dbei.eventType == EVENTTYPE_FILE || DbEventIsCustomForMsgWindow(dbei);
}
bool DbEventIsShown(const DBEVENTINFO &dbei)
@@ -73,107 +75,15 @@ bool DbEventIsShown(const DBEVENTINFO &dbei)
return 0;
}
- return DbEventIsCustomForMsgWindow(&dbei);
-}
-
-EventData* CMsgDialog::GetEventFromDB(MCONTACT hContact, MEVENT hDbEvent)
-{
- DB::EventInfo dbei(hDbEvent);
- if (!dbei)
- return nullptr;
-
- if (!DbEventIsShown(dbei))
- return nullptr;
-
- EventData *evt = (EventData*)mir_calloc(sizeof(EventData));
- evt->custom = DbEventIsCustomForMsgWindow(&dbei);
- if (!(dbei.flags & DBEF_SENT) && (dbei.eventType == EVENTTYPE_MESSAGE || evt->custom)) {
- db_event_markRead(hContact, hDbEvent);
- g_clistApi.pfnRemoveEvent(hContact, hDbEvent);
- }
- else if (dbei.eventType == EVENTTYPE_JABBER_CHATSTATES || dbei.eventType == EVENTTYPE_JABBER_PRESENCE)
- db_event_markRead(hContact, hDbEvent);
-
- evt->eventType = dbei.eventType;
- evt->dwFlags = (dbei.flags & DBEF_READ ? IEEDF_READ : 0) | (dbei.flags & DBEF_SENT ? IEEDF_SENT : 0) | (dbei.flags & DBEF_RTL ? IEEDF_RTL : 0);
- evt->dwFlags |= IEEDF_UNICODE_TEXT | IEEDF_UNICODE_NICK;
-
- if (m_bUseRtl)
- evt->dwFlags |= IEEDF_RTL;
-
- evt->time = dbei.timestamp;
- evt->szNick.w = nullptr;
- if (evt->dwFlags & IEEDF_SENT)
- evt->szNick.w = Contact::GetInfo(CNF_DISPLAY, 0, m_szProto);
- else
- evt->szNick.w = mir_wstrdup(Clist_GetContactDisplayName(hContact));
-
- evt->szText.w = DbEvent_GetTextW(&dbei, CP_UTF8);
-
- if (!m_bUseRtl && Utils_IsRtl(evt->szText.w))
- evt->dwFlags |= IEEDF_RTL;
-
- return evt;
-}
-
-static EventData* GetTestEvent(uint32_t flags)
-{
- EventData *evt = (EventData *)mir_calloc(sizeof(EventData));
- evt->eventType = EVENTTYPE_MESSAGE;
- evt->dwFlags = IEEDF_READ | flags;
- evt->dwFlags |= IEEDF_UNICODE_TEXT | IEEDF_UNICODE_NICK;
- evt->time = time(0);
- return evt;
+ return DbEventIsCustomForMsgWindow(dbei);
}
-static EventData* GetTestEvents()
+static void AppendUnicodeToBuffer(CMStringA &buf, const wchar_t *line)
{
- EventData *evt, *firstEvent, *prevEvent;
- firstEvent = prevEvent = evt = GetTestEvent(IEEDF_SENT);
- evt->szNick.w = mir_wstrdup(TranslateT("Me"));
- evt->szText.w = mir_wstrdup(TranslateT("O Lord, bless this Thy hand grenade that with it Thou mayest blow Thine enemies"));
-
- evt = GetTestEvent(IEEDF_SENT);
- evt->szNick.w = mir_wstrdup(TranslateT("Me"));
- evt->szText.w = mir_wstrdup(TranslateT("to tiny bits, in Thy mercy"));
- prevEvent->next = evt;
- prevEvent = evt;
-
- evt = GetTestEvent(0);
- evt->szNick.w = mir_wstrdup(TranslateT("My contact"));
- evt->szText.w = mir_wstrdup(TranslateT("Lorem ipsum dolor sit amet,"));
- prevEvent->next = evt;
- prevEvent = evt;
-
- evt = GetTestEvent(0);
- evt->szNick.w = mir_wstrdup(TranslateT("My contact"));
- evt->szText.w = mir_wstrdup(TranslateT("consectetur adipisicing elit"));
- prevEvent->next = evt;
- prevEvent = evt;
- return firstEvent;
-}
+ buf.Append("{\\uc1 ");
-static void freeEvent(EventData *evt)
-{
- mir_free(evt->szNick.w);
- mir_free(evt->szText.w);
- mir_free(evt);
-}
-
-static int AppendUnicodeOrAnsiiToBufferL(CMStringA &buf, const wchar_t *line, size_t maxLen, BOOL isAnsii)
-{
- if (maxLen == -1)
- maxLen = mir_wstrlen(line);
-
- const wchar_t *maxLine = line + maxLen;
-
- if (isAnsii)
- buf.Append("{");
- else
- buf.Append("{\\uc1 ");
-
- int wasEOL = 0, textCharsCount = 0;
- for (; line < maxLine; line++, textCharsCount++) {
+ int wasEOL = 0;
+ for (; *line; line++) {
wasEOL = 0;
if (*line == '\r' && line[1] == '\n') {
buf.Append("\\line ");
@@ -194,9 +104,6 @@ static int AppendUnicodeOrAnsiiToBufferL(CMStringA &buf, const wchar_t *line, si
else if (*line < 128) {
buf.AppendChar((char)*line);
}
- else if (isAnsii) {
- buf.AppendFormat("\\'%02x", (*line) & 0xFF);
- }
else {
buf.AppendFormat("\\u%d ?", *line);
}
@@ -205,18 +112,6 @@ static int AppendUnicodeOrAnsiiToBufferL(CMStringA &buf, const wchar_t *line, si
buf.AppendChar(' ');
buf.AppendChar('}');
-
- return textCharsCount;
-}
-
-static int AppendAnsiToBuffer(CMStringA &buf, const char *line)
-{
- return AppendUnicodeOrAnsiiToBufferL(buf, _A2T(line), -1, true);
-}
-
-static int AppendUnicodeToBuffer(CMStringA &buf, const wchar_t *line)
-{
- return AppendUnicodeOrAnsiiToBufferL(buf, line, -1, false);
}
// mir_free() the return value
@@ -333,276 +228,22 @@ int isSameDate(time_t time1, time_t time2)
return 0;
}
-static void AppendWithCustomLinks(EventData *evt, int style, CMStringA &buf)
+static void AppendWithCustomLinks(DBEVENTINFO &dbei, int style, CMStringA &buf)
{
- if (evt->szText.w == nullptr)
+ if (dbei.pBlob == nullptr)
return;
- BOOL isAnsii = (evt->dwFlags & IEEDF_UNICODE_TEXT) == 0;
wchar_t *wText;
- size_t len;
- if (isAnsii) {
- len = mir_strlen(evt->szText.a);
- wText = mir_a2u(evt->szText.a);
- }
- else {
- wText = evt->szText.w;
- len = (int)mir_wstrlen(evt->szText.w);
- }
-
- if (len > 0) {
- buf.AppendFormat("%s ", SetToStyle(style));
- AppendUnicodeOrAnsiiToBufferL(buf, wText, len, isAnsii);
- }
-
- if (isAnsii)
- mir_free(wText);
-}
-
-// mir_free() the return value
-char* CMsgDialog::CreateRTFFromEvent(EventData *evt, GlobalMessageData *gdat, LogStreamData *streamData)
-{
- int style, showColon = 0;
- int isGroupBreak = TRUE;
- int highlight = 0;
-
- if ((gdat->flags.bGroupMessages) && evt->dwFlags == LOWORD(m_lastEventType) &&
- evt->eventType == EVENTTYPE_MESSAGE && HIWORD(m_lastEventType) == EVENTTYPE_MESSAGE &&
- (isSameDate(evt->time, m_lastEventTime)) && ((((int)evt->time < m_startTime) == (m_lastEventTime < m_startTime)) || !(evt->dwFlags & IEEDF_READ))) {
- isGroupBreak = FALSE;
- }
-
- CMStringA buf;
- if (!streamData->isFirst && !m_isMixed) {
- if (isGroupBreak || gdat->flags.bMarkFollowups)
- buf.Append("\\par");
- else
- buf.Append("\\line");
- }
-
- if (evt->dwFlags & IEEDF_RTL)
- m_isMixed = 1;
-
- if (!streamData->isFirst && isGroupBreak && (gdat->flags.bDrawLines))
- buf.AppendFormat("\\sl-1\\slmult0\\highlight%d\\cf%d\\fs1 \\par\\sl0", fontOptionsListSize + 4, fontOptionsListSize + 4);
-
- buf.Append((evt->dwFlags & IEEDF_RTL) ? "\\rtlpar" : "\\ltrpar");
-
- if (evt->eventType == EVENTTYPE_MESSAGE)
- highlight = fontOptionsListSize + 2 + ((evt->dwFlags & IEEDF_SENT) ? 1 : 0);
+ if ((dbei.flags & DBEF_UTF) == 0)
+ wText = mir_a2u((char*)dbei.pBlob);
else
- highlight = fontOptionsListSize + 1;
-
- buf.AppendFormat("\\highlight%d\\cf%d", highlight, highlight);
- if (!streamData->isFirst && m_isMixed) {
- if (isGroupBreak)
- buf.Append("\\sl-1 \\par\\sl0");
- else
- buf.Append("\\sl-1 \\line\\sl0");
- }
- streamData->isFirst = FALSE;
- if (m_isMixed) {
- if (evt->dwFlags & IEEDF_RTL)
- buf.Append("\\ltrch\\rtlch");
- else
- buf.Append("\\rtlch\\ltrch");
- }
- if ((gdat->flags.bShowIcons) && isGroupBreak) {
- int i = LOGICON_MSG_NOTICE;
-
- switch (evt->eventType) {
- case EVENTTYPE_MESSAGE:
- if (evt->dwFlags & IEEDF_SENT)
- i = LOGICON_MSG_OUT;
- else
- i = LOGICON_MSG_IN;
- break;
-
- default:
- i = LOGICON_MSG_NOTICE;
- break;
- }
-
- buf.Append("\\fs1 ");
- buf.Append(pLogIconBmpBits[i]);
- buf.AppendChar(' ');
- }
-
- if (gdat->flags.bShowTime && (evt->eventType != EVENTTYPE_MESSAGE ||
- (gdat->flags.bMarkFollowups || isGroupBreak || !(gdat->flags.bGroupMessages)))) {
- wchar_t *timestampString = nullptr;
- if (gdat->flags.bGroupMessages && evt->eventType == EVENTTYPE_MESSAGE) {
- if (isGroupBreak) {
- if (!gdat->flags.bMarkFollowups)
- timestampString = TimestampToString(gdat->flags, evt->time, 0);
- else if (gdat->flags.bShowDate)
- timestampString = TimestampToString(gdat->flags, evt->time, 1);
- }
- else if (gdat->flags.bMarkFollowups)
- timestampString = TimestampToString(gdat->flags, evt->time, 2);
- }
- else timestampString = TimestampToString(gdat->flags, evt->time, 0);
-
- if (timestampString != nullptr) {
- buf.AppendFormat("%s ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME));
- AppendUnicodeToBuffer(buf, timestampString);
- }
- if (evt->eventType != EVENTTYPE_MESSAGE)
- buf.AppendFormat("%s: ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
- showColon = 1;
- }
- if ((!(gdat->flags.bHideNames) && evt->eventType == EVENTTYPE_MESSAGE && isGroupBreak) || evt->eventType == EVENTTYPE_JABBER_CHATSTATES || evt->eventType == EVENTTYPE_JABBER_PRESENCE) {
- if (evt->eventType == EVENTTYPE_MESSAGE) {
- if (showColon)
- buf.AppendFormat(" %s ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME));
- else
- buf.AppendFormat("%s ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME));
- }
- else buf.AppendFormat("%s ", SetToStyle(MSGFONTID_NOTICE));
-
- if (evt->dwFlags & IEEDF_UNICODE_NICK)
- AppendUnicodeToBuffer(buf, evt->szNick.w);
- else
- AppendAnsiToBuffer(buf, evt->szNick.a);
-
- showColon = 1;
- if (evt->eventType == EVENTTYPE_MESSAGE && gdat->flags.bGroupMessages) {
- if (gdat->flags.bMarkFollowups)
- buf.Append("\\par");
- else
- buf.Append("\\line");
- showColon = 0;
- }
- }
+ wText = mir_utf8decodeW((char *)dbei.pBlob);
- if (gdat->flags.bShowTime && gdat->flags.bGroupMessages && gdat->flags.bMarkFollowups && evt->eventType == EVENTTYPE_MESSAGE && isGroupBreak) {
- buf.AppendFormat(" %s ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME));
- AppendUnicodeToBuffer(buf, TimestampToString(gdat->flags, evt->time, 2));
- showColon = 1;
- }
- if (showColon && evt->eventType == EVENTTYPE_MESSAGE) {
- if (evt->dwFlags & IEEDF_RTL)
- buf.AppendFormat("\\~%s: ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
- else
- buf.AppendFormat("%s: ", SetToStyle(evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
- }
- switch (evt->eventType) {
- case EVENTTYPE_JABBER_CHATSTATES:
- case EVENTTYPE_JABBER_PRESENCE:
- case EVENTTYPE_FILE:
- style = MSGFONTID_NOTICE;
+ if (wText) {
buf.AppendFormat("%s ", SetToStyle(style));
- if (evt->eventType == EVENTTYPE_FILE) {
- if (evt->dwFlags & IEEDF_SENT)
- AppendUnicodeToBuffer(buf, TranslateT("File sent"));
- else
- AppendUnicodeToBuffer(buf, TranslateT("File received"));
- AppendUnicodeToBuffer(buf, L":");
- }
- AppendUnicodeToBuffer(buf, L" ");
-
- if (evt->szText.w != nullptr) {
- if (evt->dwFlags & IEEDF_UNICODE_TEXT)
- AppendUnicodeToBuffer(buf, evt->szText.w);
- else
- AppendAnsiToBuffer(buf, evt->szText.a);
- }
- break;
-
- default:
- if (gdat->flags.bMsgOnNewline && showColon)
- buf.Append("\\line");
-
- style = evt->dwFlags & IEEDF_SENT ? MSGFONTID_MYMSG : MSGFONTID_YOURMSG;
- AppendWithCustomLinks(evt, style, buf);
- break;
- }
-
- if (m_isMixed)
- buf.Append("\\par");
-
- m_lastEventTime = evt->time;
- m_lastEventType = MAKELONG(evt->dwFlags, evt->eventType);
- return buf.Detach();
-}
-
-static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
-{
- LogStreamData *dat = (LogStreamData*)dwCookie;
-
- if (dat->buffer == nullptr) {
- dat->bufferOffset = 0;
- switch (dat->stage) {
- case STREAMSTAGE_HEADER:
- dat->buffer = CreateRTFHeader();
- dat->stage = STREAMSTAGE_EVENTS;
- break;
- case STREAMSTAGE_EVENTS:
- if (dat->events != nullptr) {
- EventData *evt = dat->events;
- dat->buffer = nullptr;
- dat->buffer = dat->dlgDat->CreateRTFFromEvent(evt, dat->gdat, dat);
- dat->events = evt->next;
- freeEvent(evt);
- }
- else if (dat->eventsToInsert) {
- do {
- EventData *evt = dat->dlgDat->GetEventFromDB(dat->hContact, dat->hDbEvent);
- dat->buffer = nullptr;
- if (evt != nullptr) {
- dat->buffer = dat->dlgDat->CreateRTFFromEvent(evt, dat->gdat, dat);
- freeEvent(evt);
- }
- if (dat->buffer)
- dat->hDbEventLast = dat->hDbEvent;
- dat->hDbEvent = db_event_next(dat->hContact, dat->hDbEvent);
- if (--dat->eventsToInsert == 0)
- break;
- } while (dat->buffer == nullptr && dat->hDbEvent);
- }
- if (dat->buffer)
- break;
-
- dat->stage = STREAMSTAGE_TAIL;
- __fallthrough;
-
- case STREAMSTAGE_TAIL:
- dat->buffer = CreateRTFTail();
- dat->stage = STREAMSTAGE_STOP;
- break;
- case STREAMSTAGE_STOP:
- *pcb = 0;
- return 0;
- }
- dat->bufferLen = mir_strlen(dat->buffer);
- }
- *pcb = min(cb, LONG(dat->bufferLen - dat->bufferOffset));
- memcpy(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
- dat->bufferOffset += *pcb;
- if (dat->bufferOffset == dat->bufferLen) {
- mir_free(dat->buffer);
- dat->buffer = nullptr;
+ AppendUnicodeToBuffer(buf, wText);
+ mir_free(wText);
}
- return 0;
-}
-
-void StreamInTestEvents(HWND hEditWnd, GlobalMessageData *gdat)
-{
- CMsgDialog *dat = new CMsgDialog(0, false);
-
- LogStreamData streamData = { 0 };
- streamData.isFirst = TRUE;
- streamData.events = GetTestEvents();
- streamData.dlgDat = dat;
- streamData.gdat = gdat;
-
- EDITSTREAM stream = { 0 };
- stream.pfnCallback = LogStreamInEvents;
- stream.dwCookie = (DWORD_PTR)&streamData;
- SendMessage(hEditWnd, EM_STREAMIN, SF_RTF, (LPARAM)&stream);
- SendMessage(hEditWnd, EM_HIDESELECTION, FALSE, 0);
-
- delete dat;
}
#define RTFPICTHEADERMAXSIZE 78
@@ -691,10 +332,21 @@ class CLogWindow : public CRtfLogWindow
{
typedef CRtfLogWindow CSuper;
+ int m_isMixed = 0;
+ int m_lastEventType = -1;
+ time_t m_startTime, m_lastEventTime;
+
public:
CLogWindow(CMsgDialog &pDlg) :
CSuper(pDlg)
- {}
+ {
+ m_lastEventTime = m_startTime = time(0);
+ }
+
+ void AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf) override
+ {
+ AppendUnicodeToBuffer(str, pwszBuf);
+ }
void Attach() override
{
@@ -726,8 +378,191 @@ public:
m_rtf.SendMsg(EM_AUTOURLDETECT, TRUE, 0);
}
+ char* CreateRTFFromEvent(DB::EventInfo &dbei, LogStreamData *streamData)
+ {
+ int style, showColon = 0;
+ int isGroupBreak = TRUE;
+ int highlight = 0;
+ auto *gdat = streamData->gdat;
+
+ if ((gdat->flags.bGroupMessages) && dbei.flags == LOWORD(m_lastEventType) &&
+ dbei.eventType == EVENTTYPE_MESSAGE && HIWORD(m_lastEventType) == EVENTTYPE_MESSAGE &&
+ (isSameDate(dbei.timestamp, m_lastEventTime)) && ((((int)dbei.timestamp < m_startTime) == (m_lastEventTime < m_startTime)) || !(dbei.flags & DBEF_READ))) {
+ isGroupBreak = FALSE;
+ }
+
+ ptrW wszText(DbEvent_GetTextW(&dbei, CP_UTF8)), wszNick;
+
+ // test contact
+ if (m_pDlg.m_hContact != 0) {
+ if (dbei.flags & DBEF_SENT)
+ wszNick = Contact::GetInfo(CNF_DISPLAY, 0, m_pDlg.m_szProto);
+ else
+ wszNick = mir_wstrdup(Clist_GetContactDisplayName(m_pDlg.m_hContact));
+ }
+ else wszNick = mir_wstrdup((dbei.flags & DBEF_SENT) ? TranslateT("Me") : TranslateT("My contact"));
+
+ if (!m_pDlg.m_bUseRtl && Utils_IsRtl(wszText))
+ dbei.flags |= DBEF_RTL;
+
+ CMStringA buf;
+ if (!streamData->isFirst && !m_isMixed) {
+ if (isGroupBreak || gdat->flags.bMarkFollowups)
+ buf.Append("\\par");
+ else
+ buf.Append("\\line");
+ }
+
+ if (dbei.flags & DBEF_RTL)
+ m_isMixed = 1;
+
+ if (!streamData->isFirst && isGroupBreak && (gdat->flags.bDrawLines))
+ buf.AppendFormat("\\sl-1\\slmult0\\highlight%d\\cf%d\\fs1 \\par\\sl0", fontOptionsListSize + 4, fontOptionsListSize + 4);
+
+ buf.Append((dbei.flags & DBEF_RTL) ? "\\rtlpar" : "\\ltrpar");
+
+ if (dbei.eventType == EVENTTYPE_MESSAGE)
+ highlight = fontOptionsListSize + 2 + ((dbei.flags & DBEF_SENT) ? 1 : 0);
+ else
+ highlight = fontOptionsListSize + 1;
+
+ buf.AppendFormat("\\highlight%d\\cf%d", highlight, highlight);
+ if (!streamData->isFirst && m_isMixed) {
+ if (isGroupBreak)
+ buf.Append("\\sl-1 \\par\\sl0");
+ else
+ buf.Append("\\sl-1 \\line\\sl0");
+ }
+ streamData->isFirst = FALSE;
+ if (m_isMixed) {
+ if (dbei.flags & DBEF_RTL)
+ buf.Append("\\ltrch\\rtlch");
+ else
+ buf.Append("\\rtlch\\ltrch");
+ }
+ if ((gdat->flags.bShowIcons) && isGroupBreak) {
+ int i = LOGICON_MSG_NOTICE;
+
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ if (dbei.flags & DBEF_SENT)
+ i = LOGICON_MSG_OUT;
+ else
+ i = LOGICON_MSG_IN;
+ break;
+
+ default:
+ i = LOGICON_MSG_NOTICE;
+ break;
+ }
+
+ buf.Append("\\fs1 ");
+ buf.Append(pLogIconBmpBits[i]);
+ buf.AppendChar(' ');
+ }
+
+ if (gdat->flags.bShowTime && (dbei.eventType != EVENTTYPE_MESSAGE ||
+ (gdat->flags.bMarkFollowups || isGroupBreak || !(gdat->flags.bGroupMessages)))) {
+ wchar_t *timestampString = nullptr;
+ if (gdat->flags.bGroupMessages && dbei.eventType == EVENTTYPE_MESSAGE) {
+ if (isGroupBreak) {
+ if (!gdat->flags.bMarkFollowups)
+ timestampString = TimestampToString(gdat->flags, dbei.timestamp, 0);
+ else if (gdat->flags.bShowDate)
+ timestampString = TimestampToString(gdat->flags, dbei.timestamp, 1);
+ }
+ else if (gdat->flags.bMarkFollowups)
+ timestampString = TimestampToString(gdat->flags, dbei.timestamp, 2);
+ }
+ else timestampString = TimestampToString(gdat->flags, dbei.timestamp, 0);
+
+ if (timestampString != nullptr) {
+ buf.AppendFormat("%s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME));
+ AppendUnicodeToBuffer(buf, timestampString);
+ }
+ if (dbei.eventType != EVENTTYPE_MESSAGE)
+ buf.AppendFormat("%s: ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
+ showColon = 1;
+ }
+ if ((!(gdat->flags.bHideNames) && dbei.eventType == EVENTTYPE_MESSAGE && isGroupBreak) || dbei.eventType == EVENTTYPE_JABBER_CHATSTATES || dbei.eventType == EVENTTYPE_JABBER_PRESENCE) {
+ if (dbei.eventType == EVENTTYPE_MESSAGE) {
+ if (showColon)
+ buf.AppendFormat(" %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME));
+ else
+ buf.AppendFormat("%s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME));
+ }
+ else buf.AppendFormat("%s ", SetToStyle(MSGFONTID_NOTICE));
+
+ AppendUnicodeToBuffer(buf, wszNick);
+
+ showColon = 1;
+ if (dbei.eventType == EVENTTYPE_MESSAGE && gdat->flags.bGroupMessages) {
+ if (gdat->flags.bMarkFollowups)
+ buf.Append("\\par");
+ else
+ buf.Append("\\line");
+ showColon = 0;
+ }
+ }
+
+ if (gdat->flags.bShowTime && gdat->flags.bGroupMessages && gdat->flags.bMarkFollowups && dbei.eventType == EVENTTYPE_MESSAGE && isGroupBreak) {
+ buf.AppendFormat(" %s ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME));
+ AppendUnicodeToBuffer(buf, TimestampToString(gdat->flags, dbei.timestamp, 2));
+ showColon = 1;
+ }
+ if (showColon && dbei.eventType == EVENTTYPE_MESSAGE) {
+ if (dbei.flags & DBEF_RTL)
+ buf.AppendFormat("\\~%s: ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
+ else
+ buf.AppendFormat("%s: ", SetToStyle(dbei.flags & DBEF_SENT ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON));
+ }
+ switch (dbei.eventType) {
+ case EVENTTYPE_JABBER_CHATSTATES:
+ case EVENTTYPE_JABBER_PRESENCE:
+ case EVENTTYPE_FILE:
+ style = MSGFONTID_NOTICE;
+ buf.AppendFormat("%s ", SetToStyle(style));
+ if (dbei.eventType == EVENTTYPE_FILE) {
+ DB::FILE_BLOB blob(dbei);
+ if (blob.isOffline()) {
+ InsertFileLink(buf, streamData->hDbEvent, blob);
+ break;
+ }
+
+ if (dbei.flags & DBEF_SENT)
+ AppendUnicodeToBuffer(buf, TranslateT("File sent"));
+ else
+ AppendUnicodeToBuffer(buf, TranslateT("File received"));
+ AppendUnicodeToBuffer(buf, L":");
+ }
+ AppendUnicodeToBuffer(buf, L" ");
+
+ if (wszText != nullptr)
+ AppendUnicodeToBuffer(buf, wszText);
+ break;
+
+ default:
+ if (gdat->flags.bMsgOnNewline && showColon)
+ buf.Append("\\line");
+
+ style = dbei.flags & DBEF_SENT ? MSGFONTID_MYMSG : MSGFONTID_YOURMSG;
+ AppendWithCustomLinks(dbei, style, buf);
+ break;
+ }
+
+ if (m_isMixed)
+ buf.Append("\\par");
+
+ m_lastEventTime = dbei.timestamp;
+ m_lastEventType = MAKELONG(dbei.flags, dbei.eventType);
+ return buf.Detach();
+ }
+
void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override
{
+ if (!bAppend)
+ m_lastEventType = -1;
+
CHARRANGE oldSel, sel;
m_rtf.SetDraw(false);
m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldSel);
@@ -736,7 +571,7 @@ public:
streamData.hContact = m_pDlg.m_hContact;
streamData.hDbEvent = hDbEventFirst;
streamData.hDbEventLast = m_pDlg.m_hDbEventLast;
- streamData.dlgDat = &m_pDlg;
+ streamData.pLog = this;
streamData.eventsToInsert = count;
streamData.isFirst = bAppend ? m_rtf.GetRichTextLength() == 0 : 1;
streamData.gdat = &g_dat;
@@ -774,7 +609,7 @@ public:
sel.cpMax = m_rtf.GetRichTextLength();
m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
fi.chrg.cpMin = 0;
- m_pDlg.m_isMixed = 0;
+ m_isMixed = 0;
}
m_rtf.SendMsg(EM_STREAMIN, bAppend ? SFF_SELECTION | SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM)&stream);
@@ -817,6 +652,8 @@ public:
m_pDlg.m_hDbEventLast = streamData.hDbEventLast;
}
+ ////////////////////////////////////////////////////////////////////////////////////////
+
void LogEvents(struct LOGINFO *lin, bool bRedraw) override
{
auto *si = m_pDlg.m_si;
@@ -982,6 +819,121 @@ public:
}
};
+/////////////////////////////////////////////////////////////////////////////////////////
+
+const char *szBuiltinEvents[] = {
+ "O Lord, bless this Thy hand grenade that with it Thou mayest blow Thine enemies",
+ "to tiny bits, in Thy mercy",
+ "Lorem ipsum dolor sit amet,",
+ "consectetur adipisicing elit",
+};
+
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
+{
+ LogStreamData *dat = (LogStreamData *)dwCookie;
+
+ if (dat->buffer == nullptr) {
+ dat->bufferOffset = 0;
+ switch (dat->stage) {
+ case STREAMSTAGE_HEADER:
+ dat->buffer = CreateRTFHeader();
+ dat->stage = STREAMSTAGE_EVENTS;
+ break;
+
+ case STREAMSTAGE_EVENTS:
+ // predefined text event
+ if (dat->dbei != nullptr) {
+ dat->dbei->flags = DBEF_UTF | ((dat->eventsToInsert < 2) ? DBEF_SENT : 0);
+ dat->dbei->pBlob = (uint8_t *)TranslateU(szBuiltinEvents[dat->eventsToInsert++]);
+ dat->dbei->cbBlob = (int)mir_strlen((char *)dat->dbei->pBlob);
+ dat->buffer = dat->pLog->CreateRTFFromEvent(*dat->dbei, dat);
+ if (dat->eventsToInsert == _countof(szBuiltinEvents)) {
+ dat->dbei->pBlob = nullptr;
+ dat->dbei = nullptr;
+ }
+ }
+ // usual database event
+ else if (dat->eventsToInsert) {
+ do {
+ dat->buffer = nullptr;
+
+ DB::EventInfo dbei(dat->hDbEvent);
+ if (dbei && DbEventIsShown(dbei)) {
+ dat->buffer = dat->pLog->CreateRTFFromEvent(dbei, dat);
+
+ if (!(dbei.flags & DBEF_SENT) && (dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsCustomForMsgWindow(dbei))) {
+ db_event_markRead(dat->hContact, dat->hDbEvent);
+ g_clistApi.pfnRemoveEvent(dat->hContact, dat->hDbEvent);
+ }
+ else if (dbei.eventType == EVENTTYPE_JABBER_CHATSTATES || dbei.eventType == EVENTTYPE_JABBER_PRESENCE)
+ db_event_markRead(dat->hContact, dat->hDbEvent);
+ }
+
+ if (dat->buffer)
+ dat->hDbEventLast = dat->hDbEvent;
+ dat->hDbEvent = db_event_next(dat->hContact, dat->hDbEvent);
+ if (--dat->eventsToInsert == 0)
+ break;
+ } while (dat->buffer == nullptr && dat->hDbEvent);
+ }
+ if (dat->buffer)
+ break;
+
+ dat->stage = STREAMSTAGE_TAIL;
+ __fallthrough;
+
+ case STREAMSTAGE_TAIL:
+ dat->buffer = CreateRTFTail();
+ dat->stage = STREAMSTAGE_STOP;
+ break;
+
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
+ }
+ dat->bufferLen = mir_strlen(dat->buffer);
+ }
+ *pcb = min(cb, LONG(dat->bufferLen - dat->bufferOffset));
+ memcpy(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
+ dat->bufferOffset += *pcb;
+ if (dat->bufferOffset == dat->bufferLen) {
+ mir_free(dat->buffer);
+ dat->buffer = nullptr;
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void StreamInTestEvents(HWND hEditWnd, GlobalMessageData *gdat)
+{
+ DB::EventInfo dbei;
+ dbei.flags = DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.timestamp = time(0);
+ dbei.szModule = SRMM_MODULE;
+
+ CMsgDialog *dat = new CMsgDialog(0, false);
+
+ LogStreamData streamData = {};
+ streamData.isFirst = TRUE;
+ streamData.dbei = &dbei;
+ streamData.pLog = new CLogWindow(*dat);
+ streamData.gdat = gdat;
+
+ EDITSTREAM stream = { 0 };
+ stream.pfnCallback = LogStreamInEvents;
+ stream.dwCookie = (DWORD_PTR)&streamData;
+ SendMessage(hEditWnd, EM_STREAMIN, SF_RTF, (LPARAM)&stream);
+ SendMessage(hEditWnd, EM_HIDESELECTION, FALSE, 0);
+
+ delete streamData.pLog;
+ delete dat;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module entry point
+
CSrmmLogWindow* logBuilder(CMsgDialog &pDlg)
{
return new CLogWindow(pDlg);
diff --git a/plugins/Scriver/src/msgs.cpp b/plugins/Scriver/src/msgs.cpp
index 498dfe43e3..b3e0026f77 100644
--- a/plugins/Scriver/src/msgs.cpp
+++ b/plugins/Scriver/src/msgs.cpp
@@ -91,7 +91,7 @@ static int MessageEventAdded(WPARAM hContact, LPARAM hDbEvent)
if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ))
return 0;
- if (dbei.flags & DBEF_SENT || !DbEventIsMessageOrCustom(&dbei))
+ if (dbei.flags & DBEF_SENT || !DbEventIsMessageOrCustom(dbei))
return 0;
/* does a window for the contact exist? */
@@ -239,7 +239,7 @@ static void RestoreUnreadMessageAlerts(void)
DBEVENTINFO dbei = {};
if (db_event_get(hDbEvent, &dbei))
continue;
- if (dbei.markedRead() || !DbEventIsMessageOrCustom(&dbei) || !Proto_GetBaseAccountName(hContact))
+ if (dbei.markedRead() || !DbEventIsMessageOrCustom(dbei) || !Proto_GetBaseAccountName(hContact))
continue;
int windowAlreadyExists = Srmm_FindWindow(hContact) != nullptr;
diff --git a/plugins/Scriver/src/msgs.h b/plugins/Scriver/src/msgs.h
index 3daa951eea..ce0e5c082c 100644
--- a/plugins/Scriver/src/msgs.h
+++ b/plugins/Scriver/src/msgs.h
@@ -29,23 +29,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MSGERROR_RETRY 1
#define MSGERROR_DONE 2
-struct EventData
-{
- int cbSize;
- int iType;
- uint32_t dwFlags;
- const char *fontName;
- int fontSize;
- int fontStyle;
- COLORREF color;
- MAllStrings szNick; // Nick, usage depends on type of event
- MAllStrings szText; // Text, usage depends on type of event
- uint32_t time;
- uint32_t eventType;
- BOOL custom;
- EventData *next;
-};
-
struct ToolbarButton
{
wchar_t *name;
@@ -97,9 +80,6 @@ class CMsgDialog : public CSrmmBaseDialog
HICON m_hStatusIcon, m_hStatusIconBig, m_hStatusIconOverlay;
char *m_szProto;
- time_t m_startTime, m_lastEventTime;
- int m_lastEventType;
- int m_isMixed;
bool m_bUseRtl;
HBITMAP m_hbmpAvatarPic;
@@ -192,9 +172,6 @@ public:
wchar_t *m_wszInitialText;
- char* CreateRTFFromEvent(EventData *evt, GlobalMessageData *gdat, struct LogStreamData *streamData);
- EventData *GetEventFromDB(MCONTACT hContact, MEVENT hDbEvent);
-
void Reattach(HWND hwndContainer);
};
@@ -216,8 +193,8 @@ public:
#define EVENTTYPE_JABBER_PRESENCE 2001
bool DbEventIsShown(const DBEVENTINFO &dbei);
-bool DbEventIsCustomForMsgWindow(const DBEVENTINFO *dbei);
-bool DbEventIsMessageOrCustom(const DBEVENTINFO *dbei);
+bool DbEventIsCustomForMsgWindow(const DBEVENTINFO &dbei);
+bool DbEventIsMessageOrCustom(const DBEVENTINFO &dbei);
void LoadMsgLogIcons(void);
void FreeMsgLogIcons(void);
int IsAutoPopup(MCONTACT hContact);
diff --git a/plugins/Scriver/src/msgutils.cpp b/plugins/Scriver/src/msgutils.cpp
index dff0e00e10..b2abbe2a55 100644
--- a/plugins/Scriver/src/msgutils.cpp
+++ b/plugins/Scriver/src/msgutils.cpp
@@ -28,7 +28,6 @@ void CMsgDialog::ClearLog()
CSuper::ClearLog();
m_hDbEventFirst = 0;
- m_lastEventType = -1;
}
void CMsgDialog::CloseTab()
@@ -102,7 +101,7 @@ void CMsgDialog::EventAdded(MEVENT hDbEvent, const DBEVENTINFO &dbei)
else
SendMessage(m_hwnd, DM_REMAKELOG, 0, 0);
- if (!(dbei.flags & DBEF_SENT) && !DbEventIsCustomForMsgWindow(&dbei)) {
+ if (!(dbei.flags & DBEF_SENT) && !DbEventIsCustomForMsgWindow(dbei)) {
if (!bIsActive) {
m_iShowUnread = 1;
UpdateIcon();
@@ -124,7 +123,7 @@ bool CMsgDialog::GetFirstEvent()
if (m_hDbEventFirst != 0) {
DBEVENTINFO dbei = {};
db_event_get(m_hDbEventFirst, &dbei);
- if (DbEventIsMessageOrCustom(&dbei) && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT))
+ if (DbEventIsMessageOrCustom(dbei) && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT))
notifyUnread = true;
}
diff --git a/plugins/TabSRMM/src/msgdlgutils.cpp b/plugins/TabSRMM/src/msgdlgutils.cpp
index eff4705074..f3ed376965 100644
--- a/plugins/TabSRMM/src/msgdlgutils.cpp
+++ b/plugins/TabSRMM/src/msgdlgutils.cpp
@@ -320,6 +320,9 @@ bool IsStringValidLink(wchar_t *pszText)
if (pszText[0] == '\\' && pszText[1] == '\\')
return true;
+ if (!mir_wstrncmp(pszText, L"ofile:", 6))
+ return true;
+
if (mir_wstrlen(pszText) < 5 || wcschr(pszText, '"'))
return false;
diff --git a/plugins/TabSRMM/src/msglog.cpp b/plugins/TabSRMM/src/msglog.cpp
index 3499e97cc3..36c76a92ad 100644
--- a/plugins/TabSRMM/src/msglog.cpp
+++ b/plugins/TabSRMM/src/msglog.cpp
@@ -94,7 +94,7 @@ struct LogStreamData
int eventsToInsert;
int isEmpty;
int isAppend;
- CMsgDialog *dlgDat;
+ class CLogWindow *pLog;
DBEVENTINFO *dbei;
};
@@ -234,12 +234,11 @@ static int TSAPI GetColorIndex(char *rtffont)
return 0;
}
-static int AppendUnicodeToBuffer(CMStringA &str, const wchar_t *line, int mode)
+static void AppendUnicodeToBuffer(CMStringA &str, const wchar_t *line, int mode)
{
str.Append("{\\uc1 ");
- int textCharsCount = 0;
- for (; *line; line++, textCharsCount++) {
+ for (; *line; line++) {
if (*line == 127 && line[1] != 0) {
wchar_t code = line[2];
if (((code == '0' || code == '1') && line[3] == ' ') || (line[1] == 'c' && code == 'x')) {
@@ -302,17 +301,19 @@ static int AppendUnicodeToBuffer(CMStringA &str, const wchar_t *line, int mode)
}
str.AppendChar('}');
- return textCharsCount;
}
/////////////////////////////////////////////////////////////////////////////////////////
+// mir_free() the return value
-static void Build_RTF_Header(CMStringA &str, CMsgDialog *dat)
+static char* CreateRTFHeader(CLogWindow *pLog)
{
int i;
- LOGFONTW *logFonts = dat->m_pContainer->m_theme.logFonts;
- COLORREF *fontColors = dat->m_pContainer->m_theme.fontColors;
- TLogTheme *theme = &dat->m_pContainer->m_theme;
+ CMStringA str;
+ auto &dat = pLog->GetDialog();
+ TLogTheme *theme = &dat.m_pContainer->m_theme;
+ LOGFONTW *logFonts = theme->logFonts;
+ COLORREF *fontColors = theme->fontColors;
str.Append("{\\rtf1\\ansi\\deff0{\\fonttbl");
@@ -359,15 +360,8 @@ static void Build_RTF_Header(CMStringA &str, CMsgDialog *dat)
str.AppendFormat("}");
// indent
- if (!(dat->m_dwFlags & MWF_LOG_INDENT))
+ if (!(dat.m_dwFlags & MWF_LOG_INDENT))
str.AppendFormat("\\li%u\\ri%u\\fi%u\\tx%u", 2 * 15, 2 * 15, 0, 70 * 15);
-}
-
-// mir_free() the return value
-static char* CreateRTFHeader(CMsgDialog *dat)
-{
- CMStringA str;
- Build_RTF_Header(str, dat);
return str.Detach();
}
@@ -425,7 +419,212 @@ bool DbEventIsForMsgWindow(const DBEVENTINFO *dbei)
return et && (et->flags & DETF_MSGWINDOW);
}
-static char* Template_CreateRTFFromDbEvent(CMsgDialog *dat, MCONTACT hContact, MEVENT hDbEvent, LogStreamData *streamData)
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
+{
+ LogStreamData *dat = (LogStreamData*)dwCookie;
+
+ if (dat->buffer == nullptr) {
+ dat->bufferOffset = 0;
+ switch (dat->stage) {
+ case STREAMSTAGE_HEADER:
+ mir_free(dat->buffer);
+ dat->buffer = CreateRTFHeader(dat->pLog);
+ dat->stage = STREAMSTAGE_EVENTS;
+ break;
+
+ case STREAMSTAGE_EVENTS:
+ if (dat->eventsToInsert) {
+ do {
+ mir_free(dat->buffer);
+ dat->buffer = dat->pLog->CreateRTFFromDbEvent(dat);
+ if (dat->buffer)
+ dat->hDbEventLast = dat->hDbEvent;
+ dat->hDbEvent = db_event_next(dat->hContact, dat->hDbEvent);
+ if (--dat->eventsToInsert == 0)
+ break;
+ } while (dat->buffer == nullptr && dat->hDbEvent);
+
+ if (dat->buffer)
+ break;
+ }
+ dat->stage = STREAMSTAGE_TAIL;
+ __fallthrough;
+
+ case STREAMSTAGE_TAIL:
+ mir_free(dat->buffer);
+ dat->buffer = CreateRTFTail();
+ dat->stage = STREAMSTAGE_STOP;
+ break;
+
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
+ }
+ dat->bufferLen = (int)mir_strlen(dat->buffer);
+ }
+ *pcb = min(cb, dat->bufferLen - dat->bufferOffset);
+ memcpy(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
+ dat->bufferOffset += *pcb;
+ if (dat->bufferOffset == dat->bufferLen)
+ replaceStr(dat->buffer, nullptr);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CLogWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ bool isCtrl, isShift, isAlt;
+
+ switch (msg) {
+ case WM_KILLFOCUS:
+ if (wParam != (WPARAM)m_rtf.GetHwnd() && 0 != wParam) {
+ CHARRANGE cr;
+ m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&cr);
+ if (cr.cpMax != cr.cpMin) {
+ cr.cpMin = cr.cpMax;
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&cr);
+ }
+ }
+ break;
+
+ case WM_CHAR:
+ m_pDlg.KbdState(isShift, isCtrl, isAlt);
+ if (wParam == 0x03 && isCtrl) // Ctrl+C
+ return m_pDlg.WMCopyHandler(msg, wParam, lParam);
+ if (wParam == 0x11 && isCtrl) // Ctrl+Q
+ m_pDlg.m_btnQuote.Click();
+ break;
+
+ case WM_LBUTTONUP:
+ if (m_pDlg.isChat() && g_Settings.bClickableNicks) {
+ POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+ CheckCustomLink(m_rtf.GetHwnd(), &pt, msg, wParam, lParam, TRUE);
+ }
+
+ if (g_plugin.bAutoCopy) {
+ CHARRANGE sel;
+ SendMessage(m_rtf.GetHwnd(), EM_EXGETSEL, 0, (LPARAM)&sel);
+ if (sel.cpMin != sel.cpMax) {
+ SendMessage(m_rtf.GetHwnd(), WM_COPY, 0, 0);
+ sel.cpMin = sel.cpMax;
+ SendMessage(m_rtf.GetHwnd(), EM_EXSETSEL, 0, (LPARAM)&sel);
+ SetFocus(m_pDlg.m_message.GetHwnd());
+ }
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ if (m_pDlg.isChat() && g_Settings.bClickableNicks) {
+ POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+ CheckCustomLink(m_rtf.GetHwnd(), &pt, msg, wParam, lParam, TRUE);
+ }
+ break;
+
+ case WM_SETCURSOR:
+ if (g_Settings.bClickableNicks && m_pDlg.isChat() && (LOWORD(lParam) == HTCLIENT)) {
+ POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(m_rtf.GetHwnd(), &pt);
+ if (CheckCustomLink(m_rtf.GetHwnd(), &pt, msg, wParam, lParam, FALSE))
+ return TRUE;
+ }
+ break;
+
+ case WM_SYSKEYUP:
+ if (wParam == VK_MENU) {
+ m_pDlg.ProcessHotkeysByMsgFilter(m_rtf, msg, wParam, lParam);
+ return 0;
+ }
+ break;
+
+ case WM_SYSKEYDOWN:
+ m_pDlg.m_bkeyProcessed = false;
+ if (m_pDlg.ProcessHotkeysByMsgFilter(m_rtf, msg, wParam, lParam)) {
+ m_pDlg.m_bkeyProcessed = true;
+ return 0;
+ }
+ break;
+
+ case WM_SYSCHAR:
+ if (m_pDlg.m_bkeyProcessed) {
+ m_pDlg.m_bkeyProcessed = false;
+ return 0;
+ }
+ break;
+
+ case WM_KEYDOWN:
+ m_pDlg.KbdState(isShift, isCtrl, isAlt);
+ if (wParam == VK_INSERT && isCtrl)
+ return m_pDlg.WMCopyHandler(msg, wParam, lParam);
+
+ if (wParam == 0x57 && isCtrl) { // ctrl-w (close window)
+ PostMessage(m_pDlg.m_hwnd, WM_CLOSE, 0, 1);
+ return TRUE;
+ }
+
+ break;
+
+ case WM_COPY:
+ return m_pDlg.WMCopyHandler(msg, wParam, lParam);
+
+ case WM_NCCALCSIZE:
+ return CSkin::NcCalcRichEditFrame(m_rtf.GetHwnd(), &m_pDlg, ID_EXTBKHISTORY, msg, wParam, lParam, stubLogProc);
+
+ case WM_NCPAINT:
+ return CSkin::DrawRichEditFrame(m_rtf.GetHwnd(), &m_pDlg, ID_EXTBKHISTORY, msg, wParam, lParam, stubLogProc);
+
+ case WM_CONTEXTMENU:
+ if (!m_pDlg.isChat()) {
+ POINT pt;
+ if (lParam == 0xFFFFFFFF) {
+ CHARRANGE sel;
+ m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
+ m_rtf.SendMsg(EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax);
+ ClientToScreen(m_rtf.GetHwnd(), &pt);
+ }
+ else {
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(lParam);
+ }
+
+ m_pDlg.ShowPopupMenu(m_rtf, pt);
+ return TRUE;
+ }
+ }
+
+ return CSuper::WndProc(msg, wParam, lParam);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogWindow::AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf)
+{
+ AppendUnicodeToBuffer(str, pwszBuf, 0);
+}
+
+void CLogWindow::Attach()
+{
+ CSuper::Attach();
+
+ m_rtf.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
+ m_rtf.SendMsg(EM_AUTOURLDETECT, TRUE, 0);
+ m_rtf.SendMsg(EM_EXLIMITTEXT, 0, 0x7FFFFFFF);
+ m_rtf.SendMsg(EM_SETUNDOLIMIT, 0, 0);
+ m_rtf.SendMsg(EM_HIDESELECTION, TRUE, 0);
+ m_rtf.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_LINK);
+ m_rtf.SendMsg(EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
+ m_rtf.SendMsg(EM_SETLANGOPTIONS, 0, m_rtf.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOFONTSIZEADJUST);
+ m_rtf.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+char* CLogWindow::CreateRTFFromDbEvent(LogStreamData *streamData)
{
HANDLE hTimeZone = nullptr;
struct tm event_time = { 0 };
@@ -437,19 +636,20 @@ static char* Template_CreateRTFFromDbEvent(CMsgDialog *dat, MCONTACT hContact, M
memcpy(&dbei, streamData->dbei, sizeof(DBEVENTINFO));
else {
dbei.cbBlob = -1;
- db_event_get(hDbEvent, &dbei);
+ db_event_get(streamData->hDbEvent, &dbei);
if (!DbEventIsShown(&dbei))
return nullptr;
}
+ auto *dat = &m_pDlg;
if (dbei.eventType == EVENTTYPE_MESSAGE && !dbei.markedRead())
dat->m_cache->updateStats(TSessionStats::SET_LAST_RCV, mir_strlen((char *)dbei.pBlob));
BOOL isSent = (dbei.flags & DBEF_SENT);
BOOL bIsStatusChangeEvent = IsStatusEvent(dbei.eventType);
if (!isSent && (bIsStatusChangeEvent || dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei))) {
- db_event_markRead(hContact, hDbEvent);
- g_clistApi.pfnRemoveEvent(hContact, hDbEvent);
+ db_event_markRead(streamData->hContact, streamData->hDbEvent);
+ g_clistApi.pfnRemoveEvent(streamData->hContact, streamData->hDbEvent);
}
CMStringW msg(ptrW(DbEvent_GetTextW(&dbei, CP_UTF8)));
@@ -549,7 +749,7 @@ static char* Template_CreateRTFFromDbEvent(CMsgDialog *dat, MCONTACT hContact, M
memmove(dat->m_hHistoryEvents, &dat->m_hHistoryEvents[1], sizeof(HANDLE) * (dat->m_maxHistory - 1));
dat->m_curHistory--;
}
- dat->m_hHistoryEvents[dat->m_curHistory++] = hDbEvent;
+ dat->m_hHistoryEvents[dat->m_curHistory++] = streamData->hDbEvent;
}
str.Append("\\ul0\\b0\\i0\\v0 ");
@@ -851,8 +1051,13 @@ static char* Template_CreateRTFFromDbEvent(CMsgDialog *dat, MCONTACT hContact, M
str.Append(GetRTFFont(iFontIDOffset + (isSent ? MSGFONTID_MYMISC : MSGFONTID_YOURMISC)));
str.AppendChar(' ');
}
-
- AppendUnicodeToBuffer(str, ptrW(DbEvent_GetTextW(&dbei, CP_ACP)), 0);
+ {
+ DB::FILE_BLOB blob(dbei);
+ if (blob.isOffline())
+ InsertFileLink(str, streamData->hDbEvent, blob);
+ else
+ AppendUnicodeToBuffer(str, ptrW(DbEvent_GetTextW(&dbei, CP_ACP)), 0);
+ }
break;
default:
@@ -981,7 +1186,7 @@ skip:
}
if (dat->m_hHistoryEvents)
- str.AppendFormat(dat->m_szMicroLf, MSGDLGFONTCOUNT + 1 + ((isSent) ? 1 : 0), hDbEvent);
+ str.AppendFormat(dat->m_szMicroLf, MSGDLGFONTCOUNT + 1 + ((isSent) ? 1 : 0), streamData->hDbEvent);
str.Append("\\par");
@@ -993,204 +1198,8 @@ skip:
return str.Detach();
}
-static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
-{
- LogStreamData *dat = (LogStreamData*)dwCookie;
-
- if (dat->buffer == nullptr) {
- dat->bufferOffset = 0;
- switch (dat->stage) {
- case STREAMSTAGE_HEADER:
- mir_free(dat->buffer);
- dat->buffer = CreateRTFHeader(dat->dlgDat);
- dat->stage = STREAMSTAGE_EVENTS;
- break;
-
- case STREAMSTAGE_EVENTS:
- if (dat->eventsToInsert) {
- do {
- mir_free(dat->buffer);
- dat->buffer = Template_CreateRTFFromDbEvent(dat->dlgDat, dat->hContact, dat->hDbEvent, dat);
- if (dat->buffer)
- dat->hDbEventLast = dat->hDbEvent;
- dat->hDbEvent = db_event_next(dat->hContact, dat->hDbEvent);
- if (--dat->eventsToInsert == 0)
- break;
- } while (dat->buffer == nullptr && dat->hDbEvent);
-
- if (dat->buffer)
- break;
- }
- dat->stage = STREAMSTAGE_TAIL;
- __fallthrough;
-
- case STREAMSTAGE_TAIL:
- mir_free(dat->buffer);
- dat->buffer = CreateRTFTail();
- dat->stage = STREAMSTAGE_STOP;
- break;
-
- case STREAMSTAGE_STOP:
- *pcb = 0;
- return 0;
- }
- dat->bufferLen = (int)mir_strlen(dat->buffer);
- }
- *pcb = min(cb, dat->bufferLen - dat->bufferOffset);
- memcpy(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
- dat->bufferOffset += *pcb;
- if (dat->bufferOffset == dat->bufferLen)
- replaceStr(dat->buffer, nullptr);
- return 0;
-}
-
/////////////////////////////////////////////////////////////////////////////////////////
-INT_PTR CLogWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- bool isCtrl, isShift, isAlt;
-
- switch (msg) {
- case WM_KILLFOCUS:
- if (wParam != (WPARAM)m_rtf.GetHwnd() && 0 != wParam) {
- CHARRANGE cr;
- m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&cr);
- if (cr.cpMax != cr.cpMin) {
- cr.cpMin = cr.cpMax;
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&cr);
- }
- }
- break;
-
- case WM_CHAR:
- m_pDlg.KbdState(isShift, isCtrl, isAlt);
- if (wParam == 0x03 && isCtrl) // Ctrl+C
- return m_pDlg.WMCopyHandler(msg, wParam, lParam);
- if (wParam == 0x11 && isCtrl) // Ctrl+Q
- m_pDlg.m_btnQuote.Click();
- break;
-
- case WM_LBUTTONUP:
- if (m_pDlg.isChat() && g_Settings.bClickableNicks) {
- POINT pt = { LOWORD(lParam), HIWORD(lParam) };
- CheckCustomLink(m_rtf.GetHwnd(), &pt, msg, wParam, lParam, TRUE);
- }
-
- if (g_plugin.bAutoCopy) {
- CHARRANGE sel;
- SendMessage(m_rtf.GetHwnd(), EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin != sel.cpMax) {
- SendMessage(m_rtf.GetHwnd(), WM_COPY, 0, 0);
- sel.cpMin = sel.cpMax;
- SendMessage(m_rtf.GetHwnd(), EM_EXSETSEL, 0, (LPARAM)&sel);
- SetFocus(m_pDlg.m_message.GetHwnd());
- }
- }
- break;
-
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- case WM_RBUTTONUP:
- case WM_RBUTTONDOWN:
- case WM_RBUTTONDBLCLK:
- if (m_pDlg.isChat() && g_Settings.bClickableNicks) {
- POINT pt = { LOWORD(lParam), HIWORD(lParam) };
- CheckCustomLink(m_rtf.GetHwnd(), &pt, msg, wParam, lParam, TRUE);
- }
- break;
-
- case WM_SETCURSOR:
- if (g_Settings.bClickableNicks && m_pDlg.isChat() && (LOWORD(lParam) == HTCLIENT)) {
- POINT pt;
- GetCursorPos(&pt);
- ScreenToClient(m_rtf.GetHwnd(), &pt);
- if (CheckCustomLink(m_rtf.GetHwnd(), &pt, msg, wParam, lParam, FALSE))
- return TRUE;
- }
- break;
-
- case WM_SYSKEYUP:
- if (wParam == VK_MENU) {
- m_pDlg.ProcessHotkeysByMsgFilter(m_rtf, msg, wParam, lParam);
- return 0;
- }
- break;
-
- case WM_SYSKEYDOWN:
- m_pDlg.m_bkeyProcessed = false;
- if (m_pDlg.ProcessHotkeysByMsgFilter(m_rtf, msg, wParam, lParam)) {
- m_pDlg.m_bkeyProcessed = true;
- return 0;
- }
- break;
-
- case WM_SYSCHAR:
- if (m_pDlg.m_bkeyProcessed) {
- m_pDlg.m_bkeyProcessed = false;
- return 0;
- }
- break;
-
- case WM_KEYDOWN:
- m_pDlg.KbdState(isShift, isCtrl, isAlt);
- if (wParam == VK_INSERT && isCtrl)
- return m_pDlg.WMCopyHandler(msg, wParam, lParam);
-
- if (wParam == 0x57 && isCtrl) { // ctrl-w (close window)
- PostMessage(m_pDlg.m_hwnd, WM_CLOSE, 0, 1);
- return TRUE;
- }
-
- break;
-
- case WM_COPY:
- return m_pDlg.WMCopyHandler(msg, wParam, lParam);
-
- case WM_NCCALCSIZE:
- return CSkin::NcCalcRichEditFrame(m_rtf.GetHwnd(), &m_pDlg, ID_EXTBKHISTORY, msg, wParam, lParam, stubLogProc);
-
- case WM_NCPAINT:
- return CSkin::DrawRichEditFrame(m_rtf.GetHwnd(), &m_pDlg, ID_EXTBKHISTORY, msg, wParam, lParam, stubLogProc);
-
- case WM_CONTEXTMENU:
- if (!m_pDlg.isChat()) {
- POINT pt;
- if (lParam == 0xFFFFFFFF) {
- CHARRANGE sel;
- m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
- m_rtf.SendMsg(EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax);
- ClientToScreen(m_rtf.GetHwnd(), &pt);
- }
- else {
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
- }
-
- m_pDlg.ShowPopupMenu(m_rtf, pt);
- return TRUE;
- }
- }
-
- return CSuper::WndProc(msg, wParam, lParam);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CLogWindow::Attach()
-{
- CSuper::Attach();
-
- m_rtf.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
- m_rtf.SendMsg(EM_AUTOURLDETECT, TRUE, 0);
- m_rtf.SendMsg(EM_EXLIMITTEXT, 0, 0x7FFFFFFF);
- m_rtf.SendMsg(EM_SETUNDOLIMIT, 0, 0);
- m_rtf.SendMsg(EM_HIDESELECTION, TRUE, 0);
- m_rtf.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_LINK);
- m_rtf.SendMsg(EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
- m_rtf.SendMsg(EM_SETLANGOPTIONS, 0, m_rtf.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOFONTSIZEADJUST);
- m_rtf.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
-}
-
void CLogWindow::LogEvents(MEVENT hDbEventFirst, int count, bool fAppend)
{
LogEvents(hDbEventFirst, count, fAppend, nullptr);
@@ -1228,7 +1237,7 @@ void CLogWindow::LogEvents(MEVENT hDbEventFirst, int count, bool fAppend, DBEVEN
LogStreamData streamData = { 0 };
streamData.hContact = m_pDlg.m_hContact;
streamData.hDbEvent = hDbEventFirst;
- streamData.dlgDat = &m_pDlg;
+ streamData.pLog = this;
streamData.eventsToInsert = count;
streamData.isEmpty = fAppend ? GetWindowTextLength(m_rtf.GetHwnd()) == 0 : 1;
streamData.dbei = dbei_s;
@@ -1306,6 +1315,8 @@ void CLogWindow::LogEvents(MEVENT hDbEventFirst, int count, bool fAppend, DBEVEN
mir_free(streamData.buffer);
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CLogWindow::LogEvents(LOGINFO *lin, bool bRedraw)
{
auto *si = m_pDlg.m_si;
@@ -1460,6 +1471,8 @@ void CLogWindow::LogEvents(LOGINFO *lin, bool bRedraw)
}
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CLogWindow::ReplaceIcons(LONG startAt, int fAppend, BOOL isSent)
{
wchar_t trbuffer[40];
@@ -1582,6 +1595,8 @@ void CLogWindow::ReplaceIcons(LONG startAt, int fAppend, BOOL isSent)
}
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CLogWindow::ScrollToBottom()
{
ScrollToBottom(false, false);
@@ -1606,6 +1621,8 @@ void CLogWindow::ScrollToBottom(bool bImmediate, bool bRedraw)
InvalidateRect(m_rtf.GetHwnd(), nullptr, FALSE);
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CLogWindow::UpdateOptions()
{
COLORREF colour = m_pDlg.isChat() ? g_Settings.crLogBackground : db_get_dw(0, FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR);
@@ -1633,6 +1650,9 @@ void CLogWindow::UpdateOptions()
}
}
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module entry point
+
CSrmmLogWindow *logBuilder(CMsgDialog &pDlg)
{
return new CLogWindow(pDlg);
diff --git a/plugins/TabSRMM/src/msgs.h b/plugins/TabSRMM/src/msgs.h
index 6d05b1a25f..d3bdec4c3d 100644
--- a/plugins/TabSRMM/src/msgs.h
+++ b/plugins/TabSRMM/src/msgs.h
@@ -371,42 +371,6 @@ struct TContainerData : public MZeroedObject
};
/////////////////////////////////////////////////////////////////////////////////////////
-// CLogWindow - built-in log window
-
-class CLogWindow : public CRtfLogWindow
-{
- typedef CRtfLogWindow CSuper;
-
-public:
- CLogWindow(CMsgDialog &pDlg) :
- CSuper(pDlg)
- {
- }
-
- void Attach() override;
- void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override;
- void LogEvents(struct LOGINFO *, bool) override;
- void ScrollToBottom() override;
- void UpdateOptions() override;
-
- void DisableStaticEdge()
- {
- SetWindowLongPtr(m_rtf.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_rtf.GetHwnd(), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
- }
-
- char* GetRichTextRtf(bool bText, bool bSelection)
- {
- return m_rtf.GetRichTextRtf(bText, bSelection);
- }
-
- void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend, DBEVENTINFO *dbei);
- void ReplaceIcons(LONG startAt, int fAppend, BOOL isSent);
- void ScrollToBottom(bool, bool);
-
- INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam) override;
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
// CMsgDialog - SRMM window class
class CMsgDialog : public CSrmmBaseDialog
@@ -711,6 +675,44 @@ public:
extern LIST<void> g_arUnreadWindows;
+/////////////////////////////////////////////////////////////////////////////////////////
+// CLogWindow - built-in log window
+
+class CLogWindow : public CRtfLogWindow
+{
+ typedef CRtfLogWindow CSuper;
+
+public:
+ CLogWindow(CMsgDialog &pDlg) :
+ CSuper(pDlg)
+ {}
+
+ char *CreateRTFFromDbEvent(struct LogStreamData *streamData);
+
+ void AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf) override;
+ void Attach() override;
+ void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override;
+ void LogEvents(struct LOGINFO *, bool) override;
+ void ScrollToBottom() override;
+ void UpdateOptions() override;
+
+ void DisableStaticEdge()
+ {
+ SetWindowLongPtr(m_rtf.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_rtf.GetHwnd(), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+ }
+
+ char *GetRichTextRtf(bool bText, bool bSelection)
+ {
+ return m_rtf.GetRichTextRtf(bText, bSelection);
+ }
+
+ void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend, DBEVENTINFO *dbei);
+ void ReplaceIcons(LONG startAt, int fAppend, BOOL isSent);
+ void ScrollToBottom(bool, bool);
+
+ INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam) override;
+};
+
#define MESSAGE_WINDOW_DATA_SIZE offsetof(_MessageWindowData, hdbEventFirst);
/*
diff --git a/src/core/stdmsg/src/chat_window.cpp b/src/core/stdmsg/src/chat_window.cpp
index a8806f0cbc..c78e3d1d0e 100644
--- a/src/core/stdmsg/src/chat_window.cpp
+++ b/src/core/stdmsg/src/chat_window.cpp
@@ -107,110 +107,6 @@ void CMsgDialog::UpdateStatusBar()
/////////////////////////////////////////////////////////////////////////////////////////
-void CLogWindow::LogEvents(LOGINFO *lin, bool bRedraw)
-{
- auto *si = m_pDlg.m_si;
- if (lin == nullptr || si == nullptr)
- return;
-
- if (!bRedraw && si->iType == GCW_CHATROOM && (m_pDlg.m_iLogFilterFlags & lin->iType) == 0)
- return;
-
- LOGSTREAMDATA streamData;
- memset(&streamData, 0, sizeof(streamData));
- streamData.hwnd = m_rtf.GetHwnd();
- streamData.si = si;
- streamData.lin = lin;
- streamData.bStripFormat = FALSE;
-
- bool bFlag = false;
-
- EDITSTREAM stream = {};
- stream.pfnCallback = Srmm_LogStreamCallback;
- stream.dwCookie = (DWORD_PTR)& streamData;
-
- SCROLLINFO scroll;
- scroll.cbSize = sizeof(SCROLLINFO);
- scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
- GetScrollInfo(m_rtf.GetHwnd(), SB_VERT, &scroll);
-
- POINT point = {};
- m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point);
-
- // do not scroll to bottom if there is a selection
- CHARRANGE oldsel, sel;
- m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldsel);
- if (oldsel.cpMax != oldsel.cpMin)
- m_rtf.SetDraw(false);
-
- //set the insertion point at the bottom
- sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
-
- // fix for the indent... must be a M$ bug
- if (sel.cpMax == 0)
- bRedraw = TRUE;
-
- // should the event(s) be appended to the current log
- WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF;
-
- //get the number of pixels per logical inch
- if (bRedraw) {
- HDC hdc = GetDC(nullptr);
- g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
- g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
- ReleaseDC(nullptr, hdc);
- m_rtf.SetDraw(false);
- bFlag = true;
- }
-
- // stream in the event(s)
- streamData.lin = lin;
- streamData.bRedraw = bRedraw;
- m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream);
-
- // do smileys
- if (g_plugin.bSmileyInstalled && (bRedraw || (lin->ptszText && lin->iType != GC_EVENT_JOIN && lin->iType != GC_EVENT_NICK && lin->iType != GC_EVENT_ADDSTATUS && lin->iType != GC_EVENT_REMOVESTATUS))) {
- CHARRANGE newsel;
- newsel.cpMax = -1;
- newsel.cpMin = sel.cpMin;
- if (newsel.cpMin < 0)
- newsel.cpMin = 0;
-
- SMADD_RICHEDIT3 sm = {};
- sm.cbSize = sizeof(sm);
- sm.hwndRichEditControl = m_rtf.GetHwnd();
- sm.Protocolname = si->pszModule;
- sm.rangeToReplace = bRedraw ? nullptr : &newsel;
- sm.disableRedraw = TRUE;
- sm.hContact = si->hContact;
- CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm);
- }
-
- // scroll log to bottom if the log was previously scrolled to bottom, else restore old position
- if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)
- ScrollToBottom();
- else
- m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point);
-
- // do we need to restore the selection
- if (oldsel.cpMax != oldsel.cpMin) {
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldsel);
- m_rtf.SetDraw(true);
- InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE);
- }
-
- // need to invalidate the window
- if (bFlag) {
- sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
- m_rtf.SetDraw(true);
- InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
INT_PTR CALLBACK CMsgDialog::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int iFlags;
diff --git a/src/core/stdmsg/src/msgdialog.cpp b/src/core/stdmsg/src/msgdialog.cpp
index 08f0036782..cfeca501ef 100644
--- a/src/core/stdmsg/src/msgdialog.cpp
+++ b/src/core/stdmsg/src/msgdialog.cpp
@@ -922,7 +922,7 @@ LRESULT CMsgDialog::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam)
}
if (wParam == VK_NEXT || wParam == VK_PRIOR) {
- ((CLogWindow *)m_pLog)->WndProc(msg, wParam, lParam);
+ ((CRtfLogWindow *)m_pLog)->WndProc(msg, wParam, lParam);
return TRUE;
}
}
diff --git a/src/core/stdmsg/src/msglog.cpp b/src/core/stdmsg/src/msglog.cpp
index 318e246ae3..d9c7c5f69b 100644
--- a/src/core/stdmsg/src/msglog.cpp
+++ b/src/core/stdmsg/src/msglog.cpp
@@ -42,7 +42,7 @@ struct LogStreamData
CMStringA buf;
int eventsToInsert;
bool isEmpty;
- CMsgDialog *dlgDat;
+ class CLogWindow *pLog;
};
static int logPixelSY;
@@ -51,6 +51,8 @@ static char szSep2[40], szSep2_RTL[50];
static const wchar_t *bbcodes[] = { L"[b]", L"[i]", L"[u]", L"[s]", L"[/b]", L"[/i]", L"[/u]", L"[/s]" };
static const char *bbcodefmt[] = { "\\b ", "\\i ", "\\ul ", "\\strike ", "\\b0 ", "\\i0 ", "\\ul0 ", "\\strike0 " };
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);
+
static void AppendPlainUnicode(CMStringA &buf, const wchar_t *str)
{
for (; *str; str++) {
@@ -198,214 +200,6 @@ bool DbEventIsShown(const DBEVENTINFO *dbei)
return dbei->eventType == EVENTTYPE_MESSAGE || dbei->eventType == EVENTTYPE_FILE || DbEventIsForMsgWindow(dbei);
}
-static bool CreateRTFFromDbEvent(LogStreamData *dat)
-{
- DB::EventInfo dbei(dat->hDbEvent);
- if (!dbei)
- return false;
-
- if (!DbEventIsShown(&dbei))
- return false;
-
- if (!(dbei.flags & DBEF_SENT) && (dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei))) {
- db_event_markRead(dat->hContact, dat->hDbEvent);
- g_clistApi.pfnRemoveEvent(dat->hContact, dat->hDbEvent);
- }
- else if (dbei.eventType == EVENTTYPE_JABBER_CHATSTATES || dbei.eventType == EVENTTYPE_JABBER_PRESENCE) {
- db_event_markRead(dat->hContact, dat->hDbEvent);
- }
-
- CMStringA &buf = dat->buf;
- bool bIsRtl = dat->dlgDat->m_bIsAutoRTL;
- if (!bIsRtl && !dat->isEmpty)
- buf.Append("\\par");
-
- if (dbei.flags & DBEF_RTL) {
- buf.Append("\\rtlpar");
- bIsRtl = true;
- }
- else buf.Append("\\ltrpar");
-
- dat->isEmpty = false;
-
- if (bIsRtl) {
- if (dbei.flags & DBEF_RTL)
- buf.Append("\\ltrch\\rtlch");
- else
- buf.Append("\\rtlch\\ltrch");
- }
-
- if (g_plugin.bShowIcons) {
- int i = ((dbei.eventType == EVENTTYPE_MESSAGE) ? ((dbei.flags & DBEF_SENT) ? LOGICON_MSG_OUT : LOGICON_MSG_IN): LOGICON_MSG_NOTICE);
-
- buf.Append("\\f0\\fs14");
- buf.Append(pLogIconBmpBits[i]);
- }
-
- int showColon = 0;
- if (g_plugin.bShowTime) {
- const wchar_t* szFormat;
- wchar_t str[64];
-
- if (g_plugin.bShowSecs)
- szFormat = g_plugin.bShowDate ? L"d s" : L"s";
- else
- szFormat = g_plugin.bShowDate ? L"d t" : L"t";
-
- TimeZone_PrintTimeStamp(nullptr, dbei.timestamp, szFormat, str, _countof(str), 0);
-
- SetToStyle((dbei.flags & DBEF_SENT) ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME, buf);
- AppendToBufferWithRTF(buf, str);
- showColon = 1;
- }
-
- if (g_plugin.bShowNames && dbei.eventType != EVENTTYPE_JABBER_CHATSTATES && dbei.eventType != EVENTTYPE_JABBER_PRESENCE) {
- wchar_t *szName;
-
- if (dbei.flags & DBEF_SENT) {
- if (wchar_t *p = Contact::GetInfo(CNF_DISPLAY, 0, dbei.szModule))
- szName = NEWWSTR_ALLOCA(p);
- else
- szName = TranslateT("Me");
- }
- else szName = Clist_GetContactDisplayName(dat->hContact);
-
- SetToStyle((dbei.flags & DBEF_SENT) ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME, buf);
- AppendToBufferWithRTF(buf, szName);
- showColon = 1;
- }
-
- if (showColon)
- SetToStyle((dbei.flags & DBEF_SENT) ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON, buf);
-
- wchar_t *msg, *szName;
- switch (dbei.eventType) {
- case EVENTTYPE_JABBER_CHATSTATES:
- case EVENTTYPE_JABBER_PRESENCE:
- if (dbei.flags & DBEF_SENT) {
- if (wchar_t *p = Contact::GetInfo(CNF_DISPLAY, 0, dbei.szModule)) {
- szName = NEWWSTR_ALLOCA(p);
- mir_free(p);
- }
- else szName = L"";
- }
- else szName = Clist_GetContactDisplayName(dat->hContact);
-
- SetToStyle(MSGFONTID_NOTICE, buf);
- AppendToBufferWithRTF(buf, szName);
- AppendToBufferWithRTF(buf, L" ");
-
- msg = DbEvent_GetTextW(&dbei, CP_ACP);
- if (msg) {
- AppendToBufferWithRTF(buf, msg);
- mir_free(msg);
- }
- break;
-
- case EVENTTYPE_FILE:
- SetToStyle(MSGFONTID_NOTICE, buf);
- {
- DB::FILE_BLOB blob(dbei);
- if (blob.isOffline()) {
- AppendToBufferWithRTF(buf, TranslateT("Offline file"));
- buf.Append(" {\\field{\\*\\fldinst HYPERLINK \"");
- buf.AppendFormat("ofile:%ul", dat->hDbEvent);
- buf.Append("\"}{\\fldrslt{\\ul ");
- AppendToBufferWithRTF(buf, blob.getName());
- buf.AppendFormat("}}} | %uKB", blob.getSize() / 1024);
-
- CMStringA szHost;
- if (const char *b = strstr(blob.getUrl(), "://"))
- for (b = b + 3; *b != 0 && *b != '/' && *b != ':'; b++)
- szHost.AppendChar(*b);
-
- if (!szHost.IsEmpty())
- buf.AppendFormat(" on %s", szHost.c_str());
-
- if (blob.getSize() > 0 && blob.getSize() == blob.getTransferred()) {
- buf.AppendChar(' ');
- AppendToBufferWithRTF(buf, TranslateT("Completed"));
- }
- }
- else {
- AppendToBufferWithRTF(buf, (dbei.flags & DBEF_SENT) ? TranslateT("File sent") : TranslateT("File received"));
- buf.Append(": ");
- AppendToBufferWithRTF(buf, blob.getName());
-
- if (mir_wstrlen(blob.getDescr())) {
- buf.Append(" (");
- AppendToBufferWithRTF(buf, blob.getDescr());
- buf.Append(")");
- }
- }
- }
- break;
-
- case EVENTTYPE_MESSAGE:
- default:
- msg = DbEvent_GetTextW(&dbei, CP_ACP);
- SetToStyle((dbei.eventType == EVENTTYPE_MESSAGE) ? ((dbei.flags & DBEF_SENT) ? MSGFONTID_MYMSG : MSGFONTID_YOURMSG) : MSGFONTID_NOTICE, buf);
- AppendToBufferWithRTF(buf, msg);
- mir_free(msg);
- }
-
- if (bIsRtl)
- buf.Append("\\par");
-
- return true;
-}
-
-static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
-{
- LogStreamData *dat = (LogStreamData*)dwCookie;
-
- if (dat->buf.IsEmpty()) {
- switch (dat->stage) {
- case STREAMSTAGE_HEADER:
- CreateRTFHeader(dat->buf);
- dat->stage = STREAMSTAGE_EVENTS;
- break;
-
- case STREAMSTAGE_EVENTS:
- if (dat->eventsToInsert) {
- bool bOk;
- do {
- bOk = CreateRTFFromDbEvent(dat);
- if (bOk)
- dat->hDbEventLast = dat->hDbEvent;
- dat->hDbEvent = db_event_next(dat->hContact, dat->hDbEvent);
- if (--dat->eventsToInsert == 0)
- break;
- } while (!bOk && dat->hDbEvent);
-
- if (bOk) {
- dat->isEmpty = false;
- break;
- }
- }
- dat->stage = STREAMSTAGE_TAIL;
- __fallthrough;
-
- case STREAMSTAGE_TAIL:
- CreateRTFTail(dat->buf);
- dat->stage = STREAMSTAGE_STOP;
- break;
- case STREAMSTAGE_STOP:
- *pcb = 0;
- return 0;
- }
- }
-
- *pcb = min(cb, dat->buf.GetLength());
- memcpy(pbBuff, dat->buf.GetBuffer(), *pcb);
- if (dat->buf.GetLength() == *pcb)
- dat->buf.Empty();
- else
- dat->buf.Delete(0, *pcb);
-
- return 0;
-}
-
#define RTFPICTHEADERMAXSIZE 78
void LoadMsgLogIcons(void)
{
@@ -461,204 +255,519 @@ void FreeMsgLogIcons(void)
}
/////////////////////////////////////////////////////////////////////////////////////////
+// Log window class
-void CLogWindow::Attach()
+class CLogWindow : public CRtfLogWindow
{
- CSuper::Attach();
+ typedef CRtfLogWindow CSuper;
- // get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF
- m_rtf.SendMsg(EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0);
- m_rtf.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_SCROLL);
- m_rtf.SendMsg(EM_HIDESELECTION, TRUE, 0);
- m_rtf.SendMsg(EM_AUTOURLDETECT, TRUE, 0);
-}
+public:
+ CLogWindow(CMsgDialog &pDlg) :
+ CSuper(pDlg)
+ {}
-void CLogWindow::LogEvents(MEVENT hDbEventFirst, int count, bool bAppend)
-{
- CHARRANGE oldSel, sel;
- BOOL bottomScroll = TRUE;
- POINT scrollPos;
-
- m_rtf.SetDraw(false);
- m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldSel);
-
- LogStreamData streamData = {};
- streamData.hContact = m_pDlg.m_hContact;
- streamData.hDbEvent = hDbEventFirst;
- streamData.dlgDat = &m_pDlg;
- streamData.eventsToInsert = count;
- streamData.isEmpty = !bAppend || GetWindowTextLength(m_rtf.GetHwnd()) == 0;
-
- EDITSTREAM stream = {};
- stream.pfnCallback = LogStreamInEvents;
- stream.dwCookie = (DWORD_PTR)&streamData;
-
- if (!streamData.isEmpty) {
- bottomScroll = GetFocus() != m_rtf.GetHwnd() && AtBottom();
- if (!bottomScroll)
- m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&scrollPos);
+ void AppendUnicodeString(CMStringA &str, const wchar_t *pwszBuf)
+ {
+ AppendToBufferWithRTF(str, pwszBuf);
}
- FINDTEXTEXA fi;
- if (bAppend) {
- sel.cpMin = sel.cpMax = -1;
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
- fi.chrg.cpMin = 0;
- }
- else {
- GETTEXTLENGTHEX gtxl = { 0 };
- gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
- gtxl.codepage = 1200;
- fi.chrg.cpMin = m_rtf.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)&gtxl, 0);
+ void Attach() override
+ {
+ CSuper::Attach();
- sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ // get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF
+ m_rtf.SendMsg(EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0);
+ m_rtf.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_SCROLL);
+ m_rtf.SendMsg(EM_HIDESELECTION, TRUE, 0);
+ m_rtf.SendMsg(EM_AUTOURLDETECT, TRUE, 0);
}
- mir_strcpy(szSep2, bAppend ? "\\par\\sl0" : "\\sl1000");
- mir_strcpy(szSep2_RTL, bAppend ? "\\rtlpar\\rtlmark\\par\\sl1000" : "\\sl1000");
+ bool CreateRTFFromDbEvent(LogStreamData *dat)
+ {
+ DB::EventInfo dbei(dat->hDbEvent);
+ if (!dbei)
+ return false;
- m_rtf.SendMsg(EM_STREAMIN, bAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM)&stream);
- if (bottomScroll) {
- sel.cpMin = sel.cpMax = -1;
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
- }
- else {
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldSel);
- m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&scrollPos);
+ if (!DbEventIsShown(&dbei))
+ return false;
+
+ if (!(dbei.flags & DBEF_SENT) && (dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei))) {
+ db_event_markRead(dat->hContact, dat->hDbEvent);
+ g_clistApi.pfnRemoveEvent(dat->hContact, dat->hDbEvent);
+ }
+ else if (dbei.eventType == EVENTTYPE_JABBER_CHATSTATES || dbei.eventType == EVENTTYPE_JABBER_PRESENCE) {
+ db_event_markRead(dat->hContact, dat->hDbEvent);
+ }
+
+ CMStringA &buf = dat->buf;
+ bool bIsRtl = m_pDlg.m_bIsAutoRTL;
+ if (!bIsRtl && !dat->isEmpty)
+ buf.Append("\\par");
+
+ if (dbei.flags & DBEF_RTL) {
+ buf.Append("\\rtlpar");
+ bIsRtl = true;
+ }
+ else buf.Append("\\ltrpar");
+
+ dat->isEmpty = false;
+
+ if (bIsRtl) {
+ if (dbei.flags & DBEF_RTL)
+ buf.Append("\\ltrch\\rtlch");
+ else
+ buf.Append("\\rtlch\\ltrch");
+ }
+
+ if (g_plugin.bShowIcons) {
+ int i = ((dbei.eventType == EVENTTYPE_MESSAGE) ? ((dbei.flags & DBEF_SENT) ? LOGICON_MSG_OUT : LOGICON_MSG_IN) : LOGICON_MSG_NOTICE);
+
+ buf.Append("\\f0\\fs14");
+ buf.Append(pLogIconBmpBits[i]);
+ }
+
+ int showColon = 0;
+ if (g_plugin.bShowTime) {
+ const wchar_t *szFormat;
+ wchar_t str[64];
+
+ if (g_plugin.bShowSecs)
+ szFormat = g_plugin.bShowDate ? L"d s" : L"s";
+ else
+ szFormat = g_plugin.bShowDate ? L"d t" : L"t";
+
+ TimeZone_PrintTimeStamp(nullptr, dbei.timestamp, szFormat, str, _countof(str), 0);
+
+ SetToStyle((dbei.flags & DBEF_SENT) ? MSGFONTID_MYTIME : MSGFONTID_YOURTIME, buf);
+ AppendToBufferWithRTF(buf, str);
+ showColon = 1;
+ }
+
+ if (g_plugin.bShowNames && dbei.eventType != EVENTTYPE_JABBER_CHATSTATES && dbei.eventType != EVENTTYPE_JABBER_PRESENCE) {
+ wchar_t *szName;
+
+ if (dbei.flags & DBEF_SENT) {
+ if (wchar_t *p = Contact::GetInfo(CNF_DISPLAY, 0, dbei.szModule))
+ szName = NEWWSTR_ALLOCA(p);
+ else
+ szName = TranslateT("Me");
+ }
+ else szName = Clist_GetContactDisplayName(dat->hContact);
+
+ SetToStyle((dbei.flags & DBEF_SENT) ? MSGFONTID_MYNAME : MSGFONTID_YOURNAME, buf);
+ AppendToBufferWithRTF(buf, szName);
+ showColon = 1;
+ }
+
+ if (showColon)
+ SetToStyle((dbei.flags & DBEF_SENT) ? MSGFONTID_MYCOLON : MSGFONTID_YOURCOLON, buf);
+
+ wchar_t *msg, *szName;
+ switch (dbei.eventType) {
+ case EVENTTYPE_JABBER_CHATSTATES:
+ case EVENTTYPE_JABBER_PRESENCE:
+ if (dbei.flags & DBEF_SENT) {
+ if (wchar_t *p = Contact::GetInfo(CNF_DISPLAY, 0, dbei.szModule)) {
+ szName = NEWWSTR_ALLOCA(p);
+ mir_free(p);
+ }
+ else szName = L"";
+ }
+ else szName = Clist_GetContactDisplayName(dat->hContact);
+
+ SetToStyle(MSGFONTID_NOTICE, buf);
+ AppendToBufferWithRTF(buf, szName);
+ AppendToBufferWithRTF(buf, L" ");
+
+ msg = DbEvent_GetTextW(&dbei, CP_ACP);
+ if (msg) {
+ AppendToBufferWithRTF(buf, msg);
+ mir_free(msg);
+ }
+ break;
+
+ case EVENTTYPE_FILE:
+ SetToStyle(MSGFONTID_NOTICE, buf);
+ {
+ DB::FILE_BLOB blob(dbei);
+ if (blob.isOffline()) {
+ InsertFileLink(buf, dat->hDbEvent, blob);
+ }
+ else {
+ AppendToBufferWithRTF(buf, (dbei.flags & DBEF_SENT) ? TranslateT("File sent") : TranslateT("File received"));
+ buf.Append(": ");
+ AppendToBufferWithRTF(buf, blob.getName());
+
+ if (mir_wstrlen(blob.getDescr())) {
+ buf.Append(" (");
+ AppendToBufferWithRTF(buf, blob.getDescr());
+ buf.Append(")");
+ }
+ }
+ }
+ break;
+
+ case EVENTTYPE_MESSAGE:
+ default:
+ msg = DbEvent_GetTextW(&dbei, CP_ACP);
+ SetToStyle((dbei.eventType == EVENTTYPE_MESSAGE) ? ((dbei.flags & DBEF_SENT) ? MSGFONTID_MYMSG : MSGFONTID_YOURMSG) : MSGFONTID_NOTICE, buf);
+ AppendToBufferWithRTF(buf, msg);
+ mir_free(msg);
+ }
+
+ if (bIsRtl)
+ buf.Append("\\par");
+
+ return true;
}
- if (g_plugin.bSmileyInstalled) {
- SMADD_RICHEDIT3 smre;
- smre.cbSize = sizeof(SMADD_RICHEDIT3);
- smre.hwndRichEditControl = m_rtf.GetHwnd();
+ /////////////////////////////////////////////////////////////////////////////////////////
- MCONTACT hContact = db_mc_getSrmmSub(m_pDlg.m_hContact);
- smre.Protocolname = (hContact != 0) ? Proto_GetBaseAccountName(hContact) : m_pDlg.m_szProto;
+ void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override
+ {
+ CHARRANGE oldSel, sel;
+ BOOL bottomScroll = TRUE;
+ POINT scrollPos;
- if (fi.chrg.cpMin > 0) {
- sel.cpMin = fi.chrg.cpMin;
- sel.cpMax = -1;
- smre.rangeToReplace = &sel;
+ m_rtf.SetDraw(false);
+ m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldSel);
+
+ LogStreamData streamData = {};
+ streamData.hContact = m_pDlg.m_hContact;
+ streamData.hDbEvent = hDbEventFirst;
+ streamData.pLog = this;
+ streamData.eventsToInsert = count;
+ streamData.isEmpty = !bAppend || GetWindowTextLength(m_rtf.GetHwnd()) == 0;
+
+ EDITSTREAM stream = {};
+ stream.pfnCallback = LogStreamInEvents;
+ stream.dwCookie = (DWORD_PTR)&streamData;
+
+ if (!streamData.isEmpty) {
+ bottomScroll = GetFocus() != m_rtf.GetHwnd() && AtBottom();
+ if (!bottomScroll)
+ m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&scrollPos);
}
- else smre.rangeToReplace = nullptr;
- smre.disableRedraw = TRUE;
- smre.hContact = m_pDlg.m_hContact;
- smre.flags = 0;
- CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&smre);
+ FINDTEXTEXA fi;
+ if (bAppend) {
+ sel.cpMin = sel.cpMax = -1;
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ fi.chrg.cpMin = 0;
+ }
+ else {
+ GETTEXTLENGTHEX gtxl = { 0 };
+ gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
+ gtxl.codepage = 1200;
+ fi.chrg.cpMin = m_rtf.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)&gtxl, 0);
+
+ sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ }
+
+ mir_strcpy(szSep2, bAppend ? "\\par\\sl0" : "\\sl1000");
+ mir_strcpy(szSep2_RTL, bAppend ? "\\rtlpar\\rtlmark\\par\\sl1000" : "\\sl1000");
+
+ m_rtf.SendMsg(EM_STREAMIN, bAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM)&stream);
+ if (bottomScroll) {
+ sel.cpMin = sel.cpMax = -1;
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ }
+ else {
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldSel);
+ m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&scrollPos);
+ }
+
+ if (g_plugin.bSmileyInstalled) {
+ SMADD_RICHEDIT3 smre;
+ smre.cbSize = sizeof(SMADD_RICHEDIT3);
+ smre.hwndRichEditControl = m_rtf.GetHwnd();
+
+ MCONTACT hContact = db_mc_getSrmmSub(m_pDlg.m_hContact);
+ smre.Protocolname = (hContact != 0) ? Proto_GetBaseAccountName(hContact) : m_pDlg.m_szProto;
+
+ if (fi.chrg.cpMin > 0) {
+ sel.cpMin = fi.chrg.cpMin;
+ sel.cpMax = -1;
+ smre.rangeToReplace = &sel;
+ }
+ else smre.rangeToReplace = nullptr;
+
+ smre.disableRedraw = TRUE;
+ smre.hContact = m_pDlg.m_hContact;
+ smre.flags = 0;
+ CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&smre);
+ }
+
+ m_rtf.SetDraw(true);
+ if (bottomScroll || AtBottom()) {
+ ScrollToBottom();
+ RedrawWindow(m_rtf.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+
+ m_pDlg.m_hDbEventLast = streamData.hDbEventLast;
}
- m_rtf.SetDraw(true);
- if (bottomScroll || AtBottom()) {
- ScrollToBottom();
- RedrawWindow(m_rtf.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ void LogEvents(struct LOGINFO *lin, bool bRedraw) override
+ {
+ auto *si = m_pDlg.m_si;
+ if (lin == nullptr || si == nullptr)
+ return;
+
+ if (!bRedraw && si->iType == GCW_CHATROOM && (m_pDlg.m_iLogFilterFlags & lin->iType) == 0)
+ return;
+
+ LOGSTREAMDATA streamData;
+ memset(&streamData, 0, sizeof(streamData));
+ streamData.hwnd = m_rtf.GetHwnd();
+ streamData.si = si;
+ streamData.lin = lin;
+ streamData.bStripFormat = FALSE;
+
+ bool bFlag = false;
+
+ EDITSTREAM stream = {};
+ stream.pfnCallback = Srmm_LogStreamCallback;
+ stream.dwCookie = (DWORD_PTR)&streamData;
+
+ SCROLLINFO scroll;
+ scroll.cbSize = sizeof(SCROLLINFO);
+ scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+ GetScrollInfo(m_rtf.GetHwnd(), SB_VERT, &scroll);
+
+ POINT point = {};
+ m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point);
+
+ // do not scroll to bottom if there is a selection
+ CHARRANGE oldsel, sel;
+ m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldsel);
+ if (oldsel.cpMax != oldsel.cpMin)
+ m_rtf.SetDraw(false);
+
+ //set the insertion point at the bottom
+ sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+
+ // fix for the indent... must be a M$ bug
+ if (sel.cpMax == 0)
+ bRedraw = TRUE;
+
+ // should the event(s) be appended to the current log
+ WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF;
+
+ //get the number of pixels per logical inch
+ if (bRedraw) {
+ HDC hdc = GetDC(nullptr);
+ g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
+ ReleaseDC(nullptr, hdc);
+ m_rtf.SetDraw(false);
+ bFlag = true;
+ }
+
+ // stream in the event(s)
+ streamData.lin = lin;
+ streamData.bRedraw = bRedraw;
+ m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream);
+
+ // do smileys
+ if (g_plugin.bSmileyInstalled && (bRedraw || (lin->ptszText && lin->iType != GC_EVENT_JOIN && lin->iType != GC_EVENT_NICK && lin->iType != GC_EVENT_ADDSTATUS && lin->iType != GC_EVENT_REMOVESTATUS))) {
+ CHARRANGE newsel;
+ newsel.cpMax = -1;
+ newsel.cpMin = sel.cpMin;
+ if (newsel.cpMin < 0)
+ newsel.cpMin = 0;
+
+ SMADD_RICHEDIT3 sm = {};
+ sm.cbSize = sizeof(sm);
+ sm.hwndRichEditControl = m_rtf.GetHwnd();
+ sm.Protocolname = si->pszModule;
+ sm.rangeToReplace = bRedraw ? nullptr : &newsel;
+ sm.disableRedraw = TRUE;
+ sm.hContact = si->hContact;
+ CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm);
+ }
+
+ // scroll log to bottom if the log was previously scrolled to bottom, else restore old position
+ if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)
+ ScrollToBottom();
+ else
+ m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point);
+
+ // do we need to restore the selection
+ if (oldsel.cpMax != oldsel.cpMin) {
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldsel);
+ m_rtf.SetDraw(true);
+ InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE);
+ }
+
+ // need to invalidate the window
+ if (bFlag) {
+ sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength();
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ m_rtf.SetDraw(true);
+ InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE);
+ }
}
- m_pDlg.m_hDbEventLast = streamData.hDbEventLast;
-}
+ /////////////////////////////////////////////////////////////////////////////////////////
-void CLogWindow::UpdateOptions()
-{
- if (m_pDlg.isChat())
- m_rtf.SendMsg(EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground);
- else {
- // configure message history for proper RTL formatting
- PARAFORMAT2 pf2;
- memset(&pf2, 0, sizeof(pf2));
- pf2.cbSize = sizeof(pf2);
-
- pf2.wEffects = PFE_RTLPARA;
- pf2.dwMask = PFM_RTLPARA;
- m_rtf.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-
- pf2.wEffects = 0;
- m_rtf.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-
- m_rtf.SendMsg(EM_SETLANGOPTIONS, 0, m_rtf.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
- m_rtf.SendMsg(EM_SETBKGNDCOLOR, 0, g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR));
+ void UpdateOptions() override
+ {
+ if (m_pDlg.isChat())
+ m_rtf.SendMsg(EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground);
+ else {
+ // configure message history for proper RTL formatting
+ PARAFORMAT2 pf2;
+ memset(&pf2, 0, sizeof(pf2));
+ pf2.cbSize = sizeof(pf2);
+
+ pf2.wEffects = PFE_RTLPARA;
+ pf2.dwMask = PFM_RTLPARA;
+ m_rtf.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+
+ pf2.wEffects = 0;
+ m_rtf.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+
+ m_rtf.SendMsg(EM_SETLANGOPTIONS, 0, m_rtf.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ m_rtf.SendMsg(EM_SETBKGNDCOLOR, 0, g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR));
+ }
}
-}
-/////////////////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////////////////
-static const CHARRANGE rangeAll = { 0, -1 };
+ INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam) override
+ {
+ CHARRANGE sel;
-INT_PTR CLogWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- CHARRANGE sel;
-
- switch (msg) {
- case WM_CONTEXTMENU:
- // we display context menu here only for private chats, group chats are processed by the core
- if (!m_pDlg.isChat()) {
- POINT pt;
- GetCursorPos(&pt);
-
- SetFocus(m_rtf.GetHwnd());
-
- HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT));
- HMENU hSubMenu = GetSubMenu(hMenu, 0);
- TranslateMenu(hSubMenu);
-
- CHARRANGE all = { 0, -1 };
- m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin == sel.cpMax)
- EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
-
- switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlg.m_hwnd, nullptr)) {
- case IDM_COPY:
- m_rtf.SendMsg(WM_COPY, 0, 0);
- break;
- case IDM_COPYALL:
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all);
- m_rtf.SendMsg(WM_COPY, 0, 0);
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
- break;
- case IDM_SELECTALL:
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all);
- break;
- case IDM_CLEAR:
- Clear();
- m_pDlg.m_hDbEventFirst = 0;
- break;
+ switch (msg) {
+ case WM_CONTEXTMENU:
+ // we display context menu here only for private chats, group chats are processed by the core
+ if (!m_pDlg.isChat()) {
+ POINT pt;
+ GetCursorPos(&pt);
+
+ SetFocus(m_rtf.GetHwnd());
+
+ HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT));
+ HMENU hSubMenu = GetSubMenu(hMenu, 0);
+ TranslateMenu(hSubMenu);
+
+ CHARRANGE all = { 0, -1 };
+ m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
+ if (sel.cpMin == sel.cpMax)
+ EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
+
+ switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlg.m_hwnd, nullptr)) {
+ case IDM_COPY:
+ m_rtf.SendMsg(WM_COPY, 0, 0);
+ break;
+ case IDM_COPYALL:
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all);
+ m_rtf.SendMsg(WM_COPY, 0, 0);
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ break;
+ case IDM_SELECTALL:
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all);
+ break;
+ case IDM_CLEAR:
+ Clear();
+ m_pDlg.m_hDbEventFirst = 0;
+ break;
+ }
+ DestroyMenu(hSubMenu);
+ DestroyMenu(hMenu);
+ return TRUE;
}
- DestroyMenu(hSubMenu);
- DestroyMenu(hMenu);
- return TRUE;
- }
- break;
-
- case WM_LBUTTONUP:
- if (g_plugin.bAutoCopy) {
- m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
- if (sel.cpMin != sel.cpMax) {
- m_rtf.SendMsg(WM_COPY, 0, 0);
- sel.cpMin = sel.cpMax;
- m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ break;
+
+ case WM_LBUTTONUP:
+ if (g_plugin.bAutoCopy) {
+ m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel);
+ if (sel.cpMin != sel.cpMax) {
+ m_rtf.SendMsg(WM_COPY, 0, 0);
+ sel.cpMin = sel.cpMax;
+ m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+ }
+ SetFocus(m_pDlg.m_message.GetHwnd());
}
- SetFocus(m_pDlg.m_message.GetHwnd());
- }
- break;
-
- case WM_KEYDOWN:
- bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
- bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
- bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0;
-
- if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window)
- m_pDlg.CloseTab();
- return TRUE;
+ break;
+
+ case WM_KEYDOWN:
+ bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
+ bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0;
+
+ if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window)
+ m_pDlg.CloseTab();
+ return TRUE;
+ }
+
+ if (m_pDlg.ProcessHotkeys(wParam, isShift, isCtrl, isAlt))
+ return FALSE;
}
- if (m_pDlg.ProcessHotkeys(wParam, isShift, isCtrl, isAlt))
- return FALSE;
+ return CSuper::WndProc(msg, wParam, lParam);
}
+};
- return CSuper::WndProc(msg, wParam, lParam);
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
+{
+ LogStreamData *dat = (LogStreamData *)dwCookie;
+
+ if (dat->buf.IsEmpty()) {
+ switch (dat->stage) {
+ case STREAMSTAGE_HEADER:
+ CreateRTFHeader(dat->buf);
+ dat->stage = STREAMSTAGE_EVENTS;
+ break;
+
+ case STREAMSTAGE_EVENTS:
+ if (dat->eventsToInsert) {
+ bool bOk;
+ do {
+ bOk = dat->pLog->CreateRTFFromDbEvent(dat);
+ if (bOk)
+ dat->hDbEventLast = dat->hDbEvent;
+ dat->hDbEvent = db_event_next(dat->hContact, dat->hDbEvent);
+ if (--dat->eventsToInsert == 0)
+ break;
+ } while (!bOk && dat->hDbEvent);
+
+ if (bOk) {
+ dat->isEmpty = false;
+ break;
+ }
+ }
+ dat->stage = STREAMSTAGE_TAIL;
+ __fallthrough;
+
+ case STREAMSTAGE_TAIL:
+ CreateRTFTail(dat->buf);
+ dat->stage = STREAMSTAGE_STOP;
+ break;
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
+ }
+ }
+
+ *pcb = min(cb, dat->buf.GetLength());
+ memcpy(pbBuff, dat->buf.GetBuffer(), *pcb);
+ if (dat->buf.GetLength() == *pcb)
+ dat->buf.Empty();
+ else
+ dat->buf.Delete(0, *pcb);
+
+ return 0;
}
-CSrmmLogWindow *logBuilder(CMsgDialog &pDlg)
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module entry point
+
+CSrmmLogWindow* logBuilder(CMsgDialog &pDlg)
{
return new CLogWindow(pDlg);
}
diff --git a/src/core/stdmsg/src/msgs.h b/src/core/stdmsg/src/msgs.h
index 59458e220a..2dc98a0e66 100644
--- a/src/core/stdmsg/src/msgs.h
+++ b/src/core/stdmsg/src/msgs.h
@@ -31,23 +31,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define EVENTTYPE_JABBER_CHATSTATES 2000
#define EVENTTYPE_JABBER_PRESENCE 2001
-class CLogWindow : public CRtfLogWindow
-{
- typedef CRtfLogWindow CSuper;
-
-public:
- CLogWindow(CMsgDialog &pDlg) :
- CSuper(pDlg)
- {}
-
- void Attach() override;
- void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override;
- void LogEvents(struct LOGINFO *, bool) override;
- void UpdateOptions() override;
-
- INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam) override;
-};
-
class CMsgDialog : public CSrmmBaseDialog
{
friend class CLogWindow;
diff --git a/src/mir_app/src/db_events.cpp b/src/mir_app/src/db_events.cpp
index c3135bfa76..29436c5f51 100644
--- a/src/mir_app/src/db_events.cpp
+++ b/src/mir_app/src/db_events.cpp
@@ -91,14 +91,14 @@ MIR_APP_DLL(DBEVENTTYPEDESCR*) DbEvent_GetType(const char *szModule, int eventTy
/////////////////////////////////////////////////////////////////////////////////////////
-static wchar_t* getEventString(DBEVENTINFO *dbei, LPSTR &buf)
+static wchar_t* getEventString(const DB::EventInfo *dbei, LPSTR &buf)
{
LPSTR in = buf;
buf += mir_strlen(buf) + 1;
- return (dbei->flags & DBEF_UTF) ? mir_utf8decodeW(in) : mir_a2u(in);
+ return dbei->getString(in);
}
-static INT_PTR DbEventGetTextWorker(DB::EventInfo *dbei, int codepage, int datatype)
+static INT_PTR DbEventGetTextWorker(const DB::EventInfo *dbei, int codepage, int datatype)
{
if (dbei == nullptr || dbei->szModule == nullptr)
return 0;
@@ -205,12 +205,12 @@ static INT_PTR DbEventGetTextWorker(DB::EventInfo *dbei, int codepage, int datat
return 0;
}
-MIR_APP_DLL(char*) DbEvent_GetTextA(DBEVENTINFO *dbei, int codepage)
+MIR_APP_DLL(char*) DbEvent_GetTextA(const DBEVENTINFO *dbei, int codepage)
{
return (char*)DbEventGetTextWorker((DB::EventInfo *)dbei, codepage, DBVT_ASCIIZ);
}
-MIR_APP_DLL(wchar_t*) DbEvent_GetTextW(DBEVENTINFO *dbei, int codepage)
+MIR_APP_DLL(wchar_t*) DbEvent_GetTextW(const DBEVENTINFO *dbei, int codepage)
{
return (wchar_t*)DbEventGetTextWorker((DB::EventInfo *)dbei, codepage, DBVT_WCHAR);
}
diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def
index d586c688c3..021694711d 100644
--- a/src/mir_app/src/mir_app.def
+++ b/src/mir_app/src/mir_app.def
@@ -849,3 +849,5 @@ Chat_IsMuted @941 NONAME
?getSize@FILE_BLOB@DB@@QBEIXZ @965 NONAME
?getTransferred@FILE_BLOB@DB@@QBEIXZ @966 NONAME
?getString@EventInfo@DB@@QBEPA_WPBD@Z @967 NONAME
+?InsertFileLink@CRtfLogWindow@@IAEXAAV?$CMStringT@DV?$ChTraitsCRT@D@@@@IABVFILE_BLOB@DB@@@Z @968 NONAME
+?GetDialog@CSrmmLogWindow@@QBEAAVCMsgDialog@@XZ @969 NONAME
diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def
index 0d86eeb01a..b888eb1a3b 100644
--- a/src/mir_app/src/mir_app64.def
+++ b/src/mir_app/src/mir_app64.def
@@ -849,3 +849,5 @@ Chat_IsMuted @941 NONAME
?getSize@FILE_BLOB@DB@@QEBAIXZ @965 NONAME
?getTransferred@FILE_BLOB@DB@@QEBAIXZ @966 NONAME
?getString@EventInfo@DB@@QEBAPEA_WPEBD@Z @967 NONAME
+?InsertFileLink@CRtfLogWindow@@IEAAXAEAV?$CMStringT@DV?$ChTraitsCRT@D@@@@IAEBVFILE_BLOB@DB@@@Z @968 NONAME
+?GetDialog@CSrmmLogWindow@@QEBAAEAVCMsgDialog@@XZ @969 NONAME
diff --git a/src/mir_app/src/srmm_log_rtf.cpp b/src/mir_app/src/srmm_log_rtf.cpp
index dec151b43d..eae329a4f0 100644
--- a/src/mir_app/src/srmm_log_rtf.cpp
+++ b/src/mir_app/src/srmm_log_rtf.cpp
@@ -124,6 +124,31 @@ wchar_t* CRtfLogWindow::GetSelection()
/////////////////////////////////////////////////////////////////////////////////////////
+void CRtfLogWindow::InsertFileLink(CMStringA &buf, MEVENT hEvent, const DB::FILE_BLOB &blob)
+{
+ AppendUnicodeString(buf, TranslateT("Offline file"));
+ buf.Append(" {\\field{\\*\\fldinst HYPERLINK \"");
+ buf.AppendFormat("ofile:%ul", hEvent);
+ buf.Append("\"}{\\fldrslt{\\ul ");
+ AppendUnicodeString(buf, blob.getName());
+ buf.AppendFormat("}}} | %uKB", blob.getSize() / 1024);
+
+ CMStringA szHost;
+ if (const char *b = strstr(blob.getUrl(), "://"))
+ for (b = b + 3; *b != 0 && *b != '/' && *b != ':'; b++)
+ szHost.AppendChar(*b);
+
+ if (!szHost.IsEmpty())
+ buf.AppendFormat(" on %s", szHost.c_str());
+
+ if (blob.getSize() > 0 && blob.getSize() == blob.getTransferred()) {
+ buf.AppendChar(' ');
+ AppendUnicodeString(buf, TranslateT("Completed"));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
INT_PTR CRtfLogWindow::Notify(WPARAM, LPARAM lParam)
{
LPNMHDR hdr = (LPNMHDR)lParam;