Closes #5303 Attachment reminder
This commit is contained in:
parent
833066746c
commit
34236be3d5
2 changed files with 118 additions and 2 deletions
|
|
@ -80,6 +80,10 @@ public class ComposerWindow : Gtk.Window {
|
|||
</style>
|
||||
</head><body id="message-body"></body></html>""";
|
||||
|
||||
public const string ATTACHMENT_KEYWORDS_GENERIC = ".doc|.pdf|.xls|.ppt|.rtf|.pps";
|
||||
/// A list of keywords, separated by pipe ("|") characters, that suggest an attachment
|
||||
public const string ATTACHMENT_KEYWORDS_LOCALIZED = _("attach|enclosed|enclosing|cover letter");
|
||||
|
||||
// Signal sent when the "Send" button is clicked.
|
||||
public signal void send(ComposerWindow composer);
|
||||
|
||||
|
|
@ -304,7 +308,7 @@ public class ComposerWindow : Gtk.Window {
|
|||
try {
|
||||
body_html = referred.get_message().get_body(true);
|
||||
} catch (Error error) {
|
||||
debug("Error getting messae body: %s", error.message);
|
||||
debug("Error getting message body: %s", error.message);
|
||||
}
|
||||
add_attachments(referred.attachments);
|
||||
break;
|
||||
|
|
@ -659,9 +663,56 @@ public class ComposerWindow : Gtk.Window {
|
|||
on_discard();
|
||||
}
|
||||
|
||||
private bool email_contains_attachment_keywords() {
|
||||
// Filter out all content contained in block quotes
|
||||
string filtered = @"$subject\n";
|
||||
filtered += Util.DOM.get_text_representation(editor.get_dom_document(), "blockquote");
|
||||
|
||||
Regex url_regex = null;
|
||||
try {
|
||||
// Prepare to ignore urls later
|
||||
url_regex = new Regex(URL_REGEX, RegexCompileFlags.CASELESS);
|
||||
} catch (Error error) {
|
||||
debug("Error building regex in keyword checker: %s", error.message);
|
||||
}
|
||||
|
||||
string[] keys = ATTACHMENT_KEYWORDS_GENERIC.casefold().split("|");
|
||||
foreach (string key in ATTACHMENT_KEYWORDS_LOCALIZED.casefold().split("|")) {
|
||||
keys += key;
|
||||
}
|
||||
|
||||
string folded;
|
||||
foreach (string line in filtered.split("\n")) {
|
||||
// Stop looking once we hit forwarded content
|
||||
if (line.has_prefix("--")) {
|
||||
break;
|
||||
}
|
||||
|
||||
folded = line.casefold();
|
||||
foreach (string key in keys) {
|
||||
if (key in folded) {
|
||||
try {
|
||||
// Make sure the match isn't coming from a url
|
||||
if (key in url_regex.replace(folded, -1, 0, "")) {
|
||||
return true;
|
||||
}
|
||||
} catch (Error error) {
|
||||
debug("Regex replacement error in keyword checker: %s", error.message);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool should_send() {
|
||||
bool has_subject = !Geary.String.is_empty(subject.strip());
|
||||
bool has_body_or_attachment = !Geary.String.is_empty(get_html()) || attachment_files.size > 0;
|
||||
bool has_body = !Geary.String.is_empty(get_html());
|
||||
bool has_attachment = attachment_files.size > 0;
|
||||
bool has_body_or_attachment = has_body || has_attachment;
|
||||
|
||||
string? confirmation = null;
|
||||
if (!has_subject && !has_body_or_attachment) {
|
||||
confirmation = _("Send message with an empty subject and body?");
|
||||
|
|
@ -669,6 +720,8 @@ public class ComposerWindow : Gtk.Window {
|
|||
confirmation = _("Send message with an empty subject?");
|
||||
} else if (!has_body_or_attachment) {
|
||||
confirmation = _("Send message with an empty body?");
|
||||
} else if (!has_attachment && email_contains_attachment_keywords()) {
|
||||
confirmation = _("Send message without an attachment?");
|
||||
}
|
||||
if (confirmation != null) {
|
||||
ConfirmationDialog dialog = new ConfirmationDialog(this,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,69 @@ namespace Util.DOM {
|
|||
class_list.remove(clas);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the text contained in the DOM document, after ignoring tags of type "exclude"
|
||||
// and padding newlines where appropriate. Used to scan for attachment keywords.
|
||||
public string get_text_representation(WebKit.DOM.Document doc, string exclude) {
|
||||
WebKit.DOM.HTMLElement? copy = Util.DOM.clone_node(doc.get_body());
|
||||
if (copy == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Keep deleting the next excluded element until there are none left
|
||||
while (true) {
|
||||
WebKit.DOM.HTMLElement? current = Util.DOM.select(copy, exclude);
|
||||
if (current == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
WebKit.DOM.Node parent = current.get_parent_node();
|
||||
try {
|
||||
parent.remove_child(current);
|
||||
} catch (Error error) {
|
||||
debug("Error removing blockquotes: %s", error.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WebKit.DOM.NodeList node_list;
|
||||
try {
|
||||
node_list = copy.query_selector_all("br");
|
||||
} catch (Error error) {
|
||||
debug("Error finding <br>s: %s", error.message);
|
||||
return copy.get_inner_text();
|
||||
}
|
||||
|
||||
// Replace <br> tags with newlines
|
||||
for (int i = 0; i < node_list.length; ++i) {
|
||||
WebKit.DOM.Node br = node_list.item(i);
|
||||
WebKit.DOM.Node parent = br.get_parent_node();
|
||||
try {
|
||||
parent.replace_child(doc.create_text_node("\n"), br);
|
||||
} catch (Error error) {
|
||||
debug("Error replacing <br>: %s", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
node_list = copy.query_selector_all("div");
|
||||
} catch (Error error) {
|
||||
debug("Error finding <div>s: %s", error.message);
|
||||
return copy.get_inner_text();
|
||||
}
|
||||
|
||||
// Pad each <div> with newlines
|
||||
for (int i = 0; i < node_list.length; ++i) {
|
||||
WebKit.DOM.Node div = node_list.item(i);
|
||||
try {
|
||||
div.insert_before(doc.create_text_node("\n"), div.first_child);
|
||||
div.append_child(doc.create_text_node("\n"));
|
||||
} catch (Error error) {
|
||||
debug("Error padding <div> with newlines: %s", error.message);
|
||||
}
|
||||
}
|
||||
return copy.get_inner_text();
|
||||
}
|
||||
}
|
||||
|
||||
public void bind_event(WebKit.WebView view, string selector, string event, Callback callback,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue