summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-05-07 12:59:46 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-05-07 12:59:46 +0300
commita5dee9d892a8d7c56657842c1e7a4ca742dc41b5 (patch)
treedc78f3a176f32fe99f183d3069afc189995c5865
parent4ab93d52285bf072cea05ceac5333a1587c9980b (diff)
MsgExport: fix for writing data about offline files + export-related code finally moved to the separate file
-rw-r--r--plugins/Msg_Export/msg_export.vcxproj1
-rw-r--r--plugins/Msg_Export/msg_export.vcxproj.filters3
-rw-r--r--plugins/Msg_Export/src/export.cpp445
-rw-r--r--plugins/Msg_Export/src/options.cpp2
-rw-r--r--plugins/Msg_Export/src/utils.cpp548
-rw-r--r--plugins/Msg_Export/src/utils.h4
-rw-r--r--plugins/NewStory/src/version.h2
7 files changed, 489 insertions, 516 deletions
diff --git a/plugins/Msg_Export/msg_export.vcxproj b/plugins/Msg_Export/msg_export.vcxproj
index e25874b1f9..5f093aec81 100644
--- a/plugins/Msg_Export/msg_export.vcxproj
+++ b/plugins/Msg_Export/msg_export.vcxproj
@@ -26,6 +26,7 @@
<Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
</ImportGroup>
<ItemGroup>
+ <ClCompile Include="src\export.cpp" />
<ClCompile Include="src\FileViewer.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\options.cpp" />
diff --git a/plugins/Msg_Export/msg_export.vcxproj.filters b/plugins/Msg_Export/msg_export.vcxproj.filters
index cdbccc06ab..4ad24bf9d2 100644
--- a/plugins/Msg_Export/msg_export.vcxproj.filters
+++ b/plugins/Msg_Export/msg_export.vcxproj.filters
@@ -17,6 +17,9 @@
<ClCompile Include="src\utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\export.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\FileViewer.h">
diff --git a/plugins/Msg_Export/src/export.cpp b/plugins/Msg_Export/src/export.cpp
new file mode 100644
index 0000000000..95675786df
--- /dev/null
+++ b/plugins/Msg_Export/src/export.cpp
@@ -0,0 +1,445 @@
+/*
+Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h"
+
+const char szUtf8ByteOrderHeader[] = "\xEF\xBB\xBF";
+bool bIsUtf8Header(uint8_t *pucByteOrder)
+{
+ return memcmp(pucByteOrder, szUtf8ByteOrderHeader, 3) == 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Member Function : bWriteToFile
+// Type : Global
+// Parameters : hFile - ?
+// pszSrc - in UTF8 or ANSII
+// nLen - ?
+// Returns : Returns true if all the data was written to the file
+
+static bool bWriteToFile(HANDLE hFile, const char *pszSrc, int nLen = -1)
+{
+ if (nLen < 0)
+ nLen = (int)mir_strlen(pszSrc);
+
+ DWORD dwBytesWritten;
+ return WriteFile(hFile, pszSrc, nLen, &dwBytesWritten, nullptr) && (dwBytesWritten == (uint32_t)nLen);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Member Function : bWriteTextToFile
+// Type : Global
+// Parameters : hFile - ?
+// pszSrc - ?
+// bUtf8File - ?
+// Returns : Returns true if
+
+static bool bWriteTextToFile(HANDLE hFile, const wchar_t *pszSrc, bool bUtf8File, int nLen = -1)
+{
+ if (nLen != -1) {
+ wchar_t *tmp = (wchar_t *)alloca(sizeof(wchar_t) * (nLen + 1));
+ mir_wstrncpy(tmp, pszSrc, nLen + 1);
+ pszSrc = tmp;
+ }
+
+ if (!bUtf8File) {
+ // We need to downgrade text to ansi
+ ptrA pszAstr(mir_u2a(pszSrc));
+ return bWriteToFile(hFile, pszAstr, -1);
+ }
+
+ return bWriteToFile(hFile, T2Utf(pszSrc), -1);
+}
+
+/////////////////////////////////////////////////////////////////////
+// Member Function : bWriteNewLine
+// Type : Global
+// Parameters : hFile - ?
+// nIndent - ?
+// Returns : Returns true if all the data was written to the file
+
+const wchar_t wszNewLineIndent[] = L"\r\n ";
+void bWriteNewLine(CMStringW &str, int dwIndent)
+{
+ if (dwIndent > sizeof(wszNewLineIndent) - 2)
+ dwIndent = sizeof(wszNewLineIndent) - 2;
+
+ str.Append(wszNewLineIndent, dwIndent + 2);
+}
+
+/////////////////////////////////////////////////////////////////////
+// Member Function : bWriteHexToFile
+// Type : Global
+// Parameters : hFile - ?
+// - ?
+// nSize - ?
+
+bool bWriteHexToFile(HANDLE hFile, void *pData, int nSize)
+{
+ char cBuf[10];
+ uint8_t *p = (uint8_t *)pData;
+ for (int n = 0; n < nSize; n++) {
+ mir_snprintf(cBuf, "%.2X ", p[n]);
+ if (!bWriteToFile(hFile, cBuf, 3))
+ return false;
+ }
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Member Function : bWriteIndentedToFile
+// Type : Global
+// Parameters : hFile - ?
+// nIndent - ?
+// pszSrc -
+// Returns : Returns true if
+
+static bool bWriteIndentedToFile(CMStringW &str, int nIndent, const wchar_t *pszSrc)
+{
+ if (pszSrc == nullptr)
+ return true;
+
+ bool bOk = true;
+ bool bFirstLine = true;
+
+ while (*pszSrc) { // first we will scan forward in string to finde either new line or "max line with"
+ int nLineLen = 0;
+ do {
+ if (pszSrc[nLineLen] == '\n' || pszSrc[nLineLen] == '\r')
+ break;
+
+ // if user set nMaxLineWidth to 0, we don't break anything, otherwise check the length
+ if (nMaxLineWidth != 0 && nLineLen >= nMaxLineWidth) {
+ // ok the line was not broken. we need to force a break
+ // we will scan backwards again to finde a space !!
+ // then we will look for a ? and so on.
+
+ const wchar_t ac[] = { ' ', '?', '-', '.', ',' };
+ for (auto &it : ac) {
+ for (int n = nLineLen; n > 0; n--) {
+ if (pszSrc[n] == it) {
+ nLineLen = n;
+ goto SuperBreak;
+ }
+ }
+ }
+ break;
+ }
+ nLineLen++;
+ } while (pszSrc[nLineLen]);
+
+ // trim away traling spaces !!
+ if (nLineLen > 0) {
+ while (pszSrc[nLineLen - 1] == ' ')
+ nLineLen--;
+ }
+
+SuperBreak:
+ // nLineLen should contain the number af chars we need to write to the file
+ if (nLineLen > 0) {
+ if (!bFirstLine)
+ bWriteNewLine(str, nIndent);
+
+ str.Append(pszSrc, nLineLen);
+ }
+ bFirstLine = false;
+
+ // skip any noice chars, MAC style '\r' '\r' '\n'
+ // and excess spaces
+ const wchar_t *pszPrev = pszSrc;
+ pszSrc += nLineLen;
+ while (*pszSrc == ' ' || *pszSrc == '\n' || *pszSrc == '\r')
+ pszSrc++;
+
+ if (pszPrev == pszSrc) {
+ // this is an programming error we have not moved forward in string
+ MessageBox(nullptr, L"Programming error on line __LINE__ please report this", MSG_BOX_TITEL, MB_OK);
+ break;
+ }
+ }
+
+ // if bOk if false file writing failed
+ return bOk;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Member Function : ExportDBEventInfo
+// Type : Global
+// Parameters : hContact - handle to contact
+// hFile - handle to file
+// sFilePath - path to file
+// dbei - Event to export
+// Returns : false on serious error, when file should be closed to not lost/overwrite any data
+
+const char *pSettings[] =
+{
+ LPGEN("FirstName"),
+ LPGEN("LastName"),
+ LPGEN("e-mail"),
+ LPGEN("Nick"),
+ LPGEN("Age"),
+ LPGEN("Gender"),
+ LPGEN("City"),
+ LPGEN("State"),
+ LPGEN("Phone"),
+ LPGEN("Homepage"),
+ LPGEN("About")
+};
+
+static bool ExportDBEventInfo(MCONTACT hContact, HANDLE hFile, const wstring &sFilePath, DB::EventInfo &dbei, bool bAppendOnly)
+{
+ wstring sLocalUser;
+ wstring sRemoteUser;
+ string::size_type nFirstColumnWidth;
+ auto *pJson = (MDatabaseExport *)hFile;
+
+ const char *szProto = Proto_GetBaseAccountName(hContact);
+ if (szProto == nullptr) {
+ Netlib_Logf(0, MODULENAME ": cannot write message for a contact %d without protocol", hContact);
+ return false;
+ }
+
+ if (g_plugin.bUseAngleBrackets) {
+ sLocalUser = L"<<";
+ sRemoteUser = L">>";
+ nFirstColumnWidth = 4;
+ }
+ else {
+ sLocalUser = ptrW(GetMyOwnNick(hContact));
+ sRemoteUser = Clist_GetContactDisplayName(hContact);
+
+ nFirstColumnWidth = max(sRemoteUser.size(), clFileTo1ColWidth[sFilePath]);
+ nFirstColumnWidth = max(sLocalUser.size(), nFirstColumnWidth);
+ nFirstColumnWidth += 2;
+ }
+
+ bool bWriteUTF8Format = false;
+
+ if (bAppendOnly) {
+ bWriteUTF8Format = g_plugin.bUseUtf8InNewFiles;
+ }
+ else {
+ if (g_bUseJson) {
+ if (!pJson->BeginExport())
+ pJson->ExportContact(hContact);
+ }
+ else {
+ DWORD dwHighSize = 0;
+ DWORD dwLowSize = GetFileSize(hFile, &dwHighSize);
+ if (dwLowSize == INVALID_FILE_SIZE || dwLowSize != 0 || dwHighSize != 0) {
+ DWORD dwDataRead = 0;
+ uint8_t ucByteOrder[3];
+ if (ReadFile(hFile, ucByteOrder, 3, &dwDataRead, nullptr))
+ bWriteUTF8Format = bIsUtf8Header(ucByteOrder);
+
+ DWORD dwPtr = SetFilePointer(hFile, 0, nullptr, FILE_END);
+ if (dwPtr == INVALID_SET_FILE_POINTER)
+ return false;
+ }
+ else {
+ bWriteUTF8Format = g_plugin.bUseUtf8InNewFiles;
+ if (bWriteUTF8Format)
+ if (!bWriteToFile(hFile, szUtf8ByteOrderHeader, sizeof(szUtf8ByteOrderHeader) - 1))
+ return false;
+
+ CMStringW output = L"------------------------------------------------\r\n";
+ output.AppendFormat(L"%s\r\n", TranslateT(" History for"));
+
+ // This is written this way because I expect this will become a string the user may set
+ // in the options dialog.
+ output.AppendFormat(L"%-10s: %s\r\n", TranslateT("User"), sRemoteUser.c_str());
+ output.AppendFormat(L"%-10s: %S\r\n", TranslateT("Account"), szProto);
+
+ ptrW id(Contact::GetInfo(CNF_UNIQUEID, hContact, szProto));
+ if (id != NULL)
+ output.AppendFormat(L"%-10s: %s\r\n", TranslateT("User ID"), id.get());
+
+ int c = db_get_b(hContact, szProto, "Gender", 0);
+ if (c)
+ output.AppendFormat(L"%-10s: %c\r\n", TranslateT("Gender"), c);
+
+ int age = db_get_w(hContact, szProto, "Age", 0);
+ if (age != 0)
+ output.AppendFormat(L"%-10s: %d\r\n", TranslateT("Age"), age);
+
+ for (auto &it : pSettings) {
+ wstring szValue = _DBGetStringW(hContact, szProto, it, L"");
+ if (!szValue.empty())
+ output.AppendFormat(L"%-10s: %s\r\n", TranslateW(_A2T(it)), szValue.c_str());
+ }
+
+ output += L"------------------------------------------------\r\n";
+
+ if (!bWriteTextToFile(hFile, output, bWriteUTF8Format, output.GetLength()))
+ return false;
+ }
+ }
+ }
+
+ if (g_bUseJson) {
+ pJson->ExportEvent(dbei);
+ return true;
+ }
+
+ if (dbei.szUserId && Contact::IsGroupChat(hContact))
+ if (auto *si = Chat_Find(hContact, szProto))
+ if (auto *pUser = g_chatApi.UM_FindUser(si, Utf2T(dbei.szUserId)))
+ sRemoteUser = pUser->pszNick;
+
+ // Get time stamp
+ CMStringW output;
+ output.AppendFormat(L"%-*s", (int)nFirstColumnWidth, dbei.flags & DBEF_SENT ? sLocalUser.c_str() : sRemoteUser.c_str());
+ {
+ wchar_t buf[100];
+ TimeZone_ToStringW(dbei.timestamp, g_sTimeFormat.c_str(), buf, _countof(buf));
+ output.Append(buf);
+ }
+
+ output.AppendChar(' ');
+ int nIndent = output.GetLength();
+
+ if (dbei.pBlob != nullptr && dbei.cbBlob >= 2) {
+ dbei.pBlob[dbei.cbBlob] = 0;
+
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ output += ptrW(DbEvent_GetTextW(&dbei));
+ break;
+
+ case EVENTTYPE_FILE:
+ {
+ DB::FILE_BLOB blob(dbei);
+ if (!blob.isCompleted())
+ return false;
+
+ output.Append(L"File: ");
+ bWriteIndentedToFile(output, nIndent, blob.getName());
+
+ if (mir_wstrlen(blob.getDescr())) {
+ bWriteNewLine(output, nIndent);
+ output.Append(L"Description: ");
+ bWriteIndentedToFile(output, nIndent, blob.getDescr());
+ }
+
+ if (blob.isOffline()) {
+ CMStringW val(FORMAT, L"%lld", blob.getSize());
+ bWriteNewLine(output, nIndent);
+ output.Append(L"Size: ");
+ bWriteIndentedToFile(output, nIndent, val);
+
+ val.Format(L"%lld", blob.getTransferred());
+ bWriteNewLine(output, nIndent);
+ output.Append(L"Transferred: ");
+ bWriteIndentedToFile(output, nIndent, val);
+
+ if (mir_wstrlen(blob.getLocalName())) {
+ bWriteNewLine(output, nIndent);
+ output.Append(L"Path: ");
+ bWriteIndentedToFile(output, nIndent, blob.getLocalName());
+ }
+
+ if (mir_strlen(blob.getUrl())) {
+ bWriteNewLine(output, nIndent);
+ output.Append(L"URL: ");
+ bWriteIndentedToFile(output, nIndent, _A2T(blob.getUrl()));
+ }
+ }
+ }
+ break;
+
+ case EVENTTYPE_AUTHREQUEST:
+ case EVENTTYPE_ADDED:
+ {
+ const wchar_t *pszTypes[] = {
+ LPGENW("Nick :"),
+ LPGENW("FirstName :"),
+ LPGENW("LastName :"),
+ LPGENW("e-mail :"),
+ LPGENW("Reason :") };
+
+ if (dbei.cbBlob < 8 || dbei.cbBlob > 5000) {
+ output.AppendFormat(TranslateT("Invalid Database event received. Type %d, size %d"), dbei.eventType, dbei.cbBlob);
+ break;
+ }
+
+ int nStringCount;
+ char *pszCurBlobPos;
+ if (dbei.eventType == EVENTTYPE_AUTHREQUEST) { // request
+ //blob is: uin(uint32_t), hContact(uint32_t), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)
+ nStringCount = 5;
+ pszCurBlobPos = (char *)dbei.pBlob + sizeof(uint32_t) * 2;
+ output.Append(L"The following user made an authorization request:");
+ }
+ else { // Added
+ //blob is: uin(uint32_t), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ)
+ pszCurBlobPos = (char *)dbei.pBlob + sizeof(uint32_t);
+ nStringCount = 4;
+ output.Append(L"The following user added you to their contact list:");
+ }
+ bWriteNewLine(output, nIndent);
+
+ output.Append(L"UIN :");
+ output.AppendFormat(L"%d", *((PDWORD)(dbei.pBlob)));
+
+ char *pszEnd = (char *)(dbei.pBlob + sizeof(dbei));
+ for (int i = 0; i < nStringCount && pszCurBlobPos < pszEnd; i++) {
+ if (*pszCurBlobPos) {
+ bWriteNewLine(output, nIndent);
+ output.Append(TranslateW(pszTypes[i]));
+ bWriteIndentedToFile(output, nIndent, _A2T(pszCurBlobPos));
+ }
+ pszCurBlobPos += mir_strlen(pszCurBlobPos) + 1;
+ }
+ }
+ break;
+
+ default:
+ output.AppendFormat(TranslateT("Unknown event type %d, size %d"), dbei.eventType, dbei.cbBlob);
+ break;
+ }
+ }
+ else {
+ output.AppendFormat(TranslateT("Unknown event type %d, size %d"), dbei.eventType, dbei.cbBlob);
+ }
+
+ output.Append(g_plugin.bAppendNewLine ? L"\r\n\r\n" : L"\r\n");
+ if (!bWriteTextToFile(hFile, output, bWriteUTF8Format, output.GetLength()))
+ return false;
+
+ UpdateFileViews(sFilePath.c_str());
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module entry point
+
+bool bExportEvent(MCONTACT hContact, MEVENT hDbEvent, HANDLE hFile, const wstring &sFilePath, bool bAppendOnly)
+{
+ bool result = true;
+
+ DB::EventInfo dbei(hDbEvent);
+ if (dbei) {
+ if (db_mc_isMeta(hContact))
+ hContact = dbei.hContact;
+
+ // Write the event
+ result = ExportDBEventInfo(hContact, hFile, sFilePath, dbei, bAppendOnly);
+ }
+
+ return result;
+}
diff --git a/plugins/Msg_Export/src/options.cpp b/plugins/Msg_Export/src/options.cpp
index a9d2ccb3fb..ef1d7ff71c 100644
--- a/plugins/Msg_Export/src/options.cpp
+++ b/plugins/Msg_Export/src/options.cpp
@@ -132,7 +132,7 @@ void __cdecl exportContactsMessages(struct ExportDialogData *data)
else {
hFile = openCreateFile(sFilePath);
if (hFile == INVALID_HANDLE_VALUE) {
- DisplayErrorDialog(LPGENW("Failed to open or create file:\n"), sFilePath, nullptr);
+ DisplayErrorDialog(LPGENW("Failed to open or create file:\n"), sFilePath);
continue;
}
}
diff --git a/plugins/Msg_Export/src/utils.cpp b/plugins/Msg_Export/src/utils.cpp
index 1c78003bea..36210a760b 100644
--- a/plugins/Msg_Export/src/utils.cpp
+++ b/plugins/Msg_Export/src/utils.cpp
@@ -59,12 +59,6 @@ bool g_bUseJson;
DATABASELINK *g_pDriver = nullptr;
-const char szUtf8ByteOrderHeader[] = "\xEF\xBB\xBF";
-bool bIsUtf8Header(uint8_t * pucByteOrder)
-{
- return memcmp(pucByteOrder, szUtf8ByteOrderHeader, 3) == 0;
-}
-
/////////////////////////////////////////////////////////////////////
// Member Function : nGetFormatCount
// Type : Global
@@ -180,81 +174,53 @@ void LogLastError(const wchar_t *pszError)
}
/////////////////////////////////////////////////////////////////////
-// Member Function : bWriteToFile
+// Member Function : nContactDeleted
// Type : Global
-// Parameters : hFile - ?
-// pszSrc - in UTF8 or ANSII
-// nLen - ?
-// Returns : Returns true if all the data was written to the file
+// Parameters : wparam - handle to the deleted Contact
+// lparam - 0
+// Returns : int
+// Description : Called when an contact is about to be deleted
-static bool bWriteToFile(HANDLE hFile, const char *pszSrc, int nLen = -1)
+int nContactDeleted(WPARAM hContact, LPARAM)
{
- if (nLen < 0)
- nLen = (int)mir_strlen(pszSrc);
-
- DWORD dwBytesWritten;
- return WriteFile(hFile, pszSrc, nLen, &dwBytesWritten, nullptr) && (dwBytesWritten == (uint32_t)nLen);
-}
-
+ HWND hInternalWindow = WindowList_Find(hInternalWindowList, hContact);
+ if (hInternalWindow)
+ CloseWindow(hInternalWindow);
-/////////////////////////////////////////////////////////////////////
-// Member Function : bWriteTextToFile
-// Type : Global
-// Parameters : hFile - ?
-// pszSrc - ?
-// bUtf8File - ?
-// Returns : Returns true if
+ if (g_enDeleteAction == eDANothing)
+ return 0;
-static bool bWriteTextToFile(HANDLE hFile, const wchar_t *pszSrc, bool bUtf8File, int nLen = -1)
-{
- if (nLen != -1) {
- wchar_t *tmp = (wchar_t*)alloca(sizeof(wchar_t)*(nLen + 1));
- mir_wstrncpy(tmp, pszSrc, nLen + 1);
- pszSrc = tmp;
- }
+ wstring sFilePath = GetFilePathFromUser(hContact);
- if (!bUtf8File) {
- // We need to downgrade text to ansi
- ptrA pszAstr(mir_u2a(pszSrc));
- return bWriteToFile(hFile, pszAstr, -1);
- }
+ // Test if there is another user using this file
+ for (auto &hOtherContact : Contacts())
+ if (hContact != hOtherContact && sFilePath == GetFilePathFromUser(hOtherContact))
+ return 0; // we found another contact abort mission :-)
- return bWriteToFile(hFile, T2Utf(pszSrc), -1);
-}
+ // Test to see if there is a file to delete
+ HANDLE hPrevFile = CreateFile(sFilePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hPrevFile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hPrevFile);
-/////////////////////////////////////////////////////////////////////
-// Member Function : bWriteNewLine
-// Type : Global
-// Parameters : hFile - ?
-// nIndent - ?
-// Returns : Returns true if all the data was written to the file
+ wchar_t szTemp[500];
+ mir_snwprintf(szTemp, L"%s\r\n%s", TranslateT("User has been deleted. Do you want to delete the file?"), sFilePath.c_str());
-const char szNewLineIndent[] = "\r\n ";
-bool bWriteNewLine(HANDLE hFile, uint32_t dwIndent)
-{
- if (dwIndent > sizeof(szNewLineIndent) - 2)
- dwIndent = sizeof(szNewLineIndent) - 2;
-
- return bWriteToFile(hFile, szNewLineIndent, dwIndent + 2);
+ if (g_enDeleteAction == eDAAutomatic || MessageBox(nullptr, szTemp, MSG_BOX_TITEL, MB_YESNO) == IDYES) {
+ if (!DeleteFile(sFilePath.c_str())) {
+ mir_snwprintf(szTemp, L"%s\r\n%s", TranslateT("Failed to delete the file"), sFilePath.c_str());
+ LogLastError(szTemp);
+ }
+ }
+ }
+ return 0;
}
/////////////////////////////////////////////////////////////////////
-// Member Function : bWriteHexToFile
-// Type : Global
-// Parameters : hFile - ?
-// - ?
-// nSize - ?
-bool bWriteHexToFile(HANDLE hFile, void * pData, int nSize)
+wchar_t* GetMyOwnNick(MCONTACT hContact)
{
- char cBuf[10];
- uint8_t *p = (uint8_t*)pData;
- for (int n = 0; n < nSize; n++) {
- mir_snprintf(cBuf, "%.2X ", p[n]);
- if (!bWriteToFile(hFile, cBuf, 3))
- return false;
- }
- return true;
+ wchar_t *p = Contact::GetInfo(CNF_DISPLAY, NULL, Proto_GetBaseAccountName(hContact));
+ return (p != nullptr) ? p : mir_wstrdup(TranslateT("No_Nick"));
}
/////////////////////////////////////////////////////////////////////
@@ -529,7 +495,7 @@ void UpdateFileToColWidth()
// sFile - ?
// dbei - ?
-void DisplayErrorDialog(const wchar_t *pszError, wstring &sFilePath, DBEVENTINFO *dbei)
+void DisplayErrorDialog(const wchar_t *pszError, wstring &sFilePath)
{
wstring sError = TranslateW(pszError);
sError += sFilePath;
@@ -537,303 +503,7 @@ void DisplayErrorDialog(const wchar_t *pszError, wstring &sFilePath, DBEVENTINFO
sError += sGetErrorString();
sError += TranslateT("\nMessage has not been saved!\n");
sError += TranslateT("Do you wish to save debug information?");
- if (MessageBox(nullptr, sError.c_str(), MSG_BOX_TITEL, MB_YESNO) == IDYES) {
- wchar_t szFile[260]; // buffer for file name
- wcsncpy_s(szFile, L"DebugInfo.txt", _TRUNCATE);
-
- // Initialize OPENFILENAME
- OPENFILENAME ofn = {};
- ofn.lStructSize = sizeof(OPENFILENAME);
- ofn.lpstrFile = szFile;
- ofn.nMaxFile = _countof(szFile);
- ofn.lpstrFilter = TranslateT("All\0*.*\0Text\0*.TXT\0\0");
- ofn.nFilterIndex = 1;
- ofn.lpstrDefExt = L"TXT";
-
- // Display the Open dialog box.
- if (GetSaveFileName(&ofn)) {
- HANDLE hf = CreateFile(ofn.lpstrFile, GENERIC_WRITE,
- 0, (LPSECURITY_ATTRIBUTES)nullptr,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
- (HANDLE)nullptr); // file handle
-
- bWriteTextToFile(hf, sError.c_str(), false);
- if (dbei) {
- bWriteToFile(hf, "\r\ndbei :");
-
- bWriteHexToFile(hf, dbei, sizeof(DBEVENTINFO));
- if (dbei->pBlob) {
- bWriteToFile(hf, "\r\ndbei.pBlob :");
- bWriteHexToFile(hf, dbei->pBlob, min(dbei->cbBlob, 10000));
- }
- if (dbei->szModule) {
- bWriteToFile(hf, "\r\ndbei.szModule :");
- bWriteToFile(hf, dbei->szModule);
- }
- }
- CloseHandle(hf);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-// Member Function : ExportDBEventInfo
-// Type : Global
-// Parameters : hContact - handle to contact
-// hFile - handle to file
-// sFilePath - path to file
-// dbei - Event to export
-// Returns : false on serious error, when file should be closed to not lost/overwrite any data
-
-const char *pSettings[] =
-{
- LPGEN("FirstName"),
- LPGEN("LastName"),
- LPGEN("e-mail"),
- LPGEN("Nick"),
- LPGEN("Age"),
- LPGEN("Gender"),
- LPGEN("City"),
- LPGEN("State"),
- LPGEN("Phone"),
- LPGEN("Homepage"),
- LPGEN("About")
-};
-
-static bool ExportDBEventInfo(MCONTACT hContact, HANDLE hFile, const wstring &sFilePath, DB::EventInfo &dbei, bool bAppendOnly)
-{
- wstring sLocalUser;
- wstring sRemoteUser;
- string::size_type nFirstColumnWidth;
- auto *pJson = (MDatabaseExport *)hFile;
-
- const char *szProto = Proto_GetBaseAccountName(hContact);
- if (szProto == nullptr) {
- Netlib_Logf(0, MODULENAME ": cannot write message for a contact %d without protocol", hContact);
- return false;
- }
-
- if (g_plugin.bUseAngleBrackets) {
- sLocalUser = L"<<";
- sRemoteUser = L">>";
- nFirstColumnWidth = 4;
- }
- else {
- sLocalUser = ptrW(GetMyOwnNick(hContact));
- sRemoteUser = Clist_GetContactDisplayName(hContact);
-
- nFirstColumnWidth = max(sRemoteUser.size(), clFileTo1ColWidth[sFilePath]);
- nFirstColumnWidth = max(sLocalUser.size(), nFirstColumnWidth);
- nFirstColumnWidth += 2;
- }
-
- wchar_t szTemp[500];
- bool bWriteUTF8Format = false;
-
- if (bAppendOnly) {
- bWriteUTF8Format = g_plugin.bUseUtf8InNewFiles;
- }
- else {
- if (g_bUseJson) {
- if (!pJson->BeginExport())
- pJson->ExportContact(hContact);
- }
- else {
- DWORD dwHighSize = 0;
- DWORD dwLowSize = GetFileSize(hFile, &dwHighSize);
- if (dwLowSize == INVALID_FILE_SIZE || dwLowSize != 0 || dwHighSize != 0) {
- DWORD dwDataRead = 0;
- uint8_t ucByteOrder[3];
- if (ReadFile(hFile, ucByteOrder, 3, &dwDataRead, nullptr))
- bWriteUTF8Format = bIsUtf8Header(ucByteOrder);
-
- DWORD dwPtr = SetFilePointer(hFile, 0, nullptr, FILE_END);
- if (dwPtr == INVALID_SET_FILE_POINTER)
- return false;
- }
- else {
- bWriteUTF8Format = g_plugin.bUseUtf8InNewFiles;
- if (bWriteUTF8Format)
- if (!bWriteToFile(hFile, szUtf8ByteOrderHeader, sizeof(szUtf8ByteOrderHeader) - 1))
- return false;
-
- CMStringW output = L"------------------------------------------------\r\n";
- output.AppendFormat(L"%s\r\n", TranslateT(" History for"));
-
- // This is written this way because I expect this will become a string the user may set
- // in the options dialog.
- output.AppendFormat(L"%-10s: %s\r\n", TranslateT("User"), sRemoteUser.c_str());
- output.AppendFormat(L"%-10s: %S\r\n", TranslateT("Account"), szProto);
-
- ptrW id(Contact::GetInfo(CNF_UNIQUEID, hContact, szProto));
- if (id != NULL)
- output.AppendFormat(L"%-10s: %s\r\n", TranslateT("User ID"), id.get());
-
- szTemp[0] = (wchar_t)db_get_b(hContact, szProto, "Gender", 0);
- if (szTemp[0]) {
- szTemp[1] = 0;
- output.AppendFormat(L"%-10s: %s\r\n", TranslateT("Gender"), szTemp);
- }
-
- int age = db_get_w(hContact, szProto, "Age", 0);
- if (age != 0)
- output.AppendFormat(L"%-10s: %d\r\n", TranslateT("Age"), age);
-
- for (auto &it : pSettings) {
- wstring szValue = _DBGetStringW(hContact, szProto, it, L"");
- if (!szValue.empty()) {
- mir_snwprintf(szTemp, L"%-10s: %s\r\n", TranslateW(_A2T(it)), szValue.c_str());
- output += szTemp;
- }
- }
-
- output += L"------------------------------------------------\r\n";
-
- if (!bWriteTextToFile(hFile, output, bWriteUTF8Format, output.GetLength()))
- return false;
- }
- }
- }
-
- if (g_bUseJson) {
- pJson->ExportEvent(dbei);
- return true;
- }
-
- if (dbei.szUserId && Contact::IsGroupChat(hContact))
- if (auto *si = Chat_Find(hContact, szProto))
- if (auto *pUser = g_chatApi.UM_FindUser(si, Utf2T(dbei.szUserId)))
- sRemoteUser = pUser->pszNick;
-
- // Get time stamp
- int nIndent = mir_snwprintf(szTemp, L"%-*s", (int)nFirstColumnWidth, dbei.flags & DBEF_SENT ? sLocalUser.c_str() : sRemoteUser.c_str());
-
- TimeZone_ToStringW(dbei.timestamp, g_sTimeFormat.c_str(), &szTemp[nIndent], _countof(szTemp) - nIndent - 2);
-
- nIndent = (int)mir_wstrlen(szTemp);
- szTemp[nIndent++] = ' ';
-
- // Write first part of line with name and timestamp
- if (!bWriteTextToFile(hFile, szTemp, bWriteUTF8Format, nIndent))
- return false;
-
- if (dbei.pBlob != nullptr && dbei.cbBlob >= 2) {
- dbei.pBlob[dbei.cbBlob] = 0;
-
- switch (dbei.eventType) {
- case EVENTTYPE_MESSAGE:
- bWriteIndentedToFile(hFile, nIndent, ptrW(DbEvent_GetTextW(&dbei)), bWriteUTF8Format);
- break;
-
- case EVENTTYPE_FILE:
- {
- DB::FILE_BLOB blob(dbei);
-
- const wchar_t *pszType = LPGENW("File: ");
- bWriteTextToFile(hFile, pszType, bWriteUTF8Format);
- bWriteIndentedToFile(hFile, nIndent, blob.getName(), bWriteUTF8Format);
-
- if (mir_wstrlen(blob.getDescr())) {
- bWriteNewLine(hFile, nIndent);
- bWriteTextToFile(hFile, LPGENW("Description: "), bWriteUTF8Format);
- bWriteIndentedToFile(hFile, nIndent, blob.getDescr(), bWriteUTF8Format);
- }
-
- if (blob.isOffline()) {
- CMStringW val(FORMAT, L"%lld", blob.getSize());
- bWriteNewLine(hFile, nIndent);
- bWriteTextToFile(hFile, LPGENW("Size: "), bWriteUTF8Format);
- bWriteIndentedToFile(hFile, nIndent, val, bWriteUTF8Format);
-
- val.Format(L"%lld", blob.getTransferred());
- bWriteNewLine(hFile, nIndent);
- bWriteTextToFile(hFile, LPGENW("Transferred: "), bWriteUTF8Format);
- bWriteIndentedToFile(hFile, nIndent, val, bWriteUTF8Format);
-
- if (mir_wstrlen(blob.getLocalName())) {
- bWriteNewLine(hFile, nIndent);
- bWriteTextToFile(hFile, LPGENW("Path: "), bWriteUTF8Format);
- bWriteIndentedToFile(hFile, nIndent, blob.getLocalName(), bWriteUTF8Format);
- }
-
- if (mir_strlen(blob.getUrl())) {
- bWriteNewLine(hFile, nIndent);
- bWriteTextToFile(hFile, LPGENW("URL: "), bWriteUTF8Format);
- bWriteIndentedToFile(hFile, nIndent, _A2T(blob.getUrl()), bWriteUTF8Format);
- }
- }
- }
- break;
-
- case EVENTTYPE_AUTHREQUEST:
- case EVENTTYPE_ADDED:
- {
- const wchar_t *pszTypes[] = {
- LPGENW("Nick :"),
- LPGENW("FirstName :"),
- LPGENW("LastName :"),
- LPGENW("e-mail :"),
- LPGENW("Reason :") };
-
- if (dbei.cbBlob < 8 || dbei.cbBlob > 5000) {
- int n = mir_snwprintf(szTemp, TranslateT("Invalid Database event received. Type %d, size %d"), dbei.eventType, dbei.cbBlob);
- bWriteTextToFile(hFile, szTemp, bWriteUTF8Format, n);
- break;
- }
-
- int nStringCount;
- const wchar_t *pszTitle;
- char *pszCurBlobPos;
- if (dbei.eventType == EVENTTYPE_AUTHREQUEST) { // request
- //blob is: uin(uint32_t), hContact(uint32_t), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)
- nStringCount = 5;
- pszCurBlobPos = (char *)dbei.pBlob + sizeof(uint32_t) * 2;
- pszTitle = LPGENW("The following user made an authorization request:");
- }
- else { // Added
- //blob is: uin(uint32_t), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ)
- pszCurBlobPos = (char *)dbei.pBlob + sizeof(uint32_t);
- nStringCount = 4;
- pszTitle = LPGENW("The following user added you to their contact list:");
- }
-
- if (bWriteTextToFile(hFile, pszTitle, bWriteUTF8Format) &&
- bWriteNewLine(hFile, nIndent) &&
- bWriteTextToFile(hFile, LPGENW("UIN :"), bWriteUTF8Format)) {
- uint32_t uin = *((PDWORD)(dbei.pBlob));
- int n = mir_snwprintf(szTemp, L"%d", uin);
- if (bWriteTextToFile(hFile, szTemp, bWriteUTF8Format, n)) {
- char *pszEnd = (char *)(dbei.pBlob + sizeof(dbei));
- for (int i = 0; i < nStringCount && pszCurBlobPos < pszEnd; i++) {
- if (*pszCurBlobPos) {
- if (!bWriteNewLine(hFile, nIndent) ||
- !bWriteTextToFile(hFile, TranslateW(pszTypes[i]), bWriteUTF8Format) ||
- !bWriteIndentedToFile(hFile, nIndent, _A2T(pszCurBlobPos), bWriteUTF8Format)) {
- break;
- }
- pszCurBlobPos += mir_strlen(pszCurBlobPos);
- }
- pszCurBlobPos++;
- }
- }
- }
- }
- break;
-
- default:
- int n = mir_snwprintf(szTemp, TranslateT("Unknown event type %d, size %d"), dbei.eventType, dbei.cbBlob);
- bWriteTextToFile(hFile, szTemp, bWriteUTF8Format, n);
- break;
- }
- }
- else {
- int n = mir_snwprintf(szTemp, TranslateT("Unknown event type %d, size %d"), dbei.eventType, dbei.cbBlob);
- bWriteTextToFile(hFile, szTemp, bWriteUTF8Format, n);
- }
-
- bWriteToFile(hFile, g_plugin.bAppendNewLine ? "\r\n\r\n" : "\r\n");
- UpdateFileViews(sFilePath.c_str());
- return true;
+ MessageBox(nullptr, sError.c_str(), MSG_BOX_TITEL, MB_OK | MB_ICONERROR);
}
/////////////////////////////////////////////////////////////////////
@@ -887,7 +557,7 @@ int nExportEvent(WPARAM hContact, LPARAM hDbEvent)
if (g_bUseJson) {
pJson = g_pDriver->Export(sFilePath.c_str());
if (pJson == nullptr) {
- DisplayErrorDialog(LPGENW("Failed to open or create file:\n"), sFilePath, nullptr);
+ DisplayErrorDialog(LPGENW("Failed to open or create file:\n"), sFilePath);
return 0;
}
@@ -896,7 +566,7 @@ int nExportEvent(WPARAM hContact, LPARAM hDbEvent)
else {
hFile = openCreateFile(sFilePath);
if (hFile == INVALID_HANDLE_VALUE) {
- DisplayErrorDialog(LPGENW("Failed to open or create file:\n"), sFilePath, nullptr);
+ DisplayErrorDialog(LPGENW("Failed to open or create file:\n"), sFilePath);
return 0;
}
}
@@ -913,147 +583,3 @@ int nExportEvent(WPARAM hContact, LPARAM hDbEvent)
return 0;
}
-
-bool bExportEvent(MCONTACT hContact, MEVENT hDbEvent, HANDLE hFile, const wstring &sFilePath, bool bAppendOnly)
-{
- bool result = true;
-
- DB::EventInfo dbei(hDbEvent);
- if (dbei) {
- if (db_mc_isMeta(hContact))
- hContact = dbei.hContact;
-
- // Write the event
- result = ExportDBEventInfo(hContact, hFile, sFilePath, dbei, bAppendOnly);
- }
-
- return result;
-}
-
-/////////////////////////////////////////////////////////////////////
-// Member Function : bWriteIndentedToFile
-// Type : Global
-// Parameters : hFile - ?
-// nIndent - ?
-// pszSrc -
-// Returns : Returns true if
-
-bool bWriteIndentedToFile(HANDLE hFile, int nIndent, const wchar_t *pszSrc, bool bUtf8File)
-{
- if (pszSrc == nullptr)
- return true;
-
- bool bOk = true;
- bool bFirstLine = true;
-
- while (*pszSrc) { // first we will scan forward in string to finde either new line or "max line with"
- int nLineLen = 0;
- do {
- if (pszSrc[nLineLen] == '\n' || pszSrc[nLineLen] == '\r')
- break;
-
- // if user set nMaxLineWidth to 0, we don't break anything, otherwise check the length
- if (nMaxLineWidth != 0 && nLineLen >= nMaxLineWidth) {
- // ok the line was not broken. we need to force a break
- // we will scan backwards again to finde a space !!
- // then we will look for a ? and so on.
-
- const wchar_t ac[] = { ' ', '?', '-', '.', ',' };
- for (auto &it : ac) {
- for (int n = nLineLen; n > 0; n--) {
- if (pszSrc[n] == it) {
- nLineLen = n;
- goto SuperBreak;
- }
- }
- }
- break;
- }
- nLineLen++;
- } while (pszSrc[nLineLen]);
-
- // trim away traling spaces !!
- if (nLineLen > 0) {
- while (pszSrc[nLineLen - 1] == ' ')
- nLineLen--;
- }
-
- SuperBreak:
- // nLineLen should contain the number af chars we need to write to the file
- if (nLineLen > 0) {
- if (!bFirstLine)
- if (!bWriteNewLine(hFile, nIndent))
- bOk = false;
-
- if (!bWriteTextToFile(hFile, pszSrc, bUtf8File, nLineLen))
- bOk = false;
- }
- bFirstLine = false;
-
- // skip any noice chars, MAC style '\r' '\r' '\n'
- // and excess spaces
- const wchar_t *pszPrev = pszSrc;
- pszSrc += nLineLen;
- while (*pszSrc == ' ' || *pszSrc == '\n' || *pszSrc == '\r')
- pszSrc++;
-
- if (pszPrev == pszSrc) {
- // this is an programming error we have not moved forward in string
- MessageBox(nullptr, L"Programming error on line __LINE__ please report this", MSG_BOX_TITEL, MB_OK);
- break;
- }
- }
-
- // if bOk if false file writing failed
- return bOk;
-}
-
-/////////////////////////////////////////////////////////////////////
-// Member Function : nContactDeleted
-// Type : Global
-// Parameters : wparam - handle to the deleted Contact
-// lparam - 0
-// Returns : int
-// Description : Called when an contact is about to be deleted
-
-int nContactDeleted(WPARAM hContact, LPARAM)
-{
- HWND hInternalWindow = WindowList_Find(hInternalWindowList, hContact);
- if (hInternalWindow)
- CloseWindow(hInternalWindow);
-
- if (g_enDeleteAction == eDANothing)
- return 0;
-
- wstring sFilePath = GetFilePathFromUser(hContact);
-
- // Test if there is another user using this file
- for (auto &hOtherContact : Contacts())
- if (hContact != hOtherContact && sFilePath == GetFilePathFromUser(hOtherContact))
- return 0; // we found another contact abort mission :-)
-
- // Test to see if there is a file to delete
- HANDLE hPrevFile = CreateFile(sFilePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
- if (hPrevFile != INVALID_HANDLE_VALUE) {
- CloseHandle(hPrevFile);
-
- wchar_t szTemp[500];
- mir_snwprintf(szTemp, L"%s\r\n%s", TranslateT("User has been deleted. Do you want to delete the file?"), sFilePath.c_str());
-
- if (g_enDeleteAction == eDAAutomatic || MessageBox(nullptr, szTemp, MSG_BOX_TITEL, MB_YESNO) == IDYES) {
- if (!DeleteFile(sFilePath.c_str())) {
- mir_snwprintf(szTemp, L"%s\r\n%s", TranslateT("Failed to delete the file"), sFilePath.c_str());
- LogLastError(szTemp);
- }
- }
- }
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////
-
-wchar_t* GetMyOwnNick(MCONTACT hContact)
-{
- wchar_t *p = Contact::GetInfo(CNF_DISPLAY, NULL, Proto_GetBaseAccountName(hContact));
- return (p != nullptr) ? p : mir_wstrdup(TranslateT("No_Nick"));
-}
diff --git a/plugins/Msg_Export/src/utils.h b/plugins/Msg_Export/src/utils.h
index b5b650e2f3..2e10273cda 100644
--- a/plugins/Msg_Export/src/utils.h
+++ b/plugins/Msg_Export/src/utils.h
@@ -41,7 +41,7 @@ extern bool g_bUseJson;
extern DATABASELINK *g_pDriver;
void LogLastError(const wchar_t *pszError);
-void DisplayErrorDialog(const wchar_t *pszError, wstring &sFilePath, DBEVENTINFO *dbei);
+void DisplayErrorDialog(const wchar_t *pszError, wstring &sFilePath);
bool bIsExportEnabled(MCONTACT hContact);
HANDLE openCreateFile(const wstring &sFilePath);
@@ -62,8 +62,6 @@ wstring GetFilePathFromUser(MCONTACT hContact);
void ReplaceDefines(MCONTACT hContact, wstring &sTarget);
void ReplaceTimeVariables(wstring &sRet);
-bool bWriteIndentedToFile(HANDLE hFile, int nIndent, const wchar_t *pszSrc, bool bUtf8File);
-bool bWriteNewLine(HANDLE hFile, uint32_t dwIndent);
bool bIsUtf8Header(uint8_t *pucByteOrder);
#endif
diff --git a/plugins/NewStory/src/version.h b/plugins/NewStory/src/version.h
index 65765375a9..7d9f500c7e 100644
--- a/plugins/NewStory/src/version.h
+++ b/plugins/NewStory/src/version.h
@@ -1,7 +1,7 @@
#define __MAJOR_VERSION 0
#define __MINOR_VERSION 2
#define __RELEASE_NUM 0
-#define __BUILD_NUM 1
+#define __BUILD_NUM 2
#include <stdver.h>