at 25.11-pre 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 ''"''${pkgs.postfix}/bin/sendmail"''; 225 # '' ; # fix vim 226 description = '' 227 Path to {file}`sendmail` program. 228 The default uses the local sendmail wrapper 229 (see {option}`config.services.mail.sendmailSetuidWrapper`), 230 otherwise the {file}`false` 231 binary to cause an error if used. 232 ''; 233 }; 234 235 hfaxdConfig = mkOption { 236 type = configAttrType; 237 example.RecvqProtection = "0400"; 238 description = '' 239 Attribute set of lines for the global 240 hfaxd config file {file}`etc/hfaxd.conf`. 241 ${commonDescr} 242 ''; 243 }; 244 245 faxqConfig = mkOption { 246 type = configAttrType; 247 example = { 248 InternationalPrefix = "00"; 249 LongDistancePrefix = "0"; 250 }; 251 description = '' 252 Attribute set of lines for the global 253 faxq config file {file}`etc/config`. 254 ${commonDescr} 255 ''; 256 }; 257 258 commonModemConfig = mkOption { 259 type = configAttrType; 260 example = { 261 InternationalPrefix = "00"; 262 LongDistancePrefix = "0"; 263 }; 264 description = '' 265 Attribute set of default values for 266 modem config files {file}`etc/config.*`. 267 ${commonDescr} 268 Think twice before changing 269 paths of fax-processing scripts. 270 ''; 271 }; 272 273 modems = mkOption { 274 type = attrsOf (submodule [ modemConfigOptions ]); 275 default = { }; 276 example.ttyS1 = { 277 type = "cirrus"; 278 config = { 279 FAXNumber = "123456"; 280 LocalIdentifier = "Smith"; 281 }; 282 }; 283 description = '' 284 Description of installed modems. 285 At least on modem must be defined 286 to enable the HylaFAX server. 287 ''; 288 }; 289 290 spoolExtraInit = mkOption { 291 type = lines; 292 default = ""; 293 example = "chmod 0755 . # everyone may read my faxes"; 294 description = '' 295 Additional shell code that is executed within the 296 spooling area directory right after its setup. 297 ''; 298 }; 299 300 faxcron.enable.spoolInit = mkEnableOption '' 301 purging old files from the spooling area with 302 {file}`faxcron` 303 each time the spooling area is initialized 304 ''; 305 faxcron.enable.frequency = mkOption { 306 type = nullOr nonEmptyStr; 307 default = null; 308 example = "daily"; 309 description = '' 310 purging old files from the spooling area with 311 {file}`faxcron` with the given frequency 312 (see {manpage}`systemd.time(7)`) 313 ''; 314 }; 315 faxcron.infoDays = mkOption { 316 type = ints.positive; 317 default = 30; 318 description = '' 319 Set the expiration time for data in the 320 remote machine information directory in days. 321 ''; 322 }; 323 faxcron.logDays = mkOption { 324 type = ints.positive; 325 default = 30; 326 description = '' 327 Set the expiration time for 328 session trace log files in days. 329 ''; 330 }; 331 faxcron.rcvDays = mkOption { 332 type = ints.positive; 333 default = 7; 334 description = '' 335 Set the expiration time for files in 336 the received facsimile queue in days. 337 ''; 338 }; 339 340 faxqclean.enable.spoolInit = mkEnableOption '' 341 purging old files from the spooling area with 342 {file}`faxqclean` 343 each time the spooling area is initialized 344 ''; 345 faxqclean.enable.frequency = mkOption { 346 type = nullOr nonEmptyStr; 347 default = null; 348 example = "daily"; 349 description = '' 350 Purge old files from the spooling area with 351 {file}`faxcron` with the given frequency 352 (see {manpage}`systemd.time(7)`). 353 ''; 354 }; 355 faxqclean.archiving = mkOption { 356 type = enum [ 357 "never" 358 "as-flagged" 359 "always" 360 ]; 361 default = "as-flagged"; 362 example = "always"; 363 description = '' 364 Enable or suppress job archiving: 365 `never` disables job archiving, 366 `as-flagged` archives jobs that 367 have been flagged for archiving by sendfax, 368 `always` forces archiving of all jobs. 369 See also {manpage}`sendfax(1)` and {manpage}`faxqclean(8)`. 370 ''; 371 }; 372 faxqclean.doneqMinutes = mkOption { 373 type = ints.positive; 374 default = 15; 375 example = literalExpression "24*60"; 376 description = '' 377 Set the job 378 age threshold (in minutes) that controls how long 379 jobs may reside in the doneq directory. 380 ''; 381 }; 382 faxqclean.docqMinutes = mkOption { 383 type = ints.positive; 384 default = 60; 385 example = literalExpression "24*60"; 386 description = '' 387 Set the document 388 age threshold (in minutes) that controls how long 389 unreferenced files may reside in the docq directory. 390 ''; 391 }; 392 393 }; 394 395 config.services.hylafax = mkIf (config.services.hylafax.enable) (mkMerge [ 396 defaultConfig 397 localConfig 398 ]); 399 400}