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 }