1
0
Fork 0
mirror of https://github.com/deltachat/deltachat-core.git synced 2025-10-05 19:42:04 +02:00
deltachat-core/src/mrmailbox.cpp

450 lines
11 KiB
C++

/*******************************************************************************
*
* Messenger Backend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
*
* 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, either version 3 of the License, or (at your option) any later
* version.
*
* 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/ .
*
*******************************************************************************
*
* File: mrmailbox.cpp
* Authors: Björn Petersen
* Purpose: MrMailbox represents a single mailbox, see header for details.
*
******************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include "mrmailbox.h"
#include "mrimfparser.h"
#include "mrcontact.h"
#include "mrmsg.h"
/*******************************************************************************
* Init/Exit
******************************************************************************/
MrMailbox::MrMailbox()
: m_sql(this), m_imap(this)
{
}
MrMailbox::~MrMailbox()
{
Close();
}
bool MrMailbox::Open(const char* dbfile)
{
{
MrSqlite3Locker locker(m_sql);
// Open() sets up the object and connects to the given database
// from which all configuration is read/written to.
// Create/open sqlite database
if( !m_sql.Open(dbfile) ) {
goto Open_Error; // error already logged
}
}
// success
return true;
// error
Open_Error:
Close();
return false;
}
void MrMailbox::Close()
{
MrSqlite3Locker locker(m_sql);
m_sql.Close();
}
/*******************************************************************************
* Import EML-files
******************************************************************************/
bool MrMailbox::ImportFile(const char* filename)
{
bool success = false;
FILE* f = NULL;
struct stat stat_info;
char* data = NULL;
// read file content to `data`
if( (f=fopen(filename, "r")) == NULL ) {
MrLogError("MrMailbox::ImportFile(): Cannot open file.", filename);
goto ImportFile_Cleanup;
}
if( stat(filename, &stat_info) != 0 || stat_info.st_size == 0 ) {
MrLogError("MrMailbox::ImportFile(): Cannot find out file size or file is empty.", filename);
goto ImportFile_Cleanup;
}
if( (data=(char*)malloc(stat_info.st_size))==NULL ) {
MrLogError("MrMailbox::ImportFile(): Out of memory.", filename);
goto ImportFile_Cleanup;
}
if( fread(data, 1, stat_info.st_size, f)!=(size_t)stat_info.st_size ) {
MrLogError("MrMailbox::ImportFile(): Read error.", filename);
goto ImportFile_Cleanup;
}
fclose(f);
f = NULL;
// import `data`
ReceiveImf(data, stat_info.st_size);
// success
success = true;
// cleanup:
ImportFile_Cleanup:
free(data);
if( f ) {
fclose(f);
}
return success;
}
bool MrMailbox::ImportSpec(const char* spec)
{
bool success = false;
char* spec_memory = NULL;
if( !m_sql.Ok() ) {
MrLogError("MrMailbox::ImportSpec(): Datebase not opened.", spec);
goto ImportSpec_Cleanup;
}
// if `spec` is not given, try to use the last one
if( spec == NULL ) {
MrSqlite3Locker locker(m_sql);
spec_memory = m_sql.GetConfig("import_spec", NULL);
spec = spec_memory; // may still be NULL
if( spec == NULL ) {
MrLogError("MrMailbox::ImportSpec(): No file or folder given.", spec);
goto ImportSpec_Cleanup;
}
}
if( strlen(spec)>=4 && strcmp(&spec[strlen(spec)-4], ".eml")==0 ) {
// import a single file
if( !ImportFile(spec) ) {
goto ImportSpec_Cleanup; // error already logged
}
}
else {
// import a directory
MrLogError("MrMailbox::ImportSpec(): Directory import not yet implemented.", spec);
goto ImportSpec_Cleanup;
}
// success
{
MrSqlite3Locker locker(m_sql);
m_sql.SetConfig("import_spec", spec);
}
success = true;
// cleanup
ImportSpec_Cleanup:
free(spec_memory);
return success;
}
/*******************************************************************************
* Connect
******************************************************************************/
bool MrMailbox::Connect()
{
if( m_imap.IsConnected() ) {
return true;
}
// read parameter, unset parameters are still NULL afterwards
{
MrSqlite3Locker locker(m_sql);
m_loginParam.Clear();
m_loginParam.m_email = m_sql.GetConfig ("email", NULL);
m_loginParam.m_mail_server = m_sql.GetConfig ("mail_server", NULL);
m_loginParam.m_mail_port = m_sql.GetConfigInt("mail_port", 0);
m_loginParam.m_mail_user = m_sql.GetConfig ("mail_user", NULL);
m_loginParam.m_mail_pw = m_sql.GetConfig ("mail_pw", NULL);
m_loginParam.m_send_server = m_sql.GetConfig ("send_server", NULL);
m_loginParam.m_send_port = m_sql.GetConfigInt("send_port", 0);
m_loginParam.m_send_user = m_sql.GetConfig ("send_user", NULL);
m_loginParam.m_send_pw = m_sql.GetConfig ("send_pw", NULL);
}
// try to suggest unset parameters
m_loginParam.Complete();
// connect
return m_imap.Connect(&m_loginParam);
}
void MrMailbox::Disconnect()
{
m_imap.Disconnect();
}
bool MrMailbox::Fetch()
{
return m_imap.Fetch();
}
/*******************************************************************************
* Receive an IMF as an result to calling Fetch() or Import*()
* the new IMF may be old or new and should be parsed, contacts created etc.
* However, the caller should make sure, it does not exist in the database.
******************************************************************************/
void MrMailbox::ReceiveImf(const char* imf_raw_not_terminated, size_t imf_raw_bytes)
{
MrImfParser parser(this);
if( !parser.Imf2Msg(imf_raw_not_terminated, imf_raw_bytes) ) {
return; // error already logged
}
}
/*******************************************************************************
* Handle contacts
******************************************************************************/
size_t MrMailbox::GetContactCnt()
{
MrSqlite3Locker locker(m_sql);
return MrContact::GetContactCnt(this);
}
/*******************************************************************************
* Handle chats
******************************************************************************/
size_t MrMailbox::GetChatCnt()
{
MrSqlite3Locker locker(m_sql);
return MrChat::GetChatCnt(this);
}
MrChatList* MrMailbox::GetChats()
{
MrSqlite3Locker locker(m_sql);
MrChatList* obj = new MrChatList(this);
if( obj->LoadFromDb() ) {
return obj;
}
else {
delete obj;
return NULL;
}
}
MrChat* MrMailbox::GetChat(const char* name)
{
MrSqlite3Locker locker(m_sql);
MrChat* obj = new MrChat(this);
if( obj->LoadFromDb(name, 0) ) {
return obj;
}
else {
delete obj;
return NULL;
}
}
MrChat* MrMailbox::GetChat(uint32_t id)
{
MrSqlite3Locker locker(m_sql);
MrChat* obj = new MrChat(this);
if( obj->LoadFromDb(NULL, id) ) {
return obj;
}
else {
delete obj;
return NULL;
}
}
/*******************************************************************************
* Misc.
******************************************************************************/
char* MrMailbox::GetDbFile()
{
if( m_sql.m_dbfile == NULL ) {
return NULL; // database not opened
}
return strdup(m_sql.m_dbfile); // must be freed by the caller
}
char* MrMailbox::GetInfo()
{
const char unset[] = "<unset>";
const char set[] = "<set>";
#define BUF_BYTES 10000
char* buf = (char*)malloc(BUF_BYTES+1);
if( buf == NULL ) {
MrLogError("MrMailbox::GetInfo(): Out of memory.");
return NULL; // error
}
// read data (all pointers may be NULL!)
char *email, *mail_server, *mail_port, *mail_user, *mail_pw, *send_server, *send_port, *send_user, *send_pw, *debug_dir;
int contacts, chats, messages;
{
MrSqlite3Locker locker(m_sql);
email = m_sql.GetConfig("email", NULL);
mail_server = m_sql.GetConfig("mail_server", NULL);
mail_port = m_sql.GetConfig("mail_port", NULL);
mail_user = m_sql.GetConfig("mail_user", NULL);
mail_pw = m_sql.GetConfig("mail_pw", NULL);
send_server = m_sql.GetConfig("send_server", NULL);
send_port = m_sql.GetConfig("send_port", NULL);
send_user = m_sql.GetConfig("send_user", NULL);
send_pw = m_sql.GetConfig("send_pw", NULL);
debug_dir = m_sql.GetConfig("debug_dir", NULL);
contacts = MrContact::GetContactCnt(this);
chats = MrChat::GetChatCnt(this);
messages = MrMsg::GetMsgCnt(this);
}
// create info
snprintf(buf, BUF_BYTES,
"Backend version %i.%i.%i\n"
"SQLite version %s, threadsafe=%i\n"
"libEtPan version %i.%i\n"
"Database file %s\n"
"Contacts %i\n"
"Chats/Messages %i/%i\n"
"email %s\n"
"mail_server %s\n"
"mail_port %s\n"
"mail_user %s\n"
"mail_pw %s\n"
"send_server %s\n"
"send_port %s\n"
"send_user %s\n"
"send_pw %s\n"
"debug_dir %s\n"
"If possible, unset values are filled by the program with typical values.\n"
, MR_VERSION_MAJOR, MR_VERSION_MINOR, MR_VERSION_REVISION
, SQLITE_VERSION, sqlite3_threadsafe()
, libetpan_get_version_major(), libetpan_get_version_minor()
, m_sql.m_dbfile? m_sql.m_dbfile : unset
, contacts
, chats, messages
, email? email : unset
, mail_server? mail_server : unset
, mail_port? mail_port : unset
, mail_user? mail_user : unset
, mail_pw? set : unset // we do not display the password here; in the cli-utility, you can see it using `get mail_pw`
, send_server? send_server : unset
, send_port? send_port : unset
, send_user? send_user : unset
, send_pw? set : unset // we do not display the password here; in the cli-utility, you can see it using `get send_pw`
, debug_dir? debug_dir : unset
);
// free data
#define GI_FREE_(a) if((a)) { free((a)); }
GI_FREE_(email);
GI_FREE_(mail_server);
GI_FREE_(mail_port);
GI_FREE_(mail_user);
GI_FREE_(mail_pw);
GI_FREE_(send_server);
GI_FREE_(send_port);
GI_FREE_(send_user);
GI_FREE_(send_pw);
return buf; // must be freed by the caller
}
bool MrMailbox::Empty()
{
MrSqlite3Locker locker(m_sql);
m_sql.sqlite3_execute_("DELETE FROM contacts;");
m_sql.sqlite3_execute_("DELETE FROM chats;");
m_sql.sqlite3_execute_("DELETE FROM chats_contacts;");
m_sql.sqlite3_execute_("DELETE FROM msg;");
m_sql.sqlite3_execute_("DELETE FROM msg_to;");
m_sql.sqlite3_execute_("DELETE FROM config WHERE keyname LIKE 'folder.%';");
return true;
}