|
|
|
@@ -17,6 +17,7 @@ |
17 | #include "wydawca.h" |
17 | #include "wydawca.h" |
18 | #include <mail.h> |
18 | #include <mail.h> |
19 | #include <hash.h> |
19 | #include <hash.h> |
| |
20 | #include <gpgme.h> |
20 | |
21 | |
21 | int mailer_opened; |
22 | int mailer_opened; |
22 | mu_mailer_t mailer; |
23 | mu_mailer_t mailer; |
@@ -27,6 +28,7 @@ unsigned long owner_notification_flags; |
27 | char *user_message_template[MAX_EVENT]; |
28 | char *user_message_template[MAX_EVENT]; |
28 | |
29 | |
29 | char *admin_stat_message; |
30 | char *admin_stat_message; |
| |
31 | char *admin_stat_sign_key; |
30 | |
32 | |
31 | void |
33 | void |
32 | mail_init () |
34 | mail_init () |
@@ -44,8 +46,203 @@ mail_init () |
44 | } |
46 | } |
45 | } |
47 | } |
46 | |
48 | |
| |
49 | struct mu_stream_handle |
| |
50 | { |
| |
51 | mu_stream_t str; |
| |
52 | mu_off_t off; |
| |
53 | }; |
| |
54 | |
| |
55 | static ssize_t |
| |
56 | mu_stream_data_read_cb (void *handle, void *buffer, size_t size) |
| |
57 | { |
| |
58 | struct mu_stream_handle *mhp = handle; |
| |
59 | size_t nread; |
| |
60 | int rc; |
| |
61 | |
| |
62 | rc = mu_stream_read (mhp->str, buffer, size, mhp->off, &nread); |
| |
63 | if (rc) |
| |
64 | { |
| |
65 | logmsg (LOG_ERR, "mu_stream_read: %s", mu_strerror (rc)); |
| |
66 | errno = EIO; |
| |
67 | return -1; |
| |
68 | } |
| |
69 | |
| |
70 | mhp->off += nread; |
| |
71 | return nread; |
| |
72 | } |
| |
73 | |
| |
74 | static int |
| |
75 | gpg_sign (gpgme_data_t *output, gpgme_data_t input, const char *sign_keys) |
| |
76 | { |
| |
77 | gpgme_ctx_t ctx; |
| |
78 | gpgme_error_t err = 0; |
| |
79 | gpgme_key_t key; |
| |
80 | |
| |
81 | err = gpgme_new (&ctx); |
| |
82 | if (err) |
| |
83 | { |
| |
84 | logmsg (LOG_ERR, _("GPGME: cannot create context: %s"), |
| |
85 | gpgme_strerror (err)); |
| |
86 | return 1; |
| |
87 | } |
| |
88 | |
| |
89 | err = gpgme_op_keylist_start (ctx, sign_keys, 0); |
| |
90 | if (!err) |
| |
91 | { |
| |
92 | while ((err = gpgme_op_keylist_next (ctx, &key)) == 0) |
| |
93 | { |
| |
94 | err = gpgme_signers_add (ctx, key); |
| |
95 | gpgme_key_release (key); |
| |
96 | } |
| |
97 | } |
| |
98 | |
| |
99 | if (err && gpg_err_code (err) != GPG_ERR_EOF) |
| |
100 | { |
| |
101 | logmsg (LOG_ERR, _("GPGME: cannot list keys: %s"), |
| |
102 | gpgme_strerror (err)); |
| |
103 | gpgme_release (ctx); |
| |
104 | return 1; |
| |
105 | } |
| |
106 | |
| |
107 | err = gpgme_data_new (output); |
| |
108 | if (err) |
| |
109 | { |
| |
110 | logmsg (LOG_ERR, _("%s: GPGME error: %s"), |
| |
111 | "gpgme_data_new", |
| |
112 | gpgme_strerror (err)); |
| |
113 | gpgme_release (ctx); |
| |
114 | return 1; |
| |
115 | } |
| |
116 | |
| |
117 | /* FIXME: Passphrase */ |
| |
118 | gpgme_set_textmode (ctx, 1); |
| |
119 | gpgme_set_armor (ctx, 1); |
| |
120 | |
| |
121 | err = gpgme_op_sign (ctx, input, *output, GPGME_SIG_MODE_CLEAR); |
| |
122 | if (err) |
| |
123 | logmsg (LOG_ERR, _("%s: GPGME error: %s"), |
| |
124 | "gpgme_op_sign", |
| |
125 | gpgme_strerror (err)); |
| |
126 | #if 0 |
| |
127 | /* FIXME: */ |
| |
128 | else if (debug_level > 1) |
| |
129 | gpgme_debug_info (ctx); |
| |
130 | #endif |
| |
131 | |
| |
132 | gpgme_release (ctx); |
| |
133 | return err != 0; |
| |
134 | } |
| |
135 | |
| |
136 | static int |
| |
137 | sign_message (mu_message_t *pmsg, const char *key) |
| |
138 | { |
| |
139 | mu_message_t msg = *pmsg; |
| |
140 | mu_message_t newmsg; |
| |
141 | mu_body_t body; |
| |
142 | mu_header_t hdr; |
| |
143 | struct mu_stream_handle mhn; |
| |
144 | mu_stream_t istr, ostr; |
| |
145 | int rc; |
| |
146 | struct gpgme_data_cbs cbs; |
| |
147 | gpgme_data_t input, output; |
| |
148 | gpgme_error_t err; |
| |
149 | char *buf = NULL; |
| |
150 | size_t size = 0; |
| |
151 | size_t nread; |
| |
152 | |
| |
153 | if (debug_level) |
| |
154 | logmsg (LOG_DEBUG, _("signing message as %s"), key); |
| |
155 | |
| |
156 | if (wydawca_gpg_homedir) |
| |
157 | { |
| |
158 | if (debug_level > 1) |
| |
159 | logmsg (LOG_DEBUG, _("setting GNUPG home directory: %s"), |
| |
160 | wydawca_gpg_homedir); |
| |
161 | setenv ("GNUPGHOME", wydawca_gpg_homedir, 1); |
| |
162 | } |
| |
163 | |
| |
164 | if ((rc = mu_message_get_body (msg, &body))) |
| |
165 | { |
| |
166 | logmsg (LOG_ERR, "mu_message_get_body: %s", mu_strerror (rc)); |
| |
167 | return 1; |
| |
168 | } |
| |
169 | |
| |
170 | if ((rc = mu_body_get_stream (body, &mhn.str))) |
| |
171 | { |
| |
172 | logmsg (LOG_ERR, "mu_message_get_stream: %s", mu_strerror (rc)); |
| |
173 | return 1; |
| |
174 | } |
| |
175 | |
| |
176 | mu_stream_seek (mhn.str, 0, SEEK_SET); |
| |
177 | mhn.off = 0; |
| |
178 | |
| |
179 | memset (&cbs, 0, sizeof (cbs)); |
| |
180 | cbs.read = mu_stream_data_read_cb; |
| |
181 | |
| |
182 | err = gpgme_data_new_from_cbs (&input, &cbs, &mhn); |
| |
183 | if (err) |
| |
184 | { |
| |
185 | logmsg (LOG_ERR, "gpgme_data_new_from_cbs: %s", |
| |
186 | gpgme_strerror (rc)); |
| |
187 | return 1; |
| |
188 | } |
| |
189 | |
| |
190 | rc = gpg_sign (&output, input, key); |
| |
191 | |
| |
192 | if (gpgme_data_seek (output, 0, SEEK_SET) == -1) |
| |
193 | { |
| |
194 | logmsg (LOG_ERR, "gpgme_data_seek: %s", strerror (errno)); |
| |
195 | return 1; |
| |
196 | } |
| |
197 | |
| |
198 | mu_message_create (&newmsg, NULL); |
| |
199 | mu_message_get_stream (newmsg, &ostr); |
| |
200 | |
| |
201 | /* Copy headers */ |
| |
202 | mu_message_get_header (msg, &hdr); |
| |
203 | mu_header_get_stream (hdr, &istr); |
| |
204 | mu_stream_seek (istr, 0, SEEK_SET); |
| |
205 | while ((rc = mu_stream_sequential_getline (istr, &buf, &size, &nread)) == 0 |
| |
206 | && nread) |
| |
207 | { |
| |
208 | rc = mu_stream_sequential_write (ostr, buf, nread); |
| |
209 | if (rc) |
| |
210 | { |
| |
211 | logmsg (LOG_ERR, "mu_stream_sequential_write: %s", |
| |
212 | mu_strerror (rc)); |
| |
213 | break; |
| |
214 | } |
| |
215 | } |
| |
216 | |
| |
217 | if (rc == 0) |
| |
218 | { |
| |
219 | while ((nread = gpgme_data_read (output, buf, size)) > 0) |
| |
220 | { |
| |
221 | rc = mu_stream_sequential_write (ostr, buf, nread); |
| |
222 | if (rc) |
| |
223 | { |
| |
224 | logmsg (LOG_ERR, "mu_stream_sequential_write: %s", |
| |
225 | mu_strerror (rc)); |
| |
226 | break; |
| |
227 | } |
| |
228 | } |
| |
229 | |
| |
230 | if (rc == 0) |
| |
231 | { |
| |
232 | mu_message_destroy (&msg, mu_message_get_owner (msg)); |
| |
233 | *pmsg = newmsg; |
| |
234 | } |
| |
235 | } |
| |
236 | |
| |
237 | gpgme_data_release (output); |
| |
238 | free (buf); |
| |
239 | |
| |
240 | return rc; |
| |
241 | } |
| |
242 | |
47 | void |
243 | void |
48 | mail_send_message (mu_address_t rcpt, const char *text) |
244 | mail_send_message (mu_address_t rcpt, const char *text, |
| |
245 | const char *signer_key) |
49 | { |
246 | { |
50 | int rc; |
247 | int rc; |
51 | mu_message_t msg; |
248 | mu_message_t msg; |
@@ -91,7 +288,7 @@ mail_send_message (mu_address_t rcpt, const char *text) |
91 | if (debug_level > 2) |
288 | if (debug_level > 2) |
92 | mailer_flags = MAILER_FLAG_DEBUG_DATA; |
289 | mailer_flags = MAILER_FLAG_DEBUG_DATA; |
93 | } |
290 | } |
94 | |
291 | |
95 | if (!mailer_opened) |
292 | if (!mailer_opened) |
96 | { |
293 | { |
97 | if ((rc = mu_mailer_open (mailer, mailer_flags))) |
294 | if ((rc = mu_mailer_open (mailer, mailer_flags))) |
@@ -106,10 +303,16 @@ mail_send_message (mu_address_t rcpt, const char *text) |
106 | mailer_opened = 1; |
303 | mailer_opened = 1; |
107 | } |
304 | } |
108 | |
305 | |
109 | rc = mu_mailer_send_message (mailer, msg, from_address, rcpt); |
306 | if (signer_key) |
110 | if (rc) |
307 | sign_message (&msg, signer_key); |
111 | logmsg (LOG_CRIT, _("cannot send message: %s"), mu_strerror (rc)); |
308 | |
112 | |
309 | if (!dry_run_mode) |
| |
310 | { |
| |
311 | rc = mu_mailer_send_message (mailer, msg, from_address, rcpt); |
| |
312 | if (rc) |
| |
313 | logmsg (LOG_CRIT, _("cannot send message: %s"), mu_strerror (rc)); |
| |
314 | } |
| |
315 | |
113 | mu_message_destroy (&msg, mu_message_get_owner (msg)); |
316 | mu_message_destroy (&msg, mu_message_get_owner (msg)); |
114 | } |
317 | } |
115 | |
318 | |
@@ -244,9 +447,6 @@ mail_stats () |
244 | free (buf); |
447 | free (buf); |
245 | } |
448 | } |
246 | |
449 | |
247 | if (dry_run_mode) |
| |
248 | return; |
| |
249 | |
| |
250 | tc = timer_get_count () * 3; |
450 | tc = timer_get_count () * 3; |
251 | exp = make_stat_expansion (tc + 1); |
451 | exp = make_stat_expansion (tc + 1); |
252 | time (&t); |
452 | time (&t); |
@@ -264,7 +464,7 @@ mail_stats () |
264 | } |
464 | } |
265 | text = meta_expand_string (tmpl, exp, NULL, NULL, NULL); |
465 | text = meta_expand_string (tmpl, exp, NULL, NULL, NULL); |
266 | |
466 | |
267 | mail_send_message (admin_address, text); |
467 | mail_send_message (admin_address, text, admin_stat_sign_key); |
268 | |
468 | |
269 | free (text); |
469 | free (text); |
270 | meta_free (exp); |
470 | meta_free (exp); |
@@ -366,6 +566,8 @@ do_notify (struct file_triplet *trp, enum notification_event ev, |
366 | { |
566 | { |
367 | mu_address_t rcpt = NULL; |
567 | mu_address_t rcpt = NULL; |
368 | const char *errp; |
568 | const char *errp; |
| |
569 | const char *msg; |
| |
570 | |
369 | switch (ntf->tgt) |
571 | switch (ntf->tgt) |
370 | { |
572 | { |
371 | case notify_read: |
573 | case notify_read: |
@@ -408,21 +610,19 @@ do_notify (struct file_triplet *trp, enum notification_event ev, |
408 | free (buf); |
610 | free (buf); |
409 | } |
611 | } |
410 | else |
612 | else |
411 | logmsg (LOG_DEBUG, _("notifying message recipients (project %s) about %s"), |
613 | logmsg (LOG_DEBUG, |
| |
614 | _("notifying message recipients (project %s) about %s"), |
412 | trp->project, notification_event_str (ev)); |
615 | trp->project, notification_event_str (ev)); |
413 | } |
616 | } |
414 | |
617 | |
415 | if (!dry_run_mode) |
618 | msg = resolve_message_template (ntf->msg); |
| |
619 | if (!msg) |
| |
620 | logmsg (LOG_ERR, _("undefined message reference: %s"), ntf->msg); |
| |
621 | else |
416 | { |
622 | { |
417 | const char *msg = resolve_message_template (ntf->msg); |
623 | char *text = triplet_expand_param (msg, trp); |
418 | if (!msg) |
624 | mail_send_message (rcpt, text, ntf->sign_keys); |
419 | logmsg (LOG_ERR, _("undefined message reference: %s"), ntf->msg); |
625 | free (text); |
420 | else |
| |
421 | { |
| |
422 | char *text = triplet_expand_param (msg, trp); |
| |
423 | mail_send_message (rcpt, text); |
| |
424 | free (text); |
| |
425 | } |
| |
426 | } |
626 | } |
427 | |
627 | |
428 | mu_address_destroy (&rcpt); |
628 | mu_address_destroy (&rcpt); |
|