Package: guix-patches;
Reported by: Nils Landt <nils <at> landt.email>
Date: Sun, 15 Oct 2023 14:03:01 UTC
Severity: normal
Tags: patch
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Nils Landt <nils <at> landt.email> To: guix-patches <at> gnu.org Cc: Nils Landt <nils.landt <at> nlsoft.de> Subject: [PATCH] home: services: Add goimapnotify service. Date: Sun, 15 Oct 2023 16:01:18 +0200
From: Nils Landt <nils.landt <at> nlsoft.de> * gnu/home/services/mail.scm: (home-goimapnotify-configuration, home-goimapnotify-service-type, goimapnotify-account, goimapnotify-tls-options): New variables. (goimapnotify-format-field, goimapnotify-serialize-field, goimapnotify-serialize-goimapnotify-tls-options): New procedures. * doc/guix.texi (Mail Home Services): New node. --- This patch adds a home service for generating goimapnotify JSON configuration files. I was unable to get generate-documentation working with sub-documentation, so the configurations are documented separately. doc/guix.texi | 209 +++++++++++++++++++++++++++------ gnu/home/services/mail.scm | 234 ++++++++++++++++++++++++++++++++++++- 2 files changed, 406 insertions(+), 37 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 3517c95251..fba13d4a43 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -44703,25 +44703,162 @@ Sound Home Services @node Mail Home Services @subsection Mail Home Services - + The @code{(gnu home services mail)} module provides services that help you set up the tools to work with emails in your home environment. - + +@cindex goimapnotify +@uref{https://gitlab.com/shackra/goimapnotify, goimapnotify} watches your +mailbox(es) and executes a script on (new / deleted / updated) messages. + +Using @code{home-goimapnotify-configuration}, you can generate a config file +for each account you want to watch (file name relative to @code{$HOME}), e.g.: + +@lisp +(simple-service 'mail-imapnotify-config-examples + home-goimapnotify-service-type + (home-goimapnotify-configuration + (accounts (list + `(".config/goimapnotify/private-account.conf" + ,(goimapnotify-account + (host "imap.example.org") + (port 993) + (tls #t) + (username "example") + (password-cmd "pass my-private-email-account") + (on-new-mail + (file-append mbsync "/bin/mbsync private-account")) + (on-new-mail-post + (file-append mu "/bin/mu index")) + (boxes '("INBOX")))) + `(".config/goimapnotify/work-account.conf" + ,(goimapnotify-account + (host "imap.work.example.org") + (port 993) + (tls #t) + (username "example") + (password "12345") + (on-new-mail + (file-append mbsync "/bin/mbsync work-account")) + (on-new-mail-post + "notify-send 'New mail'") + (boxes '("INBOX" + "On Call"))))))))) +@end lisp + +Note: to utilize the config files, you need to start a separate goimapnotify +process for each one. Continuing the example above: +@code{goimapnotify -conf "$HOME/.config/goimapnotify/private-account.conf"} and +@code{goimapnotify -conf "$HOME/.config/goimapnotify/work-account.conf"}. + +@c %start of fragment +@deftp {Data Type} home-goimapnotify-configuration +Available @code{home-goimapnotify-configuration} fields are: + +@table @asis +@item @code{accounts} (default: @code{()}) (type: list-of-goimapnotify-accounts) +List of accounts that goimapnotify should watch. For each account, a +separate configuration file will be generated. +@end table + +@end deftp +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} goimapnotify-account +Available @code{goimapnotify-account} fields are: + +@table @asis +@item @code{host} (type: maybe-string) +Address of the IMAP server to connect to. + +@item @code{host-cmd} (type: maybe-string-or-file-like) +An executable or script that retrieves your host from somewhere, we +cannot pass arguments to this command from Stdin. + +@item @code{port} (type: maybe-integer) +Port of the IMAP server to connect to. + +@item @code{tls} (type: maybe-boolean) + +Use TLS? + +@item @code{tls-options} (type: maybe-goimapnotify-tls-options) +Option(s) for the TLS connection. Currently, only one option is +supported. + +@item @code{username} (type: maybe-string) +Username for authentication. + +@item @code{username-cmd} (type: maybe-string-or-file-like) +An executable or script that retrieves your username from +somewhere, we cannot pass arguments to this command from Stdin. + +@item @code{password} (type: maybe-string) +Password for authentication. + +@item @code{password-cmd} (type: + maybe-string-or-file-like) +An executable or script that retrieves your password from somewhere, we +cannot pass arguments to this command from Stdin. + +@item @code{xoauth2} +(type: maybe-boolean) +You can also use xoauth2 instead of password based authentication by +setting the xoauth2 option to true and the output of a tool which can +provide xoauth2 encoded tokens in passwordCmd. Examples: +@uref{https://github.com/google/oauth2l,Google oauth2l} or +@uref{https://github.com/harishkrupo/oauth2ms,xoauth2 fetcher for O36 +5}. + +@item @code{on-new-mail} (type: maybe-string-or-file-like) +An executable or script to run when new mail has arrived. + +@item @code{on-new-mail-post} (type: maybe-string-or-file-like) +An executable or script to run after onNewMail has ran. + +@item @code{wait} (type: maybe-integer) +The delay in seconds before the mail syncing is triggered. + +@item @code{boxes} (type: maybe-list-of-strings) +Mailboxes to watch. + +@end table + +@end deftp + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} goimapnotify-tls-options +Available @code{goimapnotify-tls-options} fields are: + +@table @asis +@item @code{reject-unauthorized} (type: maybe-boolean) +Skip verifying CA server identify? + +@end table + +@end deftp +@c %end of fragment + @cindex msmtp @uref{https://marlam.de/msmtp, MSMTP} is a @acronym{SMTP, Simple Mail Transfer Protocol} client. It sends mail to a predefined SMTP server that takes care of proper delivery. - + The service reference is given below. - + @defvar home-msmtp-service-type This is the service type for @command{msmtp}. Its value must be a @code{home-msmtp-configuration}, as shown below. It provides the @file{~/.config/msmtp/config} file. - + As an example, here is how you would configure @code{msmtp} for a single account: - + @lisp (service home-msmtp-service-type (home-msmtp-configuration @@ -44739,101 +44876,101 @@ Mail Home Services @end defvar @c %start of fragment - + @deftp {Data Type} home-msmtp-configuration Available @code{home-msmtp-configuration} fields are: - + @table @asis @item @code{defaults} (type: msmtp-configuration) The configuration that will be set as default for all accounts. - + @item @code{accounts} (default: @code{'()}) (type: list-of-msmtp-accounts) A list of @code{msmtp-account} records which contain information about all your accounts. - + @item @code{default-account} (type: maybe-string) Set the default account. - + @item @code{extra-content} (default: @code{""}) (type: string) Extra content appended as-is to the configuration file. Run @command{man msmtp} for more information about the configuration file format. - + @end table - + @end deftp - + @c %end of fragment - + @c %start of fragment - + @deftp {Data Type} msmtp-account Available @code{msmtp-account} fields are: - + @table @asis @item @code{name} (type: string) The unique name of the account. - + @item @code{configuration} (type: msmtp-configuration) The configuration for this given account. - + @end table - + @end deftp - + @c %end of fragment @c %start of fragment - + @deftp {Data Type} msmtp-configuration Available @code{msmtp-configuration} fields are: - + @table @asis @item @code{auth?} (type: maybe-boolean) Enable or disable authentication. - + @item @code{tls?} (type: maybe-boolean) Enable or disable TLS (also known as SSL) for secured connections. - + @item @code{tls-starttls?} (type: maybe-boolean) Choose the TLS variant: start TLS from within the session (‘on’, default), or tunnel the session through TLS (‘off’). - + @item @code{tls-trust-file} (type: maybe-string) Activate server certificate verification using a list of trusted Certification Authorities (CAs). - + @item @code{log-file} (type: maybe-string) Enable logging to the specified file. An empty argument disables logging. The file name ‘-’ directs the log information to standard output. - + @item @code{host} (type: maybe-string) The SMTP server to send the mail to. - + @item @code{port} (type: maybe-integer) The port that the SMTP server listens on. The default is 25 ("smtp"), unless TLS without STARTTLS is used, in which case it is 465 ("smtps"). - + @item @code{user} (type: maybe-string) Set the user name for authentication. - + @item @code{from} (type: maybe-string) Set the envelope-from address. - + @item @code{password-eval} (type: maybe-string) Set the password for authentication to the output (stdout) of the command cmd. - + @item @code{extra-content} (default: @code{""}) (type: string) Extra content appended as-is to the configuration block. Run @command{man msmtp} for more information about the configuration file format. - + @end table - + @end deftp - + @c %end of fragment @node Messaging Home Services diff --git a/gnu/home/services/mail.scm b/gnu/home/services/mail.scm index 5445c82c67..923867ca66 100644 --- a/gnu/home/services/mail.scm +++ b/gnu/home/services/mail.scm @@ -18,15 +18,44 @@ (define-module (gnu home services mail) #:use-module (guix gexp) + #:use-module (guix records) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu home services) #:use-module (gnu home services shepherd) + #:use-module (gnu home services utils) #:use-module (gnu packages mail) + #:use-module (gnu packages guile) + #:use-module (ice-9 match) #:use-module (ice-9 string-fun) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) - #:export (home-msmtp-configuration + #:export (home-goimapnotify-configuration + home-goimapnotify-configuration-fields + home-goimapnotify-configuration? + home-goimapnotify-configuration-accounts + home-goimapnotify-service-type + goimapnotify-account + goimapnotify-account-fields + goimapnotify-account-host + goimapnotify-account-host-cmd + goimapnotify-account-port + goimapnotify-account-tls + goimapnotify-account-tls-options + goimapnotify-account-username + goimapnotify-account-username-cmd + goimapnotify-account-password + goimapnotify-account-password-cmd + goimapnotify-account-xoauth2 + goimapnotify-account-on-new-mail + goimapnotify-account-on-new-mail-post + goimapnotify-account-wait + goimapnotify-account-boxes + goimapnotify-tls-options + goimapnotify-tls-options-fields + goimapnotify-tls-options-reject-unauthorized + + home-msmtp-configuration home-msmtp-configuration? home-msmtp-configuration-defaults home-msmtp-configuration-accounts @@ -220,3 +249,206 @@ (define home-msmtp-service-type (description "Configure msmtp, a simple @acronym{SMTP, Simple Mail Transfer Protocol} client that can relay email to SMTP servers."))) + +; Configuration for goimapnotify from (gnu packages mail) + +(define-maybe string) +(define-maybe integer) +(define-maybe boolean) +(define-maybe list-of-strings) +(define-maybe string-or-file-like) + +(define (string-or-file-like? value) + (or (string? value) + (file-like? value))) + +(define (goimapnotify-format-field field-name) + (object->camel-case-string field-name)) + +(define (goimapnotify-serialize-field field-name value) + "This is converted to JSON later, so we don't return a string here" + #~(#$(goimapnotify-format-field field-name) . #$value)) + +(define (goimapnotify-serialize-string-or-file-like field-name value) + (goimapnotify-serialize-string field-name value)) + +(define (goimapnotify-maybe-serialize field-name value serialization-function) + (if (maybe-value-set? value) + (serialization-function field-name value) + "")) + +(define (goimapnotify-serialize-maybe-string-or-file-like field-name value) + (goimapnotify-maybe-serialize field-name value + goimapnotify-serialize-string-or-file-like)) + +(define goimapnotify-serialize-string goimapnotify-serialize-field) +(define (goimapnotify-serialize-maybe-string field-name value) + (goimapnotify-maybe-serialize field-name value goimapnotify-serialize-string)) + +(define (goimapnotify-serialize-maybe-integer field-name value) + (goimapnotify-maybe-serialize field-name value goimapnotify-serialize-integer)) +(define goimapnotify-serialize-integer goimapnotify-serialize-field) + +(define (goimapnotify-serialize-maybe-boolean field-name value) + (goimapnotify-maybe-serialize field-name value goimapnotify-serialize-boolean)) +(define goimapnotify-serialize-boolean goimapnotify-serialize-field) + +(define (goimapnotify-serialize-maybe-list-of-strings field-name value) + (goimapnotify-maybe-serialize field-name value goimapnotify-serialize-list-of-strings)) +(define (goimapnotify-serialize-list-of-strings field-name value) + (goimapnotify-serialize-field field-name (list->array 1 value))) + +(define (goimapnotify-serialize-maybe-goimapnotify-tls-options field-name config) + (goimapnotify-maybe-serialize field-name config + goimapnotify-serialize-goimapnotify-tls-options)) + +(define (goimapnotify-serialize-goimapnotify-tls-options field-name config) + (goimapnotify-serialize-field + field-name + (prepare-configuration-for-json config goimapnotify-tls-options-fields))) + +(define (prepare-configuration-for-json config fields) + "Convert the configuration to the format expected by guile-json. + Unset maybe-values do not appear in the configuration file." + (filter + (lambda (val) + (not (unspecified? val))) + (map + (lambda (field) + (let ((value ((configuration-field-getter field) config))) + (if (maybe-value-set? value) + ((configuration-field-serializer field) + (configuration-field-name field) + value) + *unspecified*))) + fields))) + +(define-configuration goimapnotify-tls-options + (reject-unauthorized + (maybe-boolean) + "Skip verifying CA server identify?") + (prefix goimapnotify-)) + +(define-maybe goimapnotify-tls-options) + +; See https://gitlab.com/shackra/goimapnotify/-/blob/master/config.go?ref_type=heads#L46-62 +(define-configuration goimapnotify-account + (host + (maybe-string) + "Address of the IMAP server to connect to.") + (host-cmd + (maybe-string-or-file-like) + "An executable or script that retrieves your host from somewhere, + we cannot pass arguments to this command from Stdin.") + (port + (maybe-integer) + "Port of the IMAP server to connect to.") + (tls + (maybe-boolean) + "Use TLS?") + (tls-options + (maybe-goimapnotify-tls-options) + "Option(s) for the TLS connection. Currently, only one option is + supported.") + (username + (maybe-string) + "Username for authentication.") + (username-cmd + (maybe-string-or-file-like) + "An executable or script that retrieves your username from + somewhere, we cannot pass arguments to this command from Stdin.") + (password + (maybe-string) + "Password for authentication.") + (password-cmd + (maybe-string-or-file-like) + "An executable or script that retrieves your password from + somewhere, we cannot pass arguments to this command from Stdin.") + (xoauth2 + (maybe-boolean) + "You can also use xoauth2 instead of password based authentication + by setting the xoauth2 option to true and the output of a tool + which can provide xoauth2 encoded tokens in passwordCmd. + Examples: @url{https://github.com/google/oauth2l, Google oauth2l} + or + @url{https://github.com/harishkrupo/oauth2ms, xoauth2 fetcher for O365}.") + (on-new-mail + (maybe-string-or-file-like) + "An executable or script to run when new mail has arrived.") + (on-new-mail-post + (maybe-string-or-file-like) + "An executable or script to run after onNewMail has ran.") + (wait + (maybe-integer) + "The delay in seconds before the mail syncing is triggered.") + (boxes + (maybe-list-of-strings) + "Mailboxes to watch.") + (prefix goimapnotify-)) + +(define (list-of-goimapnotify-accounts? lst) + "List is in the form of '((file-name file-like))" + (every (lambda (element) + (match element + ((string ($ <goimapnotify-account>)) + #t) + (_ #f))) + lst)) + +(define-configuration/no-serialization home-goimapnotify-configuration + (accounts + (list-of-goimapnotify-accounts '()) + "List of accounts that goimapnotify should watch. + For each account, a separate configuration file + will be generated.")) + +(define (home-goimapnotify-extension old-config extensions) + (match-record old-config <home-goimapnotify-configuration> + (accounts) + (home-goimapnotify-configuration + (inherit old-config) + (accounts (append accounts + (append-map + home-goimapnotify-configuration-accounts + extensions)))))) + +(define (goimapnotify-files config) + (define* (account->json account-config-and-path) + (match + account-config-and-path + ((path account-config) + (let ((prepared-config + (prepare-configuration-for-json + account-config + goimapnotify-account-fields))) + `((,path + ,(computed-file + (string-append + "mail-imapnotify-config-" + (goimapnotify-account-host account-config)) + (with-extensions (list guile-json-4) + #~(begin + (use-modules (json builder)) + + (with-output-to-file #$output + (lambda () + (scm->json '(#$@prepared-config) + #:pretty #t)))))))))))) + + (match-record config <home-goimapnotify-configuration> + (accounts) + (append-map + (cut account->json <>) + accounts))) + +(define home-goimapnotify-service-type + (service-type (name 'home-goimapnotify-service) + (extensions + (list (service-extension + home-files-service-type + goimapnotify-files))) + (compose identity) + (extend home-goimapnotify-extension) + (default-value (home-goimapnotify-configuration)) + (description "Configure goimapnotify to execute scripts on IMAP + mailbox changes."))) base-commit: d2923babf3ac44cb6faa88317f77c98f3016820d -- 2.41.0
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.