Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quote html parts #626

Merged
merged 7 commits into from
May 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
# debug build - retrieve current project version from git
execute_process (
COMMAND git describe --abbrev=8 --tags --always
COMMAND git -C "${CMAKE_SOURCE_DIR}" describe --abbrev=8 --tags --always
OUTPUT_VARIABLE PROJECT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
Expand Down
20 changes: 10 additions & 10 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ Vagrant.configure("2") do |config|
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# config.vm.synced_folder "~/.mail", "/vagrant/mail"

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
config.vm.provider "virtualbox" do |vb|
# Display the VirtualBox GUI when booting the machine
# vb.gui = true

# Customize the amount of memory on the VM:
vb.memory = (3 * 1024).to_s
vb.cpus = 4
end
config.vm.provider "virtualbox" do |vb|
# Display the VirtualBox GUI when booting the machine
# vb.gui = true

# Customize the amount of memory on the VM:
vb.memory = (3 * 1024).to_s
vb.cpus = 4
end
#
# View the documentation for the provider you are using for more
# information on available options.
Expand All @@ -69,7 +69,7 @@ Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
pacman -Syu --noconfirm

pacman -S --noconfirm --needed cmake ninja git gcc notmuch-runtime glibmm gtkmm3 vte3 boost libsass libpeas ruby-ronn pkgconf webkit2gtk protobuf gobject-introspection xorg-xauth xorg-xclock cmark python-gobject ipython
pacman -S --noconfirm --needed cmake ninja git gcc notmuch-runtime glibmm gtkmm3 vte3 boost libsass libpeas ruby-ronn pkgconf webkit2gtk protobuf gobject-introspection xorg-xauth xorg-xclock cmark python-gobject ipython gvim

cat > /etc/profile.d/astroid.sh <<EOL
export ASTROID_DIR=/vagrant
Expand Down
2 changes: 2 additions & 0 deletions src/astroid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ namespace Astroid {
actions->close ();
delete actions;
}

logging::core::get()->remove_all_sinks ();
}

