2006-08-04 [colin] 2.4.0cvs27
authorColin Leroy <colin@colino.net>
Fri, 4 Aug 2006 16:12:21 +0000 (16:12 +0000)
committerColin Leroy <colin@colino.net>
Fri, 4 Aug 2006 16:12:21 +0000 (16:12 +0000)
* src/compose.c
* src/undo.c
* src/undo.h
Fix a bit replace-by-pasting undo
* src/mainwindow.c
* src/messageview.c
Fix Fold quotes menu synchro in
mainwindow when it changes in
messageview
* src/textview.c
Fix right-click on quotes blocks
* src/common/utils.c
Verify that the file created by
my_tmpfile() is writable. Fixes
bug #988 (very specific filesystem
issue)
* src/plugins/pgpcore/sgpgme.c
Fix file descriptor leak
* src/plugins/spamassassin/spamassassin.c
Warn once if spamd isn't reachable

12 files changed:
ChangeLog
PATCHSETS
configure.ac
src/common/utils.c
src/compose.c
src/mainwindow.c
src/messageview.c
src/plugins/pgpcore/sgpgme.c
src/plugins/spamassassin/spamassassin.c
src/textview.c
src/undo.c
src/undo.h

index fc485087e37c28ff1f7382541bc631fcb8b2e760..fbc74cab050f4202b6ec49ceaa59094f3da6727f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2006-08-04 [colin]     2.4.0cvs27
+
+       * src/compose.c
+       * src/undo.c
+       * src/undo.h
+               Fix a bit replace-by-pasting undo
+       * src/mainwindow.c
+       * src/messageview.c
+               Fix Fold quotes menu synchro in
+               mainwindow when it changes in 
+               messageview
+       * src/textview.c
+               Fix right-click on quotes blocks
+       * src/common/utils.c
+               Verify that the file created by
+               my_tmpfile() is writable. Fixes
+               bug #988 (very specific filesystem
+               issue)
+       * src/plugins/pgpcore/sgpgme.c
+               Fix file descriptor leak
+       * src/plugins/spamassassin/spamassassin.c
+               Warn once if spamd isn't reachable
+
 2006-08-04 [colin]     2.4.0cvs26
 
        * src/toolbar.c
index 7ac258da104ccebcf3775fb15405d4535adf3ffe..0c79ac50d4ca5195e04725e6fdaa2ad8287dcea4 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.100.2.41 -r 1.100.2.42 AUTHORS;  cvs diff -u -r 1.1.2.3 -r 1.1.2.4 sylpheed-claws.desktop;  cvs diff -u -r 1.1.2.23 -r 1.1.2.24 src/gtk/authors.h;  ) > 2.4.0cvs24.patchset
 ( cvs diff -u -r 1.274.2.133 -r 1.274.2.134 src/mainwindow.c;  cvs diff -u -r 1.94.2.93 -r 1.94.2.94 src/messageview.c;  cvs diff -u -r 1.96.2.133 -r 1.96.2.134 src/textview.c;  ) > 2.4.0cvs25.patchset
 ( cvs diff -u -r 1.43.2.47 -r 1.43.2.48 src/toolbar.c;  ) > 2.4.0cvs26.patchset
+( cvs diff -u -r 1.382.2.296 -r 1.382.2.297 src/compose.c;  cvs diff -u -r 1.274.2.134 -r 1.274.2.135 src/mainwindow.c;  cvs diff -u -r 1.94.2.94 -r 1.94.2.95 src/messageview.c;  cvs diff -u -r 1.96.2.134 -r 1.96.2.135 src/textview.c;  cvs diff -u -r 1.13.2.9 -r 1.13.2.10 src/undo.c;  cvs diff -u -r 1.5.14.5 -r 1.5.14.6 src/undo.h;  cvs diff -u -r 1.36.2.72 -r 1.36.2.73 src/common/utils.c;  cvs diff -u -r 1.1.2.22 -r 1.1.2.23 src/plugins/pgpcore/sgpgme.c;  cvs diff -u -r 1.18.2.34 -r 1.18.2.35 src/plugins/spamassassin/spamassassin.c;  ) > 2.4.0cvs27.patchset
index ab85ffb0712a1a36bcd79dc353cb07ef38dbe63a..c64e0e0c891d2b06e8de909d8018c372794988b9 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=4
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=26
+EXTRA_VERSION=27
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index 604ea0cf7c6a102b149e5fc07a8e912f774638f0..7f75728b2bde610211f25eb9a3db1cc50439cfe7 100644 (file)
@@ -3271,6 +3271,7 @@ FILE *my_tmpfile(void)
        gchar *fname;
        gint fd;
        FILE *fp;
