[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