No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 * Copyright (C) 2004 Meilof Veeningen <meilof@wanadoo.nl>
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <gtk/gtk.h>
30 #include <glib/gi18n-lib.h>
31
32 #include <e-util/e-util.h>
33 #include <libevolution-utils/e-alert-dialog.h>
34
35 #include <shell/e-shell-view.h>
36 #include <shell/e-shell-window.h>
37 #include <shell/e-shell-window-actions.h>
38
39 #include <composer/e-msg-composer.h>
40
41 #include <libemail-utils/mail-mt.h>
42 #include <libemail-engine/mail-ops.h>
43
44 #include <mail/e-mail-browser.h>
45 #include <mail/e-mail-reader.h>
46 #include <mail/em-composer-utils.h>
47 #include <mail/em-config.h>
48 #include <mail/em-utils.h>
49 #include <mail/message-list.h>
50
51 /* EAlert Message IDs */
52 #define MESSAGE_PREFIX "org.gnome.mailing-list-actions:"
53 #define MESSAGE_NO_ACTION MESSAGE_PREFIX "no-action"
54 #define MESSAGE_NO_HEADER MESSAGE_PREFIX "no-header"
55 #define MESSAGE_ASK_SEND_MESSAGE MESSAGE_PREFIX "ask-send-message"
56 #define MESSAGE_MALFORMED_HEADER MESSAGE_PREFIX "malformed-header"
57 #define MESSAGE_POSTING_NOT_ALLOWED MESSAGE_PREFIX "posting-not-allowed"
58
59 typedef enum {
60 EMLA_ACTION_HELP,
61 EMLA_ACTION_UNSUBSCRIBE,
62 EMLA_ACTION_SUBSCRIBE,
63 EMLA_ACTION_POST,
64 EMLA_ACTION_OWNER,
65 EMLA_ACTION_ARCHIVE
66 } EmlaAction;
67
68 typedef struct {
69 /* action enumeration */
70 EmlaAction action;
71
72 /* whether the user needs to edit a mailto:
73 * message (e.g. for post action) */
74 gboolean interactive;
75
76 /* header representing the action */
77 const gchar *header;
78 } EmlaActionHeader;
79
80 const EmlaActionHeader emla_action_headers[] = {
81 { EMLA_ACTION_HELP, FALSE, "List-Help" },
82 { EMLA_ACTION_UNSUBSCRIBE, TRUE, "List-Unsubscribe" },
83 { EMLA_ACTION_SUBSCRIBE, FALSE, "List-Subscribe" },
84 { EMLA_ACTION_POST, TRUE, "List-Post" },
85 { EMLA_ACTION_OWNER, TRUE, "List-Owner" },
86 { EMLA_ACTION_ARCHIVE, FALSE, "List-Archive" },
87 };
88
89 gboolean mail_browser_init (GtkUIManager *ui_manager,
90 EMailBrowser *browser);
91 gboolean mail_shell_view_init (GtkUIManager *ui_manager,
92 EShellView *shell_view);
93 gint e_plugin_lib_enable (EPlugin *ep, gint enable);
94
95 gint
96 e_plugin_lib_enable (EPlugin *ep,
97 gint enable)
98 {
99 return 0;
100 }
101
102 typedef struct _AsyncContext AsyncContext;
103
104 struct _AsyncContext {
105 EActivity *activity;
106 EMailReader *reader;
107 EmlaAction action;
108 };
109
110 static void
111 async_context_free (AsyncContext *context)
112 {
113 if (context->activity != NULL)
114 g_object_unref (context->activity);
115
116 if (context->reader != NULL)
117 g_object_unref (context->reader);
118
119 g_slice_free (AsyncContext, context);
120 }
121
122 static void
123 emla_list_action_cb (CamelFolder *folder,
124 GAsyncResult *result,
125 AsyncContext *context)
126 {
127 const gchar *header = NULL, *headerpos;
128 gchar *end, *url = NULL;
129 gint t;
130 EMsgComposer *composer;
131 EAlertSink *alert_sink;
132 CamelMimeMessage *message;
133 gint send_message_response;
134 EShell *shell;
135 ESource *source;
136 EMailBackend *backend;
137 ESourceRegistry *registry;
138 EShellBackend *shell_backend;
139 GtkWindow *window;
140 CamelStore *store;
141 const gchar *uid;
142 GError *error = NULL;
143
144 window = e_mail_reader_get_window (context->reader);
145 backend = e_mail_reader_get_backend (context->reader);
146 alert_sink = e_activity_get_alert_sink (context->activity);
147
148 shell_backend = E_SHELL_BACKEND (backend);
149 shell = e_shell_backend_get_shell (shell_backend);
150
151 registry = e_shell_get_registry (shell);
152
153 message = camel_folder_get_message_finish (folder, result, &error);
154
155 if (e_activity_handle_cancellation (context->activity, error)) {
156 g_warn_if_fail (message == NULL);
157 async_context_free (context);
158 g_error_free (error);
159 return;
160
161 } else if (error != NULL) {
162 g_warn_if_fail (message == NULL);
163 e_alert_submit (
164 alert_sink, "mail:no-retrieve-message",
165 error->message, NULL);
166 async_context_free (context);
167 g_error_free (error);
168 return;
169 }
170
171 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
172
173 /* Finalize the activity here so we don't leave a
174 * message in the task bar while display a dialog. */
175 e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
176 g_object_unref (context->activity);
177 context->activity = NULL;
178
179 store = camel_folder_get_parent_store (folder);
180 uid = camel_service_get_uid (CAMEL_SERVICE (store));
181 source = e_source_registry_ref_source (registry, uid);
182
183 /* Reuse this to hold the mail identity UID. */
184 uid = NULL;
185
186 if (source != NULL) {
187 ESourceMailAccount *extension;
188 const gchar *extension_name;
189
190 extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
191 extension = e_source_get_extension (source, extension_name);
192 uid = e_source_mail_account_get_identity_uid (extension);
193 }
194
195 for (t = 0; t < G_N_ELEMENTS (emla_action_headers); t++) {
196 if (emla_action_headers[t].action == context->action) {
197 header = camel_medium_get_header (
198 CAMEL_MEDIUM (message),
199 emla_action_headers[t].header);
200 if (header != NULL)
201 break;
202 }
203 }
204
205 if (!header) {
206 /* there was no header matching the action */
207 e_alert_run_dialog_for_args (window, MESSAGE_NO_HEADER, NULL);
208 goto exit;
209 }
210
211 headerpos = header;
212
213 if (context->action == EMLA_ACTION_POST) {
214 while (*headerpos == ' ') headerpos++;
215 if (g_ascii_strcasecmp (headerpos, "NO") == 0) {
216 e_alert_run_dialog_for_args (
217 window, MESSAGE_POSTING_NOT_ALLOWED, NULL);
218 goto exit;
219 }
220 }
221
222 /* parse the action value */
223 while (*headerpos) {
224 /* skip whitespace */
225 while (*headerpos == ' ') headerpos++;
226 if (*headerpos != '<' || (end = strchr (headerpos++, '>')) == NULL) {
227 e_alert_run_dialog_for_args (
228 window, MESSAGE_MALFORMED_HEADER,
229 emla_action_headers[t].header, header, NULL);
230 goto exit;
231 }
232
233 /* get URL portion */
234 url = g_strndup (headerpos, end - headerpos);
235
236 if (strncmp (url, "mailto:", 6) == 0) {
237 if (emla_action_headers[t].interactive)
238 send_message_response = GTK_RESPONSE_NO;
239 else
240 send_message_response = e_alert_run_dialog_for_args (
241 window, MESSAGE_ASK_SEND_MESSAGE,
242 url, NULL);
243
244 if (send_message_response == GTK_RESPONSE_YES) {
245 EComposerHeaderTable *table;
246
247 /* directly send message */
248 composer = e_msg_composer_new_from_url (shell, url);
249 table = e_msg_composer_get_header_table (composer);
250
251 if (uid != NULL)
252 e_composer_header_table_set_identity_uid (table, uid);
253 e_msg_composer_send (composer);
254 } else if (send_message_response == GTK_RESPONSE_NO) {
255 /* show composer */
256 em_utils_compose_new_message_with_mailto (shell, url, folder);
257 }
258
259 goto exit;
260 } else {
261 e_show_uri (window, url);
262 goto exit;
263 }
264 g_free (url);
265 url = NULL;
266 headerpos = end++;
267
268 /* ignore everything 'till next comma */
269 headerpos = strchr (headerpos, ',');
270 if (!headerpos)
271 break;
272 headerpos++;
273 }
274
275 /* if we got here, there's no valid action */
276 e_alert_run_dialog_for_args (window, MESSAGE_NO_ACTION, header, NULL);
277
278 exit:
279 if (source != NULL)
280 g_object_unref (source);
281
282 g_object_unref (message);
283 g_free (url);
284
285 async_context_free (context);
286 }
287
288 static void
289 emla_list_action (EMailReader *reader,
290 EmlaAction action)
291 {
292 EActivity *activity;
293 AsyncContext *context;
294 GCancellable *cancellable;
295 CamelFolder *folder;
296 GPtrArray *uids;
297 const gchar *message_uid;
298
299 folder = e_mail_reader_get_folder (reader);
300 g_return_if_fail (CAMEL_IS_FOLDER (folder));
301
302 uids = e_mail_reader_get_selected_uids (reader);
303 g_return_if_fail (uids != NULL && uids->len == 1);
304 message_uid = g_ptr_array_index (uids, 0);
305
306 activity = e_mail_reader_new_activity (reader);
307 cancellable = e_activity_get_cancellable (activity);
308
309 context = g_slice_new0 (AsyncContext);
310 context->activity = activity;
311 context->reader = g_object_ref (reader);
312 context->action = action;
313
314 camel_folder_get_message (
315 folder, message_uid, G_PRIORITY_DEFAULT,
316 cancellable, (GAsyncReadyCallback)
317 emla_list_action_cb, context);
318
319 em_utils_uids_free (uids);
320 }
321
322 static void
323 action_mailing_list_archive_cb (GtkAction *action,
324 EMailReader *reader)
325 {
326 emla_list_action (reader, EMLA_ACTION_ARCHIVE);
327 }
328
329 static void
330 action_mailing_list_help_cb (GtkAction *action,
331 EMailReader *reader)
332 {
333 emla_list_action (reader, EMLA_ACTION_HELP);
334 }
335
336 static void
337 action_mailing_list_owner_cb (GtkAction *action,
338 EMailReader *reader)
339 {
340 emla_list_action (reader, EMLA_ACTION_OWNER);
341 }
342
343 static void
344 action_mailing_list_post_cb (GtkAction *action,
345 EMailReader *reader)
346 {
347 emla_list_action (reader, EMLA_ACTION_POST);
348 }
349
350 static void
351 action_mailing_list_subscribe_cb (GtkAction *action,
352 EMailReader *reader)
353 {
354 emla_list_action (reader, EMLA_ACTION_SUBSCRIBE);
355 }
356
357 static void
358 action_mailing_list_unsubscribe_cb (GtkAction *action,
359 EMailReader *reader)
360 {
361 emla_list_action (reader, EMLA_ACTION_UNSUBSCRIBE);
362 }
363
364 static GtkActionEntry mailing_list_entries[] = {
365
366 { "mailing-list-archive",
367 NULL,
368 N_("Get List _Archive"),
369 NULL,
370 N_("Get an archive of the list this message belongs to"),
371 G_CALLBACK (action_mailing_list_archive_cb) },
372
373 { "mailing-list-help",
374 NULL,
375 N_("Get List _Usage Information"),
376 NULL,
377 N_("Get information about the usage of the list this message belongs to"),
378 G_CALLBACK (action_mailing_list_help_cb) },
379
380 { "mailing-list-owner",
381 NULL,
382 N_("Contact List _Owner"),
383 NULL,
384 N_("Contact the owner of the mailing list this message belongs to"),
385 G_CALLBACK (action_mailing_list_owner_cb) },
386
387 { "mailing-list-post",
388 NULL,
389 N_("_Post Message to List"),
390 NULL,
391 N_("Post a message to the mailing list this message belongs to"),
392 G_CALLBACK (action_mailing_list_post_cb) },
393
394 { "mailing-list-subscribe",
395 NULL,
396 N_("_Subscribe to List"),
397 NULL,
398 N_("Subscribe to the mailing list this message belongs to"),
399 G_CALLBACK (action_mailing_list_subscribe_cb) },
400
401 { "mailing-list-unsubscribe",
402 NULL,
403 N_("_Unsubscribe from List"),
404 NULL,
405 N_("Unsubscribe from the mailing list this message belongs to"),
406 G_CALLBACK (action_mailing_list_unsubscribe_cb) },
407
408 /*** Menus ***/
409
410 { "mailing-list-menu",
411 NULL,
412 N_("Mailing _List"),
413 NULL,
414 NULL,
415 NULL }
416 };
417
418 static void
419 update_actions_cb (EMailReader *reader,
420 guint32 state,
421 GtkActionGroup *action_group)
422 {
423 gboolean sensitive;
424
425 sensitive = (state & E_MAIL_READER_SELECTION_IS_MAILING_LIST) != 0
426 && (state & E_MAIL_READER_SELECTION_SINGLE) != 0;
427 gtk_action_group_set_sensitive (action_group, sensitive);
428 }
429
430 static void
431 setup_actions (EMailReader *reader,
432 GtkUIManager *ui_manager)
433 {
434 GtkActionGroup *action_group;
435 const gchar *domain = GETTEXT_PACKAGE;
436
437 action_group = gtk_action_group_new ("mailing-list");
438 gtk_action_group_set_translation_domain (action_group, domain);
439 gtk_action_group_add_actions (
440 action_group, mailing_list_entries,
441 G_N_ELEMENTS (mailing_list_entries), reader);
442 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
443 g_object_unref (action_group);
444
445 /* GtkUIManager now owns the action group reference.
446 * The signal we're connecting to will only be emitted
447 * during the GtkUIManager's lifetime, so the action
448 * group will not disappear on us. */
449
450 g_signal_connect (
451 reader, "update-actions",
452 G_CALLBACK (update_actions_cb), action_group);
453 }
454
455 gboolean
456 mail_browser_init (GtkUIManager *ui_manager,
457 EMailBrowser *browser)
458 {
459 setup_actions (E_MAIL_READER (browser), ui_manager);
460
461 return TRUE;
462 }
463
464 gboolean
465 mail_shell_view_init (GtkUIManager *ui_manager,
466 EShellView *shell_view)
467 {
468 EShellContent *shell_content;
469
470 shell_content = e_shell_view_get_shell_content (shell_view);
471
472 setup_actions (E_MAIL_READER (shell_content), ui_manager);
473
474 return TRUE;
475 }