+       gchar buf[2]="a";
 
        tmpdir = get_tmp_dir();
        tmplen = strlen(tmpdir);
@@ -3292,13 +3293,23 @@ FILE *my_tmpfile(void)
 
 #ifndef G_OS_WIN32
        g_unlink(fname);
+       
+       /* verify that we can write in the file after unlinking */
+       if (write(fd, buf, 1) < 0) {
+               close(fd);
+               return tmpfile();
+       }
+       
 #endif
 
        fp = fdopen(fd, "w+b");
        if (!fp)
                close(fd);
-       else
+       else {
+               rewind(fp);
                return fp;
+       }
+
 #endif /* HAVE_MKSTEMP || G_OS_WIN32 */
 
        return tmpfile();
index 4efc05b893092814085d025e57e6580a4366d18e..63b2efe2f4a3fea1e6ded496a8eadb54a0f2ee25 100644 (file)
@@ -7934,16 +7934,18 @@ static void entry_paste_clipboard(Compose *compose, GtkWidget *entry,
                GtkTextMark *mark_start = gtk_text_buffer_get_insert(buffer);
                GtkTextIter start_iter, end_iter;
                gint start, end;
-               
                gchar *contents = gtk_clipboard_wait_for_text(gtk_clipboard_get(clip));
 
                if (contents == NULL)
                        return;
 
+               undo_paste_clipboard(compose->text, compose->undostruct);
+
                /* we shouldn't delete the selection when middle-click-pasting, or we
                 * can't mid-click-paste our own selection */
-               if (clip != GDK_SELECTION_PRIMARY)
+               if (clip != GDK_SELECTION_PRIMARY) {
                        gtk_text_buffer_delete_selection(buffer, FALSE, TRUE);
+               }
                
                if (insert_place == NULL) {
                        /* if insert_place isn't specified, insert at the cursor.
@@ -7971,7 +7973,6 @@ static void entry_paste_clipboard(Compose *compose, GtkWidget *entry,
                        gtk_text_iter_backward_char(&start_iter);
                        compose_beautify_paragraph(compose, &start_iter, TRUE);
                }
-               
        } else if (GTK_IS_EDITABLE(entry))
                gtk_editable_paste_clipboard (GTK_EDITABLE(entry));
        
index cb869535fc0b601dc5a810ff8fff3a12d4d24d3b..2e0f9421c1f70096af1116fe4cfe202ea47f7e01 100644 (file)
@@ -2277,6 +2277,9 @@ void main_window_set_menu_sensitive(MainWindow *mainwin)
                SET_CHECK_MENU_ACTIVE("/View/Show all headers",
                              mainwin->messageview->mimeview->textview->show_all_headers);
        SET_CHECK_MENU_ACTIVE("/View/Thread view", (state & M_THREADED) != 0);
+       SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold all", FALSE);
+       SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 2", FALSE);
+       SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 3", FALSE);
        if (prefs_common.hide_quotes == 1)
                SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold all", TRUE);
        if (prefs_common.hide_quotes == 2)
@@ -3281,8 +3284,7 @@ static void hide_quotes_cb(MainWindow *mainwin, guint action,
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), prefs_common.hide_quotes > 0);
        mainwin->menu_lock_count--;
 
-       summary_display_msg_selected(mainwin->summaryview,
-                       mainwin->summaryview->messageview->all_headers);
+       summary_redisplay_msg(mainwin->summaryview);
 }
 
 #undef SET_CHECK_MENU_ACTIVE
index 4b28c329687c7f8b67941ca26fe55aaf4521d817..99fbc73c36ba9280640e681e1fa3dbf6c05d9e60 100644 (file)
@@ -120,7 +120,7 @@ static void view_source_cb          (gpointer        data,
 static void show_all_header_cb         (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
-static void hide_quotes_cb             (gpointer        data,
+static void msg_hide_quotes_cb         (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
 
@@ -278,9 +278,9 @@ static GtkItemFactoryEntry msgview_entries[] =
        {N_("/_View/Mess_age source"),  "<control>U", view_source_cb, 0, NULL},
        {N_("/_View/Show all _headers"),"<control>H", show_all_header_cb, 0, "<ToggleItem>"},
        {N_("/_View/Quotes"),                   NULL, NULL, 0, "<Branch>"},
-       {N_("/_View/Quotes/_Fold all"),         "<control><shift>Q", hide_quotes_cb, 1, "<ToggleItem>"},
-       {N_("/_View/Quotes/Fold from level _2"),NULL, hide_quotes_cb, 2, "<ToggleItem>"},
-       {N_("/_View/Quotes/Fold from level _3"),NULL, hide_quotes_cb, 3, "<ToggleItem>"},
+       {N_("/_View/Quotes/_Fold all"),         "<control><shift>Q", msg_hide_quotes_cb, 1, "<ToggleItem>"},
+       {N_("/_View/Quotes/Fold from level _2"),NULL, msg_hide_quotes_cb, 2, "<ToggleItem>"},
+       {N_("/_View/Quotes/Fold from level _3"),NULL, msg_hide_quotes_cb, 3, "<ToggleItem>"},
 
        {N_("/_Message"),               NULL, NULL, 0, "<Branch>"},
        {N_("/_Message/Compose _new message"),
@@ -816,9 +816,15 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
        
        if (messageview->msginfo != msginfo) {
                procmsg_msginfo_free(messageview->msginfo);
+               messageview->msginfo = NULL;
+               messageview_set_menu_sensitive(messageview);
                messageview->msginfo = procmsg_msginfo_get_full_info(msginfo);
                if (!messageview->msginfo)
                        messageview->msginfo = procmsg_msginfo_copy(msginfo);
+       } else {
+               messageview->msginfo = NULL;
+               messageview_set_menu_sensitive(messageview);
+               messageview->msginfo = msginfo;
        }
        headerview_show(messageview->headerview, messageview->msginfo);
 
@@ -1525,7 +1531,7 @@ static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget)
        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); \
 }
 
-static void hide_quotes_cb(gpointer data, guint action, GtkWidget *widget)
+static void msg_hide_quotes_cb(gpointer data, guint action, GtkWidget *widget)
 {
        MessageView *messageview = (MessageView *)data;
        MsgInfo *msginfo = messageview->msginfo;
@@ -1549,7 +1555,10 @@ static void hide_quotes_cb(gpointer data, guint action, GtkWidget *widget)
        messageview_show(messageview, msginfo,
                         messageview->all_headers);
        procmsg_msginfo_free(msginfo);
+       
+       /* update main window */
        main_window_set_menu_sensitive(messageview->mainwin);
+       summary_redisplay_msg(messageview->mainwin->summaryview);
 }
 #undef SET_CHECK_MENU_ACTIVE
 
@@ -1654,7 +1663,7 @@ static gboolean messageview_update_msg(gpointer source, gpointer data)
 void messageview_set_menu_sensitive(MessageView *messageview)
 {
        GtkItemFactory *ifactory;
-       GtkWidget *menuitem;
+       GtkWidget *menuitem = NULL;
 
        if (!messageview || !messageview->new_window) 
                return;
@@ -1667,20 +1676,21 @@ void messageview_set_menu_sensitive(MessageView *messageview)
                gtk_check_menu_item_set_active
                        (GTK_CHECK_MENU_ITEM(menuitem),
                         messageview->mimeview->textview->show_all_headers);
-               if (prefs_common.hide_quotes) {
-                       if (prefs_common.hide_quotes == 1)
-                               menuitem = gtk_item_factory_get_widget(ifactory, 
-                                               "/View/Quotes/Fold all");
-                       if (prefs_common.hide_quotes == 2)
-                               menuitem = gtk_item_factory_get_widget(ifactory, 
-                                               "/View/Quotes/Fold from level 2");
-                       if (prefs_common.hide_quotes == 3)
-                               menuitem = gtk_item_factory_get_widget(ifactory, 
-                                               "/View/Quotes/Fold from level 3");
-                       gtk_check_menu_item_set_active
-                               (GTK_CHECK_MENU_ITEM(menuitem),
-                                TRUE);
-               }
+       }
+       if (prefs_common.hide_quotes) {
+               menuitem = NULL;
+               if (prefs_common.hide_quotes == 1)
+                       menuitem = gtk_item_factory_get_widget(ifactory, 
+                                       "/View/Quotes/Fold all");
+               if (prefs_common.hide_quotes == 2)
+                       menuitem = gtk_item_factory_get_widget(ifactory, 
+                                       "/View/Quotes/Fold from level 2");
+               if (prefs_common.hide_quotes == 3)
+                       menuitem = gtk_item_factory_get_widget(ifactory, 
+                                       "/View/Quotes/Fold from level 3");
+               gtk_check_menu_item_set_active
+                       (GTK_CHECK_MENU_ITEM(menuitem),
+                        TRUE);
        }
 }
 
