Skip to content

Commit

Permalink
improve mailto uri handling
Browse files Browse the repository at this point in the history
1. This introduces consistent mailto uri handling, supporting passing a
   body and all headers that can be given as agruments to EditMessage,
   namely, To, From, Cc, Bcc and Subject.
   Other headers are not dropped but prepended to the email body with a note.

2. Positional (i.e., non-option) commandline arguments are now
   interpreted as --mailto options.

3. Multiple --mailto options on the commandline are now supported, and are
   merged into one mailto argument before being passed to EditMessage.

4. A consequence is that libsoup is not used any more, enabling
   compatibility with webkit2gtk-4.1 while maintaining compatibility with
   gio (glib) 2.16, and thus building on older and current distros.
  • Loading branch information
jorsn committed Jun 4, 2024
1 parent c1e5cdb commit 4c76a4c
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 72 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci-debian-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ jobs:
libpeas-dev \
libprotobuf-dev \
libsass-dev \
libsoup2.4-dev \
libvte-2.91-dev \
libwebkit2gtk-${WEBKITGTK_VERSION}-dev \
ninja-build \
Expand Down
6 changes: 1 addition & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ pkg_check_modules (GLIBMM2 REQUIRED glibmm-2.4)
pkg_check_modules (WEBKIT2GTK REQUIRED webkit2gtk-4.0>=2.22)
pkg_check_modules (SASS REQUIRED libsass)
pkg_check_modules (GIOMM2 REQUIRED giomm-2.4)
pkg_check_modules (GIOUNIX REQUIRED gio-unix-2.0)
pkg_check_modules (LIBSOUP REQUIRED libsoup-2.4)
pkg_check_modules (GIOUNIX REQUIRED gio-unix-2.0>=2.16)

