[Xfce4-commits] <postler:master> Refactor fetch and send processes to be stateful

Christian Dywan noreply at xfce.org
Thu Feb 10 00:44:01 CET 2011


Updating branch refs/heads/master
         to 51fce9eadbe58992d3c7054553a76d394e024621 (commit)
       from e73876bfafb363cfe6a0dc4cc25bb313b57899b7 (commit)

commit 51fce9eadbe58992d3c7054553a76d394e024621
Author: Christian Dywan <christian at twotoasts.de>
Date:   Wed Feb 9 23:04:13 2011 +0100

    Refactor fetch and send processes to be stateful
    
    The HelperProcess class in the service keeps track
    of stdin and stderr of a process, emits a line_read
    signal, telling if it was an error and a done signal
    with an optional error message.
    
    For sending, messages on stderr are treated like
    fatal errors for now.
    
    No graphical error dialogue anymore in the service.
    
    The service gains a sent signal now. So the composer
    can show a progress bar and wait while sending is
    in progress or show an error if needed.
    
    Errors while receiving continue to be ignored.

 postler/postler-bureau.vala   |    2 +-
 postler/postler-client.vala   |   14 ++-
 postler/postler-composer.vala |   34 ++++++-
 postler/postler-service.vala  |  189 +++++++++++++++++++++++------------------
 4 files changed, 145 insertions(+), 94 deletions(-)

diff --git a/postler/postler-bureau.vala b/postler/postler-bureau.vala
index 722a05d..4208cdd 100644
--- a/postler/postler-bureau.vala
+++ b/postler/postler-bureau.vala
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2010 Christian Dywan <christian at twotoasts.de>
+ Copyright (C) 2011 Christian Dywan <christian at twotoasts.de>
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
diff --git a/postler/postler-client.vala b/postler/postler-client.vala
index 2502799..77d7bb8 100644
--- a/postler/postler-client.vala
+++ b/postler/postler-client.vala
@@ -16,7 +16,8 @@ namespace Postler {
         public signal void progress (string text, double fraction);
         public abstract bool receive (string account) throws IOError;
         public abstract bool fetch (string account) throws IOError;
-        public abstract bool send (string account, string filename) throws IOError;
+        public abstract void send (string account, string filename) throws IOError;
+        public signal void sent (string account, string filename, string error_message);
         public abstract void quit () throws IOError;
     }
 
