summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Plugins/historylog/Docs/historylog_changelog.txt4
-rw-r--r--Plugins/historylog/Docs/historylog_readme.txt16
-rw-r--r--Plugins/historylog/Docs/historylog_version.txt2
-rw-r--r--Plugins/historylog/ZIP/doit.bat14
-rw-r--r--Plugins/historylog/commons.h16
-rw-r--r--Plugins/historylog/historylog.cpp549
-rw-r--r--Plugins/historylog/historylog.dsp8
-rw-r--r--Plugins/historylog/options.cpp214
-rw-r--r--Plugins/historylog/options.h5
-rw-r--r--Plugins/historylog/resource.h4
-rw-r--r--Plugins/historylog/resource.rc35
11 files changed, 759 insertions, 108 deletions
diff --git a/Plugins/historylog/Docs/historylog_changelog.txt b/Plugins/historylog/Docs/historylog_changelog.txt
index aa1b65e..e28771b 100644
--- a/Plugins/historylog/Docs/historylog_changelog.txt
+++ b/Plugins/historylog/Docs/historylog_changelog.txt
@@ -2,6 +2,10 @@ History Log
Changelog:
+. 0.0.0.3
+ + Added BOM to files (editors should work better with this) - only for new files
+ + Added group chat logging (dll needed to be renamed for this to work)
+
. 0.0.0.2
* Fix for multi-line messages (closes #41)
+ Added new variables to filename (closes #44)
diff --git a/Plugins/historylog/Docs/historylog_readme.txt b/Plugins/historylog/Docs/historylog_readme.txt
index d964cfc..38bedd0 100644
--- a/Plugins/historylog/Docs/historylog_readme.txt
+++ b/Plugins/historylog/Docs/historylog_readme.txt
@@ -3,9 +3,9 @@ History Log plugin
CAUTION: THIS IS ALPHA QUALITY SOFTWARE. USE AT YOUR OWN RISK.
-This is a plugin that logs to a text file all messages exchanged with contact. The text file is encoded in UTF-8. It can't handle group chat.
+This is a plugin that logs to a text file all messages exchanged with contact or in a group chat. The text file is encoded in UTF-8.
-The filename pattern accepts the following vars: (also, it support variables plugin)
+The messages filename pattern accepts the following vars: (also, it support variables plugin)
%contact%
%contact_id%
%protocol%
@@ -15,10 +15,14 @@ The filename pattern accepts the following vars: (also, it support variables plu
%month_name%
%day%
+The group chat filename pattern accepts the following vars: (also, it support variables plugin)
+ %session%
+ %protocol%
+ %year%
+ %month%
+ %month_name%
+ %day%
+
This plugin requires at least Miranda 0.7 and needs History Events to work.
To report bugs/make suggestions, go to the forum thread: http://forums.miranda-im.org/showthread.php?t=18488
-
-To do:
- - Handle group chat (maybe)
-
diff --git a/Plugins/historylog/Docs/historylog_version.txt b/Plugins/historylog/Docs/historylog_version.txt
index 46d219a..883a1a1 100644
--- a/Plugins/historylog/Docs/historylog_version.txt
+++ b/Plugins/historylog/Docs/historylog_version.txt
@@ -1 +1 @@
-HistoryLog 0.0.0.2 \ No newline at end of file
+HistoryLog 0.0.0.3 \ No newline at end of file
diff --git a/Plugins/historylog/ZIP/doit.bat b/Plugins/historylog/ZIP/doit.bat
index 9de9c05..6f61f5f 100644
--- a/Plugins/historylog/ZIP/doit.bat
+++ b/Plugins/historylog/ZIP/doit.bat
@@ -50,28 +50,28 @@ del /Q *.*
copy ..\..\..\sdk\*.*
cd ..
cd ..
-copy ..\Release\%name%.pdb
-copy "..\Unicode_Release\%name%W.pdb"
+copy ..\Release\aa_%name%.pdb
+copy "..\Unicode_Release\aa_%name%W.pdb"
mkdir Plugins
cd Plugins
-copy "..\..\..\..\bin\release unicode\Plugins\%name%W.dll"
+copy "..\..\..\..\bin\release unicode\Plugins\aa_%name%W.dll"
cd ..
"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%W.zip Plugins Docs
cd Plugins
-del /Q %name%W.dll
-copy "..\..\..\..\bin\release\Plugins\%name%.dll"
+del /Q aa_%name%W.dll
+copy "..\..\..\..\bin\release\Plugins\aa_%name%.dll"
cd ..
"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%.zip Plugins Docs
"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%_src.zip src\*.*
-"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%.pdb.zip %name%.pdb
-"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%W.pdb.zip %name%W.pdb
+"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%.pdb.zip aa_%name%.pdb
+"C:\Program Files\Filzip\Filzip.exe" -a -rp %name%W.pdb.zip aa_%name%W.pdb
del *.pdb
rd /S /Q Plugins
diff --git a/Plugins/historylog/commons.h b/Plugins/historylog/commons.h
index eea49b3..0559573 100644
--- a/Plugins/historylog/commons.h
+++ b/Plugins/historylog/commons.h
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2006 Ricardo Pescuma Domenecci
+Copyright (C) 2008 Ricardo Pescuma Domenecci
This is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA.
#include <m_historyevents.h>
#include <m_protocols.h>
#include <m_protosvc.h>
+#include <m_chat.h>
#include "../utils/mir_memory.h"
#include "../utils/mir_options.h"
@@ -59,6 +60,16 @@ Boston, MA 02111-1307, USA.
#include "options.h"
+#define GC_EVENT_HIGHLIGHT 0x1000
+
+
+#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr"
+typedef int (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam);
+typedef struct {
+ GETEVENTFUNC pfnAddEvent;
+}GCPTRS;
+
+
#define MODULE_NAME "HistoryLog"
@@ -76,5 +87,8 @@ extern PLUGINLINK *pluginLink;
BOOL IsEventEnabled(WORD eventType);
void SetEventEnabled(WORD eventType, BOOL enable);
+BOOL IsChatEventEnabled(WORD type);
+void SetChatEventEnabled(WORD type, BOOL enable);
+
#endif // __COMMONS_H__
diff --git a/Plugins/historylog/historylog.cpp b/Plugins/historylog/historylog.cpp
index 85e22a0..9a0b422 100644
--- a/Plugins/historylog/historylog.cpp
+++ b/Plugins/historylog/historylog.cpp
@@ -31,7 +31,7 @@ PLUGININFOEX pluginInfo={
#else
"History Log",
#endif
- PLUGIN_MAKE_VERSION(0,0,0,2),
+ PLUGIN_MAKE_VERSION(0,0,0,3),
"Logs history events to disk on the fly",
"Ricardo Pescuma Domenecci",
"",
@@ -53,7 +53,10 @@ PLUGINLINK *pluginLink;
LIST_INTERFACE li;
char *metacontacts_proto = NULL;
-ContactAsyncQueue *queue;
+BOOL shutingDown = FALSE;
+
+ContactAsyncQueue *queue = NULL;
+ContactAsyncQueue *chatQueue = NULL;
static HANDLE hHooks[3] = {0};
@@ -62,6 +65,10 @@ int PreShutdown(WPARAM wParam, LPARAM lParam);
int DbEventAdded(WPARAM wParam, LPARAM lParam);
void ProcessEvent(HANDLE hContact, void *param);
+void ProcessChat(HANDLE hDummy, void *param);
+
+void InitChat();
+void FreeChat();
// Functions ////////////////////////////////////////////////////////////////////////////
@@ -115,7 +122,10 @@ extern "C" int __declspec(dllexport) Load(PLUGINLINK *link)
InitOptions();
- queue = new ContactAsyncQueue(ProcessEvent, 1);
+ queue = new ContactAsyncQueue(ProcessEvent);
+ chatQueue = new ContactAsyncQueue(ProcessChat);
+
+ InitChat();
return 0;
}
@@ -167,9 +177,16 @@ int ModulesLoaded(WPARAM wParam, LPARAM lParam)
int PreShutdown(WPARAM wParam, LPARAM lParam)
{
+ shutingDown = TRUE;
+
+ FreeChat();
+
delete queue;
queue = NULL;
+ delete chatQueue;
+ chatQueue = NULL;
+
DeInitOptions();
for(int i = 0; i < MAX_REGS(hHooks); i++)
@@ -213,7 +230,7 @@ BOOL IsProtocolEnabled(const char *proto)
return FALSE;
char setting[256];
- mir_snprintf(setting, sizeof(setting), "%sEnabled", proto);
+ mir_snprintf(setting, sizeof(setting), "Enable%s", proto);
return (BOOL) DBGetContactSettingByte(NULL, MODULE_NAME, setting, TRUE);
}
@@ -234,6 +251,38 @@ void SetEventEnabled(WORD eventType, BOOL enable)
}
+BOOL IsChatProtocolEnabled(const char *proto)
+{
+ if (proto == NULL)
+ return FALSE;
+
+ if ((CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_CHAT) == 0)
+ return FALSE;
+
+ char setting[256];
+ mir_snprintf(setting, sizeof(setting), "ChatEnable%s", proto);
+ return (BOOL) DBGetContactSettingByte(NULL, MODULE_NAME, setting, TRUE);
+}
+
+
+BOOL IsChatEventEnabled(WORD type)
+{
+ char setting[256];
+ mir_snprintf(setting, sizeof(setting), "Chat%dEnabled", (int) type);
+ return (BOOL) DBGetContactSettingByte(NULL, MODULE_NAME, setting, type == GC_EVENT_MESSAGE
+ || type == GC_EVENT_TOPIC
+ || type == GC_EVENT_ACTION);
+}
+
+
+void SetChatEventEnabled(WORD type, BOOL enable)
+{
+ char setting[256];
+ mir_snprintf(setting, sizeof(setting), "Chat%dEnabled", (int) type);
+ DBWriteContactSettingByte(NULL, MODULE_NAME, setting, enable);
+}
+
+
int DbEventAdded(WPARAM wParam, LPARAM lParam)
{
HANDLE hContact = (HANDLE) wParam;
@@ -328,10 +377,10 @@ void GetDateTexts(DWORD timestamp, TCHAR year[16], TCHAR month[16], TCHAR month_
filetime.dwLowDateTime=liFiletime.LowPart;
FileTimeToSystemTime(&filetime,&st);
- GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("yyyy"), year, MAX_REGS(year));
- GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("MM"), month, MAX_REGS(month));
- GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("MMMM"), month_name, MAX_REGS(month_name));
- GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("dd"), day, MAX_REGS(day));
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("yyyy"), year, 16);
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("MM"), month, 16);
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("MMMM"), month_name, 32);
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, _T("dd"), day, 16);
}
@@ -351,6 +400,142 @@ TCHAR * GetContactGroup(HANDLE hContact)
}
+void AppendToFile(TCHAR *filename_pattern, TCHAR **vars, int numVars, HANDLE hContact, TCHAR *text)
+{
+ char path[1024];
+ CallService(MS_DB_GETPROFILEPATH, (WPARAM) MAX_REGS(path), (LPARAM) path);
+
+ Buffer<TCHAR> filename;
+ filename.append(path);
+ filename.append(_T("\\"));
+
+ ReplaceTemplate(&filename, hContact, filename_pattern, vars, numVars);
+
+ // Replace invalid chars
+ filename.replaceAll(_T('\\'), _T('_'));
+ filename.replaceAll(_T('/'), _T('_'));
+ filename.replaceAll(_T(':'), _T('_'));
+ filename.replaceAll(_T('*'), _T('_'));
+ filename.replaceAll(_T('?'), _T('_'));
+ filename.replaceAll(_T('"'), _T('_'));
+ filename.replaceAll(_T('<'), _T('_'));
+ filename.replaceAll(_T('>'), _T('_'));
+ filename.replaceAll(_T('|'), _T('_'));
+
+ filename.pack();
+
+ // Assert folder exists
+ TCHAR *p = _tcschr(filename.str, _T('\\'));
+ if (p != NULL)
+ p = _tcschr(p+1, _T('\\'));
+ while(p != NULL)
+ {
+ *p = _T('\0');
+ CreateDirectory(filename.str, NULL);
+ *p = _T('\\');
+ p = _tcschr(p+1, _T('\\'));
+ }
+
+ BOOL writeBOM = (GetFileAttributes(filename.str) == INVALID_FILE_ATTRIBUTES);
+
+ FILE *out = _tfopen(filename.str, _T("ab"));
+ if (out != NULL)
+ {
+ if (writeBOM)
+ fprintf(out, "\xEF\xBB\xBF");
+
+ char *utf = mir_utf8encodeT(text);
+ fprintf(out, "%s\r\n", utf);
+ mir_free(utf);
+ fclose(out);
+ }
+}
+
+
+void AppendKeepingIndentationRemovingFormatting(Buffer<TCHAR> &text, TCHAR *eventText, BOOL ident)
+{
+ size_t spaces = text.len;
+ for(TCHAR *c = eventText; *c != NULL; c++)
+ {
+ if (*c == _T('\r'))
+ {
+ if (*(c+1) == _T('\n'))
+ continue;
+ else
+ *c = _T('\n');
+ }
+
+ if (*c == _T('\n'))
+ {
+ text.append(_T("\r\n"));
+ if (ident)
+ text.appendn(spaces, _T(' '));
+ }
+ else if (*c == _T('%'))
+ {
+ switch (*(c+1))
+ {
+ case _T('%'):
+ text.append(_T('%'));
+ c++;
+ break;
+
+ case 'b':
+ case 'u':
+ case 'i':
+ case 'B':
+ case 'U':
+ case 'I':
+ case 'r':
+ case 'C':
+ case 'F':
+ c++;
+ break;
+
+ case 'c':
+ case 'f':
+ c += 3;
+ break;
+
+ default:
+ text.append(_T('%'));
+ break;
+ }
+ }
+ else
+ {
+ text.append(*c);
+ }
+ }
+}
+
+
+void AppendKeepingIndentation(Buffer<TCHAR> &text, TCHAR *eventText, BOOL ident)
+{
+ size_t spaces = text.len;
+ for(TCHAR *c = eventText; *c != NULL; c++)
+ {
+ if (*c == _T('\r'))
+ {
+ if (*(c+1) == _T('\n'))
+ continue;
+ else
+ *c = _T('\n');
+ }
+ if (*c == _T('\n'))
+ {
+ text.append(_T("\r\n"));
+ if (ident)
+ text.appendn(spaces, _T(' '));
+ }
+ else
+ {
+ text.append(*c);
+ }
+ }
+}
+
+
void ProcessEvent(HANDLE hDbEvent, void *param)
{
HANDLE hContact = (HANDLE) param;
@@ -420,36 +605,9 @@ void ProcessEvent(HANDLE hDbEvent, void *param)
text.append(_T(": "));
}
- size_t spaces = text.len;
- for(TCHAR *c = eventText; *c != NULL; c++)
- {
- if (*c == _T('\r'))
- {
- if (*(c+1) == _T('\n'))
- continue;
- else
- *c = _T('\n');
- }
- if (*c == _T('\n'))
- {
- text.append(_T("\r\n"));
- if (opts.ident_multiline_msgs)
- text.appendn(spaces, _T(' '));
- }
- else
- {
- text.append(*c);
- }
- }
-// text.append(eventText);
- text.pack();
-
- char path[1024];
- CallService(MS_DB_GETPROFILEPATH, (WPARAM) MAX_REGS(path), (LPARAM) path);
+ AppendKeepingIndentation(text, eventText, opts.ident_multiline_msgs);
- Buffer<TCHAR> filename;
- filename.append(path);
- filename.append(_T("\\"));
+ text.pack();
TCHAR year[16];
TCHAR month[16];
@@ -473,43 +631,302 @@ void ProcessEvent(HANDLE hDbEvent, void *param)
_T("contact_id"), cid
};
- ReplaceTemplate(&filename, hContact, opts.filename_pattern, vars, MAX_REGS(vars));
+ AppendToFile(opts.filename_pattern, vars, MAX_REGS(vars), hContact, text.str);
- filename.replaceAll(_T('\\'), _T('_'));
- filename.replaceAll(_T('/'), _T('_'));
- filename.replaceAll(_T(':'), _T('_'));
- filename.replaceAll(_T('*'), _T('_'));
- filename.replaceAll(_T('?'), _T('_'));
- filename.replaceAll(_T('"'), _T('_'));
- filename.replaceAll(_T('<'), _T('_'));
- filename.replaceAll(_T('>'), _T('_'));
- filename.replaceAll(_T('|'), _T('_'));
+ mir_free(protocol);
+ mir_free(group);
+ mir_free(eventText);
+}
- filename.pack();
- // Assert folder exists
- TCHAR *p = _tcschr(filename.str, _T('\\'));
- if (p != NULL)
- p = _tcschr(p+1, _T('\\'));
- while(p != NULL)
+typedef HANDLE (*CREATESERVICEFUNCTION)(const char *,MIRANDASERVICE);
+CREATESERVICEFUNCTION originalCreateServiceFunction = NULL;
+MIRANDASERVICE originalChatGetEventPtrService = NULL;
+MIRANDASERVICE originalChatAddEventService = NULL;
+GETEVENTFUNC originalAddEvent = NULL;
+
+struct ChatMsg
+{
+ int type;
+ char *proto;
+ TCHAR *name;
+ DWORD time;
+ TCHAR *nick;
+ TCHAR *status;
+ TCHAR *text;
+ TCHAR *userInfo;
+};
+
+
+int ChatAddEvent(WPARAM wParam, LPARAM lParam)
+{
+ int ret;
+ if (originalAddEvent != NULL)
+ ret = originalAddEvent(wParam, lParam);
+
+ else if (originalChatAddEventService != NULL)
+ ret = originalChatAddEventService(wParam, lParam);
+
+ else
+ return GC_EVENT_ERROR;
+
+ if (shutingDown || chatQueue == NULL)
+ return ret;
+
+
+ GCEVENT *gce = (GCEVENT*) lParam;
+ if (gce == NULL)
+ return ret;
+
+ if (!(gce->dwFlags & GCEF_ADDTOLOG))
+ return ret;
+
+ GCDEST *gcd = gce->pDest;
+ if (gcd == NULL || gcd->pszModule == NULL || gcd->pszModule[0] == '\0'
+ || gcd->pszID == NULL || gcd->pszID[0] == '\0') // No all/active window messages right now
+ return ret;
+
+ if (gce->dwFlags & GC_UNICODE)
{
- *p = _T('\0');
- CreateDirectory(filename.str, NULL);
- *p = _T('\\');
- p = _tcschr(p+1, _T('\\'));
+ if (lstrcmpW((WCHAR *) gcd->pszID, L"Network log") == 0)
+ return ret;
+ }
+ else
+ {
+ if (strcmp(gcd->pszID, "Network log") == 0)
+ return ret;
}
- FILE *out = _tfopen(filename.str, _T("ab"));
- if (out != NULL)
+ ChatMsg *msg = new ChatMsg();
+
+ msg->type = gcd->iType;
+ msg->time = gce->time;
+ msg->proto = mir_strdup(gcd->pszModule);
+
+ if (gce->dwFlags & GC_UNICODE)
{
- char *utf = mir_utf8encodeT(text.str);
- fprintf(out, "%s\r\n", utf);
- mir_free(utf);
- fclose(out);
+ msg->name = mir_u2t((WCHAR *) gcd->pszID);
+ msg->nick = mir_u2t((WCHAR *) gce->pszNick);
+ msg->status = mir_u2t((WCHAR *) gce->pszStatus);
+ msg->text = mir_u2t((WCHAR *) gce->pszText);
+ msg->userInfo = mir_u2t((WCHAR *) gce->pszUserInfo);
+ }
+ else
+ {
+ msg->name = mir_a2t(gce->pszUID);
+ msg->nick = mir_a2t(gce->pszNick);
+ msg->status = mir_a2t(gce->pszStatus);
+ msg->text = mir_a2t(gce->pszText);
+ msg->userInfo = mir_a2t(gce->pszUserInfo);
}
- mir_free(protocol);
- mir_free(group);
- mir_free(eventText);
+ chatQueue->Add(500, 0, msg);
+
+ return ret;
+}
+
+
+void ProcessChat(HANDLE hDummy, void *param)
+{
+ if (param == NULL)
+ return;
+
+ ChatMsg *msg = (ChatMsg *) param;
+ msg->type = msg->type & ~GC_EVENT_HIGHLIGHT;
+
+ if (IsChatProtocolEnabled(msg->proto) && IsChatEventEnabled(msg->type))
+ {
+ int i;
+ for(i = lstrlen(msg->name) - 1; i > 0
+ && (msg->name[i] == _T(' ') || msg->name[i] == _T('\t') || msg->name[i] == _T('-')); i--);
+ msg->name[i+1] = _T('\0');
+
+ TCHAR date[128];
+ DBTIMETOSTRINGT tst = {0};
+ tst.szFormat = _T("d s");
+ tst.szDest = date;
+ tst.cbDest = 128;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM) msg->time, (LPARAM) &tst);
+
+ Buffer<TCHAR> text;
+ text.append(_T("["));
+ text.append(date);
+ text.append(_T("] "));
+
+ Buffer<TCHAR> nick;
+ if (msg->nick != NULL)
+ {
+ nick.append(msg->nick);
+ if (msg->userInfo)
+ {
+ nick.append(_T(" ("));
+ nick.append(msg->userInfo);
+ nick.append(_T(")"));
+ }
+ }
+ nick.pack();
+
+ Buffer<TCHAR> plain;
+ if (msg->text != NULL)
+ {
+ AppendKeepingIndentationRemovingFormatting(plain, msg->text, FALSE);
+ plain.replaceAll('\r', ' ');
+ plain.replaceAll('\n', ' ');
+ }
+ plain.pack();
+
+ switch (msg->type)
+ {
+ case GC_EVENT_MESSAGE:
+ text.append(_T("* "));
+ text.append(nick);
+ text.append(_T(": "));
+ AppendKeepingIndentationRemovingFormatting(text, msg->text, opts.chat_ident_multiline_msgs);
+ break;
+ case GC_EVENT_ACTION:
+ text.append(_T("* "));
+ text.append(nick);
+ text.append(_T(" "));
+ AppendKeepingIndentationRemovingFormatting(text, msg->text, opts.chat_ident_multiline_msgs);
+ break;
+ case GC_EVENT_JOIN:
+ text.append(_T("> "));
+ text.appendPrintf(TranslateT("%s has joined"), nick.str);
+ break;
+ case GC_EVENT_PART:
+ text.append(_T("< "));
+ if (msg->text == NULL)
+ text.appendPrintf(TranslateT("%s has left"), nick.str);
+ else
+ text.appendPrintf(TranslateT("%s has left (%s)"), nick.str, plain.str);
+ break;
+ case GC_EVENT_QUIT:
+ text.append(_T("< "));
+ if (msg->text == NULL)
+ text.appendPrintf(TranslateT("%s has disconnected"), nick.str);
+ else
+ text.appendPrintf(TranslateT("%s has disconnected (%s)"), nick.str, plain.str);
+ break;
+ case GC_EVENT_NICK:
+ text.append(_T("^ "));
+ text.appendPrintf(TranslateT("%s is now known as %s"), nick.str, msg->text);
+ break;
+ case GC_EVENT_KICK:
+ text.append(_T("~ "));
+ if (msg->text == NULL)
+ text.appendPrintf(TranslateT("%s kicked %s"), msg->status, nick.str);
+ else
+ text.appendPrintf(TranslateT("%s kicked %s (%s)"), msg->status, nick.str, plain.str);
+ break;
+ case GC_EVENT_NOTICE:
+ text.append(_T("¤ "));
+ text.appendPrintf(TranslateT("Notice from %s: %s"), nick.str, plain.str);
+ break;
+ case GC_EVENT_TOPIC:
+ text.append(_T("# "));
+ if (msg->nick == NULL)
+ text.appendPrintf(TranslateT("The topic is \'%s\'"), plain.str);
+ else
+ text.appendPrintf(TranslateT("The topic is \'%s\' (set by %s)"), plain.str, nick.str);
+ break;
+ case GC_EVENT_INFORMATION:
+ text.append(_T("! "));
+ text.append(plain);
+ break;
+ case GC_EVENT_ADDSTATUS:
+ text.append(_T("+ "));
+ text.appendPrintf(TranslateT("%s enables \'%s\' status for %s"), msg->text, msg->status, nick.str);
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ text.append(_T("- "));
+ text.appendPrintf(TranslateT("%s disables \'%s\' status for %s"), msg->text, msg->status, nick.str);
+ break;
+ }
+
+ text.pack();
+
+ TCHAR year[16];
+ TCHAR month[16];
+ TCHAR month_name[32];
+ TCHAR day[16];
+ GetDateTexts(msg->time, year, month, month_name, day);
+
+ TCHAR *protocol = mir_a2t(msg->proto);
+
+ TCHAR *vars[] = {
+ _T("protocol"), protocol,
+ _T("year"), year,
+ _T("month"), month,
+ _T("month_name"), month_name,
+ _T("day"), day,
+ _T("session"), msg->name
+ };
+
+ AppendToFile(opts.chat_filename_pattern, vars, MAX_REGS(vars), NULL, text.str);
+
+ mir_free(protocol);
+ }
+
+ mir_free(msg->proto);
+ mir_free(msg->name);
+ mir_free(msg->nick);
+ mir_free(msg->status);
+ mir_free(msg->text);
+ mir_free(msg->userInfo);
+ delete msg;
+}
+
+
+int ChatGetEventPtr(WPARAM wParam, LPARAM lParam)
+{
+ if (originalChatGetEventPtrService == NULL)
+ return -1;
+
+ int ret = originalChatGetEventPtrService(wParam, lParam);
+ if (ret != 0 || lParam == NULL || shutingDown)
+ return ret;
+
+ GCPTRS * gp = (GCPTRS *) lParam;
+ originalAddEvent = gp->pfnAddEvent;
+ gp->pfnAddEvent = &ChatAddEvent;
+
+ return ret;
+}
+
+
+HANDLE HackCreateServiceFunction(const char *name, MIRANDASERVICE service)
+{
+ if (name == NULL || service == NULL)
+ return originalCreateServiceFunction(name, service);
+
+ if (strcmp(name, MS_GC_GETEVENTPTR) == 0)
+ {
+ if (originalChatGetEventPtrService == NULL)
+ originalChatGetEventPtrService = service;
+
+ return originalCreateServiceFunction(name, &ChatGetEventPtr);
+ }
+ else if (strcmp(name, MS_GC_EVENT) == 0)
+ {
+ if (originalChatAddEventService == NULL)
+ originalChatAddEventService = service;
+
+ return originalCreateServiceFunction(name, &ChatAddEvent);
+ }
+
+ return originalCreateServiceFunction(name, service);
+}
+
+
+void InitChat()
+{
+ originalCreateServiceFunction = pluginLink->CreateServiceFunction;
+ pluginLink->CreateServiceFunction = HackCreateServiceFunction;
}
+
+void FreeChat()
+{
+ if (originalCreateServiceFunction)
+ pluginLink->CreateServiceFunction = originalCreateServiceFunction;
+}
diff --git a/Plugins/historylog/historylog.dsp b/Plugins/historylog/historylog.dsp
index 500761d..21a9bae 100644
--- a/Plugins/historylog/historylog.dsp
+++ b/Plugins/historylog/historylog.dsp
@@ -57,7 +57,7 @@ BSC32=bscmake.exe
LINK32=link.exe
# ADD BASE LINK32 user32.lib shell32.lib wininet.lib gdi32.lib /nologo /base:"0x67100000" /dll /machine:I386 /filealign:0x200
# SUBTRACT BASE LINK32 /pdb:none /map
-# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /map /debug /machine:I386 /out:"..\..\bin\release\Plugins\historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /map /debug /machine:I386 /out:"..\..\bin\release\Plugins\aa_historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT LINK32 /profile /pdb:none
!ELSEIF "$(CFG)" == "historylog - Win32 Debug"
@@ -86,7 +86,7 @@ BSC32=bscmake.exe
LINK32=link.exe
# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..bin\release\Plugins\historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT BASE LINK32 /profile /pdb:none
-# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /incremental:yes /debug /machine:I386 /out:"..\..\bin\debug\Plugins\historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /incremental:yes /debug /machine:I386 /out:"..\..\bin\debug\Plugins\aa_historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT LINK32 /profile /pdb:none
!ELSEIF "$(CFG)" == "historylog - Win32 Unicode Debug"
@@ -115,7 +115,7 @@ BSC32=bscmake.exe
LINK32=link.exe
# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x32100000" /dll /incremental:yes /debug /machine:I386 /out:"..\..\bin\debug\Plugins\historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT BASE LINK32 /profile /pdb:none
-# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /incremental:yes /debug /machine:I386 /out:"..\..\bin\debug unicode\Plugins\historylogW.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /incremental:yes /debug /machine:I386 /out:"..\..\bin\debug unicode\Plugins\aa_historylogW.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT LINK32 /profile /pdb:none
!ELSEIF "$(CFG)" == "historylog - Win32 Unicode Release"
@@ -144,7 +144,7 @@ BSC32=bscmake.exe
LINK32=link.exe
# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x32100000" /dll /map /machine:I386 /out:"..\..\bin\release\Plugins\historylog.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT BASE LINK32 /profile /pdb:none
-# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /map /debug /machine:I386 /out:"..\..\bin\release unicode\Plugins\historylogW.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
+# ADD LINK32 gdi32.lib kernel32.lib user32.lib ole32.lib oleaut32.lib /nologo /base:"0x3EC60000" /dll /map /debug /machine:I386 /out:"..\..\bin\release unicode\Plugins\aa_historylogW.dll" /filealign:0x200 /ALIGN:4096 /ignore:4108
# SUBTRACT LINK32 /profile /pdb:none
!ENDIF
diff --git a/Plugins/historylog/options.cpp b/Plugins/historylog/options.cpp
index 1773201..3ce843e 100644
--- a/Plugins/historylog/options.cpp
+++ b/Plugins/historylog/options.cpp
@@ -29,6 +29,7 @@ HANDLE hOptHook = NULL;
Options opts;
static BOOL CALLBACK OptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static BOOL CALLBACK ChatDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL AllowProtocol(const char *proto)
@@ -40,6 +41,15 @@ BOOL AllowProtocol(const char *proto)
}
+BOOL ChatAllowProtocol(const char *proto)
+{
+ if ((CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_CHAT) == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
static OptPageControl optionsControls[] = {
{ &opts.filename_pattern, CONTROL_TEXT, IDC_FILENAME, "FilenamePattern", (DWORD) _T("Log\\%group%\\%contact%.msgs") },
{ &opts.ident_multiline_msgs, CONTROL_CHECKBOX, IDC_IDENT_MULTILINE,"IdentMultilineMsgs", TRUE },
@@ -47,6 +57,13 @@ static OptPageControl optionsControls[] = {
};
+static OptPageControl chatControls[] = {
+ { &opts.chat_filename_pattern, CONTROL_TEXT, IDC_FILENAME, "ChatFilenamePattern", (DWORD) _T("Log\\Group Chats\\%session%.msgs") },
+ { &opts.chat_ident_multiline_msgs, CONTROL_CHECKBOX, IDC_IDENT_MULTILINE,"ChatIdentMultilineMsgs", TRUE },
+ { NULL, CONTROL_PROTOCOL_LIST, IDC_PROTOCOLS, "ChatEnable%s", TRUE, (int)ChatAllowProtocol }
+};
+
+
// Functions //////////////////////////////////////////////////////////////////////////////////////
@@ -56,12 +73,19 @@ int InitOptionsCallback(WPARAM wParam,LPARAM lParam)
OPTIONSDIALOGPAGE odp = {0};
odp.cbSize = sizeof(odp);
odp.hInstance = hInst;
- odp.ptszGroup = TranslateT("History");
- odp.ptszTitle = TranslateT("Disk Log");
- odp.pfnDlgProc = OptionsDlgProc;
+ odp.ptszGroup = _T("History");
+ odp.ptszTitle = _T("Disk Log");
odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+
+ odp.ptszTab = _T("Messages");
+ odp.pfnDlgProc = OptionsDlgProc;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
+ odp.ptszTab = _T("Group Chat");
+ odp.pfnDlgProc = ChatDlgProc;
CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+
return 0;
}
@@ -69,6 +93,7 @@ int InitOptionsCallback(WPARAM wParam,LPARAM lParam)
void LoadOptions()
{
LoadOpts(optionsControls, MAX_REGS(optionsControls), MODULE_NAME);
+ LoadOpts(chatControls, MAX_REGS(chatControls), MODULE_NAME);
}
@@ -250,7 +275,8 @@ static BOOL CALLBACK OptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARA
ScrollWindowEx(hwndDlg, 0, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN);
- UpdateWindow(hwndDlg);
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ //UpdateWindow(hwndDlg);
// Reset the scroll bar.
@@ -296,3 +322,183 @@ static BOOL CALLBACK OptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARA
return SaveOptsDlgProc(optionsControls, MAX_REGS(optionsControls), MODULE_NAME, hwndDlg, msg, wParam, lParam);
}
+
+
+
+struct
+{
+ int type;
+ TCHAR *name;
+}
+CHAT_EVENTS[] =
+{
+ { GC_EVENT_MESSAGE, _T("Message") },
+ { GC_EVENT_ACTION, _T("Action") },
+ { GC_EVENT_JOIN, _T("User joined") },
+ { GC_EVENT_PART, _T("User left") },
+ { GC_EVENT_QUIT, _T("User disconnected") },
+ { GC_EVENT_KICK, _T("User kicked") },
+ { GC_EVENT_NICK, _T("Nickname change") },
+ { GC_EVENT_NOTICE, _T("Notice") },
+ { GC_EVENT_TOPIC, _T("Topic change") },
+ { GC_EVENT_INFORMATION, _T("Information message") },
+ { GC_EVENT_ADDSTATUS, _T("Status enabled") },
+ { GC_EVENT_REMOVESTATUS, _T("Status disabled") }
+};
+
+static BOOL CALLBACK ChatDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int avaiable = 0;
+ static int total = 0;
+ static int current = 0;
+ static int lineHeigth = 0;
+ static int eventTypeCount = 0;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_EVENT_TYPES), &rc);
+
+ POINT pt = { rc.left, rc.bottom + 5 };
+ ScreenToClient(hwndDlg, &pt);
+ int origY = pt.y;
+
+ GetClientRect(hwndDlg, &rc);
+
+ HFONT hFont = (HFONT) SendMessage(hwndDlg, WM_GETFONT, 0, 0);
+ TEXTMETRIC font;
+ GetTextMetric(hFont, &font);
+
+ int height = max(font.tmHeight, 16) + 4;
+ int width = rc.right - rc.left - 50;
+
+ lineHeigth = height;
+
+ // Create all items
+ int id = IDC_EVENT_TYPES + 100;
+ eventTypeCount = MAX_REGS(CHAT_EVENTS);
+ for (int k = 0; k < eventTypeCount; k++)
+ {
+ int x = pt.x + 20;
+
+ // Event type
+
+ HWND chk = CreateWindow(_T("BUTTON"), TranslateTS(CHAT_EVENTS[k].name),
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_CHECKBOX | BS_AUTOCHECKBOX,
+ x, pt.y, width - (x - pt.x), height, hwndDlg, (HMENU) id, hInst, NULL);
+ SendMessage(chk, WM_SETFONT, (WPARAM) hFont, FALSE);
+ SendMessage(chk, BM_SETCHECK, IsChatEventEnabled(CHAT_EVENTS[k].type) ? BST_CHECKED : BST_UNCHECKED, 0);
+ id ++;
+
+ pt.y += height;
+ }
+
+ avaiable = rc.bottom - rc.top;
+ total = pt.y;
+ current = 0;
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = total;
+ si.nPage = avaiable;
+ si.nPos = current;
+ SetScrollInfo(hwndDlg, SB_VERT, &si, TRUE);
+
+ break;
+ }
+
+ case WM_VSCROLL:
+ {
+ int yDelta; // yDelta = new_pos - current_pos
+ int yNewPos; // new position
+
+ switch (LOWORD(wParam))
+ {
+ case SB_PAGEUP:
+ yNewPos = current - avaiable / 2;
+ break;
+ case SB_PAGEDOWN:
+ yNewPos = current + avaiable / 2;
+ break;
+ case SB_LINEUP:
+ yNewPos = current - lineHeigth;
+ break;
+ case SB_LINEDOWN:
+ yNewPos = current + lineHeigth;
+ break;
+ case SB_THUMBPOSITION:
+ yNewPos = HIWORD(wParam);
+ break;
+ case SB_THUMBTRACK:
+ yNewPos = HIWORD(wParam);
+ break;
+ default:
+ yNewPos = current;
+ }
+
+ yNewPos = min(total - avaiable, max(0, yNewPos));
+
+ if (yNewPos == current)
+ break;
+
+ yDelta = yNewPos - current;
+ current = yNewPos;
+
+ // Scroll the window. (The system repaints most of the
+ // client area when ScrollWindowEx is called; however, it is
+ // necessary to call UpdateWindow in order to repaint the
+ // rectangle of pixels that were invalidated.)
+
+ ScrollWindowEx(hwndDlg, 0, -yDelta, (CONST RECT *) NULL,
+ (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
+ SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN);
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ //UpdateWindow(hwndDlg);
+
+ // Reset the scroll bar.
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ si.nPos = current;
+ SetScrollInfo(hwndDlg, SB_VERT, &si, TRUE);
+
+ break;
+ }
+
+ case WM_COMMAND:
+ {
+ if ((HWND) lParam != GetFocus())
+ break;
+
+ int id = LOWORD(wParam);
+ if (id >= IDC_EVENT_TYPES + 100 && id < IDC_EVENT_TYPES + 100 + eventTypeCount)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+ if (lpnmhdr->idFrom != 0 || lpnmhdr->code != PSN_APPLY)
+ break;
+
+ // Create all items
+ int id = IDC_EVENT_TYPES + 100;
+ for (int k = 0; k < eventTypeCount; k++)
+ {
+ SetChatEventEnabled(CHAT_EVENTS[k].type, IsDlgButtonChecked(hwndDlg, id));
+ id ++;
+ }
+
+ break;
+ }
+
+ }
+
+ return SaveOptsDlgProc(chatControls, MAX_REGS(chatControls), MODULE_NAME, hwndDlg, msg, wParam, lParam);
+}
diff --git a/Plugins/historylog/options.h b/Plugins/historylog/options.h
index e0b327b..9d50762 100644
--- a/Plugins/historylog/options.h
+++ b/Plugins/historylog/options.h
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2006 Ricardo Pescuma Domenecci
+Copyright (C) 2008 Ricardo Pescuma Domenecci
This is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -30,6 +30,9 @@ typedef struct
TCHAR filename_pattern[1024];
BYTE ident_multiline_msgs;
+ TCHAR chat_filename_pattern[1024];
+ BYTE chat_ident_multiline_msgs;
+
} Options;
extern Options opts;
diff --git a/Plugins/historylog/resource.h b/Plugins/historylog/resource.h
index 5e20b99..c7ebaea 100644
--- a/Plugins/historylog/resource.h
+++ b/Plugins/historylog/resource.h
@@ -1,5 +1,5 @@
//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
+// Microsoft Developer Studio generated include file.
// Used by resource.rc
//
#define IDD_OPTIONS 119
@@ -86,7 +86,7 @@
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 126
#define _APS_NEXT_COMMAND_VALUE 40004
-#define _APS_NEXT_CONTROL_VALUE 1106
+#define _APS_NEXT_CONTROL_VALUE 1107
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/Plugins/historylog/resource.rc b/Plugins/historylog/resource.rc
index 6e5ca07..70a6d49 100644
--- a/Plugins/historylog/resource.rc
+++ b/Plugins/historylog/resource.rc
@@ -1,4 +1,4 @@
-// Microsoft Visual C++ generated resource script.
+//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
@@ -27,17 +27,20 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// Dialog
//
-IDD_OPTIONS DIALOGEX 0, 0, 306, 228
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_VSCROLL
+IDD_OPTIONS DIALOGEX 0, 0, 319, 231
+STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_VSCROLL
EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
+FONT 8, "MS Shell Dlg"
BEGIN
- LTEXT "Filename pattern:",IDC_STATIC,5,5,76,11
- EDITTEXT IDC_FILENAME,87,3,193,14,ES_AUTOHSCROLL
- LTEXT "Only log for these protocols:",IDC_STATIC,5,42,275,9
- CONTROL "",IDC_PROTOCOLS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,13,54,142,55
- LTEXT "Only these event types:",IDC_EVENT_TYPES,5,120,275,10
- CONTROL "Ident multi-line messages",IDC_IDENT_MULTILINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,23,275,12
+ LTEXT "Filename pattern:",IDC_STATIC,5,9,76,11
+ EDITTEXT IDC_FILENAME,87,7,193,14,ES_AUTOHSCROLL
+ LTEXT "Only log for these protocols:",IDC_STATIC,5,46,275,9
+ CONTROL "",IDC_PROTOCOLS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER |
+ LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,13,58,142,55
+ LTEXT "Only these event types:",IDC_EVENT_TYPES,5,124,275,10
+ CONTROL "Ident multi-line messages",IDC_IDENT_MULTILINE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,5,27,275,12
END
@@ -47,13 +50,13 @@ END
//
#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
+GUIDELINES DESIGNINFO MOVEABLE PURE
BEGIN
IDD_OPTIONS, DIALOG
BEGIN
LEFTMARGIN, 3
- RIGHTMARGIN, 292
- BOTTOMMARGIN, 225
+ RIGHTMARGIN, 305
+ BOTTOMMARGIN, 228
END
END
#endif // APSTUDIO_INVOKED
@@ -77,19 +80,19 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN
// TEXTINCLUDE
//
-1 TEXTINCLUDE
+1 TEXTINCLUDE MOVEABLE PURE
BEGIN
"resource.h\0"
END
-2 TEXTINCLUDE
+2 TEXTINCLUDE MOVEABLE PURE
BEGIN
"#include ""resource.h""\r\n"
"#include ""winresrc.h""\r\n"
"\0"
END
-3 TEXTINCLUDE
+3 TEXTINCLUDE MOVEABLE PURE
BEGIN
"\r\n"
"\0"