mirror of https://github.com/djcb/mu.git
remove some dead code
This commit is contained in:
parent
362c53a7e7
commit
98744c66f7
|
@ -238,7 +238,7 @@ Contacts::add (ContactInfo&& ci)
|
|||
|
||||
if (ci.last_seen > ci_existing.last_seen) { // update.
|
||||
wash(ci.name);
|
||||
ci_existing.name = std::move(ci.name);
|
||||
ci_existing.name = std::move(ci.name);
|
||||
ci_existing.email = std::move(ci.email);
|
||||
|
||||
wash(ci.full_address);
|
||||
|
|
|
@ -207,43 +207,6 @@ Mu::mu_maildir_link (const char* src, const char *targetpath, GError **err)
|
|||
}
|
||||
|
||||
|
||||
static MuError
|
||||
process_dir (const char* path, const char *mdir,
|
||||
MuMaildirWalkMsgCallback msg_cb,
|
||||
MuMaildirWalkDirCallback dir_cb, gboolean full,
|
||||
void *data);
|
||||
|
||||
static MuError
|
||||
process_file (const char* fullpath, const char* mdir,
|
||||
MuMaildirWalkMsgCallback msg_cb, void *data)
|
||||
{
|
||||
MuError result;
|
||||
struct stat statbuf;
|
||||
|
||||
if (!msg_cb)
|
||||
return MU_OK;
|
||||
|
||||
if (G_UNLIKELY(access(fullpath, R_OK) != 0)) {
|
||||
g_warning ("cannot access %s: %s", fullpath,
|
||||
strerror(errno));
|
||||
return MU_ERROR;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY(stat (fullpath, &statbuf) != 0)) {
|
||||
g_warning ("cannot stat %s: %s", fullpath, strerror(errno));
|
||||
return MU_ERROR;
|
||||
}
|
||||
|
||||
result = (msg_cb)(fullpath, mdir, &statbuf, data);
|
||||
if (result == MU_STOP)
|
||||
g_debug ("callback said 'MU_STOP' for %s", fullpath);
|
||||
else if (result == MU_ERROR)
|
||||
g_warning ("%s: error in callback (%s)",
|
||||
__func__, fullpath);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* determine if path is a maildir leaf-dir; ie. if it's 'cur' or 'new'
|
||||
|
@ -280,290 +243,6 @@ Mu::mu_maildir_is_leaf_dir (const char *path)
|
|||
}
|
||||
|
||||
|
||||
/* check if there path contains file; used for checking if there is
|
||||
* MU_MAILDIR_NOINDEX_FILE or MU_MAILDIR_NOUPDATE_FILE in this
|
||||
* dir; */
|
||||
static gboolean
|
||||
dir_contains_file (const char *path, const char *file)
|
||||
{
|
||||
const char* fullpath;
|
||||
|
||||
/* static buffer */
|
||||
fullpath = mu_str_fullpath_s (path, file);
|
||||
|
||||
if (access (fullpath, F_OK) == 0)
|
||||
return TRUE;
|
||||
else if (G_UNLIKELY(errno != ENOENT && errno != EACCES))
|
||||
g_warning ("error testing for %s/%s: %s",
|
||||
fullpath, file, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_dotdir_to_ignore (const char* dir)
|
||||
{
|
||||
int i;
|
||||
const char* ignore[] = {
|
||||
".notmuch",
|
||||
".nnmaildir",
|
||||
".#evolution"
|
||||
}; /* when adding names, check the optimization below */
|
||||
|
||||
if (dir[0] != '.')
|
||||
return FALSE; /* not a dotdir */
|
||||
|
||||
if (dir[1] == '\0' || (dir[1] == '.' && dir[2] == '\0'))
|
||||
return TRUE; /* ignore '.' and '..' */
|
||||
|
||||
/* optimization: special dirs have 'n' or '#' in pos 1 */
|
||||
if (dir[1] != 'n' && dir[1] != '#')
|
||||
return FALSE; /* not special: don't ignore */
|
||||
|
||||
for (i = 0; i != G_N_ELEMENTS(ignore); ++i)
|
||||
if (strcmp(dir, ignore[i]) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE; /* don't ignore */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ignore_dir_entry (struct dirent *entry, unsigned char d_type)
|
||||
{
|
||||
if (G_LIKELY(d_type == DT_REG)) {
|
||||
|
||||
guint u;
|
||||
|
||||
/* ignore emacs tempfiles */
|
||||
if (entry->d_name[0] == '#')
|
||||
return TRUE;
|
||||
/* ignore dovecot metadata */
|
||||
if (entry->d_name[0] == 'd' &&
|
||||
strncmp (entry->d_name, "dovecot", 7) == 0)
|
||||
return TRUE;
|
||||
/* ignore special files */
|
||||
if (entry->d_name[0] == '.')
|
||||
return TRUE;
|
||||
/* ignore core files */
|
||||
if (entry->d_name[0] == 'c' &&
|
||||
strncmp (entry->d_name, "core", 4) == 0)
|
||||
return TRUE;
|
||||
/* ignore tmp/backup files; find the last char */
|
||||
for (u = 0; entry->d_name[u] != '\0'; ++u) {
|
||||
switch (entry->d_name[u]) {
|
||||
case '#':
|
||||
case '~':
|
||||
/* looks like a backup / tempsave file */
|
||||
if (entry->d_name[u + 1] == '\0')
|
||||
return TRUE;
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return FALSE; /* other files: don't ignore */
|
||||
|
||||
} else if (d_type == DT_DIR)
|
||||
return is_dotdir_to_ignore (entry->d_name);
|
||||
else
|
||||
return TRUE; /* ignore non-normal files, non-dirs */
|
||||
}
|
||||
|
||||
/*
|
||||
* return the maildir value for the the path - this is the directory
|
||||
* for the message (with the top-level dir as "/"), and without the
|
||||
* leaf "/cur" or "/new". In other words, contatenate old_mdir + "/" + dir,
|
||||
* unless dir is either 'new' or 'cur'. The value will be used in queries.
|
||||
*/
|
||||
static char*
|
||||
get_mdir_for_path (const char *old_mdir, const char *dir)
|
||||
{
|
||||
/* if the current dir is not 'new' or 'cur', contatenate
|
||||
* old_mdir an dir */
|
||||
if ((dir[0] == 'n' && strcmp(dir, "new") == 0) ||
|
||||
(dir[0] == 'c' && strcmp(dir, "cur") == 0) ||
|
||||
(dir[0] == 't' && strcmp(dir, "tmp") == 0))
|
||||
return strdup (old_mdir ? old_mdir : G_DIR_SEPARATOR_S);
|
||||
else
|
||||
return g_strconcat (old_mdir ? old_mdir : "",
|
||||
G_DIR_SEPARATOR_S, dir, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static MuError
|
||||
process_dir_entry (const char* path, const char* mdir, struct dirent *entry,
|
||||
MuMaildirWalkMsgCallback cb_msg,
|
||||
MuMaildirWalkDirCallback cb_dir,
|
||||
gboolean full, void *data)
|
||||
{
|
||||
const char *fp;
|
||||
char* fullpath;
|
||||
unsigned char d_type;
|
||||
|
||||
/* we have to copy the buffer from fullpath_s, because it
|
||||
* returns a static buffer, and we maybe called reentrantly */
|
||||
fp = mu_str_fullpath_s (path, entry->d_name);
|
||||
fullpath = g_newa (char, strlen(fp) + 1);
|
||||
strcpy (fullpath, fp);
|
||||
|
||||
d_type = get_dtype(entry, fullpath, FALSE/*stat*/);
|
||||
|
||||
/* ignore special files/dirs */
|
||||
if (ignore_dir_entry (entry, d_type)) {
|
||||
/* g_debug ("ignoring %s\n", entry->d_name); */
|
||||
return MU_OK;
|
||||
}
|
||||
|
||||
switch (d_type) {
|
||||
case DT_REG: /* we only want files in cur/ and new/ */
|
||||
if (!mu_maildir_is_leaf_dir (path))
|
||||
return MU_OK;
|
||||
|
||||
return process_file (fullpath, mdir, cb_msg, data);
|
||||
|
||||
case DT_DIR: {
|
||||
char *my_mdir;
|
||||
MuError rv;
|
||||
/* my_mdir is the search maildir (the dir starting
|
||||
* with the top-level maildir as /, and without the
|
||||
* /tmp, /cur, /new */
|
||||
my_mdir = get_mdir_for_path (mdir, entry->d_name);
|
||||
rv = process_dir (fullpath, my_mdir, cb_msg, cb_dir, full, data);
|
||||
g_free (my_mdir);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
default:
|
||||
return MU_OK; /* ignore other types */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_STRUCT_DIRENT_D_INO
|
||||
static int
|
||||
dirent_cmp (struct dirent *d1, struct dirent *d2)
|
||||
{
|
||||
/* we do it his way instead of a simple d1->d_ino - d2->d_ino
|
||||
* because this way, we don't need 64-bit numbers for the
|
||||
* actual sorting */
|
||||
if (d1->d_ino < d2->d_ino)
|
||||
return -1;
|
||||
else if (d1->d_ino > d2->d_ino)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif /*HAVE_STRUCT_DIRENT_D_INO*/
|
||||
|
||||
static MuError
|
||||
process_dir_entries (DIR *dir, const char* path, const char* mdir,
|
||||
MuMaildirWalkMsgCallback msg_cb,
|
||||
MuMaildirWalkDirCallback dir_cb,
|
||||
gboolean full, void *data)
|
||||
{
|
||||
MuError result;
|
||||
GSList *lst, *c;
|
||||
|
||||
for (lst = NULL;;) {
|
||||
struct dirent *entry, *res;
|
||||
errno = 0;
|
||||
res = readdir (dir);
|
||||
if (res) {
|
||||
entry = (struct dirent*)g_memdup (res, sizeof(struct dirent));
|
||||
lst = g_slist_prepend (lst, entry);
|
||||
} else if (errno == 0) {
|
||||
break;
|
||||
} else {
|
||||
g_warning ("error scanning dir: %s", strerror(errno));
|
||||
return MU_ERROR_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
/* we sort by inode; this makes things much faster on
|
||||
* extfs2,3 */
|
||||
#if HAVE_STRUCT_DIRENT_D_INO
|
||||
c = lst = g_slist_sort (lst, (GCompareFunc)dirent_cmp);
|
||||
#endif /*HAVE_STRUCT_DIRENT_D_INO*/
|
||||
|
||||
for (c = lst, result = MU_OK; c && result == MU_OK; c = g_slist_next(c))
|
||||
result = process_dir_entry (path, mdir, (struct dirent*)c->data,
|
||||
msg_cb, dir_cb, full, data);
|
||||
|
||||
g_slist_foreach (lst, (GFunc)g_free, NULL);
|
||||
g_slist_free (lst);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static MuError
|
||||
process_dir (const char* path, const char* mdir,
|
||||
MuMaildirWalkMsgCallback msg_cb, MuMaildirWalkDirCallback dir_cb,
|
||||
gboolean full, void *data)
|
||||
{
|
||||
MuError result;
|
||||
DIR* dir;
|
||||
|
||||
/* if it has a noindex file, we ignore this dir */
|
||||
if (dir_contains_file (path, MU_MAILDIR_NOINDEX_FILE) ||
|
||||
(!full && dir_contains_file (path, MU_MAILDIR_NOUPDATE_FILE))) {
|
||||
g_debug ("found noindex/noupdate: ignoring dir %s", path);
|
||||
return MU_OK;
|
||||
}
|
||||
|
||||
if (dir_cb) {
|
||||
MuError rv;
|
||||
rv = dir_cb (path, TRUE/*enter*/, data);
|
||||
/* ignore this dir; not necessarily an _error_, dir might
|
||||
* be up-to-date and return MU_IGNORE */
|
||||
if (rv == MU_IGNORE)
|
||||
return MU_OK;
|
||||
else if (rv != MU_OK)
|
||||
return rv;
|
||||
}
|
||||
|
||||
dir = opendir (path);
|
||||
if (!dir) {
|
||||
g_warning ("cannot access %s: %s", path, strerror(errno));
|
||||
return MU_OK;
|
||||
}
|
||||
|
||||
result = process_dir_entries (dir, path, mdir, msg_cb, dir_cb,
|
||||
full, data);
|
||||
closedir (dir);
|
||||
|
||||
/* only run dir_cb if it exists and so far, things went ok */
|
||||
if (dir_cb && result == MU_OK)
|
||||
return dir_cb (path, FALSE/*leave*/, data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
MuError
|
||||
Mu::mu_maildir_walk (const char *path, MuMaildirWalkMsgCallback cb_msg,
|
||||
MuMaildirWalkDirCallback cb_dir, gboolean full,
|
||||
void *data)
|
||||
{
|
||||
MuError rv;
|
||||
char *mypath;
|
||||
|
||||
g_return_val_if_fail (path && cb_msg, MU_ERROR);
|
||||
g_return_val_if_fail (mu_util_check_dir(path, TRUE, FALSE), MU_ERROR);
|
||||
|
||||
/* strip the final / or \ */
|
||||
mypath = g_strdup (path);
|
||||
if (mypath[strlen(mypath)-1] == G_DIR_SEPARATOR)
|
||||
mypath[strlen(mypath)-1] = '\0';
|
||||
|
||||
rv = process_dir (mypath, NULL, cb_msg, cb_dir, full, data);
|
||||
g_free (mypath);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
clear_links (const char *path, DIR *dir)
|
||||
{
|
||||
|
|
|
@ -64,57 +64,6 @@ gboolean mu_maildir_mkdir (const char* path, mode_t mode, gboolean noindex,
|
|||
gboolean mu_maildir_link (const char* src, const char *targetpath,
|
||||
GError **err);
|
||||
|
||||
/**
|
||||
* MuMaildirWalkMsgCallback -- callback function for
|
||||
* mu_path_walk_maildir; see the documentation there. It will be
|
||||
* called for each message found, with fullpath containing the full
|
||||
* path to the message, mdir containing the maildir -- that is, when
|
||||
* indexing ~/Maildir, a message ~/Maildir/foo/bar/cur/msg would have
|
||||
* the maildir "foo/bar". Then, the information from 'stat' of this
|
||||
* file (see stat(3)), and a user_data pointer
|
||||
*/
|
||||
typedef MuError (*MuMaildirWalkMsgCallback)
|
||||
(const char* fullpath, const char* mdir, struct stat *statinfo,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* MuPathWalkDirCallback -- callback function for mu_path_walk_maildir; see the
|
||||
* documentation there. It will be called each time a dir is entered or left,
|
||||
* with 'enter' being TRUE upon entering, FALSE otherwise
|
||||
*/
|
||||
typedef MuError (*MuMaildirWalkDirCallback)
|
||||
(const char* fullpath, gboolean enter, void *user_data);
|
||||
|
||||
/**
|
||||
* start a recursive walk of a maildir; for each file found, we call
|
||||
* callback with the path (with the Maildir path of scanner_new as
|
||||
* root), the filename, the timestamp (mtime) of the file,and the
|
||||
* *data pointer, for user data. dot-files are ignored, as well as
|
||||
* files outside cur/ and new/ dirs and unreadable files; however,
|
||||
* dotdirs are visited (ie. '.dotdir/cur'), so this enables Maildir++.
|
||||
* (http://www.inter7.com/courierimap/README.maildirquota.html, search
|
||||
* for 'Mission statement'). In addition, dirs containing a file named
|
||||
* '.noindex' are ignored, as are their subdirectories, and dirs
|
||||
* containing a file called '.noupdate' are ignored, unless @param
|
||||
* full is TRUE.
|
||||
*
|
||||
* mu_walk_maildir stops if the callbacks return something different
|
||||
* from MU_OK. For example, it can return MU_STOP to stop the scan, or
|
||||
* some error.
|
||||
*
|
||||
* @param path the maildir path to scan
|
||||
* @param cb_msg the callback function called for each msg
|
||||
* @param cb_dir the callback function called for each dir
|
||||
* @param full whether do a full scan, i.e., to ignore .noupdate files
|
||||
* @param data user data pointer
|
||||
*
|
||||
* @return a scanner result; MU_OK if everything went ok,
|
||||
* MU_STOP if we want to stop, or MU_ERROR in
|
||||
* case of error
|
||||
*/
|
||||
MuError mu_maildir_walk (const char *path, MuMaildirWalkMsgCallback cb_msg,
|
||||
MuMaildirWalkDirCallback cb_dir, gboolean full,
|
||||
void *data);
|
||||
/**
|
||||
* recursively delete all the symbolic links in a directory tree
|
||||
*
|
||||
|
@ -126,8 +75,6 @@ MuError mu_maildir_walk (const char *path, MuMaildirWalkMsgCallback cb_msg,
|
|||
*/
|
||||
gboolean mu_maildir_clear_links (const char* dir, GError **err);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* whether the directory path ends in '/cur/' or '/new/'
|
||||
*
|
||||
|
|
|
@ -135,8 +135,8 @@ mu_msg_destroy (MuMsg *self)
|
|||
|
||||
{ /* cleanup the strings / lists we stored */
|
||||
mu_str_free_list (self->_free_later_str);
|
||||
g_slist_foreach (self->_free_later_lst,
|
||||
(GFunc)mu_str_free_list, NULL);
|
||||
for (auto cur = self->_free_later_lst; cur; cur = g_slist_next(cur))
|
||||
g_slist_free_full((GSList*)cur->data, g_free);
|
||||
g_slist_free (self->_free_later_lst);
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ process_field (const std::string& field, Flags flags)
|
|||
add_field (fields, MU_MSG_FIELD_ID_SUBJECT);
|
||||
add_field (fields, MU_MSG_FIELD_ID_BODY_TEXT);
|
||||
} else {
|
||||
const auto id = field_id (field.c_str());
|
||||
const auto id = field_id (field);
|
||||
if (id != MU_MSG_FIELD_ID_NONE)
|
||||
add_field (fields, id);
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ process_field (const std::string& field, Flags flags)
|
|||
static bool
|
||||
is_range_field (const std::string& field)
|
||||
{
|
||||
const auto id = field_id (field.c_str());
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return false;
|
||||
else
|
||||
|
@ -192,7 +192,7 @@ static MyRange
|
|||
process_range (const std::string& field, const std::string& lower,
|
||||
const std::string& upper)
|
||||
{
|
||||
const auto id = field_id (field.c_str());
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return { lower, upper };
|
||||
|
||||
|
@ -213,7 +213,7 @@ process_range (const std::string& field, const std::string& lower,
|
|||
std::vector<std::string>
|
||||
Parser::Private::process_regex (const std::string& field, const std::regex& rx) const
|
||||
{
|
||||
const auto id = field_id (field.c_str());
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return {};
|
||||
|
||||
|
|
158
lib/mu-store.cc
158
lib/mu-store.cc
|
@ -59,10 +59,6 @@ constexpr auto DefaultMaxMessageSize = 100'000'000U;
|
|||
|
||||
constexpr auto ExpectedSchemaVersion = MU_STORE_SCHEMA_VERSION;
|
||||
|
||||
extern "C" {
|
||||
static unsigned add_or_update_msg (MuStore *store, unsigned docid, MuMsg *msg, GError **err);
|
||||
}
|
||||
|
||||
/* we cache these prefix strings, so we don't have to allocate them all
|
||||
* the time; this should save 10-20 string allocs per message */
|
||||
G_GNUC_CONST static const std::string&
|
||||
|
@ -239,6 +235,9 @@ struct Store::Private {
|
|||
return make_metadata(path);
|
||||
}
|
||||
|
||||
Xapian::docid add_or_update_msg (Xapian::docid docid, MuMsg *msg, GError **err);
|
||||
Xapian::Document new_doc_from_message (MuMsg *msg);
|
||||
|
||||
const bool read_only_{};
|
||||
std::unique_ptr<Xapian::Database> db_;
|
||||
|
||||
|
@ -384,8 +383,7 @@ Store::add_message (const std::string& path)
|
|||
throw Error{Error::Code::Message, "failed to create message: %s",
|
||||
gerr ? gerr->message : "something went wrong"};
|
||||
|
||||
auto store{reinterpret_cast<MuStore*>(this)}; // yuk.
|
||||
const auto docid{add_or_update_msg (store, 0, msg, &gerr)};
|
||||
const auto docid{priv_->add_or_update_msg (0, msg, &gerr)};
|
||||
mu_msg_unref (msg);
|
||||
if (G_UNLIKELY(docid == MU_STORE_INVALID_DOCID))
|
||||
throw Error{Error::Code::Message, "failed to add message: %s",
|
||||
|
@ -401,10 +399,8 @@ Store::add_message (const std::string& path)
|
|||
bool
|
||||
Store::update_message (MuMsg *msg, unsigned docid)
|
||||
{
|
||||
auto store{reinterpret_cast<MuStore*>(this)}; // yuk.
|
||||
|
||||
GError *gerr{};
|
||||
const auto docid2{add_or_update_msg (store, docid, msg, &gerr)};
|
||||
const auto docid2{priv_->add_or_update_msg (docid, msg, &gerr)};
|
||||
|
||||
if (G_UNLIKELY(docid != docid2))
|
||||
throw Error{Error::Code::Internal, "failed to update message",
|
||||
|
@ -588,112 +584,6 @@ Store::commit () try
|
|||
|
||||
} MU_XAPIAN_CATCH_BLOCK;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// C compat
|
||||
extern "C" {
|
||||
|
||||
|
||||
struct MuStore_ { Mu::Store* self; };
|
||||
|
||||
|
||||
static const Mu::Store*
|
||||
self (const MuStore *store)
|
||||
{
|
||||
if (!store) {
|
||||
g_error ("invalid store"); // terminates
|
||||
return {};
|
||||
}
|
||||
|
||||
return reinterpret_cast<const Mu::Store*>(store);
|
||||
}
|
||||
|
||||
static Mu::Store*
|
||||
mutable_self (MuStore *store)
|
||||
{
|
||||
if (!store) {
|
||||
g_error ("invalid store"); // terminates
|
||||
return {};
|
||||
}
|
||||
|
||||
auto s = reinterpret_cast<Mu::Store*>(store);
|
||||
if (s->metadata().read_only) {
|
||||
g_error ("store is read-only"); // terminates
|
||||
return {};
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
MuStore*
|
||||
mu_store_new_readable (const char* xpath, GError **err)
|
||||
{
|
||||
g_return_val_if_fail (xpath, NULL);
|
||||
|
||||
g_debug ("opening database at %s (read-only)", xpath);
|
||||
|
||||
try {
|
||||
return reinterpret_cast<MuStore*>(new Store (xpath));
|
||||
|
||||
} catch (const Mu::Error& me) {
|
||||
g_warning ("failed to open database: %s", me.what());
|
||||
} catch (const Xapian::Error& dbe) {
|
||||
g_warning ("failed to open database @ %s: %s", xpath,
|
||||
dbe.get_error_string() ? dbe.get_error_string() : "something went wrong");
|
||||
}
|
||||
|
||||
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_XAPIAN_CANNOT_OPEN,
|
||||
"failed to open database @ %s", xpath);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
MuStore*
|
||||
mu_store_ref (MuStore* store)
|
||||
{
|
||||
g_return_val_if_fail (store, NULL);
|
||||
g_return_val_if_fail (self(store)->priv()->ref_count_ > 0, NULL);
|
||||
|
||||
++self(store)->priv()->ref_count_;
|
||||
return store;
|
||||
}
|
||||
|
||||
|
||||
MuStore*
|
||||
mu_store_unref (MuStore* store)
|
||||
{
|
||||
g_return_val_if_fail (store, NULL);
|
||||
g_return_val_if_fail (self(store)->priv()->ref_count_ > 0, NULL);
|
||||
|
||||
auto me = reinterpret_cast<Mu::Store*>(store);
|
||||
|
||||
if (--me->priv()->ref_count_ == 0)
|
||||
delete me;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned
|
||||
mu_store_count (const MuStore *store, GError **err)
|
||||
{
|
||||
g_return_val_if_fail (store, (unsigned)-1);
|
||||
|
||||
try {
|
||||
return self(store)->size();
|
||||
|
||||
} MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(err, MU_ERROR_XAPIAN,
|
||||
(unsigned)-1);
|
||||
}
|
||||
|
||||
const char*
|
||||
mu_store_schema_version (const MuStore *store)
|
||||
{
|
||||
g_return_val_if_fail (store, NULL);
|
||||
|
||||
return self(store)->metadata().schema_version.c_str();
|
||||
}
|
||||
|
||||
static void
|
||||
add_terms_values_date (Xapian::Document& doc, MuMsg *msg, MuMsgFieldId mfid)
|
||||
{
|
||||
|
@ -958,7 +848,7 @@ add_terms_values_body (Xapian::Document& doc, MuMsg *msg,
|
|||
struct MsgDoc {
|
||||
Xapian::Document *_doc;
|
||||
MuMsg *_msg;
|
||||
Store *_store;
|
||||
Store::Private *_priv;
|
||||
/* callback data, to determine whether this message is 'personal' */
|
||||
gboolean _personal;
|
||||
const StringVec *_my_addresses;
|
||||
|
@ -1085,7 +975,7 @@ each_contact_info (MuMsgContact *contact, MsgDoc *msgdoc)
|
|||
add_term(*msgdoc->_doc, pfx + flat);
|
||||
add_address_subfields (*msgdoc->_doc, contact->email, pfx);
|
||||
/* store it also in our contacts cache */
|
||||
auto& contacts = msgdoc->_store->priv()->contacts_;
|
||||
auto& contacts{msgdoc->_priv->contacts_};
|
||||
contacts.add(Mu::ContactInfo(contact->full_address,
|
||||
contact->email,
|
||||
contact->name ? contact->name : "",
|
||||
|
@ -1095,11 +985,12 @@ each_contact_info (MuMsgContact *contact, MsgDoc *msgdoc)
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
static Xapian::Document
|
||||
new_doc_from_message (MuStore *store, MuMsg *msg)
|
||||
|
||||
Xapian::Document
|
||||
Store::Private::new_doc_from_message (MuMsg *msg)
|
||||
{
|
||||
Xapian::Document doc;
|
||||
MsgDoc docinfo = {&doc, msg, mutable_self(store), 0, NULL};
|
||||
MsgDoc docinfo = {&doc, msg, this, 0, NULL};
|
||||
|
||||
mu_msg_field_foreach ((MuMsgFieldForeachFunc)add_terms_values, &docinfo);
|
||||
|
||||
|
@ -1112,7 +1003,7 @@ new_doc_from_message (MuStore *store, MuMsg *msg)
|
|||
else if (msgdoc->_personal)
|
||||
return TRUE; // already deemed personal
|
||||
|
||||
if (msgdoc->_store->contacts().is_personal(contact->email))
|
||||
if (msgdoc->_priv->contacts_.is_personal(contact->email))
|
||||
msgdoc->_personal = true; // this one's personal.
|
||||
|
||||
return TRUE;
|
||||
|
@ -1150,38 +1041,29 @@ update_threading_info (MuMsg *msg, Xapian::Document& doc)
|
|||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
add_or_update_msg (MuStore *store, unsigned docid, MuMsg *msg, GError **err)
|
||||
Xapian::docid
|
||||
Store::Private::add_or_update_msg (unsigned docid, MuMsg *msg, GError **err)
|
||||
{
|
||||
g_return_val_if_fail (store, MU_STORE_INVALID_DOCID);
|
||||
g_return_val_if_fail (msg, MU_STORE_INVALID_DOCID);
|
||||
|
||||
try {
|
||||
Xapian::docid id;
|
||||
Xapian::Document doc (new_doc_from_message(store, msg));
|
||||
Xapian::Document doc (new_doc_from_message(msg));
|
||||
const std::string term (get_uid_term (mu_msg_get_path(msg)));
|
||||
|
||||
auto self = mutable_self(store);
|
||||
auto wdb = self->priv()->writable_db();
|
||||
|
||||
add_term (doc, term);
|
||||
|
||||
// update the threading info if this message has a message id
|
||||
if (mu_msg_get_msgid (msg))
|
||||
update_threading_info (msg, doc);
|
||||
|
||||
if (docid == 0)
|
||||
id = wdb.replace_document (term, doc);
|
||||
else {
|
||||
wdb.replace_document (docid, doc);
|
||||
id = docid;
|
||||
}
|
||||
|
||||
return id;
|
||||
if (docid == 0)
|
||||
return writable_db().replace_document (term, doc);
|
||||
|
||||
writable_db().replace_document (docid, doc);
|
||||
return docid;
|
||||
|
||||
} MU_XAPIAN_CATCH_BLOCK_G_ERROR (err, MU_ERROR_XAPIAN_STORE_FAILED);
|
||||
|
||||
return MU_STORE_INVALID_DOCID;
|
||||
}
|
||||
|
||||
} // extern C
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
|
||||
#include <mu-msg.hh>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
@ -38,6 +36,10 @@
|
|||
|
||||
namespace Mu {
|
||||
|
||||
/* http://article.gmane.org/gmane.comp.search.xapian.general/3656 */
|
||||
#define MU_STORE_MAX_TERM_LENGTH (240)
|
||||
#define MU_STORE_INVALID_DOCID 0
|
||||
|
||||
class Store {
|
||||
public:
|
||||
using Id = unsigned; /**< Id for a message in the store (internally,
|
||||
|
@ -292,79 +294,4 @@ private:
|
|||
|
||||
} // namespace Mu
|
||||
|
||||
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <inttypes.h>
|
||||
#include <utils/mu-util.h>
|
||||
#include <mu-contacts.hh>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct MuStore_;
|
||||
typedef struct MuStore_ MuStore;
|
||||
|
||||
/* http://article.gmane.org/gmane.comp.search.xapian.general/3656 */
|
||||
#define MU_STORE_MAX_TERM_LENGTH (240)
|
||||
|
||||
/**
|
||||
* create a new read-only Xapian store, for querying documents
|
||||
*
|
||||
* @param path the path to the database
|
||||
* @param err to receive error info or NULL. err->code is MuError value
|
||||
*
|
||||
* @return a new MuStore object with ref count == 1, or NULL in case of error;
|
||||
* free with mu_store_unref
|
||||
*/
|
||||
MuStore* mu_store_new_readable (const char* xpath, GError **err)
|
||||
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* increase the reference count for this store with 1
|
||||
*
|
||||
* @param store a valid store object
|
||||
*
|
||||
* @return the same store with increased ref count, or NULL in case of
|
||||
* error
|
||||
*/
|
||||
MuStore* mu_store_ref (MuStore *store);
|
||||
|
||||
/**
|
||||
* decrease the reference count for this store with 1
|
||||
*
|
||||
* @param store a valid store object
|
||||
*
|
||||
* @return NULL
|
||||
*/
|
||||
MuStore* mu_store_unref (MuStore *store);
|
||||
|
||||
/**
|
||||
* get the version of the xapian database (ie., the version of the
|
||||
* 'schema' we are using). If this version != MU_STORE_SCHEMA_VERSION,
|
||||
* it's means we need to a full reindex.
|
||||
*
|
||||
* @param store the store to inspect
|
||||
*
|
||||
* @return the version of the database as a newly allocated string
|
||||
* (free with g_free); if there is no version yet, it will return NULL
|
||||
*/
|
||||
const char* mu_store_schema_version (const MuStore* store);
|
||||
|
||||
|
||||
/**
|
||||
* get the numbers of documents in the database
|
||||
*
|
||||
* @param index a valid MuStore instance
|
||||
* @param err to receive error info or NULL. err->code is MuError value
|
||||
*
|
||||
* @return the number of documents in the database; (unsigned)-1 in
|
||||
* case of error
|
||||
*/
|
||||
unsigned mu_store_count (const MuStore *store, GError **err);
|
||||
|
||||
#define MU_STORE_INVALID_DOCID 0
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __MU_STORE_HH__ */
|
||||
|
|
|
@ -191,207 +191,6 @@ test_mu_maildir_mkdir_05 (void)
|
|||
==, FALSE);
|
||||
}
|
||||
|
||||
|
||||
static gchar*
|
||||
copy_test_data (void)
|
||||
{
|
||||
gchar *dir, *cmd;
|
||||
|
||||
dir = test_mu_common_get_random_tmpdir();
|
||||
cmd = g_strdup_printf ("mkdir -p -m 0700 %s", dir);
|
||||
if (g_test_verbose())
|
||||
g_debug ("cmd: %s\n", cmd);
|
||||
g_assert (g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL));
|
||||
g_free (cmd);
|
||||
|
||||
cmd = g_strdup_printf ("cp -R %s %s", MU_TESTMAILDIR, dir);
|
||||
if (g_test_verbose())
|
||||
g_debug ("cmd: %s\n", cmd);
|
||||
g_assert (g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL));
|
||||
g_free (cmd);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
int _file_count;
|
||||
int _dir_entered;
|
||||
int _dir_left;
|
||||
} WalkData;
|
||||
|
||||
static MuError
|
||||
dir_cb (const char *fullpath, gboolean enter, WalkData *data)
|
||||
{
|
||||
if (enter)
|
||||
++data->_dir_entered;
|
||||
else
|
||||
++data->_dir_left;
|
||||
|
||||
if (g_test_verbose())
|
||||
g_debug ("%s: %s: %s (%u)\n", __func__, enter ? "entering" : "leaving",
|
||||
fullpath, enter ? data->_dir_entered : data->_dir_left);
|
||||
|
||||
return MU_OK;
|
||||
}
|
||||
|
||||
|
||||
static MuError
|
||||
msg_cb (const char *fullpath, const char* mdir, struct stat *statinfo,
|
||||
WalkData *data)
|
||||
{
|
||||
++data->_file_count;
|
||||
return MU_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_mu_maildir_walk_01 (void)
|
||||
{
|
||||
char *tmpdir;
|
||||
WalkData data;
|
||||
MuError rv;
|
||||
|
||||
tmpdir = copy_test_data ();
|
||||
memset (&data, 0, sizeof(WalkData));
|
||||
|
||||
rv = mu_maildir_walk (tmpdir,
|
||||
(MuMaildirWalkMsgCallback)msg_cb,
|
||||
(MuMaildirWalkDirCallback)dir_cb,
|
||||
TRUE,
|
||||
&data);
|
||||
|
||||
g_assert_cmpuint (MU_OK, ==, rv);
|
||||
g_assert_cmpuint (data._file_count, ==, 19);
|
||||
|
||||
g_assert_cmpuint (data._dir_entered,==, 5);
|
||||
g_assert_cmpuint (data._dir_left,==, 5);
|
||||
|
||||
g_free (tmpdir);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_mu_maildir_walk (void)
|
||||
{
|
||||
char *tmpdir, *cmd, *dir;
|
||||
WalkData data;
|
||||
MuError rv;
|
||||
|
||||
tmpdir = copy_test_data ();
|
||||
memset (&data, 0, sizeof(WalkData));
|
||||
|
||||
/* mark the 'new' dir with '.noindex', to ignore it */
|
||||
dir = g_strdup_printf ("%s%ctestdir%cnew", tmpdir,
|
||||
G_DIR_SEPARATOR, G_DIR_SEPARATOR);
|
||||
cmd = g_strdup_printf ("chmod 700 %s", dir);
|
||||
g_assert (g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL));
|
||||
g_free (cmd);
|
||||
|
||||
cmd = g_strdup_printf ("touch %s%c.noindex", dir, G_DIR_SEPARATOR);
|
||||
g_assert (g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL));
|
||||
g_free (cmd);
|
||||
g_free (dir);
|
||||
|
||||
rv = mu_maildir_walk (tmpdir,
|
||||
(MuMaildirWalkMsgCallback)msg_cb,
|
||||
(MuMaildirWalkDirCallback)dir_cb,
|
||||
TRUE,
|
||||
&data);
|
||||
|
||||
g_assert_cmpuint (MU_OK, ==, rv);
|
||||
g_assert_cmpuint (data._file_count, ==, 15);
|
||||
|
||||
g_assert_cmpuint (data._dir_entered,==, 4);
|
||||
g_assert_cmpuint (data._dir_left,==, 4);
|
||||
|
||||
g_free (tmpdir);
|
||||
}
|
||||
|
||||
static void
|
||||
test_mu_maildir_walk_with_noupdate (void)
|
||||
{
|
||||
char *tmpdir, *cmd, *dir;
|
||||
WalkData data;
|
||||
MuError rv;
|
||||
|
||||
tmpdir = copy_test_data ();
|
||||
|
||||
/* mark the 'new' dir with '.noindex', to ignore it */
|
||||
dir = g_strdup_printf ("%s%ctestdir%cnew", tmpdir,
|
||||
G_DIR_SEPARATOR, G_DIR_SEPARATOR);
|
||||
cmd = g_strdup_printf ("chmod 700 %s", dir);
|
||||
g_assert (g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL));
|
||||
g_free (cmd);
|
||||
|
||||
memset (&data, 0, sizeof(WalkData));
|
||||
rv = mu_maildir_walk (tmpdir,
|
||||
(MuMaildirWalkMsgCallback)msg_cb,
|
||||
(MuMaildirWalkDirCallback)dir_cb,
|
||||
FALSE, /* ie., non-full update */
|
||||
&data);
|
||||
|
||||
g_assert_cmpuint (MU_OK, ==, rv);
|
||||
g_assert_cmpuint (data._file_count, ==, 19);
|
||||
g_assert_cmpuint (data._dir_entered,==, 5);
|
||||
g_assert_cmpuint (data._dir_left,==, 5);
|
||||
|
||||
/* again, full update. results should be the same, since there
|
||||
* is no noupdate yet */
|
||||
memset (&data, 0, sizeof(WalkData));
|
||||
rv = mu_maildir_walk (tmpdir,
|
||||
(MuMaildirWalkMsgCallback)msg_cb,
|
||||
(MuMaildirWalkDirCallback)dir_cb,
|
||||
TRUE, /* ie., full update */
|
||||
&data);
|
||||
|
||||
g_assert_cmpuint (MU_OK, ==, rv);
|
||||
g_assert_cmpuint (data._file_count, ==, 19);
|
||||
g_assert_cmpuint (data._dir_entered,==, 5);
|
||||
g_assert_cmpuint (data._dir_left,==, 5);
|
||||
|
||||
/* add a '.noupdate' file; this affects the outcome when the
|
||||
* 4th arg to mu_maildir_walk is FALSE */
|
||||
cmd = g_strdup_printf ("touch %s%c.noupdate", dir, G_DIR_SEPARATOR);
|
||||
g_assert (g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL));
|
||||
g_free (cmd);
|
||||
|
||||
memset (&data, 0, sizeof(WalkData));
|
||||
rv = mu_maildir_walk (tmpdir,
|
||||
(MuMaildirWalkMsgCallback)msg_cb,
|
||||
(MuMaildirWalkDirCallback)dir_cb,
|
||||
FALSE, /* non-full update */
|
||||
&data);
|
||||
|
||||
g_assert_cmpuint (MU_OK, ==, rv);
|
||||
g_assert_cmpuint (data._file_count, ==, 15);
|
||||
|
||||
g_assert_cmpuint (data._dir_entered,==, 4);
|
||||
g_assert_cmpuint (data._dir_left,==, 4);
|
||||
|
||||
/* now run again, but do a full update */
|
||||
memset (&data, 0, sizeof(WalkData));
|
||||
rv = mu_maildir_walk (tmpdir,
|
||||
(MuMaildirWalkMsgCallback)msg_cb,
|
||||
(MuMaildirWalkDirCallback)dir_cb,
|
||||
TRUE, /* full update */
|
||||
&data);
|
||||
|
||||
g_assert_cmpuint (MU_OK, ==, rv);
|
||||
g_assert_cmpuint (data._file_count, ==, 19);
|
||||
|
||||
g_assert_cmpuint (data._dir_entered,==, 5);
|
||||
g_assert_cmpuint (data._dir_left,==, 5);
|
||||
|
||||
g_free (dir);
|
||||
g_free (tmpdir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_mu_maildir_get_flags_from_path (void)
|
||||
{
|
||||
|
@ -661,15 +460,6 @@ main (int argc, char *argv[])
|
|||
g_test_add_func ("/mu-maildir/mu-maildir-mkdir-05",
|
||||
test_mu_maildir_mkdir_05);
|
||||
|
||||
|
||||
/* mu_util_maildir_walk */
|
||||
g_test_add_func ("/mu-maildir/mu-maildir-walk-01",
|
||||
test_mu_maildir_walk_01);
|
||||
g_test_add_func ("/mu-maildir/mu-maildir-walk",
|
||||
test_mu_maildir_walk);
|
||||
g_test_add_func ("/mu-maildir/mu-maildir-walk-with-noupdate",
|
||||
test_mu_maildir_walk_with_noupdate);
|
||||
|
||||
/* get/set flags */
|
||||
g_test_add_func("/mu-maildir/mu-maildir-get-new-path-new",
|
||||
test_mu_maildir_get_new_path_new);
|
||||
|
|
|
@ -39,7 +39,11 @@ mu_date_str_s (const char* frm, time_t t)
|
|||
g_return_val_if_fail (frm, NULL);
|
||||
|
||||
tmbuf = localtime(&t);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
len = strftime (buf, sizeof(buf) - 1, frm, tmbuf);
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
if (len == 0)
|
||||
return ""; /* not necessarily an error... */
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "config.h"
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE (500)
|
||||
#endif /*_XOPEN_SOURCE*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
@ -38,7 +41,7 @@ mu_str_size_s (size_t s)
|
|||
static char buf[32];
|
||||
char *tmp;
|
||||
|
||||
tmp = g_format_size_for_display ((goffset)s);
|
||||
tmp = g_format_size((goffset)s);
|
||||
strncpy (buf, tmp, sizeof(buf));
|
||||
buf[sizeof(buf) -1] = '\0'; /* just in case */
|
||||
g_free (tmp);
|
||||
|
@ -46,13 +49,6 @@ mu_str_size_s (size_t s)
|
|||
return buf;
|
||||
}
|
||||
|
||||
char*
|
||||
mu_str_size (size_t s)
|
||||
{
|
||||
return g_strdup (mu_str_size_s(s));
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
mu_str_summarize (const char* str, size_t max_lines)
|
||||
{
|
||||
|
@ -94,34 +90,6 @@ mu_str_summarize (const char* str, size_t max_lines)
|
|||
return summary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
char*
|
||||
mu_str_replace (const char *str, const char *substr, const char *repl)
|
||||
{
|
||||
GString *gstr;
|
||||
const char *cur;
|
||||
|
||||
g_return_val_if_fail (str, NULL);
|
||||
g_return_val_if_fail (substr, NULL);
|
||||
g_return_val_if_fail (repl, NULL);
|
||||
|
||||
gstr = g_string_sized_new (2 * strlen (str));
|
||||
|
||||
for (cur = str; *cur; ++cur) {
|
||||
if (g_str_has_prefix (cur, substr)) {
|
||||
g_string_append (gstr, repl);
|
||||
cur += strlen (substr) - 1;
|
||||
} else
|
||||
g_string_append_c (gstr, *cur);
|
||||
}
|
||||
|
||||
return g_string_free (gstr, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
char*
|
||||
mu_str_from_list (const GSList *lst, char sepa)
|
||||
{
|
||||
|
@ -179,69 +147,6 @@ mu_str_to_list (const char *str, char sepa, gboolean strip)
|
|||
return lst;
|
||||
}
|
||||
|
||||
GSList*
|
||||
mu_str_esc_to_list (const char *strings)
|
||||
{
|
||||
GSList *lst;
|
||||
GString *part;
|
||||
unsigned u;
|
||||
gboolean quoted, escaped;
|
||||
|
||||
g_return_val_if_fail (strings, NULL);
|
||||
|
||||
part = g_string_new (NULL);
|
||||
|
||||
for (u = 0, lst = NULL, quoted = FALSE, escaped = FALSE;
|
||||
u != strlen (strings); ++u) {
|
||||
|
||||
char kar;
|
||||
kar = strings[u];
|
||||
|
||||
if (kar == '\\') {
|
||||
if (escaped)
|
||||
g_string_append_c (part, '\\');
|
||||
escaped = !escaped;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quoted && kar != '"') {
|
||||
g_string_append_c (part, kar);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (kar) {
|
||||
case '"':
|
||||
if (!escaped)
|
||||
quoted = !quoted;
|
||||
else
|
||||
g_string_append_c (part, kar);
|
||||
continue;
|
||||
case ' ':
|
||||
if (part->len > 0) {
|
||||
lst = g_slist_prepend
|
||||
(lst, g_string_free (part, FALSE));
|
||||
part = g_string_new (NULL);
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
g_string_append_c (part, kar);
|
||||
}
|
||||
}
|
||||
|
||||
if (part->len)
|
||||
lst = g_slist_prepend (lst, g_string_free (part, FALSE));
|
||||
|
||||
return g_slist_reverse (lst);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mu_str_free_list (GSList *lst)
|
||||
{
|
||||
g_slist_foreach (lst, (GFunc)g_free, NULL);
|
||||
g_slist_free (lst);
|
||||
}
|
||||
|
||||
|
||||
/* this function is critical for sorting performance; therefore, no
|
||||
* regexps, but just some good old c pointer magic */
|
||||
|
@ -306,34 +211,6 @@ mu_str_fullpath_s (const char* path, const char* name)
|
|||
}
|
||||
|
||||
|
||||
char*
|
||||
mu_str_escape_c_literal (const gchar* str, gboolean in_quotes)
|
||||
{
|
||||
const char* cur;
|
||||
GString *tmp;
|
||||
|
||||
g_return_val_if_fail (str, NULL);
|
||||
|
||||
tmp = g_string_sized_new (2 * strlen(str));
|
||||
|
||||
if (in_quotes)
|
||||
g_string_append_c (tmp, '"');
|
||||
|
||||
for (cur = str; *cur; ++cur)
|
||||
switch (*cur) {
|
||||
case '\\': tmp = g_string_append (tmp, "\\\\"); break;
|
||||
case '"': tmp = g_string_append (tmp, "\\\""); break;
|
||||
default: tmp = g_string_append_c (tmp, *cur);
|
||||
}
|
||||
|
||||
if (in_quotes)
|
||||
g_string_append_c (tmp, '"');
|
||||
|
||||
return g_string_free (tmp, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* turn \0-terminated buf into ascii (which is a utf8 subset); convert
|
||||
* any non-ascii into '.'
|
||||
*/
|
||||
|
|
|
@ -40,8 +40,6 @@ G_BEGIN_DECLS
|
|||
* 10-based SI units, _not_ the powers-of-2 based ones.
|
||||
*
|
||||
* mu_str_size_s returns a ptr to a static buffer,
|
||||
* while mu_str_size returns dynamically allocated
|
||||
* memory that must be freed after use.
|
||||
*
|
||||
* @param t the size as an size_t
|
||||
*
|
||||
|
@ -49,20 +47,6 @@ G_BEGIN_DECLS
|
|||
* for what to do with it
|
||||
*/
|
||||
const char* mu_str_size_s (size_t s);
|
||||
char* mu_str_size (size_t s) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
|
||||
/**
|
||||
* Replace all occurrences of substr in str with repl
|
||||
*
|
||||
* @param str a string
|
||||
* @param substr some string to replace
|
||||
* @param repl a replacement string
|
||||
*
|
||||
* @return a newly allocated string with the substr replaced by repl; free with g_free
|
||||
*/
|
||||
char *mu_str_replace (const char *str, const char *substr, const char *repl);
|
||||
|
||||
|
||||
/**
|
||||
* get a 'summary' of the string, ie. the first /n/ lines of the
|
||||
|
@ -87,18 +71,6 @@ char* mu_str_summarize (const char* str, size_t max_lines)
|
|||
*/
|
||||
const char* mu_str_fullpath_s (const char* path, const char* name);
|
||||
|
||||
/**
|
||||
* escape a string like a string literal in C; ie. replace \ with \\,
|
||||
* and " with \"
|
||||
*
|
||||
* @param str a non-NULL str
|
||||
* @param in_quotes whether the result should be enclosed in ""
|
||||
*
|
||||
* @return the escaped string, newly allocated (free with g_free)
|
||||
*/
|
||||
char* mu_str_escape_c_literal (const gchar* str, gboolean in_quotes)
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* turn a string into plain ascii by replacing each non-ascii
|
||||
* character with a dot ('.'). Replacement is done in-place.
|
||||
|
@ -162,24 +134,12 @@ char* mu_str_from_list (const GSList *lst, char sepa);
|
|||
*/
|
||||
GSList* mu_str_to_list (const char *str, char sepa, gboolean strip);
|
||||
|
||||
/**
|
||||
* convert a string (with possible escaping) to a list. list items are
|
||||
* separated by one or more spaces. list items can be quoted (using
|
||||
* '"').
|
||||
*
|
||||
* @param str a string
|
||||
*
|
||||
* @return a list of elements or NULL in case of error, free with
|
||||
* mu_str_free_list
|
||||
*/
|
||||
GSList* mu_str_esc_to_list (const char *str);
|
||||
|
||||
/**
|
||||
* free a GSList consisting of allocated strings
|
||||
*
|
||||
* @param lst a GSList
|
||||
*/
|
||||
void mu_str_free_list (GSList *lst);
|
||||
#define mu_str_free_list(lst) g_slist_free_full(lst, g_free)
|
||||
|
||||
/**
|
||||
* strip the subject of Re:, Fwd: etc.
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
|
||||
#include "mu-util.h"
|
||||
#define _XOPEN_SOURCE 500
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE (500)
|
||||
#endif /*_XOPEN_SOURCE*/
|
||||
|
||||
#include "mu-util.h"
|
||||
#ifdef HAVE_WORDEXP_H
|
||||
#include <wordexp.h> /* for shell-style globbing */
|
||||
#endif /*HAVE_WORDEXP_H*/
|
||||
|
|
|
@ -32,73 +32,6 @@
|
|||
|
||||
#include "mu-str.h"
|
||||
|
||||
|
||||
static void
|
||||
test_mu_str_size_01 (void)
|
||||
{
|
||||
struct lconv *lc;
|
||||
char *tmp2;
|
||||
|
||||
lc = localeconv();
|
||||
|
||||
g_assert_cmpstr (mu_str_size_s (0), ==, "0 bytes");
|
||||
|
||||
tmp2 = g_strdup_printf ("97%s7 KB", lc->decimal_point);
|
||||
g_assert_cmpstr (mu_str_size_s (100000), ==, tmp2);
|
||||
g_free (tmp2);
|
||||
|
||||
tmp2 = g_strdup_printf ("1%s0 MB", lc->decimal_point);
|
||||
g_assert_cmpstr (mu_str_size_s (1100*1000), ==, tmp2);
|
||||
g_free (tmp2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_mu_str_size_02 (void)
|
||||
{
|
||||
struct lconv *lc;
|
||||
char *tmp1, *tmp2;
|
||||
|
||||
lc = localeconv();
|
||||
|
||||
tmp2 = g_strdup_printf ("1%s0 MB", lc->decimal_point);
|
||||
tmp1 = mu_str_size (999999);
|
||||
g_assert_cmpstr (tmp1, !=, tmp2);
|
||||
|
||||
g_free (tmp1);
|
||||
g_free (tmp2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_mu_str_esc_to_list (void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
const char* str;
|
||||
const char* strs[3];
|
||||
} strings [] = {
|
||||
{ "maildir:foo",
|
||||
{"maildir:foo", NULL, NULL}},
|
||||
{ "maildir:sent items",
|
||||
{"maildir:sent", "items", NULL}},
|
||||
{ "\"maildir:sent items\"",
|
||||
{"maildir:sent items", NULL, NULL}},
|
||||
};
|
||||
|
||||
for (i = 0; i != G_N_ELEMENTS(strings); ++i) {
|
||||
GSList *lst, *cur;
|
||||
unsigned u;
|
||||
lst = mu_str_esc_to_list (strings[i].str);
|
||||
for (cur = lst, u = 0; cur; cur = g_slist_next(cur), ++u)
|
||||
g_assert_cmpstr ((const char*)cur->data,==,
|
||||
strings[i].strs[u]);
|
||||
mu_str_free_list (lst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
assert_cmplst (GSList *lst, const char *items[])
|
||||
{
|
||||
|
@ -189,33 +122,6 @@ test_mu_str_to_list_strip (void)
|
|||
mu_str_free_list (lst);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_mu_str_replace (void)
|
||||
{
|
||||
unsigned u;
|
||||
struct {
|
||||
const char* str;
|
||||
const char* sub;
|
||||
const char *repl;
|
||||
const char *exp;
|
||||
} strings [] = {
|
||||
{ "hello", "ll", "xx", "hexxo" },
|
||||
{ "hello", "hello", "hi", "hi" },
|
||||
{ "hello", "foo", "bar", "hello" }
|
||||
};
|
||||
|
||||
for (u = 0; u != G_N_ELEMENTS(strings); ++u) {
|
||||
char *res;
|
||||
res = mu_str_replace (strings[u].str,
|
||||
strings[u].sub,
|
||||
strings[u].repl);
|
||||
g_assert_cmpstr (res,==,strings[u].exp);
|
||||
g_free (res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_mu_str_remove_ctrl_in_place (void)
|
||||
{
|
||||
|
@ -248,12 +154,6 @@ main (int argc, char *argv[])
|
|||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
/* mu_str_size */
|
||||
g_test_add_func ("/mu-str/mu-str-size-01",
|
||||
test_mu_str_size_01);
|
||||
g_test_add_func ("/mu-str/mu-str-size-02",
|
||||
test_mu_str_size_02);
|
||||
|
||||
g_test_add_func ("/mu-str/mu-str-from-list",
|
||||
test_mu_str_from_list);
|
||||
g_test_add_func ("/mu-str/mu-str-to-list",
|
||||
|
@ -261,12 +161,6 @@ main (int argc, char *argv[])
|
|||
g_test_add_func ("/mu-str/mu-str-to-list-strip",
|
||||
test_mu_str_to_list_strip);
|
||||
|
||||
g_test_add_func ("/mu-str/mu-str-replace",
|
||||
test_mu_str_replace);
|
||||
|
||||
g_test_add_func ("/mu-str/mu-str-esc-to-list",
|
||||
test_mu_str_esc_to_list);
|
||||
|
||||
g_test_add_func ("/mu-str/mu_str_remove_ctrl_in_place",
|
||||
test_mu_str_remove_ctrl_in_place);
|
||||
|
||||
|
|
|
@ -116,16 +116,11 @@ search (const char* query, unsigned expected)
|
|||
static void
|
||||
test_mu_index (void)
|
||||
{
|
||||
MuStore *store;
|
||||
gchar *xpath;
|
||||
|
||||
xpath = g_strdup_printf ("%s%c%s", DBPATH, G_DIR_SEPARATOR, "xapian");
|
||||
gchar *xpath{g_strdup_printf ("%s%c%s", DBPATH, G_DIR_SEPARATOR, "xapian")};
|
||||
g_printerr ("*** %s\n", DBPATH);
|
||||
store = mu_store_new_readable (xpath, NULL);
|
||||
g_assert (store);
|
||||
Mu::Store store{xpath, true};
|
||||
|
||||
g_assert_cmpuint (mu_store_count (store, NULL), ==, 13);
|
||||
mu_store_unref (store);
|
||||
g_assert_cmpuint (store.size(), ==, 13);
|
||||
|
||||
g_free (xpath);
|
||||
}
|
||||
|
@ -348,8 +343,8 @@ test_mu_extract_01 (void)
|
|||
==,
|
||||
"MIME-parts in this message:\n"
|
||||
" 1 <none> text/plain [<none>] (27 bytes)\n"
|
||||
" 2 sittingbull.jpg image/jpeg [inline] (23.3 KB)\n"
|
||||
" 3 custer.jpg image/jpeg [inline] (21.1 KB)\n");
|
||||
" 2 sittingbull.jpg image/jpeg [inline] (23.9\302\240kB)\n"
|
||||
" 3 custer.jpg image/jpeg [inline] (21.6\302\240kB)\n");
|
||||
|
||||
/* we expect zero lines of error output */
|
||||
g_assert_cmpuint (newlines_in_output(erroutput),==,0);
|
||||
|
|
Loading…
Reference in New Issue