index 0d1ed252b8468d5007b4621978d8a8d22992edc4..d290d61baa2f5832c1dcef9ba617f6d3d26dddd6 100644 (file)
@@ -332,10 +332,8 @@ gpgme_data_t sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
        tmp_file = get_tmp_file();
        copy_file_part(fp, mimeinfo->offset, mimeinfo->length, tmp_file);
        fclose(fp);
-       fp = g_fopen(tmp_file, "rb");
+       fp = NULL;
        debug_print("tmp file %s\n", tmp_file);
-       if (!fp) 
-               return NULL;
        
        err = gpgme_data_new_from_file(&data, tmp_file, 1);
        g_unlink(tmp_file);
index 56c72c1d0a393bfb0c916fa3af8d56f4f5d8c8fc..07fc7aa541ff4832151993a63f9421448685a011 100644 (file)
@@ -48,6 +48,7 @@
 #include "inc.h"
 #include "log.h"
 #include "prefs_common.h"
+#include "alertpanel.h"
 
 #ifdef HAVE_SYSEXITS_H
 #include <sysexits.h>
@@ -120,14 +121,20 @@ gboolean timeout_func(gpointer data)
        return FALSE;
 }
 
-static gboolean msg_is_spam(FILE *fp)
+typedef enum {
+       MSG_IS_HAM = 0,
+       MSG_IS_SPAM = 1,
+       MSG_FILTERING_ERROR = 2
+} MsgStatus;
+
+static MsgStatus msg_is_spam(FILE *fp)
 {
        struct transport trans;
        struct message m;
        gboolean is_spam = FALSE;
 
        if (!config.enable)
-               return FALSE;
+               return MSG_IS_HAM;
 
        transport_init(&trans);
        switch (config.transport) {
@@ -145,13 +152,13 @@ static gboolean msg_is_spam(FILE *fp)
                trans.socketpath = config.socket;
                break;
        default:
-               return FALSE;
+               return MSG_IS_HAM;
        }
 
        if (transport_setup(&trans, flags) != EX_OK) {
                log_error(_("Spamassassin plugin couldn't connect to spamd.\n"));
                debug_print("failed to setup transport\n");
-               return FALSE;
+               return MSG_FILTERING_ERROR;
        }
 
        m.type = MESSAGE_NONE;
@@ -161,13 +168,14 @@ static gboolean msg_is_spam(FILE *fp)
        if (message_read(fileno(fp), flags, &m) != EX_OK) {
                debug_print("failed to read message\n");
                message_cleanup(&m);
-               return FALSE;
+               return MSG_FILTERING_ERROR;
        }
 
        if (message_filter(&trans, config.username, flags, &m) != EX_OK) {
+               log_error(_("Spamassassin plugin filtering failed.\n"));
                debug_print("filtering the message failed\n");
                message_cleanup(&m);
-               return FALSE;
+               return MSG_FILTERING_ERROR;
        }
 
        if (m.is_spam == EX_ISSPAM)
@@ -175,14 +183,15 @@ static gboolean msg_is_spam(FILE *fp)
 
        message_cleanup(&m);
 
-       return is_spam;
+       return is_spam ? MSG_IS_SPAM:MSG_IS_HAM;
 }
 
 static gboolean mail_filtering_hook(gpointer source, gpointer data)
 {
        MailFilteringData *mail_filtering_data = (MailFilteringData *) source;
        MsgInfo *msginfo = mail_filtering_data->msginfo;
-       gboolean is_spam = FALSE;
+       gboolean is_spam = FALSE, error = FALSE;
+       static gboolean warned_error = FALSE;
        FILE *fp = NULL;
        int pid = 0;
        int status;
@@ -203,7 +212,7 @@ static gboolean mail_filtering_hook(gpointer source, gpointer data)
 
        pid = fork();
        if (pid == 0) {
-               _exit(msg_is_spam(fp) ? 1 : 0);
+               _exit(msg_is_spam(fp));
        } else {
                gint running = 0;
 
@@ -218,8 +227,11 @@ static gboolean mail_filtering_hook(gpointer source, gpointer data)
                        ret = waitpid(pid, &status, WNOHANG);
                        if (ret == pid) {
                                if (WIFEXITED(status)) {
+                                       MsgStatus result = MSG_IS_HAM;
                                        running &= ~CHILD_RUNNING;
-                                       is_spam = WEXITSTATUS(status) == 1 ? TRUE : FALSE;
+                                       result = WEXITSTATUS(status);
+                                       is_spam = (result == MSG_IS_SPAM) ? TRUE : FALSE;
+                                       error = (result == MSG_FILTERING_ERROR);
                                }
                        } if (ret < 0) {
                                running &= ~CHILD_RUNNING;
@@ -257,6 +269,17 @@ static gboolean mail_filtering_hook(gpointer source, gpointer data)
                debug_print("message is ham\n");
                procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
        }
+       
+       if (error) {
+               if (!warned_error) {
+                       alertpanel_error(_("The Spamassassin plugin couldn't filter "
+                                          "a message. The probable error cause is "
+                                          "an unreachable spamd daemon. Please make "
+                                          "sure spamd is running and accessible."));
+               }
+               warned_error = TRUE;
+       }
+       
        return FALSE;
 }
 
index dd2e345ea0da2bad8cb23cebc1af81fae7a70baf..093d43c5b27d68d82dece00049fd43c0d1bd93f1 100644 (file)
@@ -2398,7 +2398,10 @@ static gboolean textview_uri_button_pressed(GtkTextTag *tag, GObject *obj,
        bevent = (GdkEventButton *) event;
        
        /* doubleclick: open compose / add address / browser */
-       if ((event->type == (qlink ? GDK_2BUTTON_PRESS:GDK_BUTTON_PRESS) && bevent->button == 1) ||
+       if (qlink && event->type == GDK_BUTTON_PRESS && bevent->button != 1) {
+               /* pass rightclick through */
+               return FALSE;
+       } else if ((event->type == (qlink ? GDK_2BUTTON_PRESS:GDK_BUTTON_PRESS) && bevent->button == 1) ||
                bevent->button == 2 || bevent->button == 3) {
                if (uri->filename && !g_ascii_strncasecmp(uri->filename, "sc://", 5)) {
                        MimeView *mimeview = 
@@ -2417,7 +2420,6 @@ static gboolean textview_uri_button_pressed(GtkTextTag *tag, GObject *obj,
                } else if (qlink && bevent->button == 1) {
                        textview_toggle_quote(textview, uri, FALSE);
                        return TRUE;
-                               
                } else if (!g_ascii_strncasecmp(uri->uri, "mailto:", 7)) {
                        if (bevent->button == 3) {
                                g_object_set_data(
index 2676d72df6a8635c0f5947342b77ed6e5a333f54..ced57c5156c995f83cebe6cf8e8a6db767c338c4 100644 (file)
@@ -468,9 +468,9 @@ void undo_redo(UndoMain *undostruct)
                /* "pull" another data structure from the list */
                redoinfo = (UndoInfo *)undostruct->redo->data;
                g_return_if_fail(redoinfo != NULL);
-               undostruct->undo = g_list_prepend(undostruct->redo, redoinfo);
-               undostruct->redo = g_list_remove(undostruct->undo, redoinfo);
-               g_return_if_fail(redoinfo->action == UNDO_ACTION_REPLACE_DELETE);
+               undostruct->undo = g_list_prepend(undostruct->undo, redoinfo);
+               undostruct->redo = g_list_remove(undostruct->redo, redoinfo);
+               g_return_if_fail(redoinfo->action == UNDO_ACTION_REPLACE_INSERT);
                gtk_text_buffer_insert(buffer, &start_iter, redoinfo->text, -1);
                break;
        case UNDO_ACTION_REPLACE_INSERT:
@@ -537,7 +537,8 @@ void undo_insert_text_cb(GtkTextBuffer *textbuf, GtkTextIter *iter,
        pos = gtk_text_iter_get_offset(iter);
        if (undostruct->wrap && undostruct->undo) {
                UndoInfo *last_undo = undostruct->undo->data;
-               if (last_undo && last_undo->action == UNDO_ACTION_INSERT
+               if (last_undo && (last_undo->action == UNDO_ACTION_INSERT
+                                 || last_undo->action == UNDO_ACTION_REPLACE_INSERT)
                &&  last_undo->start_pos < pos && last_undo->end_pos > pos) {
                        GtkTextIter start,end;
                        last_undo->end_pos += g_utf8_strlen(new_text, -1);
@@ -549,7 +550,6 @@ void undo_insert_text_cb(GtkTextBuffer *textbuf, GtkTextIter *iter,
                        return;
                } else debug_print("add:last: %d, %d-%d (%d)\n", last_undo->action,
                        last_undo->start_pos, last_undo->end_pos, pos);
-               
        } 
        Xstrndup_a(text_to_insert, new_text, new_text_length, return);
        debug_print("add:undo add %d-%ld\n", pos, pos + g_utf8_strlen(text_to_insert, -1));
@@ -573,7 +573,8 @@ void undo_delete_text_cb(GtkTextBuffer *textbuf, GtkTextIter *start,
 
        if (undostruct->wrap && undostruct->undo) {
                UndoInfo *last_undo = undostruct->undo->data;
-               if (last_undo && last_undo->action == UNDO_ACTION_INSERT
+               if (last_undo && (last_undo->action == UNDO_ACTION_INSERT
+                                 || last_undo->action == UNDO_ACTION_REPLACE_INSERT)
                &&  last_undo->start_pos < start_pos && last_undo->end_pos > end_pos) {
                        GtkTextIter start,end;
                        last_undo->end_pos -= g_utf8_strlen(text_to_delete, -1);
@@ -593,7 +594,12 @@ void undo_delete_text_cb(GtkTextBuffer *textbuf, GtkTextIter *start,
        g_free(text_to_delete);
 }
 
-void undo_paste_clipboard_cb(GtkTextView *textview, UndoMain *undostruct)
+void undo_paste_clipboard(GtkTextView *textview, UndoMain *undostruct)
+{
+       undo_paste_clipboard_cb(textview, undostruct);
+}
+
+static void undo_paste_clipboard_cb(GtkTextView *textview, UndoMain *undostruct)
 {
        if (prefs_common.undolevels > 0)
                if (undo_get_selection(textview, NULL, NULL))
index 76a334d168cef998bc198d4616cd76b06ef5a157..922d76793e79007707bd62328867470371571bce 100644 (file)
@@ -79,4 +79,6 @@ void undo_block                       (UndoMain               *undostruct);
 void undo_unblock              (UndoMain               *undostruct);
 void undo_wrapping             (UndoMain               *undostruct, 
                                 gboolean                wrap);
+void undo_paste_clipboard      (GtkTextView            *textview, 
+                                UndoMain               *undostruct);
 #endif /* __UNDO_H__ */