summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk-Jan C. Binnema <djcb@djcbsoftware.nl>2025-08-26 21:29:18 +0300
committerDirk-Jan C. Binnema <djcb@djcbsoftware.nl>2025-08-26 21:31:57 +0300
commitb3c7cc269623ef92a9df9b3c3a4c024031c6ea86 (patch)
treecde32222152c2ba3ff59efc9631c28a13642496b
parent0221607f82c02e309a886fbddd86ed3a414cb9cd (diff)
scm: implement store personal?, rename all-labels->labels
Add a method personal? to check if some string looks like a personal address; add docs / tests as well. Rename the all-labels method into simply 'labels' Make some define* into define-method, for consistency.
-rw-r--r--scm/mu-scm-store.cc17
-rw-r--r--scm/mu-scm-test.scm3
-rw-r--r--scm/mu-scm.cc7
-rw-r--r--scm/mu-scm.scm72
-rw-r--r--scm/mu-scm.texi17
5 files changed, 82 insertions, 34 deletions
diff --git a/scm/mu-scm-store.cc b/scm/mu-scm-store.cc
index 928f93f..cf74eaf 100644
--- a/scm/mu-scm-store.cc
+++ b/scm/mu-scm-store.cc
@@ -177,6 +177,20 @@ subr_cc_store_mfind(SCM store_scm, SCM query_scm, SCM related_scm, SCM skip_dups
}
static SCM
+subr_cc_store_is_personal(SCM store_scm, SCM address_scm) try {
+
+ constexpr auto func{"cc-store-is-personal"};
+ const auto& store{to_store(store_scm, func, 1)};
+ const auto& address{from_scm<std::string>(address_scm, func, 2)};
+
+ return to_scm(store.contacts_cache().is_personal(address));
+
+} catch (const ScmError& err) {
+ err.throw_scm();
+}
+
+
+static SCM
subr_cc_store_all_labels(SCM store_scm) try {
constexpr auto func{"cc-store-all-labels"};
@@ -208,6 +222,8 @@ init_subrs()
reinterpret_cast<scm_t_subr>(subr_cc_store_cfind));
scm_c_define_gsubr("cc-store-alist", 1/*req*/, 0/*opt*/, 0/*rst*/,
reinterpret_cast<scm_t_subr>(subr_cc_store_alist));
+ scm_c_define_gsubr("cc-store-is-personal", 2/*req*/, 0/*opt*/, 0/*rst*/,
+ reinterpret_cast<scm_t_subr>(subr_cc_store_is_personal));
scm_c_define_gsubr("cc-store-all-labels", 1/*req*/, 0/*opt*/, 0/*rst*/,
reinterpret_cast<scm_t_subr>(subr_cc_store_all_labels));
#pragma GCC diagnostic pop
@@ -233,7 +249,6 @@ Mu::Scm::init_store(const Store& store)
initialized = true;
}
-
SCM
Mu::Scm::to_scm(const Contact& contact)
{
diff --git a/scm/mu-scm-test.scm b/scm/mu-scm-test.scm
index 23cd027..b9af156 100644
--- a/scm/mu-scm-test.scm
+++ b/scm/mu-scm-test.scm
@@ -10,6 +10,9 @@
(test-equal "cfind" 29 (length (cfind "")))
(test-equal "mfind" 19 (length (mfind "")))
+ (test-assert (personal? "user@example.com"))
+ (test-assert (not (personal? "user@anotherexample.com")))
+
(let ((info (store->alist)))
(test-equal 50000 (assoc-ref info 'batch-size))
(test-equal 100000000 (assoc-ref info 'max-message-size)))
diff --git a/scm/mu-scm.cc b/scm/mu-scm.cc
index 63cb404..ab162fb 100644
--- a/scm/mu-scm.cc
+++ b/scm/mu-scm.cc
@@ -290,7 +290,12 @@ test_scm_script()
::setenv("MU_TESTTEMPDIR", tempdir.path().c_str(), 1);
- auto store{Store::make_new(tempdir.path(), MuTestMaildir)};
+ MemDb mdb;
+ Config conf{mdb};
+; conf.set<Config::Id::PersonalAddresses>(
+ std::vector<std::string>{"user@example.com"});
+
+ auto store{Store::make_new(tempdir.path(), MuTestMaildir, conf)};
assert_valid_result(store);
{
diff --git a/scm/mu-scm.scm b/scm/mu-scm.scm
index 182a46b..a15ae90 100644
--- a/scm/mu-scm.scm
+++ b/scm/mu-scm.scm
@@ -91,7 +91,8 @@
mfind
mcount
cfind
- all-labels
+ labels
+ personal?
store->alist
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -118,7 +119,7 @@
(define (set-documentation! symbol docstring)
"Set the docstring for symbol in current module to docstring.
This is useful for symbols that do not support docstrings directly, such
-as (define foo 123)."
+as (define foo 123) and, apparently, define-method."
;; https://git.wolfsden.cz/guile-wolfsden/tree/wolfsden/documentation.scm
(set-object-property! (module-ref (current-module) symbol)
'documentation docstring))
@@ -199,13 +200,16 @@ CONTENT-ONLY? is implied to be #t."
(cc-mime-make-stream-port (cc-mimepart mime-part) content-only? decode?))
(define-method (filename (mime-part <mime-part>))
- "Determine the file-name for MIME-part.
-Either the 'filename' field in the mime-part and if that does not exist, use
-'mime-part-<index>' with <index> being the number of the mime-part."
(let ((alist (mime-part->alist mime-part)))
(or (assoc-ref alist 'filename)
(format #f "mime-part-~d" (assoc-ref alist 'index)))))
+(set-documentation! 'filename
+ "Determine the file-name for MIME-part.
+Either the 'filename' field in the mime-part and if that does not exist, use
+'mime-part-<index>' with <index> being the number of the mime-part.")
+
+
(define* (make-output-file mime-part #:key (path #f) (overwrite? #f))
"Create a port for the file to write MIME-PART to.
@@ -270,7 +274,7 @@ has the data, but when a message is loaded from file, either
through make-message or by calling a function that needs a
full message, such as header or body, the cc-message is initialized.")
-(define (make-message path)
+(define-method (make-message (path <string>))
"Create a <message> from file at PATH."
(make <message> #:cc-message (cc-message-make path)))
@@ -513,14 +517,16 @@ STORE-OBJ a 'foreign-object' for a mu Store pointer."
"Default store object.
This is defined in the C++ code, and represents a \"foreign\" Store* object.")
-(define* (store->alist #:key (store %default-store))
- "Get an alist-representation for some store.
-Keyword arguments:
- #:store %default-store. Leave at default."
+(define-method (store->alist (store <store>))
+ "Get an alist-representation for some STORE."
(when (not (slot-ref store 'alist))
(slot-set! store 'alist (cc-store-alist (cc-store store))))
(slot-ref store 'alist))
+(define-method (store->alist)
+ "Get an alist-representation from the default store."
+ (store->alist %default-store))
+
(define* (mfind query
#:key
(store %default-store)
@@ -539,17 +545,11 @@ 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 (data)
- (make <message> #:serialized data))
- (cc-store-mfind (cc-store store) query
- related? skip-dups? sort-field
- reverse? max-results)))
-
-(define* (mcount
- #:key
- (store %default-store))
- "Get the number of messages."
- (cc-store-mcount (cc-store store)))
+ (map (lambda (data)
+ (make <message> #:serialized data))
+ (cc-store-mfind (cc-store store) query
+ related? skip-dups? sort-field
+ reverse? max-results)))
(define* (cfind pattern
#:key
@@ -567,12 +567,34 @@ The pattern is mandatory; the other (keyword) arguments are optional.
#:max-results max. number of matches. Default: false (unlimited))."
(cc-store-cfind (cc-store store) pattern personal? after max-results))
-(define* (all-labels
- #:key
- (store %default-store))
- "Get the list of all labels in the store."
+(define-method (mcount (store <store>))
+ ;; "Get the number of messages in STORE."
+ (cc-store-mcount (cc-store store)))
+
+(define-method (mcount)
+ "Get the number of messages in the default store."
+ (mcount %default-store))
+
+(define-method (personal? (store <store>) (address <string>))
+ "Does the given email ADDRESS match the personal addresses in STORE?
+I.e., the personal addresses / regular expressions as specified during `mu
+init'."
+ (cc-store-is-personal (cc-store store) address))
+
+(define-method (personal? (address <string>))
+ "Does the given email ADDRESS match the personal addresses?
+I.e., the personal addresses / regular expressions as specified during `mu
+init'. Uses the default-store."
+ (personal? %default-store address))
+
+(define-method (labels (store <store>))
+ "Get the list of all labels in STORE."
(cc-store-all-labels (cc-store store)))
+(define-method (labels)
+ "Get the list of all labels in the default store."
+ (labels %default-store))
+
;;; Misc
;; Get an alist with the general options this instance of \"mu\" started with.
diff --git a/scm/mu-scm.texi b/scm/mu-scm.texi
index 57fe472..1b259e0 100644
--- a/scm/mu-scm.texi
+++ b/scm/mu-scm.texi
@@ -381,12 +381,15 @@ The store represents the @t{mu} database, i.e., the place where @t{mu index}
stores information about messages and contacts.
While you could theoretically have @emph{multiple} stores, for now @t{mu-scm}
-only supports a single one, which is the store you opened when you started
-@command{mu scm}. For completeness and possible future use, store-related
-methods do take a @t{#:store} parameter, but you can (in fact, @emph{must})
-leave it out, and use its default value.
+only supports a @emph{single} one, which is the store you opened when you
+started @command{mu scm}.
-Hence, in the API descriptions below, we leave out the @t{#:store} argument.
+For completeness and possible future use, store-related methods do take a
+@t{store} parameter or a @t{#:store} keyword parameter, but it can be left out
+for for now.
+
+Hence, for brevity, in the API descriptions below, the @t{store} parameter is
+implicit.
The store currently only exposes a few methods, described below.
@@ -472,7 +475,7 @@ Example:
(root-maildir . "/home/user/Maildir") (schema-version . 500))
@end lisp
-@deffn {Scheme Procedure} all-labels
+@deffn {Scheme Procedure} labels
@end deffn
Get the list of all labels present in the store, or @code{#f} if there are none.
Not to be confused with @code{labels} procedure for a @code{message} object.
@@ -811,7 +814,7 @@ For example:
@deffn {Scheme Procedure} labels message
@end deffn
Get the list of labels for this message, or @code{#f} if there are none.
-Not to be confused with the @code{all-labels} procedure for a Store.
+Not to be confused with the @code{labels} procedure for a Store.
For example:
@lisp