From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id cJ7gC4D3qWOxyQAAbAwnHQ (envelope-from ) for ; Mon, 26 Dec 2022 20:35:28 +0100 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id mBrnC4D3qWOn/gAA9RJhRA (envelope-from ) for ; Mon, 26 Dec 2022 20:35:28 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 7000938ED9 for ; Mon, 26 Dec 2022 20:35:27 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p9tFb-00012t-Nh; Mon, 26 Dec 2022 14:35:07 -0500 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 1p9tFX-00012W-6F for guix-patches@gnu.org; Mon, 26 Dec 2022 14:35:04 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p9tFW-0002JF-Lx for guix-patches@gnu.org; Mon, 26 Dec 2022 14:35:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1p9tFW-00088o-6g for guix-patches@gnu.org; Mon, 26 Dec 2022 14:35:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#56046] [PATCH opensmtpd-records v3] services (opensmtpd): add opensmtpd records to enhance opensmtpd-configuration. Resent-From: Liliana Marie Prikler Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 26 Dec 2022 19:35:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 56046 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Joshua Branson , 56046@debbugs.gnu.org Cc: Joshua Branson Received: via spool by 56046-submit@debbugs.gnu.org id=B56046.167208330131284 (code B ref 56046); Mon, 26 Dec 2022 19:35:02 +0000 Received: (at 56046) by debbugs.gnu.org; 26 Dec 2022 19:35:01 +0000 Received: from localhost ([127.0.0.1]:54129 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p9tFR-00088T-RS for submit@debbugs.gnu.org; Mon, 26 Dec 2022 14:35:01 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:35733) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p9tFN-00088C-20 for 56046@debbugs.gnu.org; Mon, 26 Dec 2022 14:34:56 -0500 Received: by mail-wm1-f65.google.com with SMTP id m8-20020a05600c3b0800b003d96f801c48so5576657wms.0 for <56046@debbugs.gnu.org>; Mon, 26 Dec 2022 11:34:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject :date:message-id:reply-to; bh=DH0uGBkVsQH/eD6sIv4g13Jybt+/1AdDUWlfScwaWpE=; b=h7qhWGPdCO/u29qMGL86AubeBykdbmQUfAWQNP4Fe4sXhvuwzvY9yc0xUoKPcHJ0gg IsSV9MbwRNG7wkL9kHSKGZlOKeIv9MXHSPn1KDDjvL+AkNQvgnOtTGGg8NLobdz3q2TG JnK0TI4fg7AarDP8263SeXt0ZfgBmTNTQtaMkR761kbJu5rYJYcyMPYwBSqc3Bc6l/g4 SD1EDjOqZxVnhqZ0dun7uP2U5uDebAL+syRmxiL+5/MSHZLdlcoVLVY4JeFu3Hz/HEwD H0bPOpYdNAB9rtP8BTGzltD69qP/22I5wf9VkSM2I1PgSwc9uqaWjlDDXNRBuX4ehZrN oLqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=DH0uGBkVsQH/eD6sIv4g13Jybt+/1AdDUWlfScwaWpE=; b=nR1C5Ix0sM0URtMwPVQ9wbMBjfPfrGoTHUrw31os4Ein3rJjC2LFuHvaC1p5lF0Huy XLSPLWXLPfnyktTP83xly6e2xH+nRMFxKzSKGpCtLAH6NTpH8O2QSaLNRYiI+J8fT9am 1Ope9rIkcmtAIm10s3fN2DL38HzNWYQtNjd3khYRejrg0LpKfRHLq6L/qXVnmIq/XCoo +8TBXME9Ddz8QLMjzZnsN0VwDTPAy3auK8ij+v0OF6qbM5HNKOmvAEUdDl32F4Ox5jo6 I2H9v3d1sog5VEtWKMn2uz4/8cE4gzHfVptgVI1prOnc6wDBLzA91UjuBDWlaAVcQovz slKA== X-Gm-Message-State: AFqh2kq4VOze60l1hgAcYaPtRBWRKrVK8PBeePcXAZnx2B09hTHqbj22 WjZtKZwx0zFFK16dk1qU2cA= X-Google-Smtp-Source: AMrXdXtGyrB3K+cYeHg98skf1T2t9hQe3SHU98n8wDnawZKDVkr27Z+Fw88Rpqp0G3PenCXBLLjqjA== X-Received: by 2002:a05:600c:3b90:b0:3d1:f0f1:ceb4 with SMTP id n16-20020a05600c3b9000b003d1f0f1ceb4mr13693938wms.19.1672083286153; Mon, 26 Dec 2022 11:34:46 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id d22-20020a1c7316000000b003d9862ec435sm2286156wmb.20.2022.12.26.11.34.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 11:34:45 -0800 (PST) Message-ID: <37239abae388f1fadcba559b62c0aae07de9d319.camel@gmail.com> From: Liliana Marie Prikler Date: Mon, 26 Dec 2022 20:34:43 +0100 In-Reply-To: <8001f404c0e54baba71ef9c5536abc54275c4167.1671803496.git.joshua@gnucode.me> References: <8001f404c0e54baba71ef9c5536abc54275c4167.1671803496.git.joshua@gnucode.me> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1672083327; a=rsa-sha256; cv=none; b=XH0j6CIhdTp5QwMhJfc68S/SL9wUlSFVeO63y8F5TDIExPjKvV0moKbYo+3BiaMVgjIDsa aUvOocM7FyQoq1VRO0+z+OxpgRHpQ2RXiW+IXNBr/0VbdvT5tR3XSrJJDNx3a6gbAsMkhA HI12YfB+slehhFWtpxbSJ5sA99LkLWuFdhBY4m1DU+WTge0MVtqgQ4A3Pc3huzZovWyY+f 1boJulrzbS3BGxmaAjoFVJ3wY2Ybe3aRBdO8WtOOcgI+dmxMAoubctV2OiDG29C9+sY0bK 1ulVTRvU8wlYvhECiAYEX/V2XQ2PcZ6/61uC1lXDM+XxF9kok9Vf/+XyzUGTTg== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=gmail.com header.s=20210112 header.b=h7qhWGPd; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1672083327; h=from:from:sender:sender: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:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=DH0uGBkVsQH/eD6sIv4g13Jybt+/1AdDUWlfScwaWpE=; b=BxdGQUv5rs4vYVO7Kqiy/5CtG2H212w+vQKG0Ea/vK8ZmXizv29RLVRLoVRlAmzjkyHhuD nMzQaghKmTEx1qO8+LTy62dfaZsc2Ue/3JnA7HBIQ4qo4vJI1QTKdLlUS4QEfwd2eShORm cwrGFfb/kq8O50bO4FJbksGplIkRIAsG6IlZcV6h1lF8U8Y03vOoVY+GsmF0Jousl6OeFW FEMUrjTp7D2ugmKkSZW4vR2neVztBvrE5wJjpoadpCuC+mgXXDrmFhe2m1PwEI1vTptaaX EcKCTzE+Px7WVCemlAa7AyosyAk8Q8YoH38nft9vgTD4v6sslH1095uVXq80kA== X-Spam-Score: -1.43 X-Migadu-Queue-Id: 7000938ED9 Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=gmail.com header.s=20210112 header.b=h7qhWGPd; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none) X-Migadu-Scanner: scn0.migadu.com X-Migadu-Spam-Score: -1.43 X-TUID: tQETMhrZp6Ad Am Freitag, dem 23.12.2022 um 08:52 -0500 schrieb Joshua Branson: >=20 > * gnu/services/mail.scm: > (opensmtpd-table, > opensmtpd-ca, > opensmtpd-pki, > opensmtpd-action-local-delivery, > opensmtpd-maildir, > opensmtpd-mda, > opensmtpd-lmtp, > opensmtpd-relay, > opensmtpd-option, > opensmtpd-filter-phase, > opensmtpd-filter, > opensmtpd-interface, > opensmtpd-socket, > opensmtpd-match, > opensmtpd-smtp, > opensmtpd-srs, > opensmtpd-queue, and > opensmtpd-configuration): New records. Don't forget to put closing parentheses at the end of lines. Also, feel free to group them to save vertical space. > (false?, is-value-right-type, add-comma-or-string, > list-of-procedures->string, string-in-list?, my-sanitize, > opensmtpd-filter-chain?, throw-error-duplicate-option, > sanitize-list-of-options-for-match, sanitize-filters, > list-has-duplicates-or-non-filters?, > filter-phase-has-message-and-value?, > filter-phase-decision-lacks-proper-message?, > filter-phase-lacks-proper-value?, > filter-phase-has-incorrect-junk-or-bypass?, > filter-phase-junks-after-commit?, > list-of-unique-filter-or-filter-phase?, throw-error, > contains-duplicate?, list-of-type?, list-of-strings?, > list-of-unique-opensmtpd-option?, > list-of-opensmtpd-ca?, > list-of-opensmtpd-pki?, > list-of-opensmtpd-listen-on?, > list-of-unique-opensmtpd-match?, list-of-strings->string, > assoc-list? assoc-list, variable->string, > tables-data-are-assoc-list?, > tables-data-are-a-list-of-strings?, > table-data-are-a-nested-list-of-strings?, > assoc-list->string, > opensmtpd-table->string, > opensmtpd-listen-on->string, > opensmtpd-listen-on-socket->string, > opensmtpd-action-relay->string, > opensmtpd-lmtp->string, > opensmtpd-mda->string, > opensmtpd-maildir->string, > opensmtpd-action-local-delivery->string, > opensmtpd-action->string, opensmtpd-option->string, > opensmtpd-match->string, > opensmtpd-ca->string, opensmtpd-pki->string, > generate-filter-chain-name, opensmtpd-filter-chain->string, > opensmtpd-filter-phase->string, opensmtpd-filters->string, > opensmtpd-listen->string, > opensmtpd-srs->string, > opensmtpd-smtp->string, > opensmtpd-queue->string, get-opensmtpd-actions, > get-opensmtpd-pkis, get-opensmtpd-filters, flatten, > get-opensmtpd-tables, opensmtpd-fieldname->string, > list-of-records->string, opensmtpd->mixed-text-file): New > procedures. >=20 > * gnu/tests/mail.scm : new tests for various opensmtpd records. >=20 > * doc/guix.texi (OpenSMTPD Service): Added documentation for the > new records for opensmtpd. > --- > =C2=A0doc/guix.texi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 106= 5 ++++++++++++++++- > =C2=A0gnu/services/mail.scm | 2560 > ++++++++++++++++++++++++++++++++++++++++- > =C2=A0gnu/tests/mail.scm=C2=A0=C2=A0=C2=A0 |=C2=A0 713 ++++++++++++ > =C2=A03 files changed, 4310 insertions(+), 28 deletions(-) >=20 > diff --git a/doc/guix.texi b/doc/guix.texi > index 535c8cdfc3..879a2ad233 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -25407,16 +25407,66 @@ could instantiate a dovecot service like > this: > =C2=A0@end lisp > =C2=A0 > =C2=A0@subsubheading OpenSMTPD Service > +@cindex opensmtpd > =C2=A0 > =C2=A0@deffn {Scheme Variable} opensmtpd-service-type > -This is the type of the @uref{https://www.opensmtpd.org, OpenSMTPD} > -service, whose value should be an @code{opensmtpd-configuration} > object > -as in this example: > +OpenSMTPD is an easy-to-use mail transfer agent (MTA).=C2=A0 OpenSMTPD > +@strong{listens} for incoming mail and @strong{matches} the mail to > +@strong{actions}. The following records represent those stages: > =C2=A0 > -@lisp > -(service opensmtpd-service-type > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-configuratio= n > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (config-fil= e (local-file "./my-smtpd.conf")))) > +@multitable {aaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} I hope this will receive proper documentation. > +@item @strong{listens} > +@tab @code{} > +@item > +@tab @code{} > +@item > +@tab > +@item @strong{matches} > +@tab @code{} > +@item > +@tab > +@item @strong{actions} > +@tab @code{} > +@item > +@tab @code{} > +@end multitable > + > +Additionally, each @code{} and > +@code{} may use a list of @code{ filter>}, > +and/or @code{} records to filter > +email/spam. Also numerous records' fieldnames use > +@code{} records to hold lists or key value pairs of > +data.=C2=A0 Be sure to read the @code{} section to lear= n > the > +differance between a @code{mapping table} and a @code{list table}. > + > +Finally, both @code{} and > +@code{} use @code{} to > +configure various options. > + > +A simple example opensmtpd configuration is below: > + > +@lisp > +(let ((smtp.gnu.org (opensmtpd-pki > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (domain = "smtp.gnu.org") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cert "f= ile.cert") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (key "fi= le.key")))) > +=C2=A0 (service opensmtpd-service-type > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-= configuration > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (inte= rfaces (list > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (o= pensmtpd-interface > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (pki smtp.gnu.org)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (o= pensmtpd-interface > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (pki smtp.gnu.org) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (secure-connection "smtps")))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (matc= hes (list > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-match > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmt= pd-local-delivery > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (n= ame "local-delivery")))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-match > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmt= pd-relay > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (n= ame "relay"))))))))) > =C2=A0@end lisp > =C2=A0@end deffn > =C2=A0 > @@ -25425,7 +25475,7 @@ Data type representing the configuration of > opensmtpd. > =C2=A0 > =C2=A0@table @asis > =C2=A0@item @code{package} (default: @var{opensmtpd}) > -Package object of the OpenSMTPD SMTP server. > +Package object of the OpenSMTPD server. > =C2=A0 > =C2=A0@item @code{config-file} (default: @code{%default-opensmtpd-config- > file}) > =C2=A0File-like object of the OpenSMTPD configuration file to use.=C2=A0 = By > default > @@ -25433,14 +25483,1013 @@ it listens on the loopback network > interface, and allows for mail from > =C2=A0users and daemons on the local machine, as well as permitting email > to > =C2=A0remote servers.=C2=A0 Run @command{man smtpd.conf} for more informa= tion. > =C2=A0 > +@item @code{bounce} (default: @code{(list "4h")}) > +@code{bounce} is a list of strings, which send warning messages to > the > +envelope sender when temporary delivery failures cause a message to > +remain in the queue for longer than a specified delay. Each delay > option > +is a string parameter beginning with a positive decimal integer and > a > +unit, which can be 's', 'm', 'h', or 'd'. At most four delay > parameters > +can be specified. > + > +@item @code{interfaces} default: > +@lisp > +(list > +=C2=A0 (opensmtpd-interface > +=C2=A0=C2=A0=C2=A0 (interface "lo") > +=C2=A0=C2=A0=C2=A0 (port 25))) > +@end lisp > +@code{interfaces} is a list of @code{} records. > +This list details what interfaces and ports OpenSMTPD listens on as > well as > +other options. > + > +@item @code{socket} (default: @code{(opensmtpd-socket)}) > +Listens for incoming connections on the Unix domain socket. > + > +@item @code{includes} (default: @code{#f}) > +@code{includes} is a list of string filenames. Each filename's > contents is > +additional configuration that is inserted into the top of the > configuration > +file.=C2=A0 Run @code{man smtpd.conf} for more information. > + > +@item @code{matches} default: > +@lisp > +(list (opensmtpd-match > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action (opensmtpd-local-delivery > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 (name "local") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 (method "mbox") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 (options > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (list > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for local"))))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-match > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (action (opensmtpd-relay > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 (name "outbound"))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (options > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (list > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "from loc= al")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for any"= )))))) > +@end lisp > +@code{matches} is a list of @code{} records, which > +matches incoming mail and sends it to a correspending action. The > match > +records are evaluated sequentially, with the first match winning. > +Therefore @emph{the order that you arrange your matches is > important}. > +It's a good idea to put specific matches first and an all > emcompassing > +match (like @code{(option "for any")}) @strong{last}. If an incoming > +mail does not match any match records, then it is rejected. > + > +@item @code{mta-max-deferred} (default: @code{100}) > +When delivery to a given host is suspended due to temporary > failures, cache > +at most number envelopes for that host such that they can be > delivered as > +soon as another delivery succeeds to that host. The default is 100. > + > +@item @code{queue} (default: @code{#f}) > +@code{queue} expects an @code{} record. With it, > one may > +compress and encrypt queue-ed emails as well as set the default > expiration > +time for temporarily undeliverable messages. > + > +@item @code{smtp} (default: @code{#f}) > +@code{smtp} expects an @code{} record, which lets > one > +specifiy how large email may be along with other settings. > + > +@item @code{srs} (default: @code{#f}) > +@code{srs} expects an @code{} record, which lets one > set > +up SRS, the Sender Rewritting Scheme. > + > =C2=A0@item @code{setgid-commands?} (default: @code{#t}) > =C2=A0Make the following commands setgid to @code{smtpq} so they can be > =C2=A0executed: @command{smtpctl}, @command{sendmail}, @command{send- > mail}, > =C2=A0@command{makemap}, @command{mailq}, and @command{newaliases}. > =C2=A0@xref{Setuid Programs}, for more information on setgid programs. > + > =C2=A0@end table > =C2=A0@end deftp > =C2=A0 > +@itemize > +@item Data Type: opensmtpd-interface > +Data type representing the configuration of an > +@code{}. It listens on the fieldname > +@code{interface} for incoming connections, using the same syntax as > +@code{ifconfig}. The interface parameter may also be an string > interface > +group, an string IP address, or a string domain name. Listening can > +optionally be restricted to a specific address via the fieldname > +@code{family}, which can be either @code{"inet4"} or @code{"inet6"}. > + > +@itemize > +@item @code{interface} (default: @code{"lo"}) > + > +The string interface to listen for incoming connections.=C2=A0 This > string > +may be an interface group, an IP address, or a domain name. These > +interfaces can usually be found by the command @code{ip link}. > + > +@item @code{family} (default: @code{#f}) > + > +Only listen on a specific address family.=C2=A0 Valid strings are > +@code{"inet4"} or @code{"inet6"}, which will only listen on IPv4 or > IPv6 > +respectfully.=C2=A0 If @code{(family #f)}, then opensmtpd will listen on > both > +IPv4 and IPv6. > + > +@item @code{auth} (default: @code{#f}) > +Support SMTPAUTH: clients may only start SMTP transactions after > +successful authentication. If @code{auth} is @code{#t}, then users > are > +authenticated against their own normal login credentials. > Alternatively > +@code{auth} may be a @code{mapping table} that maps usernames to > +encrypted passwords.=C2=A0 The password can be encrypted via the > +@code{smtpctl} @code{encrypt} subcommand. > + > +@item @code{auth-optional} (default: @code{#f}) > +Support SMTPAUTH optionally: clients need not authenticate, but may > do > +so.=C2=A0 This allows the @code{} to both accept > +incoming mail from untrusted senders and permit outgoing mail from > +authenticated users. It can be used in situations where it is not > +possible to listen on a separate port (usually the submission port, > 587) > +for users to authenticate.=C2=A0 This option also accepts a @code{mappin= g > +table} that maps usernames to encrypted passwords. > + > +@item @code{filters} (default: @code{#f}) > +A list of one or many @code{} or > +@code{} records. The filters are applied > +sequentially. These records listen and filter on connections handled > by this > +listener. > + > +@item @code{hostname} (default: @code{#f}) > +Change the default server name in the greeting banner instead of the > +default one. > + > +@item @code{hostnames} (default: @code{#f}) > +Override the server name for specific addresses. Use a @code{mapping > +table} that maps string IP addresses to string hostnames. If the > address > +on which the connection arrives appears in the mapping, the > associated > +hostname is used. > + > +@item @code{mask-src} (default: @code{#f}) > +If @code{#t}, then omit the from part when prepending =E2=80=9CReceived= =E2=80=9D > headers. > + > +@item @code{disable-dsn} (default: @code{#f}) > +When @code{#t}, then disable the DSN (Delivery Status Notification) > extension. > + > +@item @code{pki} (default: @code{#f}) > +For secure connections, use an @code{} record to > prove a > +mail server's identity. > + > +@item @code{port} (default: @code{25}) > +Listen on the integer port instead of the default port of 25. > + > +@item @code{proxy-v2} (default: @code{#f}) > +If @code{#t}, then support the PROXYv2 protocol, rewriting > appropriately source > +address received from proxy. > + > +@item @code{received-auth} (default: @code{#f}) > +If @code{#t}, then in =E2=80=9CReceived=E2=80=9D headers, report whether= the session > was > +authenticated and by which local user. > + > +@item @code{senders} (default: @code{#f}) > +Look up the authenticated user in the supplied @code{mapping table} > to > +find the email addresses that user is allowed to submit mail as. > + > +@item @code{masquerade} (default: @code{#f}) > +@code{masquerade}, is used in conjunction with @code{senders}.=C2=A0 If > +@code{#t}, then the From header is rewritten to match the sender > +provided in the SMTP session.=C2=A0 If @code{senders} is @code{#false}, > then > +@code{masquerade} cannot be @code{#t}. > + > +@item @code{secure-connection} (default: @code{#f}) > +This is a string of one of these options: > + > +@multitable {aaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} Same here > +@item @code{"smtps"} > +@tab Support SMTPS, by default on port 465. > +@item @code{"tls"} > +@tab Support STARTTLS, by default on port 25. > +@item @code{"tls-require"} > +@tab Like @code{"tls"}, but force clients to > +@item > +@tab establish a secure connection before being > +@item > +@tab allowed to start an SMTP transaction. > +@item @code{"tls-require-verify"} > +@tab Like @code{"tls-require"}, but clients must > +@item > +@tab also provide a valid certificate > +@item > +@tab to establish an SMTP session. > +@end multitable > + > +@item @code{tag} (default: @code{#f}) > +Clients connecting to the listener are tagged with the given string > tag. > +@end itemize > + > +@item Data Type: opensmtpd-socket > +Data type representing the configuration of an > +@code{}. Listen for incoming SMTP connections on > the > +Unix domain socket @samp{/var/run/smtpd.sock}. This is done by > default, > +even if the record is absent. > + > +@itemize > +@item @code{filters} (default: @code{#f}) > +A list of one or many @code{} or > +@code{} records. These filter incoming > +connections handled by this listener. > + > +@item @code{mask-src} (default: @code{#f}) > +If @code{#t}, then omit the from part when prepending =E2=80=9CReceived= =E2=80=9D > headers. > + > +@item @code{tag} (default: @code{#f}) > +Clients connecting to the listener are tagged with the given string > tag. > +@end itemize > + > +@item Data Type: opensmtpd-match > +@cindex opensmtpd-match > +This data type represents the configuration of an > +@code{} record. > + > +If at least one mail envelope matches the options of one match > record, > +receive the incoming message, put a copy into each matching > envelope, > +and atomically save the envelopes to the mail spool for later > processing > +by the respective @code{} found in fieldname > +@code{action}.=C2=A0 Here is an example @code{opensmtpd-match} > +record. > + > +@lisp > +(opensmtpd-match > + (action (opensmtpd-local-delivery > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "receive") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (method (opensmtp= d-maildir > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (pathname "/home/%@{rcpt.user@}/Maildi= r") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (junk #t))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (virtual (opensmt= pd-table > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "virt") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data '(("carmen" . "carmen@@gnu= .org"))))))) > + (options (list (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (option "from any")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (option "for domain") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (data (opensmtpd-table > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "d= omain-table") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data (l= ist "gnu.org" "fsf.org")))))))) > +@end lisp > + > +@itemize > +@item @code{action} (default: @code{#f}) > + > +If mail matches this match configuration, then do this action. Valid > values > +include @code{} or > +@code{}. > + > +@item @code{options} (default: @code{#f}) > +The fieldname @code{option} is a list of unique > +@code{} records. > + > +There are some mutually exclusive options: there can be only one > ``for'' > +and only one ``from'' option. > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} and here. > +@headitem for > +@tab from > +@item only use one of the following: > +@tab only use one of the following: > +@item @code{"for any"} > +@tab @code{"from any"} > +@item @code{"for local"} > +@tab @code{"from auth"} > +@item @code{"for domain"} > +@tab @code{"from local"} > +@item @code{"for rcpt-to"} > +@tab @code{"from mail-from"} > +@item > +@tab @code{"from socket"} > +@item > +@tab @code{"from src"} > +@end multitable > + > +Additionally, some options require additional data via > +@code{}'s fieldname @code{data}.=C2=A0 The following > list > +will explain the below syntax. > + > +@itemize > +@item @code{"for any"} > +This option only requires fieldname @code{option} to have the string > +@code{"for any"}: > + > +@lisp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for any")) > +@end lisp > + > +@item @code{"tag"} _tag_ > +This option only requires fieldname @code{option} to have the string > +@code{"tag"} with a string in fieldname @code{data}: > + > +@lisp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "tag") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data "this-tag")) > +@end lisp > + > +@item @code{"for rcpt"} _domain_ | > +This option requires fieldname @code{data} to have a string domain > or > +@code{list table}: > + > +@lisp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for rcpt") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data "gnu.org")) > +@end lisp > + > +OR > + > +@lisp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (opensmtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (option "for rcpt") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (data (list "gnu.org" "fsf.org"))) > +@end lisp > +@end itemize > + > +The following matching options are supported and can all be negated > (via not > +#t). The options that support a table (anything surrounded with '<' > and '>' > +eg: ), also support specifying regex via (regex #t). > + > +@itemize > +@item @code{"for any"} > +Specify that session may address any destination. > + > +@item @code{"for local"} > +Specify that session may address any local domain.=C2=A0 This is the > default, > +and may be omitted. > + > +@item @code{"for domain"} _domain_ | > +Specify that session may address the string _domain_ or > +@code{list table} . > + > +@item @code{"for rcpt-to"} _recipient_ | > +Specify that session may address the string _recipient_ or list > table > +. > + > +@item @code{"from any"} > +Specify that session may originate from any source. > + > +@item @code{"from auth"} > +Specify that session may originate from any authenticated user, no > matter > +the source IP address. > + > +@item @code{"from auth"} _user_ | > +Specify that the session may originate from authenticated _user_ or > +@code{list table} , no matter the source IP address. > + > +@item @code{"from local"} > +Specify that session may only originate from a local IP address, or > from > +the local enqueuer.=C2=A0 This is the default, and may be omitted. > + > +@item @code{"from mail-from"} _sender_ | > +Specify that session may originate from _sender_ or @code{list > table} > +, no matter the source IP address. > + > +@item @code{"from rdns"} > +Specify that session may only originate from an IP address that > resolves > +to a reverse DNS@. > + > +@item @samp{"from rdns"} _hostname_ | > +Specify that session may only originate from an IP address that > resolves > +to a reverse DNS matching string _hostname_ or @code{list table} > +. > + > +@item @samp{"from socket"} > +Specify that session may only originate from the local enqueuer. > + > +@item @code{"from src"} _address_ |
> +Specify that session may only originate from string _address_ or > +@code{list table}
which can be a specific address or a > subnet > +expressed in CIDR-notation. > + > +@item @code{"auth"} > +Matches transactions which have been authenticated. > + > +@item @code{"auth"} _username_ | > +Matches transactions which have been authenticated for string _user_ > or > +@code{list table} . > + > +@item @code{"helo"} _helo-name_ | > +Specify that session's HELO / EHLO should match the string _helo- > name_ > +or @code{list table} . > + > +@item @code{"mail-from"} _sender_ | > +Specify that transactions's MAIL FROM should match the string > _sender_ > +or @code{list table} . > + > +@item @code{"rcpt-to"} _recipient_ | > +Specify that transaction's RCPT TO should match the string > _recipient_ > +or @code{list table} . > + > +@item @code{"tag"} _tag_ > +Matches transactions tagged with the given tag. > + > +@item @code{"tls"} > +Specify that transaction should take place in a TLS channel. > +@end itemize > + > +@end itemize > + > +@item Data Type: opensmtpd-local-delivery > +This data type represents the configuration of an > +@code{} record. > + > +@itemize > +@item @code{name} (default: @code{#f}) > +@code{name} is the string name of the relay action. > + > +@item @code{method} (default: @code{"mbox"}) > +The email delivery option.=C2=A0 Valid options are: > + > +@itemize > +@item @code{"mbox"} > +Deliver the message to the user's mbox with mail.local(8). > + > +@item @code{"expand-only"} > +Only accept the message if a delivery method was specified in an > aliases > +or .forward file. > + > +@item @code{"forward-only"} > +Only accept the message if the recipient results in a remote address > after > +the processing of aliases or forward file. > + > +@item @code{} > +Deliver the message to an LMTP server at @code{}'s > +fieldname @code{destination}. The location may be expressed as > string > +host:port or as a UNIX socket. Optionally, @code{}'s > +fieldname @code{rcpt-to} might be specified to use the recipient > email > +address (after expansion) instead of the local user in the LMTP > session > +as RCPT TO. > + > +@item @code{} > +Deliver the message to the maildir in > +@code{}'s fieldname @code{pathname} if specified, > +or by default to @code{"~/Maildir"}. > + > +The pathname may contain format specifiers that are expanded before > use > +(see the below section about Format Specifiers). > + > +If @code{}'s record fieldname @code{junk} is > @code{#t}, > +then message will be moved to the =E2=80=98Junk=E2=80=99 folder if it co= ntains a > positive > +=E2=80=98X-Spam=E2=80=99 header. This folder will be created under field= name > @code{pathname} if > +it does not yet exist. > + > +@item @code{} > +Delegate the delivery to the @code{}'s fieldname > +@code{command} (type string) that receives the message on its > standard input. > + > +The @code{command} may contain format specifiers that are expanded > before use > +(see Format Specifiers). > +@end itemize > + > +@item @code{alias} (default: @code{#f}) > +Use the @code{mapping table} for aliases expansion. > + > +@item @code{ttl} (default: @code{#f}) > +@code{ttl} is a string specify how long a message may remain in the > queue.=C2=A0 It's > +format is @code{n@{s|m|h|d@}}.=C2=A0 eg: @code{"4m"} is four minutes. > + > +@item @code{user} (default: @code{#f} ) > +@code{user} is the string username for performing the delivery, to > be looked up > +with getpwnam(3). > + > +This is used for virtual hosting where a single username is in > charge of > +handling delivery for all virtual users. > + > +This option is not usable with the mbox delivery method. > + > +@item @code{userbase} (default: @code{#f}) > +@code{userbase} is an @code{} record for mapping > user > +lookups instead of the getpwnam(3) function. > + > +The fieldnames @code{user} and @code{userbase} are mutually > exclusive. > + > +@item @code{virtual} (default: @code{#f}) > +@code{virtual} is an @code{} record is used for > virtual > +expansion. > +@end itemize > + > +@item Data Type: opensmtpd-relay > +This data type represents the configuration of an > +@code{} record. > + > +@itemize > +@item @code{name} (default: @code{#f}) > +@code{name} is the string name of the relay action. > + > +@item @code{backup} (default: @code{#f}) > +When @code{#t}, operate as a backup mail exchanger delivering > messages to any > +mail exchanger with higher priority. > + > +@item @code{backup-mx} (default: @code{#f}) > +Operate as a backup mail exchanger delivering messages to any mail > exchanger > +with higher priority than mail exchanger identified as string name. > + > +@item @code{helo} (default: @code{#f}) > +Advertise string heloname as the hostname to other mail exchangers > during > +the HELO phase. > + > +@item @code{helo-src} (default: @code{#f} ) > + Use the mapping @code{} to look up a hostname > +matching the source address, to advertise during the HELO phase. > + > +@item @code{domain} (default: @code{#f}) > +Do not perform MX lookups but look up destination domain in an > +@code{} and use matching relay url as relay host. > + > +@item @code{host} (default: @code{#f}) > +Do not perform MX lookups but relay messages to the relay host > described by > +the string relay-url. The format for relay-url is > +@samp{[proto://[label@@]]host[:port]}. The following protocols are > available: > + > +@multitable {aaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. > +@item @code{smtp} > +@tab Normal SMTP session with opportunistic STARTTLS (the default). > +@item @code{smtp+tls} > +@tab Normal SMTP session with mandatory STARTTLS@. > +@item @code{smtp+notls} > +@tab Plain text SMTP session without TLS@. > +@item @code{lmtp} > +@tab LMTP session.=C2=A0 port is required. > +@item @code{smtps} > +@tab SMTP session with forced TLS on connection, default port is > +@item > +@tab 465. > +@end multitable > + > +Unless noted, port defaults to 25. > + > +The label corresponds to an entry in a credentials table, as > documented in > +@code{man table}. It is used with the @code{"smtp+tls"} and > @code{"smtps"} protocols for > +authentication. Server certificates for those protocols are verified > by > +default. > + > +@item @code{pki} (default: @code{#f}) > +For secure connections, use the certificate associated with > +@code{} (declared in a pki directive) to prove the > +client's identity to the remote mail server. > + > +@item @code{srs} (default: @code{#f}) > +If @code{#t}, then when relaying a mail resulting from a forward, > use the Sender > +Rewriting Scheme to rewrite sender address. > + > +@item @code{tls} (default: @code{#f}) boolean or string ``no- > verify'' Instead of a string, take 'no-verify as symbol perhaps? > +When @code{#t}, Require TLS to be used when relaying, using > mandatory STARTTLS by > +default. When used with a smarthost, the protocol must not be > +@samp{"smtp+notls://"}. When string @code{"no-verify"}, then do not > require a valid > +certificate. > + > +@item @code{auth} (default: @code{#f}) @code{} > +Use the alist @code{} for connecting to relay-url > +using credentials. This option is usable only with fieldname > @code{host} option. > + > +@item @code{mail-from} (default: @code{#f}) string > +Use the string mailaddress as MAIL FROM address within the SMTP > transaction. > + > +@item @code{src} (default: @code{#f}) string | @code{ table>} > +Use the string or @code{} sourceaddr for the > +source IP address, which is useful on machines with multiple > interfaces. If > +the list contains more than one address, all of them are used in > such a way > +that traffic is routed as efficiently as possible. > +@end itemize > + > +@item Data Type: opensmtpd-filter > +This data type represents the configuration of an > +@code{}. This is the filter record one should use > +if they want to use an external package to filter email eg: rspamd > or > +spamassassin. > + > +@itemize > +@item @code{name} (default: @code{#f}) > +The string name of the filter. > + > +@item @code{proc} (default: @code{#f}) > +The string command or process name.=C2=A0 If @code{proc-exec} is > @code{#t}, @code{proc} is > +treated as a command to execute.=C2=A0 Otherwise, it is a process name. > + > +@item @code{proc-exec} (default: @code{#f}) > +If @code{#t}, then execute the command in @code{proc}. > +@end itemize > + > +@item Data Type: opensmtpd-filter-phase > +This data type represents the configuration of an > +@code{}. > + > +In a regular workflow, @code{smtpd(8)} may accept or reject a > message > +based only on the content of envelopes. Its decisions are about the > +handling of the message, not about the handling of an active > session. > + > +Filtering extends the decision making process by allowing > +@code{smtpd(8)} to stop at each phase of an SMTP session, check that > +options are met, then decide if a session is allowed to move > forward. > + > +With filtering via an @code{} record, a > +session may be interrupted at any phase before an envelope is > complete. A > +message may also be rejected after being submitted, regardless of > whether the > +envelope was accepted or not. > + > +@itemize > +@item @code{name} (default: @code{#f}) > + > +The string name of the filter phase. > + > +@item @code{phase-name} (default: @code{#f}) > +The string name of the phase. Valid values are: > + > +@multitable {aaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @code{"connect"} > +@tab upon connection, before a banner is displayed > +@item @code{"helo"} > +@tab after HELO command is submitted > +@item @code{"ehlo"} > +@tab after EHLO command is submitted > +@item @code{"mail-from"} > +@tab after MAIL FROM command is submitted > +@item @code{"rcpt-to"} > +@tab after RCPT TO command is submitted > +@item @code{"data"} > +@tab after DATA command is submitted > +@item @code{"commit"} > +@tab after message is fully is submitted > +@end multitable > + > +@item @code{options} (default @code{#f}) > +A list of unique @code{} records. > + > +At each phase, various options, specified by a list of > +@code{}, may be checked. The > +@code{}'s fieldname @code{option} values of: > +@code{"fcrdns"}, @code{"rdns"}, and @code{"src"} data are available > in > +all phases, but other data must have been already submitted before > they > +are available. Options with a @code{
} next to them require > the > +@code{}'s fieldname @code{data} to be an > +@code{}. There are the available options: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @code{"fcrdns"} > +@tab forward-confirmed reverse DNS is valid > +@item @code{"rdns"} > +@tab session has a reverse DNS > +@item @code{"rdns"}
> +@tab session has a reverse DNS in table > +@item @code{"src"}
> +@tab source address is in table > +@item @code{"helo"}
> +@tab helo name is in table > +@item @code{"auth"} > +@tab session is authenticated > +@item @code{"auth"}
> +@tab session username is in table > +@item @code{"mail-from"}
> +@tab sender address is in table > +@item @code{"rcpt-to"}
> +@tab recipient address is in table > +@end multitable > + > +These conditions may all be negated by setting > +@code{(opensmtpd-option (bool #f))}. > + > +Any conditions that require a table may indicate that tables include > regexs > +setting @code{(opensmtpd-option (regex #t))}. > + > +@item @code{decision} > +A string decision to be taken. Some decisions require an > @code{message} > +or @code{value}.=C2=A0 The value and message may be put in the > +@code{}'s fieldname @code{data}.=C2=A0 Valid strings > are: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @code{"bypass"} > +@tab the session or transaction bypasses filters > +@item @code{"disconnect"} message > +@tab the session is disconnected with message > +@item @code{"junk"} > +@tab the session or transaction is junked, > +@item > +@tab=C2=A0 i.e., an =E2=80=98X-Spam: yes=E2=80=99 header is added to > +@item > +@tab any messages > +@item @code{"reject"} message > +@tab the command is rejected with message > +@item @code{"rewrite"} value > +@tab the command parameter is rewritten with value > +@end multitable > + > +Decisions that involve a message require that the message be RFC > valid, > +meaning that they should either start with a 4xx or 5xx status code. > +Descisions can be taken at any phase, though junking can only happen > before > +a message is committed. > + > +@item @code{message} (default @code{#f}) > +A string message beginning with a 4xx or 5xx status code. > + > +@item @code{value} (default: @code{#f}) > +A number value.=C2=A0 @code{value} and @code{message} are mutually > exclusive. > +@end itemize > + > +@item Data Type: opensmtpd-option > +This data type represents the configuration of an > +@code{}, which is used by > +@code{} and @code{} > +to match various options for email. > + > +@itemize > +@item @code{option} (default @code{#f}) string > + > +A string option to be taken. Some options require the fieldname > +@code{data} to have a string or an @code{}. When > the > +option record is used inside of an @code{}, > then > +valid strings for fieldname @code{option} are: > + > +@itemize > +@item @code {"fcrdns"} > +@item @code {"rdns"} > +@item @code {"src"} > +@item @code {"helo"} > +@item @code {"auth"} > +@item @code {"mail-from"} > +@item @code {"rcpt-to"} > +@end itemize > + > +When @code{} is used inside of an > +@code{}, then valid strings for fieldname > @code{option} > +are: > + > +@itemize > +@item @code {"for"} > +@item @code {"for any"} > +@item @code {"for local"} > +@item @code {"for domain"} > +@item @code {"for rcpt-to"} > +@item @code {"from any"} > +@item @code {"from auth"} > +@item @code {"from local"} > +@item @code {"from mail-from"} > +@item @code {"from rdns"} > +@item @code {"from socket"} > +@item @code {"from src"} > +@item @code {"auth"} > +@item @code {"helo"} > +@item @code {"mail-from"} > +@item @code {"rcpt-to"} > +@item @code {"tag"} > +@item @code {"tls"} > +@end itemize > + > +@item @code{data} (default @code{#f}) string | @code{ table>} > +Some options require a string or @code{} to be > +present. One would specify that table here. > + > +@item @code{regex} (default: @code{#f}) boolean > +Any options using a table may indicate that tables hold regular > +expressions by setting this option to @code{#t}. > + > +@item @code{bool} (default: @code{#t}) boolean > +When @code{(bool #f)}, this option record is negated. > +@end itemize > + > +@item Data Type: opensmtpd-table > +This data type represents the configuration of an > +@code{}. > + > +@itemize > +@item @code{name} (default @code{#f}) > +@code{name} is the name of the @code{} record. > + > +@item @code{data} (default: @code{#f}) string | list | alist | > nested-list > +@code{data} expects a string, a list of strings, an alist of > strings, or > +a nested list of strings. > +eg: > + > +@itemize > + > +@item string > +@lisp > +(data "dev@@gnu.org") > +@end lisp > + > +A table of this type is called a @code{string table}. > + > +@item list > +@lisp > +(data (list ("gnu.org" "fsf.org"))) > +@end lisp > + > +A table of this type is called a @code{list table}. > + > +@item alist > +@lisp > +(data '(("james" . "$encryptedPassword") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ("jennifer" . "$encryptedPass= word2))) > +@end lisp > + > +A table of this type is called a @code{mapping table}. > + > +@item nested-list > +@lisp > +(data '(("user1" "root@@gnu.org" "admin@@gnu.org") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ("user2" "james@@guix.gnu.org= " "sarah@@fsf.org"))) > +@end lisp > + > +A table of this type is also called a @code{mapping table}. > + > +@end itemize > +@end itemize > + > +@item Data Type: opensmtpd-pki > +This data type represents the configuration of an > +@code{}. > + > +@itemize > +@item @code{domain} (default @code{#f}) > +@code{domain} is the string name of the @code{} > record. > + > +@item @code{cert} (default: @code{#f}) > +@code{cert} (default: @code{#f}) > + > +@code{cert} is the string certificate filename to use for this pki. > + > +@item @code{key} (default: @code{#f}) > +@code{key} is the string certificate falename to use for this pki. > + > +@item @code{dhe} (default: @code{"none"}) > +Specify the DHE string parameter to use for DHE cipher suites with > host > +pkiname. Valid parameter values are @code{"none"}, @code{"legacy"}, > or > +@code{"auto"}. For @code{"legacy"}, a fixed key length of 1024 bits > is > +used, whereas for @code{"auto"}, the key length is determined > +automatically. The default is @code{"none"}, which disables DHE > cipher > +suites. > +@end itemize > + > +@item Data Type: opensmtpd-maildir > +@itemize > +@item @code{pathname} (default: @code{"~/Maildir"}) > +Deliver the message to the maildir if pathname if specified, or by > default > +to @code{"~/Maildir"}. > + > +The pathname may contain format specifiers that are expanded before > use > +(see FORMAT SPECIFIERS). > + > +@item @code{junk} (default: @code{#f}) > +If the junk argument is @code{#t}, then the message will be moved to > the @samp{=E2=80=98Junk=E2=80=99} > +folder if it contains a positive @samp{=E2=80=98X-Spam=E2=80=99} header.= This folder > will be > +created under pathname if it does not yet exist. > +@end itemize > + > +@item Data Type: opensmtpd-mda > +This record lets you delegate the delivery to a command that > receives > +the message on its standard input. > + > +@itemize > +@item @code{name} > +The string name for this MDA command. > + > +@item @code{command} > +The command to that delivers the mail. > + > +The command may contain format specifiers that are expanded before > use (see > +FORMAT SPECIFIERS). > +@end itemize > + > +@item Data Type: opensmtpd-queue > +@itemize > +@item @code{compression} (default @code{#f}) > +Store queue files in a compressed format. This may be useful to save > disk > +space. > + > +@item @code{encryption} (default @code{#f}) > +Encrypt queue files with EVP@math{_aes}@math{_256}@math{_gcm}(3). If > no key is specified, it is > +read with getpass(3). If the string stdin or a single dash (=E2=80=98-= =E2=80=99) is > given > +instead of a key, the key is read from the standard input. > + > +@item @code{ttl-delay} (default @code{#f}) > +Set the default expiration time for temporarily undeliverable > messages, > +given as a positive decimal integer followed by a unit s, m, h, or > d. The > +default is four days (@code{"4d"}). > +@end itemize > + > +@item Data Type: opensmtpd-smtp > +Data type representing an @code{} record. > + > +@itemize > +@item @code{ciphers} (default: @code{#f}) > +Set the control string for > SSL@math{_CTX}@math{_set}@math{_cipher}@math{_list}(3).=C2=A0 The default > is > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ``HIGH:!aNULL:!MD5''. > + > +@item @code{limit-max-mails} (default: @code{100}) > +Limit the number of messages to count for each sessio > + > +@item @code{limit-max-rcpt} (default: @code{1000}) > +Limit the number of recipients to count for each transaction. > + > +@item @code{max-message-size} (default: @code{35M}) > +Reject messages larger than size, given as a positive number of > bytes or as > +a string to be parsed with scan@math{_scaled}(3). > + > +@item @code{sub-addr-delim character} (default: @code{+}) > +When resolving the local part of a local email address, ignore the > ASCII > +character and all characters following it. This is helpful for email > +filters. @samp{"admin+bills@@gnu.org"} is the same email address as > +@samp{"admin@@gnu.org"}. BUT an email filter can filter emails > addressed to first > +email address into a 'Bills' email folder. > +@end itemize > + > +@item Data Type: opensmtpd-srs > +Use this record to set up the Sender Rewriting Scheme (SRS). > + > +@itemize > +@item @code{key} (default: @code{#f}) > +Set the secret key to use for SRS, the Sender Rewriting Scheme. > + > +@item @code{backup-key} (default: @code{#f}) > +Set a backup secret key to use as a fallback for SRS@. This can be > used to > +implement SRS key rotation. > + > +@item @code{ttl-delay} (default: @code{"4d"}) > +Set the time-to-live delay for SRS envelopes. After this delay, a > bounce > +reply to the SRS address will be discarded to limit risks of forged > +addresses. > +@end itemize > + > +@item Format Specifiers > +Some configuration records support expansion of their parameters at > +runtime. Such records (for example > +@code{}, @code{}) may use > +format specifiers which are expanded before delivery or relaying. > The > +following formats are currently supported: > + > +@multitable {aaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{sender@}} > +@tab sender email address, may be empty string > +@item @samp{%@{sender.user@}} > +@tab user part of the sender email address, may be empty > +@item @samp{%@{sender.domain@}} > +@tab domain part of the sender email address, may be empty > +@item @samp{%@{rcpt@}} > +@tab recipient email address > +@item @samp{%@{rcpt.user@}} > +@tab user part of the recipient email address > +@item @samp{%@{rcpt.domain@}} > +@tab domain part of the recipient email address > +@item @samp{%@{dest@}} > +@tab recipient email address after expansion > +@item @samp{%@{dest.user@}} > +@tab user part after expansion > +@item @samp{%@{dest.domain@}} > +@tab domain part after expansion > +@item @samp{%@{user.username@}} > +@tab local user > +@item @samp{%@{user.directory@}} > +@tab home directory of the local user > +@item @samp{%@{mbox.from@}} > +@tab name used in mbox From separator lines > +@item @samp{%@{mda@}} > +@tab mda command, only available for mda wrappers > +@end multitable > + > +Expansion formats also support partial expansion using the optional > bracket notations > +with substring offset.=C2=A0 For example, with recipient domain > @samp{=E2=80=9Cexample.org=E2=80=9D}: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{rcpt.domain[0]@}} > +@tab expands to =E2=80=9Ce=E2=80=9D > +@item @samp{%@{rcpt.domain[1]@}} > +@tab expands to =E2=80=9Cx=E2=80=9D > +@item @samp{%@{rcpt.domain[8:]@}} > +@tab expands to =E2=80=9Corg=E2=80=9D > +@item @samp{%@{rcpt.domain[-3:]@}} > +@tab expands to =E2=80=9Corg=E2=80=9D > +@item @samp{%@{rcpt.domain[0:6]@}} > +@tab expands to =E2=80=9Cexample=E2=80=9D > +@item @samp{%@{rcpt.domain[0:-4]@}} > +@tab expands to =E2=80=9Cexample=E2=80=9D > +@end multitable > + > +In addition, modifiers may be applied to the token.=C2=A0 For example, > with recipient > +@samp{=E2=80=9CUser+Tag@@Example.org=E2=80=9D}: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{rcpt:lowercase@}} > +@tab expands to =E2=80=9Cuser+tag@@example.org=E2=80=9D > +@item @samp{%@{rcpt:uppercase@}} > +@tab expands to =E2=80=9CUSER+TAG@@EXAMPLE.ORG=E2=80=9D > +@item @samp{%@{rcpt:strip@}} > +@tab expands to =E2=80=9CUser@@Example.org=E2=80=9D > +@item @samp{%@{rcpt:lowercasestrip@}} > +@tab expands to =E2=80=9Cuser@@example.org=E2=80=9D > +@end multitable > + > +For security concerns, expanded values are sanitized and potentially > dangerous > +characters are replaced with =E2=80=98:=E2=80=99. In situations where th= ey are > desirable, the > +=E2=80=9Craw=E2=80=9D modifier may be applied. For example, with recipie= nt > +@samp{=E2=80=9Cuser+t?g@@example.org=E2=80=9D}: > + > +@multitable {aaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{rcpt@}} > +@tab expands to =E2=80=9Cuser+t:g@@example.org=E2=80=9D > +@item @samp{%@{rcpt:raw@}} > +@tab expands to =E2=80=9Cuser+t?g@@example.org=E2=80=9D > +@end multitable > +@end itemize > + > =C2=A0@subsubheading Exim Service > =C2=A0 > =C2=A0@cindex mail transfer agent (MTA) > diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm > index 43f144a42d..4175cab375 100644 > --- a/gnu/services/mail.scm > +++ b/gnu/services/mail.scm > @@ -35,6 +35,10 @@ (define-module (gnu services mail) > =C2=A0=C2=A0 #:use-module (gnu packages admin) > =C2=A0=C2=A0 #:use-module (gnu packages dav) > =C2=A0=C2=A0 #:use-module (gnu packages tls) > +=C2=A0 #:use-module (guix i18n) > +=C2=A0 #:use-module (guix diagnostics) > +=C2=A0 #:use-module (guix ui) > +=C2=A0 #:use-module (guix utils) > =C2=A0=C2=A0 #:use-module (guix records) > =C2=A0=C2=A0 #:use-module (guix packages) > =C2=A0=C2=A0 #:use-module (guix gexp) > @@ -58,10 +62,149 @@ (define-module (gnu services mail) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mailbox-configuration > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = namespace-configuration > =C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-table > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-table? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-table-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-table-data > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-ca > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-ca? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-ca-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-ca-file > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-pki > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-pki? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-pki-domain > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-pki-cert > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-pki-key > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-pki-dhe > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-method > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-alias > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-ttl > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-user > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-userbase > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-virtual > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-local-delivery-wrapper > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-maildir > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-maildir? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-maildir-pathname > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-maildir-junk > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-mda > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-mda-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-mda-command > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-lmtp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-lmtp-destination > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-lmtp-rcpt > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-backup > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-backup-mx > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-helo > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-domain > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-host > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-pki > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-srs > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-tls > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-auth > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-mail-from > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-relay-src > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-option? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-option-option > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-option-bool > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-option-regex > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-option-data > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase-phase > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase-options > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase-decision > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase-message > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-phase-value > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-filter-proc > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-interface > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-family > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-auth > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-auth-optional > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-filters > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-hostname > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-hostnames > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-mask-src > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-disable-dsn > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-pki > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-port > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-proxy-v2 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-received-auth > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-senders > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-masquerade > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-secure-connection > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-interface-tag > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-socket > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-socket? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-socket-filters > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-socket-mask-src > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-socket-tag > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-match > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-match? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-match-action > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-match-options > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp-ciphers > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp-limit-max-mails > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp-limit-max-rcpt > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp-max-message-size > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-smtp-sub-addr-delim character > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-srs > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-srs? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-srs-key > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-srs-backup-key > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-srs-ttl-delay > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-queue > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-queue? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-queue-compression > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-queue-encryption > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-queue-ttl-delay > + > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = opensmtpd-configuration > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = opensmtpd-configuration? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-package > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-config-file > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-bounce > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-cas > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-interfaces > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-socket > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-includes > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-matches > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;;ope= nsmtpd-configuration-mda-wrappers > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-mta-max-deferred > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-srs > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-smtp > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 opens= mtpd-configuration-queue > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = opensmtpd-service-type > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 %defa= ult-opensmtpd-config-file > =C2=A0 > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mail-aliases-service-type > =C2=A0 > @@ -1641,22 +1784,2351 @@ (define (generate-dovecot-documentation) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (listeners unix-listener-confi= guration fifo-listener- > configuration > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 inet-listener-configuration)) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (protocol-configuration ,protocol-co= nfiguration-fields)) > -=C2=A0 'dovecot-configuration)) > +=C2=A0=C2=A0 'dovecot-configuration)) > =C2=A0 > =C2=A0=0C > -;;; > =C2=A0;;; OpenSMTPD. > =C2=A0;;; > +;;; This next bit of code helps me create my own sanitizer > functions. > + > +;; some fieldnames have a default value of #f, which is ok.=C2=A0 They > cannot have > +;; a value of #t. > +;; for example opensmtpd-table-data can be #f, BUT NOT true. > +;; my/sanitize procedure tests values to see if they are of the > right kind. > +;; procedure false? is needed to allow fields like 'values' to be > blank, > +;; (empty), or #f BUT also have a value like a list of strings. Use less egocentric comments ;) > +(define (false? var) > +=C2=A0 (eq? #f var)) > + > +;; TODO I have to have this procedure, or I need to change > my/sanitize > +;; procedure. > +(define (my-file-exists? file) > +=C2=A0 (and (string? file) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (access? file F_OK))) Does file-exists? not work for you? > +;; This procedure takes in a var and a list of procedures.=C2=A0 It loop= s > through > +;; list of procedures passing in var to each. > +;; if one procedure returns #t, the function returns true.=C2=A0 > Otherwise #f. > +;; TODO for fun rewrite this using map > +;; If I rewrote it in map, then it may help with sanitizing. > +;; eg: I could then potentially easily sanitize vars with lambda > procedures. > +(define (is-value-right-type? var list-of-procedures record > fieldname) > +=C2=A0 (if (null? list-of-procedures) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #f > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if ((car list-of-procedures) var) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #t > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (is-value-right-t= ype? var (cdr list-of-procedures) record > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 fieldname)))) Alternatively, (any (cut <> var) list-of-procedures). > +;; converts strings like this: > +;; "apple, ham, cherry" -> "apple, ham, or cherry" > +;; "pineapple" -> "pinneapple". > +;; "cheese, grapefruit, or jam" -> "cheese, grapefruit, or jam" > +(define (add-comma-or string) > +=C2=A0 (define last-comma-location (string-rindex string #\,)) > +=C2=A0 (if last-comma-location > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if (string-contains string ", or" last-c= omma-location) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 string > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (string-replace s= tring ", or" last-comma-location > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (+ 1 last-comma-location))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 string)) > + > + > +(define (list-of-procedures->string procedures) > +=C2=A0 (define string > +=C2=A0=C2=A0=C2=A0 (let loop ((procedures procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if (null? procedures) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (stri= ng-append > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (cond ((eq? false? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "#f, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? boolean? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a boolean, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? string? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a string, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? integer? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an integer, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? list-of-strings? (car procedures= )) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of strings, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? assoc-list? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an association list of strings,= ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? nested-list? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a nested-list of strings, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? opensmtpd-pki? (car procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an record, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? opensmtpd-table? (car procedures= )) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an record, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? list-of-opensmtpd-match? (car pr= ocedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of unique records, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? list-of-strings-or-gexps? (car p= rocedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of strings or gexps, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; TODO can I remove the next two proc= edures? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; tables-data-are-a* ?=C2=A0 I think = I can. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? tables-data-are-assoc-list? (car > procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (string-append > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an reco= rd whose fieldname > 'data' are " > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "an assoc-list.\nFor examp= le: (opensmtpd-table=C2=A0 > " > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "(name \"hostnames\") , " > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "(data '((\"124.394.23.1\"= . \"gnu.org\"))))")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? tables-data-are-a-list-of-string= s? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (c= ar procedures)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (string-append > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "on reco= rd whose fieldname > 'data' is " > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a list of strings.\n" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "For example: (opensmtpd-t= able (name > \"domains\") , " > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "(data (list \"gnu.org\" \= "guix.gnu.org\")))")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ((eq? my-file-exists? (car procedures)= ) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "a file, ") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (else "has an incorrect value, ")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (loop (cdr procedures))))))) > +=C2=A0 (add-comma-or (string-append (string-drop-right string 2) ".\n"))= ) (define (procedure->string) ...) (define (procedures->string list) (define strings (map procedure->string list)) (string-append (string-join (drop-right strings 1) ", ") (if (> (length list) 1) ", or") (last strings) ".\n")) > +(define (list-of-strings-or-gexps? list) > +=C2=A0 (and (list? list) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cond ((null? list) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 #t) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= ((or (string? (car list)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (gexp? (car list)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (local-file? (car list)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (file-append? (car list)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plain-file? (car list)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (computed-file? (car list)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (program-file? (car list))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (list-of-strings-or-gexps? (cdr list))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (else #f)))) > + > +(define (my/sanitize var record fieldname list-of-procedures) > +=C2=A0 (define try-string > +=C2=A0=C2=A0=C2=A0 (string-append "Try " (list-of-procedures->string lis= t-of- > procedures))) > +=C2=A0 (if (is-value-right-type? var list-of-procedures record fieldname= ) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 var > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cond ((string? var) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (report-error (G_ "(~a \"~a\") is invalid.~%") > fieldname var)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 ((or (number? var) (boolean? var)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (report-error (G_ "(~a ~a) is invalid.~%") fieldname > var) ) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (else > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (report-error (G_ "(~a ...) is invalid.~%Value is: > ~a~%") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 fieldname var))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (display-hint (G_ try-string)= ) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (throw 'bad! var)))) This procedure needs a proper name, like sanitize/check-type, but more importantly, why not simply use define-configuration? Cheers