1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8
9 cfg = config.services.dspam;
10
11 dspam = pkgs.dspam;
12
13 defaultSock = "/run/dspam/dspam.sock";
14
15 cfgfile = pkgs.writeText "dspam.conf" ''
16 Home /var/lib/dspam
17 StorageDriver ${dspam}/lib/dspam/lib${cfg.storageDriver}_drv.so
18
19 Trust root
20 Trust ${cfg.user}
21 SystemLog on
22 UserLog on
23
24 ${lib.optionalString (cfg.domainSocket != null) ''
25 ServerDomainSocketPath "${cfg.domainSocket}"
26 ClientHost "${cfg.domainSocket}"
27 ''}
28
29 ${cfg.extraConfig}
30 '';
31
32in
33{
34
35 ###### interface
36
37 options = {
38
39 services.dspam = {
40
41 enable = lib.mkOption {
42 type = lib.types.bool;
43 default = false;
44 description = "Whether to enable the dspam spam filter.";
45 };
46
47 user = lib.mkOption {
48 type = lib.types.str;
49 default = "dspam";
50 description = "User for the dspam daemon.";
51 };
52
53 group = lib.mkOption {
54 type = lib.types.str;
55 default = "dspam";
56 description = "Group for the dspam daemon.";
57 };
58
59 storageDriver = lib.mkOption {
60 type = lib.types.str;
61 default = "hash";
62 description = "Storage driver backend to use for dspam.";
63 };
64
65 domainSocket = lib.mkOption {
66 type = lib.types.nullOr lib.types.path;
67 default = defaultSock;
68 description = "Path to local domain socket which is used for communication with the daemon. Set to null to disable UNIX socket.";
69 };
70
71 extraConfig = lib.mkOption {
72 type = lib.types.lines;
73 default = "";
74 description = "Additional dspam configuration.";
75 };
76
77 maintenanceInterval = lib.mkOption {
78 type = lib.types.nullOr lib.types.str;
79 default = null;
80 description = "If set, maintenance script will be run at specified (in systemd.timer format) interval";
81 };
82
83 };
84
85 };
86
87 ###### implementation
88
89 config = lib.mkIf cfg.enable (
90 lib.mkMerge [
91 {
92 users.users = lib.optionalAttrs (cfg.user == "dspam") {
93 dspam = {
94 group = cfg.group;
95 uid = config.ids.uids.dspam;
96 };
97 };
98
99 users.groups = lib.optionalAttrs (cfg.group == "dspam") {
100 dspam.gid = config.ids.gids.dspam;
101 };
102
103 environment.systemPackages = [ dspam ];
104
105 environment.etc."dspam/dspam.conf".source = cfgfile;
106
107 systemd.services.dspam = {
108 description = "dspam spam filtering daemon";
109 wantedBy = [ "multi-user.target" ];
110 after = [ "postgresql.service" ];
111 restartTriggers = [ cfgfile ];
112
113 serviceConfig = {
114 ExecStart = "${dspam}/bin/dspam --daemon --nofork";
115 User = cfg.user;
116 Group = cfg.group;
117 RuntimeDirectory = lib.optional (cfg.domainSocket == defaultSock) "dspam";
118 RuntimeDirectoryMode = lib.optional (cfg.domainSocket == defaultSock) "0750";
119 StateDirectory = "dspam";
120 StateDirectoryMode = "0750";
121 LogsDirectory = "dspam";
122 LogsDirectoryMode = "0750";
123 # DSPAM segfaults on just about every error
124 Restart = "on-abort";
125 RestartSec = "1s";
126 };
127 };
128 }
129
130 (lib.mkIf (cfg.maintenanceInterval != null) {
131 systemd.timers.dspam-maintenance = {
132 description = "Timer for dspam maintenance script";
133 wantedBy = [ "timers.target" ];
134 timerConfig = {
135 OnCalendar = cfg.maintenanceInterval;
136 Unit = "dspam-maintenance.service";
137 };
138 };
139
140 systemd.services.dspam-maintenance = {
141 description = "dspam maintenance script";
142 restartTriggers = [ cfgfile ];
143
144 serviceConfig = {
145 ExecStart = "${dspam}/bin/dspam_maintenance --verbose";
146 Type = "oneshot";
147 User = cfg.user;
148 Group = cfg.group;
149 };
150 };
151 })
152 ]
153 );
154}