evolution-3.6.4/plugins/mailing-list-actions/mailing-list-actions.c

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 }