#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <cstdio>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/rand.h>
#include "misc.h"
#include "muchsync.h"
#include "infinibuf.h"
using namespace std;
bool interrupted;
class msg_sync {
sqlite3 *db_;
notmuch_db &nm_;
sqlstmt_t update_hash_stamp_;
sqlstmt_t add_file_;
sqlstmt_t del_file_;
sqlstmt_t set_link_count_;
sqlstmt_t delete_link_count_;
sqlstmt_t clear_tags_;
sqlstmt_t add_tag_;
sqlstmt_t update_message_id_stamp_;
sqlstmt_t record_docid_;
std::unordered_map<string,i64> dir_ids_;
std::pair<i64,i64> mystamp_;
i64 get_dir_docid (const string &dir);
public:
hash_lookup hashdb;
tag_lookup tagdb;
msg_sync(notmuch_db &nm, sqlite3 *db);
bool hash_sync(const versvector &remote_sync_vector,
const hash_info &remote_hash_info,
const string *sourcefile, const tag_info *tip);
bool tag_sync(const versvector &remote_sync_vector,
const tag_info &remote_tag_info);
void commit();
};
static void
interrupt(int sig)
{
interrupted = true;
}
static void
catch_interrupts(int sig, bool active)
{
struct sigaction act;
memset(&act, 0, sizeof(act));
if (active) {
act.sa_handler = &interrupt;
act.sa_flags = SA_RESETHAND;
}
else {
if (interrupted)
exit(1);
act.sa_handler = SIG_DFL;
}
sigaction(sig, &act, nullptr);
}
static string
myhostname()
{
char buf[257];
buf[sizeof(buf) - 1] = '\0';
if (gethostname (buf, sizeof(buf) - 1))
throw runtime_error (string("gethsotname: ") + strerror (errno));
return buf;
}
inline uint32_t
randint()
{
uint32_t v;
if (RAND_bytes ((unsigned char *) &v, sizeof (v)) == -1)
throw runtime_error ("RAND_bytes failed");
return v;
}
static string
maildir_name()
{
static string hostname = myhostname();
static int pid = getpid();
static int ndeliveries = 0;
ostringstream os;
using namespace std::chrono;
auto now = system_clock::now().time_since_epoch();
os << duration_cast<seconds>(now).count()
<< ".M" << duration_cast<nanoseconds>(now % seconds(1)).count()
<< 'P' << pid
<< 'Q' << ++ndeliveries
<< 'R' << setfill('0') << hex << setw(2 * sizeof(randint())) << randint()
<< '.' << hostname;
return os.str();
}
static string
new_maildir_path(const string &dir, string *namep = nullptr)
{
string name = maildir_name();
if ((dir.size() > 4 && !strncmp(dir.data() + (dir.size() - 4), "/cur", 4))
|| (dir.size() == 3 && dir == "cur"))
name += ":2,"