string (REGEX REPLACE "([0-9]+\.[0-9]+)\.[0-9]+" "\\1" GMIME_MAJOR_MINOR ${Notmuch_GMIME_VERSION})
pkg_check_modules (GMIME REQUIRED gmime-${GMIME_MAJOR_MINOR}>=${Notmuch_GMIME_VERSION})
Expand Down Expand Up @@ -154,7 +153,6 @@ include_directories (
${GLIBMM2_INCLUDE_DIRS}
${GIOMM2_INCLUDE_DIRS}
${GIOUNIX_INCLUDE_DIRS}
${LIBSOUP_INCLUDE_DIRS}
${GMIME_INCLUDE_DIRS}
${WEBKIT2GTK_INCLUDE_DIRS}
${VTE2_INCLUDE_DIRS}
Expand All @@ -169,7 +167,6 @@ add_compile_options (
${GLIBMM2_CFLAGS}
${GIOMM2_CFLAGS}
${GIOUNIX_CFLAGS}
${LIBSOUP_CFLAGS}
${GMIME_CFLAGS}
${WEBKIT2GTK_CFLAGS}
${VTE2_CFLAGS}
Expand Down Expand Up @@ -339,7 +336,6 @@ target_link_libraries (
${GLIBMM2_LDFLAGS}
${GIOMM2_LDFLAGS}
${GIOUNIX_LDFLAGS}
${LIBSOUP_LDFLAGS}
${GMIME_LDFLAGS}
${VTE2_LDFLAGS}
${SASS_LDFLAGS}
Expand Down
91 changes: 39 additions & 52 deletions src/astroid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@
# include <gmime/gmime.h>
# include <utils/gmime/gmime-compat.h>

# include <libsoup/soup.h>

using namespace std;
using namespace boost::filesystem;

Expand Down Expand Up @@ -126,7 +124,7 @@ namespace Astroid {
# ifdef DEBUG
( "test-config,t", "use test config (same as used when tests are run), only makes sense from the source root")
# endif
( "mailto,m", po::value<ustring>(), "compose mail with mailto url or address")
( "mailto,m", po::value< vector<ustring> >()->composing(), "compose mail with mailto url or address")
( "no-auto-poll", "do not poll automatically")
( "disable-log", "disable logging")
( "log-stdout", "log to stdout regardless of configuration")
Expand All @@ -139,6 +137,9 @@ namespace Astroid {
# else
;
# endif

/* default option (without --<option> prefix) */
pdesc.add("mailto", -1);
}
// }}}

Expand All @@ -153,7 +154,11 @@ namespace Astroid {
bool show_help = false;

try {
po::store ( po::parse_command_line (argc, argv, desc), vm );
po::store ( po::command_line_parser(argc, argv).
options(desc).
positional(pdesc).
run(),
vm );
} catch (po::unknown_option &ex) {
LOG (error) << "unknown option" << endl;
LOG (error) << ex.what() << endl;
Expand Down Expand Up @@ -438,16 +443,40 @@ namespace Astroid {
po::variables_map vm;

try {
po::store ( po::parse_command_line (argc, argv, desc), vm );
po::store ( po::command_line_parser(argc, argv).
options(desc).
positional(pdesc).
run(),
vm );
} catch (po::unknown_option &ex) {
LOG (error) << "unknown option" << endl;
LOG (error) << ex.what() << endl;
return 1;
}

if (vm.count("mailto")) {
ustring mailtourl = vm["mailto"].as<ustring>();
send_mailto (mailtourl);
vector <ustring> mailto_list = vm["mailto"].as<vector <ustring>>();

// is the conversion from ustring to std::string really safe?
std::string mailto = "";
std::string next;

ustring::size_type sep;

for (std::vector<ustring>::size_type i = 0; i < mailto_list.size(); i++) {
next = mailto_list[i];
sep = next.find("?");
if (sep != next.npos)
next[sep] = '&';
if (next.substr(0, 7) == "mailto:")
next.erase(0,7);
mailto += "&to=" + next;
}

mailto[0] = '?';
mailto.insert(0, "mailto:");

send_mailto (mailto);
new_window = false;
}

Expand Down Expand Up @@ -545,53 +574,11 @@ namespace Astroid {
open_new_window ();
}

void Astroid::send_mailto (ustring url) {
LOG (info) << "astroid: mailto: " << url;
void Astroid::send_mailto (ustring uri) {
LOG (info) << "astroid: mailto: " << uri;

MainWindow * mw = (MainWindow*) get_windows ()[0];

SoupURI *uri = soup_uri_new(url.c_str());

if (SOUP_URI_IS_VALID(uri)) {
/* we got an mailto url */
ustring from, to, cc, bcc, subject, body;

to = soup_uri_decode (soup_uri_get_path (uri));

const char * soup_query = soup_uri_get_query (uri);
if (soup_query) {
std::istringstream query_string (soup_query);
std::string keyval;
while (std::getline(query_string, keyval, '&')) {
ustring::size_type pos = keyval.find ("=");

ustring key = keyval.substr (0, pos);
key = key.lowercase ();

ustring val = soup_uri_decode (keyval.substr (pos+1).c_str());

if (key == "from") {
from = ustring (val);
} else if (key == "cc") {
cc = ustring (val);
} else if (key == "bcc") {
bcc = ustring (val);
} else if (key == "subject" ) {
subject = ustring (val);
} else if (key == "body") {
body = ustring (val);
}
}
}

mw->add_mode (new EditMessage (mw, to, from, cc, bcc, subject, body));

} else {
/* we probably just got the address on the cmd line */
mw->add_mode (new EditMessage (mw, url));
}

soup_uri_free (uri);
mw->add_mode (new EditMessage (mw, uri));
}

int Astroid::hint_level () {
Expand Down
1 change: 1 addition & 0 deletions src/astroid.hh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ namespace Astroid {

int _hint_level = 0;
po::options_description desc;
po::positional_options_description pdesc;
};

/* globally available instance of our main Astroid-class */
Expand Down
3 changes: 1 addition & 2 deletions src/message_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -721,8 +721,7 @@ namespace Astroid {

ustring scheme = Glib::uri_parse_scheme (a);
if (scheme == "mailto") {

a = a.substr (scheme.length ()+1, a.length () - scheme.length()-1);
a = a.substr (7);
UstringUtils::trim (a);
al += Address(a);
}
Expand Down
89 changes: 82 additions & 7 deletions src/modes/edit_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# include <memory>

# include <gtkmm.h>
# include <glib.h>

# include <boost/filesystem.hpp>

Expand Down Expand Up @@ -35,19 +36,88 @@ using namespace boost::filesystem;
namespace Astroid {
int EditMessage::edit_id = 0;

EditMessage::EditMessage (MainWindow * mw, ustring _to, ustring _from, ustring _cc, ustring _bcc, ustring _subject, ustring _body) :
EditMessage::EditMessage (MainWindow * mw, ustring mailto, ustring _from, ustring _cc, ustring _bcc, ustring _subject, ustring _body) :
EditMessage (mw, false) { // {{{

in_read = false;
to = _to;
cc = _cc;
bcc = _bcc;
subject = _subject;
body = _body;
to = "";
cc = "";
bcc = "";
subject = "";
body = "";

if (ustring (g_uri_parse_scheme(mailto.c_str())) != "mailto") {
// if the prefix 'mailto:' is missing, assume it is only the receipient's address
to = mailto;
} else {
mailto.erase(0,7);
ustring::size_type sep = mailto.find("?");

to = g_uri_unescape_string (mailto.substr(0, sep).c_str(), NULL);
try {
mailto.erase(0, sep+1);
} catch (const std::out_of_range& ex) {
mailto = "";
}

ustring key;
ustring val;

while (mailto.size() > 0) {
sep = mailto.find("=");
key = mailto.substr(0, sep);
try {
mailto.erase (0,sep+1);
} catch (const std::out_of_range& ex) {
// = not found, i.e. syntax error
break;
}
sep = mailto.find("&");
val = ustring (g_uri_unescape_string (mailto.substr(0, sep).c_str(), NULL));
try {
if (sep == mailto.npos) {
mailto = "";
} else {
mailto.erase (0, sep+1);
}
} catch (const std::out_of_range& ex) {
// no value
break;
}

key = key.lowercase ();
if (!val.empty ()) {
if (key == "to") {
append_address (&to, val);
} else if (key == "cc") {
append_address (&cc, val);
} else if (key == "bcc") {
append_address (&bcc, val);
} else if (key == "subject") {
subject += val;
} else if (key == "body") {
body += val;
} else if (key == "from") {
// we accept only one "From" address
set_from (Address (val));
} else {
body = ustring::compose ("Unknown header: %1: %2\n%3", key, val, body);
}
}
}
}

append_address (&cc, _cc);
append_address (&bcc, _bcc);
subject += _subject;
body += _body;


if (!_from.empty ()) {
// we accept only one "From" address
set_from (Address (_from));
}


/* reload message */
prepare_message ();
read_edited_message ();
Expand Down Expand Up @@ -1029,6 +1099,11 @@ namespace Astroid {
}
}

void EditMessage::append_address (ustring *s, ustring a) {
*s += (s->empty() ? a : "," + a);
}


/* }}} */

/* send message {{{ */
Expand Down
4 changes: 3 additions & 1 deletion src/modes/edit_message.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ namespace Astroid {

public:
EditMessage (MainWindow *, bool edit_when_ready = true);
EditMessage (MainWindow *, ustring to, ustring from = "", ustring cc = "", ustring bcc = "", ustring subject = "", ustring body = "");
// mailto can be mailto uri or simply To: addresses
EditMessage (MainWindow *, ustring mailto, ustring from = "", ustring cc = "", ustring bcc = "", ustring subject = "", ustring body = "");
EditMessage (MainWindow *, refptr<Message> _msg);
~EditMessage ();

Expand Down Expand Up @@ -166,6 +167,7 @@ namespace Astroid {
void on_from_combo_changed ();
//bool on_from_combo_key_press (GdkEventKey *);
void on_element_action (int id, ThreadView::ElementAction action);
void append_address (ustring *s, ustring a);

public:
void grab_modal () override;
Expand Down
4 changes: 0 additions & 4 deletions src/modes/thread_view/thread_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,6 @@ namespace Astroid {
ustring scheme = Glib::uri_parse_scheme (uri);

if (scheme == "mailto") {

uri = uri.substr (scheme.length ()+1, uri.length () - scheme.length()-1);
UstringUtils::trim(uri);

main_window->add_mode (new EditMessage (main_window, uri));

} else if (scheme == "id" || scheme == "mid" ) {
Expand Down

0 comments on commit 4c76a4c

Please sign in to comment.