aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/save-attachments/ChangeLog4
-rw-r--r--plugins/save-attachments/Makefile.am11
-rw-r--r--plugins/save-attachments/org-gnome-save-attachments.eplug.in23
-rw-r--r--plugins/save-attachments/org-gnome-save-attachments.xml19
-rw-r--r--plugins/save-attachments/save-attachments.c391
5 files changed, 448 insertions, 0 deletions
diff --git a/plugins/save-attachments/ChangeLog b/plugins/save-attachments/ChangeLog
new file mode 100644
index 0000000000..ed5dcefcbb
--- /dev/null
+++ b/plugins/save-attachments/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-20 Not Zed <NotZed@Ximian.com>
+
+ * Imported save-attachments example plugin.
+
diff --git a/plugins/save-attachments/Makefile.am b/plugins/save-attachments/Makefile.am
new file mode 100644
index 0000000000..424f88a42a
--- /dev/null
+++ b/plugins/save-attachments/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(EVOLUTION_MAIL_CFLAGS)
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-save-attachments.eplug org-gnome-save-attachments.xml
+plugin_LTLIBRARIES = liborg-gnome-save-attachments.la
+
+liborg_gnome_save_attachments_la_SOURCES = save-attachments.c
+liborg_gnome_save_attachments_la_LDFLAGS = -module -avoid-version
diff --git a/plugins/save-attachments/org-gnome-save-attachments.eplug.in b/plugins/save-attachments/org-gnome-save-attachments.eplug.in
new file mode 100644
index 0000000000..0e162665bd
--- /dev/null
+++ b/plugins/save-attachments/org-gnome-save-attachments.eplug.in
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+ <!-- the path to the shared library -->
+ <e-plugin
+ id="org.gnome.plugin.attachments.save"
+ type="shlib"
+ location="@PLUGINDIR@/liborg-gnome-save-attachments.so"
+ name="Save attachments plugin"
+ description="A plugin for saving all attachments or parts of a message at once.">
+ <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
+ <menu id="org.gnome.evolution.mail.browser" target="select">
+ <!-- the path to the bonobo menu description -->
+ <ui file="@PLUGINDIR@/org-gnome-save-attachments.xml"/>
+ <item
+ type="item"
+ verb="EPSASaveAttachments"
+ path="/commands/EPSASaveAttachments"
+ enable="one"
+ activate="org_gnome_save_attachments_save"/>
+ </menu>
+ </hook>
+ </e-plugin>
+</e-plugin-list>
diff --git a/plugins/save-attachments/org-gnome-save-attachments.xml b/plugins/save-attachments/org-gnome-save-attachments.xml
new file mode 100644
index 0000000000..449bd229c8
--- /dev/null
+++ b/plugins/save-attachments/org-gnome-save-attachments.xml
@@ -0,0 +1,19 @@
+<Root>
+ <commands>
+ <cmd name="EPSASaveAttachments" _label="Save Attachments ..."
+ _tip="Save all attachments"
+ pixtype="stock" pixname="Save"/>
+ </commands>
+
+ <menu>
+ <submenu name="Actions">
+ <placeholder name="ComponentActionsPlaceholder">
+ <placeholder name="MailMessageActions">
+ <separator f="" name="emaillist5"/>
+ <menuitem name="EPSASaveAttachments" verb=""/>
+ </placeholder>
+ </placeholder>
+ </submenu>
+
+ </menu>
+</Root>
diff --git a/plugins/save-attachments/save-attachments.c b/plugins/save-attachments/save-attachments.c
new file mode 100644
index 0000000000..bcf77df1d8
--- /dev/null
+++ b/plugins/save-attachments/save-attachments.c
@@ -0,0 +1,391 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* This is prototype code only, this may, or may not, use undocumented
+ * unstable or private internal function calls. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtktreestore.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcellrenderertoggle.h>
+#include <gtk/gtkbox.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkfilechooser.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkalignment.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <libgnomeui/gnome-file-entry.h>
+
+#include <camel/camel-folder.h>
+#include <camel/camel-exception.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-utf8.h>
+
+#include "mail/em-menu.h"
+#include "mail/em-utils.h"
+
+/* these are sort of mail-internal */
+#include "mail/mail-mt.h"
+#include "mail/mail-ops.h"
+
+void org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target);
+
+struct _save_data {
+ CamelFolder *folder;
+ char *uid;
+ CamelMimeMessage *msg;
+
+ char *path;
+ char *base;
+
+ GtkWidget *entry;
+ GtkWidget *tree;
+ GtkTreeStore *model;
+};
+
+static void
+free_data(struct _save_data *data)
+{
+ if (data->msg)
+ camel_object_unref(data->msg);
+ g_free(data->base);
+ g_free(data->path);
+ g_free(data->uid);
+ camel_object_unref(data->folder);
+ g_free(data);
+}
+
+static char *
+clean_name(const char *s)
+{
+ GString *out = g_string_new("");
+ int c;
+ char *r;
+
+ while ( (c = camel_utf8_getc((const unsigned char **)&s)) ) {
+ if (!g_unichar_isprint(c) || ( c < 0x7f && strchr(" /'\"`&();|<>$%{}!", c )))
+ c = '_';
+ g_string_append_u(out, c);
+ }
+
+ r = g_strdup(out->str);
+ g_string_free(out, TRUE);
+
+ return r;
+}
+
+static void
+fill_model_rec(CamelMimeMessage *msg, CamelMimePart *part, GtkTreeStore *model, GtkTreeIter *parent, GString *name)
+{
+ CamelDataWrapper *containee;
+ int parts, i;
+ char *type;
+ GtkTreeIter iter;
+ int len = name->len;
+ CamelContentType *mime;
+
+ containee = camel_medium_get_content_object((CamelMedium *)part);
+ if (containee == NULL)
+ return;
+
+ mime = ((CamelDataWrapper *)containee)->mime_type;
+ type = camel_content_type_simple(mime);
+
+ if (CAMEL_IS_MULTIPART(containee)) {
+ gtk_tree_store_append(model, &iter, parent);
+ g_string_append_printf(name, ".multipart");
+ gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1);
+
+ parts = camel_multipart_get_number((CamelMultipart *)containee);
+ for (i = 0; i < parts; i++) {
+ CamelMimePart *mpart = camel_multipart_get_part((CamelMultipart *)containee, i);
+
+ g_string_truncate(name, len);
+ g_string_append_printf(name, ".%d", i);
+ fill_model_rec(msg, mpart, model, &iter, name);
+ }
+ } else if (CAMEL_IS_MIME_MESSAGE(containee)) {
+ gtk_tree_store_append(model, &iter, parent);
+ g_string_append_printf(name, ".msg");
+ gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1);
+ fill_model_rec(msg, (CamelMimePart *)containee, model, &iter, name);
+ } else {
+ char *filename = NULL;
+ const char *ext = NULL, *tmp;
+ int save = FALSE;
+
+ gtk_tree_store_append(model, &iter, parent);
+ tmp = camel_mime_part_get_filename(part);
+ if (tmp) {
+ filename = clean_name(tmp);
+ ext = strrchr(filename, '.');
+ }
+ tmp = camel_mime_part_get_disposition(part);
+ if (tmp && !strcmp(tmp, "attachment"))
+ save = TRUE;
+
+ if (camel_content_type_is(mime, "text", "*")) {
+ if (ext == NULL) {
+ if ((ext = mime->subtype) == NULL || !strcmp(ext, "plain"))
+ ext = "text";
+ }
+ } else if (camel_content_type_is(mime, "image", "*")) {
+ if (ext == NULL) {
+ if ((ext = mime->subtype) == NULL)
+ ext = "image";
+ }
+ save = TRUE;
+ }
+
+ g_string_append_printf(name, ".%s", ext);
+ gtk_tree_store_set(model, &iter, 0, save, 1, type, 2, filename?filename:name->str, 3, filename?NULL:name->str, 4, part, -1);
+ g_free(filename);
+ }
+ g_free(type);
+
+ g_string_truncate(name, len);
+}
+
+static void
+fill_model(CamelMimeMessage *msg, GtkTreeStore *model)
+{
+ GString *name = g_string_new("");
+ GtkTreeIter iter;
+
+ gtk_tree_store_append(model, &iter, NULL);
+ gtk_tree_store_set(model, &iter, 0, FALSE, 1, "message/rfc822", 2, ".msg", 3, ".msg", 4, msg, -1);
+ fill_model_rec(msg, (CamelMimePart *)msg, model, &iter, name);
+ g_string_free(name, TRUE);
+}
+
+static gboolean
+save_part(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d)
+{
+ struct _save_data *data = d;
+ char *filename, *ext, *save;
+ CamelMimePart *part;
+ gboolean doit;
+
+ /* TODO: check for existing file */
+
+ gtk_tree_model_get(model, iter, 0, &doit, -1);
+ if (!doit)
+ return FALSE;
+
+ gtk_tree_model_get(model, iter, 2, &filename, 3, &ext, 4, &part, -1);
+ if (ext == NULL)
+ save = g_build_filename(data->path, filename, NULL);
+ else
+ save = g_strdup_printf("%s%s", data->base, ext);
+
+ /* FIXME: if part == data->msg then we need to save this
+ * differently, not using the envelope MimePart */
+
+ em_utils_save_part_to_file(NULL, save, part);
+
+ g_free(ext);
+ g_free(filename);
+
+ return FALSE;
+}
+
+static void
+save_response(GtkWidget *d, int id, struct _save_data *data)
+{
+ if (id == GTK_RESPONSE_OK) {
+ char *tmp;
+
+ data->base = gnome_file_entry_get_full_path((GnomeFileEntry *)data->entry, FALSE);
+ data->path = g_strdup(data->base);
+ tmp = strrchr(data->path, '/');
+ if (tmp)
+ *tmp = 0;
+ gtk_tree_model_foreach((GtkTreeModel *)data->model, save_part, data);
+ }
+
+ gtk_widget_destroy(d);
+ free_data(data);
+}
+
+static gboolean
+entry_changed_update(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d)
+{
+ const char *name = d;
+ char *filename, *ext;
+
+ gtk_tree_model_get(model, iter, 3, &ext, -1);
+ if (ext) {
+ filename = g_strdup_printf("%s%s", name, ext);
+ gtk_tree_store_set((GtkTreeStore *)model, iter, 2, filename, -1);
+ g_free(filename);
+ g_free(ext);
+ }
+
+ return FALSE;
+}
+
+static void
+entry_changed(GtkWidget *entry, struct _save_data *data)
+{
+ char *path;
+ const char *file;
+ struct stat st;
+
+ path = gnome_file_entry_get_full_path((GnomeFileEntry *)data->entry, FALSE);
+ if (path == NULL
+ || (file = strrchr(path, '/')) == NULL
+ || file[1] == 0
+ || (stat(path, &st) == 0 && S_ISDIR(st.st_mode)))
+ file = "attachment";
+ else
+ file++;
+
+ gtk_tree_model_foreach((GtkTreeModel *)data->model, entry_changed_update, (void *)file);
+ g_free(path);
+}
+
+static void
+toggle_changed(GtkWidget *entry, const char *spath, struct _save_data *data)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_string(spath);
+ if (gtk_tree_model_get_iter((GtkTreeModel *)data->model, &iter, path)) {
+ gboolean on;
+
+ gtk_tree_model_get((GtkTreeModel *)data->model, &iter, 0, &on, -1);
+ gtk_tree_store_set(data->model, &iter, 0, !on, -1);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+save_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d)
+{
+ struct _save_data *data = d;
+ GtkDialog *dialog;
+ GtkWidget *w, *tree;
+ GtkTreeStore *model;
+ GtkCellRenderer *renderer;
+
+ /* not found, the mailer will show an error box for this */
+ if (msg == NULL) {
+ free_data(data);
+ return;
+ }
+
+ data->msg = msg;
+ camel_object_ref(msg);
+
+ dialog = (GtkDialog *)gtk_dialog_new_with_buttons("Save attachments",
+ NULL, /* target->parent? */
+ 0,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+ w = gnome_file_entry_new("save-attachments", _("Select save base name"));
+ data->entry = w;
+ g_object_set(w, "filechooser_action", GTK_FILE_CHOOSER_ACTION_SAVE, NULL);
+ gtk_widget_show(w);
+ gtk_box_pack_start((GtkBox *)dialog->vbox, w, FALSE, TRUE, 6);
+
+ w = gnome_file_entry_gtk_entry((GnomeFileEntry *)data->entry);
+ g_signal_connect(w, "changed", G_CALLBACK(entry_changed), data);
+
+ model = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
+ data->model = model;
+ fill_model(msg, model);
+
+ tree = gtk_tree_view_new_with_model((GtkTreeModel *)model);
+ data->tree = tree;
+ gtk_widget_show(tree);
+ gtk_tree_view_expand_all((GtkTreeView *)tree);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
+ _("MIME Type"), renderer, "text", 1, NULL);
+ gtk_tree_view_set_expander_column((GtkTreeView *)tree, gtk_tree_view_get_column((GtkTreeView *)tree, 0));
+
+ renderer = gtk_cell_renderer_toggle_new();
+ g_object_set(renderer, "activatable", TRUE, NULL);
+ g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_changed), data);
+
+ gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
+ _("Save"), renderer, "active", 0, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1,
+ _("Name"), renderer, "text", 2, NULL);
+
+ w = g_object_new(gtk_frame_get_type(),
+ "shadow_type", GTK_SHADOW_NONE,
+ "label_widget", g_object_new(gtk_label_get_type(),
+ "label", "<span weight=\"bold\">Attachments</span>",
+ "use_markup", TRUE,
+ "xalign", 0.0, NULL),
+ "child", g_object_new(gtk_alignment_get_type(),
+ "left_padding", 12,
+ "top_padding", 6,
+ "child", g_object_new(gtk_scrolled_window_get_type(),
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "child", tree,
+ NULL),
+ NULL),
+ NULL);
+ gtk_widget_show_all(w);
+
+ gtk_box_pack_start((GtkBox *)dialog->vbox, w, TRUE, TRUE, 0);
+ g_signal_connect(dialog, "response", G_CALLBACK(save_response), data);
+ gtk_window_set_default_size((GtkWindow *)dialog, 500, 500);
+ gtk_widget_show((GtkWidget *)dialog);
+}
+
+void
+org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target)
+{
+ struct _save_data *data;
+
+ if (target->uids->len != 1)
+ return;
+
+ data = g_malloc0(sizeof(*data));
+ data->folder = target->folder;
+ camel_object_ref(data->folder);
+ data->uid = g_strdup(target->uids->pdata[0]);
+
+ mail_get_message(data->folder, data->uid, save_got_message, data, mail_thread_new);
+}