at master 11 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 10 inherit (lib) 11 getExe' 12 literalExpression 13 mkDefault 14 mkEnableOption 15 mkIf 16 mkMerge 17 mkOption 18 mkPackageOption 19 ; 20 inherit (lib.types) 21 attrsOf 22 bool 23 enum 24 ints 25 lines 26 nonEmptyStr 27 nullOr 28 path 29 str 30 submodule 31 ; 32 33 commonDescr = '' 34 Values can be either strings or integers 35 (which will be added to the config file verbatimly) 36 or lists thereof 37 (which will be translated to multiple 38 lines with the same configuration key). 39 Boolean values are translated to "Yes" or "No". 40 The default contains some reasonable 41 configuration to yield an operational system. 42 ''; 43 44 configAttrType = 45 # Options in HylaFAX configuration files can be 46 # booleans, strings, integers, or list thereof 47 # representing multiple config directives with the same key. 48 # This type definition resolves all 49 # those types into a list of strings. 50 let 51 inherit (lib.types) 52 attrsOf 53 coercedTo 54 int 55 listOf 56 ; 57 innerType = coercedTo bool (x: if x then "Yes" else "No") (coercedTo int (toString) str); 58 in 59 attrsOf (coercedTo innerType lib.singleton (listOf innerType)); 60 61 cfg = config.services.hylafax; 62 63 modemConfigOptions = 64 { name, config, ... }: 65 { 66 options = { 67 name = mkOption { 68 type = nonEmptyStr; 69 example = "ttyS1"; 70 description = '' 71 Name of modem device, 72 will be searched for in {file}`/dev`. 73 ''; 74 }; 75 type = mkOption { 76 type = nonEmptyStr; 77 example = "cirrus"; 78 description = '' 79 Name of modem configuration file, 80 will be searched for in {file}`config` 81 in the spooling area directory. 82 ''; 83 }; 84 config = mkOption { 85 type = configAttrType; 86 example = { 87 AreaCode = "49"; 88 LocalCode = "30"; 89 FAXNumber = "123456"; 90 LocalIdentifier = "LostInBerlin"; 91 }; 92 description = '' 93 Attribute set of values for the given modem. 94 ${commonDescr} 95 Options defined here override options in 96 {option}`commonModemConfig` for this modem. 97 ''; 98 }; 99 }; 100 config.name = mkDefault name; 101 config.config.Include = [ "config/${config.type}" ]; 102 }; 103 104 defaultConfig = 105 let 106 inherit (config.security) wrapperDir; 107 inherit (config.services.mail.sendmailSetuidWrapper) program; 108 mkIfDefault = cond: value: mkIf cond (mkDefault value); 109 noWrapper = config.services.mail.sendmailSetuidWrapper == null; 110 # If a sendmail setuid wrapper exists, 111 # we add the path to the default configuration file. 112 # Otherwise, we use `false` to provoke 113 # an error if hylafax tries to use it. 114 c.sendmailPath = mkMerge [ 115 (mkIfDefault noWrapper (getExe' pkgs.coreutils "false")) 116 (mkIfDefault (!noWrapper) "${wrapperDir}/${program}") 117 ]; 118 importDefaultConfig = 119 file: lib.attrsets.mapAttrs (lib.trivial.const mkDefault) (import file { inherit lib pkgs; }); 120 c.commonModemConfig = importDefaultConfig ./modem-default.nix; 121 c.faxqConfig = importDefaultConfig ./faxq-default.nix; 122 c.hfaxdConfig = importDefaultConfig ./hfaxd-default.nix; 123 in 124 c; 125 126 localConfig = 127 let 128 c.hfaxdConfig.UserAccessFile = cfg.userAccessFile; 129 c.faxqConfig = lib.attrsets.mapAttrs (lib.trivial.const (v: mkIf (v != null) v)) { 130 AreaCode = cfg.areaCode; 131 CountryCode = cfg.countryCode; 132 LongDistancePrefix = cfg.longDistancePrefix; 133 InternationalPrefix = cfg.internationalPrefix; 134 }; 135 c.commonModemConfig = c.faxqConfig; 136 in 137 c; 138 139in 140 141{ 142 143 options.services.hylafax = { 144 145 enable = mkEnableOption "HylaFAX server"; 146 147 package = mkPackageOption pkgs "HylaFAX" { default = "hylafaxplus"; }; 148 149 autostart = mkOption { 150 type = bool; 151 default = true; 152 example = false; 153 description = '' 154 Autostart the HylaFAX queue manager at system start. 155 If this is `false`, the queue manager 156 will still be started if there are pending 157 jobs or if a user tries to connect to it. 158 ''; 159 }; 160 161 countryCode = mkOption { 162 type = nullOr nonEmptyStr; 163 default = null; 164 example = "49"; 165 description = "Country code for server and all modems."; 166 }; 167 168 areaCode = mkOption { 169 type = nullOr nonEmptyStr; 170 default = null; 171 example = "30"; 172 description = "Area code for server and all modems."; 173 }; 174 175 longDistancePrefix = mkOption { 176 type = nullOr str; 177 default = null; 178 example = "0"; 179 description = "Long distance prefix for server and all modems."; 180 }; 181 182 internationalPrefix = mkOption { 183 type = nullOr str; 184 default = null; 185 example = "00"; 186 description = "International prefix for server and all modems."; 187 }; 188 189 spoolAreaPath = mkOption { 190 type = path; 191 default = "/var/spool/fax"; 192 description = '' 193 The spooling area will be created/maintained 194 at the location given here. 195 ''; 196 }; 197 198 userAccessFile = mkOption { 199 type = path; 200 default = "/etc/hosts.hfaxd"; 201 description = '' 202 The {file}`hosts.hfaxd` 203 file entry in the spooling area 204 will be symlinked to the location given here. 205 This file must exist and be 206 readable only by the `uucp` user. 207 See {manpage}`hosts.hfaxd(5)` for details. 208 This configuration permits access for all users: 209 ``` 210 environment.etc."hosts.hfaxd" = { 211 mode = "0600"; 212 user = "uucp"; 213 text = ".*"; 214 }; 215 ``` 216 Note that host-based access can be controlled with 217 {option}`config.systemd.sockets.hylafax-hfaxd.listenStreams`; 218 by default, only 127.0.0.1 is permitted to connect. 219 ''; 220 }; 221 222 sendmailPath = mkOption { 223 type = path; 224 example = literalExpression ''lib.getExe' config.services.postfix.package "sendmail"''; 225 description = '' 226 Path to {file}`sendmail` program. 227 The default uses the local sendmail wrapper 228 (see {option}`config.services.mail.sendmailSetuidWrapper`), 229 otherwise the {file}`false` 230 binary to cause an error if used. 231 ''; 232 }; 233 234 hfaxdConfig = mkOption { 235 type = configAttrType; 236 example.RecvqProtection = "0400"; 237 description = '' 238 Attribute set of lines for the global 239 hfaxd config file {file}`etc/hfaxd.conf`. 240 ${commonDescr} 241 ''; 242 }; 243 244 faxqConfig = mkOption { 245 type = configAttrType; 246 example = { 247 InternationalPrefix = "00"; 248 LongDistancePrefix = "0"; 249 }; 250 description = '' 251 Attribute set of lines for the global 252 faxq config file {file}`etc/config`. 253 ${commonDescr} 254 ''; 255 }; 256 257 commonModemConfig = mkOption { 258 type = configAttrType; 259 example = { 260 InternationalPrefix = "00"; 261 LongDistancePrefix = "0"; 262 }; 263 description = '' 264 Attribute set of default values for 265 modem config files {file}`etc/config.*`. 266 ${commonDescr} 267 Think twice before changing 268 paths of fax-processing scripts. 269 ''; 270 }; 271 272 modems = mkOption { 273 type = attrsOf (submodule [ modemConfigOptions ]); 274 default = { }; 275 example.ttyS1 = { 276 type = "cirrus"; 277 config = { 278 FAXNumber = "123456"; 279 LocalIdentifier = "Smith"; 280 }; 281 }; 282 description = '' 283 Description of installed modems. 284 At least on modem must be defined 285 to enable the HylaFAX server. 286 ''; 287 }; 288 289 spoolExtraInit = mkOption { 290 type = lines; 291 default = ""; 292 example = "chmod 0755 . # everyone may read my faxes"; 293 description = '' 294 Additional shell code that is executed within the 295 spooling area directory right after its setup. 296 ''; 297 }; 298 299 faxcron.enable.spoolInit = mkEnableOption '' 300 purging old files from the spooling area with 301 {file}`faxcron` 302 each time the spooling area is initialized 303 ''; 304 faxcron.enable.frequency = mkOption { 305 type = nullOr nonEmptyStr; 306 default = null; 307 example = "daily"; 308 description = '' 309 purging old files from the spooling area with 310 {file}`faxcron` with the given frequency 311 (see {manpage}`systemd.time(7)`) 312 ''; 313 }; 314 faxcron.infoDays = mkOption { 315 type = ints.positive; 316 default = 30; 317 description = '' 318 Set the expiration time for data in the 319 remote machine information directory in days. 320 ''; 321 }; 322 faxcron.logDays = mkOption { 323 type = ints.positive; 324 default = 30; 325 description = '' 326 Set the expiration time for 327 session trace log files in days. 328 ''; 329 }; 330 faxcron.rcvDays = mkOption { 331 type = ints.positive; 332 default = 7; 333 description = '' 334 Set the expiration time for files in 335 the received facsimile queue in days. 336 ''; 337 }; 338 339 faxqclean.enable.spoolInit = mkEnableOption '' 340 purging old files from the spooling area with 341 {file}`faxqclean` 342 each time the spooling area is initialized 343 ''; 344 faxqclean.enable.frequency = mkOption { 345 type = nullOr nonEmptyStr; 346 default = null; 347 example = "daily"; 348 description = '' 349 Purge old files from the spooling area with 350 {file}`faxcron` with the given frequency 351 (see {manpage}`systemd.time(7)`). 352 ''; 353 }; 354 faxqclean.archiving = mkOption { 355 type = enum [ 356 "never" 357 "as-flagged" 358 "always" 359 ]; 360 default = "as-flagged"; 361 example = "always"; 362 description = '' 363 Enable or suppress job archiving: 364 `never` disables job archiving, 365 `as-flagged` archives jobs that 366 have been flagged for archiving by sendfax, 367 `always` forces archiving of all jobs. 368 See also {manpage}`sendfax(1)` and {manpage}`faxqclean(8)`. 369 ''; 370 }; 371 faxqclean.doneqMinutes = mkOption { 372 type = ints.positive; 373 default = 15; 374 example = literalExpression "24*60"; 375 description = '' 376 Set the job 377 age threshold (in minutes) that controls how long 378 jobs may reside in the doneq directory. 379 ''; 380 }; 381 faxqclean.docqMinutes = mkOption { 382 type = ints.positive; 383 default = 60; 384 example = literalExpression "24*60"; 385 description = '' 386 Set the document 387 age threshold (in minutes) that controls how long 388 unreferenced files may reside in the docq directory. 389 ''; 390 }; 391 392 }; 393 394 config.services.hylafax = mkIf (config.services.hylafax.enable) (mkMerge [ 395 defaultConfig 396 localConfig 397 ]); 398 399}