1{ lib, config, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.znc;
8
9 networkOpts = {
10 options = {
11
12 server = mkOption {
13 type = types.str;
14 example = "chat.freenode.net";
15 description = ''
16 IRC server address.
17 '';
18 };
19
20 port = mkOption {
21 type = types.ints.u16;
22 default = 6697;
23 description = ''
24 IRC server port.
25 '';
26 };
27
28 password = mkOption {
29 type = types.str;
30 default = "";
31 description = ''
32 IRC server password, such as for a Slack gateway.
33 '';
34 };
35
36 useSSL = mkOption {
37 type = types.bool;
38 default = true;
39 description = ''
40 Whether to use SSL to connect to the IRC server.
41 '';
42 };
43
44 modules = mkOption {
45 type = types.listOf types.str;
46 default = [ "simple_away" ];
47 example = literalExample ''[ "simple_away" "sasl" ]'';
48 description = ''
49 ZNC network modules to load.
50 '';
51 };
52
53 channels = mkOption {
54 type = types.listOf types.str;
55 default = [];
56 example = [ "nixos" ];
57 description = ''
58 IRC channels to join.
59 '';
60 };
61
62 hasBitlbeeControlChannel = mkOption {
63 type = types.bool;
64 default = false;
65 description = ''
66 Whether to add the special Bitlbee operations channel.
67 '';
68 };
69
70 extraConf = mkOption {
71 default = "";
72 type = types.lines;
73 example = ''
74 Encoding = ^UTF-8
75 FloodBurst = 4
76 FloodRate = 1.00
77 IRCConnectEnabled = true
78 Ident = johntron
79 JoinDelay = 0
80 Nick = johntron
81 '';
82 description = ''
83 Extra config for the network. Consider using
84 <option>services.znc.config</option> instead.
85 '';
86 };
87 };
88 };
89
90in
91
92{
93
94 options = {
95 services.znc = {
96
97 useLegacyConfig = mkOption {
98 default = true;
99 type = types.bool;
100 description = ''
101 Whether to propagate the legacy options under
102 <option>services.znc.confOptions.*</option> to the znc config. If this
103 is turned on, the znc config will contain a user with the default name
104 "znc", global modules "webadmin" and "adminlog" will be enabled by
105 default, and more, all controlled through the
106 <option>services.znc.confOptions.*</option> options.
107 You can use <command>nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.services.znc.config</command>
108 to view the current value of the config.
109 </para>
110 <para>
111 In any case, if you need more flexibility,
112 <option>services.znc.config</option> can be used to override/add to
113 all of the legacy options.
114 '';
115 };
116
117 confOptions = {
118 modules = mkOption {
119 type = types.listOf types.str;
120 default = [ "webadmin" "adminlog" ];
121 example = [ "partyline" "webadmin" "adminlog" "log" ];
122 description = ''
123 A list of modules to include in the `znc.conf` file.
124 '';
125 };
126
127 userModules = mkOption {
128 type = types.listOf types.str;
129 default = [ "chansaver" "controlpanel" ];
130 example = [ "chansaver" "controlpanel" "fish" "push" ];
131 description = ''
132 A list of user modules to include in the `znc.conf` file.
133 '';
134 };
135
136 userName = mkOption {
137 default = "znc";
138 example = "johntron";
139 type = types.str;
140 description = ''
141 The user name used to log in to the ZNC web admin interface.
142 '';
143 };
144
145 networks = mkOption {
146 default = { };
147 type = with types; attrsOf (submodule networkOpts);
148 description = ''
149 IRC networks to connect the user to.
150 '';
151 example = literalExample ''
152 {
153 "freenode" = {
154 server = "chat.freenode.net";
155 port = 6697;
156 useSSL = true;
157 modules = [ "simple_away" ];
158 };
159 };
160 '';
161 };
162
163 nick = mkOption {
164 default = "znc-user";
165 example = "john";
166 type = types.str;
167 description = ''
168 The IRC nick.
169 '';
170 };
171
172 passBlock = mkOption {
173 example = literalExample ''
174 <Pass password>
175 Method = sha256
176 Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93
177 Salt = l5Xryew4g*!oa(ECfX2o
178 </Pass>
179 '';
180 type = types.str;
181 description = ''
182 Generate with `nix-shell -p znc --command "znc --makepass"`.
183 This is the password used to log in to the ZNC web admin interface.
184 You can also set this through
185 <option>services.znc.config.User.<username>.Pass.Method</option>
186 and co.
187 '';
188 };
189
190 port = mkOption {
191 default = 5000;
192 type = types.int;
193 description = ''
194 Specifies the port on which to listen.
195 '';
196 };
197
198 useSSL = mkOption {
199 default = true;
200 type = types.bool;
201 description = ''
202 Indicates whether the ZNC server should use SSL when listening on
203 the specified port. A self-signed certificate will be generated.
204 '';
205 };
206
207 uriPrefix = mkOption {
208 type = types.nullOr types.str;
209 default = null;
210 example = "/znc/";
211 description = ''
212 An optional URI prefix for the ZNC web interface. Can be
213 used to make ZNC available behind a reverse proxy.
214 '';
215 };
216
217 extraZncConf = mkOption {
218 default = "";
219 type = types.lines;
220 description = ''
221 Extra config to `znc.conf` file.
222 '';
223 };
224 };
225
226 };
227 };
228
229 config = mkIf cfg.useLegacyConfig {
230
231 services.znc.config = let
232 c = cfg.confOptions;
233 # defaults here should override defaults set in the non-legacy part
234 mkDefault = mkOverride 900;
235 in {
236 LoadModule = mkDefault c.modules;
237 Listener.l = {
238 Port = mkDefault c.port;
239 IPv4 = mkDefault true;
240 IPv6 = mkDefault true;
241 SSL = mkDefault c.useSSL;
242 URIPrefix = c.uriPrefix;
243 };
244 User.${c.userName} = {
245 Admin = mkDefault true;
246 Nick = mkDefault c.nick;
247 AltNick = mkDefault "${c.nick}_";
248 Ident = mkDefault c.nick;
249 RealName = mkDefault c.nick;
250 LoadModule = mkDefault c.userModules;
251 Network = mapAttrs (name: net: {
252 LoadModule = mkDefault net.modules;
253 Server = mkDefault "${net.server} ${optionalString net.useSSL "+"}${toString net.port} ${net.password}";
254 Chan = optionalAttrs net.hasBitlbeeControlChannel { "&bitlbee" = mkDefault {}; } //
255 listToAttrs (map (n: nameValuePair "#${n}" (mkDefault {})) net.channels);
256 extraConfig = if net.extraConf == "" then mkDefault null else net.extraConf;
257 }) c.networks;
258 extraConfig = [ c.passBlock ];
259 };
260 extraConfig = optional (c.extraZncConf != "") c.extraZncConf;
261 };
262 };
263
264 imports = [
265 (mkRemovedOptionModule ["services" "znc" "zncConf"] ''
266 Instead of `services.znc.zncConf = "... foo ...";`, use
267 `services.znc.configFile = pkgs.writeText "znc.conf" "... foo ...";`.
268 '')
269 ];
270}