9d9d826054
... to be able to limit the number of mails to be retrieved. local refers to the "store" configuration, remote to the "channel".
192 lines
4.9 KiB
Nix
192 lines
4.9 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
dag = config.lib.dag;
|
|
|
|
cfg = config.programs.mbsync;
|
|
|
|
# Accounts for which mbsync is enabled.
|
|
mbsyncAccounts =
|
|
filter (a: a.mbsync.enable) (attrValues config.accounts.email.accounts);
|
|
|
|
genTlsConfig = tls: {
|
|
SSLType =
|
|
if !tls.enable then "None"
|
|
else if tls.useStartTls then "STARTTLS"
|
|
else "IMAPS";
|
|
}
|
|
//
|
|
optionalAttrs (tls.enable && tls.certificatesFile != null) {
|
|
CertificateFile = tls.certificatesFile;
|
|
};
|
|
|
|
masterSlaveMapping = {
|
|
none = "None";
|
|
imap = "Master";
|
|
maildir = "Slave";
|
|
both = "Both";
|
|
};
|
|
|
|
genSection = header: entries:
|
|
let
|
|
escapeValue = escape [ "\"" ];
|
|
hasSpace = v: builtins.match ".* .*" v != null;
|
|
genValue = v:
|
|
if isList v
|
|
then concatMapStringsSep " " genValue v
|
|
else if isInt v then toString v
|
|
else if (hasSpace v) then "\"${escapeValue v}\""
|
|
else v;
|
|
in
|
|
''
|
|
${header}
|
|
${concatStringsSep "\n"
|
|
(mapAttrsToList (n: v: "${n} ${genValue v}") entries)}
|
|
'';
|
|
|
|
genAccountConfig = account: with account;
|
|
if (imap == null || maildir == null)
|
|
then ""
|
|
else
|
|
genSection "IMAPAccount ${name}" (
|
|
{
|
|
Host = imap.host;
|
|
User = userName;
|
|
PassCmd = toString passwordCommand;
|
|
}
|
|
//
|
|
genTlsConfig imap.tls
|
|
//
|
|
optionalAttrs (imap.port != null) { Port = toString imap.port; }
|
|
)
|
|
+ "\n"
|
|
+ genSection "IMAPStore ${name}-remote" {
|
|
Account = name;
|
|
}
|
|
+ "\n"
|
|
+ genSection "MaildirStore ${name}-local" (
|
|
{
|
|
Path = "${maildir.absPath}/";
|
|
Inbox = "${maildir.absPath}/${folders.inbox}";
|
|
SubFolders = "Verbatim";
|
|
}
|
|
// optionalAttrs (mbsync.flatten != null) { Flatten = mbsync.flatten; }
|
|
// mbsync.extraConfig.local
|
|
)
|
|
+ "\n"
|
|
+ genSection "Channel ${name}" (
|
|
{
|
|
Master = ":${name}-remote:";
|
|
Slave = ":${name}-local:";
|
|
Patterns = mbsync.patterns;
|
|
Create = masterSlaveMapping.${mbsync.create};
|
|
Remove = masterSlaveMapping.${mbsync.remove};
|
|
Expunge = masterSlaveMapping.${mbsync.expunge};
|
|
SyncState = "*";
|
|
}
|
|
// mbsync.extraConfig.remote
|
|
)
|
|
+ "\n";
|
|
|
|
genGroupConfig = name: channels:
|
|
let
|
|
genGroupChannel = n: boxes: "Channel ${n}:${concatStringsSep "," boxes}";
|
|
in
|
|
concatStringsSep "\n" (
|
|
[ "Group ${name}" ] ++ mapAttrsToList genGroupChannel channels
|
|
);
|
|
|
|
in
|
|
|
|
{
|
|
options = {
|
|
programs.mbsync = {
|
|
enable = mkEnableOption "mbsync IMAP4 and Maildir mailbox synchronizer";
|
|
|
|
package = mkOption {
|
|
type = types.package;
|
|
default = pkgs.isync;
|
|
defaultText = "pkgs.isync";
|
|
example = literalExample "pkgs.isync";
|
|
description = "The package to use for the mbsync binary.";
|
|
};
|
|
|
|
groups = mkOption {
|
|
type = types.attrsOf (types.attrsOf (types.listOf types.str));
|
|
default = {};
|
|
example = literalExample ''
|
|
{
|
|
inboxes = {
|
|
account1 = [ "Inbox" ];
|
|
account2 = [ "Inbox" ];
|
|
};
|
|
}
|
|
'';
|
|
description = ''
|
|
Definition of groups.
|
|
'';
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
type = types.lines;
|
|
default = "";
|
|
description = ''
|
|
Extra configuration lines to add to the mbsync configuration.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
assertions = [
|
|
(
|
|
let
|
|
badAccounts = filter (a: a.maildir == null) mbsyncAccounts;
|
|
in
|
|
{
|
|
assertion = badAccounts == [];
|
|
message = "mbsync: Missing maildir configuration for accounts: "
|
|
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
|
}
|
|
)
|
|
|
|
(
|
|
let
|
|
badAccounts = filter (a: a.imap == null) mbsyncAccounts;
|
|
in
|
|
{
|
|
assertion = badAccounts == [];
|
|
message = "mbsync: Missing IMAP configuration for accounts: "
|
|
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
|
}
|
|
)
|
|
];
|
|
|
|
home.packages = [ cfg.package ];
|
|
|
|
programs.notmuch.new.ignore = [ ".uidvalidity" ".mbsyncstate" ];
|
|
|
|
home.file.".mbsyncrc".text =
|
|
let
|
|
accountsConfig = map genAccountConfig mbsyncAccounts;
|
|
groupsConfig = mapAttrsToList genGroupConfig cfg.groups;
|
|
in
|
|
concatStringsSep "\n" (
|
|
[ "# Generated by Home Manager.\n" ]
|
|
++ accountsConfig
|
|
++ groupsConfig
|
|
++ optional (cfg.extraConfig != "") cfg.extraConfig
|
|
);
|
|
|
|
home.activation.createMaildir =
|
|
dag.entryBetween [ "linkGeneration" ] [ "writeBoundary" ] ''
|
|
$DRY_RUN_CMD mkdir -m700 -p $VERBOSE_ARG ${
|
|
concatMapStringsSep " " (a: a.maildir.absPath) mbsyncAccounts
|
|
}
|
|
'';
|
|
};
|
|
}
|