1{
2 pkgs,
3 lib,
4 config,
5 ...
6}:
7let
8 cfg = config.services.gammu-smsd;
9
10 configFile = pkgs.writeText "gammu-smsd.conf" ''
11 [gammu]
12 Device = ${cfg.device.path}
13 Connection = ${cfg.device.connection}
14 SynchronizeTime = ${if cfg.device.synchronizeTime then "yes" else "no"}
15 LogFormat = ${cfg.log.format}
16 ${lib.optionalString (cfg.device.pin != null) "PIN = ${cfg.device.pin}"}
17 ${cfg.extraConfig.gammu}
18
19
20 [smsd]
21 LogFile = ${cfg.log.file}
22 Service = ${cfg.backend.service}
23
24 ${lib.optionalString (cfg.backend.service == "files") ''
25 InboxPath = ${cfg.backend.files.inboxPath}
26 OutboxPath = ${cfg.backend.files.outboxPath}
27 SentSMSPath = ${cfg.backend.files.sentSMSPath}
28 ErrorSMSPath = ${cfg.backend.files.errorSMSPath}
29 ''}
30
31 ${lib.optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") ''
32 Driver = ${cfg.backend.sql.driver}
33 DBDir = ${cfg.backend.sql.database}
34 ''}
35
36 ${lib.optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") (
37 with cfg.backend;
38 ''
39 Driver = ${sql.driver}
40 ${lib.optionalString (sql.database != null) "Database = ${sql.database}"}
41 ${lib.optionalString (sql.host != null) "Host = ${sql.host}"}
42 ${lib.optionalString (sql.user != null) "User = ${sql.user}"}
43 ${lib.optionalString (sql.password != null) "Password = ${sql.password}"}
44 ''
45 )}
46
47 ${cfg.extraConfig.smsd}
48 '';
49
50 initDBDir = "share/doc/gammu/examples/sql";
51
52 gammuPackage =
53 with cfg.backend;
54 (pkgs.gammu.override {
55 dbiSupport = service == "sql" && sql.driver == "sqlite";
56 postgresSupport = service == "sql" && sql.driver == "native_pgsql";
57 });
58
59in
60{
61 options = {
62 services.gammu-smsd = {
63
64 enable = lib.mkEnableOption "gammu-smsd daemon";
65
66 user = lib.mkOption {
67 type = lib.types.str;
68 default = "smsd";
69 description = "User that has access to the device";
70 };
71
72 device = {
73 path = lib.mkOption {
74 type = lib.types.path;
75 description = "Device node or address of the phone";
76 example = "/dev/ttyUSB2";
77 };
78
79 group = lib.mkOption {
80 type = lib.types.str;
81 default = "root";
82 description = "Owner group of the device";
83 example = "dialout";
84 };
85
86 connection = lib.mkOption {
87 type = lib.types.str;
88 default = "at";
89 description = "Protocol which will be used to talk to the phone";
90 };
91
92 synchronizeTime = lib.mkOption {
93 type = lib.types.bool;
94 default = true;
95 description = "Whether to set time from computer to the phone during starting connection";
96 };
97
98 pin = lib.mkOption {
99 type = lib.types.nullOr lib.types.str;
100 default = null;
101 description = "PIN code for the simcard";
102 };
103 };
104
105 log = {
106 file = lib.mkOption {
107 type = lib.types.str;
108 default = "syslog";
109 description = "Path to file where information about communication will be stored";
110 };
111
112 format = lib.mkOption {
113 type = lib.types.enum [
114 "nothing"
115 "text"
116 "textall"
117 "textalldate"
118 "errors"
119 "errorsdate"
120 "binary"
121 ];
122 default = "errors";
123 description = "Determines what will be logged to the LogFile";
124 };
125 };
126
127 extraConfig = {
128 gammu = lib.mkOption {
129 type = lib.types.lines;
130 default = "";
131 description = "Extra config lines to be added into [gammu] section";
132 };
133
134 smsd = lib.mkOption {
135 type = lib.types.lines;
136 default = "";
137 description = "Extra config lines to be added into [smsd] section";
138 };
139 };
140
141 backend = {
142 service = lib.mkOption {
143 type = lib.types.enum [
144 "null"
145 "files"
146 "sql"
147 ];
148 default = "null";
149 description = "Service to use to store sms data.";
150 };
151
152 files = {
153 inboxPath = lib.mkOption {
154 type = lib.types.path;
155 default = "/var/spool/sms/inbox/";
156 description = "Where the received SMSes are stored";
157 };
158
159 outboxPath = lib.mkOption {
160 type = lib.types.path;
161 default = "/var/spool/sms/outbox/";
162 description = "Where SMSes to be sent should be placed";
163 };
164
165 sentSMSPath = lib.mkOption {
166 type = lib.types.path;
167 default = "/var/spool/sms/sent/";
168 description = "Where the transmitted SMSes are placed";
169 };
170
171 errorSMSPath = lib.mkOption {
172 type = lib.types.path;
173 default = "/var/spool/sms/error/";
174 description = "Where SMSes with error in transmission is placed";
175 };
176 };
177
178 sql = {
179 driver = lib.mkOption {
180 type = lib.types.enum [
181 "native_mysql"
182 "native_pgsql"
183 "odbc"
184 "dbi"
185 ];
186 description = "DB driver to use";
187 };
188
189 sqlDialect = lib.mkOption {
190 type = lib.types.nullOr lib.types.str;
191 default = null;
192 description = "SQL dialect to use (odbc driver only)";
193 };
194
195 database = lib.mkOption {
196 type = lib.types.nullOr lib.types.str;
197 default = null;
198 description = "Database name to store sms data";
199 };
200
201 host = lib.mkOption {
202 type = lib.types.str;
203 default = "localhost";
204 description = "Database server address";
205 };
206
207 user = lib.mkOption {
208 type = lib.types.nullOr lib.types.str;
209 default = null;
210 description = "User name used for connection to the database";
211 };
212
213 password = lib.mkOption {
214 type = lib.types.nullOr lib.types.str;
215 default = null;
216 description = "User password used for connection to the database";
217 };
218 };
219 };
220 };
221 };
222
223 config = lib.mkIf cfg.enable {
224 users.users.${cfg.user} = {
225 description = "gammu-smsd user";
226 isSystemUser = true;
227 group = cfg.device.group;
228 };
229
230 environment.systemPackages =
231 with cfg.backend;
232 [ gammuPackage ] ++ lib.optionals (service == "sql" && sql.driver == "sqlite") [ pkgs.sqlite ];
233
234 systemd.services.gammu-smsd = {
235 description = "gammu-smsd daemon";
236
237 wantedBy = [ "multi-user.target" ];
238
239 wants =
240 with cfg.backend;
241 [ ] ++ lib.optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ];
242
243 preStart =
244 with cfg.backend;
245
246 lib.optionalString (service == "files") (
247 with files;
248 ''
249 mkdir -m 755 -p ${inboxPath} ${outboxPath} ${sentSMSPath} ${errorSMSPath}
250 chown ${cfg.user} -R ${inboxPath}
251 chown ${cfg.user} -R ${outboxPath}
252 chown ${cfg.user} -R ${sentSMSPath}
253 chown ${cfg.user} -R ${errorSMSPath}
254 ''
255 )
256 + lib.optionalString (service == "sql" && sql.driver == "sqlite") ''
257 cat "${gammuPackage}/${initDBDir}/sqlite.sql" \
258 | ${pkgs.sqlite.bin}/bin/sqlite3 ${sql.database}
259 ''
260 + (
261 let
262 execPsql =
263 extraArgs:
264 lib.concatStringsSep " " [
265 (lib.optionalString (sql.password != null) "PGPASSWORD=${sql.password}")
266 "${config.services.postgresql.package}/bin/psql"
267 (lib.optionalString (sql.host != null) "-h ${sql.host}")
268 (lib.optionalString (sql.user != null) "-U ${sql.user}")
269 "$extraArgs"
270 "${sql.database}"
271 ];
272 in
273 lib.optionalString (service == "sql" && sql.driver == "native_pgsql") ''
274 echo '\i '"${gammuPackage}/${initDBDir}/pgsql.sql" | ${execPsql ""}
275 ''
276 );
277
278 serviceConfig = {
279 User = "${cfg.user}";
280 Group = "${cfg.device.group}";
281 PermissionsStartOnly = true;
282 ExecStart = "${gammuPackage}/bin/gammu-smsd -c ${configFile}";
283 };
284
285 };
286 };
287}