src/mn-webmail-mailbox.gob (9324B) - raw
1 /*
2 * Mail Notification
3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 %headertop{
21 #include "mn-authenticated-mailbox.h"
22 %}
23
24 %{
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <glib/gi18n.h>
32 #include <gmime/gmime.h>
33 #include "mn-mailbox-private.h"
34 #include "mn-authenticated-mailbox-private.h"
35 #include "mn-message-mime.h"
36 #include "mn-util.h"
37 %}
38
39 class MN:Webmail:Mailbox from MN:Authenticated:Mailbox (abstract)
40 {
41 classwide const char *default_domain;
42
43 public char *folder destroywith g_free;
44 property STRING folder (link,
45 flags = CONSTRUCT
46 | MN_MAILBOX_PARAM_LOAD_SAVE
47 | MN_MAILBOX_PARAM_REQUIRED,
48 default_value = "Inbox");
49
50 override (MN:Mailbox) void
51 seal (MNMailbox *mailbox)
52 {
53 MNAuthenticatedMailbox *auth_mailbox = MN_AUTHENTICATED_MAILBOX(mailbox);
54 Self *self = SELF(mailbox);
55
56 PARENT_HANDLER(mailbox);
57
58 if (! mailbox->runtime_name)
59 mailbox->runtime_name = self_build_name(SELF_GET_CLASS(self), MN_AUTHENTICATED_MAILBOX(mailbox)->username, self->folder);
60
61 if (! auth_mailbox->keyring_domain)
62 auth_mailbox->keyring_domain = g_strdup(MN_WEBMAIL_MAILBOX_CLASS(SELF_GET_CLASS(self))->default_domain);
63 }
64
65 protected void
66 parse_username (self, char **username (check null), char **domain (check null))
67 {
68 mn_authenticated_mailbox_parse_username(MN_AUTHENTICATED_MAILBOX(self), username, domain);
69 if (! *domain)
70 *domain = g_strdup(MN_WEBMAIL_MAILBOX_CLASS(SELF_GET_CLASS(self))->default_domain);
71 }
72
73 private int
74 create_temporary_file (char **filename (check null), GError **err)
75 {
76 int fd;
77 char *_filename;
78 GError *tmp_err = NULL;
79
80 /* GetLive chokes on the hyphen in "mail-notification", so use "mn" */
81 fd = g_file_open_tmp("mn.XXXXXX", &_filename, &tmp_err);
82 if (fd == -1)
83 {
84 g_set_error(err, 0, 0, _("unable to create a temporary file: %s"), tmp_err->message);
85 g_error_free(tmp_err);
86 return -1;
87 }
88
89 if (fchmod(fd, S_IRUSR | S_IWUSR) < 0)
90 {
91 g_set_error(err, 0, 0, _("unable to change the permissions of the temporary file: %s"), g_strerror(errno));
92 g_free(_filename);
93 close(fd);
94 return -1;
95 }
96
97 *filename = _filename;
98 return fd;
99 }
100
101 protected char *
102 create_spool_file (GError **err)
103 {
104 int fd;
105 char *filename;
106
107 fd = self_create_temporary_file(&filename, err);
108 if (fd == -1)
109 return NULL;
110
111 close(fd);
112
113 return filename;
114 }
115
116 protected char *
117 write_temporary_file (const char *contents (check null),
118 const char *encoding (check null),
119 GError **err)
120 {
121 int fd;
122 GError *tmp_err = NULL;
123 char *filename;
124 GIOChannel *channel;
125 gsize bytes_written;
126
127 fd = self_create_temporary_file(&filename, err);
128 if (fd == -1)
129 return NULL;
130
131 channel = g_io_channel_unix_new(fd);
132
133 if (g_io_channel_set_encoding(channel, encoding, &tmp_err) != G_IO_STATUS_NORMAL)
134 {
135 g_set_error(err, 0, 0, _("unable to set encoding of %s: %s"), filename, tmp_err->message);
136 goto error;
137 }
138
139 if (g_io_channel_write_chars(channel, contents, -1, &bytes_written, &tmp_err) != G_IO_STATUS_NORMAL)
140 {
141 g_set_error(err, 0, 0, _("unable to write to %s: %s"), filename, tmp_err->message);
142 goto error;
143 }
144
145 if (g_io_channel_shutdown(channel, TRUE, &tmp_err) != G_IO_STATUS_NORMAL)
146 {
147 g_set_error(err, 0, 0, _("unable to close %s: %s"), filename, tmp_err->message);
148 goto error_noshutdown;
149 }
150
151 g_io_channel_unref(channel);
152
153 return filename;
154
155 error:
156 g_io_channel_shutdown(channel, FALSE, NULL);
157 error_noshutdown:
158 g_io_channel_unref(channel);
159 g_free(filename);
160 return NULL;
161 }
162
163 virtual private char *
164 get_error_message (self,
165 const char *helper_stdout,
166 const char *helper_stderr,
167 gboolean *is_auth_failure (check null));
168
169 private void
170 print_multiline_text (self,
171 const char *text (check null),
172 const char *line_prefix (check null))
173 {
174 char **lines;
175 int i;
176
177 lines = g_strsplit(text, "\n", 0);
178 for (i = 0; lines[i]; i++)
179 {
180 // do not print the empty last line
181 if (! lines[i + 1] && ! lines[i][0])
182 break;
183
184 mn_mailbox_notice(MN_MAILBOX(self), "%s%s", line_prefix, lines[i]);
185 }
186 g_strfreev(lines);
187 }
188
189 protected void
190 print_config (self, const char *config (check null))
191 {
192 mn_mailbox_notice(MN_MAILBOX(self), _("configuration:"));
193 self_print_multiline_text(self, config, "> ");
194 }
195
196 private void
197 print_output (self,
198 const char *header (check null),
199 const char *contents)
200 {
201 if (! contents || ! *contents)
202 return;
203
204 mn_mailbox_notice(MN_MAILBOX(self), "%s", header);
205 self_print_multiline_text(self, contents, "< ");
206 }
207
208 protected gboolean
209 run_helper (self,
210 const char *name (check null),
211 const char *command (check null),
212 GError **err)
213 {
214 GError *tmp_err = NULL;
215 char *helper_stdout;
216 char *helper_stderr;
217 int exit_status;
218 gboolean status = FALSE;
219
220 mn_mailbox_notice(MN_MAILBOX(self), _("running %s"), command);
221
222 if (! g_spawn_command_line_sync(command, &helper_stdout, &helper_stderr, &exit_status, &tmp_err))
223 {
224 g_set_error(err, 0, 0, _("cannot execute \"%s\": %s"), name, tmp_err->message);
225 g_error_free(tmp_err);
226 return FALSE;
227 }
228
229 self_print_output(self, _("standard output:"), helper_stdout);
230 self_print_output(self, _("standard error output:"), helper_stderr);
231
232 if (WEXITSTATUS(exit_status) != 0)
233 {
234 char *message;
235 gboolean is_auth_failure = FALSE;
236
237 message = self_get_error_message(self,
238 helper_stdout,
239 helper_stderr,
240 &is_auth_failure);
241 if (message)
242 {
243 g_set_error(err, 0, 0, "%s", message);
244 g_free(message);
245 }
246 else
247 /* translators: %s is a program name, as in "unknown fetchyahoo failure" */
248 g_set_error(err, 0, 0, _("unknown %s failure"), name);
249
250 if (is_auth_failure && MN_AUTHENTICATED_MAILBOX(self)->auth_prompted)
251 mn_authenticated_mailbox_auth_failed(MN_AUTHENTICATED_MAILBOX(self));
252
253 goto end;
254 }
255
256 status = TRUE;
257
258 end:
259 g_free(helper_stdout);
260 g_free(helper_stderr);
261
262 return status;
263 }
264
265 protected gboolean
266 read_spool_file (self, const char *spool_file (check null), GError **err)
267 {
268 int fd;
269 GMimeStream *stream;
270 GMimeParser *parser;
271 GSList *messages = NULL;
272
273 fd = open(spool_file, O_RDONLY);
274 if (fd < 0)
275 {
276 g_set_error(err, 0, 0, _("unable to open %s: %s"), spool_file, strerror(errno));
277 return FALSE;
278 }
279
280 stream = g_mime_stream_fs_new(fd);
281
282 parser = g_mime_parser_new_with_stream(stream);
283 g_object_unref(stream);
284 g_mime_parser_set_scan_from(parser, TRUE);
285
286 while (! g_mime_parser_eos(parser))
287 {
288 GMimeMessage *mime_message;
289
290 mime_message = g_mime_parser_construct_message(parser);
291 if (mime_message)
292 {
293 MNMessage *message;
294
295 message = mn_message_new_from_mime_message(MN_MAILBOX(self), mime_message, NULL, 0, TRUE);
296 g_object_unref(mime_message);
297
298 if (message)
299 messages = g_slist_prepend(messages, message);
300 }
301 }
302
303 g_object_unref(parser);
304
305 /* the fd is owned by the stream and closed by it */
306
307 GDK_THREADS_ENTER();
308
309 mn_mailbox_set_messages(MN_MAILBOX(self), messages);
310 mn_g_object_slist_free(messages);
311
312 gdk_flush();
313 GDK_THREADS_LEAVE();
314
315 return TRUE;
316 }
317
318 virtual private gboolean
319 webmail_check (self, GError **err);
320
321 override (MN:Authenticated:Mailbox) void
322 authenticated_check (MNAuthenticatedMailbox *mailbox)
323 {
324 Self *self = SELF(mailbox);
325 GError *err = NULL;
326
327 PARENT_HANDLER(mailbox);
328
329 again:
330 if (! mn_authenticated_mailbox_fill_password(mailbox, TRUE))
331 return;
332
333 if (! self_webmail_check(self, &err))
334 {
335 if (mailbox->auth_prompted && mailbox->auth_failed)
336 {
337 g_clear_error(&err);
338 goto again;
339 }
340
341 GDK_THREADS_ENTER();
342
343 mn_mailbox_set_error(MN_MAILBOX(self), "%s", err->message);
344 g_error_free(err);
345
346 gdk_flush();
347 GDK_THREADS_LEAVE();
348 }
349 }
350
351 public char *
352 build_name (MNWebmailMailboxClass *class (check null),
353 const char *username (check null),
354 const char *folder)
355 {
356 GString *name;
357
358 name = g_string_new(NULL);
359
360 if (strchr(username, '@'))
361 g_string_append(name, username);
362 else
363 g_string_append_printf(name, "%s@%s", username, class->default_domain);
364
365 if (folder && strcmp(folder, "Inbox"))
366 g_string_append_printf(name, "/%s", folder);
367
368 return g_string_free(name, FALSE);
369 }
370 }