int Astroid::on_command_line (const refptr<Gio::ApplicationCommandLine> & cmd) {
Expand Down
3 changes: 2 additions & 1 deletion src/compose_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ namespace Astroid {
sf << s.rdbuf ();
s.close ();
if (account->signature_separate) {
md_body_content += "-- \n";
md_body_content += "-- \n";
}
md_body_content += sf.str ();
}
Expand Down Expand Up @@ -228,6 +228,7 @@ namespace Astroid {
contentStream = g_mime_stream_mem_new_with_buffer(_html.c_str(), _html.size());
}

g_spawn_close_pid (pid);
} catch (Glib::SpawnError &ex) {
LOG (error) << "cm: md: failed to spawn markdown processor: " << ex.what ();

Expand Down
2 changes: 2 additions & 0 deletions src/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ namespace Astroid {
default_config.put ("editor.markdown_processor", "cmark");
default_config.put ("editor.markdown_on", false); // default

default_config.put ("mail.reply.quote_processor", "w3m -dump -T text/html"); // e.g. lynx -dump

/* mail composition */
default_config.put ("mail.reply.quote_line", "Excerpts from %1's message of %2:"); // %1 = author, %2 = pretty_verbose_date
default_config.put ("mail.reply.mailinglist_reply_to_sender", true);
Expand Down
62 changes: 62 additions & 0 deletions src/message_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# include "message_thread.hh"
# include "chunk.hh"
# include "utils/utils.hh"
# include "utils/cmd.hh"
# include "utils/date_utils.hh"
# include "utils/address.hh"
# include "utils/ustring_utils.hh"
Expand Down Expand Up @@ -367,6 +368,67 @@ namespace Astroid {
return body;
}

ustring Message::quote () {
if (missing_content) {
LOG (warn) << "message: missing content, no text.";
return "";
}

ustring body;

function< void (refptr<Chunk>) > app_body =
[&] (refptr<Chunk> c)
{
/* check if we're the preferred sibling */
bool use = false;

if (c->siblings.size() >= 1) {
if (c->is_content_type ("text", "plain") || c->is_content_type ("text", "html")) {
use = true;
} else {
/* check if there are any other preferred */
if (all_of (c->siblings.begin (),
c->siblings.end (),
[](refptr<Chunk> c) { return !(c->is_content_type ("text", "plain") || c->is_content_type("text", "html")); })) {
use = true; // no
} else {
use = false;
}
}
} else {
use = true;
}

if (use) {
if (c->viewable && (c->is_content_type ("text", "plain") || c->is_content_type ("text", "html"))) {
/* will output html if HTML part */
if (c->is_content_type ("text", "html")) {
ustring quote_cmd = astroid->config ().get<string>("mail.reply.quote_processor");

if (!quote_cmd.empty()) {
ustring h = c->viewable_text (false);
ustring _stdout, _stderr;
Cmd::pipe (quote_cmd, h, _stdout, _stderr);

body += _stdout;
}

} else {
body += c->viewable_text (false);
}
}

for_each (c->kids.begin(),
c->kids.end (),
app_body);
}
};

app_body (root);

return body;
}

vector<refptr<Chunk>> Message::attachments () {
/* return a flat vector of attachments */

Expand Down
1 change: 1 addition & 0 deletions src/message_thread.hh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ namespace Astroid {
std::vector<ustring> tags;

ustring plain_text (bool fallback_html = false);
ustring quote ();
std::vector<refptr<Chunk>> attachments ();
refptr<Chunk> get_chunk_by_id (int id);

Expand Down
2 changes: 1 addition & 1 deletion src/modes/edit_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@ namespace Astroid {

if (tmpfile.fail()) {
LOG (error) << "em: error: could not create tmpfile!";
throw runtime_error ("em: coult not create tmpfile!");
throw runtime_error ("em: could not create tmpfile!");
}

tmpfile.close ();
Expand Down
2 changes: 1 addition & 1 deletion src/modes/forward_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ namespace Astroid {
quoted << "Cc: " << AddressList(msg->cc()).str () << endl;
quoted << endl;

string vt = msg->plain_text (false);
string vt = msg->quote ();
quoted << vt;

body = ustring(quoted.str());
Expand Down
2 changes: 1 addition & 1 deletion src/modes/reply_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace Astroid {
quoted << quoting_a.raw ()
<< endl;

string vt = msg->plain_text (false);
string vt = msg->quote ();
stringstream sstr (vt);
while (sstr.good()) {
string line;
Expand Down
57 changes: 55 additions & 2 deletions src/utils/cmd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using std::endl;
using std::string;

namespace bfs = boost::filesystem;

namespace Astroid {
Expand Down Expand Up @@ -44,9 +45,8 @@ namespace Astroid {
ustring c = (!undo ? cmd : undo_cmd);

LOG (info) << "cmd: running: " << c;
string _stdout;
string _stderr;
int exit;
string _stdout, _stderr;

string _cmd = c;
try {
Expand All @@ -71,6 +71,7 @@ namespace Astroid {
return (exit == 0);
}


ustring Cmd::substitute (const ustring _cmd) {
ustring ncmd = _cmd;

Expand All @@ -82,6 +83,58 @@ namespace Astroid {

return ncmd;
}

bool Cmd::pipe (ustring cmd, const ustring& _stdin, ustring& _stdout, ustring &_stderr) {
LOG (info) << "cmd: running: " << cmd;

try {
int pid;
int stdin;
int stdout;
int stderr;
std::vector<std::string> args = Glib::shell_parse_argv (cmd);

Glib::spawn_async_with_pipes ("",
args,
Glib::SPAWN_DO_NOT_REAP_CHILD |
Glib::SPAWN_SEARCH_PATH,
sigc::slot <void> (),
&pid,
&stdin,
&stdout,
&stderr
);

refptr<Glib::IOChannel> ch_stdin;
refptr<Glib::IOChannel> ch_stdout;
refptr<Glib::IOChannel> ch_stderr;
ch_stdin = Glib::IOChannel::create_from_fd (stdin);
ch_stdout = Glib::IOChannel::create_from_fd (stdout);
ch_stderr = Glib::IOChannel::create_from_fd (stderr);

ch_stdin->write (_stdin);
ch_stdin->close ();

ch_stderr->read_to_end (_stderr);
ch_stderr->close ();

if (!_stderr.empty ()) {
LOG (error) << "cmd: " << _stderr;
}

ch_stdout->read_to_end (_stdout);
ch_stdout->close ();

g_spawn_close_pid (pid);

} catch (Glib::SpawnError &ex) {
LOG (error) << "cmd: failed to execute: '" << cmd << "': " << ex.what ();
return false;
}


return true;
}
}


10 changes: 5 additions & 5 deletions src/utils/cmd.hh
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# pragma once

# include "astroid.hh"

# include <mutex>
# include <chrono>
# include <glibmm/threads.h>
# include <glibmm/iochannel.h>
# include <string>

namespace Astroid {
class Cmd {
Expand All @@ -25,8 +21,12 @@ namespace Astroid {
ustring undo_cmd;

int execute (bool undo); /* currently only in sync */
int execute (bool undo, std::string& _stdout, std::string& _stderr); /* currently only in sync */

ustring substitute (ustring);

public:
static bool pipe (ustring cmd, const ustring& _stdin, ustring& _stdout, ustring& _stderr);
};
}

2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ add_astroid_test (address test_address test_address.cc
add_astroid_test (dates test_dates test_dates.cc )
add_astroid_test (crypto test_crypto test_crypto.cc )
add_astroid_test (gmime_version test_gmime_version test_gmime_version.cc )
add_astroid_test (quote_html test_quote_html test_quote_html.cc )

63 changes: 63 additions & 0 deletions tests/test_quote_html.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# define BOOST_TEST_DYN_LINK
# define BOOST_TEST_MODULE TestCompose
# include <boost/test/unit_test.hpp>

# include "test_common.hh"
# include "message_thread.hh"
# include "utils/ustring_utils.hh"
# include "config.hh"

BOOST_AUTO_TEST_SUITE(QuoteHtml)

BOOST_AUTO_TEST_CASE(quote_html)
{
using Astroid::Message;
setup ();

ustring fname = "tests/mail/test_mail/only-html.eml";

Message m (fname);
ustring quoted = m.quote ();

LOG (trace) << "quoted plain text: " << quoted;

Astroid::UstringUtils::trim (quoted);

ustring target = R"(1. save an email as file.eml
2. write a new email
3. attach file.eml
4. save as draft
5. quit astroid
6. open draft again
7. edit the draft
8. here it is.

You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.*)";

BOOST_CHECK (quoted == target);

teardown ();
}

BOOST_AUTO_TEST_CASE(quote_html_convert_error)
{
using Astroid::Message;
setup ();

// TODO: Does not work with lynx
/* const_cast<ptree&>(astroid->config()).put ("mail.reply.quote_processor", "lynx -dump -stdin"); */

ustring fname = "tests/mail/test_mail/isspace-fail-utf-8.eml";

Message m (fname);
ustring quoted = m.quote ();

LOG (trace) << "quoted plain text: " << quoted;

teardown ();
}

BOOST_AUTO_TEST_SUITE_END()