Skip to content

Commit 4c76a4c

Browse files
committed
improve mailto uri handling
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.
1 parent c1e5cdb commit 4c76a4c

File tree

8 files changed

+127
-72
lines changed

8 files changed

+127
-72
lines changed

.github/workflows/ci-debian-build-test.yml

-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ jobs:
5959
libpeas-dev \
6060
libprotobuf-dev \
6161
libsass-dev \
62-
libsoup2.4-dev \
6362
libvte-2.91-dev \
6463
libwebkit2gtk-${WEBKITGTK_VERSION}-dev \
6564
ninja-build \

CMakeLists.txt

+1-5
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ pkg_check_modules (GLIBMM2 REQUIRED glibmm-2.4)
9898
pkg_check_modules (WEBKIT2GTK REQUIRED webkit2gtk-4.0>=2.22)
9999
pkg_check_modules (SASS REQUIRED libsass)
100100
pkg_check_modules (GIOMM2 REQUIRED giomm-2.4)
101-
pkg_check_modules (GIOUNIX REQUIRED gio-unix-2.0)
102-
pkg_check_modules (LIBSOUP REQUIRED libsoup-2.4)
101+
pkg_check_modules (GIOUNIX REQUIRED gio-unix-2.0>=2.16)
103102

104103
string (REGEX REPLACE "([0-9]+\.[0-9]+)\.[0-9]+" "\\1" GMIME_MAJOR_MINOR ${Notmuch_GMIME_VERSION})
105104
pkg_check_modules (GMIME REQUIRED gmime-${GMIME_MAJOR_MINOR}>=${Notmuch_GMIME_VERSION})
@@ -154,7 +153,6 @@ include_directories (
154153
${GLIBMM2_INCLUDE_DIRS}
155154
${GIOMM2_INCLUDE_DIRS}
156155
${GIOUNIX_INCLUDE_DIRS}
157-
${LIBSOUP_INCLUDE_DIRS}
158156
${GMIME_INCLUDE_DIRS}
159157
${WEBKIT2GTK_INCLUDE_DIRS}
160158
${VTE2_INCLUDE_DIRS}
@@ -169,7 +167,6 @@ add_compile_options (
169167
${GLIBMM2_CFLAGS}
170168
${GIOMM2_CFLAGS}
171169
${GIOUNIX_CFLAGS}
172-
${LIBSOUP_CFLAGS}
173170
${GMIME_CFLAGS}
174171
${WEBKIT2GTK_CFLAGS}
175172
${VTE2_CFLAGS}
@@ -339,7 +336,6 @@ target_link_libraries (
339336
${GLIBMM2_LDFLAGS}
340337
${GIOMM2_LDFLAGS}
341338
${GIOUNIX_LDFLAGS}
342-
${LIBSOUP_LDFLAGS}
343339
${GMIME_LDFLAGS}
344340
${VTE2_LDFLAGS}
345341
${SASS_LDFLAGS}

src/astroid.cc

+39-52
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@
5353
# include <gmime/gmime.h>
5454
# include <utils/gmime/gmime-compat.h>
5555

56-
# include <libsoup/soup.h>
57-
5856
using namespace std;
5957
using namespace boost::filesystem;
6058

@@ -126,7 +124,7 @@ namespace Astroid {
126124
# ifdef DEBUG
127125
( "test-config,t", "use test config (same as used when tests are run), only makes sense from the source root")
128126
# endif
129-
( "mailto,m", po::value<ustring>(), "compose mail with mailto url or address")
127+
( "mailto,m", po::value< vector<ustring> >()->composing(), "compose mail with mailto url or address")
130128
( "no-auto-poll", "do not poll automatically")
131129
( "disable-log", "disable logging")
132130
( "log-stdout", "log to stdout regardless of configuration")
@@ -139,6 +137,9 @@ namespace Astroid {
139137
# else
140138
;
141139
# endif
140+
141+
/* default option (without --<option> prefix) */
142+
pdesc.add("mailto", -1);
142143
}
143144
// }}}
144145

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

155156
try {
156-
po::store ( po::parse_command_line (argc, argv, desc), vm );
157+
po::store ( po::command_line_parser(argc, argv).
158+
options(desc).
159+
positional(pdesc).
160+
run(),
161+
vm );
157162
} catch (po::unknown_option &ex) {
158163
LOG (error) << "unknown option" << endl;
159164
LOG (error) << ex.what() << endl;
@@ -438,16 +443,40 @@ namespace Astroid {
438443
po::variables_map vm;
439444

440445
try {
441-
po::store ( po::parse_command_line (argc, argv, desc), vm );
446+
po::store ( po::command_line_parser(argc, argv).
447+
options(desc).
448+
positional(pdesc).
449+
run(),
450+
vm );
442451
} catch (po::unknown_option &ex) {
443452
LOG (error) << "unknown option" << endl;
444453
LOG (error) << ex.what() << endl;
445454
return 1;
446455
}
447456

448457
if (vm.count("mailto")) {
449-
ustring mailtourl = vm["mailto"].as<ustring>();
450-
send_mailto (mailtourl);
458+
vector <ustring> mailto_list = vm["mailto"].as<vector <ustring>>();
459+
460+
// is the conversion from ustring to std::string really safe?
461+
std::string mailto = "";
462+
std::string next;
463+
464+
ustring::size_type sep;
465+
466+
for (std::vector<ustring>::size_type i = 0; i < mailto_list.size(); i++) {
467+
next = mailto_list[i];
468+
sep = next.find("?");
469+
if (sep != next.npos)
470+
next[sep] = '&';
471+
if (next.substr(0, 7) == "mailto:")
472+
next.erase(0,7);
473+
mailto += "&to=" + next;
474+
}
475+
476+
mailto[0] = '?';
477+
mailto.insert(0, "mailto:");
478+
479+
send_mailto (mailto);
451480
new_window = false;
452481
}
453482

@@ -545,53 +574,11 @@ namespace Astroid {
545574
open_new_window ();
546575
}
547576

548-
void Astroid::send_mailto (ustring url) {
549-
LOG (info) << "astroid: mailto: " << url;
577+
void Astroid::send_mailto (ustring uri) {
578+
LOG (info) << "astroid: mailto: " << uri;
550579

551580
MainWindow * mw = (MainWindow*) get_windows ()[0];
552-
553-
SoupURI *uri = soup_uri_new(url.c_str());
554-
555-
if (SOUP_URI_IS_VALID(uri)) {
556-
/* we got an mailto url */
557-
ustring from, to, cc, bcc, subject, body;
558-
559-
to = soup_uri_decode (soup_uri_get_path (uri));
560-
561-
const char * soup_query = soup_uri_get_query (uri);
562-
if (soup_query) {
563-
std::istringstream query_string (soup_query);
564-
std::string keyval;
565-
while (std::getline(query_string, keyval, '&')) {
566-
ustring::size_type pos = keyval.find ("=");
567-
568-
ustring key = keyval.substr (0, pos);
569-
key = key.lowercase ();
570-
571-
ustring val = soup_uri_decode (keyval.substr (pos+1).c_str());
572-
573-
if (key == "from") {
574-
from = ustring (val);
575-
} else if (key == "cc") {
576-
cc = ustring (val);
577-
} else if (key == "bcc") {
578-
bcc = ustring (val);
579-
} else if (key == "subject" ) {
580-
subject = ustring (val);
581-
} else if (key == "body") {
582-
body = ustring (val);
583-
}
584-
}
585-
}
586-
587-
mw->add_mode (new EditMessage (mw, to, from, cc, bcc, subject, body));
588-
589-
} else {
590-
/* we probably just got the address on the cmd line */
591-
mw->add_mode (new EditMessage (mw, url));
592-
}
593-
594-
soup_uri_free (uri);
581+
mw->add_mode (new EditMessage (mw, uri));
595582
}
596583

597584
int Astroid::hint_level () {

src/astroid.hh

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ namespace Astroid {
9494

9595
int _hint_level = 0;
9696
po::options_description desc;
97+
po::positional_options_description pdesc;
9798
};
9899

99100
/* globally available instance of our main Astroid-class */

src/message_thread.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -721,8 +721,7 @@ namespace Astroid {
721721

722722
ustring scheme = Glib::uri_parse_scheme (a);
723723
if (scheme == "mailto") {
724-
725-
a = a.substr (scheme.length ()+1, a.length () - scheme.length()-1);
724+
a = a.substr (7);
726725
UstringUtils::trim (a);
727726
al += Address(a);
728727
}

src/modes/edit_message.cc

+82-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# include <memory>
77

88
# include <gtkmm.h>
9+
# include <glib.h>
910

1011
# include <boost/filesystem.hpp>
1112

@@ -35,19 +36,88 @@ using namespace boost::filesystem;
3536
namespace Astroid {
3637
int EditMessage::edit_id = 0;
3738

38-
EditMessage::EditMessage (MainWindow * mw, ustring _to, ustring _from, ustring _cc, ustring _bcc, ustring _subject, ustring _body) :
39+
EditMessage::EditMessage (MainWindow * mw, ustring mailto, ustring _from, ustring _cc, ustring _bcc, ustring _subject, ustring _body) :
3940
EditMessage (mw, false) { // {{{
40-
4141
in_read = false;
42-
to = _to;
43-
cc = _cc;
44-
bcc = _bcc;
45-
subject = _subject;
46-
body = _body;
42+
to = "";
43+
cc = "";
44+
bcc = "";
45+
subject = "";
46+
body = "";
47+
48+
if (ustring (g_uri_parse_scheme(mailto.c_str())) != "mailto") {
49+
// if the prefix 'mailto:' is missing, assume it is only the receipient's address
50+
to = mailto;
51+
} else {
52+
mailto.erase(0,7);
53+
ustring::size_type sep = mailto.find("?");
54+
55+
to = g_uri_unescape_string (mailto.substr(0, sep).c_str(), NULL);
56+
try {
57+
mailto.erase(0, sep+1);
58+
} catch (const std::out_of_range& ex) {
59+
mailto = "";
60+
}
61+
62+
ustring key;
63+
ustring val;
64+
65+
while (mailto.size() > 0) {
66+
sep = mailto.find("=");
67+
key = mailto.substr(0, sep);
68+
try {
69+
mailto.erase (0,sep+1);
70+
} catch (const std::out_of_range& ex) {
71+
// = not found, i.e. syntax error
72+
break;
73+
}
74+
sep = mailto.find("&");
75+
val = ustring (g_uri_unescape_string (mailto.substr(0, sep).c_str(), NULL));
76+
try {
77+
if (sep == mailto.npos) {
78+
mailto = "";
79+
} else {
80+
mailto.erase (0, sep+1);
81+
}
82+
} catch (const std::out_of_range& ex) {
83+
// no value
84+
break;
85+
}
86+
87+
key = key.lowercase ();
88+
if (!val.empty ()) {
89+
if (key == "to") {
90+
append_address (&to, val);
91+
} else if (key == "cc") {
92+
append_address (&cc, val);
93+
} else if (key == "bcc") {
94+
append_address (&bcc, val);
95+
} else if (key == "subject") {
96+
subject += val;
97+
} else if (key == "body") {
98+
body += val;
99+
} else if (key == "from") {
100+
// we accept only one "From" address
101+
set_from (Address (val));
102+
} else {
103+
body = ustring::compose ("Unknown header: %1: %2\n%3", key, val, body);
104+
}
105+
}
106+
}
107+
}
108+
109+
append_address (&cc, _cc);
110+
append_address (&bcc, _bcc);
111+
subject += _subject;
112+
body += _body;
113+
114+
47115
if (!_from.empty ()) {
116+
// we accept only one "From" address
48117
set_from (Address (_from));
49118
}
50119

120+
51121
/* reload message */
52122
prepare_message ();
53123
read_edited_message ();
@@ -1029,6 +1099,11 @@ namespace Astroid {
10291099
}
10301100
}
10311101

1102+
void EditMessage::append_address (ustring *s, ustring a) {
1103+
*s += (s->empty() ? a : "," + a);
1104+
}
1105+
1106+
10321107
/* }}} */
10331108

10341109
/* send message {{{ */

src/modes/edit_message.hh

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ namespace Astroid {
3131

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

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

170172
public:
171173
void grab_modal () override;

src/modes/thread_view/thread_view.cc

-4
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,6 @@ namespace Astroid {
196196
ustring scheme = Glib::uri_parse_scheme (uri);
197197

198198
if (scheme == "mailto") {
199-
200-
uri = uri.substr (scheme.length ()+1, uri.length () - scheme.length()-1);
201-
UstringUtils::trim(uri);
202-
203199
main_window->add_mode (new EditMessage (main_window, uri));
204200

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

0 commit comments

Comments
 (0)