diff --git a/lib/mu-contacts.cc b/lib/mu-contacts.cc index 28c421ea..157953a4 100644 --- a/lib/mu-contacts.cc +++ b/lib/mu-contacts.cc @@ -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); diff --git a/lib/mu-maildir.cc b/lib/mu-maildir.cc index 86050658..f50381f2 100644 --- a/lib/mu-maildir.cc +++ b/lib/mu-maildir.cc @@ -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) { diff --git a/lib/mu-maildir.hh b/lib/mu-maildir.hh index 93684d01..98f9958a 100644 --- a/lib/mu-maildir.hh +++ b/lib/mu-maildir.hh @@ -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/' * diff --git a/lib/mu-msg.cc b/lib/mu-msg.cc index 6ef4b183..ed74e643 100644 --- a/lib/mu-msg.cc +++ b/lib/mu-msg.cc @@ -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); } diff --git a/lib/mu-parser.cc b/lib/mu-parser.cc index 70fdd72d..b7104459 100644 --- a/lib/mu-parser.cc +++ b/lib/mu-parser.cc @@ -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 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 {}; diff --git a/lib/mu-store.cc b/lib/mu-store.cc index d2909bef..2fa03c2e 100644 --- a/lib/mu-store.cc +++ b/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 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(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(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(store); -} - -static Mu::Store* -mutable_self (MuStore *store) -{ - if (!store) { - g_error ("invalid store"); // terminates - return {}; - } - - auto s = reinterpret_cast(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(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(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 diff --git a/lib/mu-store.hh b/lib/mu-store.hh index 1d815db1..d1d05673 100644 --- a/lib/mu-store.hh +++ b/lib/mu-store.hh @@ -22,8 +22,6 @@ #include -#ifdef __cplusplus - #include #include #include @@ -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 -#include -#include -#include - -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__ */ diff --git a/lib/test-mu-maildir.cc b/lib/test-mu-maildir.cc index 3665c9cb..5be3dddb 100644 --- a/lib/test-mu-maildir.cc +++ b/lib/test-mu-maildir.cc @@ -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); diff --git a/lib/utils/mu-date.c b/lib/utils/mu-date.c index 4d463972..b8810667 100644 --- a/lib/utils/mu-date.c +++ b/lib/utils/mu-date.c @@ -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... */ diff --git a/lib/utils/mu-str.c b/lib/utils/mu-str.c index 607d3221..c74f2903 100644 --- a/lib/utils/mu-str.c +++ b/lib/utils/mu-str.c @@ -22,6 +22,9 @@ #include "config.h" #endif /*HAVE_CONFIG_H*/ +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE (500) +#endif /*_XOPEN_SOURCE*/ #include #include @@ -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 '.' */ diff --git a/lib/utils/mu-str.h b/lib/utils/mu-str.h index f009a118..cfb292fd 100644 --- a/lib/utils/mu-str.h +++ b/lib/utils/mu-str.h @@ -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. diff --git a/lib/utils/mu-util.c b/lib/utils/mu-util.c index e71e9c10..816a70ca 100644 --- a/lib/utils/mu-util.c +++ b/lib/utils/mu-util.c @@ -23,9 +23,11 @@ #include #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 /* for shell-style globbing */ #endif /*HAVE_WORDEXP_H*/ diff --git a/lib/utils/test-mu-str.c b/lib/utils/test-mu-str.c index 75fc71fb..f714d3f3 100644 --- a/lib/utils/test-mu-str.c +++ b/lib/utils/test-mu-str.c @@ -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); diff --git a/mu/test-mu-cmd.cc b/mu/test-mu-cmd.cc index d82fe76c..d494cd19 100644 --- a/mu/test-mu-cmd.cc +++ b/mu/test-mu-cmd.cc @@ -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 text/plain [] (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);