1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.asterisk;
7
8 asteriskUser = "asterisk";
9
10 varlibdir = "/var/lib/asterisk";
11 spooldir = "/var/spool/asterisk";
12 logdir = "/var/log/asterisk";
13
14 asteriskEtc = pkgs.stdenv.mkDerivation
15 ((mapAttrs' (name: value: nameValuePair
16 # Fudge the names to make bash happy
17 ((replaceChars ["."] ["_"] name) + "_")
18 (value)
19 ) cfg.confFiles) //
20 {
21 confFilesString = concatStringsSep " " (
22 attrNames cfg.confFiles
23 );
24
25 name = "asterisk.etc";
26
27 # Default asterisk.conf file
28 # (Notice that astetcdir will be set to the path of this derivation)
29 asteriskConf = ''
30 [directories]
31 astetcdir => @out@
32 astmoddir => ${pkgs.asterisk}/lib/asterisk/modules
33 astvarlibdir => /var/lib/asterisk
34 astdbdir => /var/lib/asterisk
35 astkeydir => /var/lib/asterisk
36 astdatadir => /var/lib/asterisk
37 astagidir => /var/lib/asterisk/agi-bin
38 astspooldir => /var/spool/asterisk
39 astrundir => /var/run/asterisk
40 astlogdir => /var/log/asterisk
41 astsbindir => ${pkgs.asterisk}/sbin
42 '';
43 extraConf = cfg.extraConfig;
44
45 # Loading all modules by default is considered sensible by the authors of
46 # "Asterisk: The Definitive Guide". Secure sites will likely want to
47 # specify their own "modules.conf" in the confFiles option.
48 modulesConf = ''
49 [modules]
50 autoload=yes
51 '';
52
53 # Use syslog for logging so logs can be viewed with journalctl
54 loggerConf = ''
55 [general]
56
57 [logfiles]
58 syslog.local0 => notice,warning,error
59 '';
60
61 buildCommand = ''
62 mkdir -p "$out"
63
64 # Create asterisk.conf, pointing astetcdir to the path of this derivation
65 echo "$asteriskConf" | sed "s|@out@|$out|g" > "$out"/asterisk.conf
66 echo "$extraConf" >> "$out"/asterisk.conf
67
68 echo "$modulesConf" > "$out"/modules.conf
69
70 echo "$loggerConf" > "$out"/logger.conf
71
72 # Config files specified in confFiles option override all other files
73 for i in $confFilesString; do
74 conf=$(echo "$i"_ | sed 's/\./_/g')
75 echo "''${!conf}" > "$out"/"$i"
76 done
77 '';
78 });
79in
80
81{
82 options = {
83 services.asterisk = {
84 enable = mkOption {
85 type = types.bool;
86 default = false;
87 description = ''
88 Whether to enable the Asterisk PBX server.
89 '';
90 };
91
92 extraConfig = mkOption {
93 default = "";
94 type = types.lines;
95 example = ''
96 [options]
97 verbose=3
98 debug=3
99 '';
100 description = ''
101 Extra configuration options appended to the default
102 <literal>asterisk.conf</literal> file.
103 '';
104 };
105
106 confFiles = mkOption {
107 default = {};
108 type = types.attrsOf types.str;
109 example = literalExample
110 ''
111 {
112 "extensions.conf" = '''
113 [tests]
114 ; Dial 100 for "hello, world"
115 exten => 100,1,Answer()
116 same => n,Wait(1)
117 same => n,Playback(hello-world)
118 same => n,Hangup()
119
120 [softphones]
121 include => tests
122
123 [unauthorized]
124 ''';
125 "sip.conf" = '''
126 [general]
127 allowguest=no ; Require authentication
128 context=unauthorized ; Send unauthorized users to /dev/null
129 srvlookup=no ; Don't do DNS lookup
130 udpbindaddr=0.0.0.0 ; Listen on all interfaces
131 nat=force_rport,comedia ; Assume device is behind NAT
132
133 [softphone](!)
134 type=friend ; Match on username first, IP second
135 context=softphones ; Send to softphones context in
136 ; extensions.conf file
137 host=dynamic ; Device will register with asterisk
138 disallow=all ; Manually specify codecs to allow
139 allow=g722
140 allow=ulaw
141 allow=alaw
142
143 [myphone](softphone)
144 secret=GhoshevFew ; Change this password!
145 ''';
146 "logger.conf" = '''
147 [general]
148
149 [logfiles]
150 ; Add debug output to log
151 syslog.local0 => notice,warning,error,debug
152 ''';
153 }
154 '';
155 description = ''
156 Sets the content of config files (typically ending with
157 <literal>.conf</literal>) in the Asterisk configuration directory.
158
159 Note that if you want to change <literal>asterisk.conf</literal>, it
160 is preferable to use the <option>services.asterisk.extraConfig</option>
161 option over this option. If <literal>"asterisk.conf"</literal> is
162 specified with the <option>confFiles</option> option (not recommended),
163 you must be prepared to set your own <literal>astetcdir</literal>
164 path.
165
166 See
167 <link xlink:href="http://www.asterisk.org/community/documentation"/>
168 for more examples of what is possible here.
169 '';
170 };
171
172 extraArguments = mkOption {
173 default = [];
174 type = types.listOf types.str;
175 example =
176 [ "-vvvddd" "-e" "1024" ];
177 description = ''
178 Additional command line arguments to pass to Asterisk.
179 '';
180 };
181 };
182 };
183
184 config = mkIf cfg.enable {
185 users.extraUsers = singleton
186 { name = asteriskUser;
187 uid = config.ids.uids.asterisk;
188 description = "Asterisk daemon user";
189 home = varlibdir;
190 };
191
192 systemd.services.asterisk = {
193 description = ''
194 Asterisk PBX server
195 '';
196
197 wantedBy = [ "multi-user.target" ];
198
199 preStart = ''
200 # Copy skeleton directory tree to /var
201 for d in '${varlibdir}' '${spooldir}' '${logdir}'; do
202 # TODO: Make exceptions for /var directories that likely should be updated
203 if [ ! -e "$d" ]; then
204 mkdir -p "$d"
205 cp --recursive ${pkgs.asterisk}/"$d" "$d"
206 chown --recursive ${asteriskUser} "$d"
207 find "$d" -type d | xargs chmod 0755
208 fi
209 done
210 '';
211
212 serviceConfig = {
213 ExecStart =
214 let
215 # FIXME: This doesn't account for arguments with spaces
216 argString = concatStringsSep " " cfg.extraArguments;
217 in
218 "${pkgs.asterisk}/bin/asterisk -U ${asteriskUser} -C ${asteriskEtc}/asterisk.conf ${argString} -F";
219 Type = "forking";
220 PIDFile = "/var/run/asterisk/asterisk.pid";
221 };
222 };
223 };
224}