From patchwork Sun Oct 15 14:01:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Nils Landt X-Patchwork-Id: 54847 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 0A6E027BBE2; Sun, 15 Oct 2023 19:49:38 +0100 (BST) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 6233327BBE2 for ; Sun, 15 Oct 2023 19:49:34 +0100 (BST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qs6Aa-0008Vj-BH; Sun, 15 Oct 2023 14:48:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qs1hW-0000d0-1u for guix-patches@gnu.org; Sun, 15 Oct 2023 10:02:43 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qs1hV-0007f2-PM for guix-patches@gnu.org; Sun, 15 Oct 2023 10:02:37 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qs1ht-0004il-QY for guix-patches@gnu.org; Sun, 15 Oct 2023 10:03:01 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#66557] [PATCH] home: services: Add goimapnotify service. Resent-From: Nils Landt Original-Sender: "Debbugs-submit" Resent-CC: , guix-patches@gnu.org Resent-Date: Sun, 15 Oct 2023 14:03:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 66557 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 66557@debbugs.gnu.org Cc: Nils Landt , ( , Andrew Tropin , Ludovic =?utf-8?q?Court=C3=A8s?= X-Debbugs-Original-To: guix-patches@gnu.org X-Debbugs-Original-Xcc: ( , Andrew Tropin , Ludovic =?utf-8?q?Court=C3=A8s?= Received: via spool by submit@debbugs.gnu.org id=B.169737855718116 (code B ref -1); Sun, 15 Oct 2023 14:03:01 +0000 Received: (at submit) by debbugs.gnu.org; 15 Oct 2023 14:02:37 +0000 Received: from localhost ([127.0.0.1]:53862 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qs1hU-0004i7-Bt for submit@debbugs.gnu.org; Sun, 15 Oct 2023 10:02:37 -0400 Received: from lists.gnu.org ([2001:470:142::17]:51600) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qs1hP-0004hr-R9 for submit@debbugs.gnu.org; Sun, 15 Oct 2023 10:02:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qs1gv-0000TL-Uf for guix-patches@gnu.org; Sun, 15 Oct 2023 10:02:01 -0400 Received: from mout-p-202.mailbox.org ([80.241.56.172]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_CHACHA20_POLY1305:256) (Exim 4.90_1) (envelope-from ) id 1qs1ge-0007b7-7T for guix-patches@gnu.org; Sun, 15 Oct 2023 10:01:50 -0400 Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-202.mailbox.org (Postfix) with ESMTPS id 4S7hk90pr6z9sp7; Sun, 15 Oct 2023 16:01:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=landt.email; s=MBO0001; t=1697378497; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=P7igJAJFjkjc/e3BaAO1VNmsd+cYiDlPXeEaOTr6oCs=; b=G9NH3vc+VI1EoNPLA5h2qzcsSuOe3fre4DwzeN1i9nZX+kn6utc58xhF5DsxfmOSIm3k+Q 0/lyC54yjH7G6u49MmC3M3UKIYRqrNa8bueOjHLFcxJjJy8gow8/Pf1tifcSvFLtTPrmIN arnu3gfdn8z0hfIup07y6IQyQZCqVVew3L7ts6lY6lNeXl+3K34GE35S/mgKQmxSXU1dJL mvegeh3o0ya0ZYdXvhRZQjsR8lA375Ios1bhUre7mcLR+PKt27Tj64BQATSPPUkn+WWy8O 7ip5/LgAUHmmZ+8XcpgbzljfPuUpb/NP4LvtlbPpb4zE52gmSFpZfiiqbAndkQ== From: Nils Landt Date: Sun, 15 Oct 2023 16:01:18 +0200 Message-ID: MIME-Version: 1.0 X-MBO-RS-META: jmr8w6kn99tujj9tjbk3bu65sfh5csr4 X-MBO-RS-ID: 7f8937042144065bde5 X-Rspamd-Queue-Id: 4S7hk90pr6z9sp7 Received-SPF: pass client-ip=80.241.56.172; envelope-from=nils@landt.email; helo=mout-p-202.mailbox.org X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-Mailman-Approved-At: Sun, 15 Oct 2023 14:48:52 -0400 X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches From: Nils Landt * 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(-) base-commit: d2923babf3ac44cb6faa88317f77c98f3016820d -- 2.41.0 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 ($ )) + #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 + (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 + (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.")))