# SPDX-FileCopyrightText: V # SPDX-License-Identifier: OSL-3.0 # TODO(V): Figure out what the coderepo/cgit stuff is about # TODO(V): Consider a different architecture to what we're currently using { config, lib, pkgs, ... }: with lib; let cfg = config.services.public-inbox; root = "/var/lib/public-inbox"; environment.PI_CONFIG = "${pkgs.writeText "public-inbox-config" (generators.toGitINI public-inbox-config)}"; # TODO(V): Port this to a Nix type # $ng =~ m![^A-Za-z0-9/_\.\-\~\@\+\=:]! and # die "--newsgroup `$ng' is not valid\n"; # ($ng =~ m!\A\.! || $ng =~ m!\.\z!) and # die "--newsgroup `$ng' must not start or end with `.'\n"; public-inbox-config = recursiveUpdate { publicinbox = mapAttrs (inbox: config: { address = [ "${inbox}@${config.domain}" ]; url = "https://${config.domain}/${inbox}"; # TODO(V): Allow using a different location than this inboxdir = "${root}/${inbox}"; inherit (config) watch; }) cfg.inboxes; } cfg.settings; inboxOpts = { options = { description = mkOption { description = "Description of the inbox."; type = types.str; }; domain = mkOption { description = "Domain of the inbox."; type = types.str; example = "example.org"; }; watch = mkOption { description = "Directory to watch for incoming mails in."; type = types.str; }; }; }; in { # XXX(V): this is here to fix the build until we migrate to the # upstream module that was added recently. disabledModules = [ "services/mail/public-inbox.nix" ]; options.services.public-inbox = { enable = mkOption { type = types.bool; default = false; }; inboxes = mkOption { type = with types; attrsOf (submodule inboxOpts); default = {}; }; settings = mkOption { type = types.attrs; # TODO: Use freeformType default = {}; }; }; config = mkIf cfg.enable { users.users.public-inbox = { isSystemUser = true; group = "public-inbox"; home = root; }; users.groups.public-inbox = {}; systemd.tmpfiles.rules = [ "d ${root} 0750 public-inbox public-inbox" ]; systemd.services.public-inbox-init = { description = "public-inbox mailing-list archive (initialization)"; wantedBy = [ "public-inbox-watch.service" "multi-user.target" ]; before = [ "public-inbox-watch.service" ]; script = concatStrings (mapAttrsToList (inbox: config: let pi-config = public-inbox-config.publicinbox.${inbox}; in '' ${pkgs.public-inbox-init-lite}/bin/public-inbox-init-lite ${inbox} ${pi-config.inboxdir} ${head pi-config.address} ln -sf ${pkgs.writeText "public-inbox-description" config.description} ${pi-config.inboxdir}/description ${pkgs.public-inbox}/bin/public-inbox-index ${pi-config.inboxdir} '') cfg.inboxes); serviceConfig = { Type = "oneshot"; RemainAfterExit = true; User = "public-inbox"; }; }; # FIXME(V): Currently, if new mail appears in the mlmmj archive while public-inbox-watch is not running, it never gets added! # This directly contradicts what the manpage states: "Upon startup, it scans the mailbox for new messages to be imported while it was not running." # This might be a bug in public-inbox! # We currently save a copy of all mails received by mlmmj to ensure none are lost if this happens. systemd.services.public-inbox-watch = { description = "public-inbox mailing-list archive (incoming mail monitor)"; wantedBy = [ "multi-user.target" ]; inherit environment; serviceConfig = { ExecStart = "${pkgs.public-inbox}/bin/public-inbox-watch"; # TODO(V): ExecReload User = "public-inbox"; SupplementaryGroups = [ "mlmmj" ]; }; }; # TODO(V): Consider using public-inbox.cgi + cgiserver instead? systemd.sockets.public-inbox-httpd = { description = "public-inbox mailing-list archive (web server)"; listenStreams = [ "/run/public-inbox/httpd.sock" ]; wantedBy = [ "sockets.target" ]; }; systemd.services.public-inbox-httpd = { description = "public-inbox mailing-list archive (web server)"; requires = [ "public-inbox-httpd.socket" ]; after = [ "public-inbox-httpd.socket" ]; # Descriptions are cached for the lifetime of the process, so updates require a restart to get picked up. restartTriggers = mapAttrsToList (inbox: config: "${inbox}:${builtins.hashString "sha256" config.description}") cfg.inboxes; inherit environment; serviceConfig = { ExecStart = "${pkgs.public-inbox}/bin/public-inbox-httpd"; DynamicUser = true; SupplementaryGroups = [ "public-inbox" ]; NonBlocking = true; # "to avoid stalled processes when multiple service instances start" }; }; }; meta.maintainers = with maintainers; [ V ]; }