Merge branch 'wip/40-backslash-in-folder-name' into 'master'
Fix mailbox names not being sent to the server quoted if needed See merge request GNOME/geary!24 Fixes #40
This commit is contained in:
commit
c9b25e25ec
16 changed files with 246 additions and 99 deletions
|
|
@ -282,7 +282,6 @@ src/engine/imap/message/imap-fetch-data-specifier.vala
|
|||
src/engine/imap/message/imap-flag.vala
|
||||
src/engine/imap/message/imap-flags.vala
|
||||
src/engine/imap/message/imap-internal-date.vala
|
||||
src/engine/imap/message/imap-mailbox-parameter.vala
|
||||
src/engine/imap/message/imap-mailbox-specifier.vala
|
||||
src/engine/imap/message/imap-message-data.vala
|
||||
src/engine/imap/message/imap-message-flag.vala
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class ConversationWebView : ClientWebView {
|
|||
// Key codes we don't forward on to the super class on key press
|
||||
// since we want to override them elsewhere, especially
|
||||
// ConversationListBox.
|
||||
private const int[] BLACKLISTED_KEY_CODES = {
|
||||
private const uint[] BLACKLISTED_KEY_CODES = {
|
||||
Gdk.Key.space,
|
||||
Gdk.Key.KP_Space,
|
||||
Gdk.Key.Up,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ public class Geary.Endpoint : BaseObject {
|
|||
public Flags flags { get; private set; }
|
||||
public uint timeout_sec { get; private set; }
|
||||
public TlsCertificateFlags tls_validation_flags { get; set; default = TlsCertificateFlags.VALIDATE_ALL; }
|
||||
public bool force_ssl3 { get; set; default = false; }
|
||||
|
||||
/**
|
||||
* The maximum number of commands that will be pipelined at once.
|
||||
|
|
@ -169,7 +168,6 @@ public class Geary.Endpoint : BaseObject {
|
|||
}
|
||||
|
||||
private void prepare_tls_cx(TlsClientConnection tls_cx, bool starttls) {
|
||||
tls_cx.use_ssl3 = force_ssl3;
|
||||
tls_cx.set_validation_flags(tls_validation_flags);
|
||||
|
||||
// Vala doesn't do delegates in a ternary operator very well
|
||||
|
|
@ -178,7 +176,7 @@ public class Geary.Endpoint : BaseObject {
|
|||
else
|
||||
tls_cx.accept_certificate.connect(on_accept_ssl_certificate);
|
||||
}
|
||||
|
||||
|
||||
private bool on_accept_starttls_certificate(TlsConnection cx, TlsCertificate cert, TlsCertificateFlags flags) {
|
||||
return report_tls_warnings(SecurityType.STARTTLS, cx, cert, flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,10 +125,15 @@ private class Geary.ImapEngine.RevokableMove : Revokable {
|
|||
);
|
||||
final_ops.add(op);
|
||||
set_invalid();
|
||||
|
||||
// Capture these for the closure below, since once it gets
|
||||
// invoked, this instance may no longer exist.
|
||||
GenericAccount account = this.account;
|
||||
Geary.Folder destination = this.destination;
|
||||
op.wait_for_ready_async.begin(null, (obj, res) => {
|
||||
try {
|
||||
op.wait_for_ready_async.end(res);
|
||||
this.account.update_folder(this.destination);
|
||||
account.update_folder(destination);
|
||||
} catch (Error err) {
|
||||
// Oh well
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@
|
|||
namespace Geary.Imap.DataFormat {
|
||||
|
||||
private const char[] ATOM_SPECIALS = {
|
||||
'(', ')', '{', ' ', '%', '*', '"'
|
||||
'(', ')', '{', ' ', // CTL chars are handled by is_special_char
|
||||
'%', '*', // list-wildcards
|
||||
'"', '\\', // quoted-specials
|
||||
']' // resp-specials
|
||||
};
|
||||
|
||||
private const char[] TAG_SPECIALS = {
|
||||
|
|
@ -21,12 +24,15 @@ public enum Quoting {
|
|||
}
|
||||
|
||||
private bool is_special_char(char ch, char[] ar, string? exceptions) {
|
||||
if (ch > 0x7F || ch.iscntrl())
|
||||
// Check for CTL chars
|
||||
if (ch <= 0x1F || ch >= 0x7F) {
|
||||
return true;
|
||||
|
||||
if (ch in ar)
|
||||
}
|
||||
|
||||
if (ch in ar) {
|
||||
return (exceptions != null) ? Ascii.index_of(exceptions, ch) < 0 : true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
/* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A {@link StringParameter} that holds a mailbox reference (can be wildcarded).
|
||||
*
|
||||
* Used to juggle between our internal UTF-8 representation of mailboxes and IMAP's
|
||||
* odd "modified UTF-7" representation. The value is stored in IMAP's encoded
|
||||
* format since that's how it comes across the wire.
|
||||
*/
|
||||
|
||||
public class Geary.Imap.MailboxParameter : StringParameter {
|
||||
public MailboxParameter(string mailbox) {
|
||||
base (utf8_to_imap_utf7(mailbox));
|
||||
}
|
||||
|
||||
public MailboxParameter.from_string_parameter(StringParameter string_parameter) {
|
||||
base (string_parameter.ascii);
|
||||
}
|
||||
|
||||
private static string utf8_to_imap_utf7(string utf8) {
|
||||
try {
|
||||
return Geary.ImapUtf7.utf8_to_imap_utf7(utf8);
|
||||
} catch (ConvertError e) {
|
||||
debug("Error encoding mailbox name '%s': %s", utf8, e.message);
|
||||
return utf8;
|
||||
}
|
||||
}
|
||||
|
||||
private static string imap_utf7_to_utf8(string imap_utf7) {
|
||||
try {
|
||||
return Geary.ImapUtf7.imap_utf7_to_utf8(imap_utf7);
|
||||
} catch (ConvertError e) {
|
||||
debug("Invalid mailbox name '%s': %s", imap_utf7, e.message);
|
||||
return imap_utf7;
|
||||
}
|
||||
}
|
||||
|
||||
public string decode() {
|
||||
return imap_utf7_to_utf8(ascii);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public override void serialize(Serializer ser, Tag tag) throws Error {
|
||||
serialize_string(ser);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public override string to_string() {
|
||||
return ascii;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,15 +48,38 @@ public class Geary.Imap.MailboxSpecifier : BaseObject, Gee.Hashable<MailboxSpeci
|
|||
* See [[http://tools.ietf.org/html/rfc3501#section-5.1]]
|
||||
*/
|
||||
public bool is_inbox { get; private set; }
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new specifier from a UTF-8 name.
|
||||
*/
|
||||
public MailboxSpecifier(string name) {
|
||||
init(name);
|
||||
}
|
||||
|
||||
public MailboxSpecifier.from_parameter(MailboxParameter param) {
|
||||
init(param.decode());
|
||||
|
||||
/**
|
||||
* Constructs a new specifier from a IMAP modified-UTF-7 string.
|
||||
*
|
||||
* If a modified-UTF-7 decoding error occurs, the parameter will
|
||||
* assumed to be UTF-8, repaired, and used instead.
|
||||
*/
|
||||
public MailboxSpecifier.from_parameter(StringParameter param) {
|
||||
string? name = null;
|
||||
try {
|
||||
name = Geary.ImapUtf7.imap_utf7_to_utf8(param.ascii);
|
||||
} catch (ConvertError err) {
|
||||
// Could no decode the name as IMAP modified UTF7, so per
|
||||
// https://imapwiki.org/ClientImplementation/MailboxList
|
||||
// assume UTF8 and repair to make sure it's valid at
|
||||
// least.
|
||||
debug(
|
||||
"Error decoding mailbox name, assuming UTF-8: %s", err.message
|
||||
);
|
||||
name = param.ascii.make_valid();
|
||||
}
|
||||
|
||||
init(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the {@link Geary.FolderPath} points to the IMAP Inbox.
|
||||
*/
|
||||
|
|
@ -187,11 +210,18 @@ public class Geary.Imap.MailboxSpecifier : BaseObject, Gee.Hashable<MailboxSpeci
|
|||
|
||||
return !String.is_empty(basename) ? basename : name;
|
||||
}
|
||||
|
||||
|
||||
public Parameter to_parameter() {
|
||||
return new MailboxParameter(name);
|
||||
string encoded= Geary.ImapUtf7.utf8_to_imap_utf7(this.name);
|
||||
Parameter? param = null;
|
||||
try {
|
||||
param = StringParameter.get_best_for(encoded);
|
||||
} catch (ImapError err) {
|
||||
param = new LiteralParameter(new Geary.Memory.StringBuffer(encoded));
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
|
||||
public uint hash() {
|
||||
return is_inbox ? Ascii.stri_hash(name) : Ascii.str_hash(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,19 +71,21 @@ public class Geary.Imap.MailboxInformation : BaseObject {
|
|||
// decode everything
|
||||
MailboxAttributes attributes = new MailboxAttributes(attrlist);
|
||||
StringParameter? delim = server_data.get_as_nullable_string(3);
|
||||
MailboxParameter mailbox = new MailboxParameter.from_string_parameter(
|
||||
server_data.get_as_string(4));
|
||||
|
||||
// Set \Inbox to standard path
|
||||
if (canonical_inbox && Geary.Imap.MailboxAttribute.SPECIAL_FOLDER_INBOX in attributes) {
|
||||
return new MailboxInformation(MailboxSpecifier.inbox,
|
||||
(delim != null) ? delim.nullable_ascii : null, attributes);
|
||||
} else {
|
||||
return new MailboxInformation(new MailboxSpecifier.from_parameter(mailbox),
|
||||
(delim != null) ? delim.nullable_ascii : null, attributes);
|
||||
}
|
||||
StringParameter mailbox = server_data.get_as_string(4);
|
||||
|
||||
// If special-use flag \Inbox is set just use the canonical
|
||||
// Inbox name, otherwise decode it
|
||||
MailboxSpecifier? specifier =
|
||||
(canonical_inbox &&
|
||||
Geary.Imap.MailboxAttribute.SPECIAL_FOLDER_INBOX in attributes)
|
||||
? MailboxSpecifier.inbox
|
||||
: new MailboxSpecifier.from_parameter(mailbox);
|
||||
|
||||
return new MailboxInformation(
|
||||
specifier, (delim != null) ? delim.nullable_ascii : null, attributes
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The {@link Geary.FolderPath} for the {@link mailbox}.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -74,10 +74,9 @@ public class Geary.Imap.StatusData : Object {
|
|||
throw new ImapError.PARSE_ERROR("Bad STATUS command name in response \"%s\"",
|
||||
server_data.to_string());
|
||||
}
|
||||
|
||||
MailboxParameter mailbox_param = new MailboxParameter.from_string_parameter(
|
||||
server_data.get_as_string(2));
|
||||
|
||||
|
||||
StringParameter mailbox_param = server_data.get_as_string(2);
|
||||
|
||||
int messages = UNSET;
|
||||
int recent = UNSET;
|
||||
UID? uid_next = null;
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@ geary_engine_vala_sources = files(
|
|||
'imap/message/imap-flags.vala',
|
||||
'imap/message/imap-internal-date.vala',
|
||||
'imap/message/imap-mailbox-specifier.vala',
|
||||
'imap/message/imap-mailbox-parameter.vala',
|
||||
'imap/message/imap-message-data.vala',
|
||||
'imap/message/imap-message-flag.vala',
|
||||
'imap/message/imap-message-flags.vala',
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ private int first_encode_index(string str) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public string utf8_to_imap_utf7(string str) throws ConvertError {
|
||||
public string utf8_to_imap_utf7(string str) {
|
||||
int p = first_encode_index(str);
|
||||
if (p < 0) {
|
||||
/* no characters that need to be encoded */
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ int sqlite3FtsUnicodeIsalnum(int c){
|
|||
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
|
||||
}else if( c<(1<<22) ){
|
||||
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
|
||||
int iRes;
|
||||
int iRes= 0;
|
||||
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
|
||||
int iLo = 0;
|
||||
while( iHi>=iLo ){
|
||||
|
|
|
|||
104
test/engine/imap/message/imap-data-format-test.vala
Normal file
104
test/engine/imap/message/imap-data-format-test.vala
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2018 Michael Gratton <mike@vee.net>
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
class Geary.Imap.DataFormatTest : TestCase {
|
||||
|
||||
|
||||
public DataFormatTest() {
|
||||
base("Geary.Imap.DataFormatTest");
|
||||
add_test("is_atom_special", is_atom_special);
|
||||
}
|
||||
|
||||
public void is_atom_special() throws Error {
|
||||
assert_false(
|
||||
DataFormat.is_atom_special('a') || DataFormat.is_atom_special('z'),
|
||||
"Lower case ASCII"
|
||||
);
|
||||
assert_false(
|
||||
DataFormat.is_atom_special('A') || DataFormat.is_atom_special('Z'),
|
||||
"Upper case ASCII"
|
||||
);
|
||||
assert_false(
|
||||
DataFormat.is_atom_special('0') || DataFormat.is_atom_special('9'),
|
||||
"ASCII numbers"
|
||||
);
|
||||
assert_false(
|
||||
DataFormat.is_atom_special('#') ||
|
||||
DataFormat.is_atom_special('.') ||
|
||||
DataFormat.is_atom_special('+') ||
|
||||
DataFormat.is_atom_special('/') ||
|
||||
DataFormat.is_atom_special('~') ||
|
||||
DataFormat.is_atom_special(':'),
|
||||
"Common mailbox ASCII symbols"
|
||||
);
|
||||
|
||||
// atom-specials
|
||||
assert_true(
|
||||
DataFormat.is_atom_special('('),
|
||||
"Atom-special: ("
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(')'),
|
||||
"Atom-special: )"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special('{'),
|
||||
"Atom-special: {"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(' '),
|
||||
"Atom-special: SP"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(0x00),
|
||||
"Atom-special: CTL (NUL)"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(0x1F),
|
||||
"Atom-special: CTL (US)"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(0x7F),
|
||||
"Atom-special: CTL (DEL)"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(0x80),
|
||||
"Atom-special: Non-ASCII (0x80)"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(0xFE),
|
||||
"Atom-special: Non-ASCII (0xFE)"
|
||||
);
|
||||
|
||||
// list-wildcards
|
||||
assert_true(
|
||||
DataFormat.is_atom_special('%'),
|
||||
"Atom-special: %"
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special('*'),
|
||||
"Atom-special: *"
|
||||
);
|
||||
|
||||
// quoted-specials
|
||||
assert_true(
|
||||
DataFormat.is_atom_special('\"'),
|
||||
"Atom-special: \""
|
||||
);
|
||||
assert_true(
|
||||
DataFormat.is_atom_special('\\'),
|
||||
"Atom-special: \\"
|
||||
);
|
||||
|
||||
// resp-specials
|
||||
assert_true(
|
||||
DataFormat.is_atom_special(']'),
|
||||
"Atom-special: ]"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
60
test/engine/imap/message/imap-mailbox-specifier-test.vala
Normal file
60
test/engine/imap/message/imap-mailbox-specifier-test.vala
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2018 Michael Gratton <mike@vee.net>
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
class Geary.Imap.MailboxSpecifierTest : TestCase {
|
||||
|
||||
|
||||
public MailboxSpecifierTest() {
|
||||
base("Geary.Imap.MailboxSpecifierTest");
|
||||
add_test("to_parameter", to_parameter);
|
||||
add_test("from_parameter", from_parameter);
|
||||
}
|
||||
|
||||
public void to_parameter() throws Error {
|
||||
assert_string(
|
||||
"test",
|
||||
new MailboxSpecifier("test").to_parameter().to_string()
|
||||
);
|
||||
assert_string(
|
||||
"foo/bar",
|
||||
new MailboxSpecifier("foo/bar").to_parameter().to_string()
|
||||
);
|
||||
|
||||
// The param won't be quoted or escaped since
|
||||
// QuotedStringParameter doesn't actually handle that, so just
|
||||
// check that it is correct type
|
||||
Parameter quoted = new MailboxSpecifier("""foo\bar""").to_parameter();
|
||||
assert_true(quoted is QuotedStringParameter, "Backslash was not quoted");
|
||||
|
||||
assert_string(
|
||||
"ol&AOk-",
|
||||
new MailboxSpecifier("olé").to_parameter().to_string()
|
||||
);
|
||||
}
|
||||
|
||||
public void from_parameter() throws Error {
|
||||
assert_string(
|
||||
"test",
|
||||
new MailboxSpecifier.from_parameter(
|
||||
new UnquotedStringParameter("test")).name
|
||||
);
|
||||
|
||||
// This won't be quoted or escaped since QuotedStringParameter
|
||||
// doesn't actually handle that.
|
||||
assert_string(
|
||||
"foo\\bar",
|
||||
new MailboxSpecifier.from_parameter(
|
||||
new QuotedStringParameter("""foo\bar""")).name
|
||||
);
|
||||
assert_string(
|
||||
"olé",
|
||||
new MailboxSpecifier.from_parameter(
|
||||
new UnquotedStringParameter("ol&AOk-")).name
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ geary_test_engine_sources = [
|
|||
'engine/db/db-database-test.vala',
|
||||
'engine/db/db-versioned-database-test.vala',
|
||||
'engine/imap/command/imap-create-command-test.vala',
|
||||
'engine/imap/message/imap-data-format-test.vala',
|
||||
'engine/imap/message/imap-mailbox-specifier-test.vala',
|
||||
'engine/imap/response/imap-namespace-response-test.vala',
|
||||
'engine/imap/transport/imap-deserializer-test.vala',
|
||||
'engine/imap-db/imap-db-attachment-test.vala',
|
||||
|
|
|
|||
|
|
@ -36,8 +36,11 @@ int main(string[] args) {
|
|||
engine.add_suite(new Geary.Db.DatabaseTest().get_suite());
|
||||
engine.add_suite(new Geary.Db.VersionedDatabaseTest().get_suite());
|
||||
engine.add_suite(new Geary.HTML.UtilTest().get_suite());
|
||||
engine.add_suite(new Geary.Imap.DeserializerTest().get_suite());
|
||||
// Other IMAP tests rely on DataFormat working, so test that first
|
||||
engine.add_suite(new Geary.Imap.DataFormatTest().get_suite());
|
||||
engine.add_suite(new Geary.Imap.CreateCommandTest().get_suite());
|
||||
engine.add_suite(new Geary.Imap.DeserializerTest().get_suite());
|
||||
engine.add_suite(new Geary.Imap.MailboxSpecifierTest().get_suite());
|
||||
engine.add_suite(new Geary.Imap.NamespaceResponseTest().get_suite());
|
||||
engine.add_suite(new Geary.ImapDB.AttachmentTest().get_suite());
|
||||
engine.add_suite(new Geary.ImapDB.AttachmentIoTest().get_suite());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue