diff --git a/scm/mu-scm-store.cc b/scm/mu-scm-store.cc index 17f6dd03..420c66f8 100644 --- a/scm/mu-scm-store.cc +++ b/scm/mu-scm-store.cc @@ -38,6 +38,57 @@ to_store(SCM scm, const char *func, int pos) return *reinterpret_cast(scm_foreign_object_ref(scm, 0)); } +static SCM +subr_cc_store_alist(SCM store_scm) try { + constexpr auto func{"cc-store-alist"}; + + SCM alist{SCM_EOL}; + const auto& conf{to_store(store_scm, func, 1).config()}; + + using MuConfig = Mu::Config; + using Type = MuConfig::Type; + + for (const auto& prop: Mu::Config::properties) { + + // don't expose internal values & values that may change during + // runtime + if (any_of(prop.flags & + (MuConfig::Flags::Internal | MuConfig::Flags::Runtime))) + continue; + + const auto str{conf.get_str(prop)}; + if (str.empty()) + continue; + + const auto name{make_symbol(prop.name)}; + const auto val = std::invoke([&]() { + switch (prop.type) { + case Type::Number: + return to_scm(MuConfig::decode(str)); + case Type::Boolean: + return to_scm(MuConfig::decode(str)); + case Type::Timestamp: + return to_scm(MuConfig::decode(str)); + case Type::Path: + return to_scm(MuConfig::decode(str)); + case Type::String: + return to_scm(MuConfig::decode(str)); + case Type::StringList: + return to_scm(MuConfig::decode(str)); + default: + throw ScmError{ScmError::Id::WrongType, func, 1, store_scm, "store"}; + } + }); + + alist = scm_acons(name, val, alist); + } + + return scm_reverse_x(alist, SCM_EOL); + +} catch (const ScmError& err) { + err.throw_scm(); +} + static SCM subr_cc_store_mcount(SCM store_scm) try { return to_scm(to_store(store_scm, "cc-store-mcount", 1).size()); @@ -139,6 +190,9 @@ init_subrs() reinterpret_cast(subr_cc_store_mcount)); scm_c_define_gsubr("cc-store-cfind", 5/*req*/, 0/*opt*/, 0/*rst*/, reinterpret_cast(subr_cc_store_cfind)); + scm_c_define_gsubr("cc-store-alist", 1/*req*/, 0/*opt*/, 0/*rst*/, + reinterpret_cast(subr_cc_store_alist)); + #pragma GCC diagnostic pop } @@ -167,8 +221,8 @@ Mu::Scm::init_store(const Store& store) SCM Mu::Scm::to_scm(const Contact& contact) { - static SCM email{scm_from_utf8_symbol("email")}; - static SCM name{scm_from_utf8_symbol("name")}; + static SCM email{make_symbol("email")}; + static SCM name{make_symbol("name")}; SCM alist = scm_acons(email, to_scm(contact.email), SCM_EOL); if (!contact.name.empty()) diff --git a/scm/mu-scm-test.scm b/scm/mu-scm-test.scm index bde76488..234a527e 100644 --- a/scm/mu-scm-test.scm +++ b/scm/mu-scm-test.scm @@ -3,14 +3,18 @@ (use-modules (mu) (srfi srfi-64) (ice-9 textual-ports)) -(define (test-basic) - (test-begin "test-basic") +(define (test-store) + (test-begin "test-store") (test-equal "mcount" 19 (mcount)) (test-equal "cfind" 29 (length (cfind ""))) (test-equal "mfind" 19 (length (mfind ""))) - (test-end "test-basic")) + (let ((info (store->alist))) + (test-equal 50000 (assoc-ref info 'batch-size)) + (test-equal 100000000 (assoc-ref info 'max-message-size))) + + (test-end "test-store")) (define (test-basic-mfind) @@ -33,10 +37,8 @@ (let ((recip (car (to msg)))) (test-equal "Bilbo Baggins" (assoc-ref recip 'name)) (test-equal "bilbo@anotherexample.com" (assoc-ref recip 'email))) - ;; no date (test-assert (not (date msg))) - ;; flags (test-equal '(unread) (flags msg)) (test-assert (unread? msg)) @@ -171,7 +173,7 @@ (test-with-runner runner (test-begin "mu-scm-tests") - (test-basic) + (test-store) (test-basic-mfind) (test-mfind) (test-message-full) diff --git a/scm/mu-scm.hh b/scm/mu-scm.hh index e16760c0..02a9cb9f 100644 --- a/scm/mu-scm.hh +++ b/scm/mu-scm.hh @@ -221,6 +221,13 @@ namespace Mu::Scm { return scm_from_utf8_stringn(val.data(), val.size()); else if constexpr (is_char_array_v|| std::is_same_v) return scm_from_utf8_string(val); + else if constexpr (std::is_same_v>) { + SCM lst{SCM_EOL}; + for (const auto& s: val) + lst = scm_append_x(scm_list_2(lst, + scm_list_1(to_scm(s)))); + return lst; + } else if constexpr (std::is_same_v) return scm_from_bool(val); else if constexpr (std::is_same_v) diff --git a/scm/mu-scm.scm b/scm/mu-scm.scm index 445921c6..8a4ae850 100644 --- a/scm/mu-scm.scm +++ b/scm/mu-scm.scm @@ -87,6 +87,7 @@ mfind mcount cfind + store->alist ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Other @@ -453,7 +454,8 @@ This is a list of objects." ;; the 'store-object' is a foreign object wrapping a const Store*. (define-class () - (store-object #:init-keyword #:store-object #:getter store-object)) + (store-object #:init-keyword #:store-object #:getter store-object) + (alist #:init-value #f)) ;; not exported (define-method (make-store store-object) @@ -464,6 +466,14 @@ This is a list of objects." ;; %default-store-object is defined in mu-scm-store.cc (make-store %default-store-object)) +(define* (store->alist #:key (store %default-store)) + "Get an alist-representation for some store. +Keyword arguments: + #:store %default-store. Leave at default." + (when (not (slot-ref store 'alist)) + (slot-set! store 'alist (cc-store-alist (store-object store)))) + (slot-ref store 'alist)) + (define* (mfind query #:key (store %default-store) @@ -472,7 +482,7 @@ This is a list of objects." (sort-field 'date) (reverse? #f) (max-results #f)) - "Find messages matching some query. + "Find messages matching some query. The query is mandatory, the other (keyword) arguments are optional. (mfind QUERY @@ -482,10 +492,10 @@ The query is mandatory, the other (keyword) arguments are optional. #:sort-field? field to sort by, a symbol. Default: date #:reverse? sort in descending order (z-a) #:max-results max. number of matches. Default: false (unlimited))." - (map (lambda (plist) - (make #:plist plist)) - (cc-store-mfind (store-object store) query - related? skip-dups? sort-field reverse? max-results))) + (map (lambda (plist) + (make #:plist plist)) + (cc-store-mfind (store-object store) query + related? skip-dups? sort-field reverse? max-results))) (define* (mcount #:key diff --git a/scm/mu-scm.texi b/scm/mu-scm.texi index 517cf82c..36e658f7 100644 --- a/scm/mu-scm.texi +++ b/scm/mu-scm.texi @@ -260,7 +260,7 @@ few key concepts, represented in some GOOP objects and other data-structures: @end itemize @menu -* Store:: the database of all information +* Store:: where message information lives * Message:: inspecting individual messages * Miscellaneous:: other functions * Helpers:: some helper functions @@ -352,6 +352,18 @@ Example usage: => 140728 @end lisp +@deffn {Scheme Procedure} store->alist +@end deffn +Retrieve an association list (``alist'') with information about the store. + +Example: +@lisp +(store->alist) +=> ((batch-size . 50000) (created . 1741180008) (max-message-size . 100000000) + (personal-addresses "djcb@@example.com" "msx@@example.com") + (root-maildir . "/home/user/Maildir") (schema-version . 500)) +@end lisp + @node Message @section Message