@@ -31,6 +32,9 @@ namespace Postler {
                 client.progress.connect ((text, fraction) => {
                     progress (text != "" ? text : null, fraction);
                 });
+                client.sent.connect ((account, filename, error_message) => {
+                    sent (account, filename, error_message != "" ? error_message : null);
+                });
                 /* Ensure Postler is running, ignore errors */
                 Process.spawn_async (null,
                     { Postler.App.argv0, "-m", "service" }, null,
@@ -57,14 +61,16 @@ namespace Postler {
             }
         }
 
-        public bool send (string account, string filename) {
+        public void send (string account, string filename) {
             try {
-                return client.send (account, filename);
+                client.send (account, filename);
             } catch (GLib.Error error) {
-                return false;
+                sent (account, filename, error.message);
             }
         }
 
+        public signal void sent (string account, string filename, string? error_message);
+
         public void quit () {
             try {
                 client.quit ();
diff --git a/postler/postler-composer.vala b/postler/postler-composer.vala
index a49b2a1..627e845 100644
--- a/postler/postler-composer.vala
+++ b/postler/postler-composer.vala
@@ -28,6 +28,7 @@ public class Postler.Composer : Gtk.Window {
     Gtk.Entry entry_subject;
     Gtk.Button button_send;
     uint grace_period_timer = 0;
+    uint progress_timer = 0;
 
     public string subject { get { return entry_subject.text; } }
     int part = 0;
@@ -88,8 +89,9 @@ public class Postler.Composer : Gtk.Window {
 
         if (state) {
             button_send.label = STOCK_MAIL_SEND;
+            button_send.sensitive = true;
             progressbar.hide ();
-            grace_period_timer = 0;
+            grace_period_timer = progress_timer = 0;
         }
         else {
             button_send.label = Gtk.STOCK_CANCEL;
@@ -106,9 +108,16 @@ public class Postler.Composer : Gtk.Window {
         return true;
     }
 
+    bool send_progress_timer () {
+        progressbar.pulse ();
+        return true;
+    }
+
     void action_mail_send () {
         if (grace_period_timer > 0) {
             GLib.Source.remove (grace_period_timer);
+            if (progress_timer > 0)
+                GLib.Source.remove (progress_timer);
             toggle_sensitivity (true);
             return;
         }
@@ -120,6 +129,9 @@ public class Postler.Composer : Gtk.Window {
     }
 
     void send_message () {
+        progress_timer = GLib.Timeout.add_seconds (1, send_progress_timer);
+        button_send.sensitive = false;
+
         if (entry_subject.text == "") {
             var dialog = new Gtk.MessageDialog (this, 0,
                 Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE,
@@ -278,10 +290,22 @@ public class Postler.Composer : Gtk.Window {
                         + Postler.Messages.generate_maildir_filename ("S");
                     FileUtils.set_contents (filename, header + "\n" + body, -1);
                     FileUtils.chmod (filename, 0700);
-                    if (!client.send (info.name, filename))
-                        throw new GLib.FileError.FAILED (_("Sending failed."));
-                    /* TODO: Handle failure to send */
-                    destroy ();
+                    client.sent.connect ((account, file, message) => {
+                        if (account != info.name || file != filename)
+                            return;
+                        if (message == null) {
+                            destroy ();
+                            return;
+                        }
+                        var error_dialog = new Gtk.MessageDialog (null, 0,
+                            Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
+                            _("Failed to send message."));
+                        error_dialog.format_secondary_text (message);
+                        error_dialog.run ();
+                        error_dialog.destroy ();
+                        toggle_sensitivity (true);
+                    });
+                    client.send (info.name, filename);
                 } catch (GLib.Error error) {
                     GLib.critical (_("Failed to send message: %s"), error.message);
                     toggle_sensitivity (true);
diff --git a/postler/postler-service.vala b/postler/postler-service.vala
index 023c0b6..830a29b 100644
--- a/postler/postler-service.vala
+++ b/postler/postler-service.vala
@@ -10,6 +10,73 @@
 */
 
 namespace Postler {
+    internal class HelperProcess {
+        string? command = null;
+        IOChannel inputc;
+        IOChannel errorc;
+
+        internal void execute (string command) {
+            this.command = command;
+
+            try {
+                string[] argv;
+                Pid pid;
+                int out_fd, err_fd;
+                Shell.parse_argv (command, out argv);
+                Process.spawn_async_with_pipes (null, argv, null,
+                    SpawnFlags.SEARCH_PATH,
+                    null, out pid, null, out out_fd, out err_fd);
+                inputc = new IOChannel.unix_new (out_fd);
+                inputc.add_watch_full (0, IOCondition.IN | IOCondition.HUP, input_callback);
+                errorc = new IOChannel.unix_new (err_fd);
+                errorc.add_watch_full (0, IOCondition.IN | IOCondition.HUP, input_callback);
+            }
+            catch (GLib.Error error) {
+                GLib.debug ("Error, reading, %s: %s", command, error.message);
+                done (error.message);
+            }
+        }
+
+        bool input_callback (IOChannel channel, IOCondition condition) {
+            if (command == null)
+                return false;
+
+            if ((condition & IOCondition.HUP) == IOCondition.HUP) {
+                GLib.debug ("Done/ %s: %s",
+                            channel == errorc ? "error" : "input", command);
+                done ();
+                return false;
+            }
+
+            try {
+                StringBuilder msg = new StringBuilder ();
+                size_t len;
+                channel.read_line_string (msg, out len);
+                GLib.debug ("Line/ %s: %s",
+                            channel == errorc ? "error" : "input", msg.str);
+                line_read (msg.str, channel == errorc);
+                /* finnish may have been called in a line_read callback */
+                if (command == null)
+                    return false;
+            }
+            catch (Error error) {
+                GLib.debug ("Error, reading, %s: %s", command, error.message);
+                finnish (error.message);
+                return false;
+            }
+            return true;
+        }
+
+        internal signal void line_read (string line, bool is_error);
+
+        internal void finnish (string error_message="") {
+            command = null;
+            done (error_message);
+        }
+
+        internal signal void done (string error_message="");
+    }
+
     [DBus (name = "org.elementary.Postler")]
     class PostlerService : Object {
         double total = 0;
@@ -95,64 +162,6 @@ namespace Postler {
         }
 #endif
 
-        bool execute_command_with_status (string command, IOFunc io_callback) {
-            try {
-                string[] argv;
-                Pid pid;
-                int out_fd;
-                Shell.parse_argv (command, out argv);
-                Process.spawn_async_with_pipes (null, argv, null,
-                    SpawnFlags.SEARCH_PATH,
-                    null, out pid, null, out out_fd, null);
-                IOChannel ioc = new IOChannel.unix_new (out_fd);
-                ioc.add_watch (IOCondition.IN | IOCondition.HUP, io_callback);
-            }
-            catch (GLib.Error error) {
-                var error_dialog = new Gtk.MessageDialog (null, 0,
-                    Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
-                    _("Failed to execute external command."));
-                error_dialog.format_secondary_text (error.message);
-                error_dialog.response.connect ((dialog, response) => {
-                    dialog.destroy ();
-                });
-                error_dialog.show ();
-            }
-            return true;
-        }
-
-        bool mbsync_input (IOChannel gio, IOCondition condition) {
-            IOStatus ret;
-            StringBuilder msg = new StringBuilder ();
-            size_t len;
-
-            if ((condition & IOCondition.HUP) == IOCondition.HUP)
-                return mbsync_done (gio, condition);
-
-            try {
-                ret = gio.read_line_string (msg, out len);
-            }
-            catch (Error error) {
-                GLib.warning ("Error reading: %s", error.message);
-            }
-            GLib.debug ("Read %u bytes: %s", (uint)len, msg.str);
-
-            /* FIXME: for whatever reason the satus itself is not updated
-             * in the label... escape chars, anyone?*/
-            display_status (msg.str.split ("\n") [0]);
-            return true;
-        }
-
-        bool mbsync_done (IOChannel gio, IOCondition condition) {
-            GLib.debug ("Done: %d new messages", unread);
-            progress ("", 0.0);
-            if (unread > 0) {
-                Postler.App.send_notification (ngettext ("You have %d message",
-                    "You have %d new messages", unread).printf (unread));
-                Postler.App.play_sound ("message-new-email");
-            }
-            return false;
-        }
-
         void display_status (string msg) {
             if (msg.contains ("master: ")) {
                 total = (msg.split (" ") [1]).to_double ();
@@ -206,9 +215,29 @@ namespace Postler {
             unread = 0;
             foreach (var info in infos) {
                 try {
-                    string command = accounts.get_receive_command (info);
-                    execute_command_with_status (command, mbsync_input);
                     progress (_("Fetching..."), 0.0);
+                    string command = accounts.get_receive_command (info);
+                    var helper = new HelperProcess ();
+                    helper.line_read.connect ((line) => {
+                        /* FIXME: the status itself isn't updated - escape chars? */
+                        display_status (line.split ("\n") [0]);
+                    });
+                    helper.done.connect ((error_message) => {
+                        progress ("", 0.0);
+                        /* FIXME: Handle error_message */
+                        if (error_message != "") {
+                            GLib.critical (error_message);
+                            return;
+                        }
+                        GLib.debug ("Done: %d new messages", unread);
+                        if (unread > 0) {
+                            Postler.App.send_notification (
+                                ngettext ("You have %d message",
+                                "You have %d new messages", unread).printf (unread));
+                            Postler.App.play_sound ("message-new-email");
+                        }
+                    });
+                    helper.execute (command);
                 } catch (Error error) {
                     return false;
                 }
@@ -265,40 +294,32 @@ namespace Postler {
             return true;
         }
 
-        bool msmtp_input (IOChannel channel, IOCondition condition) {
-            if ((condition & IOCondition.HUP) == IOCondition.HUP) {
-                /* FIXME: Move file */
-                GLib.debug ("Done sending");
-                return false;
-            }
-
-            try {
-                StringBuilder msg = new StringBuilder ();
-                size_t len;
-                channel.read_line_string (msg, out len);
-                GLib.debug ("%s", msg.str);
-            }
-            catch (Error error) {
-                GLib.warning ("Error reading: %s", error.message);
-            }
-            return true;
-        }
-
-        public bool send (string account, string filename) {
+        public void send (string account, string filename) {
             var accounts = new Accounts ();
             try {
                 foreach (var info in accounts.get_infos ())
                     if (info.name == account) {
                         string command = accounts.get_send_command (info, filename);
-                        execute_command_with_status (command, msmtp_input);
-                        return true;
+                        var helper = new HelperProcess ();
+                        helper.line_read.connect ((line, is_error) => {
+                            if (is_error)
+                                helper.finnish (line);
+                        });
+                        helper.done.connect ((error_message) => {
+                            sent (account, filename,
+                                (error_message ?? "").replace ("msmtp: ", ""));
+                        });
+                        helper.execute (command);
+                        return;
                     }
             } catch (Error error) {
-                return false;
+                sent (account, filename, error.message);
             }
-            return false;
+            sent (account, filename, _("Account \"%s\" doesn't exist").printf (account));
         }
 
+        public signal void sent (string account, string filename, string error_message);
+
         public void quit () {
             Gtk.main_quit ();
         }



More information about the Xfce4-commits mailing list