summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/m_db_int.h53
-rw-r--r--libs/win32/mir_app.libbin276800 -> 277558 bytes
-rw-r--r--libs/win64/mir_app.libbin276086 -> 276852 bytes
-rw-r--r--plugins/Import/src/textjson.cpp153
-rw-r--r--plugins/NewStory/src/history_dlg.cpp113
-rw-r--r--src/mir_app/src/mir_app.def3
-rw-r--r--src/mir_app/src/mir_app64.def3
7 files changed, 193 insertions, 132 deletions
diff --git a/include/m_db_int.h b/include/m_db_int.h
index fa25ddcc26..baa1395bf3 100644
--- a/include/m_db_int.h
+++ b/include/m_db_int.h
@@ -310,6 +310,19 @@ public:
};
/////////////////////////////////////////////////////////////////////////////////////////
+// Export database, that can export a contact or an event in the specified format
+
+struct MIR_APP_EXPORT MDatabaseExport : public MDatabaseReadonly
+{
+ MDatabaseExport() {}
+
+ STDMETHOD_(BOOL, BeginExport)(void) PURE;
+ STDMETHOD_(BOOL, ExportContact)(MCONTACT hContact) PURE;
+ STDMETHOD_(BOOL, ExportEvent)(const DB::EventInfo &ddei) PURE;
+ STDMETHOD_(BOOL, EndExport)(void) PURE;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
// Each database plugin should register itself using this structure
// Codes for DATABASELINK functions
@@ -328,7 +341,7 @@ public:
#define MDB_CAPS_CREATE 0x0001 // new database can be created
#define MDB_CAPS_COMPACT 0x0002 // database can be compacted
#define MDB_CAPS_CHECK 0x0004 // database can be checked
-
+#define MDB_CAPS_EXPORT 0x0008 // driver can export contacts/events
struct DATABASELINK
{
@@ -336,32 +349,28 @@ struct DATABASELINK
char* szShortName; // uniqie short database name
wchar_t* szFullName; // in English, auto-translated by the core
- /*
- profile: pointer to a string which contains full path + name
- Affect: The database plugin should create the profile, the filepath will not exist at
- the time of this call, profile will be C:\..\<name>.dat
- Returns: 0 on success, non zero on failure - error contains extended error information, see EMKPRF_*
- */
+ // profile: pointer to a string which contains full path + name
+ // The database plugin should create the profile, the filepath will not exist at
+ // the time of this call, profile will be C:\..\<name>.dat
+ // Returns: 0 on success, non zero on failure - error contains extended error information, see EMKPRF_*
int (*makeDatabase)(const wchar_t *profile);
- /*
- profile: [in] a null terminated string to file path of selected profile
- error: [in/out] pointer to an int to set with error if any
- Affect: Ask the database plugin if it supports the given profile, if it does it will
- return 0, if it doesnt return 1, with the error set in error -- EGROKPRF_* can be valid error
- condition, most common error would be [EGROKPRF_UNKHEADER]
- Note: Just because 1 is returned, doesnt mean the profile is not supported, the profile might be damaged
- etc.
- Returns: 0 on success, non zero on failure
- */
+ // profile: [in] a null terminated string to file path of selected profile
+ // error: [in/out] pointer to an int to set with error if any
+ // Asks the database plugin if it supports the given profile, if it does it will
+ // return 0, if it doesnt return 1, with the error set in error -- EGROKPRF_* can be valid error
+ // condition, most common error would be [EGROKPRF_UNKHEADER]
+ // Note: Just because 1 is returned, doesnt mean the profile is not supported, the profile might be damaged etc.
+ // Returns: 0 on success, non zero on failure
int (*grokHeader)(const wchar_t *profile);
- /*
- Affect: Tell the database to create all services/hooks that a 3.xx legacy database might support into link,
- which is a PLUGINLINK structure
- Returns: 0 on success, nonzero on failure
- */
+ // Loads the database and tells it to create all services/hooks
+ // Returns: 0 on success, nonzero on failure
MDatabaseCommon* (*Load)(const wchar_t *profile, BOOL bReadOnly);
+
+ // Prepares the export from the currently opened database into the specified file
+ // Should be implemented if capabilities contains MDB_CAPS_EXPORT
+ MDatabaseExport* (*Export)(const wchar_t *profile);
};
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/win32/mir_app.lib b/libs/win32/mir_app.lib
index 92640a1e1a..1e603f9851 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 d7cf9c5710..edfe9d3eb1 100644
--- a/libs/win64/mir_app.lib
+++ b/libs/win64/mir_app.lib
Binary files differ
diff --git a/plugins/Import/src/textjson.cpp b/plugins/Import/src/textjson.cpp
index db0adcd73d..5f45920dee 100644
--- a/plugins/Import/src/textjson.cpp
+++ b/plugins/Import/src/textjson.cpp
@@ -24,7 +24,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <m_json.h>
-static int mc_makeDatabase(const wchar_t*)
+static 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 int json_makeDatabase(const wchar_t*)
{
return 1;
}
@@ -37,11 +52,13 @@ static int CompareModules(const char *p1, const char *p2)
return mir_strcmp(p1, p2);
}
-class CDbxJson : public MDatabaseReadonly, public MZeroedObject
+class CDbxJson : public MDatabaseExport, public MZeroedObject
{
JSONNode *m_root = nullptr;
LIST<JSONNode> m_events;
LIST<char> m_modules;
+ FILE *m_out = nullptr;
+ bool m_bAppendOnly = false;
public:
CDbxJson() :
@@ -71,7 +88,7 @@ public:
return EGROKPRF_CANTREAD;
DWORD dwSize = GetFileSize(hFile, nullptr), dwRead;
- ptrA szFile((char*)mir_alloc(dwSize + 1));
+ ptrA szFile((char *)mir_alloc(dwSize + 1));
BOOL r = ReadFile(hFile, szFile, dwSize, &dwRead, nullptr);
CloseHandle(hFile);
if (!r)
@@ -149,10 +166,10 @@ public:
std::string szModule = node["module"].as_string();
if (!szModule.empty()) {
- dbei->szModule = m_modules.find((char*)szModule.c_str());
+ dbei->szModule = m_modules.find((char *)szModule.c_str());
if (dbei->szModule == nullptr) {
dbei->szModule = mir_strdup(szModule.c_str());
- m_modules.insert((char*)dbei->szModule);
+ m_modules.insert((char *)dbei->szModule);
}
}
@@ -169,7 +186,7 @@ public:
if (auto &size = node["size"])
blob.setSize(size.as_int());
- blob.write(*(DB::EventInfo*)dbei);
+ blob.write(*(DB::EventInfo *)dbei);
}
else {
std::string szBody = node["body"].as_string();
@@ -209,13 +226,13 @@ public:
if ((int)iEvent >= m_events.getCount())
return 0;
- return iEvent+1;
+ return iEvent + 1;
}
STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT) override
{
int numEvents = m_events.getCount();
- return numEvents ? numEvents-1 : 0;
+ return numEvents ? numEvents - 1 : 0;
}
STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT, MEVENT iEvent) override
@@ -223,18 +240,109 @@ public:
if (iEvent <= 1)
return 0;
- return iEvent-1;
+ return iEvent - 1;
}
STDMETHODIMP_(DATABASELINK *) GetDriver();
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Export interface
+
+ int Create(const wchar_t *profile)
+ {
+ m_out = _wfopen(profile, L"wt");
+ return (m_out == nullptr) ? EGROKPRF_CANTREAD : EGROKPRF_NOERROR;
+ }
+
+ STDMETHODIMP_(int) BeginExport() override
+ {
+ return 0;
+ }
+
+ STDMETHODIMP_(int) ExportContact(MCONTACT hContact) override
+ {
+ char *szProto = Proto_GetBaseAccountName(hContact);
+ ptrW id(Contact::GetInfo(CNF_UNIQUEID, hContact, szProto));
+ ptrW nick(Contact::GetInfo(CNF_DISPLAY, hContact, szProto));
+ const char *uid = Proto_GetUniqueId(szProto);
+
+ JSONNode pRoot, pInfo, pHist(JSON_ARRAY);
+ pInfo.set_name("info");
+ if (szProto)
+ pInfo.push_back(JSONNode("proto", szProto));
+
+ if (id != NULL)
+ pInfo.push_back(JSONNode(uid, T2Utf(id).get()));
+
+ for (auto &it : pSettings) {
+ wchar_t *szValue = db_get_wsa(hContact, szProto, it);
+ if (szValue)
+ pInfo.push_back(JSONNode(it, T2Utf(szValue).get()));
+ mir_free(szValue);
+ }
+
+ pRoot.push_back(pInfo);
+
+ pHist.set_name("history");
+ pRoot.push_back(pHist);
+
+ fputs(pRoot.write_formatted().c_str(), m_out);
+ fseek(m_out, -4, SEEK_CUR);
+ return 0;
+ }
+
+ STDMETHODIMP_(int) ExportEvent(const DB::EventInfo &dbei) override
+ {
+ if (m_bAppendOnly) {
+ fseek(m_out, -4, SEEK_END);
+ fputs(",", m_out);
+ }
+
+ JSONNode pRoot2;
+ pRoot2.push_back(JSONNode("type", dbei.eventType));
+
+ char *szProto = Proto_GetBaseAccountName(dbei.hContact);
+ if (mir_strcmp(dbei.szModule, szProto))
+ pRoot2.push_back(JSONNode("module", dbei.szModule));
+
+ pRoot2.push_back(JSONNode("timestamp", dbei.timestamp));
+
+ wchar_t szTemp[500];
+ TimeZone_PrintTimeStamp(UTC_TIME_HANDLE, dbei.timestamp, L"I", szTemp, _countof(szTemp), 0);
+ pRoot2.push_back(JSONNode("isotime", T2Utf(szTemp).get()));
+
+ std::string flags;
+ if (dbei.flags & DBEF_SENT)
+ flags += "m";
+ if (dbei.flags & DBEF_READ)
+ flags += "r";
+ pRoot2.push_back(JSONNode("flags", flags));
+
+ ptrW msg(DbEvent_GetTextW(&dbei));
+ if (msg)
+ pRoot2.push_back(JSONNode("body", T2Utf(msg).get()));
+
+ fputs(pRoot2.write_formatted().c_str(), m_out);
+ fputs("\n]}", m_out);
+
+ m_bAppendOnly = true;
+ return 0;
+ }
+
+ STDMETHODIMP_(int) EndExport() override
+ {
+ if (m_out)
+ fclose(m_out);
+ return 0;
+ }
};
-static int mc_grokHeader(const wchar_t *profile)
+static int json_grokHeader(const wchar_t *profile)
{
return CDbxJson().Open(profile);
}
-static MDatabaseCommon* mc_load(const wchar_t *profile, BOOL)
+static MDatabaseCommon* json_load(const wchar_t *profile, BOOL)
{
std::unique_ptr<CDbxJson> db(new CDbxJson());
if (db->Open(profile))
@@ -244,14 +352,25 @@ static MDatabaseCommon* mc_load(const wchar_t *profile, BOOL)
return db.release();
}
+static MDatabaseExport *json_export(const wchar_t *profile)
+{
+ std::unique_ptr<CDbxJson> db(new CDbxJson());
+ if (db->Create(profile))
+ return nullptr;
+
+ db->Load();
+ return db.release();
+}
+
static DATABASELINK dblink =
{
- 0,
- "mcontacts",
- L"mContacts file driver",
- mc_makeDatabase,
- mc_grokHeader,
- mc_load
+ MDB_CAPS_EXPORT,
+ "JSON",
+ L"JSON text file driver",
+ json_makeDatabase,
+ json_grokHeader,
+ json_load,
+ json_export
};
STDMETHODIMP_(DATABASELINK *) CDbxJson::GetDriver()
diff --git a/plugins/NewStory/src/history_dlg.cpp b/plugins/NewStory/src/history_dlg.cpp
index e4f966e852..669a5d3b73 100644
--- a/plugins/NewStory/src/history_dlg.cpp
+++ b/plugins/NewStory/src/history_dlg.cpp
@@ -73,21 +73,6 @@ void LayoutFilterBar(HDWP hDwp, int x, int y, int w, InfoBarEvents *ib)
x + 32 + WND_SPACING, y + (16 + WND_SPACING) * 2, w - WND_SPACING - 32, 16, SWP_NOZORDER);
}
-static 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")
-};
-
class CHistoryDlg : public CDlgBase
{
HMENU m_hMenu;
@@ -184,47 +169,6 @@ class CHistoryDlg : public CDlgBase
}
}
- void ExportEvent(ItemData *pItem, FILE *out)
- {
- DB::EventInfo dbei(pItem->hEvent);
- if (!dbei)
- return;
-
- if (bAppendOnly) {
- fseek(out, -4, SEEK_END);
- fputs(",", out);
- }
-
- JSONNode pRoot2;
- pRoot2.push_back(JSONNode("type", dbei.eventType));
-
- char *szProto = Proto_GetBaseAccountName(pItem->hContact);
- if (mir_strcmp(dbei.szModule, szProto))
- pRoot2.push_back(JSONNode("module", dbei.szModule));
-
- pRoot2.push_back(JSONNode("timestamp", dbei.timestamp));
-
- wchar_t szTemp[500];
- TimeZone_PrintTimeStamp(UTC_TIME_HANDLE, dbei.timestamp, L"I", szTemp, _countof(szTemp), 0);
- pRoot2.push_back(JSONNode("isotime", T2Utf(szTemp).get()));
-
- std::string flags;
- if (dbei.flags & DBEF_SENT)
- flags += "m";
- if (dbei.flags & DBEF_READ)
- flags += "r";
- pRoot2.push_back(JSONNode("flags", flags));
-
- ptrW msg(DbEvent_GetTextW(&dbei));
- if (msg)
- pRoot2.push_back(JSONNode("body", T2Utf(msg).get()));
-
- fputs(pRoot2.write_formatted().c_str(), out);
- fputs("\n]}", out);
-
- bAppendOnly = true;
- }
-
void ShowHideControls()
{
int cmd = (m_dwOptions & WND_OPT_FILTERBAR) ? SW_SHOW : SW_HIDE;
@@ -446,6 +390,11 @@ public:
showFlags = g_plugin.getWord("showFlags", 0x7f);
m_dwOptions = g_plugin.getDword("dwOptions");
+ if (!GetDatabasePlugin("JSON")) {
+ btnExport.Disable();
+ btnExport.SetTooltip(LPGEN("You need to install the Import plugin to export events"));
+ }
+
if (m_hContact == INVALID_CONTACT_ID)
m_dwOptions |= WND_OPT_SEARCHBAR;
else if (m_hContact > 0) {
@@ -899,16 +848,11 @@ public:
return;
}
- char *szProto = Proto_GetBaseAccountName(m_hContact);
- ptrW id(Contact::GetInfo(CNF_UNIQUEID, m_hContact, szProto));
- ptrW nick(Contact::GetInfo(CNF_DISPLAY, m_hContact, szProto));
- const char *uid = Proto_GetUniqueId(szProto);
-
OPENFILENAME ofn = { 0 };
ofn.lStructSize = sizeof(ofn);
CMStringW tszFilter, tszTitle, tszFileName;
tszFilter.AppendFormat(L"%s (*.json)%c*.json%c%c", TranslateT("JSON files"), 0, 0, 0);
- tszTitle.AppendFormat(TranslateT("Export %s history"), nick);
+ tszTitle.AppendFormat(TranslateT("Export history"));
ofn.lpstrFilter = tszFilter;
ofn.hwndOwner = nullptr;
ofn.lpstrTitle = tszTitle;
@@ -927,33 +871,10 @@ public:
if (PathFileExistsW(FileName))
DeleteFileW(FileName);
- FILE *out = _wfopen(FileName, L"wt");
- if (out == NULL)
- return;
-
- // export contact info
- JSONNode pRoot, pInfo, pHist(JSON_ARRAY);
- pInfo.set_name("info");
- if (szProto)
- pInfo.push_back(JSONNode("proto", szProto));
-
- if (id != NULL)
- pInfo.push_back(JSONNode(uid, T2Utf(id).get()));
-
- for (auto &it : pSettings) {
- wchar_t *szValue = db_get_wsa(m_hContact, szProto, it);
- if (szValue)
- pInfo.push_back(JSONNode(it, T2Utf(szValue).get()));
- mir_free(szValue);
- }
-
- pRoot.push_back(pInfo);
-
- pHist.set_name("history");
- pRoot.push_back(pHist);
-
- fputs(pRoot.write_formatted().c_str(), out);
- fseek(out, -4, SEEK_CUR);
+ auto *pDriver = GetDatabasePlugin("JSON");
+ auto *pDB = pDriver->Export(FileName);
+ pDB->BeginExport();
+ pDB->ExportContact(m_hContact);
// export events
int iDone = 0;
@@ -963,18 +884,24 @@ public:
for (int i = 0; i < iCount; i++) {
auto *pItem = arItems.get(i);
if (pItem->m_bSelected) {
- ExportEvent(pItem, out);
+ DB::EventInfo dbei(pItem->hEvent);
+ if (dbei)
+ pDB->ExportEvent(dbei);
iDone++;
}
}
// no items selected? export whole history
if (iDone == 0)
- for (int i = 0; i < iCount; i++)
- ExportEvent(arItems.get(i), out);
+ for (int i = 0; i < iCount; i++) {
+ auto *pItem = arItems.get(i);
+ DB::EventInfo dbei(pItem->hEvent);
+ if (dbei)
+ pDB->ExportEvent(dbei);
+ }
// Close the file
- fclose(out);
+ pDB->EndExport();
MessageBox(m_hwnd, TranslateT("Complete"), TranslateT("History export"), MB_OK | MB_ICONINFORMATION);
}
diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def
index 705e7ba2ea..8f84e99e5e 100644
--- a/src/mir_app/src/mir_app.def
+++ b/src/mir_app/src/mir_app.def
@@ -922,3 +922,6 @@ Clist_GroupSaveExpanded @1003 NONAME
?DlgProc@CUserInfoPageDlg@@UAEHIIJ@Z @1040 NONAME
?wipeNotify@EventInfo@DB@@QAEXI@Z @1047 NONAME
_CallContactService@20 @1048 NONAME
+??0MDatabaseExport@@QAE@XZ @1049 NONAME
+??1MDatabaseExport@@UAE@XZ @1050 NONAME
+??_7MDatabaseExport@@6B@ @1051 NONAME
diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def
index 6e06ba8f4a..7eeea9080a 100644
--- a/src/mir_app/src/mir_app64.def
+++ b/src/mir_app/src/mir_app64.def
@@ -922,3 +922,6 @@ Clist_GroupSaveExpanded @1003 NONAME
?DlgProc@CUserInfoPageDlg@@UEAA_JI_K_J@Z @1040 NONAME
?wipeNotify@EventInfo@DB@@QEAAXI@Z @1041 NONAME
CallContactService @1042 NONAME
+??0MDatabaseExport@@QEAA@XZ @1043 NONAME
+??1MDatabaseExport@@UEAA@XZ @1044 NONAME
+??_7MDatabaseExport@@6B@ @1045 NONAME