diff options
author | George Hazan <ghazan@miranda.im> | 2019-05-15 22:06:36 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-05-15 22:06:36 +0300 |
commit | 7704bcb8fc6d74d1d4e4bc6b40b52f2565a7c215 (patch) | |
tree | dba35e13b37913ef19d5c6e4af9e571d4ebffbb0 | |
parent | 7a20312b1ea4998111a05f207be8023a499050fb (diff) |
Import: QIP Infium support
-rw-r--r-- | plugins/Import/ini/qip2012.ini | 5 | ||||
-rw-r--r-- | plugins/Import/src/patterns.cpp | 263 | ||||
-rw-r--r-- | plugins/Import/src/stdafx.h | 3 | ||||
-rw-r--r-- | plugins/Import/src/utils.cpp | 18 | ||||
-rw-r--r-- | plugins/Import/src/version.h | 2 |
5 files changed, 209 insertions, 82 deletions
diff --git a/plugins/Import/ini/qip2012.ini b/plugins/Import/ini/qip2012.ini new file mode 100644 index 0000000000..5cdf0d1a23 --- /dev/null +++ b/plugins/Import/ini/qip2012.ini @@ -0,0 +1,5 @@ +[General] +Name=QIP 2012/2010/Infium +Type=2 +BinProcedure=2 +DefaultExtension=qhf diff --git a/plugins/Import/src/patterns.cpp b/plugins/Import/src/patterns.cpp index 7e3b239654..15fcf4d725 100644 --- a/plugins/Import/src/patterns.cpp +++ b/plugins/Import/src/patterns.cpp @@ -60,13 +60,15 @@ void CMPlugin::LoadPattern(const wchar_t *pwszFileName) if (GetPrivateProfileStringW(L"General", L"DefaultExtension", L"", buf, _countof(buf), pwszFileName)) pNew->wszExt = buf; - if (GetPrivateProfileStringW(L"General", L"Charset", L"", buf, _countof(buf), pwszFileName)) { - if (!wcsicmp(buf, L"ANSI")) - pNew->iCodePage = GetPrivateProfileIntW(L"General", L"Codepage", CP_ACP, pwszFileName); - else if (!wcsicmp(buf, L"UCS2")) - pNew->iCodePage = 1200; + if (pNew->iType == 1) { + if (GetPrivateProfileStringW(L"General", L"Charset", L"", buf, _countof(buf), pwszFileName)) { + if (!wcsicmp(buf, L"ANSI")) + pNew->iCodePage = GetPrivateProfileIntW(L"General", L"Codepage", CP_ACP, pwszFileName); + else if (!wcsicmp(buf, L"UCS2")) + pNew->iCodePage = 1200; + } + else return; } - else return; pNew->iUseHeader = GetPrivateProfileIntW(L"General", L"UseHeader", 0, pwszFileName); pNew->iUsePreMsg = GetPrivateProfileIntW(L"General", L"UsePreMsg", 0, pwszFileName); @@ -75,25 +77,27 @@ void CMPlugin::LoadPattern(const wchar_t *pwszFileName) // [Message] section int erroffset; const char *err; - if (GetPrivateProfileStringW(L"Message", L"Pattern", L"", buf, _countof(buf), pwszFileName)) { - if ((pNew->regMessage.pattern = pcre16_compile(buf, PCRE_MULTILINE, &err, &erroffset, nullptr)) == nullptr) - return; - pNew->regMessage.extra = pcre16_study(pNew->regMessage.pattern, 0, &err); + if (pNew->iType == 1) { + if (GetPrivateProfileStringW(L"Message", L"Pattern", L"", buf, _countof(buf), pwszFileName)) { + if ((pNew->regMessage.pattern = pcre16_compile(buf, PCRE_MULTILINE, &err, &erroffset, nullptr)) == nullptr) + return; + pNew->regMessage.extra = pcre16_study(pNew->regMessage.pattern, 0, &err); + } + else return; + + if (GetPrivateProfileStringW(L"Message", L"In", L"", buf, _countof(buf), pwszFileName)) + pNew->wszIncoming = buf; + if (GetPrivateProfileStringW(L"Message", L"Out", L"", buf, _countof(buf), pwszFileName)) + pNew->wszOutgoing = buf; + + pNew->iDirection = GetPrivateProfileIntW(L"Message", L"Direction", 0, pwszFileName); + pNew->iDay = GetPrivateProfileIntW(L"Message", L"Day", 0, pwszFileName); + pNew->iMonth = GetPrivateProfileIntW(L"Message", L"Month", 0, pwszFileName); + pNew->iYear = GetPrivateProfileIntW(L"Message", L"Year", 0, pwszFileName); + pNew->iHours = GetPrivateProfileIntW(L"Message", L"Hours", 0, pwszFileName); + pNew->iMinutes = GetPrivateProfileIntW(L"Message", L"Minutes", 0, pwszFileName); + pNew->iSeconds = GetPrivateProfileIntW(L"Message", L"Seconds", 0, pwszFileName); } - else return; - - if (GetPrivateProfileStringW(L"Message", L"In", L"", buf, _countof(buf), pwszFileName)) - pNew->wszIncoming = buf; - if (GetPrivateProfileStringW(L"Message", L"Out", L"", buf, _countof(buf), pwszFileName)) - pNew->wszOutgoing = buf; - - pNew->iDirection = GetPrivateProfileIntW(L"Message", L"Direction", 0, pwszFileName); - pNew->iDay = GetPrivateProfileIntW(L"Message", L"Day", 0, pwszFileName); - pNew->iMonth = GetPrivateProfileIntW(L"Message", L"Month", 0, pwszFileName); - pNew->iYear = GetPrivateProfileIntW(L"Message", L"Year", 0, pwszFileName); - pNew->iHours = GetPrivateProfileIntW(L"Message", L"Hours", 0, pwszFileName); - pNew->iMinutes = GetPrivateProfileIntW(L"Message", L"Minutes", 0, pwszFileName); - pNew->iSeconds = GetPrivateProfileIntW(L"Message", L"Seconds", 0, pwszFileName); if (pNew->iUsePreMsg) { pNew->preRN = GetPrivateProfileIntW(L"PreMessage", L"PreRN", -1, pwszFileName); @@ -124,80 +128,137 @@ void CMPlugin::LoadPattern(const wchar_t *pwszFileName) class CDbxPattern : public MDatabaseReadonly, public MZeroedObject { CMStringW m_buf, m_folder; - MCONTACT m_hCurrContact; + MCONTACT m_hCurrContact = 0; + HANDLE m_hFile = INVALID_HANDLE_VALUE, m_hMap = 0; + const uint8_t *m_pFile = 0; + int m_iFileVersion = 0, m_iMsgHeaderSize = 0; std::vector<DWORD> m_events; std::vector<CMStringW> m_files; + //////////////////////////////////////////////////////////////////////////////////////// + // QHF file format + + bool LoadBinaryFile(const uint8_t *pFile, uint32_t iSize) + { + if (memicmp(pFile, "QHF", 3)) + return false; + + m_iFileVersion = pFile[3]; + + uint32_t fsz = RLInteger(&pFile[4]); pFile += 0x2C; + uint32_t UIDLen = RLWord(pFile); pFile += 2; + char *UIDStr = (char*)_alloca(UIDLen + 2); + if (m_iFileVersion <= 2) + strncpy_s(UIDStr, UIDLen+2, (char*)pFile, UIDLen); + else + strncpy_s(UIDStr, UIDLen+2, (char*)pFile, UIDLen+1); + pFile += UIDLen; + + uint32_t NickLen = RLWord(pFile); pFile += 2; + char *NickStr = (char*)_alloca(NickLen + 2); + if (m_iFileVersion <= 2) + strncpy_s(NickStr, NickLen + 2, (char*)pFile, NickLen); + else + strncpy_s(NickStr, NickLen + 2, (char*)pFile, NickLen + 1); + pFile += NickLen; + + uint32_t iHeaderSize = 0x30 + NickLen + UIDLen; + if (fsz != iSize - iHeaderSize) + fsz = iSize - iHeaderSize; + + m_iMsgHeaderSize = (m_iFileVersion >= 3) ? 0x23 : 0x21; + for (uint32_t i = 0; i < fsz; i += m_iMsgHeaderSize) { + m_events.push_back(i + iHeaderSize); + i += RLWord(&pFile[i + m_iMsgHeaderSize - 2]); + } + + return true; + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Text file format, parsed by regexps + + bool LoadTextFile(const uint8_t *pFile) + { + switch (g_pActivePattern->iCodePage) { + case CP_UTF8: + m_buf = mir_utf8decodeW((char*)pFile); + break; + case 1200: + m_buf = mir_wstrdup((wchar_t*)pFile); + break; + default: + m_buf = mir_a2u_cp((char*)pFile, g_pActivePattern->iCodePage); + break; + } + + // smth went wrong or empty file + if (m_buf.IsEmpty()) + return false; + + int iOffset = 0; + while (true) { + int offsets[99]; + int nMatch = pcre16_exec(g_pActivePattern->regMessage.pattern, g_pActivePattern->regMessage.extra, m_buf, m_buf.GetLength(), iOffset, PCRE_NEWLINE_ANYCRLF, offsets, _countof(offsets)); + if (nMatch <= 0) + break; + + m_events.push_back(offsets[0]); + iOffset = offsets[1]; + } + return true; + } + public: - CDbxPattern() : - m_hCurrContact(0) + CDbxPattern() {} ~CDbxPattern() { + Close(); + } + + void Close() + { + if (m_pFile != nullptr) + ::UnmapViewOfFile(m_pFile); + + if (m_hMap != nullptr) + ::CloseHandle(m_hMap); + + if (m_hFile != INVALID_HANDLE_VALUE) + ::CloseHandle(m_hFile); } bool Load(const wchar_t *pwszFileName) { m_buf.Empty(); m_events.clear(); + Close(); - HANDLE hFile = ::CreateFileW(pwszFileName, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, 0); - if (hFile == INVALID_HANDLE_VALUE) { + m_hFile = ::CreateFileW(pwszFileName, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, 0); + if (m_hFile == INVALID_HANDLE_VALUE) { Netlib_Logf(0, "failed to open file <%S> for import: %d", pwszFileName, GetLastError()); return false; } - HANDLE hMap = ::CreateFileMappingW(hFile, nullptr, PAGE_READONLY, 0, 0, L"ImportMapfile"); - if (hMap == nullptr) { + uint32_t cbLen = ::GetFileSize(m_hFile, 0); + m_hMap = ::CreateFileMappingW(m_hFile, nullptr, PAGE_READONLY, 0, 0, L"ImportMapfile"); + if (m_hMap == nullptr) { Netlib_Logf(0, "failed to mmap file <%S> for import: %d", pwszFileName, GetLastError()); return false; } - char *pFile = (char*)::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); - if (pFile == nullptr) { + m_pFile = (const uint8_t*)::MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0); + if (m_pFile == nullptr) { Netlib_Logf(0, "failed to map view of file <%S> for import: %d", pwszFileName, GetLastError()); return false; } - switch (g_pActivePattern->iCodePage) { - case CP_UTF8: - m_buf = mir_utf8decodeW(pFile); - break; - case 1200: - m_buf = mir_wstrdup((wchar_t*)pFile); - break; - default: - m_buf = mir_a2u_cp(pFile, g_pActivePattern->iCodePage); - break; - } - - bool bRes = false; - if (!m_buf.IsEmpty()) { - int iOffset = 0; - while (true) { - int offsets[99]; - int nMatch = pcre16_exec(g_pActivePattern->regMessage.pattern, g_pActivePattern->regMessage.extra, m_buf, m_buf.GetLength(), iOffset, PCRE_NEWLINE_ANYCRLF, offsets, _countof(offsets)); - if (nMatch <= 0) - break; - - m_events.push_back(offsets[0]); - iOffset = offsets[1]; - } - bRes = true; - } - - if (pFile != nullptr) - ::UnmapViewOfFile(pFile); - - if (hMap != nullptr) - ::CloseHandle(hMap); - - if (hFile != INVALID_HANDLE_VALUE) - ::CloseHandle(hFile); - - return bRes; + if (g_pActivePattern->iType == 1) // text file + return LoadTextFile(m_pFile); + return LoadBinaryFile(m_pFile, cbLen); } int Open(const wchar_t *profile) @@ -213,7 +274,7 @@ public: else { int i = wszBaseFolder.ReverseFind('\\'); if (i != -1) - wszBaseFolder = wszBaseFolder.Left(i - 1); + wszBaseFolder = wszBaseFolder.Left(i); m_folder = profile; } @@ -282,9 +343,17 @@ public: if (m_events.size() == 0 || idx < 1 || idx > m_events.size()) return 0; - int iStart = m_events[idx-1], iEnd = (idx == m_events.size()) ? m_buf.GetLength() : m_events[idx]; - CMStringW msg = m_buf.Mid(iStart, iEnd - iStart); - return (LONG)mir_strlen(ptrA(mir_utf8encodeW(msg))) + 1; + if (g_pActivePattern->iType == 1) { + int iStart = m_events[idx-1], iEnd = (idx == m_events.size()) ? m_buf.GetLength() : m_events[idx]; + CMStringW msg = m_buf.Mid(iStart, iEnd - iStart); + return (LONG)mir_strlen(ptrA(mir_utf8encodeW(msg))) + 1; + } + + if (m_pFile == nullptr) + return 0; + + const uint8_t *pMsg = m_pFile + m_events[idx-1]; + return RLWord(&pMsg[m_iMsgHeaderSize - 2]) + 1; } STDMETHODIMP_(LONG) GetContactCount(void) override @@ -382,13 +451,35 @@ public: return _wtoi(str); } - STDMETHODIMP_(BOOL) GetEvent(MEVENT idx, DBEVENTINFO *dbei) override + int getBinaryEvent(MEVENT idx, DBEVENTINFO *dbei) { - if (m_events.size() == 0 || idx < 1 || idx > m_events.size()) + if (m_pFile == nullptr) return 1; + const uint8_t *pMsg = m_pFile + m_events[idx-1]; + + dbei->eventType = EVENTTYPE_MESSAGE; + dbei->flags = DBEF_READ | DBEF_UTF; + if (pMsg[0x1A] != 0) + dbei->flags |= DBEF_SENT; + dbei->timestamp = RLInteger(&pMsg[0x12]); + dbei->cbBlob = RLWord(&pMsg[m_iMsgHeaderSize - 2]); + dbei->pBlob = (PBYTE)mir_alloc(dbei->cbBlob + 1); + memcpy(dbei->pBlob, pMsg + m_iMsgHeaderSize, dbei->cbBlob); + if (m_iFileVersion != 1) + for (unsigned i = 0; i < dbei->cbBlob; i++) { + dbei->pBlob[i] += i+1; + dbei->pBlob[i] = 255 - dbei->pBlob[i]; + } + + dbei->pBlob[dbei->cbBlob] = 0; + return 0; + } + + int getTextEvent(MEVENT idx, DBEVENTINFO *dbei) + { int offsets[99]; - int nMatch = pcre16_exec(g_pActivePattern->regMessage.pattern, g_pActivePattern->regMessage.extra, m_buf, m_buf.GetLength(), m_events[idx - 1], PCRE_NEWLINE_ANYCRLF, offsets, _countof(offsets)); + int nMatch = pcre16_exec(g_pActivePattern->regMessage.pattern, g_pActivePattern->regMessage.extra, m_buf, m_buf.GetLength(), m_events[idx-1], PCRE_NEWLINE_ANYCRLF, offsets, _countof(offsets)); if (nMatch <= 0) return 1; @@ -408,12 +499,12 @@ public: if (arn != 0) { int i = 0; - while (m_buf[h2-2] == '\r' && m_buf[h2 - 1] == '\n' && i < arn) + while (m_buf[h2 - 2] == '\r' && m_buf[h2 - 1] == '\n' && i < arn) h2 -= 2, i++; } if (dbei->cbBlob) { - CMStringW wszBody = m_buf.Mid(h1, h2-h1).Trim(); + CMStringW wszBody = m_buf.Mid(h1, h2 - h1).Trim(); if (!wszBody.IsEmpty()) { ptrA tmp(mir_utf8encodeW(wszBody)); int copySize = min(dbei->cbBlob - 1, (int)mir_strlen(tmp)); @@ -444,10 +535,20 @@ public: pcre16_free_substring_list(substrings); } - return 0; } + STDMETHODIMP_(BOOL) GetEvent(MEVENT idx, DBEVENTINFO *dbei) override + { + if (dbei == nullptr || m_events.size() == 0 || idx < 1 || idx > m_events.size()) + return 1; + + if (g_pActivePattern->iType == 1) + return getTextEvent(idx, dbei); + + return getBinaryEvent(idx, dbei); + } + STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT hContact) override { // no system history @@ -484,7 +585,7 @@ public: STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT, MEVENT idx) override { - return (idx >= 1) ? idx - 1 : 0; + return (idx >= 1) ? idx-1 : 0; } }; diff --git a/plugins/Import/src/stdafx.h b/plugins/Import/src/stdafx.h index bcf93a8391..e0698a3fbd 100644 --- a/plugins/Import/src/stdafx.h +++ b/plugins/Import/src/stdafx.h @@ -232,6 +232,9 @@ bool IsDuplicateEvent(MCONTACT hContact, DBEVENTINFO dbei); int CreateGroup(const wchar_t *name, MCONTACT hContact);
+uint32_t RLInteger(const uint8_t *p);
+uint32_t RLWord(const uint8_t *p);
+
extern HWND g_hwndWizard, g_hwndAccMerge;
extern wchar_t g_wszImportFile[MAX_PATH];
extern time_t dwSinceDate;
diff --git a/plugins/Import/src/utils.cpp b/plugins/Import/src/utils.cpp index 51965cacef..b357d345a8 100644 --- a/plugins/Import/src/utils.cpp +++ b/plugins/Import/src/utils.cpp @@ -180,6 +180,24 @@ bool IsDuplicateEvent(MCONTACT hContact, DBEVENTINFO dbei) }
/////////////////////////////////////////////////////////////////////////////////////////
+// rtl integers
+
+uint32_t RLInteger(const uint8_t *p)
+{
+ uint32_t ret = 0;
+ for (int i = 0; i < 4; i++) {
+ ret <<= 8;
+ ret += p[i];
+ }
+ return ret;
+}
+
+uint32_t RLWord(const uint8_t *p)
+{
+ return (p[0] << 8) + p[1];
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
// icons
static IconItem iconList[] =
diff --git a/plugins/Import/src/version.h b/plugins/Import/src/version.h index 632b288efb..32ee4ab17c 100644 --- a/plugins/Import/src/version.h +++ b/plugins/Import/src/version.h @@ -1,6 +1,6 @@ #define __MAJOR_VERSION 0
#define __MINOR_VERSION 95
-#define __RELEASE_NUM 10
+#define __RELEASE_NUM 11
#define __BUILD_NUM 1
#include <stdver.h>
|