From 27b39a55486dcf9c447f3b177c92bfb24f7a5c8b Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Sat, 25 Apr 2020 18:19:22 -0400 Subject: [PATCH 01/41] help-overlay: fix minor typo '/' is for finding in the current _conversation_ (singular). Match the text here with what we have for Ctrl-F. --- ui/gtk/help-overlay.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index d73f2c3a..49f4059a 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -329,7 +329,7 @@ True - Find in current conversations + Find in current conversation slash From ec649efcc90fc5becb9ebe04482daf44944a71cc Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Sat, 25 Apr 2020 18:57:20 -0400 Subject: [PATCH 02/41] help-overlay: move single-key shortcuts to a new section - Move single-key shortcuts to their own section - break the shortcuts list into two columns - mention that single-key shortcuts need to be enabled in preferences --- ui/gtk/help-overlay.ui | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index 49f4059a..854a36b2 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -251,11 +251,18 @@ + + + + + True + single-key + Single-key Shortcuts True Single-key shortcuts + context="shortcut window">Single-key conversation shortcuts (if enabled in Preferences) True @@ -298,6 +305,11 @@ E + + + + + True True From af44f4457cfeb85c183dd9f05e2de32e03cd25e4 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 28 Apr 2020 18:32:39 -0400 Subject: [PATCH 03/41] help-overlay: further single-key shortcut screen cleanups Add a bit more spacing below the header, and reduce the length of the header to fit better on smaller screens. --- ui/gtk/help-overlay.ui | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index 854a36b2..1f1925e4 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -257,12 +257,17 @@ True single-key - Single-key Shortcuts + Single-key Conversation Shortcuts True Single-key conversation shortcuts (if enabled in Preferences) + context="shortcut window">Single-key shortcuts (if enabled in Preferences) + + + True + + True @@ -310,6 +315,11 @@ True + + + True + + True From e2118daa9e4b10aac202c6b508e18e8e2683ea3f Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 1 May 2020 01:09:49 -0400 Subject: [PATCH 04/41] help-overlay: shorten single-key section name --- ui/gtk/help-overlay.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index 1f1925e4..7dfb5b85 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -257,7 +257,7 @@ True single-key - Single-key Conversation Shortcuts + Single-key Shortcuts True From d7e128ae72a122de2c518bc3ce5e57b2c97c12e5 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Thu, 21 Nov 2019 16:35:53 +1100 Subject: [PATCH 05/41] src/engine/rfc822/rfc822.vala: Fix indentation to match style --- src/engine/rfc822/rfc822.vala | 106 ++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/src/engine/rfc822/rfc822.vala b/src/engine/rfc822/rfc822.vala index cef728a2..3d800508 100644 --- a/src/engine/rfc822/rfc822.vala +++ b/src/engine/rfc822/rfc822.vala @@ -6,60 +6,66 @@ namespace Geary.RFC822 { -/** - * Common text formats supported by {@link Geary.RFC822}. - */ -public enum TextFormat { - PLAIN, - HTML -} - -/** - * Official IANA charset encoding name for the UTF-8 character set. - */ -public const string UTF8_CHARSET = "UTF-8"; - -private int init_count = 0; - -internal Regex? invalid_filename_character_re = null; - -public void init() { - if (init_count++ != 0) - return; - - GMime.init(); - GMime.ParserOptions.get_default().set_allow_addresses_without_domain(true); - - try { - invalid_filename_character_re = new Regex("[/\\0]"); - } catch (RegexError e) { - assert_not_reached(); + /** + * Common text formats supported by {@link Geary.RFC822}. + */ + public enum TextFormat { + PLAIN, + HTML } -} -public GMime.FormatOptions get_format_options() { - return GMime.FormatOptions.get_default().clone(); -} + /** + * Official IANA charset encoding name for the UTF-8 character set. + */ + public const string UTF8_CHARSET = "UTF-8"; -public GMime.ParserOptions get_parser_options() { - return GMime.ParserOptions.get_default().clone(); -} + /** + * Official IANA charset encoding name for the ASCII character set. + */ + public const string ASCII_CHARSET = "US-ASCII"; -public string? get_charset() { - return UTF8_CHARSET; -} + internal Regex? invalid_filename_character_re = null; -internal bool is_utf_8(string charset) { - string up = charset.up(); - return ( - // ASCII is a subset of UTF-8, so it's also valid - up == "ASCII" || - up == "US-ASCII" || - up == "US_ASCII" || - up == "UTF-8" || - up == "UTF8" || - up == "UTF_8" - ); -} + private int init_count = 0; + + + public void init() { + if (init_count++ != 0) + return; + + GMime.init(); + GMime.ParserOptions.get_default().set_allow_addresses_without_domain(true); + + try { + invalid_filename_character_re = new Regex("[/\\0]"); + } catch (RegexError e) { + assert_not_reached(); + } + } + + public GMime.FormatOptions get_format_options() { + return GMime.FormatOptions.get_default().clone(); + } + + public GMime.ParserOptions get_parser_options() { + return GMime.ParserOptions.get_default().clone(); + } + + public string? get_charset() { + return UTF8_CHARSET; + } + + internal bool is_utf_8(string charset) { + string up = charset.up(); + return ( + // ASCII is a subset of UTF-8, so it's also valid + up == "ASCII" || + up == "US-ASCII" || + up == "US_ASCII" || + up == "UTF-8" || + up == "UTF8" || + up == "UTF_8" + ); + } } From f77bb50b5c15a861715160d3de82901d2912960e Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 21:20:28 +1000 Subject: [PATCH 06/41] src/engine/rfc822/rfc822-utils.vala: Updated to better match code style --- src/engine/rfc822/rfc822-utils.vala | 533 ++++++++++++++-------------- 1 file changed, 271 insertions(+), 262 deletions(-) diff --git a/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala index f05c50a2..866e8098 100644 --- a/src/engine/rfc822/rfc822-utils.vala +++ b/src/engine/rfc822/rfc822-utils.vala @@ -1,179 +1,138 @@ -/* Copyright 2016 Software Freedom Conservancy Inc. +/* + * Copyright 2016 Software Freedom Conservancy Inc. * Portions copyright (C) 2000-2013 Jeffrey Stedfast * * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. + * (version 2.1 or later). See the COPYING file in this distribution. */ namespace Geary.RFC822.Utils { -// We use DEL to mark quote levels, since it's unlikely to be in email bodies, is a single byte -// in UTF-8, and is unmolested by GMime.FilterHTML. -public const char QUOTE_MARKER = '\x7f'; + // We use DEL to mark quote levels, since it's unlikely to be in + // email bodies, is a single byte in UTF-8, and is unmolested by + // GMime.FilterHTML. + public const char QUOTE_MARKER = '\x7f'; -/** - * Uses the best-possible transfer of bytes from the Memory.Buffer to the GMime.StreamMem object. - * The StreamMem object should be destroyed *before* the Memory.Buffer object, since this method - * will use unowned variants whenever possible. - */ -public GMime.StreamMem create_stream_mem(Memory.Buffer buffer) { - Memory.UnownedByteArrayBuffer? unowned_bytes_array_buffer = buffer as Memory.UnownedByteArrayBuffer; - if (unowned_bytes_array_buffer != null) { - // set_byte_array doesn't do any copying and doesn't take ownership -- perfect, this is - // the best of all possible worlds, assuming the Memory.Buffer is not destroyed first - GMime.StreamMem stream = new GMime.StreamMem(); - stream.set_byte_array(unowned_bytes_array_buffer.to_unowned_byte_array()); - - return stream; + public string create_subject_for_reply(Email email) { + return (email.subject ?? new Subject("")).create_reply().value; } - Memory.UnownedBytesBuffer? unowned_bytes_buffer = buffer as Memory.UnownedBytesBuffer; - if (unowned_bytes_buffer != null) { - // StreamMem.with_buffer does do a buffer copy (there's not set_buffer() call like - // set_byte_array() for some reason), but don't do a buffer copy when it comes out of the - // Memory.Buffer - return new GMime.StreamMem.with_buffer(unowned_bytes_buffer.to_unowned_uint8_array()); + public string create_subject_for_forward(Email email) { + return (email.subject ?? new Subject("")).create_forward().value; } - // do plain-old buffer copy - return new GMime.StreamMem.with_buffer(buffer.get_uint8_array()); -} + public MailboxAddresses create_to_addresses_for_reply(Email email, + Gee.List? sender_addresses = null) { + var new_to = new Gee.ArrayList(); -public string create_subject_for_reply(Geary.Email email) { - return (email.subject ?? new Geary.RFC822.Subject("")).create_reply().value; -} + // If we're replying to something we sent, send it to the same people we originally did. + // Otherwise, we'll send to the reply-to address or the from address. + if (email.to != null && email_is_from_sender(email, sender_addresses)) + new_to.add_all(email.to.get_all()); + else if (email.reply_to != null) + new_to.add_all(email.reply_to.get_all()); + else if (email.from != null) + new_to.add_all(email.from.get_all()); -public string create_subject_for_forward(Geary.Email email) { - return (email.subject ?? new Geary.RFC822.Subject("")).create_forward().value; -} - -// Removes address from the list of addresses. If the list contains only the given address, the -// behavior depends on empty_ok: if true the list will be emptied, otherwise it will leave the -// address in the list once. Used to remove the sender's address from a list of addresses being -// created for the "reply to" recipients. -private void remove_address(Gee.List addresses, - RFC822.MailboxAddress address, bool empty_ok = false) { - for (int i = 0; i < addresses.size; ++i) { - if (addresses[i].equal_to(address) && (empty_ok || addresses.size > 1)) - addresses.remove_at(i--); - } -} - -private bool email_is_from_sender(Geary.Email email, Gee.List? sender_addresses) { - if (sender_addresses == null || email.from == null) - return false; - - return Geary.traverse(sender_addresses) - .any(a => email.from.get_all().contains(a)); -} - -public Geary.RFC822.MailboxAddresses create_to_addresses_for_reply(Geary.Email email, - Gee.List< Geary.RFC822.MailboxAddress>? sender_addresses = null) { - Gee.List new_to = - new Gee.ArrayList(); - - // If we're replying to something we sent, send it to the same people we originally did. - // Otherwise, we'll send to the reply-to address or the from address. - if (email.to != null && email_is_from_sender(email, sender_addresses)) - new_to.add_all(email.to.get_all()); - else if (email.reply_to != null) - new_to.add_all(email.reply_to.get_all()); - else if (email.from != null) - new_to.add_all(email.from.get_all()); - - // Exclude the current sender. No need to receive the mail they're sending. - if (sender_addresses != null) { - foreach (RFC822.MailboxAddress address in sender_addresses) - remove_address(new_to, address); - } - - return new Geary.RFC822.MailboxAddresses(new_to); -} - -public Geary.RFC822.MailboxAddresses create_cc_addresses_for_reply_all(Geary.Email email, - Gee.List? sender_addresses = null) { - Gee.List new_cc = new Gee.ArrayList(); - - // If we're replying to something we received, also add other recipients. Don't do this for - // emails we sent, since everyone we sent it to is already covered in - // create_to_addresses_for_reply(). - if (email.to != null && !email_is_from_sender(email, sender_addresses)) - new_cc.add_all(email.to.get_all()); - - if (email.cc != null) - new_cc.add_all(email.cc.get_all()); - - // Again, exclude the current sender. - if (sender_addresses != null) { - foreach (RFC822.MailboxAddress address in sender_addresses) - remove_address(new_cc, address, true); - } - - return new Geary.RFC822.MailboxAddresses(new_cc); -} - -public Geary.RFC822.MailboxAddresses merge_addresses(Geary.RFC822.MailboxAddresses? first, - Geary.RFC822.MailboxAddresses? second) { - Gee.List result = new Gee.ArrayList(); - if (first != null) { - result.add_all(first.get_all()); - // Add addresses from second that aren't in first. - if (second != null) - foreach (Geary.RFC822.MailboxAddress address in second) - if (!first.contains_normalized(address.address)) - result.add(address); - } else if (second != null) { - result.add_all(second.get_all()); - } - - return new Geary.RFC822.MailboxAddresses(result); -} - -public Geary.RFC822.MailboxAddresses remove_addresses(Geary.RFC822.MailboxAddresses? from_addresses, - Geary.RFC822.MailboxAddresses? remove_addresses) { - Gee.List result = new Gee.ArrayList(); - if (from_addresses != null) { - result.add_all(from_addresses.get_all()); - if (remove_addresses != null) - foreach (Geary.RFC822.MailboxAddress address in remove_addresses) - remove_address(result, address, true); - } - return new Geary.RFC822.MailboxAddresses(result); -} - -public string reply_references(Geary.Email source) { - // generate list for References - Gee.ArrayList list = new Gee.ArrayList(); - - // 1. Start with the source's References list - if (source.references != null && source.references.list.size > 0) - list.add_all(source.references.list); - - // 2. If there are In-Reply-To Message-IDs and they're not in the References list, append them - if (source.in_reply_to != null) { - foreach (RFC822.MessageID reply_id in source.in_reply_to.list) { - if (!list.contains(reply_id)) - list.add(reply_id); + // Exclude the current sender. No need to receive the mail they're sending. + if (sender_addresses != null) { + foreach (var address in sender_addresses) { + remove_address(new_to, address); + } } + + return new MailboxAddresses(new_to); } - // 3. Append the source's Message-ID, if available. - if (source.message_id != null) - list.add(source.message_id); + public MailboxAddresses create_cc_addresses_for_reply_all(Email email, + Gee.List? sender_addresses = null) { + var new_cc = new Gee.ArrayList(); - string[] strings = new string[list.size]; - for(int i = 0; i < list.size; ++i) - strings[i] = list[i].value; + // If we're replying to something we received, also add other recipients. Don't do this for + // emails we sent, since everyone we sent it to is already covered in + // create_to_addresses_for_reply(). + if (email.to != null && !email_is_from_sender(email, sender_addresses)) + new_cc.add_all(email.to.get_all()); - return (list.size > 0) ? string.joinv(" ", strings) : ""; -} + if (email.cc != null) + new_cc.add_all(email.cc.get_all()); -public string email_addresses_for_reply(Geary.RFC822.MailboxAddresses? addresses, TextFormat format) { - if (addresses == null) - return ""; + // Again, exclude the current sender. + if (sender_addresses != null) { + foreach (var address in sender_addresses) { + remove_address(new_cc, address, true); + } + } - switch (format) { + return new MailboxAddresses(new_cc); + } + + public MailboxAddresses merge_addresses(MailboxAddresses? first, + MailboxAddresses? second) { + var result = new Gee.ArrayList(); + if (first != null) { + result.add_all(first.get_all()); + // Add addresses from second that aren't in first. + if (second != null) + foreach (MailboxAddress address in second) + if (!first.contains_normalized(address.address)) + result.add(address); + } else if (second != null) { + result.add_all(second.get_all()); + } + return new MailboxAddresses(result); + } + + public MailboxAddresses remove_addresses(MailboxAddresses? from_addresses, + MailboxAddresses? remove_addresses) { + Gee.List result = new Gee.ArrayList(); + if (from_addresses != null) { + result.add_all(from_addresses.get_all()); + if (remove_addresses != null) + foreach (MailboxAddress address in remove_addresses) + remove_address(result, address, true); + } + return new MailboxAddresses(result); + } + + public string reply_references(Email source) { + // generate list for References + var list = new Gee.ArrayList(); + + // 1. Start with the source's References list + if (source.references != null && source.references.list.size > 0) { + list.add_all(source.references.list); + } + + // 2. If there are In-Reply-To Message-IDs and they're not in the References list, append them + if (source.in_reply_to != null) { + foreach (var reply_id in source.in_reply_to.list) { + if (!list.contains(reply_id)) { + list.add(reply_id); + } + } + } + + // 3. Append the source's Message-ID, if available. + if (source.message_id != null) { + list.add(source.message_id); + } + + string[] strings = new string[list.size]; + for(int i = 0; i < list.size; ++i) { + strings[i] = list[i].value; + } + + return (list.size > 0) ? string.joinv(" ", strings) : ""; + } + + public string email_addresses_for_reply(MailboxAddresses? addresses, + TextFormat format) { + if (addresses == null) + return ""; + + switch (format) { case TextFormat.HTML: return HTML.escape_markup(addresses.to_full_display()); @@ -182,127 +141,177 @@ public string email_addresses_for_reply(Geary.RFC822.MailboxAddresses? addresses default: assert_not_reached(); - } -} - - -public bool comp_char_arr_slice(uint8[] array, uint start, string comp) { - for (int i = 0; i < comp.length; i++) { - if (array[start + i] != comp[i]) - return false; + } } - return true; -} + /** + * Obtains the best preview text from a plain or HTML string. + * + * The given string `text` should have UNIX encoded line endings (LF), + * rather than RFC822 (CRLF). The string returned will will have had + * its whitespace squashed. + */ + public string to_preview_text(string? text, TextFormat format) { + string preview = ""; -/** - * Obtains the best preview text from a plain or HTML string. - * - * The given string `text` should have UNIX encoded line endings (LF), - * rather than RFC822 (CRLF). The string returned will will have had - * its whitespace squashed. - */ -public string to_preview_text(string? text, TextFormat format) { - string preview = ""; - - if (format == TextFormat.PLAIN) { - StringBuilder buf = new StringBuilder(); - string[] all_lines = text.split("\n"); - bool in_inline_pgp_header = false; - foreach (string line in all_lines) { - if (in_inline_pgp_header) { - if (Geary.String.is_empty(line)) { - in_inline_pgp_header = false; + if (format == TextFormat.PLAIN) { + StringBuilder buf = new StringBuilder(); + string[] all_lines = text.split("\n"); + bool in_inline_pgp_header = false; + foreach (string line in all_lines) { + if (in_inline_pgp_header) { + if (Geary.String.is_empty(line)) { + in_inline_pgp_header = false; + } + continue; } - continue; + + if (line.has_prefix("-----BEGIN PGP SIGNED MESSAGE-----")) { + in_inline_pgp_header = true; + continue; + } + + if (line.has_prefix(">")) + continue; + + if (line.has_prefix("--")) + continue; + + if (line.has_prefix("====")) + continue; + + if (line.has_prefix("~~~~")) + continue; + + if (Geary.String.is_empty_or_whitespace(line)) { + buf.append("\n"); + continue; + } + + buf.append(" "); + buf.append(line); } - if (line.has_prefix("-----BEGIN PGP SIGNED MESSAGE-----")) { - in_inline_pgp_header = true; - continue; - } - - if (line.has_prefix(">")) - continue; - - if (line.has_prefix("--")) - continue; - - if (line.has_prefix("====")) - continue; - - if (line.has_prefix("~~~~")) - continue; - - if (Geary.String.is_empty_or_whitespace(line)) { - buf.append("\n"); - continue; - } - - buf.append(" "); - buf.append(line); + preview = buf.str; + } else if (format == TextFormat.HTML) { + preview = Geary.HTML.html_to_text(text, false); } - preview = buf.str; - } else if (format == TextFormat.HTML) { - preview = Geary.HTML.html_to_text(text, false); + // XXX really shouldn't have to call make_valid here but do so to + // avoid segfaults in the regex engine on invalid char data. See + // issue #186 for the proper fix. + return Geary.String.reduce_whitespace(preview.make_valid()); } - // XXX really shouldn't have to call make_valid here but do so to - // avoid segfaults in the regex engine on invalid char data. See - // issue #186 for the proper fix. - return Geary.String.reduce_whitespace(preview.make_valid()); -} + /** + * Uses a GMime.FilterBest to determine the best charset. + * + * This may require processing the entire stream, so occurs in a + * background thread. + */ + internal async string get_best_charset(GMime.Stream in_stream, + GLib.Cancellable? cancellable) + throws GLib.Error { + GMime.FilterBest filter = new GMime.FilterBest(CHARSET); + GMime.StreamFilter out_stream = new GMime.StreamFilter( + new GMime.StreamNull() + ); + out_stream.add(filter); -/** - * Uses a GMime.FilterBest to determine the best charset. - * - * This may require processing the entire stream, so occurs in a - * background thread. - */ -public async string get_best_charset(GMime.Stream in_stream, - GLib.Cancellable? cancellable) - throws GLib.Error { - GMime.FilterBest filter = new GMime.FilterBest(CHARSET); - GMime.StreamFilter out_stream = new GMime.StreamFilter( - new GMime.StreamNull() - ); - out_stream.add(filter); + yield Nonblocking.Concurrent.global.schedule_async(() => { + in_stream.write_to_stream(out_stream); + in_stream.reset(); + out_stream.close(); + }, + cancellable + ); + return filter.get_charset(); + } - yield Nonblocking.Concurrent.global.schedule_async(() => { - in_stream.write_to_stream(out_stream); - in_stream.reset(); - out_stream.close(); - }, - cancellable - ); - return filter.get_charset(); -} + /** + * Uses a GMime.FilterBest to determine the best encoding. + * + * This may require processing the entire stream, so occurs in a + * background thread. + */ + internal async GMime.ContentEncoding get_best_encoding(GMime.Stream in_stream, + GMime.EncodingConstraint constraint, + GLib.Cancellable? cancellable) + throws GLib.Error { + GMime.FilterBest filter = new GMime.FilterBest(ENCODING); + GMime.StreamFilter out_stream = new GMime.StreamFilter( + new GMime.StreamNull() + ); + out_stream.add(filter); -/** - * Uses a GMime.FilterBest to determine the best encoding. - * - * This may require processing the entire stream, so occurs in a - * background thread. - */ -public async GMime.ContentEncoding get_best_encoding(GMime.Stream in_stream, - GMime.EncodingConstraint constraint, - GLib.Cancellable? cancellable) - throws GLib.Error { - GMime.FilterBest filter = new GMime.FilterBest(ENCODING); - GMime.StreamFilter out_stream = new GMime.StreamFilter( - new GMime.StreamNull() - ); - out_stream.add(filter); + yield Nonblocking.Concurrent.global.schedule_async(() => { + in_stream.write_to_stream(out_stream); + in_stream.reset(); + out_stream.close(); + }, + cancellable + ); + return filter.encoding(constraint); + } - yield Nonblocking.Concurrent.global.schedule_async(() => { - in_stream.write_to_stream(out_stream); - in_stream.reset(); - out_stream.close(); - }, - cancellable - ); - return filter.encoding(constraint); -} + /** + * Uses the best-possible transfer of bytes from the Memory.Buffer to the GMime.StreamMem object. + * The StreamMem object should be destroyed *before* the Memory.Buffer object, since this method + * will use unowned variants whenever possible. + */ + internal GMime.StreamMem create_stream_mem(Memory.Buffer buffer) { + Memory.UnownedByteArrayBuffer? unowned_bytes_array_buffer = buffer as Memory.UnownedByteArrayBuffer; + if (unowned_bytes_array_buffer != null) { + // set_byte_array doesn't do any copying and doesn't take ownership -- perfect, this is + // the best of all possible worlds, assuming the Memory.Buffer is not destroyed first + GMime.StreamMem stream = new GMime.StreamMem(); + stream.set_byte_array(unowned_bytes_array_buffer.to_unowned_byte_array()); + return stream; + } + + Memory.UnownedBytesBuffer? unowned_bytes_buffer = buffer as Memory.UnownedBytesBuffer; + if (unowned_bytes_buffer != null) { + // StreamMem.with_buffer does do a buffer copy (there's not set_buffer() call like + // set_byte_array() for some reason), but don't do a buffer copy when it comes out of the + // Memory.Buffer + return new GMime.StreamMem.with_buffer(unowned_bytes_buffer.to_unowned_uint8_array()); + } + + // do plain-old buffer copy + return new GMime.StreamMem.with_buffer(buffer.get_uint8_array()); + } + + internal bool comp_char_arr_slice(uint8[] array, uint start, string comp) { + for (int i = 0; i < comp.length; i++) { + if (array[start + i] != comp[i]) + return false; + } + + return true; + } + + // Removes address from the list of addresses. If the list contains only the given address, the + // behavior depends on empty_ok: if true the list will be emptied, otherwise it will leave the + // address in the list once. Used to remove the sender's address from a list of addresses being + // created for the "reply to" recipients. + private void remove_address(Gee.List addresses, + MailboxAddress address, + bool empty_ok = false) { + for (int i = 0; i < addresses.size; ++i) { + if (addresses[i].equal_to(address) && + (empty_ok || addresses.size > 1)) { + addresses.remove_at(i--); + } + } + } + + private bool email_is_from_sender(Email email, Gee.List? sender_addresses) { + var ret = false; + if (sender_addresses != null && email.from != null) { + ret = traverse(sender_addresses) + .any(a => email.from.get_all().contains(a)); + } + return ret; + } } From 6d5f63692b0192b595d7c0068bda331c65fb786b Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Sat, 23 Nov 2019 10:38:40 +1100 Subject: [PATCH 07/41] Geary.Mime.ContentType: Rename ::deserialise to ::parse Add unit tests. --- src/engine/imap-db/imap-db-attachment.vala | 2 +- src/engine/mime/mime-content-type.vala | 12 +++++++---- test/engine/api/geary-attachment-test.vala | 2 +- .../{ => mime}/mime-content-type-test.vala | 21 +++++++++++++++++++ test/meson.build | 2 +- 5 files changed, 32 insertions(+), 7 deletions(-) rename test/engine/{ => mime}/mime-content-type-test.vala (78%) diff --git a/src/engine/imap-db/imap-db-attachment.vala b/src/engine/imap-db/imap-db-attachment.vala index 4db81717..d8e8f9db 100644 --- a/src/engine/imap-db/imap-db-attachment.vala +++ b/src/engine/imap-db/imap-db-attachment.vala @@ -71,7 +71,7 @@ private class Geary.ImapDB.Attachment : Geary.Attachment { this( result.rowid_for("message_id"), - Mime.ContentType.deserialize(result.nonnull_string_for("mime_type")), + Mime.ContentType.parse(result.nonnull_string_for("mime_type")), result.string_for("content_id"), result.string_for("description"), disposition, diff --git a/src/engine/mime/mime-content-type.vala b/src/engine/mime/mime-content-type.vala index 9fe333d8..41bd4b2b 100644 --- a/src/engine/mime/mime-content-type.vala +++ b/src/engine/mime/mime-content-type.vala @@ -65,9 +65,9 @@ public class Geary.Mime.ContentType : Geary.BaseObject { TYPES_TO_EXTENSIONS["image/x-bmp"] = ".bmp"; } - public static ContentType deserialize(string str) throws MimeError { - // perform a little sanity checking here, as it doesn't appear the GMime constructor has - // any error-reporting at all + public static ContentType parse(string str) throws MimeError { + // perform a little sanity checking here, as it doesn't appear + // the GMime constructor has any error-reporting at all if (String.is_empty(str)) throw new MimeError.PARSE("Empty MIME Content-Type"); @@ -113,7 +113,11 @@ public class Geary.Mime.ContentType : Geary.BaseObject { mime_type = GLib.ContentType.get_mime_type(glib_type); } - return !Geary.String.is_empty(mime_type) ? deserialize(mime_type) : null; + return ( + !Geary.String.is_empty_or_whitespace(mime_type) + ? ContentType.parse(mime_type) + : null + ); } diff --git a/test/engine/api/geary-attachment-test.vala b/test/engine/api/geary-attachment-test.vala index 6db441cf..f101c683 100644 --- a/test/engine/api/geary-attachment-test.vala +++ b/test/engine/api/geary-attachment-test.vala @@ -61,7 +61,7 @@ class Geary.AttachmentTest : TestCase { public override void set_up() { try { - this.content_type = Mime.ContentType.deserialize(CONTENT_TYPE); + this.content_type = Mime.ContentType.parse(CONTENT_TYPE); this.default_type = Mime.ContentType.ATTACHMENT_DEFAULT; this.content_disposition = new Mime.ContentDisposition("attachment", null); diff --git a/test/engine/mime-content-type-test.vala b/test/engine/mime/mime-content-type-test.vala similarity index 78% rename from test/engine/mime-content-type-test.vala rename to test/engine/mime/mime-content-type-test.vala index 4b766000..5fc1160e 100644 --- a/test/engine/mime-content-type-test.vala +++ b/test/engine/mime/mime-content-type-test.vala @@ -10,6 +10,7 @@ class Geary.Mime.ContentTypeTest : TestCase { public ContentTypeTest() { base("Geary.Mime.ContentTypeTest"); add_test("static_defaults", static_defaults); + add_test("parse", parse); add_test("get_file_name_extension", get_file_name_extension); add_test("guess_type_from_name", guess_type_from_name); add_test("guess_type_from_buf", guess_type_from_buf); @@ -26,6 +27,26 @@ class Geary.Mime.ContentTypeTest : TestCase { ); } + public void parse() throws GLib.Error { + var test_article = ContentType.parse("text/plain"); + assert_string("text", test_article.media_type); + assert_string("plain", test_article.media_subtype); + + try { + ContentType.parse(""); + assert_not_reached(); + } catch (MimeError.PARSE error) { + // All good + } + + try { + ContentType.parse("textplain"); + assert_not_reached(); + } catch (MimeError.PARSE error) { + // All good + } + } + public void get_file_name_extension() throws Error { assert(new ContentType("image", "jpeg", null).get_file_name_extension() == ".jpeg"); assert(new ContentType("test", "unknown", null).get_file_name_extension() == null); diff --git a/test/meson.build b/test/meson.build index 9cd4717f..7de5e857 100644 --- a/test/meson.build +++ b/test/meson.build @@ -52,7 +52,7 @@ geary_test_engine_sources = [ 'engine/imap-db/imap-db-folder-test.vala', 'engine/imap-engine/account-processor-test.vala', 'engine/imap-engine/imap-engine-generic-account-test.vala', - 'engine/mime-content-type-test.vala', + 'engine/mime/mime-content-type-test.vala', 'engine/outbox/outbox-email-identifier-test.vala', 'engine/rfc822-mailbox-address-test.vala', 'engine/rfc822-mailbox-addresses-test.vala', From 97e0093e29f07cd2eb0ef928c1e62e95a739afa8 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 21:24:06 +1000 Subject: [PATCH 08/41] Geary.ComposedEmail: Remove to_rfc822_message, it's redundant Callers can just call the same thing that method does instead. --- src/client/composer/composer-widget.vala | 4 +++- src/engine/api/geary-composed-email.vala | 7 ------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index a2186d7c..3e95f150 100644 --- a/src/client/composer/composer-widget.vala +++ b/src/client/composer/composer-widget.vala @@ -1771,7 +1771,9 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { if (this.draft_manager != null) { Geary.ComposedEmail draft = yield get_composed_email(null, true); yield this.draft_manager.update( - yield draft.to_rfc822_message(null, null), + yield new Geary.RFC822.Message.from_composed_email( + draft, null, null + ), null, null ); diff --git a/src/engine/api/geary-composed-email.vala b/src/engine/api/geary-composed-email.vala index 72f30ba8..5c3e27d8 100644 --- a/src/engine/api/geary-composed-email.vala +++ b/src/engine/api/geary-composed-email.vala @@ -123,13 +123,6 @@ public class Geary.ComposedEmail : EmailHeaderSet, BaseObject { return this; } - public async Geary.RFC822.Message to_rfc822_message(string? message_id, - GLib.Cancellable? cancellable) { - return yield new RFC822.Message.from_composed_email( - this, message_id, cancellable - ); - } - /** * Determines if an IMG SRC value is present in the HTML part. * From c6a09c6326d21bfa48d365d6969f64d7a92061d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emin=20Tufan=20=C3=87etin?= Date: Tue, 5 May 2020 13:55:49 +0000 Subject: [PATCH 09/41] Update Turkish translation --- po/tr.po | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/po/tr.po b/po/tr.po index d5b32eac..7c6d95dd 100644 --- a/po/tr.po +++ b/po/tr.po @@ -16,8 +16,8 @@ msgid "" msgstr "" "Project-Id-Version: geary.mainline\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-04-23 04:13+0000\n" -"PO-Revision-Date: 2020-04-25 15:34+0300\n" +"POT-Creation-Date: 2020-05-04 09:30+0000\n" +"PO-Revision-Date: 2020-05-05 16:49+0300\n" "Last-Translator: Emin Tufan Çetin \n" "Language-Team: Turkish \n" "Language: tr\n" @@ -1218,7 +1218,11 @@ msgstr "Bağlantı güvenlik ayrıntılarını gözden geçirin" msgid "%s — %s" msgstr "%s — %s" +#. Translators: The name of the folder group containing +#. folders created by people (as opposed to special-use +#. folders) #: src/client/application/application-main-window.vala:972 +#: src/client/folder-list/folder-list-account-branch.vala:43 msgid "Labels" msgstr "Etiketler" @@ -1367,7 +1371,7 @@ msgid "Preferences" msgstr "Tercihler" #. / Translators: Preferences page title -#: src/client/components/components-preferences-window.vala:179 +#: src/client/components/components-preferences-window.vala:180 msgid "Plugins" msgstr "Eklentiler" @@ -2679,14 +2683,14 @@ msgid "Add an account" msgstr "Hesap ekle" #: ui/accounts_editor_add_pane.ui:53 -msgid "Create" -msgstr "Oluştur" +msgid "_Create" +msgstr "_Oluştur" -#: ui/accounts_editor_add_pane.ui:130 ui/accounts_editor_servers_pane.ui:125 +#: ui/accounts_editor_add_pane.ui:131 ui/accounts_editor_servers_pane.ui:125 msgid "Receiving" msgstr "Alım" -#: ui/accounts_editor_add_pane.ui:178 ui/accounts_editor_servers_pane.ui:165 +#: ui/accounts_editor_add_pane.ui:179 ui/accounts_editor_servers_pane.ui:165 msgid "Sending" msgstr "Gönderiliyor" From fbb41f7e86df347469e850518119160f442b263c Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Wed, 6 May 2020 02:29:15 +0200 Subject: [PATCH 10/41] Plugins: Add libgeary-client to rpath Since we moved libgeary-client to a subdirectory, running ldd over the plug-ins shows they cannot find the library. They will still likely work in Geary, inheriting the library but we should still fix it in order not to trip up packagers' linters. --- src/client/plugin/desktop-notifications/meson.build | 3 ++- src/client/plugin/email-templates/meson.build | 3 ++- src/client/plugin/folder-highlight/meson.build | 3 ++- src/client/plugin/messaging-menu/meson.build | 3 ++- src/client/plugin/notification-badge/meson.build | 3 ++- src/client/plugin/sent-sound/meson.build | 3 ++- src/client/plugin/special-folders/meson.build | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/client/plugin/desktop-notifications/meson.build b/src/client/plugin/desktop-notifications/meson.build index 501d3042..d09e723b 100644 --- a/src/client/plugin/desktop-notifications/meson.build +++ b/src/client/plugin/desktop-notifications/meson.build @@ -13,7 +13,8 @@ shared_module( vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( diff --git a/src/client/plugin/email-templates/meson.build b/src/client/plugin/email-templates/meson.build index 56ef251f..835eb72c 100644 --- a/src/client/plugin/email-templates/meson.build +++ b/src/client/plugin/email-templates/meson.build @@ -13,7 +13,8 @@ shared_module( vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( diff --git a/src/client/plugin/folder-highlight/meson.build b/src/client/plugin/folder-highlight/meson.build index 0a5fdeb1..2abd611d 100644 --- a/src/client/plugin/folder-highlight/meson.build +++ b/src/client/plugin/folder-highlight/meson.build @@ -13,7 +13,8 @@ shared_module( vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( diff --git a/src/client/plugin/messaging-menu/meson.build b/src/client/plugin/messaging-menu/meson.build index 8a14b7c6..7b3bb0ab 100644 --- a/src/client/plugin/messaging-menu/meson.build +++ b/src/client/plugin/messaging-menu/meson.build @@ -32,7 +32,8 @@ if libmessagingmenu_dep.found() vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( diff --git a/src/client/plugin/notification-badge/meson.build b/src/client/plugin/notification-badge/meson.build index 98dca2e8..008c4a85 100644 --- a/src/client/plugin/notification-badge/meson.build +++ b/src/client/plugin/notification-badge/meson.build @@ -16,7 +16,8 @@ shared_module( vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( diff --git a/src/client/plugin/sent-sound/meson.build b/src/client/plugin/sent-sound/meson.build index ba627228..7228ecc2 100644 --- a/src/client/plugin/sent-sound/meson.build +++ b/src/client/plugin/sent-sound/meson.build @@ -16,7 +16,8 @@ shared_module( vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( diff --git a/src/client/plugin/special-folders/meson.build b/src/client/plugin/special-folders/meson.build index f6d1d522..347d40ea 100644 --- a/src/client/plugin/special-folders/meson.build +++ b/src/client/plugin/special-folders/meson.build @@ -13,7 +13,8 @@ shared_module( vala_args: geary_vala_args, c_args: plugin_c_args, install: true, - install_dir: plugin_dest + install_dir: plugin_dest, + install_rpath: client_lib_dir, ) i18n.merge_file( From e0c1fb8a8042156bfb81cc9e97a7cd39c09f53ea Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 21:48:11 +1000 Subject: [PATCH 11/41] Geary.RFC822: Ensure various data constructors throw errors Rather than just silently ignoring error conditions, throw RFC822 errors instead. --- src/client/accounts/accounts-manager.vala | 13 +- src/client/composer/composer-email-entry.vala | 11 +- src/engine/imap-db/imap-db-message-row.vala | 28 ++-- .../imap/message/imap-message-data.vala | 10 +- src/engine/rfc822/rfc822-mailbox-address.vala | 34 +++-- .../rfc822/rfc822-mailbox-addresses.vala | 13 +- src/engine/rfc822/rfc822-message-data.vala | 60 ++++---- src/engine/rfc822/rfc822-message.vala | 129 +++++++++--------- test/engine/rfc822-message-test.vala | 3 +- test/integration/smtp/client-session.vala | 3 +- 10 files changed, 160 insertions(+), 144 deletions(-) diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala index f6d5749f..7b7c101c 100644 --- a/src/client/accounts/accounts-manager.vala +++ b/src/client/accounts/accounts-manager.vala @@ -1274,10 +1274,15 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object { ALTERNATE_EMAILS_KEY ); foreach (string alt_email in alt_email_list) { - Geary.RFC822.MailboxAddresses mailboxes = - new Geary.RFC822.MailboxAddresses.from_rfc822_string(alt_email); - foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all()) { - info.append_sender(mailbox); + try { + var mailboxes = new Geary.RFC822.MailboxAddresses.from_rfc822_string(alt_email); + foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all()) { + info.append_sender(mailbox); + } + } catch (Geary.RFC822Error error) { + throw new ConfigError.SYNTAX( + "Invalid alternate email: %s", error.message + ); } } diff --git a/src/client/composer/composer-email-entry.vala b/src/client/composer/composer-email-entry.vala index b5e87314..cd4202b0 100644 --- a/src/client/composer/composer-email-entry.vala +++ b/src/client/composer/composer-email-entry.vala @@ -81,9 +81,14 @@ public class Composer.EmailEntry : Gtk.Entry { this._addresses = new Geary.RFC822.MailboxAddresses(); this.is_valid = false; } else { - this._addresses = - new Geary.RFC822.MailboxAddresses.from_rfc822_string(text); - this.is_valid = true; + try { + this._addresses = + new Geary.RFC822.MailboxAddresses.from_rfc822_string(text); + this.is_valid = true; + } catch (Geary.RFC822Error err) { + this._addresses = new Geary.RFC822.MailboxAddresses(); + this.is_valid = false; + } } } diff --git a/src/engine/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala index 36a4699b..4744a957 100644 --- a/src/engine/imap-db/imap-db-message-row.vala +++ b/src/engine/imap-db/imap-db-message-row.vala @@ -272,20 +272,22 @@ private class Geary.ImapDB.MessageRow { return (addrs == null || addrs.size == 0) ? null : addrs.to_rfc822_string(); } - private RFC822.MailboxAddress? unflatten_address(string? str) { - RFC822.MailboxAddress? addr = null; - if (str != null) { - try { - addr = new RFC822.MailboxAddress.from_rfc822_string(str); - } catch (RFC822Error e) { - // oh well - } - } - return addr; + private RFC822.MailboxAddress? unflatten_address(string? str) + throws RFC822Error { + return ( + String.is_empty_or_whitespace(str) + ? null + : new RFC822.MailboxAddress.from_rfc822_string(str) + ); } - private RFC822.MailboxAddresses? unflatten_addresses(string? str) { - return String.is_empty(str) ? null : new RFC822.MailboxAddresses.from_rfc822_string(str); + private RFC822.MailboxAddresses? unflatten_addresses(string? str) + throws RFC822Error { + return ( + String.is_empty_or_whitespace(str) + ? null + : new RFC822.MailboxAddresses.from_rfc822_string(str) + ); } + } - diff --git a/src/engine/imap/message/imap-message-data.vala b/src/engine/imap/message/imap-message-data.vala index e4d423ff..07c10f3c 100644 --- a/src/engine/imap/message/imap-message-data.vala +++ b/src/engine/imap/message/imap-message-data.vala @@ -26,8 +26,13 @@ public class Geary.Imap.RFC822Size : Geary.RFC822.Size, Geary.Imap.MessageData { } public class Geary.Imap.RFC822Header : Geary.RFC822.Header, Geary.Imap.MessageData { - public RFC822Header(Memory.Buffer buffer) { - base (buffer); + public RFC822Header(Memory.Buffer buffer) + throws ImapError { + try { + base(buffer); + } catch (RFC822Error error) { + throw new ImapError.INVALID(error.message); + } } } @@ -42,4 +47,3 @@ public class Geary.Imap.RFC822Full : Geary.RFC822.Full, Geary.Imap.MessageData { base (buffer); } } - diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala index 6d994136..5f5ad87e 100644 --- a/src/engine/rfc822/rfc822-mailbox-address.vala +++ b/src/engine/rfc822/rfc822-mailbox-address.vala @@ -233,21 +233,27 @@ public class Geary.RFC822.MailboxAddress : Geary.RFC822.get_parser_options(), rfc822 ); - if (addrlist == null) - return; - - int length = addrlist.length(); - for (int ctr = 0; ctr < length; ctr++) { - GMime.InternetAddress? addr = addrlist.get_address(ctr); - - // TODO: Handle group lists - GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox; - if (mbox_addr != null) { - this.gmime(mbox_addr); - return; - } + if (addrlist == null) { + throw new RFC822Error.INVALID( + "Not a RFC822 mailbox address: %s", rfc822 + ); } - throw new RFC822Error.INVALID("Could not parse RFC822 address: %s", rfc822); + if (addrlist.length() != 1) { + throw new RFC822Error.INVALID( + "Not a single RFC822 mailbox address: %s", rfc822 + ); + } + + GMime.InternetAddress? addr = addrlist.get_address(0); + // TODO: Handle group lists + var mbox_addr = addr as GMime.InternetAddressMailbox; + if (mbox_addr == null) { + throw new RFC822Error.INVALID( + "Group lists not currently supported: %s", rfc822 + ); + } + + this.gmime(mbox_addr); } public MailboxAddress.gmime(GMime.InternetAddressMailbox mailbox) { diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala index 4afd096d..41886acb 100644 --- a/src/engine/rfc822/rfc822-mailbox-addresses.vala +++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala @@ -78,13 +78,12 @@ public class Geary.RFC822.MailboxAddresses : this.addrs.add(addr); } - public MailboxAddresses.from_rfc822_string(string rfc822) { - GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse( - Geary.RFC822.get_parser_options(), - rfc822 - ); - if (addrlist == null) - return; + public MailboxAddresses.from_rfc822_string(string rfc822) + throws RFC822Error { + var addrlist = GMime.InternetAddressList.parse(null, rfc822); + if (addrlist == null) { + throw new RFC822Error.INVALID("Not a RFC822 mailbox address list"); + } int length = addrlist.length(); for (int ctr = 0; ctr < length; ctr++) { diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala index d4a3aa0a..ba1a9708 100644 --- a/src/engine/rfc822/rfc822-message-data.vala +++ b/src/engine/rfc822/rfc822-message-data.vala @@ -169,17 +169,15 @@ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.AbstractMessageData, Gee.Hashable { - public string? original { get; private set; } + public string original { get; private set; } public DateTime value { get; private set; } - public Date(string rfc822) throws ImapError { - DateTime? value = GMime.utils_header_decode_date(rfc822); - if (value == null) { - throw new ImapError.PARSE_ERROR( - "Unable to parse \"%s\": Outside supported range", rfc822 - ); + public Date(string rfc822) throws RFC822Error { + var date = GMime.utils_header_decode_date(rfc822); + if (date == null) { + throw new RFC822Error.INVALID("Not ISO-8601 date: %s", rfc822); } - this.value = value; + this.value = date; this.original = rfc822; } @@ -302,42 +300,38 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC private GMime.Message? message = null; private string[]? names = null; - public Header(Memory.Buffer buffer) { + public Header(Memory.Buffer buffer) throws RFC822Error { base("RFC822.Header", buffer); - } - private unowned GMime.HeaderList get_headers() throws RFC822Error { - if (message != null) - return message.get_header_list(); - - GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(buffer)); + var parser = new GMime.Parser.with_stream( + Utils.create_stream_mem(buffer) + ); parser.set_respect_content_length(false); + parser.set_format(MESSAGE); - message = parser.construct_message(Geary.RFC822.get_parser_options()); - if (message == null) + this.message = parser.construct_message(null); + if (this.message == null) { throw new RFC822Error.INVALID("Unable to parse RFC 822 headers"); - - return message.get_header_list(); + } } - public string? get_header(string name) throws RFC822Error { - GMime.Header header = get_headers().get_header(name); - if (header != null) - // We should not parse the raw-value here, but use GMime's parsing - // functionality instead. - // See: https://gitlab.gnome.org/GNOME/geary/merge_requests/382#note_669699 - return GMime.utils_header_unfold(header.get_raw_value()); - else - return null; + public string? get_header(string name) { + string? value = null; + var header = this.message.get_header_list().get_header(name); + if (header != null) { + value = header.get_value(); + } + return value; } - public string[] get_header_names() throws RFC822Error { + public string[] get_header_names() { if (this.names == null) { - this.names = new string[0]; - GMime.HeaderList headers = get_headers(); - for (int i = 0; i < headers.get_count(); i++) { - names += headers.get_header_at(i).get_name(); + GMime.HeaderList headers = this.message.get_header_list(); + var names = new string[headers.get_count()]; + for (int i = 0; i < names.length; i++) { + names[i] = headers.get_header_at(i).get_name(); } + this.names = names; } return this.names; } diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index 4ef341c8..ff63f58e 100644 --- a/src/engine/rfc822/rfc822-message.vala +++ b/src/engine/rfc822/rfc822-message.vala @@ -6,6 +6,7 @@ * (version 2.1 or later). See the COPYING file in this distribution. */ + /** * An RFC-822 style email message. * @@ -99,16 +100,19 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { stock_from_gmime(); } - public Message.from_gmime_message(GMime.Message message) { + public Message.from_gmime_message(GMime.Message message) + throws RFC822Error { this.message = message; stock_from_gmime(); } - public Message.from_buffer(Memory.Buffer full_email) throws RFC822Error { + public Message.from_buffer(Memory.Buffer full_email) + throws RFC822Error { this(new Geary.RFC822.Full(full_email)); } - public Message.from_parts(Header header, Text body) throws RFC822Error { + public Message.from_parts(Header header, Text body) + throws RFC822Error { GMime.StreamCat stream_cat = new GMime.StreamCat(); stream_cat.add_source(new GMime.StreamMem.with_buffer(header.buffer.get_bytes().get_data())); stream_cat.add_source(new GMime.StreamMem.with_buffer(body.buffer.get_bytes().get_data())); @@ -126,9 +130,11 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { public async Message.from_composed_email(Geary.ComposedEmail email, string? message_id, - GLib.Cancellable? cancellable) { + GLib.Cancellable? cancellable) + throws RFC822Error { this.message = new GMime.Message(true); + // // Required headers this.from = email.from; @@ -802,7 +808,8 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * disabled by passing false in include_sub_messages). Note that values * that come out of this function are persisted. */ - public string? get_searchable_body(bool include_sub_messages = true) { + public string? get_searchable_body(bool include_sub_messages = true) + throws RFC822Error { string? body = null; bool html = false; try { @@ -880,81 +887,70 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { return attachments; } - private void stock_from_gmime() { - GMime.HeaderList headers = this.message.get_header_list(); + private void stock_from_gmime() throws RFC822Error { + GMime.HeaderList headers = this.message.headers; for (int i = 0; i < headers.get_count(); i++) { GMime.Header header = headers.get_header_at(i); - string name = header.get_name(); - // We should not parse the raw-value here, but use GMime's parsing - // functionality instead. - // See: https://gitlab.gnome.org/GNOME/geary/merge_requests/382#note_669699 - string value = GMime.utils_header_unfold(header.get_raw_value()); - switch (name.down()) { - case "from": - this.from = append_address(this.from, value); - break; + string value = header.get_value(); + switch (header.get_name().down()) { + case "from": + this.from = append_address(this.from, value); + break; - case "sender": - try { - this.sender = new RFC822.MailboxAddress.from_rfc822_string(value); - } catch (Error err) { - debug("Could parse subject: %s", err.message); - } - break; + case "sender": + this.sender = new MailboxAddress.from_rfc822_string(value); + break; - case "reply-to": - this.reply_to = append_address(this.reply_to, value); - break; + case "reply-to": + this.reply_to = append_address(this.reply_to, value); + break; - case "to": - this.to = append_address(this.to, value); - break; + case "to": + this.to = append_address(this.to, value); + break; - case "cc": - this.cc = append_address(this.cc, value); - break; + case "cc": + this.cc = append_address(this.cc, value); + break; - case "bcc": - this.bcc = append_address(this.bcc, value); - break; + case "bcc": + this.bcc = append_address(this.bcc, value); + break; - case "subject": - this.subject = new RFC822.Subject.decode(value); - break; + case "subject": + this.subject = new Subject.decode(value); + break; - case "date": - try { - this.date = new Geary.RFC822.Date(value); - } catch (Error err) { - debug("Could not parse date: %s", err.message); - } - break; + case "date": + this.date = new Date(value); + break; - case "message-id": - this.message_id = new MessageID(value); - break; + case "message-id": + this.message_id = new MessageID(value); + break; - case "in-reply-to": - this.in_reply_to = append_message_id(this.in_reply_to, value); - break; + case "in-reply-to": + this.in_reply_to = append_message_id(this.in_reply_to, value); + break; - case "references": - this.references = append_message_id(this.references, value); - break; + case "references": + this.references = append_message_id(this.references, value); + break; - case "x-mailer": - this.mailer = GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value); - break; + case "x-mailer": + this.mailer = GMime.utils_header_decode_text(null, value); + break; - default: - // do nothing - break; + default: + // Ignore anything else not + break; } - }; + } } private MailboxAddresses append_address(MailboxAddresses? existing, - string header_value) { + string header_value) + throws RFC822Error { MailboxAddresses addresses = new MailboxAddresses.from_rfc822_string(header_value); if (existing != null) { addresses = existing.append(addresses); @@ -1063,13 +1059,16 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } #endif - public Gee.List get_sub_messages() { + public Gee.List get_sub_messages() + throws RFC822Error { Gee.List messages = new Gee.ArrayList(); find_sub_messages(messages, message.get_mime_part()); return messages; } - private void find_sub_messages(Gee.List messages, GMime.Object root) { + private void find_sub_messages(Gee.List messages, + GMime.Object root) + throws RFC822Error { // If this is a multipart container, check each of its children. GMime.Multipart? multipart = root as GMime.Multipart; if (multipart != null) { @@ -1084,7 +1083,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { if (messagepart != null) { GMime.Message sub_message = messagepart.get_message(); if (sub_message != null) { - messages.add(new Geary.RFC822.Message.from_gmime_message(sub_message)); + messages.add(new Message.from_gmime_message(sub_message)); } else { warning("Corrupt message, possibly bug 769697"); } diff --git a/test/engine/rfc822-message-test.vala b/test/engine/rfc822-message-test.vala index cc3f0a40..979fcccb 100644 --- a/test/engine/rfc822-message-test.vala +++ b/test/engine/rfc822-message-test.vala @@ -371,7 +371,8 @@ This is the second line. assert_true(out_buffer.size > (buffer.size+buffer2.size), "Expected sizeable message"); } - private async Geary.RFC822.Message message_from_composed_email(Geary.ComposedEmail composed) { + private async Message message_from_composed_email(ComposedEmail composed) + throws RFC822Error { return yield new Geary.RFC822.Message.from_composed_email( composed, GMime.utils_generate_message_id(composed.from.get(0).domain), diff --git a/test/integration/smtp/client-session.vala b/test/integration/smtp/client-session.vala index b6c0c801..33ee89d0 100644 --- a/test/integration/smtp/client-session.vala +++ b/test/integration/smtp/client-session.vala @@ -118,7 +118,8 @@ class Integration.Smtp.ClientSession : TestCase { } private async Geary.RFC822.Message new_message(Geary.RFC822.MailboxAddress from, - Geary.RFC822.MailboxAddress to) { + Geary.RFC822.MailboxAddress to) + throws Geary.RFC822Error { Geary.ComposedEmail composed = new Geary.ComposedEmail( new GLib.DateTime.now_local(), new Geary.RFC822.MailboxAddresses.single(from) From 6e50c2a4c07dc1a9da63382b8e5c6c6dccd457e8 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 21:49:16 +1000 Subject: [PATCH 12/41] Geary.Mime.ContentParameters: Minor ctor API update --- src/engine/mime/mime-content-parameters.vala | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/engine/mime/mime-content-parameters.vala b/src/engine/mime/mime-content-parameters.vala index 6d2f5ef4..eae21955 100644 --- a/src/engine/mime/mime-content-parameters.vala +++ b/src/engine/mime/mime-content-parameters.vala @@ -51,15 +51,13 @@ public class Geary.Mime.ContentParameters : BaseObject { } } - internal ContentParameters.from_gmime(GMime.ParamList? gmime_params) { - Gee.Map params = new Gee.HashMap(); - if (gmime_params != null) { - for (int i = 0; i < gmime_params.length(); i++) { - GMime.Param gmime_param = gmime_params.get_parameter_at(i); - params.set(gmime_param.get_name(), gmime_param.get_value()); - } + internal ContentParameters.from_gmime(GMime.ParamList gmime) { + var parameters = new Gee.HashMap(); + for (int i = 0; i < gmime.length(); i++) { + var param = gmime.get_parameter_at(i); + parameters.set(param.name, param.value); } - this(params); + this(parameters); } /** From 0bbf0bfd32809f169ff8ed36b42bed201aa085a9 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 21:49:47 +1000 Subject: [PATCH 13/41] Geary.RFC822.Message: Rename message_to_memory_buffer args for clarity --- src/engine/rfc822/rfc822-message.vala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index ff63f58e..08f08f1d 100644 --- a/src/engine/rfc822/rfc822-message.vala +++ b/src/engine/rfc822/rfc822-message.vala @@ -1090,18 +1090,20 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } } - private Memory.Buffer message_to_memory_buffer(bool encoded, bool dotstuffed) throws RFC822Error { + private Memory.Buffer message_to_memory_buffer(bool encode_lf, + bool stuff_smtp) + throws RFC822Error { ByteArray byte_array = new ByteArray(); GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array); stream.set_owner(false); GMime.StreamFilter stream_filter = new GMime.StreamFilter(stream); - if (encoded) { + if (encode_lf) { stream_filter.add(new GMime.FilterUnix2Dos(false)); } else { stream_filter.add(new GMime.FilterDos2Unix(false)); } - if (dotstuffed) { + if (stuff_smtp) { stream_filter.add(new GMime.FilterSmtpData()); } From 27e1b5433f8f421d0d82fba859c926a8e7df5d38 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 21:52:59 +1000 Subject: [PATCH 14/41] Geary.RFC822.MailboxAddress: Fix sense of 8-bit workaround check --- src/engine/rfc822/rfc822-mailbox-address.vala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala index 5f5ad87e..ced627a7 100644 --- a/src/engine/rfc822/rfc822-mailbox-address.vala +++ b/src/engine/rfc822/rfc822-mailbox-address.vala @@ -124,9 +124,11 @@ public class Geary.RFC822.MailboxAddress : // _internet_address_decode_name() function. // see if a broken mailer has sent raw 8-bit information - string text = GMime.utils_text_is_8bit(part.data) - ? part : GMime.utils_decode_8bit(Geary.RFC822.get_parser_options(), - part.data); + string text = ( + !GMime.utils_text_is_8bit(part.data) + ? part + : GMime.utils_decode_8bit(get_parser_options(), part.data) + ); // unquote the string then decode the text GMime.utils_unquote_string(text); From 940781a37964e6259f663a9b59a152bdb897bf39 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 22:03:04 +1000 Subject: [PATCH 15/41] test/engine: Make RFC822 tests use their own subdirectory Ensures they match the same source layout as in the engine. --- .../{ => rfc822}/rfc822-mailbox-address-test.vala | 0 .../{ => rfc822}/rfc822-mailbox-addresses-test.vala | 0 .../{ => rfc822}/rfc822-message-data-test.vala | 0 test/engine/{ => rfc822}/rfc822-message-test.vala | 0 test/engine/{ => rfc822}/rfc822-part-test.vala | 0 test/engine/{ => rfc822}/rfc822-utils-test.vala | 0 test/meson.build | 12 ++++++------ 7 files changed, 6 insertions(+), 6 deletions(-) rename test/engine/{ => rfc822}/rfc822-mailbox-address-test.vala (100%) rename test/engine/{ => rfc822}/rfc822-mailbox-addresses-test.vala (100%) rename test/engine/{ => rfc822}/rfc822-message-data-test.vala (100%) rename test/engine/{ => rfc822}/rfc822-message-test.vala (100%) rename test/engine/{ => rfc822}/rfc822-part-test.vala (100%) rename test/engine/{ => rfc822}/rfc822-utils-test.vala (100%) diff --git a/test/engine/rfc822-mailbox-address-test.vala b/test/engine/rfc822/rfc822-mailbox-address-test.vala similarity index 100% rename from test/engine/rfc822-mailbox-address-test.vala rename to test/engine/rfc822/rfc822-mailbox-address-test.vala diff --git a/test/engine/rfc822-mailbox-addresses-test.vala b/test/engine/rfc822/rfc822-mailbox-addresses-test.vala similarity index 100% rename from test/engine/rfc822-mailbox-addresses-test.vala rename to test/engine/rfc822/rfc822-mailbox-addresses-test.vala diff --git a/test/engine/rfc822-message-data-test.vala b/test/engine/rfc822/rfc822-message-data-test.vala similarity index 100% rename from test/engine/rfc822-message-data-test.vala rename to test/engine/rfc822/rfc822-message-data-test.vala diff --git a/test/engine/rfc822-message-test.vala b/test/engine/rfc822/rfc822-message-test.vala similarity index 100% rename from test/engine/rfc822-message-test.vala rename to test/engine/rfc822/rfc822-message-test.vala diff --git a/test/engine/rfc822-part-test.vala b/test/engine/rfc822/rfc822-part-test.vala similarity index 100% rename from test/engine/rfc822-part-test.vala rename to test/engine/rfc822/rfc822-part-test.vala diff --git a/test/engine/rfc822-utils-test.vala b/test/engine/rfc822/rfc822-utils-test.vala similarity index 100% rename from test/engine/rfc822-utils-test.vala rename to test/engine/rfc822/rfc822-utils-test.vala diff --git a/test/meson.build b/test/meson.build index 7de5e857..57f33a86 100644 --- a/test/meson.build +++ b/test/meson.build @@ -54,12 +54,12 @@ geary_test_engine_sources = [ 'engine/imap-engine/imap-engine-generic-account-test.vala', 'engine/mime/mime-content-type-test.vala', 'engine/outbox/outbox-email-identifier-test.vala', - 'engine/rfc822-mailbox-address-test.vala', - 'engine/rfc822-mailbox-addresses-test.vala', - 'engine/rfc822-message-test.vala', - 'engine/rfc822-message-data-test.vala', - 'engine/rfc822-part-test.vala', - 'engine/rfc822-utils-test.vala', + 'engine/rfc822/rfc822-mailbox-address-test.vala', + 'engine/rfc822/rfc822-mailbox-addresses-test.vala', + 'engine/rfc822/rfc822-message-test.vala', + 'engine/rfc822/rfc822-message-data-test.vala', + 'engine/rfc822/rfc822-part-test.vala', + 'engine/rfc822/rfc822-utils-test.vala', 'engine/util-ascii-test.vala', 'engine/util-config-file-test.vala', 'engine/util-html-test.vala', From 2b5e084b61f7fef3d12e5ccaac43116d249c7010 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Tue, 5 May 2020 22:12:08 +1000 Subject: [PATCH 16/41] Geary.Engine.MailboxAddress: Don't force ISO-8859-1 encoding --- src/engine/rfc822/rfc822-mailbox-address.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala index ced627a7..7b9ea3f6 100644 --- a/src/engine/rfc822/rfc822-mailbox-address.vala +++ b/src/engine/rfc822/rfc822-mailbox-address.vala @@ -477,7 +477,7 @@ public class Geary.RFC822.MailboxAddress : GMime.utils_header_encode_phrase( Geary.RFC822.get_format_options(), this.name, - "iso-8859-1" + null ), to_rfc822_address() ) From f25892d8799afaa480904e2b763b4380c65c81d8 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 09:37:57 +1000 Subject: [PATCH 17/41] Geary.RFC822.MailboxAddresses: Update API and valadocs Add some doc comments, fix some methods to ensure the class is actually immutable, remove some unused methods, add ctor from the GMime equivalent object. --- .../rfc822/rfc822-mailbox-addresses.vala | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala index 41886acb..1e2bdc7c 100644 --- a/src/engine/rfc822/rfc822-mailbox-addresses.vala +++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala @@ -1,8 +1,9 @@ /* - * Copyright 2016 Software Freedom Conservancy Inc. + * Copyright © 2016 Software Freedom Conservancy Inc. + * Copyright © 2020 Michael Gratton * * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. + * (version 2.1 or later). See the COPYING file in this distribution. */ /** @@ -52,6 +53,7 @@ public class Geary.RFC822.MailboxAddresses : /** Signature for "to_string" implementation for {@link list_to_string}. */ private delegate string ListToStringDelegate(MailboxAddress address); + /** Returns the number of addresses in this list. */ public int size { get { return this.addrs.size; } @@ -80,28 +82,34 @@ public class Geary.RFC822.MailboxAddresses : public MailboxAddresses.from_rfc822_string(string rfc822) throws RFC822Error { - var addrlist = GMime.InternetAddressList.parse(null, rfc822); - if (addrlist == null) { + var list = GMime.InternetAddressList.parse(null, rfc822); + if (list == null) { throw new RFC822Error.INVALID("Not a RFC822 mailbox address list"); } + this.from_gmime(list); + } - int length = addrlist.length(); - for (int ctr = 0; ctr < length; ctr++) { - GMime.InternetAddress? addr = addrlist.get_address(ctr); - - GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox; + public MailboxAddresses.from_gmime(GMime.InternetAddressList list) + throws RFC822Error { + int length = list.length(); + if (length == 0) { + throw new RFC822Error.INVALID("No addresses in list"); + } + for (int i = 0; i < length; i++) { + var addr = list.get_address(i); + var mbox_addr = addr as GMime.InternetAddressMailbox; if (mbox_addr != null) { this.addrs.add(new MailboxAddress.gmime(mbox_addr)); } else { // XXX this is pretty bad - we just flatten the // group's addresses into this list, merging lists and // losing the group names. - GMime.InternetAddressGroup? mbox_group = addr as GMime.InternetAddressGroup; + var mbox_group = addr as GMime.InternetAddressGroup; if (mbox_group != null) { - GMime.InternetAddressList group_list = mbox_group.get_members(); - for (int i = 0; i < group_list.length(); i++) { - GMime.InternetAddressMailbox? group_addr = - addrlist.get_address(i) as GMime.InternetAddressMailbox; + var group_list = mbox_group.get_members(); + for (int j = 0; j < group_list.length(); j++) { + var group_addr = + group_list.get_address(j) as GMime.InternetAddressMailbox; if (group_addr != null) { this.addrs.add(new MailboxAddress.gmime(group_addr)); } @@ -111,16 +119,19 @@ public class Geary.RFC822.MailboxAddresses : } } + /** Returns the address at the given index, if it exists. */ public new MailboxAddress? get(int index) { - return addrs.get(index); + return this.addrs.get(index); } + /** Returns a read-only iterator of the addresses in this list. */ public Gee.Iterator iterator() { - return addrs.iterator(); + return this.addrs.read_only_view.iterator(); } + /** Returns a read-only collection of the addresses in this list. */ public Gee.List get_all() { - return addrs.read_only_view; + return this.addrs.read_only_view; } public bool contains_normalized(string address) { From 6aa5c2bfbdbff6ca22aed9afad64238476653f00 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 11:20:57 +1000 Subject: [PATCH 18/41] Geary.Imap.RFC822Size: Decouple from RFC822.Size Derive directly from Int64MessageData instead and remove RFC822.Size since the latter is not actually used or specified in RFC 822 and its obsoletors. --- src/engine/imap-db/imap-db-message-row.vala | 4 +++- src/engine/imap/api/imap-email-properties.vala | 8 +++++--- src/engine/imap/api/imap-folder-session.vala | 4 ++-- src/engine/imap/message/imap-message-data.vala | 2 +- src/engine/rfc822/rfc822-message-data.vala | 5 ----- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/engine/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala index 4744a957..f7b065dc 100644 --- a/src/engine/imap-db/imap-db-message-row.vala +++ b/src/engine/imap-db/imap-db-message-row.vala @@ -171,7 +171,9 @@ private class Geary.ImapDB.MessageRow { return null; } - return new Geary.Imap.EmailProperties(constructed, new RFC822.Size(rfc822_size)); + return new Imap.EmailProperties( + constructed, new Imap.RFC822Size(this.rfc822_size) + ); } public Geary.EmailFlags? get_generic_email_flags() { diff --git a/src/engine/imap/api/imap-email-properties.vala b/src/engine/imap/api/imap-email-properties.vala index 6ef84852..88fb95f5 100644 --- a/src/engine/imap/api/imap-email-properties.vala +++ b/src/engine/imap/api/imap-email-properties.vala @@ -5,12 +5,14 @@ */ public class Geary.Imap.EmailProperties : Geary.EmailProperties, Gee.Hashable { + + public InternalDate? internaldate { get; private set; } - public RFC822.Size? rfc822_size { get; private set; } + public RFC822Size? rfc822_size { get; private set; } - public EmailProperties(InternalDate? internaldate, RFC822.Size? rfc822_size) { + public EmailProperties(InternalDate internaldate, + RFC822Size rfc822_size) { base (internaldate.value, rfc822_size.value); - this.internaldate = internaldate; this.rfc822_size = rfc822_size; } diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala index c94da4bc..a934fecc 100644 --- a/src/engine/imap/api/imap-folder-session.vala +++ b/src/engine/imap/api/imap-folder-session.vala @@ -808,7 +808,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject { // accumulate these to submit Imap.EmailProperties all at once InternalDate? internaldate = null; - RFC822.Size? rfc822_size = null; + RFC822Size? rfc822_size = null; // accumulate these to submit References all at once RFC822.MessageID? message_id = null; @@ -848,7 +848,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject { break; case FetchDataSpecifier.RFC822_SIZE: - rfc822_size = (RFC822.Size) data; + rfc822_size = (RFC822Size) data; break; case FetchDataSpecifier.FLAGS: diff --git a/src/engine/imap/message/imap-message-data.vala b/src/engine/imap/message/imap-message-data.vala index 07c10f3c..b61a8944 100644 --- a/src/engine/imap/message/imap-message-data.vala +++ b/src/engine/imap/message/imap-message-data.vala @@ -19,7 +19,7 @@ public interface Geary.Imap.MessageData : Geary.MessageData.AbstractMessageData { } -public class Geary.Imap.RFC822Size : Geary.RFC822.Size, Geary.Imap.MessageData { +public class Geary.Imap.RFC822Size : Geary.MessageData.Int64MessageData, Geary.Imap.MessageData { public RFC822Size(int64 value) { base (value); } diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala index ba1a9708..93176875 100644 --- a/src/engine/rfc822/rfc822-message-data.vala +++ b/src/engine/rfc822/rfc822-message-data.vala @@ -213,12 +213,7 @@ public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.Abs public override string to_string() { return original ?? value.to_string(); } -} -public class Geary.RFC822.Size : Geary.MessageData.Int64MessageData, Geary.RFC822.MessageData { - public Size(int64 value) { - base (value); - } } public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData, From 5b253cbee66c76a817b708d5e8bf66563667491e Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 11:25:15 +1000 Subject: [PATCH 19/41] Geary.RFC822.MessageIdList: Update API to match MailboxAddresses Make immutable, provide similar properties and accessors as MailboxAddresses. --- src/client/composer/composer-widget.vala | 4 +- src/engine/api/geary-composed-email.vala | 4 +- src/engine/api/geary-email.vala | 4 +- src/engine/rfc822/rfc822-message-data.vala | 53 +++++++++++++++------ src/engine/rfc822/rfc822-utils.vala | 6 +-- test/engine/rfc822/rfc822-message-test.vala | 2 +- 6 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index 3e95f150..5e46c22a 100644 --- a/src/client/composer/composer-widget.vala +++ b/src/client/composer/composer-widget.vala @@ -1131,7 +1131,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { this.reply_to_entry.addresses = referred.reply_to; } if (referred.in_reply_to != null) - this.in_reply_to.add_all(referred.in_reply_to.list); + this.in_reply_to.add_all(referred.in_reply_to.get_all()); if (referred.references != null) this.references = referred.references.to_rfc822_string(); if (referred.subject != null) @@ -1360,7 +1360,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { this.context_type == REPLY_ALL) && !this.in_reply_to.is_empty) email.set_in_reply_to( - new Geary.RFC822.MessageIDList.from_collection(this.in_reply_to) + new Geary.RFC822.MessageIDList(this.in_reply_to) ); if (!Geary.String.is_empty(this.references)) { diff --git a/src/engine/api/geary-composed-email.vala b/src/engine/api/geary-composed-email.vala index 5c3e27d8..a1409cba 100644 --- a/src/engine/api/geary-composed-email.vala +++ b/src/engine/api/geary-composed-email.vala @@ -70,7 +70,7 @@ public class Geary.ComposedEmail : EmailHeaderSet, BaseObject { public string img_src_prefix { get; set; default = ""; } public ComposedEmail(DateTime date, RFC822.MailboxAddresses from) { - this.date = new RFC822.Date.from_date_time(date); + this.date = new RFC822.Date(date); this.from = from; } @@ -165,7 +165,7 @@ public class Geary.ComposedEmail : EmailHeaderSet, BaseObject { ret = null; } else { RFC822.MessageIDList? ids = list as RFC822.MessageIDList; - if (ids != null && ids.list.size == 0) { + if (ids != null && ids.size == 0) { ret = null; } } diff --git a/src/engine/api/geary-email.vala b/src/engine/api/geary-email.vala index 04a2cdb4..b2b77c86 100644 --- a/src/engine/api/geary-email.vala +++ b/src/engine/api/geary-email.vala @@ -523,12 +523,12 @@ public class Geary.Email : BaseObject, EmailHeaderSet { // References list the email trail back to its source if (references != null) - ancestors.add_all(references.list); + ancestors.add_all(references.get_all()); // RFC822 requires the In-Reply-To Message-ID be prepended to the References list, but // this ensures that's the case if (in_reply_to != null) - ancestors.add_all(in_reply_to.list); + ancestors.add_all(in_reply_to.get_all()); return (ancestors.size > 0) ? ancestors : null; } diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala index 93176875..fdd75ccd 100644 --- a/src/engine/rfc822/rfc822-message-data.vala +++ b/src/engine/rfc822/rfc822-message-data.vala @@ -37,30 +37,38 @@ public class Geary.RFC822.MessageID : Geary.MessageData.StringMessageData, Geary } /** - * A Message-ID list stores its IDs from earliest to latest. + * A immutable list of RFC822 Message-ID values. */ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, Geary.RFC822.MessageData { public Gee.List list { get; private set; } - public MessageIDList() { - list = new Gee.ArrayList(); + + /** Returns the number of ids in this list. */ + public int size { + get { return this.list.size; } } - public MessageIDList.from_collection(Gee.Collection collection) { - this (); + /** Determines if there are no ids in the list. */ + public bool is_empty { + get { return this.list.is_empty; } + } - foreach(MessageID msg_id in collection) - this.list.add(msg_id); + private Gee.List list = new Gee.ArrayList(); + + + public MessageIDList(Gee.Collection? collection = null) { + if (collection != null) { + this.list.add_all(collection); + } } public MessageIDList.single(MessageID msg_id) { - this (); - + this(); list.add(msg_id); } public MessageIDList.from_rfc822_string(string value) { - this (); + this(); // Have seen some mailers use commas between Message-IDs and whitespace inside Message-IDs, // meaning that the standard whitespace tokenizer is not sufficient. The only guarantee @@ -143,12 +151,26 @@ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, // from any non-empty string, an empty Message-ID (i.e. "<>") won't. } + /** Returns the id at the given index, if it exists. */ + public new MessageID? get(int index) { + return this.list.get(index); + } + + /** Returns a read-only iterator of the ids in this list. */ + public Gee.Iterator iterator() { + return this.list.read_only_view.iterator(); + } + + /** Returns a read-only collection of the ids in this list. */ + public Gee.List get_all() { + return this.list.read_only_view; + } + /** * Returns a new list with the given messages ids appended to this list's. */ public MessageIDList append(MessageIDList others) { - MessageIDList new_ids = new MessageIDList(); - new_ids.list.add_all(this.list); + MessageIDList new_ids = new MessageIDList(this.list); new_ids.list.add_all(others.list); return new_ids; } @@ -157,13 +179,14 @@ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, return "MessageIDList (%d)".printf(list.size); } - public virtual string to_rfc822_string() { + public string to_rfc822_string() { string[] strings = new string[list.size]; - for(int i = 0; i < list.size; ++i) - strings[i] = list[i].value; + for(int i = 0; i < this.list.size; ++i) + strings[i] = this.list[i].to_rfc822_string(); return string.joinv(" ", strings); } + } public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.AbstractMessageData, diff --git a/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala index 866e8098..51fae6a3 100644 --- a/src/engine/rfc822/rfc822-utils.vala +++ b/src/engine/rfc822/rfc822-utils.vala @@ -101,13 +101,13 @@ namespace Geary.RFC822.Utils { var list = new Gee.ArrayList(); // 1. Start with the source's References list - if (source.references != null && source.references.list.size > 0) { - list.add_all(source.references.list); + if (source.references != null) { + list.add_all(source.references.get_all()); } // 2. If there are In-Reply-To Message-IDs and they're not in the References list, append them if (source.in_reply_to != null) { - foreach (var reply_id in source.in_reply_to.list) { + foreach (var reply_id in source.in_reply_to.get_all()) { if (!list.contains(reply_id)) { list.add(reply_id); } diff --git a/test/engine/rfc822/rfc822-message-test.vala b/test/engine/rfc822/rfc822-message-test.vala index 979fcccb..1d263cc0 100644 --- a/test/engine/rfc822/rfc822-message-test.vala +++ b/test/engine/rfc822/rfc822-message-test.vala @@ -100,7 +100,7 @@ This is the second line. public void duplicate_message_id() throws Error { Message dup = string_to_message(DUPLICATE_REFERENCES); - assert(dup.references.list.size == 2); + assert(dup.references.size == 2); assert_message_id_list( dup.references, "<1234@local.machine.example> <5678@local.machine.example>" ); From 6e7631b8d30febe0f4c238e2e5a3670f3d9e52d4 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 11:27:00 +1000 Subject: [PATCH 20/41] Geary.RFC822: Clean up message data interfaces and classes Split Geary.RFC822.MessageData interface up into DecodedMessageData and EncodedMessageData so the difference between the two is clear and they can't be used interchangeably. Add `DecodedMessageData::to_rfc822_string` to provide a common interface for round-tripping decoded data. Update all classes to implement one of these and follow the same general API patterns. --- src/engine/imap-db/imap-db-message-row.vala | 8 +- src/engine/imap/api/imap-folder-session.vala | 4 +- .../response/imap-fetch-data-decoder.vala | 4 +- src/engine/rfc822/rfc822-mailbox-address.vala | 5 +- .../rfc822/rfc822-mailbox-addresses.vala | 3 +- src/engine/rfc822/rfc822-message-data.vala | 176 ++++++++++++------ .../app/app-conversation-monitor-test.vala | 2 +- .../engine/app/app-conversation-set-test.vala | 2 +- test/engine/app/app-conversation-test.vala | 2 +- .../rfc822/rfc822-message-data-test.vala | 10 +- 10 files changed, 138 insertions(+), 78 deletions(-) diff --git a/src/engine/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala index f7b065dc..0b09a8cd 100644 --- a/src/engine/imap-db/imap-db-message-row.vala +++ b/src/engine/imap-db/imap-db-message-row.vala @@ -106,7 +106,7 @@ private class Geary.ImapDB.MessageRow { if (fields.is_all_set(Geary.Email.Field.DATE)) { try { email.set_send_date( - !String.is_empty(date) ? new RFC822.Date(date) : null + !String.is_empty(date) ? new RFC822.Date.from_rfc822_string(date) : null ); } catch (GLib.Error err) { debug("Error loading message date from db: %s", err.message); @@ -133,7 +133,7 @@ private class Geary.ImapDB.MessageRow { } if (fields.is_all_set(Geary.Email.Field.SUBJECT)) - email.set_message_subject(new RFC822.Subject.decode(subject ?? "")); + email.set_message_subject(new RFC822.Subject.from_rfc822_string(subject ?? "")); if (fields.is_all_set(Geary.Email.Field.HEADER)) email.set_message_header(new RFC822.Header(header ?? Memory.EmptyBuffer.instance)); @@ -191,7 +191,7 @@ private class Geary.ImapDB.MessageRow { // null if empty if (email.fields.is_all_set(Geary.Email.Field.DATE)) { - date = (email.date != null) ? email.date.original : null; + date = (email.date != null) ? email.date.to_rfc822_string() : null; date_time_t = (email.date != null) ? email.date.value.to_unix() : -1; fields = fields.set(Geary.Email.Field.DATE); @@ -222,7 +222,7 @@ private class Geary.ImapDB.MessageRow { } if (email.fields.is_all_set(Geary.Email.Field.SUBJECT)) { - subject = (email.subject != null) ? email.subject.original : null; + subject = (email.subject != null) ? email.subject.to_rfc822_string() : null; fields = fields.set(Geary.Email.Field.SUBJECT); } diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala index a934fecc..e0e37687 100644 --- a/src/engine/imap/api/imap-folder-session.vala +++ b/src/engine/imap/api/imap-folder-session.vala @@ -901,7 +901,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject { RFC822.Date? date = null; if (!String.is_empty(value)) { try { - date = new RFC822.Date(value); + date = new RFC822.Date.from_rfc822_string(value); } catch (GLib.Error err) { warning( "Error parsing date from FETCH response: %s", @@ -979,7 +979,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject { if (required_but_not_set(Geary.Email.Field.SUBJECT, required_fields, email)) { string? value = headers.get("Subject"); if (value != null) - email.set_message_subject(new RFC822.Subject.decode(value)); + email.set_message_subject(new RFC822.Subject.from_rfc822_string(value)); else email.set_message_subject(null); } diff --git a/src/engine/imap/response/imap-fetch-data-decoder.vala b/src/engine/imap/response/imap-fetch-data-decoder.vala index 8f9f42b9..2d3cfce6 100644 --- a/src/engine/imap/response/imap-fetch-data-decoder.vala +++ b/src/engine/imap/response/imap-fetch-data-decoder.vala @@ -148,7 +148,7 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder { Geary.RFC822.Date? sent_date = null; if (sent != null) { try { - sent_date = new RFC822.Date(sent.ascii); + sent_date = new RFC822.Date.from_rfc822_string(sent.ascii); } catch (GLib.Error err) { debug( "Error parsing sent date from FETCH envelope: %s", @@ -159,7 +159,7 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder { return new Envelope( sent_date, - new Geary.RFC822.Subject.decode(subject.ascii), + new Geary.RFC822.Subject.from_rfc822_string(subject.ascii), parse_addresses(from), parse_addresses(sender), parse_addresses(reply_to), (to != null) ? parse_addresses(to) : null, (cc != null) ? parse_addresses(cc) : null, diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala index 7b9ea3f6..f4f622ce 100644 --- a/src/engine/rfc822/rfc822-mailbox-address.vala +++ b/src/engine/rfc822/rfc822-mailbox-address.vala @@ -17,9 +17,10 @@ * See [[https://tools.ietf.org/html/rfc5322#section-3.4]] */ public class Geary.RFC822.MailboxAddress : + Geary.MessageData.AbstractMessageData, Geary.MessageData.SearchableMessageData, Gee.Hashable, - BaseObject { + DecodedMessageData { private static unichar[] ATEXT = { '!', '#', '$', '%', '&', '\'', '*', '+', '-', @@ -551,7 +552,7 @@ public class Geary.RFC822.MailboxAddress : * * @see to_rfc822_string */ - public string to_string() { + public override string to_string() { return to_rfc822_string(); } diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala index 1e2bdc7c..5890f23f 100644 --- a/src/engine/rfc822/rfc822-mailbox-addresses.vala +++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala @@ -17,7 +17,8 @@ public class Geary.RFC822.MailboxAddresses : Geary.MessageData.AbstractMessageData, Geary.MessageData.SearchableMessageData, - Geary.RFC822.MessageData, Gee.Hashable { + Gee.Hashable, + DecodedMessageData { /** diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala index fdd75ccd..e228b344 100644 --- a/src/engine/rfc822/rfc822-message-data.vala +++ b/src/engine/rfc822/rfc822-message-data.vala @@ -1,46 +1,75 @@ -/* Copyright 2016 Software Freedom Conservancy Inc. +/* + * Copyright © 2016 Software Freedom Conservancy Inc. + * Copyright © 2020 Michael Gratton * * This software is licensed under the GNU Lesser General Public License * (version 2.1 or later). See the COPYING file in this distribution. */ /** - * RFC822.MessageData represents a base class for all the various elements that may be present in - * an RFC822 message header. Note that some common elements (such as MailAccount) are not - * MessageData because they exist in an RFC822 header in list (i.e. multiple email addresses) form. + * A base interface for objects that represent decoded RFC822 headers. + * + * The value of these objects is the decoded form of the header + * data. Encoded forms can be obtained via {@link to_rfc822_string}. */ +public interface Geary.RFC822.DecodedMessageData : + Geary.MessageData.AbstractMessageData { + + /** Returns an RFC822-safe string representation of the data. */ + public abstract string to_rfc822_string(); -public interface Geary.RFC822.MessageData : Geary.MessageData.AbstractMessageData { } /** - * An RFC822 Message-ID. + * A base interface for objects that represent encoded RFC822 header data. * - * MessageID will normalize all strings so that they begin and end with the proper brackets ("<" and - * ">"). + * The value of these objects is the RFC822 encoded form of the header + * data. Decoded forms can be obtained via means specific to + * implementations of this interface. */ -public class Geary.RFC822.MessageID : Geary.MessageData.StringMessageData, Geary.RFC822.MessageData { +public interface Geary.RFC822.EncodedMessageData : + Geary.MessageData.BlockMessageData { + +} + +/** + * A RFC822 Message-ID. + * + * The decoded form of the id is the `addr-spec` portion, that is, + * without the leading `<` and tailing `>`. + */ +public class Geary.RFC822.MessageID : + Geary.MessageData.StringMessageData, DecodedMessageData { + + private string rfc822; + public MessageID(string value) { - string? normalized = normalize(value); - base (normalized ?? value); + base(value); } - // Adds brackets if required, null if no change required - private static string? normalize(string value) { - bool needs_prefix = !value.has_prefix("<"); - bool needs_suffix = !value.has_suffix(">"); - if (!needs_prefix && !needs_suffix) - return null; - - return "%s%s%s".printf(needs_prefix ? "<" : "", value, needs_suffix ? ">" : ""); + public MessageID.from_rfc822_string(string rfc822) { + base(GMime.utils_decode_message_id(rfc822)); + this.rfc822 = rfc822; } + + /** + * Returns the {@link Date} in RFC 822 format. + */ + public string to_rfc822_string() { + if (this.rfc822 == null) { + this.rfc822 = "<%s>".printf(this.value); + } + return this.rfc822; + } + } /** * A immutable list of RFC822 Message-ID values. */ -public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, Geary.RFC822.MessageData { - public Gee.List list { get; private set; } +public class Geary.RFC822.MessageIDList : + Geary.MessageData.AbstractMessageData, + DecodedMessageData { /** Returns the number of ids in this list. */ @@ -189,71 +218,87 @@ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, } -public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.AbstractMessageData, - Gee.Hashable { +public class Geary.RFC822.Date : + Geary.MessageData.AbstractMessageData, + Gee.Hashable, + DecodedMessageData { - public string original { get; private set; } - public DateTime value { get; private set; } - public Date(string rfc822) throws RFC822Error { + public GLib.DateTime value { get; private set; } + + private string? rfc822; + + + public Date(GLib.DateTime datetime) { + this.value = datetime; + this.rfc822 = null; + } + + public Date.from_rfc822_string(string rfc822) throws RFC822Error { var date = GMime.utils_header_decode_date(rfc822); if (date == null) { throw new RFC822Error.INVALID("Not ISO-8601 date: %s", rfc822); } + this.rfc822 = rfc822; this.value = date; - this.original = rfc822; - } - - public Date.from_date_time(DateTime datetime) { - this.original = null; - this.value = datetime; } /** * Returns the {@link Date} in RFC 822 format. */ public string to_rfc822_string() { - return GMime.utils_header_format_date(this.value); - } - - /** - * Returns {@link Date} for transmission. - * - * @see to_rfc822_string - */ - public virtual string serialize() { - return to_rfc822_string(); + if (this.rfc822 == null) { + this.rfc822 = GMime.utils_header_format_date(this.value); + } + return this.rfc822; } public virtual bool equal_to(Geary.RFC822.Date other) { - return (this != other) ? value.equal(other.value) : true; + return this == other || this.value.equal(other.value); } public virtual uint hash() { - return value.hash(); + return this.value.hash(); } public override string to_string() { - return original ?? value.to_string(); + return this.value.to_string(); } } -public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData, - Geary.MessageData.SearchableMessageData, Geary.RFC822.MessageData { +public class Geary.RFC822.Subject : + Geary.MessageData.StringMessageData, + Geary.MessageData.SearchableMessageData, + DecodedMessageData { + public const string REPLY_PREFACE = "Re:"; public const string FORWARD_PREFACE = "Fwd:"; - public string original { get; private set; } + + private string rfc822; + public Subject(string value) { - base (value); - original = value; + base(value); + this.rfc822 = null; } - public Subject.decode(string value) { - base (GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value)); - original = value; + public Subject.from_rfc822_string(string rfc822) { + base(GMime.utils_header_decode_text(get_parser_options(), rfc822)); + this.rfc822 = rfc822; + } + + /** + * Returns the subject line encoded for an RFC 822 message. + */ + public string to_rfc822_string() { + if (this.rfc822 == null) { + this.rfc822 = GMime.utils_header_encode_text( + get_format_options(), this.value, null + ); + } + return this.rfc822; } public bool is_reply() { @@ -312,9 +357,13 @@ public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData, public string to_searchable_string() { return value; } + } -public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC822.MessageData { +public class Geary.RFC822.Header : + Geary.MessageData.BlockMessageData, EncodedMessageData { + + private GMime.Message? message = null; private string[]? names = null; @@ -353,22 +402,30 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC } return this.names; } + } -public class Geary.RFC822.Text : Geary.MessageData.BlockMessageData, Geary.RFC822.MessageData { +public class Geary.RFC822.Text : + Geary.MessageData.BlockMessageData, EncodedMessageData { + public Text(Memory.Buffer buffer) { - base ("RFC822.Text", buffer); + base("RFC822.Text", buffer); } + } -public class Geary.RFC822.Full : Geary.MessageData.BlockMessageData, Geary.RFC822.MessageData { +public class Geary.RFC822.Full : + Geary.MessageData.BlockMessageData, EncodedMessageData { + public Full(Memory.Buffer buffer) { - base ("RFC822.Full", buffer); + base("RFC822.Full", buffer); } + } -// Used for decoding preview text. +/** Represents text providing a preview of an email's body. */ public class Geary.RFC822.PreviewText : Geary.RFC822.Text { + public PreviewText(Memory.Buffer _buffer) { base (_buffer); } @@ -415,4 +472,5 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text { public PreviewText.from_string(string preview) { base (new Geary.Memory.StringBuffer(preview)); } + } diff --git a/test/engine/app/app-conversation-monitor-test.vala b/test/engine/app/app-conversation-monitor-test.vala index 0dec7655..3224cf8b 100644 --- a/test/engine/app/app-conversation-monitor-test.vala +++ b/test/engine/app/app-conversation-monitor-test.vala @@ -434,7 +434,7 @@ class Geary.App.ConversationMonitorTest : TestCase { references.message_id ); } - email.set_send_date(new Geary.RFC822.Date.from_date_time(now)); + email.set_send_date(new RFC822.Date(now)); email.set_email_properties(new MockEmailProperties(now)); email.set_full_references(mid, null, refs_list); return email; diff --git a/test/engine/app/app-conversation-set-test.vala b/test/engine/app/app-conversation-set-test.vala index 1250ad6a..2966e134 100644 --- a/test/engine/app/app-conversation-set-test.vala +++ b/test/engine/app/app-conversation-set-test.vala @@ -489,7 +489,7 @@ class Geary.App.ConversationSetTest : TestCase { references.message_id ); } - email.set_send_date(new Geary.RFC822.Date.from_date_time(now)); + email.set_send_date(new RFC822.Date(now)); email.set_email_properties(new MockEmailProperties(now)); email.set_full_references(mid, null, refs_list); return email; diff --git a/test/engine/app/app-conversation-test.vala b/test/engine/app/app-conversation-test.vala index e6c73143..03ebd8f2 100644 --- a/test/engine/app/app-conversation-test.vala +++ b/test/engine/app/app-conversation-test.vala @@ -289,7 +289,7 @@ class Geary.App.ConversationTest : TestCase { ); email.set_full_references(mid, null, null); email.set_email_properties(new MockEmailProperties(now)); - email.set_send_date(new Geary.RFC822.Date.from_date_time(now)); + email.set_send_date(new RFC822.Date(now)); return email; } diff --git a/test/engine/rfc822/rfc822-message-data-test.vala b/test/engine/rfc822/rfc822-message-data-test.vala index 504efaa0..dd9b2bf3 100644 --- a/test/engine/rfc822/rfc822-message-data-test.vala +++ b/test/engine/rfc822/rfc822-message-data-test.vala @@ -61,7 +61,7 @@ class Geary.RFC822.MessageDataTest : TestCase { public void date_from_rfc822() throws GLib.Error { const string FULL_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 -0100"; - Date full_hour_tz = new Date(FULL_HOUR_TZ); + Date full_hour_tz = new Date.from_rfc822_string(FULL_HOUR_TZ); assert_int64( ((int64) (-1 * 3600)) * 1000 * 1000, full_hour_tz.value.get_utc_offset(), @@ -81,7 +81,7 @@ class Geary.RFC822.MessageDataTest : TestCase { ); const string HALF_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 +1030"; - Date half_hour_tz = new Date(HALF_HOUR_TZ); + Date half_hour_tz = new Date.from_rfc822_string(HALF_HOUR_TZ); assert_int64( ((int64) (10.5 * 3600)) * 1000 * 1000, half_hour_tz.value.get_utc_offset() @@ -96,15 +96,15 @@ class Geary.RFC822.MessageDataTest : TestCase { public void date_to_rfc822() throws GLib.Error { const string FULL_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 -0100"; - Date full_hour_tz = new Date(FULL_HOUR_TZ); + Date full_hour_tz = new Date.from_rfc822_string(FULL_HOUR_TZ); assert_string(FULL_HOUR_TZ, full_hour_tz.to_rfc822_string()); const string HALF_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 +1030"; - Date half_hour_tz = new Date(HALF_HOUR_TZ); + Date half_hour_tz = new Date.from_rfc822_string(HALF_HOUR_TZ); assert_string(HALF_HOUR_TZ, half_hour_tz.to_rfc822_string()); const string NEG_HALF_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 -1030"; - Date neg_half_hour_tz = new Date(NEG_HALF_HOUR_TZ); + Date neg_half_hour_tz = new Date.from_rfc822_string(NEG_HALF_HOUR_TZ); assert_string(NEG_HALF_HOUR_TZ, neg_half_hour_tz.to_rfc822_string()); } From 288c78a93aa1644c8ca4ac273e5d4fc390a6a312 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 12:21:16 +1000 Subject: [PATCH 21/41] Geary.RFC822.Message: Rework constructors and stocking from GMimeMessage Make constructors use the Message.from_gmime where possible. Merge that and stock_from_gmime so it's clear the stocking only happens in the ctor. Update stocking to use high-level GMime APIs where available to avoid re-parsing header values. --- src/engine/rfc822/rfc822-mailbox-address.vala | 4 +- .../rfc822/rfc822-mailbox-addresses.vala | 6 +- src/engine/rfc822/rfc822-message.vala | 166 +++++++++--------- test/engine/rfc822/rfc822-message-test.vala | 12 +- 4 files changed, 91 insertions(+), 97 deletions(-) diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala index f4f622ce..089fc459 100644 --- a/src/engine/rfc822/rfc822-mailbox-address.vala +++ b/src/engine/rfc822/rfc822-mailbox-address.vala @@ -256,10 +256,10 @@ public class Geary.RFC822.MailboxAddress : ); } - this.gmime(mbox_addr); + this.from_gmime(mbox_addr); } - public MailboxAddress.gmime(GMime.InternetAddressMailbox mailbox) { + public MailboxAddress.from_gmime(GMime.InternetAddressMailbox mailbox) { // GMime strips source route for us, so the address part // should only ever contain a single '@' string? name = mailbox.get_name(); diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala index 5890f23f..e39b27e8 100644 --- a/src/engine/rfc822/rfc822-mailbox-addresses.vala +++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala @@ -100,7 +100,7 @@ public class Geary.RFC822.MailboxAddresses : var addr = list.get_address(i); var mbox_addr = addr as GMime.InternetAddressMailbox; if (mbox_addr != null) { - this.addrs.add(new MailboxAddress.gmime(mbox_addr)); + this.addrs.add(new MailboxAddress.from_gmime(mbox_addr)); } else { // XXX this is pretty bad - we just flatten the // group's addresses into this list, merging lists and @@ -112,7 +112,9 @@ public class Geary.RFC822.MailboxAddresses : var group_addr = group_list.get_address(j) as GMime.InternetAddressMailbox; if (group_addr != null) { - this.addrs.add(new MailboxAddress.gmime(group_addr)); + this.addrs.add( + new MailboxAddress.from_gmime(group_addr) + ); } } } diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index 08f08f1d..36894084 100644 --- a/src/engine/rfc822/rfc822-message.vala +++ b/src/engine/rfc822/rfc822-message.vala @@ -36,16 +36,14 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { private const string HEADER_BCC = "Bcc"; // Internal note: If a header field is added here, it *must* be - // set in stock_from_gmime(). - - /** {@inheritDoc} */ - - /** {@inheritDoc} */ - public RFC822.MailboxAddress? sender { get; protected set; default = null; } + // set in Message.from_gmime_message(), below. /** {@inheritDoc} */ public RFC822.MailboxAddresses? from { get; protected set; default = null; } + /** {@inheritDoc} */ + public RFC822.MailboxAddress? sender { get; protected set; default = null; } + /** {@inheritDoc} */ public RFC822.MailboxAddresses? to { get; protected set; default = null; } @@ -87,23 +85,78 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { public Message(Full full) throws RFC822Error { - GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(full.buffer)); - - message = parser.construct_message(Geary.RFC822.get_parser_options()); - if (message == null) + GMime.Parser parser = new GMime.Parser.with_stream( + Utils.create_stream_mem(full.buffer) + ); + var message = parser.construct_message(get_parser_options()); + if (message == null) { throw new RFC822Error.INVALID("Unable to parse RFC 822 message"); + } + + this.from_gmime_message(message); // See the declaration of these fields for why we do this. - body_buffer = full.buffer; - body_offset = (size_t) parser.get_headers_end(); - - stock_from_gmime(); + this.body_buffer = full.buffer; + this.body_offset = (size_t) parser.get_headers_end(); } public Message.from_gmime_message(GMime.Message message) throws RFC822Error { this.message = message; - stock_from_gmime(); + + this.from = to_addresses(message.get_from()); + this.to = to_addresses(message.get_to()); + this.cc = to_addresses(message.get_cc()); + this.bcc = to_addresses(message.get_bcc()); + this.reply_to = to_addresses(message.get_reply_to()); + + var sender = ( + message.get_sender().get_address(0) as GMime.InternetAddressMailbox + ); + if (sender != null) { + this.sender = new MailboxAddress.from_gmime(sender); + } + + var subject = message.get_subject(); + if (subject != null) { + this.subject = new Subject(subject); + } + + // Use a pointer here to work around GNOME/vala#986 + GLib.DateTime* date = message.get_date(); + if (date != null) { + this.date = new Date(date); + } + + var message_id = message.get_message_id(); + if (message_id != null) { + this.message_id = new MessageID(message_id); + } + + // Since these headers may be specified multiple times, we + // need to iterate over all of them to find them. + var headers = message.get_header_list(); + for (int i = 0; i < headers.get_count(); i++) { + var header = headers.get_header_at(i); + switch (header.get_name().down()) { + case "in-reply-to": + this.in_reply_to = append_message_id( + this.in_reply_to, header.get_raw_value() + ); + break; + + case "references": + this.references = append_message_id( + this.references, header.get_raw_value() + ); + break; + + default: + break; + } + } + + this.mailer = message.get_header("X-Mailer"); } public Message.from_buffer(Memory.Buffer full_email) @@ -118,14 +171,16 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { stream_cat.add_source(new GMime.StreamMem.with_buffer(body.buffer.get_bytes().get_data())); GMime.Parser parser = new GMime.Parser.with_stream(stream_cat); - message = parser.construct_message(Geary.RFC822.get_parser_options()); - if (message == null) + var message = parser.construct_message(Geary.RFC822.get_parser_options()); + if (message == null) { throw new RFC822Error.INVALID("Unable to parse RFC 822 message"); + } - body_buffer = body.buffer; - body_offset = 0; + this.from_gmime_message(message); - stock_from_gmime(); + // See the declaration of these fields for why we do this. + this.body_buffer = body.buffer; + this.body_offset = 0; } public async Message.from_composed_email(Geary.ComposedEmail email, @@ -887,73 +942,11 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { return attachments; } - private void stock_from_gmime() throws RFC822Error { - GMime.HeaderList headers = this.message.headers; - for (int i = 0; i < headers.get_count(); i++) { - GMime.Header header = headers.get_header_at(i); - string value = header.get_value(); - switch (header.get_name().down()) { - case "from": - this.from = append_address(this.from, value); - break; - - case "sender": - this.sender = new MailboxAddress.from_rfc822_string(value); - break; - - case "reply-to": - this.reply_to = append_address(this.reply_to, value); - break; - - case "to": - this.to = append_address(this.to, value); - break; - - case "cc": - this.cc = append_address(this.cc, value); - break; - - case "bcc": - this.bcc = append_address(this.bcc, value); - break; - - case "subject": - this.subject = new Subject.decode(value); - break; - - case "date": - this.date = new Date(value); - break; - - case "message-id": - this.message_id = new MessageID(value); - break; - - case "in-reply-to": - this.in_reply_to = append_message_id(this.in_reply_to, value); - break; - - case "references": - this.references = append_message_id(this.references, value); - break; - - case "x-mailer": - this.mailer = GMime.utils_header_decode_text(null, value); - break; - - default: - // Ignore anything else not - break; - } - } - } - - private MailboxAddresses append_address(MailboxAddresses? existing, - string header_value) + private MailboxAddresses? to_addresses(GMime.InternetAddressList? list) throws RFC822Error { - MailboxAddresses addresses = new MailboxAddresses.from_rfc822_string(header_value); - if (existing != null) { - addresses = existing.append(addresses); + MailboxAddresses? addresses = null; + if (list != null && list.length() > 0) { + addresses = new MailboxAddresses.from_gmime(list); } return addresses; } @@ -971,7 +964,6 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { GMime.Object root, Mime.DispositionType requested_disposition) throws RFC822Error { - if (root is GMime.Multipart) { GMime.Multipart multipart = (GMime.Multipart) root; int count = multipart.get_count(); diff --git a/test/engine/rfc822/rfc822-message-test.vala b/test/engine/rfc822/rfc822-message-test.vala index 1d263cc0..9c8de2a2 100644 --- a/test/engine/rfc822/rfc822-message-test.vala +++ b/test/engine/rfc822/rfc822-message-test.vala @@ -74,10 +74,10 @@ This is the second line. assert_addresses(basic.to, "Charlie "); assert_addresses(basic.cc, "Dave "); assert_addresses(basic.bcc, "Eve "); - //assert_data(basic.message_id, "<3456@example.net>"); + assert_data(basic.message_id, "3456@example.net"); assert_message_id_list(basic.in_reply_to, "<1234@local.machine.example>"); assert_message_id_list(basic.references, "<1234@local.machine.example>"); - assert_data(basic.date, "Fri, 21 Nov 1997 10:01:10 -0600"); + assert_data(basic.date, "1997-11-21T10:01:10-0600"); assert(basic.mailer == "Geary Test Suite 1.0"); } @@ -85,7 +85,7 @@ This is the second line. Message enc = string_to_message(ENCODED_TO); // Courtesy Mailsploit https://www.mailsploit.com - assert(enc.to[0].name == "potus@whitehouse.gov "); + assert_string("potus@whitehouse.gov ", enc.to[0].name); } public void duplicate_mailbox() throws Error { @@ -432,9 +432,9 @@ This is the second line. private void assert_message_id_list(Geary.RFC822.MessageIDList? ids, string expected) - throws Error { - assert_non_null(ids, expected); - assert(ids.to_rfc822_string() == expected); + throws GLib.Error { + assert_non_null(ids, "ids are null"); + assert_string(expected, ids.to_rfc822_string()); } // Courtesy Mailsploit https://www.mailsploit.com From 21aea73a3daffc06fcd67eab39d96125798df584 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 12:23:18 +1000 Subject: [PATCH 22/41] test/test-engine.vala: Minor test ordering improvement --- test/test-engine.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test-engine.vala b/test/test-engine.vala index 2edf95c6..9f88b85a 100644 --- a/test/test-engine.vala +++ b/test/test-engine.vala @@ -83,10 +83,12 @@ int main(string[] args) { engine.add_suite(new Geary.Outbox.EmailIdentifierTest().get_suite()); engine.add_suite(new Geary.RFC822.MailboxAddressTest().get_suite()); engine.add_suite(new Geary.RFC822.MailboxAddressesTest().get_suite()); - engine.add_suite(new Geary.RFC822.MessageTest().get_suite()); engine.add_suite(new Geary.RFC822.MessageDataTest().get_suite()); engine.add_suite(new Geary.RFC822.PartTest().get_suite()); engine.add_suite(new Geary.RFC822.Utils.Test().get_suite()); + // Message requires all of the rest of the package working, so put + // last + engine.add_suite(new Geary.RFC822.MessageTest().get_suite()); engine.add_suite(new Geary.String.Test().get_suite()); engine.add_suite(new Geary.ComposedEmailTest().get_suite()); From c073bbbd80f0d7f2a9510e7f3fbaa67a5c8dff0c Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 12:25:14 +1000 Subject: [PATCH 23/41] test/test-server.vala: Fix build warning --- test/test-server.vala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-server.vala b/test/test-server.vala index 39e99e70..b0894688 100644 --- a/test/test-server.vala +++ b/test/test-server.vala @@ -132,6 +132,10 @@ public class TestServer : GLib.Object { foreach (var line in this.script) { result.line = line; switch (line.action) { + case CONNECTED: + // no-op + break; + case SEND_LINE: debug("Sending: %s", line.value); try { From 26e76b6f4d125d81e9d33282faee33b82b7e2ec4 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 13:54:59 +1000 Subject: [PATCH 24/41] Geary.RFC822Error: Rename so it's actually in the RFC822 namespace --- src/client/accounts/accounts-manager.vala | 4 +- src/client/composer/composer-email-entry.vala | 2 +- .../conversation-message.vala | 2 +- src/engine/api/geary-email.vala | 4 +- src/engine/imap-db/imap-db-message-row.vala | 4 +- .../imap/message/imap-message-data.vala | 2 +- src/engine/rfc822/rfc822-error.vala | 6 +- src/engine/rfc822/rfc822-mailbox-address.vala | 10 ++- .../rfc822/rfc822-mailbox-addresses.vala | 8 +-- src/engine/rfc822/rfc822-message-data.vala | 10 +-- src/engine/rfc822/rfc822-message.vala | 65 ++++++++++--------- src/engine/rfc822/rfc822-part.vala | 16 ++--- .../rfc822/rfc822-mailbox-address-test.vala | 16 ++--- .../rfc822/rfc822-mailbox-addresses-test.vala | 8 +-- .../rfc822/rfc822-message-data-test.vala | 2 +- test/engine/rfc822/rfc822-message-test.vala | 50 +++++++------- test/engine/rfc822/rfc822-part-test.vala | 10 +-- test/engine/rfc822/rfc822-utils-test.vala | 2 +- test/integration/smtp/client-session.vala | 2 +- 19 files changed, 112 insertions(+), 111 deletions(-) diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala index 7b7c101c..c0ead2bb 100644 --- a/src/client/accounts/accounts-manager.vala +++ b/src/client/accounts/accounts-manager.vala @@ -1051,7 +1051,7 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object { senders.add( new Geary.RFC822.MailboxAddress.from_rfc822_string(sender) ); - } catch (Geary.RFC822Error err) { + } catch (Geary.RFC822.Error err) { throw new ConfigError.SYNTAX( "%s: Invalid sender address: %s", id, sender ); @@ -1279,7 +1279,7 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object { foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all()) { info.append_sender(mailbox); } - } catch (Geary.RFC822Error error) { + } catch (Geary.RFC822.Error error) { throw new ConfigError.SYNTAX( "Invalid alternate email: %s", error.message ); diff --git a/src/client/composer/composer-email-entry.vala b/src/client/composer/composer-email-entry.vala index cd4202b0..6b495510 100644 --- a/src/client/composer/composer-email-entry.vala +++ b/src/client/composer/composer-email-entry.vala @@ -85,7 +85,7 @@ public class Composer.EmailEntry : Gtk.Entry { this._addresses = new Geary.RFC822.MailboxAddresses.from_rfc822_string(text); this.is_valid = true; - } catch (Geary.RFC822Error err) { + } catch (Geary.RFC822.Error err) { this._addresses = new Geary.RFC822.MailboxAddresses(); this.is_valid = false; } diff --git a/src/client/conversation-viewer/conversation-message.vala b/src/client/conversation-viewer/conversation-message.vala index a7494ad8..50ac031e 100644 --- a/src/client/conversation-viewer/conversation-message.vala +++ b/src/client/conversation-viewer/conversation-message.vala @@ -1029,7 +1029,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { id, part.write_to_buffer(Geary.RFC822.Part.EncodingConversion.UTF8) ); - } catch (Geary.RFC822Error err) { + } catch (Geary.RFC822.Error err) { debug("Failed to get inline buffer: %s", err.message); return null; } diff --git a/src/engine/api/geary-email.vala b/src/engine/api/geary-email.vala index b2b77c86..d6a0fe6d 100644 --- a/src/engine/api/geary-email.vala +++ b/src/engine/api/geary-email.vala @@ -381,7 +381,7 @@ public class Geary.Email : BaseObject, EmailHeaderSet { public void set_originators(Geary.RFC822.MailboxAddresses? from, Geary.RFC822.MailboxAddress? sender, Geary.RFC822.MailboxAddresses? reply_to) - throws RFC822Error { + throws Error { // XXX Should be throwing an error here if from is empty or // sender is same as from this.from = from; @@ -477,7 +477,7 @@ public class Geary.Email : BaseObject, EmailHeaderSet { * present. If not, {@link EngineError.INCOMPLETE_MESSAGE} is * thrown. */ - public Geary.RFC822.Message get_message() throws EngineError, RFC822Error { + public Geary.RFC822.Message get_message() throws EngineError, Error { if (message != null) return message; diff --git a/src/engine/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala index 0b09a8cd..03b49b0d 100644 --- a/src/engine/imap-db/imap-db-message-row.vala +++ b/src/engine/imap-db/imap-db-message-row.vala @@ -275,7 +275,7 @@ private class Geary.ImapDB.MessageRow { } private RFC822.MailboxAddress? unflatten_address(string? str) - throws RFC822Error { + throws RFC822.Error { return ( String.is_empty_or_whitespace(str) ? null @@ -284,7 +284,7 @@ private class Geary.ImapDB.MessageRow { } private RFC822.MailboxAddresses? unflatten_addresses(string? str) - throws RFC822Error { + throws RFC822.Error { return ( String.is_empty_or_whitespace(str) ? null diff --git a/src/engine/imap/message/imap-message-data.vala b/src/engine/imap/message/imap-message-data.vala index b61a8944..18933303 100644 --- a/src/engine/imap/message/imap-message-data.vala +++ b/src/engine/imap/message/imap-message-data.vala @@ -30,7 +30,7 @@ public class Geary.Imap.RFC822Header : Geary.RFC822.Header, Geary.Imap.MessageDa throws ImapError { try { base(buffer); - } catch (RFC822Error error) { + } catch (RFC822.Error error) { throw new ImapError.INVALID(error.message); } } diff --git a/src/engine/rfc822/rfc822-error.vala b/src/engine/rfc822/rfc822-error.vala index 23105ca7..758912a7 100644 --- a/src/engine/rfc822/rfc822-error.vala +++ b/src/engine/rfc822/rfc822-error.vala @@ -4,9 +4,11 @@ * (version 2.1 or later). See the COPYING file in this distribution. */ -public errordomain Geary.RFC822Error { +/** + * An error that is thrown when manipulating RFC 822 objects and data. + */ +public errordomain Geary.RFC822.Error { INVALID, NOT_FOUND, FAILED } - diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala index 089fc459..173312a7 100644 --- a/src/engine/rfc822/rfc822-mailbox-address.vala +++ b/src/engine/rfc822/rfc822-mailbox-address.vala @@ -231,18 +231,16 @@ public class Geary.RFC822.MailboxAddress : this.address = "%s@%s".printf(mailbox, domain); } - public MailboxAddress.from_rfc822_string(string rfc822) throws RFC822Error { + public MailboxAddress.from_rfc822_string(string rfc822) throws Error { GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse( Geary.RFC822.get_parser_options(), rfc822 ); if (addrlist == null) { - throw new RFC822Error.INVALID( - "Not a RFC822 mailbox address: %s", rfc822 - ); + throw new Error.INVALID("Not a RFC822 mailbox address: %s", rfc822); } if (addrlist.length() != 1) { - throw new RFC822Error.INVALID( + throw new Error.INVALID( "Not a single RFC822 mailbox address: %s", rfc822 ); } @@ -251,7 +249,7 @@ public class Geary.RFC822.MailboxAddress : // TODO: Handle group lists var mbox_addr = addr as GMime.InternetAddressMailbox; if (mbox_addr == null) { - throw new RFC822Error.INVALID( + throw new Error.INVALID( "Group lists not currently supported: %s", rfc822 ); } diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala index e39b27e8..40ba2462 100644 --- a/src/engine/rfc822/rfc822-mailbox-addresses.vala +++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala @@ -82,19 +82,19 @@ public class Geary.RFC822.MailboxAddresses : } public MailboxAddresses.from_rfc822_string(string rfc822) - throws RFC822Error { + throws Error { var list = GMime.InternetAddressList.parse(null, rfc822); if (list == null) { - throw new RFC822Error.INVALID("Not a RFC822 mailbox address list"); + throw new Error.INVALID("Not a RFC822 mailbox address list"); } this.from_gmime(list); } public MailboxAddresses.from_gmime(GMime.InternetAddressList list) - throws RFC822Error { + throws Error { int length = list.length(); if (length == 0) { - throw new RFC822Error.INVALID("No addresses in list"); + throw new Error.INVALID("No addresses in list"); } for (int i = 0; i < length; i++) { var addr = list.get_address(i); diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala index e228b344..48b1d6f7 100644 --- a/src/engine/rfc822/rfc822-message-data.vala +++ b/src/engine/rfc822/rfc822-message-data.vala @@ -234,10 +234,10 @@ public class Geary.RFC822.Date : this.rfc822 = null; } - public Date.from_rfc822_string(string rfc822) throws RFC822Error { + public Date.from_rfc822_string(string rfc822) throws Error { var date = GMime.utils_header_decode_date(rfc822); if (date == null) { - throw new RFC822Error.INVALID("Not ISO-8601 date: %s", rfc822); + throw new Error.INVALID("Not ISO-8601 date: %s", rfc822); } this.rfc822 = rfc822; this.value = date; @@ -367,7 +367,7 @@ public class Geary.RFC822.Header : private GMime.Message? message = null; private string[]? names = null; - public Header(Memory.Buffer buffer) throws RFC822Error { + public Header(Memory.Buffer buffer) throws Error { base("RFC822.Header", buffer); var parser = new GMime.Parser.with_stream( @@ -378,7 +378,7 @@ public class Geary.RFC822.Header : this.message = parser.construct_message(null); if (this.message == null) { - throw new RFC822Error.INVALID("Unable to parse RFC 822 headers"); + throw new Error.INVALID("Unable to parse RFC 822 headers"); } } @@ -460,7 +460,7 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text { preview_buffer.get_valid_utf8(), is_html ? TextFormat.HTML : TextFormat.PLAIN ); - } catch (RFC822Error err) { + } catch (Error err) { debug("Failed to parse preview body: %s", err.message); } } diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index 36894084..fae87da2 100644 --- a/src/engine/rfc822/rfc822-message.vala +++ b/src/engine/rfc822/rfc822-message.vala @@ -84,13 +84,13 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { private size_t? body_offset = null; - public Message(Full full) throws RFC822Error { + public Message(Full full) throws Error { GMime.Parser parser = new GMime.Parser.with_stream( Utils.create_stream_mem(full.buffer) ); var message = parser.construct_message(get_parser_options()); if (message == null) { - throw new RFC822Error.INVALID("Unable to parse RFC 822 message"); + throw new Error.INVALID("Unable to parse RFC 822 message"); } this.from_gmime_message(message); @@ -101,7 +101,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } public Message.from_gmime_message(GMime.Message message) - throws RFC822Error { + throws Error { this.message = message; this.from = to_addresses(message.get_from()); @@ -160,12 +160,12 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } public Message.from_buffer(Memory.Buffer full_email) - throws RFC822Error { + throws Error { this(new Geary.RFC822.Full(full_email)); } public Message.from_parts(Header header, Text body) - throws RFC822Error { + throws Error { GMime.StreamCat stream_cat = new GMime.StreamCat(); stream_cat.add_source(new GMime.StreamMem.with_buffer(header.buffer.get_bytes().get_data())); stream_cat.add_source(new GMime.StreamMem.with_buffer(body.buffer.get_bytes().get_data())); @@ -173,7 +173,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { GMime.Parser parser = new GMime.Parser.with_stream(stream_cat); var message = parser.construct_message(Geary.RFC822.get_parser_options()); if (message == null) { - throw new RFC822Error.INVALID("Unable to parse RFC 822 message"); + throw new Error.INVALID("Unable to parse RFC 822 message"); } this.from_gmime_message(message); @@ -186,7 +186,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { public async Message.from_composed_email(Geary.ComposedEmail email, string? message_id, GLib.Cancellable? cancellable) - throws RFC822Error { + throws Error { this.message = new GMime.Message(true); // @@ -510,15 +510,14 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { string basename, Geary.Mime.DispositionType disposition, GLib.Cancellable cancellable) - throws Error { - + throws GLib.Error { Mime.ContentType? mime_type = Mime.ContentType.guess_type( basename, buffer ); if (mime_type == null) { - throw new RFC822Error.INVALID( + throw new Error.INVALID( _("Could not determine mime type for “%s”.").printf(basename) ); } @@ -529,7 +528,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { ); if (content_type == null) { - throw new RFC822Error.INVALID( + throw new Error.INVALID( _("Could not determine content type for mime type “%s” on “%s”.").printf(mime_type.to_string(), basename) ); } @@ -551,7 +550,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { GMime.Part part, GMime.ContentType content_type, GLib.Cancellable cancellable) - throws Error { + throws GLib.Error { // Text parts should be scanned fully to determine best // (i.e. most compact) transport encoding to use, but @@ -587,7 +586,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * out. See the various constructors for details. (Otherwise, we don't have a way * to get the body part directly, because of GMime's shortcomings.) */ - public Geary.Email get_email(Geary.EmailIdentifier id) throws Error { + public Geary.Email get_email(Geary.EmailIdentifier id) throws GLib.Error { assert(body_buffer != null); assert(body_offset != null); @@ -653,7 +652,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * Returns the {@link Message} as a {@link Memory.Buffer} suitable for in-memory use (i.e. * with native linefeed characters). */ - public Memory.Buffer get_native_buffer() throws RFC822Error { + public Memory.Buffer get_native_buffer() throws Error { return message_to_memory_buffer(false, false); } @@ -664,7 +663,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * The buffer can also be dot-stuffed if required. See * [[http://tools.ietf.org/html/rfc2821#section-4.5.2]] */ - public Memory.Buffer get_network_buffer(bool dotstuffed) throws RFC822Error { + public Memory.Buffer get_network_buffer(bool dotstuffed) throws Error { return message_to_memory_buffer(true, dotstuffed); } @@ -740,7 +739,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { bool to_html, InlinePartReplacer? replacer, ref string? body) - throws RFC822Error { + throws Error { Part part = new Part(node); Mime.ContentType content_type = part.content_type; @@ -807,11 +806,11 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * something that front-facing methods want to return. */ private string? internal_get_body(string text_subtype, bool to_html, InlinePartReplacer? replacer) - throws RFC822Error { + throws Error { string? body = null; if (!construct_body_from_mime_parts(message.get_mime_part(), Mime.MultipartSubtype.UNSPECIFIED, text_subtype, to_html, replacer, ref body)) { - throw new RFC822Error.NOT_FOUND("Could not find any \"text/%s\" parts", text_subtype); + throw new Error.NOT_FOUND("Could not find any \"text/%s\" parts", text_subtype); } return body; @@ -828,9 +827,9 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * lieu of the MIME part into the final document. All other MIME * parts are ignored. * - * @throws RFC822Error.NOT_FOUND if an HTML body is not present. + * @throws Error.NOT_FOUND if an HTML body is not present. */ - public string? get_html_body(InlinePartReplacer? replacer) throws RFC822Error { + public string? get_html_body(InlinePartReplacer? replacer) throws Error { return internal_get_body("html", false, replacer); } @@ -850,9 +849,10 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * output is not converted; it's up to the caller to know what * format to return when invoked. * - * @throws RFC822Error.NOT_FOUND if a plaintext body is not present. + * @throws Error.NOT_FOUND if a plaintext body is not present. */ - public string? get_plain_body(bool convert_to_html, InlinePartReplacer? replacer) throws RFC822Error { + public string? get_plain_body(bool convert_to_html, InlinePartReplacer? replacer) + throws Error { return internal_get_body("plain", convert_to_html, replacer); } @@ -864,7 +864,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { * that come out of this function are persisted. */ public string? get_searchable_body(bool include_sub_messages = true) - throws RFC822Error { + throws Error { string? body = null; bool html = false; try { @@ -936,14 +936,15 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { // UNSPECIFIED disposition means "return all Mime parts" internal Gee.List get_attachments( - Mime.DispositionType disposition = Mime.DispositionType.UNSPECIFIED) throws RFC822Error { + Mime.DispositionType disposition = Mime.DispositionType.UNSPECIFIED) + throws Error { Gee.List attachments = new Gee.LinkedList(); get_attachments_recursively(attachments, message.get_mime_part(), disposition); return attachments; } private MailboxAddresses? to_addresses(GMime.InternetAddressList? list) - throws RFC822Error { + throws Error { MailboxAddresses? addresses = null; if (list != null && list.length() > 0) { addresses = new MailboxAddresses.from_gmime(list); @@ -963,7 +964,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { private void get_attachments_recursively(Gee.List attachments, GMime.Object root, Mime.DispositionType requested_disposition) - throws RFC822Error { + throws Error { if (root is GMime.Multipart) { GMime.Multipart multipart = (GMime.Multipart) root; int count = multipart.get_count(); @@ -1052,7 +1053,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { #endif public Gee.List get_sub_messages() - throws RFC822Error { + throws Error { Gee.List messages = new Gee.ArrayList(); find_sub_messages(messages, message.get_mime_part()); return messages; @@ -1060,7 +1061,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { private void find_sub_messages(Gee.List messages, GMime.Object root) - throws RFC822Error { + throws Error { // If this is a multipart container, check each of its children. GMime.Multipart? multipart = root as GMime.Multipart; if (multipart != null) { @@ -1084,7 +1085,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { private Memory.Buffer message_to_memory_buffer(bool encode_lf, bool stuff_smtp) - throws RFC822Error { + throws Error { ByteArray byte_array = new ByteArray(); GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array); stream.set_owner(false); @@ -1100,13 +1101,13 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } if (message.write_to_stream(Geary.RFC822.get_format_options(), stream_filter) < 0) - throw new RFC822Error.FAILED("Unable to write RFC822 message to filter stream"); + throw new Error.FAILED("Unable to write RFC822 message to filter stream"); if (stream_filter.flush() != 0) - throw new RFC822Error.FAILED("Unable to flush RFC822 message to memory stream"); + throw new Error.FAILED("Unable to flush RFC822 message to memory stream"); if (stream.flush() != 0) - throw new RFC822Error.FAILED("Unable to flush RFC822 message to memory buffer"); + throw new Error.FAILED("Unable to flush RFC822 message to memory buffer"); return new Memory.ByteBuffer.from_byte_array(byte_array); } diff --git a/src/engine/rfc822/rfc822-part.vala b/src/engine/rfc822/rfc822-part.vala index 58c58ff0..9f19b6a2 100644 --- a/src/engine/rfc822/rfc822-part.vala +++ b/src/engine/rfc822/rfc822-part.vala @@ -145,7 +145,7 @@ public class Geary.RFC822.Part : Object { public Memory.Buffer write_to_buffer(EncodingConversion conversion, BodyFormatting format = BodyFormatting.NONE) - throws RFC822Error { + throws Error { ByteArray byte_array = new ByteArray(); GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array); stream.set_owner(false); @@ -158,11 +158,11 @@ public class Geary.RFC822.Part : Object { internal void write_to_stream(GMime.Stream destination, EncodingConversion conversion, BodyFormatting format = BodyFormatting.NONE) - throws RFC822Error { + throws Error { GMime.DataWrapper? wrapper = (this.source_part != null) ? this.source_part.get_content() : null; if (wrapper == null) { - throw new RFC822Error.INVALID( + throw new Error.INVALID( "Could not get the content wrapper for content-type %s", content_type.to_string() ); @@ -227,17 +227,17 @@ public class Geary.RFC822.Part : Object { } if (wrapper.write_to_stream(filter) < 0) - throw new RFC822Error.FAILED("Unable to write textual RFC822 part to filter stream"); + throw new Error.FAILED("Unable to write textual RFC822 part to filter stream"); if (filter.flush() != 0) - throw new RFC822Error.FAILED("Unable to flush textual RFC822 part to destination stream"); + throw new Error.FAILED("Unable to flush textual RFC822 part to destination stream"); if (destination.flush() != 0) - throw new RFC822Error.FAILED("Unable to flush textual RFC822 part to destination"); + throw new Error.FAILED("Unable to flush textual RFC822 part to destination"); } else { // Keep as binary if (wrapper.write_to_stream(destination) < 0) - throw new RFC822Error.FAILED("Unable to write binary RFC822 part to destination stream"); + throw new Error.FAILED("Unable to write binary RFC822 part to destination stream"); if (destination.flush() != 0) - throw new RFC822Error.FAILED("Unable to flush binary RFC822 part to destination"); + throw new Error.FAILED("Unable to flush binary RFC822 part to destination"); } } diff --git a/test/engine/rfc822/rfc822-mailbox-address-test.vala b/test/engine/rfc822/rfc822-mailbox-address-test.vala index 6b47a81f..7436629d 100644 --- a/test/engine/rfc822/rfc822-mailbox-address-test.vala +++ b/test/engine/rfc822/rfc822-mailbox-address-test.vala @@ -24,7 +24,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { add_test("equal_to", equal_to); } - public void is_valid_address() throws Error { + public void is_valid_address() throws GLib.Error { assert(Geary.RFC822.MailboxAddress.is_valid_address("john@dep.aol.museum") == true); assert(Geary.RFC822.MailboxAddress.is_valid_address("test@example.com") == true); assert(Geary.RFC822.MailboxAddress.is_valid_address("test.other@example.com") == true); @@ -44,7 +44,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { assert(Geary.RFC822.MailboxAddress.is_valid_address("\"Surname, Name\" ") == true); } - public void unescaped_constructor() throws Error { + public void unescaped_constructor() throws GLib.Error { MailboxAddress addr1 = new MailboxAddress("test1", "test2@example.com"); assert(addr1.name == "test1"); assert(addr1.address == "test2@example.com"); @@ -72,7 +72,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { assert(addr5.domain == ""); } - public void from_rfc822_string_encoded() throws Error { + public void from_rfc822_string_encoded() throws GLib.Error { try { MailboxAddress addr = new MailboxAddress.from_rfc822_string("test@example.com"); assert(addr.name == null); @@ -172,7 +172,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { assert(addr.name == "Firstname ¯_(ツ)_/¯ Lastname via=?UTF-8?Q?_Vendor=22_"); } - public void has_distinct_name() throws Error { + public void has_distinct_name() throws GLib.Error { assert(new MailboxAddress("example", "example@example.com").has_distinct_name() == true); assert(new MailboxAddress("", "example@example.com").has_distinct_name() == false); @@ -185,7 +185,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { assert(new MailboxAddress("'prefix-example@example.com'", "example@example.com").has_distinct_name() == true); } - public void is_spoofed() throws Error { + public void is_spoofed() throws GLib.Error { assert(new MailboxAddress(null, "example@example.com").is_spoofed() == false); assert(new MailboxAddress("", "example@example.com").is_spoofed() == false); assert(new MailboxAddress("", "example@example.com").is_spoofed() == false); @@ -213,7 +213,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { } } - public void to_full_display() throws Error { + public void to_full_display() throws GLib.Error { assert(new MailboxAddress("", "example@example.com").to_full_display() == "example@example.com"); assert(new MailboxAddress("Test", "example@example.com").to_full_display() == @@ -229,7 +229,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { ); } - public void to_short_display() throws Error { + public void to_short_display() throws GLib.Error { assert(new MailboxAddress("", "example@example.com").to_short_display() == "example@example.com"); assert(new MailboxAddress("Test", "example@example.com").to_short_display() == @@ -288,7 +288,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase { } - public void to_rfc822_string() throws Error { + public void to_rfc822_string() throws GLib.Error { assert(new MailboxAddress("", "example@example.com").to_rfc822_string() == "example@example.com"); assert(new MailboxAddress(" ", "example@example.com").to_rfc822_string() == diff --git a/test/engine/rfc822/rfc822-mailbox-addresses-test.vala b/test/engine/rfc822/rfc822-mailbox-addresses-test.vala index 70e535d5..f3fc2fa8 100644 --- a/test/engine/rfc822/rfc822-mailbox-addresses-test.vala +++ b/test/engine/rfc822/rfc822-mailbox-addresses-test.vala @@ -16,7 +16,7 @@ class Geary.RFC822.MailboxAddressesTest : TestCase { add_test("hash", hash); } - public void from_rfc822_string_encoded() throws Error { + public void from_rfc822_string_encoded() throws GLib.Error { MailboxAddresses addrs = new MailboxAddresses.from_rfc822_string("test@example.com"); assert(addrs.size == 1); @@ -43,7 +43,7 @@ class Geary.RFC822.MailboxAddressesTest : TestCase { assert_string("\"Surname, Name\" ", addrs.to_rfc822_string()); } - public void to_rfc822_string() throws Error { + public void to_rfc822_string() throws GLib.Error { assert(new MailboxAddresses().to_rfc822_string() == ""); assert(new_addreses({ "test1@example.com" }) .to_rfc822_string() == "test1@example.com"); @@ -51,7 +51,7 @@ class Geary.RFC822.MailboxAddressesTest : TestCase { .to_rfc822_string() == "test1@example.com, test2@example.com"); } - public void equal_to() throws Error { + public void equal_to() throws GLib.Error { var mailboxes_a = new_addreses({ "test1@example.com" }); var mailboxes_b = new_addreses({ "test1@example.com" }); var mailboxes_c = new_addreses({ "test2@example.com" }); @@ -83,7 +83,7 @@ class Geary.RFC822.MailboxAddressesTest : TestCase { ); } - public void hash() throws Error { + public void hash() throws GLib.Error { var mailboxes_a = new_addreses({ "test1@example.com" }); var mailboxes_b = new_addreses({ "test1@example.com" }); var mailboxes_c = new_addreses({ "test2@example.com" }); diff --git a/test/engine/rfc822/rfc822-message-data-test.vala b/test/engine/rfc822/rfc822-message-data-test.vala index dd9b2bf3..c6bc1553 100644 --- a/test/engine/rfc822/rfc822-message-data-test.vala +++ b/test/engine/rfc822/rfc822-message-data-test.vala @@ -17,7 +17,7 @@ class Geary.RFC822.MessageDataTest : TestCase { add_test("PreviewText.with_header", preview_text_with_header); } - public void preview_text_with_header() throws Error { + public void preview_text_with_header() throws GLib.Error { PreviewText plain_preview1 = new PreviewText.with_header( new Geary.Memory.StringBuffer(PLAIN_BODY1_HEADERS), new Geary.Memory.StringBuffer(PLAIN_BODY1_ENCODED) diff --git a/test/engine/rfc822/rfc822-message-test.vala b/test/engine/rfc822/rfc822-message-test.vala index 9c8de2a2..cb4bde34 100644 --- a/test/engine/rfc822/rfc822-message-test.vala +++ b/test/engine/rfc822/rfc822-message-test.vala @@ -64,7 +64,7 @@ This is the second line. add_test("get_network_buffer_long_ascii_line", get_network_buffer_long_ascii_line); } - public void basic_message_from_buffer() throws Error { + public void basic_message_from_buffer() throws GLib.Error { Message basic = resource_to_message(BASIC_TEXT_PLAIN); assert_data(basic.subject, "Re: Basic text/plain message"); @@ -81,14 +81,14 @@ This is the second line. assert(basic.mailer == "Geary Test Suite 1.0"); } - public void encoded_recipient() throws Error { + public void encoded_recipient() throws GLib.Error { Message enc = string_to_message(ENCODED_TO); // Courtesy Mailsploit https://www.mailsploit.com assert_string("potus@whitehouse.gov ", enc.to[0].name); } - public void duplicate_mailbox() throws Error { + public void duplicate_mailbox() throws GLib.Error { Message dup = string_to_message(DUPLICATE_TO); assert(dup.to.size == 2); @@ -97,7 +97,7 @@ This is the second line. ); } - public void duplicate_message_id() throws Error { + public void duplicate_message_id() throws GLib.Error { Message dup = string_to_message(DUPLICATE_REFERENCES); assert(dup.references.size == 2); @@ -106,7 +106,7 @@ This is the second line. ); } - public void text_plain_as_plain() throws Error { + public void text_plain_as_plain() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_PLAIN); assert_true(test.has_plain_body(), "Expected plain body"); @@ -114,7 +114,7 @@ This is the second line. assert_string(BASIC_PLAIN_BODY, test.get_plain_body(false, null)); } - public void text_plain_as_html() throws Error { + public void text_plain_as_html() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_PLAIN); assert_true(test.has_plain_body(), "Expected plain body"); @@ -125,7 +125,7 @@ This is the second line. ); } - public void text_html_as_html() throws Error { + public void text_html_as_html() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_HTML); assert_true(test.has_html_body(), "Expected html body"); @@ -133,7 +133,7 @@ This is the second line. assert_string(BASIC_HTML_BODY, test.get_html_body(null)); } - public void text_html_as_plain() throws Error { + public void text_html_as_plain() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_HTML); assert_true(test.has_html_body(), "Expected html body"); @@ -141,7 +141,7 @@ This is the second line. assert_string(BASIC_HTML_BODY, test.get_html_body(null)); } - public void tnef_extract_attachments() throws Error { + public void tnef_extract_attachments() throws GLib.Error { Message test = resource_to_message(BASIC_MULTIPART_TNEF); Gee.List attachments = test.get_attachments(); assert_true(attachments.size == 2); @@ -149,7 +149,7 @@ This is the second line. assert_true(attachments[1].get_clean_filename() == "bookmark.htm"); } - public void multipart_alternative_as_plain() throws Error { + public void multipart_alternative_as_plain() throws GLib.Error { Message test = resource_to_message(BASIC_MULTIPART_ALTERNATIVE); assert_true(test.has_plain_body(), "Expected plain body"); @@ -157,7 +157,7 @@ This is the second line. assert_string(BASIC_PLAIN_BODY, test.get_plain_body(false, null)); } - public void multipart_alternative_as_converted_html() throws Error { + public void multipart_alternative_as_converted_html() throws GLib.Error { Message test = resource_to_message(BASIC_MULTIPART_ALTERNATIVE); assert_true(test.has_plain_body(), "Expected plain body"); @@ -168,7 +168,7 @@ This is the second line. ); } - public void multipart_alternative_as_html() throws Error { + public void multipart_alternative_as_html() throws GLib.Error { Message test = resource_to_message(BASIC_MULTIPART_ALTERNATIVE); assert_true(test.has_plain_body(), "Expected plain body"); @@ -176,13 +176,13 @@ This is the second line. assert_string(BASIC_HTML_BODY, test.get_html_body(null)); } - public void get_preview() throws Error { + public void get_preview() throws GLib.Error { Message multipart_signed = string_to_message(MULTIPART_SIGNED_MESSAGE_TEXT); assert(multipart_signed.get_preview() == MULTIPART_SIGNED_MESSAGE_PREVIEW); } - public void get_recipients() throws Error { + public void get_recipients() throws GLib.Error { Message test = string_to_message(SIMPLE_MULTIRECIPIENT_TO_CC_BCC); Gee.List? addresses = test.get_recipients(); @@ -195,14 +195,14 @@ This is the second line. assert_addresses_list(addresses, verify_list, "get_recipients"); } - public void get_searchable_body() throws Error { + public void get_searchable_body() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_HTML); string searchable = test.get_searchable_body(); assert_true(searchable.contains("This is the first line"), "Expected body text"); assert_false(searchable.contains("

"), "Expected html removed"); } - public void get_searchable_recipients() throws Error { + public void get_searchable_recipients() throws GLib.Error { Message test = string_to_message(SIMPLE_MULTIRECIPIENT_TO_CC_BCC); string searchable = test.get_searchable_recipients(); assert_true(searchable.contains("Jane Doe "), "Expected to address"); @@ -210,7 +210,7 @@ This is the second line. assert_true(searchable.contains("Jane Doe BCC "), "Expected bcc address"); } - public void get_network_buffer() throws Error { + public void get_network_buffer() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_PLAIN); Memory.Buffer buffer = test.get_network_buffer(true); assert_true(buffer.to_string() == NETWORK_BUFFER_EXPECTED, "Network buffer differs"); @@ -318,7 +318,7 @@ This is the second line. ); } - public void from_composed_email_inline_attachments() throws Error { + public void from_composed_email_inline_attachments() throws GLib.Error { RFC822.MailboxAddress to = new RFC822.MailboxAddress( "Test", "test@example.com" ); @@ -372,7 +372,7 @@ This is the second line. } private async Message message_from_composed_email(ComposedEmail composed) - throws RFC822Error { + throws GLib.Error { return yield new Geary.RFC822.Message.from_composed_email( composed, GMime.utils_generate_message_id(composed.from.get(0).domain), @@ -380,7 +380,7 @@ This is the second line. ); } - private Message resource_to_message(string path) throws Error { + private Message resource_to_message(string path) throws GLib.Error { GLib.File resource = GLib.File.new_for_uri(RESOURCE_URI).resolve_relative_path(path); @@ -392,7 +392,7 @@ This is the second line. ); } - private Message string_to_message(string message_text) throws Error { + private Message string_to_message(string message_text) throws GLib.Error { return new Message.from_buffer( new Geary.Memory.StringBuffer(message_text) ); @@ -400,21 +400,21 @@ This is the second line. private void assert_data(Geary.MessageData.AbstractMessageData? actual, string expected) - throws Error { + throws GLib.Error { assert_non_null(actual, expected); assert_string(expected, actual.to_string()); } private void assert_address(Geary.RFC822.MailboxAddress? address, string expected) - throws Error { + throws GLib.Error { assert_non_null(address, expected); assert_string(expected, address.to_rfc822_string()); } private void assert_addresses(Geary.RFC822.MailboxAddresses? addresses, string expected) - throws Error { + throws GLib.Error { assert_non_null(addresses, expected); assert_string(expected, addresses.to_rfc822_string()); } @@ -422,7 +422,7 @@ This is the second line. private void assert_addresses_list(Gee.List? addresses, Gee.List expected, string context) - throws Error { + throws GLib.Error { assert_non_null(addresses, context + " not null"); assert_true(addresses.size == expected.size, context + " size"); foreach (RFC822.MailboxAddress address in addresses) { diff --git a/test/engine/rfc822/rfc822-part-test.vala b/test/engine/rfc822/rfc822-part-test.vala index 9ec2cabf..933d1505 100644 --- a/test/engine/rfc822/rfc822-part-test.vala +++ b/test/engine/rfc822/rfc822-part-test.vala @@ -23,7 +23,7 @@ class Geary.RFC822.PartTest : TestCase { add_test("write_to_buffer_plain_utf8", write_to_buffer_plain_utf8); } - public void new_from_minimal_mime_part() throws Error { + public void new_from_minimal_mime_part() throws GLib.Error { Part test = new Part(new_part("test/plain", CR_BODY.data)); assert_null_string(test.content_id, "content_id"); @@ -31,7 +31,7 @@ class Geary.RFC822.PartTest : TestCase { assert_null(test.content_disposition, "content_disposition"); } - public void new_from_complete_mime_part() throws Error { + public void new_from_complete_mime_part() throws GLib.Error { const string TYPE = "text/plain"; const string ID = "test-id"; const string DESC = "test description"; @@ -58,7 +58,7 @@ class Geary.RFC822.PartTest : TestCase { ); } - public void write_to_buffer_plain() throws Error { + public void write_to_buffer_plain() throws GLib.Error { Part test = new Part(new_part("text/plain", CR_BODY.data)); Memory.Buffer buf = test.write_to_buffer(Part.EncodingConversion.NONE); @@ -66,7 +66,7 @@ class Geary.RFC822.PartTest : TestCase { assert_string(CR_BODY, buf.to_string()); } - public void write_to_buffer_plain_crlf() throws Error { + public void write_to_buffer_plain_crlf() throws GLib.Error { Part test = new Part(new_part("text/plain", CRLF_BODY.data)); Memory.Buffer buf = test.write_to_buffer(Part.EncodingConversion.NONE); @@ -75,7 +75,7 @@ class Geary.RFC822.PartTest : TestCase { assert_string(CR_BODY, buf.to_string()); } - public void write_to_buffer_plain_ical() throws Error { + public void write_to_buffer_plain_ical() throws GLib.Error { Part test = new Part(new_part("text/calendar", ICAL_BODY.data)); Memory.Buffer buf = test.write_to_buffer(Part.EncodingConversion.NONE); diff --git a/test/engine/rfc822/rfc822-utils-test.vala b/test/engine/rfc822/rfc822-utils-test.vala index 1691fa41..7711fa9a 100644 --- a/test/engine/rfc822/rfc822-utils-test.vala +++ b/test/engine/rfc822/rfc822-utils-test.vala @@ -15,7 +15,7 @@ class Geary.RFC822.Utils.Test : TestCase { add_test("best_encoding_binary", best_encoding_binary); } - public void to_preview_text() throws Error { + public void to_preview_text() throws GLib.Error { assert(Geary.RFC822.Utils.to_preview_text(PLAIN_BODY_ENCODED, Geary.RFC822.TextFormat.PLAIN) == PLAIN_BODY_EXPECTED); assert(Geary.RFC822.Utils.to_preview_text(HTML_BODY_ENCODED, Geary.RFC822.TextFormat.HTML) == diff --git a/test/integration/smtp/client-session.vala b/test/integration/smtp/client-session.vala index 33ee89d0..3d81a5db 100644 --- a/test/integration/smtp/client-session.vala +++ b/test/integration/smtp/client-session.vala @@ -119,7 +119,7 @@ class Integration.Smtp.ClientSession : TestCase { private async Geary.RFC822.Message new_message(Geary.RFC822.MailboxAddress from, Geary.RFC822.MailboxAddress to) - throws Geary.RFC822Error { + throws Geary.RFC822.Error { Geary.ComposedEmail composed = new Geary.ComposedEmail( new GLib.DateTime.now_local(), new Geary.RFC822.MailboxAddresses.single(from) From c54ff85ccdcc02b71a0be5e43299d41920dbdb29 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 14:44:44 +1000 Subject: [PATCH 25/41] Geary.RFC822.Message: Update API for SMTP formatting Remove `Message.without_bcc` ctor since we can now get GMime to exclude BCC headers when serialising, avoiding the overhead of taking a complete copy of the message just to strip BCCs. Rename `get_network_buffer` to `get_rfc822_buffer` to be a bit more explicit in that's the way to get an actual RFC822 formatted message. Replace book args with flags, and take a protocol-specific approach rather than feature-specific, because in the end you're either going to want all the SMTP formatting quirks or none of them. Remove custom dot-stuffing support from Smtp.ClientConnection, since it is redundant. --- src/engine/imap/api/imap-folder-session.vala | 2 +- src/engine/outbox/outbox-folder.vala | 2 +- src/engine/rfc822/rfc822-message.vala | 90 +++++++++++++------- src/engine/smtp/smtp-client-connection.vala | 49 ++++------- src/engine/smtp/smtp-client-session.vala | 6 +- test/engine/rfc822/rfc822-message-test.vala | 50 +++++++++-- 6 files changed, 118 insertions(+), 81 deletions(-) diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala index e0e37687..b7c42a86 100644 --- a/src/engine/imap/api/imap-folder-session.vala +++ b/src/engine/imap/api/imap-folder-session.vala @@ -1069,7 +1069,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject { MailboxSpecifier mailbox = session.get_mailbox_for_path(this.folder.path); AppendCommand cmd = new AppendCommand( - mailbox, msg_flags, internaldate, message.get_network_buffer(false) + mailbox, msg_flags, internaldate, message.get_rfc822_buffer() ); Gee.Map responses = yield exec_commands_async( diff --git a/src/engine/outbox/outbox-folder.vala b/src/engine/outbox/outbox-folder.vala index 6b5217b1..8a083556 100644 --- a/src/engine/outbox/outbox-folder.vala +++ b/src/engine/outbox/outbox-folder.vala @@ -122,7 +122,7 @@ public class Geary.Outbox.Folder : // save in database ready for SMTP, but without dot-stuffing Db.Statement stmt = cx.prepare( "INSERT INTO SmtpOutboxTable (message, ordering) VALUES (?, ?)"); - stmt.bind_string_buffer(0, rfc822.get_network_buffer(false)); + stmt.bind_string_buffer(0, rfc822.get_rfc822_buffer()); stmt.bind_int64(1, ordering); int64 new_id = stmt.exec_insert(cancellable); diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index fae87da2..1c780e06 100644 --- a/src/engine/rfc822/rfc822-message.vala +++ b/src/engine/rfc822/rfc822-message.vala @@ -16,6 +16,7 @@ */ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { + /** * Callback for including non-text MIME entities in message bodies. * @@ -30,11 +31,36 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { */ public delegate string? InlinePartReplacer(Part part); + private const string HEADER_IN_REPLY_TO = "In-Reply-To"; private const string HEADER_REFERENCES = "References"; private const string HEADER_MAILER = "X-Mailer"; private const string HEADER_BCC = "Bcc"; + /** Options to use when serialising a message in RFC 822 format. */ + [Flags] + public enum RFC822FormatOptions { + + /** Format for RFC 822 in general. */ + NONE, + + /** + * The message should be serialised for transmission via SMTP. + * + * SMTP imposes both operational and data-format requirements + * on RFC 822 style messages. In particular, BCC headers + * should not be included since they will expose BCC + * recipients, and lines must be dot-stuffed so as to avoid + * terminating the message early if a line starting with a `.` + * is encountered. + * + * See [[http://tools.ietf.org/html/rfc5321#section-4.5.2]] + */ + SMTP_FORMAT; + + } + + // Internal note: If a header field is added here, it *must* be // set in Message.from_gmime_message(), below. @@ -440,22 +466,6 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { this.message.set_mime_part(main_part); } - // Makes a copy of the given message without the BCC fields. This is used for sending the email - // without sending the BCC headers to all recipients. - public Message.without_bcc(Message email) throws GLib.Error { - // GMime doesn't make it easy to get a copy of the body of a message. It's easy to - // make a new message and add in all the headers, but calling set_mime_part() with - // the existing one's get_mime_part() result yields a double Content-Type header in - // the *original* message. Clearly the objects aren't meant to be used like that. - // Barring any better way to clone a message, which I couldn't find by looking at - // the docs, we just dump out the old message to a buffer and read it back in to - // create the new object. Kinda sucks, but our hands are tied. - this.from_buffer(email.message_to_memory_buffer(false, false)); - - this.message.remove_header(HEADER_BCC); - this.bcc = null; - } - private GMime.Object? coalesce_related(Gee.List parts, string type) { GMime.Object? part = coalesce_parts(parts, "related"); @@ -649,22 +659,21 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } /** - * Returns the {@link Message} as a {@link Memory.Buffer} suitable for in-memory use (i.e. - * with native linefeed characters). + * Serialises the message using native (i.e. LF) line endings. */ public Memory.Buffer get_native_buffer() throws Error { - return message_to_memory_buffer(false, false); + return message_to_memory_buffer(false, NONE); } /** - * Returns the {@link Message} as a {@link Memory.Buffer} suitable for transmission or - * storage (i.e. using protocol-specific linefeeds). + * Serialises the message using RFC 822 (i.e. CRLF) line endings. * - * The buffer can also be dot-stuffed if required. See - * [[http://tools.ietf.org/html/rfc2821#section-4.5.2]] + * Returns the message as a memory buffer suitable for network + * transmission and interoperability with other RFC 822 consumers. */ - public Memory.Buffer get_network_buffer(bool dotstuffed) throws Error { - return message_to_memory_buffer(true, dotstuffed); + public Memory.Buffer get_rfc822_buffer(RFC822FormatOptions options = NONE) + throws Error { + return message_to_memory_buffer(true, options); } /** @@ -1084,7 +1093,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } private Memory.Buffer message_to_memory_buffer(bool encode_lf, - bool stuff_smtp) + RFC822FormatOptions options) throws Error { ByteArray byte_array = new ByteArray(); GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array); @@ -1096,18 +1105,33 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } else { stream_filter.add(new GMime.FilterDos2Unix(false)); } - if (stuff_smtp) { + if (RFC822FormatOptions.SMTP_FORMAT in options) { stream_filter.add(new GMime.FilterSmtpData()); } - if (message.write_to_stream(Geary.RFC822.get_format_options(), stream_filter) < 0) - throw new Error.FAILED("Unable to write RFC822 message to filter stream"); + var format = Geary.RFC822.get_format_options(); + if (RFC822FormatOptions.SMTP_FORMAT in options) { + format = format.clone(); + format.add_hidden_header("Bcc"); + } - if (stream_filter.flush() != 0) - throw new Error.FAILED("Unable to flush RFC822 message to memory stream"); + if (message.write_to_stream(format, stream_filter) < 0) { + throw new Error.FAILED( + "Unable to write RFC822 message to filter stream" + ); + } - if (stream.flush() != 0) - throw new Error.FAILED("Unable to flush RFC822 message to memory buffer"); + if (stream_filter.flush() != 0) { + throw new Error.FAILED( + "Unable to flush RFC822 message to memory stream" + ); + } + + if (stream.flush() != 0) { + throw new Error.FAILED( + "Unable to flush RFC822 message to memory buffer" + ); + } return new Memory.ByteBuffer.from_byte_array(byte_array); } diff --git a/src/engine/smtp/smtp-client-connection.vala b/src/engine/smtp/smtp-client-connection.vala index bc0e9310..5851aff7 100644 --- a/src/engine/smtp/smtp-client-connection.vala +++ b/src/engine/smtp/smtp-client-connection.vala @@ -119,47 +119,28 @@ internal class Geary.Smtp.ClientConnection : BaseObject, Logging.Source { * Returns the final Response of the transaction. If the ResponseCode is not a successful * completion, the message should not be considered sent. */ - public async Response send_data_async(Memory.Buffer data, bool already_dotstuffed, - Cancellable? cancellable = null) throws Error { + public async Response send_data_async(Memory.Buffer data, + GLib.Cancellable? cancellable = null) + throws GLib.Error { check_connected(); // In the case of DATA, want to receive an intermediate response code, specifically 354 Response response = yield transaction_async(new Request(Command.DATA), cancellable); - if (!response.code.is_start_data()) - return response; + if (response.code.is_start_data()) { + debug("SMTP Data: <%z>", data.size); - debug("SMTP Data: <%z>", data.size); - - if (!already_dotstuffed) { - // By using DataStreamNewlineType.ANY, we're assured to get each line and convert to - // a proper line terminator for SMTP - DataInputStream dins = new DataInputStream(data.get_input_stream()); - dins.set_newline_type(DataStreamNewlineType.ANY); - - // Read each line and dot-stuff if necessary - for (;;) { - size_t length; - string? line = yield dins.read_line_async(Priority.DEFAULT, cancellable, out length); - if (line == null) - break; - - // stuffing - if (line[0] == '.') - yield Stream.write_string_async(douts, ".", cancellable); - - yield Stream.write_string_async(douts, line, cancellable); - yield Stream.write_string_async(douts, DataFormat.LINE_TERMINATOR, cancellable); - } - } else { // ready to go, send and commit - yield Stream.write_all_async(douts, data, cancellable); + yield Stream.write_all_async(this.douts, data, cancellable); + + // terminate buffer and flush to server + yield Stream.write_string_async( + this.douts, DataFormat.DATA_TERMINATOR, cancellable + ); + yield this.douts.flush_async(Priority.DEFAULT, cancellable); + + response = yield recv_response_async(cancellable); } - - // terminate buffer and flush to server - yield Stream.write_string_async(douts, DataFormat.DATA_TERMINATOR, cancellable); - yield douts.flush_async(Priority.DEFAULT, cancellable); - - return yield recv_response_async(cancellable); + return response; } public async void send_request_async(Request request, Cancellable? cancellable = null) throws Error { diff --git a/src/engine/smtp/smtp-client-session.vala b/src/engine/smtp/smtp-client-session.vala index 9e60a624..33069afd 100644 --- a/src/engine/smtp/smtp-client-session.vala +++ b/src/engine/smtp/smtp-client-session.vala @@ -214,9 +214,9 @@ public class Geary.Smtp.ClientSession : BaseObject, Logging.Source { yield send_rcpts_async(addrlist, cancellable); // DATA - Geary.RFC822.Message email_copy = new Geary.RFC822.Message.without_bcc(email); - response = yield cx.send_data_async(email_copy.get_network_buffer(true), true, - cancellable); + response = yield cx.send_data_async( + email.get_rfc822_buffer(), cancellable + ); if (!response.code.is_success_completed()) response.throw_error("Unable to send message"); diff --git a/test/engine/rfc822/rfc822-message-test.vala b/test/engine/rfc822/rfc822-message-test.vala index cb4bde34..478d5633 100644 --- a/test/engine/rfc822/rfc822-message-test.vala +++ b/test/engine/rfc822/rfc822-message-test.vala @@ -59,9 +59,10 @@ This is the second line. add_test("get_searchable_recipients", get_searchable_recipients); add_test("from_composed_email", from_composed_email); add_test("from_composed_email_inline_attachments", from_composed_email_inline_attachments); - add_test("get_network_buffer", get_network_buffer); - add_test("get_network_buffer_dot_stuff", get_network_buffer_dot_stuff); - add_test("get_network_buffer_long_ascii_line", get_network_buffer_long_ascii_line); + add_test("get_rfc822_buffer", get_rfc822_buffer); + add_test("get_rfc822_buffer_dot_stuff", get_rfc822_buffer_dot_stuff); + add_test("get_rfc822_buffer_no_bcc", get_rfc822_buffer_no_bcc); + add_test("get_rfc822_buffer_long_ascii_line", get_rfc822_buffer_long_ascii_line); } public void basic_message_from_buffer() throws GLib.Error { @@ -210,13 +211,13 @@ This is the second line. assert_true(searchable.contains("Jane Doe BCC "), "Expected bcc address"); } - public void get_network_buffer() throws GLib.Error { + public void get_rfc822_buffer() throws GLib.Error { Message test = resource_to_message(BASIC_TEXT_PLAIN); - Memory.Buffer buffer = test.get_network_buffer(true); + Memory.Buffer buffer = test.get_rfc822_buffer(NONE); assert_true(buffer.to_string() == NETWORK_BUFFER_EXPECTED, "Network buffer differs"); } - public void get_network_buffer_dot_stuff() throws GLib.Error { + public void get_rfc822_buffer_dot_stuff() throws GLib.Error { RFC822.MailboxAddress to = new RFC822.MailboxAddress( "Test", "test@example.com" ); @@ -235,11 +236,42 @@ This is the second line. ); Geary.RFC822.Message message = message_from_composed_email.end(async_result()); - string message_data = message.get_network_buffer(true).to_string(); + string message_data = message.get_rfc822_buffer(SMTP_FORMAT).to_string(); assert_true(message_data.has_suffix("..newline\r\n..\r\n")); } - public void get_network_buffer_long_ascii_line() throws GLib.Error { + public void get_rfc822_buffer_no_bcc() throws GLib.Error { + RFC822.MailboxAddress to = new RFC822.MailboxAddress( + "Test", "test@example.com" + ); + RFC822.MailboxAddress bcc = new RFC822.MailboxAddress( + "BCC", "bcc@example.com" + ); + RFC822.MailboxAddress from = new RFC822.MailboxAddress( + "Sender", "sender@example.com" + ); + Geary.ComposedEmail composed = new Geary.ComposedEmail( + new GLib.DateTime.now_local(), + new Geary.RFC822.MailboxAddresses.single(from) + ).set_to( + new Geary.RFC822.MailboxAddresses.single(to) + ).set_bcc( + new Geary.RFC822.MailboxAddresses.single(bcc) + ); + composed.body_text = "\nbody\n"; + + this.message_from_composed_email.begin( + composed, + this.async_completion + ); + Geary.RFC822.Message message = message_from_composed_email.end(async_result()); + + string message_data = message.get_rfc822_buffer(SMTP_FORMAT).to_string(); + assert_true("To: Test \r\n" in message_data); + assert_false("bcc" in message_data.down()); + } + + public void get_rfc822_buffer_long_ascii_line() throws GLib.Error { RFC822.MailboxAddress to = new RFC822.MailboxAddress( "Test", "test@example.com" ); @@ -265,7 +297,7 @@ This is the second line. ); Geary.RFC822.Message message = message_from_composed_email.end(async_result()); - string message_data = message.get_network_buffer(true).to_string(); + string message_data = message.get_rfc822_buffer(SMTP_FORMAT).to_string(); foreach (var line in message_data.split("\n")) { assert_true(line.length < 1000, line); } From d5856bf72d458070801bfdbd420fbb946a1fe53a Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 18:33:08 +1000 Subject: [PATCH 26/41] org.gnome.Geary.json: Include missed fix from the yaml version --- org.gnome.Geary.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.gnome.Geary.json b/org.gnome.Geary.json index cccfac9b..f429bcac 100644 --- a/org.gnome.Geary.json +++ b/org.gnome.Geary.json @@ -91,7 +91,7 @@ "sources": [ { "type": "archive", - "url": "https://github.com/libical/libical/releases/download/v3.0.8/libical-3.0.7.tar.gz", + "url": "https://github.com/libical/libical/releases/download/v3.0.8/libical-3.0.8.tar.gz", "sha256": "09fecacaf75ba5a242159e3a9758a5446b5ce4d0ab684f98a7040864e1d1286f" } ], From d8f2c6b49877dc3a8c2f3330b9384a1c853512ae Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Wed, 6 May 2020 18:35:03 +1000 Subject: [PATCH 27/41] desktop/org.gnome.Geary.gschema.xml: Hide formatting toolbar by default Fixes #736 --- desktop/org.gnome.Geary.gschema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml index ac477a43..bbbadc36 100644 --- a/desktop/org.gnome.Geary.gschema.xml +++ b/desktop/org.gnome.Geary.gschema.xml @@ -46,7 +46,7 @@ - true + false

Show/hide formatting toolbar True if the formatting toolbar in the composer is shown. From 6a88b8121e8e2041236cb3a0e70e1dc4f45035ec Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Wed, 6 May 2020 11:29:31 +0000 Subject: [PATCH 28/41] Update required Vala version. Vala 0.46.2+ is needed to allow overridden virtual interfaces. Fix #825. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e135e562..3d7f77cf 100644 --- a/meson.build +++ b/meson.build @@ -50,7 +50,7 @@ valac = meson.get_compiler('vala') # Required libraries and other dependencies # -target_vala = '0.42' +target_vala = '0.46.2' target_glib = '2.60.4' target_gtk = '3.24.7' target_webkit = '2.26' From 751cf0860fc50fedefea9b1e9dfcbde25f8ffdde Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 6 May 2020 18:02:21 -0400 Subject: [PATCH 29/41] help-overlay: reduce the length of the header even further --- ui/gtk/help-overlay.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index 7dfb5b85..c0c66461 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -262,7 +262,7 @@ True Single-key shortcuts (if enabled in Preferences) + context="shortcut window">Single-key shortcuts (if enabled) True From a4a99124ea33b5a2b67888c99864cd04da4f4d62 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Thu, 7 May 2020 05:51:23 +0000 Subject: [PATCH 30/41] Update Ukrainian translation --- po/uk.po | 96 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/po/uk.po b/po/uk.po index 120e659b..03d2eea8 100644 --- a/po/uk.po +++ b/po/uk.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: geary-0.4.1\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-05-03 07:37+0000\n" -"PO-Revision-Date: 2020-05-03 14:57+0300\n" +"POT-Creation-Date: 2020-05-07 01:10+0000\n" +"PO-Revision-Date: 2020-05-07 08:50+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -2811,7 +2811,6 @@ msgid "Add an account" msgstr "Додати обліковий запис" #: ui/accounts_editor_add_pane.ui:53 -#| msgid "Create" msgid "_Create" msgstr "С_творити" @@ -3421,7 +3420,7 @@ msgstr "мітка" msgid "Conversation Shortcuts" msgstr "Скорочення панелі спілкування" -#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:355 +#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:377 msgctxt "shortcut window" msgid "Actions" msgstr "Дії" @@ -3436,37 +3435,37 @@ msgctxt "shortcut window" msgid "Reply to sender" msgstr "Відповісти відправнику" -#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:269 +#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:281 msgctxt "shortcut window" msgid "Reply to all" msgstr "Відповісти всім" -#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:276 +#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:288 msgctxt "shortcut window" msgid "Forward" msgstr "Переслати" -#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:283 +#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:295 msgctxt "shortcut window" msgid "Un-mark/mark read" msgstr "Позначити або зняти позначення як прочитаного" -#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:290 +#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:302 msgctxt "shortcut window" msgid "Mark/un-mark starred" msgstr "Позначити або зняти позначення зірками" -#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:297 +#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:309 msgctxt "shortcut window" msgid "Archive conversations" msgstr "Архівувати спілкування" -#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:304 +#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:326 msgctxt "shortcut window" msgid "Move conversations" msgstr "Пересунути спілкування" -#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:311 +#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:333 msgctxt "shortcut window" msgid "Label conversations" msgstr "Позначити спілкування" @@ -3476,12 +3475,12 @@ msgctxt "shortcut window" msgid "Trash conversations" msgstr "Пересунути спілкування до смітника" -#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:318 +#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:340 msgctxt "shortcut window" msgid "Junk conversations" msgstr "Пересунути спілкування до спаму" -#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:325 +#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:347 msgctxt "shortcut window" msgid "Delete conversations" msgstr "Вилучити спілкування" @@ -3496,7 +3495,7 @@ msgctxt "shortcut window" msgid "Search for conversations" msgstr "Шукати спілкування" -#: ui/gtk/help-overlay.ui:115 +#: ui/gtk/help-overlay.ui:115 ui/gtk/help-overlay.ui:354 msgctxt "shortcut window" msgid "Find in current conversation" msgstr "Знайти у поточному спілкуванні" @@ -3536,7 +3535,7 @@ msgctxt "shortcut window" msgid "Reset zoom" msgstr "Відновити масштаб" -#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:375 +#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:397 msgctxt "shortcut window" msgid "General" msgstr "Загальні" @@ -3586,121 +3585,124 @@ msgctxt "shortcut window" msgid "Focus next/previous message" msgstr "Фокусувати наступне або попереднє повідомлення" -#: ui/gtk/help-overlay.ui:258 -msgctxt "shortcut window" -msgid "Single-key shortcuts" +#: ui/gtk/help-overlay.ui:260 +#| msgctxt "shortcut window" +#| msgid "Single-key shortcuts" +msgid "Single-key Shortcuts" msgstr "Одноклавішні скорочення" -#: ui/gtk/help-overlay.ui:262 +#: ui/gtk/help-overlay.ui:265 +#| msgctxt "shortcut window" +#| msgid "Single-key shortcuts" +msgctxt "shortcut window" +msgid "Single-key shortcuts (if enabled)" +msgstr "Одноклавішні скорочення (якщо увімкнено)" + +#: ui/gtk/help-overlay.ui:274 msgctxt "shortcut window" msgid "Reply to sender " msgstr "Відповісти відправнику" -#: ui/gtk/help-overlay.ui:332 -msgctxt "shortcut window" -msgid "Find in current conversations" -msgstr "Знайти у поточних спілкуваннях" - -#: ui/gtk/help-overlay.ui:339 +#: ui/gtk/help-overlay.ui:361 msgctxt "shortcut window" msgid "Select next/previous conversations" msgstr "Вибрати наступні або попередні спілкування" -#: ui/gtk/help-overlay.ui:351 +#: ui/gtk/help-overlay.ui:373 msgid "Composer Shortcuts" msgstr "Скорочення вікна редактора" -#: ui/gtk/help-overlay.ui:359 +#: ui/gtk/help-overlay.ui:381 msgctxt "shortcut window" msgid "Send" msgstr "Надіслати" -#: ui/gtk/help-overlay.ui:366 +#: ui/gtk/help-overlay.ui:388 msgctxt "shortcut window" msgid "Add attachment" msgstr "Додати долучення" -#: ui/gtk/help-overlay.ui:379 +#: ui/gtk/help-overlay.ui:401 msgctxt "shortcut window" msgid "Close composer window" msgstr "Закрити вікно редактора" -#: ui/gtk/help-overlay.ui:386 +#: ui/gtk/help-overlay.ui:408 msgctxt "shortcut window" msgid "Detach composer window" msgstr "Від'єднати вікно редактора" -#: ui/gtk/help-overlay.ui:393 +#: ui/gtk/help-overlay.ui:415 msgctxt "shortcut window" msgid "Editing" msgstr "Редагування" -#: ui/gtk/help-overlay.ui:398 +#: ui/gtk/help-overlay.ui:420 msgctxt "shortcut window" msgid "Move selection to the clipboard" msgstr "Пересунути позначене до буфера обміну даними" -#: ui/gtk/help-overlay.ui:405 +#: ui/gtk/help-overlay.ui:427 msgctxt "shortcut window" msgid "Copy selection to clipboard" msgstr "Копіювати позначений фрагмент до буфера обміну даними" -#: ui/gtk/help-overlay.ui:412 +#: ui/gtk/help-overlay.ui:434 msgctxt "shortcut window" msgid "Paste from the clipboard" msgstr "Вставити з буфера обміну даними" -#: ui/gtk/help-overlay.ui:419 +#: ui/gtk/help-overlay.ui:441 msgctxt "shortcut window" msgid "Quote text" msgstr "Цитувати текст" -#: ui/gtk/help-overlay.ui:426 +#: ui/gtk/help-overlay.ui:448 msgctxt "shortcut window" msgid "Unquote text" msgstr "Скасувати цитування тексту" -#: ui/gtk/help-overlay.ui:435 +#: ui/gtk/help-overlay.ui:457 msgctxt "shortcut window" msgid "Rich text editing" msgstr "Редагування з форматуванням" -#: ui/gtk/help-overlay.ui:439 +#: ui/gtk/help-overlay.ui:461 msgctxt "shortcut window" msgid "Paste without formatting" msgstr "Вставити без форматування" -#: ui/gtk/help-overlay.ui:446 +#: ui/gtk/help-overlay.ui:468 msgctxt "shortcut window" msgid "Bold text" msgstr "Зробити текст напівжирним" -#: ui/gtk/help-overlay.ui:453 +#: ui/gtk/help-overlay.ui:475 msgctxt "shortcut window" msgid "Italicize text" msgstr "Зробити текст курсивним" -#: ui/gtk/help-overlay.ui:460 +#: ui/gtk/help-overlay.ui:482 msgctxt "shortcut window" msgid "Underline text" msgstr "Підкреслити текст" -#: ui/gtk/help-overlay.ui:467 +#: ui/gtk/help-overlay.ui:489 msgctxt "shortcut window" msgid "Strike text" msgstr "Закреслити текст" -#: ui/gtk/help-overlay.ui:474 +#: ui/gtk/help-overlay.ui:496 msgctxt "shortcut window" msgid "Remove formatting" msgstr "Вилучити форматування" -#: ui/gtk/help-overlay.ui:481 +#: ui/gtk/help-overlay.ui:503 msgctxt "shortcut window" msgid "Insert an image" msgstr "Вставити зображення" -#: ui/gtk/help-overlay.ui:488 +#: ui/gtk/help-overlay.ui:510 msgctxt "shortcut window" msgid "Insert a link" msgstr "Вставити посилання" @@ -3769,3 +3771,7 @@ msgstr "_Засвідчення" #: ui/upgrade_dialog.glade:60 msgid "Geary update in progress…" msgstr "Виконується оновлення…" + +#~ msgctxt "shortcut window" +#~ msgid "Find in current conversations" +#~ msgstr "Знайти у поточних спілкуваннях" From b1d3272d491cb03be2d37f2abd85d7476ceb392c Mon Sep 17 00:00:00 2001 From: sicklylife Date: Thu, 7 May 2020 12:24:28 +0000 Subject: [PATCH 31/41] Update Japanese translation --- po/ja.po | 519 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 304 insertions(+), 215 deletions(-) diff --git a/po/ja.po b/po/ja.po index c9ed1f34..a20957bb 100644 --- a/po/ja.po +++ b/po/ja.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: geary-0.4.1\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-03-31 17:44+0000\n" +"POT-Creation-Date: 2020-05-07 01:10+0000\n" "PO-Revision-Date: 2020-04-01 02:58+0900\n" "Last-Translator: sicklylife \n" "Language-Team: Japanese (Japan) (https://l10n.gnome.org/module/geary/)\n" @@ -610,12 +610,12 @@ msgid_plural "%d days back" msgstr[0] "%d日前" #: src/client/accounts/accounts-editor-list-pane.vala:255 -#: src/client/application/application-main-window.vala:2060 +#: src/client/application/application-main-window.vala:2027 msgid "Undo" msgstr "元に戻す" #: src/client/accounts/accounts-editor-list-pane.vala:264 -#: src/client/application/application-main-window.vala:2043 +#: src/client/application/application-main-window.vala:2010 msgid "Redo" msgstr "やり直す" @@ -686,23 +686,23 @@ msgstr "サービスプロバイダー" #. Translators: This label describes what form of transport #. security (TLS, StartTLS, etc) used by an account's IMAP or SMTP #. service. -#: src/client/accounts/accounts-editor-row.vala:468 +#: src/client/accounts/accounts-editor-row.vala:469 msgid "Connection security" msgstr "接続のセキュリティ" #. Translators: Label used when no auth scheme is used #. by an account's IMAP or SMTP service. -#: src/client/accounts/accounts-editor-row.vala:479 +#: src/client/accounts/accounts-editor-row.vala:480 #: src/client/accounts/accounts-editor-servers-pane.vala:755 #: src/client/accounts/accounts-editor-servers-pane.vala:970 msgid "None" msgstr "なし" -#: src/client/accounts/accounts-editor-row.vala:486 +#: src/client/accounts/accounts-editor-row.vala:487 msgid "StartTLS" msgstr "StartTLS" -#: src/client/accounts/accounts-editor-row.vala:493 +#: src/client/accounts/accounts-editor-row.vala:494 msgid "TLS" msgstr "TLS" @@ -710,7 +710,7 @@ msgstr "TLS" #. credentials (none, use IMAP, custom) when adding a new #. account #. Translators: An info bar button label -#: src/client/accounts/accounts-editor-row.vala:534 +#: src/client/accounts/accounts-editor-row.vala:535 #: src/client/application/application-main-window.vala:544 msgid "Login" msgstr "ログイン" @@ -718,21 +718,21 @@ msgstr "ログイン" #. Translators: ComboBox value for source of SMTP #. authentication credentials (none) when adding a new #. account -#: src/client/accounts/accounts-editor-row.vala:541 +#: src/client/accounts/accounts-editor-row.vala:542 msgid "No login needed" msgstr "ログイン不要" #. Translators: ComboBox value for source of SMTP #. authentication credentials (use IMAP) when adding a new #. account -#: src/client/accounts/accounts-editor-row.vala:549 +#: src/client/accounts/accounts-editor-row.vala:550 msgid "Use same login as receiving" msgstr "受信と同じ情報を使う" #. Translators: ComboBox value for source of SMTP #. authentication credentials (custom) when adding a new #. account -#: src/client/accounts/accounts-editor-row.vala:557 +#: src/client/accounts/accounts-editor-row.vala:558 msgid "Use a different login" msgstr "他の情報を使う" @@ -820,137 +820,134 @@ msgid "Visit the Geary web site" msgstr "Geary のウェブサイト" #. / Command line option -#: src/client/application/application-client.vala:97 +#: src/client/application/application-client.vala:96 msgid "Print debug logging" msgstr "デバッグログを表示する" #. / Command line option -#: src/client/application/application-client.vala:100 +#: src/client/application/application-client.vala:99 msgid "Start with the main window hidden (deprecated)" msgstr "メインウィンドウを隠して起動する (非推奨)" #. / Command line option -#: src/client/application/application-client.vala:103 +#: src/client/application/application-client.vala:102 msgid "Enable WebKitGTK Inspector in web views" msgstr "" #. / Command line option -#: src/client/application/application-client.vala:106 +#: src/client/application/application-client.vala:105 msgid "Log conversation monitoring" msgstr "スレッドのモニタリングを記録する" #. / Command line option -#: src/client/application/application-client.vala:109 +#: src/client/application/application-client.vala:108 msgid "Log IMAP network deserialization" msgstr "IMAP ネットワークのデシリアライズを記録する" #. / Command line option. "Normalization" can also be called #. / "synchronization". -#: src/client/application/application-client.vala:113 +#: src/client/application/application-client.vala:112 msgid "Log folder normalization" msgstr "フォルダーの同期を記録する" #. / Command line option -#: src/client/application/application-client.vala:116 -msgid "Log network activity" +#: src/client/application/application-client.vala:115 +#, fuzzy +#| msgid "Log network activity" +msgid "Log IMAP network activity" msgstr "ネットワークのアクティビティを記録する" -#. / Command line option -#: src/client/application/application-client.vala:119 -msgid "Log periodic activity" -msgstr "定期的なアクティビティを記録する" - #. / Command line option. The IMAP replay queue is how changes #. / on the server are replicated on the client. It could #. / also be called the IMAP events queue. -#: src/client/application/application-client.vala:124 +#: src/client/application/application-client.vala:120 msgid "Log IMAP replay queue" msgstr "IMAP のイベントキューを記録する" -#. / Command line option. Serialization is how commands and -#. / responses are converted into a stream of bytes for -#. / network transmission -#: src/client/application/application-client.vala:129 -msgid "Log IMAP network serialization" -msgstr "IMAP ネットワークのストリームを記録する" +#. / Command line option +#: src/client/application/application-client.vala:123 +#, fuzzy +#| msgid "Log network activity" +msgid "Log SMTP network activity" +msgstr "ネットワークのアクティビティを記録する" #. / Command line option -#: src/client/application/application-client.vala:132 +#: src/client/application/application-client.vala:126 msgid "Log database queries (generates lots of messages)" msgstr "データベースのクエリを記録する (多くのメッセージを生成します)" #. / Command line option -#: src/client/application/application-client.vala:135 +#: src/client/application/application-client.vala:129 msgid "Perform a graceful quit" msgstr "正常に終了する" -#: src/client/application/application-client.vala:137 +#: src/client/application/application-client.vala:131 msgid "Open a new window" msgstr "新しいウィンドウを開く" #. / Command line option -#: src/client/application/application-client.vala:140 +#: src/client/application/application-client.vala:134 msgid "Revoke all pinned TLS server certificates" msgstr "ピン留めされた TLS サーバー証明書をすべて失効させる" #. / Command line option -#: src/client/application/application-client.vala:143 +#: src/client/application/application-client.vala:137 msgid "Display program version" msgstr "プログラムのバージョンを表示する" #. / Application runtime information label -#: src/client/application/application-client.vala:267 +#: src/client/application/application-client.vala:261 msgid "Geary version" msgstr "Geary のバージョン" #. / Application runtime information label -#: src/client/application/application-client.vala:269 +#: src/client/application/application-client.vala:263 msgid "Geary revision" msgstr "Geary のリビジョン" #. / Application runtime information label -#: src/client/application/application-client.vala:271 +#: src/client/application/application-client.vala:265 msgid "GTK version" msgstr "GTK のバージョン" #. / Applciation runtime information label -#: src/client/application/application-client.vala:278 +#: src/client/application/application-client.vala:272 msgid "GLib version" msgstr "GLib のバージョン" #. / Application runtime information label -#: src/client/application/application-client.vala:285 +#: src/client/application/application-client.vala:279 msgid "WebKitGTK version" msgstr "WebKitGTK のバージョン" #. / Application runtime information label -#: src/client/application/application-client.vala:292 +#: src/client/application/application-client.vala:286 msgid "Desktop environment" msgstr "デスクトップ環境" #. Translators: This is the file type displayed for #. attachments with unknown file types. -#: src/client/application/application-client.vala:294 +#: src/client/application/application-client.vala:288 #: src/client/components/components-attachment-pane.vala:91 msgid "Unknown" msgstr "不明" #. / Application runtime information label -#: src/client/application/application-client.vala:324 +#: src/client/application/application-client.vala:318 msgid "Distribution name" msgstr "ディストリビューション名" #. / Application runtime information label -#: src/client/application/application-client.vala:329 +#: src/client/application/application-client.vala:323 msgid "Distribution release" msgstr "" #. / Application runtime information label -#: src/client/application/application-client.vala:337 +#: src/client/application/application-client.vala:331 msgid "Installation prefix" msgstr "" -#: src/client/application/application-client.vala:590 +#: src/client/application/application-client.vala:584 #, c-format msgid "About %s" msgstr "%s について" @@ -958,7 +955,7 @@ msgstr "%s について" #. Translators: add your name and email address to receive #. credit in the About dialog For example: Yamada Taro #. -#: src/client/application/application-client.vala:594 +#: src/client/application/application-client.vala:588 msgid "translator-credits" msgstr "" "masami chikahiro \n" @@ -969,36 +966,36 @@ msgstr "" #. / Warning printed to the console when a deprecated #. / command line option is used. -#: src/client/application/application-client.vala:941 +#: src/client/application/application-client.vala:1049 msgid "The `--hidden` option is deprecated and will be removed in the future." msgstr "`--hidden` オプションは非推奨です。将来的に削除されます。" #. / Command line warning, string substitution #. / is the given argument -#: src/client/application/application-client.vala:974 +#: src/client/application/application-client.vala:1082 #, c-format msgid "Unrecognised program argument: “%s”" msgstr "不明な引数です: “%s”" #. / Notification title. -#: src/client/application/application-controller.vala:455 +#: src/client/application/application-controller.vala:485 #, c-format msgid "A problem occurred sending email for %s" msgstr "%s のメール送信時に問題が発生しました" #. / Notification body -#: src/client/application/application-controller.vala:459 +#: src/client/application/application-controller.vala:489 msgid "Email will not be sent until re-connected" msgstr "再接続するまでメールを送信しません" #. / Translators: Label for in-app notification -#: src/client/application/application-controller.vala:565 +#: src/client/application/application-controller.vala:588 msgid "Conversation marked" msgid_plural "Conversations marked" msgstr[0] "スレッドをマークしました" #. / Translators: Label for in-app notification -#: src/client/application/application-controller.vala:571 +#: src/client/application/application-controller.vala:594 msgid "Conversation un-marked" msgid_plural "Conversations un-marked" msgstr[0] "スレッドのマークを外しました" @@ -1006,8 +1003,8 @@ msgstr[0] "スレッドのマークを外しました" #. / Translators: Label for in-app #. / notification. String substitution is the name #. / of the destination folder. -#: src/client/application/application-controller.vala:597 -#: src/client/application/application-controller.vala:681 +#: src/client/application/application-controller.vala:620 +#: src/client/application/application-controller.vala:704 #, c-format msgid "Conversation moved to %s" msgid_plural "Conversations moved to %s" @@ -1018,29 +1015,29 @@ msgstr[0] "スレッドを %s へ移動しました" #. / of the source folder. #. / Translators: Label for in-app notification. String #. / substitution is the name of the destination folder. -#: src/client/application/application-controller.vala:605 -#: src/client/application/application-controller.vala:627 +#: src/client/application/application-controller.vala:628 +#: src/client/application/application-controller.vala:650 #, c-format msgid "Conversation restored to %s" msgid_plural "Conversations restored to %s" msgstr[0] "スレッドを %s へ復元しました" #. / Translators: Label for in-app notification. -#: src/client/application/application-controller.vala:648 +#: src/client/application/application-controller.vala:671 msgid "Conversation archived" msgid_plural "Conversations archived" msgstr[0] "スレッドをアーカイブへ移動しました" #. / Translators: Label for in-app notification. String #. / substitution is the name of the destination folder. -#: src/client/application/application-controller.vala:704 +#: src/client/application/application-controller.vala:727 #, c-format msgid "Message restored to %s" msgid_plural "Messages restored to %s" msgstr[0] "メッセージを %s へ復元しました" #. / Translators: Label for in-app notification. -#: src/client/application/application-controller.vala:725 +#: src/client/application/application-controller.vala:748 msgid "Message archived" msgid_plural "Messages archived" msgstr[0] "メッセージをアーカイブへ移動しました" @@ -1048,7 +1045,7 @@ msgstr[0] "メッセージをアーカイブへ移動しました" #. / Translators: Label for in-app #. / notification. String substitution is the name #. / of the destination folder. -#: src/client/application/application-controller.vala:760 +#: src/client/application/application-controller.vala:783 #, c-format msgid "Message moved to %s" msgid_plural "Messages moved to %s" @@ -1057,7 +1054,7 @@ msgstr[0] "メッセージを %s へ移動しました" #. / Translators: Label for in-app #. / notification. String substitution is the name #. / of the destination folder. -#: src/client/application/application-controller.vala:788 +#: src/client/application/application-controller.vala:811 #, c-format msgid "Conversation labelled as %s" msgid_plural "Conversations labelled as %s" @@ -1066,18 +1063,18 @@ msgstr[0] "スレッドを %s としてラベル付けしました" #. / Translators: Label for in-app #. / notification. String substitution is the name #. / of the destination folder. -#: src/client/application/application-controller.vala:796 +#: src/client/application/application-controller.vala:819 #, c-format msgid "Conversation un-labelled as %s" msgid_plural "Conversations un-labelled as %s" msgstr[0] "スレッドのラベル %s を外しました" -#: src/client/application/application-controller.vala:1215 +#: src/client/application/application-controller.vala:1305 #, c-format msgid "Unable to open the database for %s" msgstr "%s のデータベースを開けません" -#: src/client/application/application-controller.vala:1216 +#: src/client/application/application-controller.vala:1306 #, c-format msgid "" "There was an error opening the local mail database for this account. This is " @@ -1101,20 +1098,20 @@ msgstr "" "データベースを再構築すると、すべてのローカルメールと添付ファイルが破棄されま" "す。サーバー上のメールは影響を受けません。" -#: src/client/application/application-controller.vala:1218 +#: src/client/application/application-controller.vala:1308 msgid "_Rebuild" msgstr "再構築(_R)" -#: src/client/application/application-controller.vala:1218 +#: src/client/application/application-controller.vala:1308 msgid "E_xit" msgstr "終了(_X)" -#: src/client/application/application-controller.vala:1228 +#: src/client/application/application-controller.vala:1318 #, c-format msgid "Unable to rebuild database for “%s”" msgstr "“%s”のデータベースを再構築できません" -#: src/client/application/application-controller.vala:1229 +#: src/client/application/application-controller.vala:1319 #, c-format msgid "" "Error during rebuild:\n" @@ -1127,34 +1124,34 @@ msgstr "" #. / Translators: The label for an in-app notification. The #. / string substitution is a list of recipients of the email. -#: src/client/application/application-controller.vala:1468 +#: src/client/application/application-controller.vala:1449 #, c-format msgid "Email sent to %s" msgstr "%s へメールを送信しました" #. / Translators: The label for an in-app notification. The #. / string substitution is a list of recipients of the email. -#: src/client/application/application-controller.vala:2564 +#: src/client/application/application-controller.vala:2448 #, c-format msgid "Email to %s queued for delivery" msgstr "%s へのメールが送信待機中です" #. / Translators: The label for an in-app notification. The #. / string substitution is a list of recipients of the email. -#: src/client/application/application-controller.vala:2628 +#: src/client/application/application-controller.vala:2512 #, c-format msgid "Email to %s saved" msgstr "%s へのメールを保存しました" #. / Translators: A label for an in-app notification. -#: src/client/application/application-controller.vala:2643 -#: src/client/application/application-controller.vala:2701 +#: src/client/application/application-controller.vala:2527 +#: src/client/application/application-controller.vala:2585 msgid "Composer could not be restored" msgstr "" #. / Translators: The label for an in-app notification. The #. / string substitution is a list of recipients of the email. -#: src/client/application/application-controller.vala:2686 +#: src/client/application/application-controller.vala:2570 #, c-format msgid "Email to %s discarded" msgstr "%s へのメールを破棄しました" @@ -1212,46 +1209,50 @@ msgstr "接続のセキュリティに関する詳細を確認" msgid "%s — %s" msgstr "%s — %s" -#: src/client/application/application-main-window.vala:991 +#. Translators: The name of the folder group containing +#. folders created by people (as opposed to special-use +#. folders) +#: src/client/application/application-main-window.vala:972 +#: src/client/folder-list/folder-list-account-branch.vala:43 msgid "Labels" msgstr "ラベル" -#: src/client/application/application-main-window.vala:1290 +#: src/client/application/application-main-window.vala:1261 #, c-format msgid "Empty all email from your %s folder?" msgstr "%s フォルダーのすべてのメールを空にしますか?" -#: src/client/application/application-main-window.vala:1291 +#: src/client/application/application-main-window.vala:1262 msgid "This removes the email from Geary and your email server." msgstr "メールを Geary とメールサーバーから削除します。" -#: src/client/application/application-main-window.vala:1292 +#: src/client/application/application-main-window.vala:1263 msgid "This cannot be undone." msgstr "これは元に戻すことができません。" -#: src/client/application/application-main-window.vala:1293 +#: src/client/application/application-main-window.vala:1264 #, c-format msgid "Empty %s" msgstr "%s を空にする" #. / Translators: Primary text for a confirmation dialog -#: src/client/application/application-main-window.vala:1350 +#: src/client/application/application-main-window.vala:1321 msgid "Do you want to permanently delete this conversation?" msgid_plural "Do you want to permanently delete these conversations?" msgstr[0] "このスレッドを完全に削除しますか?" -#: src/client/application/application-main-window.vala:1355 -#: src/client/application/application-main-window.vala:1370 +#: src/client/application/application-main-window.vala:1326 +#: src/client/application/application-main-window.vala:1341 msgid "Delete" msgstr "削除" #. / Translators: Primary text for a confirmation dialog -#: src/client/application/application-main-window.vala:1365 +#: src/client/application/application-main-window.vala:1336 msgid "Do you want to permanently delete this message?" msgid_plural "Do you want to permanently delete these messages?" msgstr[0] "このメッセージを完全に削除しますか?" -#: src/client/application/application-main-window.vala:1698 +#: src/client/application/application-main-window.vala:1659 #, c-format msgid "%s (%d)" msgstr "%s (%d)" @@ -1262,7 +1263,7 @@ msgstr "%s (%d)" #. Document (100.9MB) #. / In the composer, the filename followed by its filesize, i.e. "notes.txt (1.12KB)" #: src/client/components/components-attachment-pane.vala:107 -#: src/client/composer/composer-widget.vala:1839 +#: src/client/composer/composer-widget.vala:1918 #, c-format msgid "%s (%s)" msgstr "%s (%s)" @@ -1283,13 +1284,13 @@ msgstr "" msgid "Don’t _ask me again" msgstr "次回から表示しない(_A)" -#: src/client/components/components-inspector.vala:72 +#: src/client/components/components-inspector.vala:78 msgid "Inspector" msgstr "" #. / Translators: Title for Inspector logs pane #. / Translators: Title for problem report dialog logs pane -#: src/client/components/components-inspector.vala:87 +#: src/client/components/components-inspector.vala:93 #: src/client/dialogs/dialogs-problem-details-dialog.vala:102 msgid "Logs" msgstr "ログ" @@ -1297,21 +1298,21 @@ msgstr "ログ" #. / Translators: Title for Inspector system system information pane #. / Translators: Title for problem report system information #. / pane -#: src/client/components/components-inspector.vala:91 +#: src/client/components/components-inspector.vala:97 #: src/client/dialogs/dialogs-problem-details-dialog.vala:105 msgid "System" msgstr "システム" #. Button label for saving problem report information -#: src/client/components/components-inspector.vala:208 -#: src/client/components/components-inspector.vala:211 +#: src/client/components/components-inspector.vala:226 +#: src/client/components/components-inspector.vala:229 #: src/client/dialogs/dialogs-problem-details-dialog.vala:221 #: src/client/dialogs/dialogs-problem-details-dialog.vala:224 #: ui/problem-details-dialog.ui:42 msgid "Save As" msgstr "名前を付けて保存" -#: src/client/components/components-inspector.vala:212 +#: src/client/components/components-inspector.vala:230 #: src/client/dialogs/dialogs-problem-details-dialog.vala:225 #: ui/accounts_editor_servers_pane.ui:17 msgid "Cancel" @@ -1360,7 +1361,7 @@ msgid "Preferences" msgstr "設定" #. / Translators: Preferences page title -#: src/client/components/components-preferences-window.vala:179 +#: src/client/components/components-preferences-window.vala:180 msgid "Plugins" msgstr "プラグイン" @@ -1596,23 +1597,23 @@ msgid "Invalid email address" msgstr "無効なメールアドレス" #. / Translators: Title for an empty composer window -#: src/client/composer/composer-widget.vala:30 +#: src/client/composer/composer-widget.vala:31 msgid "New Message" msgstr "新規メッセージ" -#: src/client/composer/composer-widget.vala:217 +#: src/client/composer/composer-widget.vala:235 msgid "Saved" msgstr "保存済み" -#: src/client/composer/composer-widget.vala:218 +#: src/client/composer/composer-widget.vala:236 msgid "Saving" msgstr "保存中" -#: src/client/composer/composer-widget.vala:219 +#: src/client/composer/composer-widget.vala:237 msgid "Error saving" msgstr "保存エラー" -#: src/client/composer/composer-widget.vala:220 +#: src/client/composer/composer-widget.vala:238 msgid "Press Backspace to delete quote" msgstr "Backspace を押すと引用を削除できます" @@ -1621,7 +1622,7 @@ msgstr "Backspace を押すと引用を削除できます" #. checking, include all variants of each word. No spaces are #. allowed. The words will be converted to lower case based on #. locale and English versions included automatically. -#: src/client/composer/composer-widget.vala:236 +#: src/client/composer/composer-widget.vala:254 msgid "" "attach|attaching|attaches|attachment|attachments|attached|enclose|enclosed|" "enclosing|encloses|enclosure|enclosures" @@ -1630,90 +1631,90 @@ msgstr "" #. Translators: This dialog text is displayed to the #. user when closing a composer where the options are #. Keep, Discard or Cancel. -#: src/client/composer/composer-widget.vala:843 +#: src/client/composer/composer-widget.vala:903 msgid "Do you want to keep or discard this draft message?" msgstr "この下書きメッセージを保持または破棄しますか?" #. Translators: This dialog text is displayed to the #. user when closing a composer where the options are #. only Discard or Cancel. -#: src/client/composer/composer-widget.vala:869 +#: src/client/composer/composer-widget.vala:929 msgid "Do you want to discard this draft message?" msgstr "この下書きメッセージを破棄しますか?" -#: src/client/composer/composer-widget.vala:1508 +#: src/client/composer/composer-widget.vala:1575 msgid "Send message with an empty subject and body?" msgstr "メッセージを件名と本文なしで送信しますか?" -#: src/client/composer/composer-widget.vala:1510 +#: src/client/composer/composer-widget.vala:1577 msgid "Send message with an empty subject?" msgstr "メッセージを件名なしで送信しますか?" -#: src/client/composer/composer-widget.vala:1512 +#: src/client/composer/composer-widget.vala:1579 msgid "Send message with an empty body?" msgstr "メッセージを本文なしで送信しますか?" -#: src/client/composer/composer-widget.vala:1521 +#: src/client/composer/composer-widget.vala:1588 msgid "Send message without an attachment?" msgstr "メッセージを添付ファイルなしで送信しますか?" -#: src/client/composer/composer-widget.vala:1825 +#: src/client/composer/composer-widget.vala:1904 #, c-format msgid "“%s” already attached for delivery." msgstr "“%s”はすでに添付されています。" -#: src/client/composer/composer-widget.vala:1861 -#: src/client/composer/composer-widget.vala:1911 +#: src/client/composer/composer-widget.vala:1940 +#: src/client/composer/composer-widget.vala:1990 #, c-format msgid "“%s” is an empty file." msgstr "“%s”は空ファイルです。" -#: src/client/composer/composer-widget.vala:1899 +#: src/client/composer/composer-widget.vala:1978 #, c-format msgid "“%s” could not be found." msgstr "“%s”が見つかりませんでした。" -#: src/client/composer/composer-widget.vala:1905 +#: src/client/composer/composer-widget.vala:1984 #, c-format msgid "“%s” is a folder." msgstr "“%s”はフォルダーです。" -#: src/client/composer/composer-widget.vala:1924 +#: src/client/composer/composer-widget.vala:2003 #, c-format msgid "“%s” could not be opened for reading." msgstr "“%s”を読み取り用に開けませんでした。" -#: src/client/composer/composer-widget.vala:1932 +#: src/client/composer/composer-widget.vala:2011 msgid "Cannot add attachment" msgstr "添付できません" #. Translators: Human-readable version of the RFC 822 To header -#: src/client/composer/composer-widget.vala:1989 +#: src/client/composer/composer-widget.vala:2071 #: src/client/conversation-viewer/conversation-email.vala:542 -#: src/client/util/util-email.vala:235 ui/conversation-message.ui:312 +#: src/client/util/util-email.vala:236 ui/conversation-message.ui:312 msgid "To:" msgstr "宛先:" #. Translators: Human-readable version of the RFC 822 CC header -#: src/client/composer/composer-widget.vala:1995 +#: src/client/composer/composer-widget.vala:2077 #: src/client/conversation-viewer/conversation-email.vala:547 -#: src/client/util/util-email.vala:240 ui/conversation-message.ui:357 +#: src/client/util/util-email.vala:241 ui/conversation-message.ui:357 msgid "Cc:" msgstr "Cc:" #. Translators: Human-readable version of the RFC 822 BCC header -#: src/client/composer/composer-widget.vala:2001 +#: src/client/composer/composer-widget.vala:2083 #: src/client/conversation-viewer/conversation-email.vala:552 #: ui/conversation-message.ui:402 msgid "Bcc:" msgstr "Bcc:" #. Translators: Human-readable version of the RFC 822 Reply-To header -#: src/client/composer/composer-widget.vala:2007 +#: src/client/composer/composer-widget.vala:2089 msgid "Reply-To: " msgstr "Reply-To: " -#: src/client/composer/composer-widget.vala:2259 +#: src/client/composer/composer-widget.vala:2341 msgid "Select Color" msgstr "色を選択" @@ -1722,14 +1723,14 @@ msgstr "色を選択" #. printf argument will be the alternate email address, #. and the second will be the account's primary email #. address. -#: src/client/composer/composer-widget.vala:2445 +#: src/client/composer/composer-widget.vala:2530 #, c-format msgid "%1$s via %2$s" msgstr "%1$s (%2$s を通して使用)" #. Translators: This is the name of the file chooser filter #. when inserting an image in the composer. -#: src/client/composer/composer-widget.vala:2802 +#: src/client/composer/composer-widget.vala:2887 msgid "Images" msgstr "画像" @@ -1799,19 +1800,19 @@ msgstr "自分" #. Translators: Human-readable version of the RFC 822 From header #: src/client/conversation-viewer/conversation-email.vala:537 -#: src/client/util/util-email.vala:226 +#: src/client/util/util-email.vala:227 msgid "From:" msgstr "差出人:" #. Translators: Human-readable version of the RFC 822 Date header #: src/client/conversation-viewer/conversation-email.vala:557 -#: src/client/util/util-email.vala:231 +#: src/client/util/util-email.vala:232 msgid "Date:" msgstr "日時:" #. Translators: Human-readable version of the RFC 822 Subject header #: src/client/conversation-viewer/conversation-email.vala:567 -#: src/client/util/util-email.vala:229 +#: src/client/util/util-email.vala:230 msgid "Subject:" msgstr "件名:" @@ -1857,22 +1858,22 @@ msgid "Image" msgstr "画像" #. Translators: Info bar status message -#: src/client/conversation-viewer/conversation-message.vala:1304 +#: src/client/conversation-viewer/conversation-message.vala:1305 msgid "Remote images not shown" msgstr "リモート画像は表示しません" #. Translators: Info bar description -#: src/client/conversation-viewer/conversation-message.vala:1306 +#: src/client/conversation-viewer/conversation-message.vala:1307 msgid "Only show remote images from senders you trust." msgstr "信頼できる送信者のリモート画像のみ表示するようにしてください。" #. Translators: Info bar button label -#: src/client/conversation-viewer/conversation-message.vala:1310 +#: src/client/conversation-viewer/conversation-message.vala:1311 msgid "Show" msgstr "表示" #. Translators: Info bar button label -#: src/client/conversation-viewer/conversation-message.vala:1314 +#: src/client/conversation-viewer/conversation-message.vala:1315 msgid "Always show from sender" msgstr "この送信者のものは常に表示" @@ -2018,24 +2019,30 @@ msgstr "詳細" msgid "Geary requires your email password to continue" msgstr "続けるにはメールのパスワードが必要です" -#. Label displaying total number of email messages in a folder -#: src/client/folder-list/folder-list-folder-entry.vala:30 +#. Translators: Label displaying total number of email +#. messages in a folder. String substitution is the actual +#. number. +#: src/client/folder-list/folder-list-folder-entry.vala:42 #, c-format msgid "%d message" msgid_plural "%d messages" msgstr[0] "%d 件のメッセージ" -#. / Label displaying number of unread email messages in a folder -#: src/client/folder-list/folder-list-folder-entry.vala:37 +#. Translators: Label displaying number of unread email +#. messages in a folder. String substitution is the actual +#. number. +#: src/client/folder-list/folder-list-folder-entry.vala:52 #, c-format msgid "%d unread" msgid_plural "%d unread" msgstr[0] "%d 件の未読" -#. / This string represents the divider between two messages: "n messages" and "n unread", -#. / shown in the folder list as a tooltip. Please use your languages conventions for -#. / combining the two, i.e. a comma (",") for English; "6 messages, 3 unread" -#: src/client/folder-list/folder-list-folder-entry.vala:43 +#. Translators: This string represents the divider between two +#. messages: "n messages" and "n unread", shown in the folder +#. list as a tooltip. Please use your languages conventions +#. for combining the two, i.e. a comma (",") for English; "6 +#. messages, 3 unread" +#: src/client/folder-list/folder-list-folder-entry.vala:60 #, c-format msgid "%s, %s" msgstr "%s, %s" @@ -2099,11 +2106,70 @@ msgstr[0] "%s, 合計 %d 件の新着メッセージ" #. / Notification title when new messages have been #. / received -#: src/client/plugin/desktop-notifications/desktop-notifications.vala:284 +#: src/client/plugin/desktop-notifications/desktop-notifications.vala:282 msgid "New message" msgid_plural "New messages" msgstr[0] "新着メッセージ" +#: src/client/plugin/email-templates/email-templates.plugin.desktop.in:4 +#, fuzzy +#| msgid "Email address" +msgid "Email Templates" +msgstr "メールアドレス" + +#: src/client/plugin/email-templates/email-templates.plugin.desktop.in:5 +msgid "Create reusable templates for sending email" +msgstr "" + +#. Translators: Templates folder name alternatives. Separate names +#. using a vertical bar and put the most common localized name to +#. the front for the default. English names do not need to be +#. included. +#: src/client/plugin/email-templates/email-templates.vala:29 +#, fuzzy +#| msgid "Sent | Sent Mail | Sent Email | Sent E-Mail" +msgid "Templates | Template Mail | Template Email | Template E-Mail" +msgstr "送信済み | 送信 | 送信メール | 送信済みメール | 送信済メール" + +#. Translators: The name of the folder used to +#. store email templates +#: src/client/plugin/email-templates/email-templates.vala:195 +msgid "Templates" +msgstr "" + +#. Translators: Info bar button label for creating a +#. new email template +#: src/client/plugin/email-templates/email-templates.vala:276 +#, fuzzy +#| msgid "Now" +msgid "New" +msgstr "今" + +#. Translators: Infobar status label for an email template +#: src/client/plugin/email-templates/email-templates.vala:287 +#, fuzzy +#| msgid "Message not saved" +msgid "Message template" +msgstr "メッセージが保存されませんでした" + +#. Translators: Info bar button label for sending an +#. email template +#: src/client/plugin/email-templates/email-templates.vala:291 +#, fuzzy +#| msgctxt "shortcut window" +#| msgid "Send" +msgid "Send" +msgstr "送信する" + +#. Translators: Info bar button label for editing an +#. existing email template +#. Translators: Info bar button label for editing a draft +#. email +#: src/client/plugin/email-templates/email-templates.vala:299 +#: src/client/plugin/special-folders/special-folders.vala:180 +msgid "Edit" +msgstr "編集" + #: src/client/plugin/folder-highlight/folder-highlight.plugin.desktop.in:4 msgid "Folder Highlight" msgstr "フォルダーのハイライト" @@ -2147,36 +2213,30 @@ msgstr "" #. Translators: Info bar button label for emptying #. trash/spam folders -#: src/client/plugin/special-folders/special-folders.vala:140 +#: src/client/plugin/special-folders/special-folders.vala:160 msgid "Empty" msgstr "空にする" #. Translators: Info bar status message for a draft email -#: src/client/plugin/special-folders/special-folders.vala:152 +#: src/client/plugin/special-folders/special-folders.vala:172 msgid "Draft message" msgstr "下書きメッセージ" #. Translators: Info bar status description for a draft #. email -#: src/client/plugin/special-folders/special-folders.vala:155 +#: src/client/plugin/special-folders/special-folders.vala:175 msgid "This message has not yet been sent." msgstr "このメッセージはまだ送信していません。" -#. Translators: Info bar button label for editing a draft -#. email -#: src/client/plugin/special-folders/special-folders.vala:160 -msgid "Edit" -msgstr "編集" - #. Translators: Info bar status message for an sent but #. unsaved email -#: src/client/plugin/special-folders/special-folders.vala:171 +#: src/client/plugin/special-folders/special-folders.vala:191 msgid "Message not saved" msgstr "メッセージが保存されませんでした" #. Translators: Info bar status description for a sent but #. unsaved email -#: src/client/plugin/special-folders/special-folders.vala:174 +#: src/client/plugin/special-folders/special-folders.vala:194 msgid "This message was sent, but has not been saved to your account." msgstr "" "このメッセージを送信しましたが、お使いのアカウントに保存されませんでした。" @@ -2272,7 +2332,7 @@ msgstr "(件名なし)" #. / Translators: This is shown for displaying a list of email #. / recipients that happens to be empty, i.e. contains no #. / email addresses. -#: src/client/util/util-email.vala:134 +#: src/client/util/util-email.vala:135 msgid "(No recipients)" msgstr "(受信者なし)" @@ -2281,7 +2341,7 @@ msgstr "(受信者なし)" #. / addresses. The first (string) substitution is #. / address of the first, the second substitution is #. / the number of n - 1 remaining recipients. -#: src/client/util/util-email.vala:146 +#: src/client/util/util-email.vala:147 #, c-format msgid "%s and %d other" msgid_plural "%s and %d others" @@ -2290,26 +2350,26 @@ msgstr[0] "%s とその他 %d 人" #. / The quoted header for a message being replied to. #. / %1$s will be substituted for the date, and %2$s will be substituted for #. / the original sender. -#: src/client/util/util-email.vala:179 +#: src/client/util/util-email.vala:180 #, c-format msgid "On %1$s, %2$s wrote:" msgstr "" #. / The quoted header for a message being replied to (in case the date is not known). #. / %s will be replaced by the original sender. -#: src/client/util/util-email.vala:186 +#: src/client/util/util-email.vala:187 #, c-format msgid "%s wrote:" msgstr "" #. / The quoted header for a message being replied to (in case the sender is not known). #. / %s will be replaced by the original date -#: src/client/util/util-email.vala:192 +#: src/client/util/util-email.vala:193 #, c-format msgid "On %s:" msgstr "" -#: src/client/util/util-email.vala:221 +#: src/client/util/util-email.vala:222 msgid "---------- Forwarded message ----------" msgstr "" @@ -2549,7 +2609,7 @@ msgstr "" #. Draft mailbox. Separate names using a vertical bar and #. put the most common localized name to the front for the #. default. English names do not need to be included. -#: src/engine/imap-engine/imap-engine-generic-account.vala:884 +#: src/engine/imap-engine/imap-engine-generic-account.vala:892 msgid "Drafts | Draft" msgstr "下書き" @@ -2557,13 +2617,13 @@ msgstr "下書き" #. Sent mailbox. Separate names using a vertical bar and #. put the most common localized name to the front for the #. default. English names do not need to be included. -#: src/engine/imap-engine/imap-engine-generic-account.vala:893 +#: src/engine/imap-engine/imap-engine-generic-account.vala:901 msgid "Sent | Sent Mail | Sent Email | Sent E-Mail" msgstr "送信済み | 送信 | 送信メール | 送信済みメール | 送信済メール" #. The localised name(s) of the Sent folder name as used #. by MS Outlook/Exchange. -#: src/engine/imap-engine/imap-engine-generic-account.vala:898 +#: src/engine/imap-engine/imap-engine-generic-account.vala:906 msgctxt "Outlook localised name" msgid "Sent Items" msgstr "送信したアイテム" @@ -2572,7 +2632,7 @@ msgstr "送信したアイテム" #. Junk/Spam mailbox. Separate names using a vertical bar #. and put the most common localized name to the front for #. the default. English names do not need to be included. -#: src/engine/imap-engine/imap-engine-generic-account.vala:908 +#: src/engine/imap-engine/imap-engine-generic-account.vala:916 msgid "" "Junk | Spam | Junk Mail | Junk Email | Junk E-Mail | Bulk Mail | Bulk Email " "| Bulk E-Mail" @@ -2582,13 +2642,13 @@ msgstr "迷惑メール | スパム | スパムメール | ごみ | ゴミ" #. Trash mailbox. Separate names using a vertical bar and #. put the most common localized name to the front for the #. default. English names do not need to be included. -#: src/engine/imap-engine/imap-engine-generic-account.vala:918 +#: src/engine/imap-engine/imap-engine-generic-account.vala:926 msgid "Trash | Rubbish | Rubbish Bin" msgstr "ごみ箱 | ゴミ箱" #. The localised name(s) of the Trash folder name as used #. by MS Outlook/Exchange. -#: src/engine/imap-engine/imap-engine-generic-account.vala:923 +#: src/engine/imap-engine/imap-engine-generic-account.vala:931 msgctxt "Outlook localised name" msgid "Deleted Items" msgstr "削除したアイテム" @@ -2597,7 +2657,7 @@ msgstr "削除したアイテム" #. Archive mailbox. Separate names using a vertical bar #. and put the most common localized name to the front for #. the default. English names do not need to be included. -#: src/engine/imap-engine/imap-engine-generic-account.vala:933 +#: src/engine/imap-engine/imap-engine-generic-account.vala:941 msgid "Archive | Archives" msgstr "アーカイブ" @@ -2620,14 +2680,16 @@ msgid "Add an account" msgstr "アカウントを追加" #: ui/accounts_editor_add_pane.ui:53 -msgid "Create" +#, fuzzy +#| msgid "Create" +msgid "_Create" msgstr "作成" -#: ui/accounts_editor_add_pane.ui:130 ui/accounts_editor_servers_pane.ui:125 +#: ui/accounts_editor_add_pane.ui:131 ui/accounts_editor_servers_pane.ui:125 msgid "Receiving" msgstr "受信" -#: ui/accounts_editor_add_pane.ui:178 ui/accounts_editor_servers_pane.ui:165 +#: ui/accounts_editor_add_pane.ui:179 ui/accounts_editor_servers_pane.ui:165 msgid "Sending" msgstr "送信" @@ -2989,29 +3051,41 @@ msgstr "" msgid "Details:" msgstr "詳細:" -#. Tooltip for inspector button -#: ui/components-inspector.ui:20 -msgid "Toggle appending new log entries" -msgstr "" - #. Tooltip for inspector button #. Tooltip for problem report button -#: ui/components-inspector.ui:37 ui/problem-details-dialog.ui:19 +#: ui/components-inspector.ui:19 ui/problem-details-dialog.ui:19 msgid "Search for matching log entries" msgstr "一致するログエントリーを検索" +#. Tooltip for inspector button +#: ui/components-inspector.ui:35 +msgid "Toggle appending new log entries" +msgstr "" + +#. Tooltip for inspector button +#: ui/components-inspector.ui:55 +msgid "Add a marker entry to the log" +msgstr "" + #. Tooltip for inspector button #. Tooltip for problem report button -#: ui/components-inspector.ui:63 ui/problem-details-dialog.ui:46 +#: ui/components-inspector.ui:81 ui/problem-details-dialog.ui:46 msgid "Save logs entries and details" msgstr "ログエントリーと詳細を保存" #. Tooltip for inspector button #. Tooltip for problem report button -#: ui/components-inspector.ui:84 ui/problem-details-dialog.ui:62 +#: ui/components-inspector.ui:101 ui/problem-details-dialog.ui:62 msgid "Copy to clipboard" msgstr "クリップボードにコピー" +#. Tooltip for inspector button +#: ui/components-inspector.ui:121 +#, fuzzy +#| msgid "Search for matching log entries" +msgid "Clears all log entries" +msgstr "一致するログエントリーを検索" + #: ui/conversation-contact-popover.ui:146 msgid "New Conversation…" msgstr "新しいスレッド…" @@ -3212,7 +3286,7 @@ msgstr "ラベル" msgid "Conversation Shortcuts" msgstr "スレッドのショートカット" -#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:355 +#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:377 msgctxt "shortcut window" msgid "Actions" msgstr "アクション" @@ -3227,37 +3301,37 @@ msgctxt "shortcut window" msgid "Reply to sender" msgstr "送信者に返信する" -#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:269 +#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:281 msgctxt "shortcut window" msgid "Reply to all" msgstr "全員に返信する" -#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:276 +#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:288 msgctxt "shortcut window" msgid "Forward" msgstr "転送する" -#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:283 +#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:295 msgctxt "shortcut window" msgid "Un-mark/mark read" msgstr "既読マークを付ける/外す" -#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:290 +#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:302 msgctxt "shortcut window" msgid "Mark/un-mark starred" msgstr "星を付ける/外す" -#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:297 +#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:309 msgctxt "shortcut window" msgid "Archive conversations" msgstr "スレッドをアーカイブへ移動する" -#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:304 +#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:326 msgctxt "shortcut window" msgid "Move conversations" msgstr "スレッドを移動する" -#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:311 +#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:333 msgctxt "shortcut window" msgid "Label conversations" msgstr "スレッドにラベルを付ける" @@ -3267,12 +3341,12 @@ msgctxt "shortcut window" msgid "Trash conversations" msgstr "スレッドをゴミ箱へ移動する" -#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:318 +#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:340 msgctxt "shortcut window" msgid "Junk conversations" msgstr "スレッドを迷惑メールへ移動する" -#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:325 +#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:347 msgctxt "shortcut window" msgid "Delete conversations" msgstr "スレッドを削除する" @@ -3287,7 +3361,7 @@ msgctxt "shortcut window" msgid "Search for conversations" msgstr "スレッドを検索する" -#: ui/gtk/help-overlay.ui:115 +#: ui/gtk/help-overlay.ui:115 ui/gtk/help-overlay.ui:354 msgctxt "shortcut window" msgid "Find in current conversation" msgstr "現在のスレッド内を検索する" @@ -3327,7 +3401,7 @@ msgctxt "shortcut window" msgid "Reset zoom" msgstr "拡大/縮小をリセットする" -#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:375 +#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:397 msgctxt "shortcut window" msgid "General" msgstr "全般" @@ -3377,121 +3451,126 @@ msgctxt "shortcut window" msgid "Focus next/previous message" msgstr "フォーカスを次/前のメッセージに移動する" -#: ui/gtk/help-overlay.ui:258 -msgctxt "shortcut window" -msgid "Single-key shortcuts" +#: ui/gtk/help-overlay.ui:260 +#, fuzzy +#| msgctxt "shortcut window" +#| msgid "Single-key shortcuts" +msgid "Single-key Shortcuts" msgstr "シングルキーショートカット" -#: ui/gtk/help-overlay.ui:262 +#: ui/gtk/help-overlay.ui:265 +#, fuzzy +#| msgctxt "shortcut window" +#| msgid "Single-key shortcuts" +msgctxt "shortcut window" +msgid "Single-key shortcuts (if enabled)" +msgstr "シングルキーショートカット" + +#: ui/gtk/help-overlay.ui:274 msgctxt "shortcut window" msgid "Reply to sender " msgstr "送信者に返信する " -#: ui/gtk/help-overlay.ui:332 -msgctxt "shortcut window" -msgid "Find in current conversations" -msgstr "現在のスレッド内を検索する" - -#: ui/gtk/help-overlay.ui:339 +#: ui/gtk/help-overlay.ui:361 msgctxt "shortcut window" msgid "Select next/previous conversations" msgstr "次/前のスレッドを選択する" -#: ui/gtk/help-overlay.ui:351 +#: ui/gtk/help-overlay.ui:373 msgid "Composer Shortcuts" msgstr "作成画面のショートカット" -#: ui/gtk/help-overlay.ui:359 +#: ui/gtk/help-overlay.ui:381 msgctxt "shortcut window" msgid "Send" msgstr "送信する" -#: ui/gtk/help-overlay.ui:366 +#: ui/gtk/help-overlay.ui:388 msgctxt "shortcut window" msgid "Add attachment" msgstr "添付ファイルを追加する" -#: ui/gtk/help-overlay.ui:379 +#: ui/gtk/help-overlay.ui:401 msgctxt "shortcut window" msgid "Close composer window" msgstr "作成ウィンドウを閉じる" -#: ui/gtk/help-overlay.ui:386 +#: ui/gtk/help-overlay.ui:408 msgctxt "shortcut window" msgid "Detach composer window" msgstr "作成ウィンドウを分離する" -#: ui/gtk/help-overlay.ui:393 +#: ui/gtk/help-overlay.ui:415 msgctxt "shortcut window" msgid "Editing" msgstr "編集" -#: ui/gtk/help-overlay.ui:398 +#: ui/gtk/help-overlay.ui:420 msgctxt "shortcut window" msgid "Move selection to the clipboard" msgstr "選択範囲をクリップボードへ移動する" -#: ui/gtk/help-overlay.ui:405 +#: ui/gtk/help-overlay.ui:427 msgctxt "shortcut window" msgid "Copy selection to clipboard" msgstr "選択範囲をクリップボードにコピーする" -#: ui/gtk/help-overlay.ui:412 +#: ui/gtk/help-overlay.ui:434 msgctxt "shortcut window" msgid "Paste from the clipboard" msgstr "クリップボードから貼り付ける" -#: ui/gtk/help-overlay.ui:419 +#: ui/gtk/help-overlay.ui:441 msgctxt "shortcut window" msgid "Quote text" msgstr "テキストを引用する" -#: ui/gtk/help-overlay.ui:426 +#: ui/gtk/help-overlay.ui:448 msgctxt "shortcut window" msgid "Unquote text" msgstr "テキストの引用を解除する" -#: ui/gtk/help-overlay.ui:435 +#: ui/gtk/help-overlay.ui:457 msgctxt "shortcut window" msgid "Rich text editing" msgstr "リッチテキスト編集" -#: ui/gtk/help-overlay.ui:439 +#: ui/gtk/help-overlay.ui:461 msgctxt "shortcut window" msgid "Paste without formatting" msgstr "書式なしで貼り付ける" -#: ui/gtk/help-overlay.ui:446 +#: ui/gtk/help-overlay.ui:468 msgctxt "shortcut window" msgid "Bold text" msgstr "テキストを太字にする" -#: ui/gtk/help-overlay.ui:453 +#: ui/gtk/help-overlay.ui:475 msgctxt "shortcut window" msgid "Italicize text" msgstr "テキストを斜体にする" -#: ui/gtk/help-overlay.ui:460 +#: ui/gtk/help-overlay.ui:482 msgctxt "shortcut window" msgid "Underline text" msgstr "テキストに下線を引く" -#: ui/gtk/help-overlay.ui:467 +#: ui/gtk/help-overlay.ui:489 msgctxt "shortcut window" msgid "Strike text" msgstr "テキストに取り消し線を引く" -#: ui/gtk/help-overlay.ui:474 +#: ui/gtk/help-overlay.ui:496 msgctxt "shortcut window" msgid "Remove formatting" msgstr "書式を削除する" -#: ui/gtk/help-overlay.ui:481 +#: ui/gtk/help-overlay.ui:503 msgctxt "shortcut window" msgid "Insert an image" msgstr "画像を挿入する" -#: ui/gtk/help-overlay.ui:488 +#: ui/gtk/help-overlay.ui:510 msgctxt "shortcut window" msgid "Insert a link" msgstr "リンクを挿入する" @@ -3561,6 +3640,16 @@ msgstr "認証(_A)" msgid "Geary update in progress…" msgstr "Geary を更新しています…" +#~ msgid "Log periodic activity" +#~ msgstr "定期的なアクティビティを記録する" + +#~ msgid "Log IMAP network serialization" +#~ msgstr "IMAP ネットワークのストリームを記録する" + +#~ msgctxt "shortcut window" +#~ msgid "Find in current conversations" +#~ msgstr "現在のスレッド内を検索する" + #~ msgid "Sent Mail" #~ msgstr "送信済みメール" From b1016f8072f7bf77f4999deefcdd5fb2c44d6d74 Mon Sep 17 00:00:00 2001 From: sicklylife Date: Thu, 7 May 2020 12:28:01 +0000 Subject: [PATCH 32/41] Update Japanese translation --- po/ja.po | 58 +++++++++++++++++--------------------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/po/ja.po b/po/ja.po index a20957bb..a798ad49 100644 --- a/po/ja.po +++ b/po/ja.po @@ -14,7 +14,7 @@ msgstr "" "Project-Id-Version: geary-0.4.1\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" "POT-Creation-Date: 2020-05-07 01:10+0000\n" -"PO-Revision-Date: 2020-04-01 02:58+0900\n" +"PO-Revision-Date: 2020-05-07 20:10+0900\n" "Last-Translator: sicklylife \n" "Language-Team: Japanese (Japan) (https://l10n.gnome.org/module/geary/)\n" "Language: ja\n" @@ -852,10 +852,8 @@ msgstr "フォルダーの同期を記録する" #. / Command line option #: src/client/application/application-client.vala:115 -#, fuzzy -#| msgid "Log network activity" msgid "Log IMAP network activity" -msgstr "ネットワークのアクティビティを記録する" +msgstr "IMAP ネットワークのアクティビティを記録する" #. / Command line option. The IMAP replay queue is how changes #. / on the server are replicated on the client. It could @@ -866,10 +864,8 @@ msgstr "IMAP のイベントキューを記録する" #. / Command line option #: src/client/application/application-client.vala:123 -#, fuzzy -#| msgid "Log network activity" msgid "Log SMTP network activity" -msgstr "ネットワークのアクティビティを記録する" +msgstr "SMTP ネットワークのアクティビティを記録する" #. / Command line option #: src/client/application/application-client.vala:126 @@ -940,12 +936,12 @@ msgstr "ディストリビューション名" #. / Application runtime information label #: src/client/application/application-client.vala:323 msgid "Distribution release" -msgstr "" +msgstr "ディストリビューションリリース" #. / Application runtime information label #: src/client/application/application-client.vala:331 msgid "Installation prefix" -msgstr "" +msgstr "インストールプレフィックス" #: src/client/application/application-client.vala:584 #, c-format @@ -2112,54 +2108,44 @@ msgid_plural "New messages" msgstr[0] "新着メッセージ" #: src/client/plugin/email-templates/email-templates.plugin.desktop.in:4 -#, fuzzy -#| msgid "Email address" msgid "Email Templates" -msgstr "メールアドレス" +msgstr "メールテンプレート" #: src/client/plugin/email-templates/email-templates.plugin.desktop.in:5 msgid "Create reusable templates for sending email" msgstr "" +"送信メール用の使い回し可能なテンプレートを作成します" #. Translators: Templates folder name alternatives. Separate names #. using a vertical bar and put the most common localized name to #. the front for the default. English names do not need to be #. included. #: src/client/plugin/email-templates/email-templates.vala:29 -#, fuzzy -#| msgid "Sent | Sent Mail | Sent Email | Sent E-Mail" msgid "Templates | Template Mail | Template Email | Template E-Mail" -msgstr "送信済み | 送信 | 送信メール | 送信済みメール | 送信済メール" +msgstr "テンプレート | テンプレートメール | メールテンプレート" #. Translators: The name of the folder used to #. store email templates #: src/client/plugin/email-templates/email-templates.vala:195 msgid "Templates" -msgstr "" +msgstr "テンプレート" #. Translators: Info bar button label for creating a #. new email template #: src/client/plugin/email-templates/email-templates.vala:276 -#, fuzzy -#| msgid "Now" msgid "New" -msgstr "今" +msgstr "新規" #. Translators: Infobar status label for an email template #: src/client/plugin/email-templates/email-templates.vala:287 -#, fuzzy -#| msgid "Message not saved" msgid "Message template" -msgstr "メッセージが保存されませんでした" +msgstr "" #. Translators: Info bar button label for sending an #. email template #: src/client/plugin/email-templates/email-templates.vala:291 -#, fuzzy -#| msgctxt "shortcut window" -#| msgid "Send" msgid "Send" -msgstr "送信する" +msgstr "送信" #. Translators: Info bar button label for editing an #. existing email template @@ -2197,7 +2183,7 @@ msgstr "通知バッジ" #: src/client/plugin/notification-badge/notification-badge.plugin.desktop.in:5 msgid "Displays a dock badge showing the number of new messages" -msgstr "" +msgstr "Dock に新着メッセージ数を示すバッジを表示します" #: src/client/plugin/sent-sound/sent-sound.plugin.desktop.in:4 msgid "Sent Sound" @@ -2680,10 +2666,8 @@ msgid "Add an account" msgstr "アカウントを追加" #: ui/accounts_editor_add_pane.ui:53 -#, fuzzy -#| msgid "Create" msgid "_Create" -msgstr "作成" +msgstr "作成(_C)" #: ui/accounts_editor_add_pane.ui:131 ui/accounts_editor_servers_pane.ui:125 msgid "Receiving" @@ -3065,7 +3049,7 @@ msgstr "" #. Tooltip for inspector button #: ui/components-inspector.ui:55 msgid "Add a marker entry to the log" -msgstr "" +msgstr "ログにマーカーエントリーを追加" #. Tooltip for inspector button #. Tooltip for problem report button @@ -3081,10 +3065,8 @@ msgstr "クリップボードにコピー" #. Tooltip for inspector button #: ui/components-inspector.ui:121 -#, fuzzy -#| msgid "Search for matching log entries" msgid "Clears all log entries" -msgstr "一致するログエントリーを検索" +msgstr "すべてのログエントリーを消去" #: ui/conversation-contact-popover.ui:146 msgid "New Conversation…" @@ -3452,19 +3434,13 @@ msgid "Focus next/previous message" msgstr "フォーカスを次/前のメッセージに移動する" #: ui/gtk/help-overlay.ui:260 -#, fuzzy -#| msgctxt "shortcut window" -#| msgid "Single-key shortcuts" msgid "Single-key Shortcuts" msgstr "シングルキーショートカット" #: ui/gtk/help-overlay.ui:265 -#, fuzzy -#| msgctxt "shortcut window" -#| msgid "Single-key shortcuts" msgctxt "shortcut window" msgid "Single-key shortcuts (if enabled)" -msgstr "シングルキーショートカット" +msgstr "シングルキーショートカット (有効な場合)" #: ui/gtk/help-overlay.ui:274 msgctxt "shortcut window" From acd6800922d509a72d6e76d71d87c0daeadc3674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Kazik?= Date: Fri, 8 May 2020 12:52:45 +0000 Subject: [PATCH 33/41] Update Slovak translation (cherry picked from commit 0ca2eab25b71894958bd40d930621526c587c54a) --- po/sk.po | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/po/sk.po b/po/sk.po index 69815f5f..1b1196ae 100644 --- a/po/sk.po +++ b/po/sk.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: geary-0.4.1\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-05-03 07:30+0000\n" -"PO-Revision-Date: 2020-05-04 10:21+0200\n" +"POT-Creation-Date: 2020-05-04 08:24+0000\n" +"PO-Revision-Date: 2020-05-08 14:50+0200\n" "Last-Translator: Dušan Kazik \n" "Language-Team: Slovak \n" "Language: sk\n" @@ -256,7 +256,6 @@ msgid "Notify of new mail at startup" msgstr "Oznámiť novú poštu po spustení" #: desktop/org.gnome.Geary.gschema.xml:97 -#| msgid "Desktop notification of new mail" msgid "True to notify of new mail at startup." msgstr "Nastavením na True, bude oznamovaná nová pošta po spustení." @@ -265,7 +264,6 @@ msgid "Ask when opening an attachment" msgstr "" #: desktop/org.gnome.Geary.gschema.xml:103 -#| msgid "To add them as attachments" msgid "True to ask when opening an attachment." msgstr "Nastavením na True, bude zobrazená výzva pri otváraní prílohy." @@ -708,7 +706,7 @@ msgstr "TLS" #: src/client/accounts/accounts-editor-row.vala:534 #: ui/application-main-window.ui:346 msgid "Login" -msgstr "Prihlasovacie meno" +msgstr "Prihlásenie" #. Translators: ComboBox value for source of SMTP #. authentication credentials (none) when adding a new @@ -892,7 +890,6 @@ msgstr "Otvorí nové okno" #. / Command line option #: src/client/application/application-client.vala:137 -#| msgid "Revoke all server certificates with TLS warnings" msgid "Revoke all pinned TLS server certificates" msgstr "Odvolá všetky certifikáty pripnutých serverov TLS" @@ -981,7 +978,6 @@ msgstr "Nerozpoznaný parameter programu: „%s“" #. / Notification title. #: src/client/application/application-controller.vala:458 #, c-format -#| msgid "A problem occurred sending mail for %s" msgid "A problem occurred sending email for %s" msgstr "Vyskytol sa problém pri odosielaní emailu z účtu %s" @@ -1000,7 +996,6 @@ msgstr[2] "Rozhovory boli označené" #. / Translators: Label for in-app notification #: src/client/application/application-controller.vala:574 -#| msgid "No conversations found" msgid "Conversation un-marked" msgid_plural "Conversations un-marked" msgstr[0] "Rozhovorom bolo zrušené označenie" @@ -2515,11 +2510,11 @@ msgstr "Vytvoriť" #: ui/accounts_editor_add_pane.ui:130 ui/accounts_editor_servers_pane.ui:125 msgid "Receiving" -msgstr "Prijíma sa" +msgstr "Prijímanie" #: ui/accounts_editor_add_pane.ui:178 ui/accounts_editor_servers_pane.ui:165 msgid "Sending" -msgstr "Odosiela sa" +msgstr "Odosielanie" #: ui/accounts_editor_edit_pane.ui:8 msgid "Edit Account" @@ -2640,7 +2635,6 @@ msgstr "Účet nahlásil nedôveryhodný server." #. Button tooltip for retrying when a login error has occurred #: ui/application-main-window.ui:350 -#| msgid "Retry receiving email, you will be prompted for a password" msgid "Retry login, you will be prompted for your password" msgstr "Znovu sa pokúsi o prihlásenie, budete vyzvaný na zadanie hesla" @@ -2816,27 +2810,21 @@ msgstr "Preškrtnutý text" # tooltip #: ui/composer-widget.ui:707 -#| msgid "Insert unordered list" msgid "Insert bulleted list" msgstr "Vloží zoznam s odrážkami" # tooltip #: ui/composer-widget.ui:731 -#| msgid "Insert unordered list" msgid "Insert numbered list" msgstr "Vloží číslovaný zoznam" # tooltip #: ui/composer-widget.ui:764 -#| msgctxt "shortcut window" -#| msgid "Unquote text" msgid "Indent or quote text" msgstr "Odsadí alebo cituje text" # tooltip #: ui/composer-widget.ui:788 -#| msgctxt "shortcut window" -#| msgid "Unquote text" msgid "Un-indent or unquote text" msgstr "Zruší odsadenie alebo citáciu textu" @@ -2991,7 +2979,6 @@ msgstr "Prepne pridávanie nových položiek záznamu" #. Tooltip for inspector button #. Tooltip for problem report button #: ui/components-inspector.ui:37 ui/problem-details-dialog.ui:19 -#| msgid "Search for more languages" msgid "Search for matching log entries" msgstr "Vyhľadá zhodné položky záznamu" @@ -3041,7 +3028,6 @@ msgstr "Odstráni emailové adresy" #. Contact popover label #: ui/conversation-contact-popover.ui:294 -#| msgid "Email address:" msgid "This email address is:" msgstr "Táto emailová adresa je:" @@ -3407,8 +3393,6 @@ msgid "Go to next/previous pane" msgstr "Prejdenie na nasledovný/predošlý panel" #: ui/gtk/help-overlay.ui:241 -#| msgctxt "shortcut window" -#| msgid "Find next/previous in current conversation" msgctxt "shortcut window" msgid "Select next/previous conversation" msgstr "Výber nasledovného/predošlého rozhovoru" @@ -3419,8 +3403,6 @@ msgid "Focus next/previous message" msgstr "Zameranie na nasledovnú/predošlú správu" #: ui/gtk/help-overlay.ui:258 -#| msgctxt "shortcut window" -#| msgid "Show keyboard shortcuts" msgctxt "shortcut window" msgid "Single-key shortcuts" msgstr "Klávesové skratky o jednom klávese" @@ -3575,8 +3557,6 @@ msgid "_Archive" msgstr "_Archivovať" #: ui/main-toolbar-menus.ui:21 -#| msgctxt "shortcut window" -#| msgid "Toggle spam" msgid "Toggle as S_pam" msgstr "Prepnúť ako _nevyžiadanú poštu" From 134e7700d0c60fe2e509784e874e70971234de2c Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Sat, 9 May 2020 21:26:40 +1000 Subject: [PATCH 34/41] FormattedConversationData: Don't hard-code conversation list font size Get the interface font from GSettings and use that as the font description for the conversation list, so that the font size (and any other attributes specified) also gets picked up. Only use one font size variation (smaller) for the date, subject and preview. Fixes #676 --- src/client/components/count-badge.vala | 4 +- .../conversation-list-store.vala | 1 - .../formatted-conversation-data.vala | 110 +++++++++--------- .../sidebar/sidebar-count-cell-renderer.vala | 2 +- 4 files changed, 59 insertions(+), 58 deletions(-) diff --git a/src/client/components/count-badge.vala b/src/client/components/count-badge.vala index c2de5cea..a0a1963d 100644 --- a/src/client/components/count-badge.vala +++ b/src/client/components/count-badge.vala @@ -63,7 +63,7 @@ public class CountBadge : Geary.BaseObject { Pango.Rectangle? logical_rect; layout_num.get_pixel_extents(out ink_rect, out logical_rect); if (ctx != null) { - double bg_width = logical_rect.width + FormattedConversationData.LINE_SPACING; + double bg_width = logical_rect.width + FormattedConversationData.SPACING; double bg_height = logical_rect.height; double radius = bg_height / 2.0; double degrees = Math.PI / 180.0; @@ -87,7 +87,7 @@ public class CountBadge : Geary.BaseObject { Pango.cairo_show_layout(ctx, layout_num); } - width = logical_rect.width + FormattedConversationData.LINE_SPACING; + width = logical_rect.width + FormattedConversationData.SPACING; height = logical_rect.height; } } diff --git a/src/client/conversation-list/conversation-list-store.vala b/src/client/conversation-list/conversation-list-store.vala index 814e0231..3854253c 100644 --- a/src/client/conversation-list/conversation-list-store.vala +++ b/src/client/conversation-list/conversation-list-store.vala @@ -290,7 +290,6 @@ public class ConversationListStore : Gtk.ListStore { this.config, conversation, preview, - this.conversations.base_folder, this.conversations.base_folder.account.information.sender_mailboxes ); diff --git a/src/client/conversation-list/formatted-conversation-data.vala b/src/client/conversation-list/formatted-conversation-data.vala index f1ec9dde..f2b635f8 100644 --- a/src/client/conversation-list/formatted-conversation-data.vala +++ b/src/client/conversation-list/formatted-conversation-data.vala @@ -13,18 +13,14 @@ public class FormattedConversationData : Geary.BaseObject { bool was_widget_selected; } - public const int LINE_SPACING = 6; + public const int SPACING = 6; private const string ME = _("Me"); private const string STYLE_EXAMPLE = "Gg"; // Use both upper and lower case to get max height. - private const int TEXT_LEFT = LINE_SPACING * 2 + IconFactory.UNREAD_ICON_SIZE; + private const int TEXT_LEFT = SPACING * 2 + IconFactory.UNREAD_ICON_SIZE; private const double DIM_TEXT_AMOUNT = 0.05; private const double DIM_PREVIEW_TEXT_AMOUNT = 0.25; - private const int FONT_SIZE_DATE = 10; - private const int FONT_SIZE_SUBJECT = 9; - private const int FONT_SIZE_FROM = 11; - private const int FONT_SIZE_PREVIEW = 8; private class ParticipantDisplay : Geary.BaseObject, Gee.Hashable { public Geary.RFC822.MailboxAddress address; @@ -104,6 +100,7 @@ public class FormattedConversationData : Geary.BaseObject { public Geary.Email? preview { get; private set; default = null; } private Application.Configuration config; + private Pango.FontDescription font; private Geary.App.Conversation? conversation = null; private Gee.List? account_owner_emails = null; @@ -116,12 +113,15 @@ public class FormattedConversationData : Geary.BaseObject { public FormattedConversationData(Application.Configuration config, Geary.App.Conversation conversation, Geary.Email preview, - Geary.Folder folder, Gee.List account_owner_emails) { this.config = config; this.conversation = conversation; this.account_owner_emails = account_owner_emails; - use_to = (folder != null) && folder.used_as.is_outgoing(); + this.use_to = conversation.base_folder.used_as.is_outgoing(); + + this.font = Pango.FontDescription.from_string( + this.config.gnome_interface.get_string("font-name") + ); // Load preview-related data. update_date_string(); @@ -141,6 +141,21 @@ public class FormattedConversationData : Geary.BaseObject { this.conversation.email_flags_changed.connect(clear_participants_cache); } + // Creates an example message (used internally for styling calculations.) + public FormattedConversationData.create_example(Application.Configuration config) { + this.config = config; + this.is_unread = false; + this.is_flagged = false; + this.date = STYLE_EXAMPLE; + this.subject_html_escaped = STYLE_EXAMPLE; + this.body = STYLE_EXAMPLE + "\n" + STYLE_EXAMPLE; + this.num_emails = 1; + + this.font = Pango.FontDescription.from_string( + this.config.gnome_interface.get_string("font-name") + ); + } + private void clear_participants_cache(Geary.Email email) { participants.markup = null; } @@ -165,17 +180,6 @@ public class FormattedConversationData : Geary.BaseObject { return true; } - // Creates an example message (used internally for styling calculations.) - public FormattedConversationData.create_example(Application.Configuration config) { - this.config = config; - this.is_unread = false; - this.is_flagged = false; - this.date = STYLE_EXAMPLE; - this.subject_html_escaped = STYLE_EXAMPLE; - this.body = STYLE_EXAMPLE + "\n" + STYLE_EXAMPLE; - this.num_emails = 1; - } - private uint8 gdk_to_rgb(double gdk) { return (uint8) (gdk.clamp(0.0, 1.0) * 255.0); } @@ -294,7 +298,7 @@ public class FormattedConversationData : Geary.BaseObject { Cairo.Context? ctx, Gtk.CellRendererState flags, bool recalc_dims, bool hover_select) { bool display_preview = this.config.display_preview; - int y = LINE_SPACING + (cell_area != null ? cell_area.y : 0); + int y = SPACING + (cell_area != null ? cell_area.y : 0); bool selected = (flags & Gtk.CellRendererState.SELECTED) != 0; bool hover = (flags & Gtk.CellRendererState.PRELIT) != 0 || (selected && hover_select); @@ -304,7 +308,7 @@ public class FormattedConversationData : Geary.BaseObject { // From field. ink_rect = render_from(widget, cell_area, ctx, y, selected, ink_rect); - y += ink_rect.height + ink_rect.y + LINE_SPACING; + y += ink_rect.height + ink_rect.y + SPACING; // If we are displaying a preview then the message counter goes on the same line as the // preview, otherwise it is with the subject. @@ -312,28 +316,28 @@ public class FormattedConversationData : Geary.BaseObject { // Setup counter badge. count_badge.count = num_emails; - int counter_width = count_badge.get_width(widget) + LINE_SPACING; + int counter_width = count_badge.get_width(widget) + SPACING; int counter_x = cell_area != null ? cell_area.width - cell_area.x - counter_width + - (LINE_SPACING / 2) : 0; + (SPACING / 2) : 0; if (display_preview) { // Subject field. render_subject(widget, cell_area, ctx, y, selected); - y += ink_rect.height + ink_rect.y + LINE_SPACING; + y += ink_rect.height + ink_rect.y + (SPACING / 2); // Number of e-mails field. - count_badge.render(widget, ctx, counter_x, y, selected); + count_badge.render(widget, ctx, counter_x, y + (SPACING / 2), selected); // Body preview. ink_rect = render_preview(widget, cell_area, ctx, y, selected, counter_width); - preview_height = ink_rect.height + ink_rect.y + LINE_SPACING; + preview_height = ink_rect.height + ink_rect.y + (int) (SPACING * 1.2); } else { // Number of e-mails field. count_badge.render(widget, ctx, counter_x, y, selected); // Subject field. render_subject(widget, cell_area, ctx, y, selected, counter_width); - y += ink_rect.height + ink_rect.y + LINE_SPACING; + y += ink_rect.height + ink_rect.y + (int) (SPACING * 1.2); } // Draw separator line. @@ -349,25 +353,25 @@ public class FormattedConversationData : Geary.BaseObject { FormattedConversationData.preview_height = preview_height; FormattedConversationData.cell_height = y + preview_height; } else { - int unread_y = display_preview ? cell_area.y + LINE_SPACING * 2 : cell_area.y + - LINE_SPACING; + int unread_y = display_preview ? cell_area.y + SPACING * 2 : cell_area.y + + SPACING; // Unread indicator. if (is_unread || hover) { Gdk.Pixbuf read_icon = IconFactory.instance.load_symbolic( is_unread ? "mail-unread-symbolic" : "mail-read-symbolic", IconFactory.UNREAD_ICON_SIZE, widget.get_style_context()); - Gdk.cairo_set_source_pixbuf(ctx, read_icon, cell_area.x + LINE_SPACING, unread_y); + Gdk.cairo_set_source_pixbuf(ctx, read_icon, cell_area.x + SPACING, unread_y); ctx.paint(); } // Starred indicator. if (is_flagged || hover) { - int star_y = cell_area.y + (cell_area.height / 2) + (display_preview ? LINE_SPACING : 0); + int star_y = cell_area.y + (cell_area.height / 2) + (display_preview ? SPACING : 0); Gdk.Pixbuf starred_icon = IconFactory.instance.load_symbolic( is_flagged ? "starred-symbolic" : "non-starred-symbolic", IconFactory.STAR_ICON_SIZE, widget.get_style_context()); - Gdk.cairo_set_source_pixbuf(ctx, starred_icon, cell_area.x + LINE_SPACING, star_y); + Gdk.cairo_set_source_pixbuf(ctx, starred_icon, cell_area.x + SPACING, star_y); ctx.paint(); } } @@ -375,21 +379,19 @@ public class FormattedConversationData : Geary.BaseObject { private Pango.Rectangle render_date(Gtk.Widget widget, Gdk.Rectangle? cell_area, Cairo.Context? ctx, int y, bool selected) { - string date_markup = "%s".printf( + string date_markup = "%s".printf( rgba_to_markup(dim_rgba(get_foreground_rgba(widget, selected), DIM_TEXT_AMOUNT)), Geary.HTML.escape_markup(date)); Pango.Rectangle? ink_rect; Pango.Rectangle? logical_rect; - Pango.FontDescription font_date = new Pango.FontDescription(); - font_date.set_size(FONT_SIZE_DATE * Pango.SCALE); Pango.Layout layout_date = widget.create_pango_layout(null); - layout_date.set_font_description(font_date); + layout_date.set_font_description(this.font); layout_date.set_markup(date_markup, -1); layout_date.set_alignment(Pango.Alignment.RIGHT); layout_date.get_pixel_extents(out ink_rect, out logical_rect); if (ctx != null && cell_area != null) { - ctx.move_to(cell_area.width - cell_area.x - ink_rect.width - ink_rect.x - LINE_SPACING, y); + ctx.move_to(cell_area.width - cell_area.x - ink_rect.width - ink_rect.x - SPACING, y); Pango.cairo_show_layout(ctx, layout_date); } return ink_rect; @@ -399,14 +401,17 @@ public class FormattedConversationData : Geary.BaseObject { Cairo.Context? ctx, int y, bool selected, Pango.Rectangle ink_rect) { string from_markup = (conversation != null) ? get_participants_markup(widget, selected) : STYLE_EXAMPLE; - Pango.FontDescription font_from = new Pango.FontDescription(); - font_from.set_size(FONT_SIZE_FROM * Pango.SCALE); + Pango.FontDescription font = this.font; + if (is_unread) { + font = font.copy(); + font.set_weight(Pango.Weight.BOLD); + } Pango.Layout layout_from = widget.create_pango_layout(null); - layout_from.set_font_description(font_from); + layout_from.set_font_description(font); layout_from.set_markup(from_markup, -1); layout_from.set_ellipsize(Pango.EllipsizeMode.END); if (ctx != null && cell_area != null) { - layout_from.set_width((cell_area.width - ink_rect.width - ink_rect.x - (LINE_SPACING * 3) - + layout_from.set_width((cell_area.width - ink_rect.width - ink_rect.x - (SPACING * 3) - TEXT_LEFT) * Pango.SCALE); ctx.move_to(cell_area.x + TEXT_LEFT, y); @@ -417,16 +422,17 @@ public class FormattedConversationData : Geary.BaseObject { private void render_subject(Gtk.Widget widget, Gdk.Rectangle? cell_area, Cairo.Context? ctx, int y, bool selected, int counter_width = 0) { - string subject_markup = "%s".printf( + string subject_markup = "%s".printf( rgba_to_markup(dim_rgba(get_foreground_rgba(widget, selected), DIM_TEXT_AMOUNT)), subject_html_escaped); - Pango.FontDescription font_subject = new Pango.FontDescription(); - font_subject.set_size(FONT_SIZE_SUBJECT * Pango.SCALE); - if (is_unread) - font_subject.set_weight(Pango.Weight.BOLD); + Pango.FontDescription font = this.font; + if (is_unread) { + font = font.copy(); + font.set_weight(Pango.Weight.BOLD); + } Pango.Layout layout_subject = widget.create_pango_layout(null); - layout_subject.set_font_description(font_subject); + layout_subject.set_font_description(font); layout_subject.set_markup(subject_markup, -1); if (cell_area != null) layout_subject.set_width((cell_area.width - TEXT_LEFT - counter_width) * Pango.SCALE); @@ -440,21 +446,17 @@ public class FormattedConversationData : Geary.BaseObject { private Pango.Rectangle render_preview(Gtk.Widget widget, Gdk.Rectangle? cell_area, Cairo.Context? ctx, int y, bool selected, int counter_width = 0) { double dim = selected ? DIM_TEXT_AMOUNT : DIM_PREVIEW_TEXT_AMOUNT; - string preview_markup = "%s".printf( + string preview_markup = "%s".printf( rgba_to_markup(dim_rgba(get_foreground_rgba(widget, selected), dim)), Geary.String.is_empty(body) ? "" : Geary.HTML.escape_markup(body)); - Pango.FontDescription font_preview = new Pango.FontDescription(); - font_preview.set_size(FONT_SIZE_PREVIEW * Pango.SCALE); - Pango.Layout layout_preview = widget.create_pango_layout(null); - layout_preview.set_font_description(font_preview); - + layout_preview.set_font_description(this.font); layout_preview.set_markup(preview_markup, -1); layout_preview.set_wrap(Pango.WrapMode.WORD); layout_preview.set_ellipsize(Pango.EllipsizeMode.END); if (ctx != null && cell_area != null) { - layout_preview.set_width((cell_area.width - TEXT_LEFT - counter_width - LINE_SPACING) * Pango.SCALE); + layout_preview.set_width((cell_area.width - TEXT_LEFT - counter_width - SPACING) * Pango.SCALE); layout_preview.set_height(preview_height * Pango.SCALE); ctx.move_to(cell_area.x + TEXT_LEFT, y); diff --git a/src/client/sidebar/sidebar-count-cell-renderer.vala b/src/client/sidebar/sidebar-count-cell-renderer.vala index 847e49fc..615cb864 100644 --- a/src/client/sidebar/sidebar-count-cell-renderer.vala +++ b/src/client/sidebar/sidebar-count-cell-renderer.vala @@ -23,7 +23,7 @@ public class SidebarCountCellRenderer : Gtk.CellRenderer { public override void get_preferred_width(Gtk.Widget widget, out int minimum_size, out int natural_size) { unread_count.count = counter; - minimum_size = unread_count.get_width(widget) + FormattedConversationData.LINE_SPACING; + minimum_size = unread_count.get_width(widget) + FormattedConversationData.SPACING; natural_size = minimum_size; } From f61fe4ba99ea5a10885446d5e0e97aff3338fe52 Mon Sep 17 00:00:00 2001 From: Daniel Mustieles Date: Thu, 14 May 2020 17:06:34 +0200 Subject: [PATCH 35/41] Updated Spanish translation --- po/es.po | 155 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 79 insertions(+), 76 deletions(-) diff --git a/po/es.po b/po/es.po index ab449b57..f985ba67 100644 --- a/po/es.po +++ b/po/es.po @@ -18,8 +18,8 @@ msgid "" msgstr "" "Project-Id-Version: geary-0.4.1\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-04-25 12:36+0000\n" -"PO-Revision-Date: 2020-04-30 11:48+0200\n" +"POT-Creation-Date: 2020-05-08 12:54+0000\n" +"PO-Revision-Date: 2020-05-14 16:25+0200\n" "Last-Translator: Daniel Mustieles \n" "Language-Team: Spanish - Spain \n" "Language: es_ES\n" @@ -876,7 +876,6 @@ msgstr "Registrar la normalización de carpetas" #. / Command line option #: src/client/application/application-client.vala:115 -#| msgid "Log network activity" msgid "Log IMAP network activity" msgstr "Registrar actividad IMAP de la red" @@ -889,7 +888,6 @@ msgstr "Registrar la cola de eventos IMAP" #. / Command line option #: src/client/application/application-client.vala:123 -#| msgid "Log network activity" msgid "Log SMTP network activity" msgstr "Registrar actividad SMTP de la red" @@ -1240,7 +1238,11 @@ msgstr "Compruebe los detalles de seguridad de la conexión" msgid "%s — %s" msgstr "%s — %s" +#. Translators: The name of the folder group containing +#. folders created by people (as opposed to special-use +#. folders) #: src/client/application/application-main-window.vala:972 +#: src/client/folder-list/folder-list-account-branch.vala:43 msgid "Labels" msgstr "Etiquetas" @@ -1293,7 +1295,7 @@ msgstr "%s (%d)" #. Document (100.9MB) #. / In the composer, the filename followed by its filesize, i.e. "notes.txt (1.12KB)" #: src/client/components/components-attachment-pane.vala:107 -#: src/client/composer/composer-widget.vala:1918 +#: src/client/composer/composer-widget.vala:1920 #, c-format msgid "%s (%s)" msgstr "%s (%s)" @@ -1392,7 +1394,7 @@ msgid "Preferences" msgstr "Preferencias" #. / Translators: Preferences page title -#: src/client/components/components-preferences-window.vala:179 +#: src/client/components/components-preferences-window.vala:180 msgid "Plugins" msgstr "Complementos" @@ -1697,63 +1699,63 @@ msgstr "¿Quiere enviar el mensaje sin cuerpo?" msgid "Send message without an attachment?" msgstr "¿Quiere enviar el mensaje sin el archivo adjunto?" -#: src/client/composer/composer-widget.vala:1904 +#: src/client/composer/composer-widget.vala:1906 #, c-format msgid "“%s” already attached for delivery." msgstr "Ya se ha adjuntado «%s» para enviarlo." -#: src/client/composer/composer-widget.vala:1940 -#: src/client/composer/composer-widget.vala:1990 +#: src/client/composer/composer-widget.vala:1942 +#: src/client/composer/composer-widget.vala:1992 #, c-format msgid "“%s” is an empty file." msgstr "«%s» es un archivo vacío." -#: src/client/composer/composer-widget.vala:1978 +#: src/client/composer/composer-widget.vala:1980 #, c-format msgid "“%s” could not be found." msgstr "No se pudo encontrar «%s»." -#: src/client/composer/composer-widget.vala:1984 +#: src/client/composer/composer-widget.vala:1986 #, c-format msgid "“%s” is a folder." msgstr "«%s» es una carpeta." -#: src/client/composer/composer-widget.vala:2003 +#: src/client/composer/composer-widget.vala:2005 #, c-format msgid "“%s” could not be opened for reading." msgstr "No se pudo abrir «%s» para lectura." -#: src/client/composer/composer-widget.vala:2011 +#: src/client/composer/composer-widget.vala:2013 msgid "Cannot add attachment" msgstr "No se puede adjuntar el archivo" #. Translators: Human-readable version of the RFC 822 To header -#: src/client/composer/composer-widget.vala:2071 +#: src/client/composer/composer-widget.vala:2073 #: src/client/conversation-viewer/conversation-email.vala:542 #: src/client/util/util-email.vala:236 ui/conversation-message.ui:312 msgid "To:" msgstr "Para:" #. Translators: Human-readable version of the RFC 822 CC header -#: src/client/composer/composer-widget.vala:2077 +#: src/client/composer/composer-widget.vala:2079 #: src/client/conversation-viewer/conversation-email.vala:547 #: src/client/util/util-email.vala:241 ui/conversation-message.ui:357 msgid "Cc:" msgstr "Cc:" #. Translators: Human-readable version of the RFC 822 BCC header -#: src/client/composer/composer-widget.vala:2083 +#: src/client/composer/composer-widget.vala:2085 #: src/client/conversation-viewer/conversation-email.vala:552 #: ui/conversation-message.ui:402 msgid "Bcc:" msgstr "Cco:" #. Translators: Human-readable version of the RFC 822 Reply-To header -#: src/client/composer/composer-widget.vala:2089 +#: src/client/composer/composer-widget.vala:2091 msgid "Reply-To: " msgstr "Responder a:" -#: src/client/composer/composer-widget.vala:2341 +#: src/client/composer/composer-widget.vala:2343 msgid "Select Color" msgstr "Seleccionar color" @@ -1762,14 +1764,14 @@ msgstr "Seleccionar color" #. printf argument will be the alternate email address, #. and the second will be the account's primary email #. address. -#: src/client/composer/composer-widget.vala:2530 +#: src/client/composer/composer-widget.vala:2532 #, c-format msgid "%1$s via %2$s" msgstr "%1$s mediante %2$s" #. Translators: This is the name of the file chooser filter #. when inserting an image in the composer. -#: src/client/composer/composer-widget.vala:2887 +#: src/client/composer/composer-widget.vala:2889 msgid "Images" msgstr "Imágenes" @@ -2168,7 +2170,6 @@ msgstr[0] "Mensaje nuevo" msgstr[1] "Mensajes nuevos" #: src/client/plugin/email-templates/email-templates.plugin.desktop.in:4 -#| msgid "Email address" msgid "Email Templates" msgstr "Plantillas de de corre-e" @@ -2181,7 +2182,6 @@ msgstr "Crear plantillas reutilizables para enviar correo" #. the front for the default. English names do not need to be #. included. #: src/client/plugin/email-templates/email-templates.vala:29 -#| msgid "Sent | Sent Mail | Sent Email | Sent E-Mail" msgid "Templates | Template Mail | Template Email | Template E-Mail" msgstr "" "Plantillas | Plantilla de correo | Plantillas correo-e | Plantillas mensajes" @@ -2195,21 +2195,17 @@ msgstr "Plantillas" #. Translators: Info bar button label for creating a #. new email template #: src/client/plugin/email-templates/email-templates.vala:276 -#| msgid "Now" msgid "New" msgstr "Nueva" #. Translators: Infobar status label for an email template #: src/client/plugin/email-templates/email-templates.vala:287 -#| msgid "Message not saved" msgid "Message template" msgstr "Plantilla de mensaje" #. Translators: Info bar button label for sending an #. email template #: src/client/plugin/email-templates/email-templates.vala:291 -#| msgctxt "shortcut window" -#| msgid "Send" msgid "Send" msgstr "Enviar" @@ -2723,18 +2719,18 @@ msgstr "Elementos eliminados" msgid "Archive | Archives" msgstr "Archivo | Archivos" -#: src/engine/rfc822/rfc822-message.vala:461 +#: src/engine/rfc822/rfc822-message.vala:531 #, c-format msgid "Could not determine mime type for “%s”." msgstr "No se pudo determinar el tipo MIME de «%s»" -#: src/engine/rfc822/rfc822-message.vala:472 +#: src/engine/rfc822/rfc822-message.vala:542 #, c-format msgid "Could not determine content type for mime type “%s” on “%s”." msgstr "" "No se pudo determinar el tipo de contenido para el tipo MIME «%s» en «%s»." -#: src/engine/rfc822/rfc822-message.vala:1003 +#: src/engine/rfc822/rfc822-message.vala:1001 msgid "(no subject)" msgstr "(sin asunto)" @@ -2743,14 +2739,15 @@ msgid "Add an account" msgstr "Añadir una cuenta" #: ui/accounts_editor_add_pane.ui:53 -msgid "Create" -msgstr "Crear" +#| msgid "Create" +msgid "_Create" +msgstr "_Crear" -#: ui/accounts_editor_add_pane.ui:130 ui/accounts_editor_servers_pane.ui:125 +#: ui/accounts_editor_add_pane.ui:131 ui/accounts_editor_servers_pane.ui:125 msgid "Receiving" msgstr "Recibiendo" -#: ui/accounts_editor_add_pane.ui:178 ui/accounts_editor_servers_pane.ui:165 +#: ui/accounts_editor_add_pane.ui:179 ui/accounts_editor_servers_pane.ui:165 msgid "Sending" msgstr "Enviando" @@ -3142,7 +3139,6 @@ msgstr "Copiar al portapapeles" #. Tooltip for inspector button #: ui/components-inspector.ui:121 -#| msgid "Search for matching log entries" msgid "Clears all log entries" msgstr "Limpiar todas las entradas del registro" @@ -3346,7 +3342,7 @@ msgstr "etiqueta" msgid "Conversation Shortcuts" msgstr "Atajos de conversaciones" -#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:355 +#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:377 msgctxt "shortcut window" msgid "Actions" msgstr "Acciones" @@ -3361,37 +3357,37 @@ msgctxt "shortcut window" msgid "Reply to sender" msgstr "Responder al remitente " -#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:269 +#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:281 msgctxt "shortcut window" msgid "Reply to all" msgstr "Responder a todos" -#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:276 +#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:288 msgctxt "shortcut window" msgid "Forward" msgstr "Reenviar" -#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:283 +#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:295 msgctxt "shortcut window" msgid "Un-mark/mark read" msgstr "Desmarcar/marcar como leído" -#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:290 +#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:302 msgctxt "shortcut window" msgid "Mark/un-mark starred" msgstr "Marcar/desmarcar como favorito" -#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:297 +#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:309 msgctxt "shortcut window" msgid "Archive conversations" msgstr "Archivar conversaciones" -#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:304 +#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:326 msgctxt "shortcut window" msgid "Move conversations" msgstr "Mover conversaciones" -#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:311 +#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:333 msgctxt "shortcut window" msgid "Label conversations" msgstr "Etiquetar conversaciones" @@ -3401,12 +3397,12 @@ msgctxt "shortcut window" msgid "Trash conversations" msgstr "Eliminar conversaciones" -#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:318 +#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:340 msgctxt "shortcut window" msgid "Junk conversations" msgstr "Marcar conversaciones" -#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:325 +#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:347 msgctxt "shortcut window" msgid "Delete conversations" msgstr "Eliminar conversaciones" @@ -3421,7 +3417,7 @@ msgctxt "shortcut window" msgid "Search for conversations" msgstr "Buscar conversaciones" -#: ui/gtk/help-overlay.ui:115 +#: ui/gtk/help-overlay.ui:115 ui/gtk/help-overlay.ui:354 msgctxt "shortcut window" msgid "Find in current conversation" msgstr "Buscar en la conversación actual" @@ -3461,7 +3457,7 @@ msgctxt "shortcut window" msgid "Reset zoom" msgstr "Restablecer ampliación" -#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:375 +#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:397 msgctxt "shortcut window" msgid "General" msgstr "General" @@ -3511,121 +3507,124 @@ msgctxt "shortcut window" msgid "Focus next/previous message" msgstr "Mover el foco al mensaje siguiente/anterior" -#: ui/gtk/help-overlay.ui:258 -msgctxt "shortcut window" -msgid "Single-key shortcuts" +#: ui/gtk/help-overlay.ui:260 +#| msgctxt "shortcut window" +#| msgid "Single-key shortcuts" +msgid "Single-key Shortcuts" msgstr "Atajos de una sola tecla" -#: ui/gtk/help-overlay.ui:262 +#: ui/gtk/help-overlay.ui:265 +#| msgctxt "shortcut window" +#| msgid "Single-key shortcuts" +msgctxt "shortcut window" +msgid "Single-key shortcuts (if enabled)" +msgstr "Atajos de una sola tecla (si están activados)" + +#: ui/gtk/help-overlay.ui:274 msgctxt "shortcut window" msgid "Reply to sender " msgstr "Responder al remitente " -#: ui/gtk/help-overlay.ui:332 -msgctxt "shortcut window" -msgid "Find in current conversations" -msgstr "Buscar en las conversaciones actual" - -#: ui/gtk/help-overlay.ui:339 +#: ui/gtk/help-overlay.ui:361 msgctxt "shortcut window" msgid "Select next/previous conversations" msgstr "Seleccionar conversaciones siguientes/anteriores" -#: ui/gtk/help-overlay.ui:351 +#: ui/gtk/help-overlay.ui:373 msgid "Composer Shortcuts" msgstr "Atajos del editor" -#: ui/gtk/help-overlay.ui:359 +#: ui/gtk/help-overlay.ui:381 msgctxt "shortcut window" msgid "Send" msgstr "Enviar" -#: ui/gtk/help-overlay.ui:366 +#: ui/gtk/help-overlay.ui:388 msgctxt "shortcut window" msgid "Add attachment" msgstr "Añadir un adjunto" -#: ui/gtk/help-overlay.ui:379 +#: ui/gtk/help-overlay.ui:401 msgctxt "shortcut window" msgid "Close composer window" msgstr "Cerrar la ventana del editor" -#: ui/gtk/help-overlay.ui:386 +#: ui/gtk/help-overlay.ui:408 msgctxt "shortcut window" msgid "Detach composer window" msgstr "Desacoplar la ventana del editor" -#: ui/gtk/help-overlay.ui:393 +#: ui/gtk/help-overlay.ui:415 msgctxt "shortcut window" msgid "Editing" msgstr "Edición" -#: ui/gtk/help-overlay.ui:398 +#: ui/gtk/help-overlay.ui:420 msgctxt "shortcut window" msgid "Move selection to the clipboard" msgstr "Mover la selección al portapapeles" -#: ui/gtk/help-overlay.ui:405 +#: ui/gtk/help-overlay.ui:427 msgctxt "shortcut window" msgid "Copy selection to clipboard" msgstr "Copiar selección a portapapeles" -#: ui/gtk/help-overlay.ui:412 +#: ui/gtk/help-overlay.ui:434 msgctxt "shortcut window" msgid "Paste from the clipboard" msgstr "Pegar desde el portapapeles" -#: ui/gtk/help-overlay.ui:419 +#: ui/gtk/help-overlay.ui:441 msgctxt "shortcut window" msgid "Quote text" msgstr "Citar el texto" -#: ui/gtk/help-overlay.ui:426 +#: ui/gtk/help-overlay.ui:448 msgctxt "shortcut window" msgid "Unquote text" msgstr "Eliminar cita del texto" -#: ui/gtk/help-overlay.ui:435 +#: ui/gtk/help-overlay.ui:457 msgctxt "shortcut window" msgid "Rich text editing" msgstr "Edición de texto enriquecido" -#: ui/gtk/help-overlay.ui:439 +#: ui/gtk/help-overlay.ui:461 msgctxt "shortcut window" msgid "Paste without formatting" msgstr "Pegar sin formato" -#: ui/gtk/help-overlay.ui:446 +#: ui/gtk/help-overlay.ui:468 msgctxt "shortcut window" msgid "Bold text" msgstr "Texto en negrita" -#: ui/gtk/help-overlay.ui:453 +#: ui/gtk/help-overlay.ui:475 msgctxt "shortcut window" msgid "Italicize text" msgstr "Texto en cursiva" -#: ui/gtk/help-overlay.ui:460 +#: ui/gtk/help-overlay.ui:482 msgctxt "shortcut window" msgid "Underline text" msgstr "Subrayar el texto" -#: ui/gtk/help-overlay.ui:467 +#: ui/gtk/help-overlay.ui:489 msgctxt "shortcut window" msgid "Strike text" msgstr "Tachar el texto" -#: ui/gtk/help-overlay.ui:474 +#: ui/gtk/help-overlay.ui:496 msgctxt "shortcut window" msgid "Remove formatting" msgstr "Eliminar el formato" -#: ui/gtk/help-overlay.ui:481 +#: ui/gtk/help-overlay.ui:503 msgctxt "shortcut window" msgid "Insert an image" msgstr "Insertar una imagen" -#: ui/gtk/help-overlay.ui:488 +#: ui/gtk/help-overlay.ui:510 msgctxt "shortcut window" msgid "Insert a link" msgstr "Insertar un enlace" @@ -3695,6 +3694,10 @@ msgstr "_Autenticar" msgid "Geary update in progress…" msgstr "Actualización de Geary en proceso…" +#~ msgctxt "shortcut window" +#~ msgid "Find in current conversations" +#~ msgstr "Buscar en las conversaciones actual" + #~ msgid "Log periodic activity" #~ msgstr "Registrar la actividad periódica" From bebeb5347d64bd8b159935146fb1ef5f19bedc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emin=20Tufan=20=C3=87etin?= Date: Sat, 16 May 2020 12:15:00 +0000 Subject: [PATCH 36/41] Update Turkish translation --- po/tr.po | 129 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/po/tr.po b/po/tr.po index 7c6d95dd..4b828d0d 100644 --- a/po/tr.po +++ b/po/tr.po @@ -16,8 +16,8 @@ msgid "" msgstr "" "Project-Id-Version: geary.mainline\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-05-04 09:30+0000\n" -"PO-Revision-Date: 2020-05-05 16:49+0300\n" +"POT-Creation-Date: 2020-05-14 15:06+0000\n" +"PO-Revision-Date: 2020-05-16 15:14+0300\n" "Last-Translator: Emin Tufan Çetin \n" "Language-Team: Turkish \n" "Language: tr\n" @@ -1272,7 +1272,7 @@ msgstr "%s (%d)" #. Document (100.9MB) #. / In the composer, the filename followed by its filesize, i.e. "notes.txt (1.12KB)" #: src/client/components/components-attachment-pane.vala:107 -#: src/client/composer/composer-widget.vala:1918 +#: src/client/composer/composer-widget.vala:1920 #, c-format msgid "%s (%s)" msgstr "%s (%s)" @@ -1670,63 +1670,63 @@ msgstr "İleti, ileti gövdesi olmadan gönderilsin mi?" msgid "Send message without an attachment?" msgstr "İleti eki olmadan gönderilsin mi?" -#: src/client/composer/composer-widget.vala:1904 +#: src/client/composer/composer-widget.vala:1906 #, c-format msgid "“%s” already attached for delivery." msgstr "“%s” gönderim için zaten eklendi." -#: src/client/composer/composer-widget.vala:1940 -#: src/client/composer/composer-widget.vala:1990 +#: src/client/composer/composer-widget.vala:1942 +#: src/client/composer/composer-widget.vala:1992 #, c-format msgid "“%s” is an empty file." msgstr "“%s” boş bir dosya." -#: src/client/composer/composer-widget.vala:1978 +#: src/client/composer/composer-widget.vala:1980 #, c-format msgid "“%s” could not be found." msgstr "“%s” bulunamadı." -#: src/client/composer/composer-widget.vala:1984 +#: src/client/composer/composer-widget.vala:1986 #, c-format msgid "“%s” is a folder." msgstr "“%s” bir klasör." -#: src/client/composer/composer-widget.vala:2003 +#: src/client/composer/composer-widget.vala:2005 #, c-format msgid "“%s” could not be opened for reading." msgstr "“%s” okuma için açılamadı." -#: src/client/composer/composer-widget.vala:2011 +#: src/client/composer/composer-widget.vala:2013 msgid "Cannot add attachment" msgstr "Eklenti eklenemiyor" #. Translators: Human-readable version of the RFC 822 To header -#: src/client/composer/composer-widget.vala:2071 +#: src/client/composer/composer-widget.vala:2073 #: src/client/conversation-viewer/conversation-email.vala:542 #: src/client/util/util-email.vala:236 ui/conversation-message.ui:312 msgid "To:" msgstr "Kime:" #. Translators: Human-readable version of the RFC 822 CC header -#: src/client/composer/composer-widget.vala:2077 +#: src/client/composer/composer-widget.vala:2079 #: src/client/conversation-viewer/conversation-email.vala:547 #: src/client/util/util-email.vala:241 ui/conversation-message.ui:357 msgid "Cc:" msgstr "Cc:" #. Translators: Human-readable version of the RFC 822 BCC header -#: src/client/composer/composer-widget.vala:2083 +#: src/client/composer/composer-widget.vala:2085 #: src/client/conversation-viewer/conversation-email.vala:552 #: ui/conversation-message.ui:402 msgid "Bcc:" msgstr "Bcc:" #. Translators: Human-readable version of the RFC 822 Reply-To header -#: src/client/composer/composer-widget.vala:2089 +#: src/client/composer/composer-widget.vala:2091 msgid "Reply-To: " msgstr "Şuna Yanıtla: " -#: src/client/composer/composer-widget.vala:2341 +#: src/client/composer/composer-widget.vala:2343 msgid "Select Color" msgstr "Renk Seç" @@ -1735,14 +1735,14 @@ msgstr "Renk Seç" #. printf argument will be the alternate email address, #. and the second will be the account's primary email #. address. -#: src/client/composer/composer-widget.vala:2530 +#: src/client/composer/composer-widget.vala:2532 #, c-format msgid "%1$s via %2$s" msgstr "%2$s aracılığıyla %1$s" #. Translators: This is the name of the file chooser filter #. when inserting an image in the composer. -#: src/client/composer/composer-widget.vala:2887 +#: src/client/composer/composer-widget.vala:2889 msgid "Images" msgstr "Resimler" @@ -2664,17 +2664,17 @@ msgstr "Silinen Ögeler" msgid "Archive | Archives" msgstr "Arşiv | Arşivler" -#: src/engine/rfc822/rfc822-message.vala:461 +#: src/engine/rfc822/rfc822-message.vala:531 #, c-format msgid "Could not determine mime type for “%s”." msgstr "“%s” için mime türü saptanamadı." -#: src/engine/rfc822/rfc822-message.vala:472 +#: src/engine/rfc822/rfc822-message.vala:542 #, c-format msgid "Could not determine content type for mime type “%s” on “%s”." msgstr "“%2$s” üstündeki “%1$s” mime türü için içerik türü saptanamadı." -#: src/engine/rfc822/rfc822-message.vala:1003 +#: src/engine/rfc822/rfc822-message.vala:1001 msgid "(no subject)" msgstr "(konu yok)" @@ -3285,7 +3285,7 @@ msgstr "etiket" msgid "Conversation Shortcuts" msgstr "Konuşma Kısayolları" -#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:355 +#: ui/gtk/help-overlay.ui:13 ui/gtk/help-overlay.ui:377 msgctxt "shortcut window" msgid "Actions" msgstr "Eylemler" @@ -3300,37 +3300,37 @@ msgctxt "shortcut window" msgid "Reply to sender" msgstr "Göndereni yanıtla" -#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:269 +#: ui/gtk/help-overlay.ui:31 ui/gtk/help-overlay.ui:281 msgctxt "shortcut window" msgid "Reply to all" msgstr "Tümünü yanıtla" -#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:276 +#: ui/gtk/help-overlay.ui:38 ui/gtk/help-overlay.ui:288 msgctxt "shortcut window" msgid "Forward" msgstr "Yönlendir" -#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:283 +#: ui/gtk/help-overlay.ui:45 ui/gtk/help-overlay.ui:295 msgctxt "shortcut window" msgid "Un-mark/mark read" msgstr "Okundu olarak imle/imi kaldır" -#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:290 +#: ui/gtk/help-overlay.ui:52 ui/gtk/help-overlay.ui:302 msgctxt "shortcut window" msgid "Mark/un-mark starred" msgstr "Yıldızla/Yıldızı kaldır" -#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:297 +#: ui/gtk/help-overlay.ui:59 ui/gtk/help-overlay.ui:309 msgctxt "shortcut window" msgid "Archive conversations" msgstr "Konuşmaları arşivle" -#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:304 +#: ui/gtk/help-overlay.ui:66 ui/gtk/help-overlay.ui:326 msgctxt "shortcut window" msgid "Move conversations" msgstr "Konuşmaları taşı" -#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:311 +#: ui/gtk/help-overlay.ui:73 ui/gtk/help-overlay.ui:333 msgctxt "shortcut window" msgid "Label conversations" msgstr "Konuşmaları etiketle" @@ -3340,12 +3340,12 @@ msgctxt "shortcut window" msgid "Trash conversations" msgstr "Konuşmaları çöpe at" -#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:318 +#: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:340 msgctxt "shortcut window" msgid "Junk conversations" msgstr "Konuşmaları gereksize taşı" -#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:325 +#: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:347 msgctxt "shortcut window" msgid "Delete conversations" msgstr "Konuşmaları sil" @@ -3360,7 +3360,7 @@ msgctxt "shortcut window" msgid "Search for conversations" msgstr "Konuşmaları ara" -#: ui/gtk/help-overlay.ui:115 +#: ui/gtk/help-overlay.ui:115 ui/gtk/help-overlay.ui:354 msgctxt "shortcut window" msgid "Find in current conversation" msgstr "Şimdiki konuşmada bul" @@ -3400,7 +3400,7 @@ msgctxt "shortcut window" msgid "Reset zoom" msgstr "Yakınlaştırmayı sıfırla" -#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:375 +#: ui/gtk/help-overlay.ui:188 ui/gtk/help-overlay.ui:397 msgctxt "shortcut window" msgid "General" msgstr "Genel" @@ -3450,121 +3450,120 @@ msgctxt "shortcut window" msgid "Focus next/previous message" msgstr "Önceki/sonraki iletiye odaklan" -#: ui/gtk/help-overlay.ui:258 -msgctxt "shortcut window" -msgid "Single-key shortcuts" -msgstr "Tek tuşlu kısayollar" +#: ui/gtk/help-overlay.ui:260 +msgid "Single-key Shortcuts" +msgstr "Tek Tuşlu Kısayollar" -#: ui/gtk/help-overlay.ui:262 +#: ui/gtk/help-overlay.ui:265 +msgctxt "shortcut window" +msgid "Single-key shortcuts (if enabled)" +msgstr "Tek tuşlu kısayollar (etkinse)" + +#: ui/gtk/help-overlay.ui:274 msgctxt "shortcut window" msgid "Reply to sender " msgstr "Göndereni yanıtla " -#: ui/gtk/help-overlay.ui:332 -msgctxt "shortcut window" -msgid "Find in current conversations" -msgstr "Geçerli konuşmalarda bul" - -#: ui/gtk/help-overlay.ui:339 +#: ui/gtk/help-overlay.ui:361 msgctxt "shortcut window" msgid "Select next/previous conversations" msgstr "Sonraki/önceki konuşmaları seç" -#: ui/gtk/help-overlay.ui:351 +#: ui/gtk/help-overlay.ui:373 msgid "Composer Shortcuts" msgstr "Oluşturucu Kısayolları" -#: ui/gtk/help-overlay.ui:359 +#: ui/gtk/help-overlay.ui:381 msgctxt "shortcut window" msgid "Send" msgstr "Gönder" -#: ui/gtk/help-overlay.ui:366 +#: ui/gtk/help-overlay.ui:388 msgctxt "shortcut window" msgid "Add attachment" msgstr "Ek ekle" -#: ui/gtk/help-overlay.ui:379 +#: ui/gtk/help-overlay.ui:401 msgctxt "shortcut window" msgid "Close composer window" msgstr "Oluşturucu penceresini kapat" -#: ui/gtk/help-overlay.ui:386 +#: ui/gtk/help-overlay.ui:408 msgctxt "shortcut window" msgid "Detach composer window" msgstr "Oluşturucu penceresini ayır" -#: ui/gtk/help-overlay.ui:393 +#: ui/gtk/help-overlay.ui:415 msgctxt "shortcut window" msgid "Editing" msgstr "Düzenleme" -#: ui/gtk/help-overlay.ui:398 +#: ui/gtk/help-overlay.ui:420 msgctxt "shortcut window" msgid "Move selection to the clipboard" msgstr "Seçimi panoya taşı" -#: ui/gtk/help-overlay.ui:405 +#: ui/gtk/help-overlay.ui:427 msgctxt "shortcut window" msgid "Copy selection to clipboard" msgstr "Seçimi panoya kopyala" -#: ui/gtk/help-overlay.ui:412 +#: ui/gtk/help-overlay.ui:434 msgctxt "shortcut window" msgid "Paste from the clipboard" msgstr "Panodan yapıştır" -#: ui/gtk/help-overlay.ui:419 +#: ui/gtk/help-overlay.ui:441 msgctxt "shortcut window" msgid "Quote text" msgstr "Metni alıntıla" -#: ui/gtk/help-overlay.ui:426 +#: ui/gtk/help-overlay.ui:448 msgctxt "shortcut window" msgid "Unquote text" msgstr "Metni alıntılama" -#: ui/gtk/help-overlay.ui:435 +#: ui/gtk/help-overlay.ui:457 msgctxt "shortcut window" msgid "Rich text editing" msgstr "Zengin metin düzenleme" -#: ui/gtk/help-overlay.ui:439 +#: ui/gtk/help-overlay.ui:461 msgctxt "shortcut window" msgid "Paste without formatting" msgstr "Biçimlendirmeden yapıştır" -#: ui/gtk/help-overlay.ui:446 +#: ui/gtk/help-overlay.ui:468 msgctxt "shortcut window" msgid "Bold text" msgstr "Kalın yazı" -#: ui/gtk/help-overlay.ui:453 +#: ui/gtk/help-overlay.ui:475 msgctxt "shortcut window" msgid "Italicize text" msgstr "Eğik metin" -#: ui/gtk/help-overlay.ui:460 +#: ui/gtk/help-overlay.ui:482 msgctxt "shortcut window" msgid "Underline text" msgstr "Metnin altını çiz" -#: ui/gtk/help-overlay.ui:467 +#: ui/gtk/help-overlay.ui:489 msgctxt "shortcut window" msgid "Strike text" msgstr "Çizgili metin" -#: ui/gtk/help-overlay.ui:474 +#: ui/gtk/help-overlay.ui:496 msgctxt "shortcut window" msgid "Remove formatting" msgstr "Biçimlendirmeyi kaldır" -#: ui/gtk/help-overlay.ui:481 +#: ui/gtk/help-overlay.ui:503 msgctxt "shortcut window" msgid "Insert an image" msgstr "Resim yerleştir" -#: ui/gtk/help-overlay.ui:488 +#: ui/gtk/help-overlay.ui:510 msgctxt "shortcut window" msgid "Insert a link" msgstr "Bağlantı yerleştir" @@ -3634,6 +3633,10 @@ msgstr "_Kimlik Doğrula" msgid "Geary update in progress…" msgstr "Geary güncellemesi sürüyor…" +#~ msgctxt "shortcut window" +#~ msgid "Find in current conversations" +#~ msgstr "Geçerli konuşmalarda bul" + #~ msgid "Log periodic activity" #~ msgstr "Dönemsel etkinliği kayda al" From a935a3bd72a24273b86edff948a7b5762ef6fc69 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Sat, 16 May 2020 14:48:12 +0000 Subject: [PATCH 37/41] Add Ukrainian translation --- help/LINGUAS | 1 + help/uk/uk.po | 1240 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1241 insertions(+) create mode 100644 help/uk/uk.po diff --git a/help/LINGUAS b/help/LINGUAS index 9a1735c5..81ea1365 100644 --- a/help/LINGUAS +++ b/help/LINGUAS @@ -11,3 +11,4 @@ pl pt_BR sv tr +uk diff --git a/help/uk/uk.po b/help/uk/uk.po new file mode 100644 index 00000000..35add2f5 --- /dev/null +++ b/help/uk/uk.po @@ -0,0 +1,1240 @@ +# Ukrainian translation for geary. +# Copyright (C) 2020 geary's COPYRIGHT HOLDER +# This file is distributed under the same license as the geary package. +# +# Yuri Chornoivan , 2020. +msgid "" +msgstr "" +"Project-Id-Version: geary mainline\n" +"POT-Creation-Date: 2020-05-14 15:06+0000\n" +"PO-Revision-Date: 2020-05-16 17:46+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: uk\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 20.07.70\n" + +#. Put one translator per line, in the form NAME , YEAR1, YEAR2 +msgctxt "_" +msgid "translator-credits" +msgstr "Юрій Чорноіван , 2020" + +#. (itstool) path: page/title +#: C/accounts.page:10 +msgid "Accounts" +msgstr "Облікові записи" + +#. (itstool) path: section/title +#: C/accounts.page:13 +msgid "Accounts Editor" +msgstr "Редактор облікових записів" + +#. (itstool) path: section/p +#: C/accounts.page:15 +msgid "" +"Your email accounts can be added, updated, and removed using the " +"accounts editor. To open it, click Geary’s application menu button " +"in the main window above the folder list, then click Accounts in " +"the pop-up menu." +msgstr "" +"Ви можете додати, оновити або вилучити ваші облікові записи електронної пошти" +" за допомогою редактора облікових записів. Щоб відкрити редактора," +" натисніть кнопку меню програми Geary у головному вікні над списком тек, а" +" потім виберіть пункт Облікові записи у контекстному меню." + +#. (itstool) path: section/p +#: C/accounts.page:20 +msgid "" +"To change the order that accounts are displayed in the folder list, click " +"and drag the handle for an account in the accounts editor, or focus an " +"account with Tab, then use Ctrl and Ctrl to re-position the " +"currently selected account." +msgstr "" +"Щоб змінити порядок, у якому облікові записи буде показано у списку тек," +" натисніть і перетягніть елемент керування для облікового запису у редакторі" +" облікових записів або наведіть фокус на пункт облікового запису за допомогою" +" натискання клавіші Tab, потім скористайтеся комбінаціями Ctrl і Ctrl<" +"/keyseq>, щоб змінити позицію поточного позначеного облікового запису." + +#. (itstool) path: section/title +#: C/accounts.page:29 +msgid "Adding accounts" +msgstr "Додавання облікових записів" + +#. (itstool) path: section/p +#: C/accounts.page:31 +msgid "" +"Geary will automatically use any email accounts you have added via the " +"Online Accounts panel of GNOME Settings. If you do not " +"have any accounts added to Online Accounts, you will be prompted " +"to add an account the first time you run Geary." +msgstr "" +"Geary автоматично скористається усіма обліковими записами, які було додано за" +" допомогою панелі Мережеві записи програми Параметри GNOME<" +"/app>. Якщо ви не додавали облікових записів за допомогою Мережевих" +" записів, програма попросить вас додати обліковий запис, коли ви вперше" +" запустите Geary." + +#. (itstool) path: section/p +#: C/accounts.page:37 +msgid "" +"To add additional accounts, open the accounts editor, then choose the " +"appropriate email provider from the list at the bottom of the window. For " +"providers supported by Online Accounts, GNOME Settings " +"will be opened and you will be asked for your account information there. For " +"other email providers, you will be asked for your account information by " +"Geary. Once entered, click Create and the account information " +"will be checked and then added." +msgstr "" +"Щоб додати облікові записи, відкрийте редактор облікових записів, потім" +" виберіть відповідного надавача послуг електронної пошти зі списку у нижній" +" частині вікна. Для підтримуваних Мережевими записами надавачів" +" послуг буде відкрито Параметри GNOME, і програма попросить вас" +" ввести дані облікового запису. Для інших надавачів послуг електронної пошти" +" Geary попросить вас ввести дані облікового запису. Після введення параметрів" +" облікового запису натисніть кнопку Створити — програма перевірить" +" дані облікового запису і додасть його до списку." + +#. (itstool) path: section/title +#: C/accounts.page:48 +msgid "Updating existing accounts" +msgstr "Оновлення наявних облікових записів" + +#. (itstool) path: section/p +#: C/accounts.page:50 +msgid "" +"To update existing accounts, open the accounts editor and choose the account " +"you wish to update. Geary will display settings for the account. From there, " +"you can add and remove additional sender email addresses, edit your email " +"signature, and various other settings." +msgstr "" +"Щоб оновити наявні облікові записи, відкрийте редактор облікових записів і" +" виберіть пункт облікового запису, дані якого ви хочете змінити. Geary покаже" +" параметри цього облікового запису. За допомогою відповідної сторінки ви" +" можете додавати і вилучати додаткові адреси електронної пошти відправника," +" редагувати підпис до повідомлень та інші параметри облікового запису." + +#. (itstool) path: section/p +#: C/accounts.page:56 +msgid "" +"The Download mail setting allows you to configure how much mail " +"Geary will download and store locally. Geary can only use locally available " +"mail when displaying and searching for conversations." +msgstr "" +"За допомогою пункту Отримання пошти ви можете налаштувати обсяг" +" поштових даних, які Geary отримуватиме із сервера і зберігатиме локально." +" Geary може показувати повідомлення і шукати дані лише у збереженій локально" +" пошті." + +#. (itstool) path: section/p +#: C/accounts.page:61 +msgid "" +"To edit the server settings for the account, scroll to the bottom of the " +"window and click Server Settings. The server settings will be " +"displayed and you can click to edit them. Once done, click Apply " +"and Geary will check the settings, then update the account. Note that " +"accounts added via the Online Accounts panel of GNOME " +"Settings cannot have their server name, security, login, or password " +"settings changed." +msgstr "" +"Щоб змінити параметри сервера для облікового запису, виконайте гортання" +" вмісту вікна до нижньої частини і натисніть кнопку Параметри сервера<" +"/gui>. Програма покаже параметри сервера — ви зможете клацати на них із метою" +" редагування. Щойно належні зміни буде внесено, натисніть кнопку Застосувати і Geary перевірить параметри, потім оновить дані" +" облікового запису. Зауважте, що для облікових записів, які було додано за" +" допомогою панелі Мережеві записи Параметрів GNOME, не" +" можна змінювати назву сервера, захист, ім'я користувача і пароль." + +#. (itstool) path: section/p +#: C/accounts.page:70 +msgid "" +"The Save draft email on server checkbox controls whether the " +"composer will save copies of email messages being written in the " +"Drafts folder. If de-selected, you will not be able to save draft " +"messages when closing the composer." +msgstr "" +"Пункт Зберігати чернетки пошти на сервері керує тим, чи буде" +" редактор зберігати копії повідомлень електронної пошти до теки Чернетки. Якщо цей пункт не позначено, чернетки повідомлень не" +" зберігатимуться, якщо ви закриєте вікно редактора." + +#. (itstool) path: section/p +#: C/accounts.page:75 +msgid "" +"The Save sent email on server checkbox controls whether Geary " +"will save copies of email that have been sent to the Sent folder. " +"If de-selected, you will no be able to see any email messages you have sent, " +"unless your server automatically saves them for you." +msgstr "" +"Пункт Зберігати надіслану пошту на сервері керує тим, чи буде" +" Geary зберігати копії повідомлень, які було надіслано, у теці Надіслані. Якщо пункт не позначено, ви не зможете переглядати" +" надіслані вами повідомлення, якщо сервер не виконуватиме автоматичного" +" зберігання цих повідомлень." + +#. (itstool) path: section/title +#: C/accounts.page:83 +msgid "Removing accounts" +msgstr "Вилучення облікових записів" + +#. (itstool) path: section/p +#: C/accounts.page:85 +msgid "" +"Accounts added via the Online Accounts panel of GNOME " +"Settings must also be removed from there. To do so, open Online " +"Accounts, select the account, and click Remove." +msgstr "" + +#. (itstool) path: section/p +#: C/accounts.page:90 +msgid "" +"To remove an account added via Geary, open the accounts editor and choose " +"the account you wish to remove. Geary will display settings for the account. " +"Scroll to the bottom of the window and click Remove Account. You " +"will be prompted to confirm removing the account. Once confirmed, if you " +"change your mind you can still undo removing the account by clicking " +"Undo in the popup notification, or by typing CtrlU." +msgstr "" + +#. (itstool) path: page/title +#: C/archive.page:8 +msgid "Archive, trash and delete messages" +msgstr "" +"Архівування, надсилання повідомлень до смітника і вилучення повідомлень" + +#. (itstool) path: page/p +#: C/archive.page:10 +msgid "" +"Geary lets you archive messages if your server supports it. Clicking the " +"Archive toolbar button moves the conversation " +"from the current folder to the Archive folder for most email " +"services, or to All Mail for GMail. Archiving helps keep your " +"email organised by moving old and replied-to email out of the way." +msgstr "" + +#. (itstool) path: page/p +#: C/archive.page:17 +msgid "" +"To move conversations to the Trash folder, select them and click " +"the Trash toolbar button. To permanently delete " +"conversations, hold down Shift and click the Delete button that appears in place of the Trash button, " +"or open the conversation in the Trash folder and click Delete there." +msgstr "" + +#. (itstool) path: note/title +#: C/archive.page:26 +msgid "Undoing changes" +msgstr "Скасовування змін" + +#. (itstool) path: note/p +#: C/archive.page:27 +msgid "" +"Note that you can always undo archiving or trashing a message if you change " +"your mind. Click Undo on the pop-up notification " +"that appears, or type CtrlZ, or open " +"the folder, find the message, then move it back to your Inbox" +msgstr "" + +#. (itstool) path: page/p +#: C/archive.page:34 +msgid "" +"While both Archive and Trash removes conversations from your Inbox folder, " +"there is an important difference. Clicking Archive will ensure your conversations are kept so you can find them again " +"later. Clicking Trash will cause conversations " +"to be hidden from , and they will likely be deleted " +"in the future." +msgstr "" + +#. (itstool) path: page/title +#: C/bugs.page:10 +msgid "Found a bug?" +msgstr "Знайшли ваду?" + +#. (itstool) path: page/p +#: C/bugs.page:12 +msgid "" +"If you suspect you've found a bug in Geary, please get in touch about it so it can be " +"fixed." +msgstr "" + +#. (itstool) path: page/p +#: C/bugs.page:16 +msgid "" +"To help diagnose the problem as fast as possible, please include the " +"following information:" +msgstr "" + +#. (itstool) path: item/p +#: C/bugs.page:20 +msgid "Geary version and installation method (Package? Flathub? Source code?)" +msgstr "" +"Версія Geary та спосіб встановлення (Пакунок? Flathub? Початковий код?)" + +#. (itstool) path: item/p +#: C/bugs.page:22 +msgid "Your desktop (GNOME? KDE? Something else?)" +msgstr "Стільничне середовища (GNOME? KDE? Щось інше?)" + +#. (itstool) path: item/p +#: C/bugs.page:23 +msgid "" +"Your operating system and version (Ubuntu 16.04? Fedora 28? Rolled your own?)" +msgstr "" +"Назва і версія операційної системи (Ubuntu 16.04? Fedora 28? Щось створене" +" власноруч?)" + +#. (itstool) path: item/p +#: C/bugs.page:25 +msgid "Email provider (Gmail, Yahoo!, Outlook.com, or someone else?)" +msgstr "" +"Надавач послуг електронної пошти (Gmail, Yahoo!, Outlook.com чи якийсь інший?)" + +#. (itstool) path: item/p +#: C/bugs.page:27 +msgid "Steps to reproduce the bug" +msgstr "Кроки для відтворення вади" + +#. (itstool) path: item/p +#: C/bugs.page:28 +msgid "What happened?" +msgstr "Що трапилося?" + +#. (itstool) path: item/p +#: C/bugs.page:29 +msgid "What did you expect to happen?" +msgstr "На які наслідки ви сподівалися?" + +#. (itstool) path: page/p +#: C/bugs.page:32 +msgid "Thanks for your help!" +msgstr "Дякуємо за вашу допомогу!" + +#. (itstool) path: page/title +#: C/contributing.page:10 +msgid "Contribute to Geary" +msgstr "Участь у розробці Geary" + +#. (itstool) path: page/p +#: C/contributing.page:12 +msgid "" +"Want to help improve Geary? There are a number of ways you can contribute:" +msgstr "" +"Хочете допомогти в удосконаленні Geary? Існує декілька способів взяти участь" +" у розробці програми:" + +#. (itstool) path: item/p +#: C/contributing.page:16 +msgid "" +"Bug " +"reporting—report new bugs or request new features" +msgstr "" +"Звітування про" +" вади — повідомляйте про вади або надсилайте запити щодо нових" +" можливостей" + +#. (itstool) path: item/p +#: C/contributing.page:19 +msgid "" +"User Experience " +"Design—research and develop Geary’s user experience" +msgstr "" +"Дизайн та вивчення" +" проблем у користуванні — вивчення проблем у користуванні Geary та" +" розробка дизайну програми" + +#. (itstool) path: item/p +#: C/contributing.page:20 +msgid "" +"Development—fix bugs and add new features" +msgstr "" +"Написання" +" програмного коду — виправлення вад та додавання нових можливостей" + +#. (itstool) path: item/p +#: C/contributing.page:21 +msgid "" +"Translating—translate Geary’s user interface and user manual into new languages" +msgstr "" +"Переклад" +" — переклад інтерфейсу та підручника Geary різними мовами" + +#. (itstool) path: item/p +#: C/contributing.page:22 +msgid "" +"Join the " +"discussion—on the mailing list or IRC channel" +msgstr "" +"Долучення до" +" обговорень у списку листування або на каналі IRC" + +#. (itstool) path: page/p +#: C/contributing.page:25 +msgid "Thanks for your help making Geary better!" +msgstr "Дякуємо вам за допомогою в удосконаленні Geary!" + +#. (itstool) path: title/media +#. This is a reference to an external file such as an image or video. When +#. the file changes, the md5 hash will change to let you know you need to +#. update your localized copy. The msgstr is not used at all. Set it to +#. whatever you like once you have updated your copy of the file. +#: C/index.page:6 +msgctxt "_" +msgid "external ref='figures/geary.svg' md5='1c66fe237d546362fda9f209840da4a8'" +msgstr "" +"external ref='figures/geary.svg' md5='1c66fe237d546362fda9f209840da4a8'" + +#. (itstool) path: page/title +#: C/index.page:5 +msgid "" +" " +"Geary" +msgstr "" +" " +"Geary" + +#. (itstool) path: section/title +#: C/index.page:11 +msgid "Introduction" +msgstr "Вступ" + +#. (itstool) path: section/title +#: C/index.page:15 +msgid "Using Geary" +msgstr "Користування Geary" + +#. (itstool) path: section/title +#: C/index.page:19 +msgid "Contributing and bug reporting" +msgstr "Участь у розробці та звітування щодо вад" + +#. (itstool) path: page/title +#: C/label.page:10 +msgid "Label or move a conversation" +msgstr "Позначення або пересування спілкування" + +#. (itstool) path: section/title +#: C/label.page:12 +msgid "Label a conversation" +msgstr "Позначення спілкування" + +#. (itstool) path: section/p +#: C/label.page:13 +msgid "" +"Geary lets you apply one or more labels to each conversation. Geary " +"labels correspond to labels in Gmail, or ordinary folders in other mail " +"services." +msgstr "" + +#. (itstool) path: section/p +#: C/label.page:15 +msgid "" +"To label one or more conversations, first select the conversation(s), then " +"do either of the following:" +msgstr "" + +#. (itstool) path: item/p +#: C/label.page:18 +msgid "" +"Click the Label button on the toolbar and select a label from the " +"resulting drop-down menu." +msgstr "" + +#. (itstool) path: item/p +#: C/label.page:20 +msgid "" +"Hold down the Ctrl key and drag the conversation(s) from the " +"conversation list to the label in the sidebar." +msgstr "" + +#. (itstool) path: section/title +#: C/label.page:25 +msgid "Move a conversation to a folder or label" +msgstr "Пересування спілкування до теки або мітки" + +#. (itstool) path: section/p +#: C/label.page:26 +msgid "" +"To move one or more conversations to a folder or label, first select the " +"conversation(s), then do either of the following:" +msgstr "" + +#. (itstool) path: item/p +#: C/label.page:29 +msgid "" +"Click the Move button on the toolbar and select a folder or label " +"from the resulting drop-down menu." +msgstr "" + +#. (itstool) path: item/p +#: C/label.page:31 +msgid "" +"Drag the conversation(s) from the conversation list to the folder or label " +"in the sidebar." +msgstr "" + +#. (itstool) path: page/title +#: C/limits.page:9 +msgid "Limitations" +msgstr "Обмеження" + +#. (itstool) path: page/p +#: C/limits.page:11 +msgid "" +"Geary is still in early development. Geary supports IMAP and has been tested " +"with Gmail, Yahoo, and the free Dovecot mail server. Experimental support " +"for Outlook.com is provided. Geary may not yet work well with some IMAP " +"servers. At this time Geary is still missing numerous features including " +"offline mode." +msgstr "" + +#. (itstool) path: page/p +#: C/limits.page:17 +msgid "" +"To learn more about the features we're working on and the future of Geary, " +"please visit Geary's wiki " +"page." +msgstr "" + +#. (itstool) path: page/title +#. (itstool) path: section/title +#: C/overview.page:9 C/shortcuts.page:13 +msgid "Overview" +msgstr "Огляд" + +#. (itstool) path: page/p +#: C/overview.page:11 +msgid "" +"Geary is an email application built around conversations, for the GNOME 3 " +"desktop. It allows you to read, find and send email with a straightforward, " +"modern interface." +msgstr "" +"Geary — програма для роботи з електронною поштою, базовою концепцією якої є " +"«спілкування». Програму призначено для стільничного середовища GNOME 3. Вона " +"надає вам змогу читати, шукати та надсилати електронну пошту. Інтерфейс " +"програми є простим і сучасним." + +#. (itstool) path: page/p +#: C/overview.page:15 +msgid "" +"Conversations allow you to read a complete discussion without having to find " +"and click from message to message." +msgstr "" + +#. (itstool) path: page/p +#: C/overview.page:18 +msgid "" +"The main Geary window is divided into several areas: The folder list, the " +"conversation list, and the conversation viewer." +msgstr "" + +#. (itstool) path: section/title +#: C/overview.page:22 +msgid "Folder list" +msgstr "Список тек" + +#. (itstool) path: section/p +#: C/overview.page:24 +msgid "" +"The folder list displays all folders and labels " +"for your email accounts. Geary uses the term label for any folder " +"that you have created to organize your email messages." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:29 +msgid "" +"Select a folder or label to display the conversations it contains in the " +"conversation list." +msgstr "" + +#. (itstool) path: section/title +#: C/overview.page:34 +msgid "Conversation list" +msgstr "Список спілкування" + +#. (itstool) path: section/p +#: C/overview.page:36 +msgid "" +"The conversation list displays a list of conversations in the " +"selected folder. Newer conversations appear at the top." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:40 +msgid "" +"Each sender’s name appears bold if there are unread messages from that " +"sender. If a conversation has more than one message, Geary displays a count " +"of messages in the conversation." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:44 +msgid "" +"Geary does not automatically download all messages in all of your mail " +"folders. When you first visit your Inbox or any other folder, Geary " +"downloads the most recent messages in that folder. To see more messages, " +"simply scroll down the conversation list and Geary will fetch more messages " +"automatically." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:50 +msgid "" +"Some commands in Geary can act on a group of conversations. To select " +"multiple conversations, hold down the Ctrl key and click each " +"conversation in turn in the conversation list. Alternatively, click the " +"first conversation in a range, then hold down Shift and click the " +"last conversation." +msgstr "" + +#. (itstool) path: section/title +#: C/overview.page:58 +msgid "Conversation viewer" +msgstr "Перегляд спілкування" + +#. (itstool) path: section/p +#: C/overview.page:60 +msgid "" +"The conversation viewer displays all email messages in the selected " +"conversation, with the oldest message at the top." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:63 +msgid "" +"When you view a conversation, Geary collapses messages that you’ve already " +"read. Click collapsed messages to expand them. Click an expanded message’s " +"header to collapse it." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:67 +msgid "" +"Click on any of the sender’s or receiver’s names or email address for a " +"message to open the contact menu, which displays additional " +"information and options for the email address. You can to start a new " +"conversation, copy the email address to the clipboard, and search for " +"related conversations. If the email address is present in your desktop " +"address book, it will show the contact’s photo, preferred name, and whether " +"they are a favourite contact. You can also open the contact in the address " +"book. If the email address is not already present, you can choose to add " +"them to the address book, and update the remote image loading preference for " +"that address." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:79 +msgid "" +"Click the star button present on each message to mark or un-mark a message " +"as being starred. Staring a message will mark the whole conversation as " +"starred, and Geary will display the first starred message in a conversation " +"when returning to it." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:84 +msgid "" +"Click the menu button present on each message to open the message menu, which allows you to reply and forward to a specific message, update " +"which messages have been marked as read or unread, print a message, and so " +"on." +msgstr "" + +#. (itstool) path: section/p +#: C/overview.page:89 +msgid "" +"Any attachments in a message appear at the bottom of the message. Double " +"click an attachment to open it, or use the Open and Save buttons to open and " +"save selected attachments." +msgstr "" + +#. (itstool) path: page/title +#: C/preferences.page:10 +msgid "Preferences" +msgstr "Параметри" + +#. (itstool) path: page/p +#: C/preferences.page:12 +msgid "" +"Geary allows you to customise how it works via its Preferences window. To open the window, select Preferences from the application menu on the main window's toolbar. " +"You can change the following options:" +msgstr "" + +#. (itstool) path: item/title +#: C/preferences.page:19 +msgid "Automatically select next message" +msgstr "Автоматично вибирати наступний лист" + +#. (itstool) path: item/p +#: C/preferences.page:20 +msgid "" +"When this option is enabled, Geary automatically selects the latest message " +"in a folder when you enter the folder. In addition, after archiving a " +"message, Geary automatically selects an adjacent message." +msgstr "" + +#. (itstool) path: item/title +#: C/preferences.page:26 +msgid "Display conversation preview" +msgstr "Показувати попередній перегляд спілкування" + +#. (itstool) path: item/p +#: C/preferences.page:27 +msgid "" +"Enables message previews in the conversation list. Previews show the first " +"few lines of each message." +msgstr "" + +#. (itstool) path: item/title +#: C/preferences.page:31 +msgid "Use three pane view" +msgstr "Використовувати ієрархію" + +#. (itstool) path: item/p +#: C/preferences.page:32 +msgid "" +"Show the folder list, the conversation list, and the messages side-by-side-" +"by-side in three panes. If not selected, the folder list and conversation " +"list will be stacked vertically in a single pane." +msgstr "" + +#. (itstool) path: item/title +#: C/preferences.page:38 +msgid "Use single key email shortcuts" +msgstr "Використовувати єдині клавіатурні скорочення" + +#. (itstool) path: item/p +#: C/preferences.page:39 +msgid "" +"Enable keyboard shortcuts for email actions that do not require pressing " +"Ctrl. These match the shortcuts used by GMail. See for details." +msgstr "" + +#. (itstool) path: item/title +#: C/preferences.page:44 +msgid "Watch for new mail when closed" +msgstr "Шукати нові повідомлення під час закриття" + +#. (itstool) path: item/p +#: C/preferences.page:45 +msgid "" +"Geary will watch your accounts for new mail even when the main window is not " +"open. To do this, it will silently start when you log in to your computer, " +"and it will continue to run after you close all windows." +msgstr "" + +#. (itstool) path: page/title +#: C/search.page:10 +msgid "Search" +msgstr "Пошук" + +#. (itstool) path: page/p +#: C/search.page:12 +msgid "" +"Geary supports a per-account full text search. To start a search, select a " +"folder associated with the account you'd like to search against. Then click " +"the search box in the toolbar (or press CtrlS) and start typing. Results will appear after a brief delay." +msgstr "" + +#. (itstool) path: page/p +#: C/search.page:16 +msgid "" +"The full text search includes email text, email addresses (to, from, and " +"cc), subject lines and attachment filenames." +msgstr "" + +#. (itstool) path: page/p +#: C/search.page:19 +msgid "" +"Keywords that match your search are highlighted in the message view. Geary " +"will match different forms of the same word, for example searching for \"walk" +"\" will also match \"walking\" and \"walked.\"" +msgstr "" + +#. (itstool) path: section/title +#: C/search.page:23 +msgid "Search operators" +msgstr "Оператори пошуку" + +#. (itstool) path: section/p +#: C/search.page:24 +msgid "Geary supports the following operators to limit the scope of searches:" +msgstr "" + +#. (itstool) path: td/p +#: C/search.page:27 +msgid "attachment:filename" +msgstr "attachment:назва_файла" + +#. (itstool) path: td/p +#: C/search.page:28 +msgid "Finds messages with attachments whose name matches filename." +msgstr "" +"Шукає повідомлення із долученнями, у яких назва файла збігається з рядком <" +"var>назва_файла." + +#. (itstool) path: td/p +#: C/search.page:31 +msgid "bcc:recipient" +msgstr "bcc:отримувач" + +#. (itstool) path: td/p +#: C/search.page:32 +msgid "Finds messages where recipient matches email BCC fields." +msgstr "" +"Шукає повідомлення, у яких отримувач збігається із вмістом полів" +" BCC." + +#. (itstool) path: td/p +#: C/search.page:35 +msgid "body:text" +msgstr "body:текст" + +#. (itstool) path: td/p +#: C/search.page:36 +msgid "Finds messages whose body contains text." +msgstr "Знаходить повідомлення, вміст яких містить текст." + +#. (itstool) path: td/p +#: C/search.page:39 +msgid "cc:recipient" +msgstr "cc:отримувач" + +#. (itstool) path: td/p +#: C/search.page:40 +msgid "Finds messages where recipient matches email CC fields." +msgstr "" +"Шукає повідомлення, у яких отримувач збігається із вмістом полів" +" CC." + +#. (itstool) path: td/p +#: C/search.page:43 +msgid "from:sender" +msgstr "from:відправник" + +#. (itstool) path: td/p +#: C/search.page:44 +msgid "Finds messages where sender matches email From fields." +msgstr "" +"Шукає повідомлення, у яких відправник збігається із вмістом полів" +" «Від»." + +#. (itstool) path: td/p +#: C/search.page:47 +msgid "is:read" +msgstr "is:read" + +#. (itstool) path: td/p +#: C/search.page:48 +msgid "Finds messages that have been marked as read." +msgstr "Знаходить повідомлення, які було позначено як прочитані." + +#. (itstool) path: td/p +#: C/search.page:51 +msgid "is:starred" +msgstr "is:starred" + +#. (itstool) path: td/p +#: C/search.page:52 +msgid "Finds messages that have been marked as starred." +msgstr "Знаходить повідомлення, які було позначено зірочками." + +#. (itstool) path: td/p +#: C/search.page:55 +msgid "is:unread" +msgstr "is:unread" + +#. (itstool) path: td/p +#: C/search.page:56 +msgid "Finds messages that have been marked as not read." +msgstr "Знаходить повідомлення, які було позначено як непрочитані." + +#. (itstool) path: td/p +#: C/search.page:59 +msgid "subject:text" +msgstr "subject:текст" + +#. (itstool) path: td/p +#: C/search.page:60 +msgid "Finds messages whose subject contains text." +msgstr "Знаходить повідомлення, тема яких містить текст." + +#. (itstool) path: td/p +#: C/search.page:63 +msgid "to:recipient" +msgstr "to:отримувач" + +#. (itstool) path: td/p +#: C/search.page:64 +msgid "" +"Finds messages where recipient matches email To, CC, or BCC " +"fields." +msgstr "" +"Шукає повідомлення, у яких отримувач збігається із вмістом полів" +" «Кому», CC або BCC." + +#. (itstool) path: section/p +#: C/search.page:68 +msgid "" +"As a special case, the bcc, cc, from, and to operators support me as their " +"argument, which searches for the account's email address in the appropriate " +"context." +msgstr "" + +#. (itstool) path: page/title +#: C/shortcuts.page:10 +msgid "Keyboard shortcuts" +msgstr "Клавіатурні скорочення" + +#. (itstool) path: section/p +#: C/shortcuts.page:14 +msgid "" +"Geary has keyboard shortcuts for most common operations. Use the built-in " +"help to discover the full list. To open the shortcuts help, select Keyboard Shortcuts from the application menu on the " +"main window's toolbar, or using the keyboard shortcuts listed below." +msgstr "" + +#. (itstool) path: section/p +#: C/shortcuts.page:20 +msgid "" +"The following keyboard shortcuts can be used to access on-line help from " +"Geary:" +msgstr "" + +#. (itstool) path: td/p +#: C/shortcuts.page:24 +msgid "Display this online help manual" +msgstr "Показати цей підручник" + +#. (itstool) path: td/p +#: C/shortcuts.page:25 +msgid "F1" +msgstr "F1" + +#. (itstool) path: td/p +#: C/shortcuts.page:28 +msgid "Display all keyboard shortcuts" +msgstr "Показати усі клавіатурні скорочення" + +#. (itstool) path: td/p +#: C/shortcuts.page:29 +msgid "Ctrl?" +msgstr "Ctrl?" + +#. (itstool) path: section/title +#: C/shortcuts.page:37 +msgid "Single key shortcuts" +msgstr "Одноклавішні скорочення" + +#. (itstool) path: section/p +#: C/shortcuts.page:39 +msgid "" +"You can enable keyboard shortcuts for email actions that do not require " +"pressing Ctrl. These match the shortcuts used by GMail. See for details." +msgstr "" + +#. (itstool) path: section/p +#: C/shortcuts.page:43 +msgid "" +"The full list of single key shortcuts enabled by this preference can be " +"found via the keyboard shortcuts help, above." +msgstr "" + +#. (itstool) path: page/title +#: C/star.page:10 +msgid "Star a message or mark it as read/unread" +msgstr "" +"Позначення повідомлення зірочками або позначення його як" +" прочитаного/непрочитаного" + +#. (itstool) path: section/title +#: C/star.page:12 +msgid "Star messages" +msgstr "Позначення повідомлень зірочками" + +#. (itstool) path: section/p +#: C/star.page:13 +msgid "" +"You can star messages to indicate that they're important to you. To mark a " +"conversation with a star, click its star icon in the conversation list. You " +"can star an individual message by clicking the star at the upper right of " +"the message itself." +msgstr "" + +#. (itstool) path: section/p +#: C/star.page:15 +msgid "" +"With Gmail accounts, starred messages appear in the Starred folder in the " +"folder list." +msgstr "" + +#. (itstool) path: section/title +#: C/star.page:18 +msgid "Mark messages as read or unread" +msgstr "Позначення повідомлень як прочитаних або непрочитаних" + +#. (itstool) path: section/p +#: C/star.page:19 +msgid "" +"Geary marks messages as read automatically as you read them. To manually " +"toggle a conversation as read or unread, click the circle icon in the " +"conversation list." +msgstr "" + +#. (itstool) path: section/p +#: C/star.page:22 +msgid "" +"Alternately, the Mark as Unread in the Mark menu on " +"the toolbar can be used to toggle the read status of the selected " +"conversation(s)." +msgstr "" + +#. (itstool) path: section/p +#: C/star.page:25 +msgid "" +"To mark an individual message as read, select Mark as Read from " +"the dropdown menu." +msgstr "" + +#. (itstool) path: page/title +#: C/write.page:7 +msgid "Writing new email and replying" +msgstr "Написання повідомлень і відповідей" + +#. (itstool) path: section/title +#: C/write.page:10 +msgid "Composing and replying" +msgstr "Редагування повідомлень та відповідей" + +#. (itstool) path: section/p +#: C/write.page:12 +msgid "" +"To start a new email conversation, click the Compose button on the toolbar. Type the email address of the people to receive " +"the message in the To text field, and a subject " +"line in the Subject field. You can then type your " +"message in the text area below these. Once the message is read to send, " +"click Send or type CtrlEnter to send the message." +msgstr "" + +#. (itstool) path: note/title +#: C/write.page:23 +msgid "Undoing sending" +msgstr "Скасовування надсилання" + +#. (itstool) path: note/p +#: C/write.page:24 +msgid "" +"When sending an email, Geary will wait 5 seconds before delivering the " +"message. During this time, you will be able to click Undo on the pop-up notification that appears or type " +"CtrlZ to re-open the email, and make " +"more changes to it." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:32 +msgid "" +"When entering an email address in the To and Cc fields, Geary will provide suggestions from your " +"desktop address book and from previously sent and received email messages. " +"To choose one of these suggestions, simply click on it. In addition, Bcc and Reply-to fields can " +"be shown by selecting Show extended fields from " +"the formatting toolbar menu." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:41 +msgid "" +"To reply to the currently selected conversation, click one of the Reply, Reply All or Forward toolbar buttons. This will open a new reply or " +"forwarded email composer for the latest message in the conversation." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:47 +msgid "" +"When replying, the message being replied to will be quoted and copied into " +"the footer of the new reply. This can be deleted before typing a reply by " +"pressing Backspace. Alternatively, text can be selectively quoted " +"by selecting the desired text in a message and clicking Reply or Reply All, only the selected " +"text will be quoted." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:55 +msgid "" +"To reply to a specific email message, open the message menu in the top " +"corner of the message and choose Reply, Reply All or " +"Forward." +msgstr "" + +#. (itstool) path: section/title +#: C/write.page:61 +msgid "Text formatting, images and attachments" +msgstr "Форматування тексту, зображення і долучення" + +#. (itstool) path: section/p +#: C/write.page:63 +msgid "" +"Geary's email composer lets you use text styles such as bold and " +"italic, indent text to quote it and links to web pages. Simply " +"select the text and click the appropriate button on the formatting toolbar." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:68 +msgid "" +"Bulleted and numbered lists can be inserted or removed by clicking the Bulleted list and Numbered " +"list buttons on the formatting toolbar. The level of indentation of " +"list items can be adjusted using the Indent and " +"Un-indent formatting toolbar buttons." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:75 +msgid "" +"Images can be inserted into rich text messages by clicking the Insert Image button on the formatting toolbar and selecting " +"the image to attach, by dragging an image from the Files " +"application into the email body and then dropping it, or by pasting an image " +"that has been copied to the clipboard from another application." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:82 +msgid "" +"Documents, music, videos, and other files can be attached to the email by " +"clicking the Attach File button at the top of " +"the composer window and selecting the document to attach, or by dragging a " +"file from the Files application to the composer window, and " +"dropping it either on the text fields at the top of the window or on the " +"toolbar at the bottom." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:90 +msgid "" +"A number of keyboard shortcuts are available in the composer; see for details." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:93 +msgid "" +"You may specify a signature to be inserted into the footer of email in the " +"composer via the dialog." +msgstr "" + +#. (itstool) path: section/title +#: C/write.page:98 +msgid "Checking spelling" +msgstr "Перевірка правопису" + +#. (itstool) path: section/p +#: C/write.page:100 +msgid "" +"Geary supports spell-checking your composed email in one or more languages, " +"as you type. To enable spell-checking, first ensure your computer has spell-" +"check dictionaries installed for the desired languages. Consult your " +"computer's help to determine how to install dictionaries if not present." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:106 +msgid "" +"To select languages for spell-checking, click the Spell check button on the formatting toolbar, and the language " +"selection popover will appear. Click on a language in the list to toggle it " +"on or off, and click the - button to remove it " +"from the list. If a language does not appear in the list, search for it by " +"typing its name in the search box, then click the + button to add it." +msgstr "" + +#. (itstool) path: section/title +#: C/write.page:117 +msgid "Saving drafts and restoring discarded messages" +msgstr "Збереження чернеток і відновлення відкинутих повідомлень" + +#. (itstool) path: section/p +#: C/write.page:119 +msgid "" +"For mail servers that support drafts, Geary will automatically save the " +"message as you type on the server after a short delay." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:123 +msgid "" +"To edit an existing draft, select the Drafts folder in the folder " +"list, select the message, and click \"Edit Draft\" in the conversation " +"viewer." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:127 +msgid "Geary will delete the draft when you send the message." +msgstr "Geary вилучить чернетку, коли ви надішлете повідомлення." + +#. (itstool) path: note/p +#: C/write.page:130 +msgid "" +"If you save or discard a composed email, you can re-open it by clicking Undo on the pop-up notification that appears or by " +"typing CtrlZ. The ability to restore " +"a saved or discarded composer will be remain for up to 30 minutes. After " +"that you will need to re-open the message via the Drafts folder, " +"if present." +msgstr "" + +#. (itstool) path: section/title +#: C/write.page:141 +msgid "Plain text messages" +msgstr "Звичайні текстові повідомлення" + +#. (itstool) path: section/p +#: C/write.page:143 +msgid "" +"Geary can also send plain text messages. In the drop-down menu, check or " +"uncheck Rich Text to toggle between plain text and " +"rich text mode. Plain text mode is useful when sending email to mailing " +"lists that prohibit rich text (HTML) messages, or when sending email to " +"people that do no use modern clients like Geary." +msgstr "" + +#. (itstool) path: section/p +#: C/write.page:150 +msgid "" +"In plain text mode, text will be automatically wrapped using soft line " +"breaks so that it is no longer than 74 characters wide, and indented text " +"will be wrapped and quoted using a “>” character for each level of " +"quoting." +msgstr "" From fa61c82f8179a100512b62472d51faeb2201d377 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Sat, 16 May 2020 14:49:48 +0000 Subject: [PATCH 38/41] Update Ukrainian translation --- po/uk.po | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/po/uk.po b/po/uk.po index 03d2eea8..fd13ad5e 100644 --- a/po/uk.po +++ b/po/uk.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: geary-0.4.1\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n" -"POT-Creation-Date: 2020-05-07 01:10+0000\n" -"PO-Revision-Date: 2020-05-07 08:50+0300\n" +"POT-Creation-Date: 2020-05-14 15:06+0000\n" +"PO-Revision-Date: 2020-05-16 17:48+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -793,7 +793,7 @@ msgstr "Зберігати чернетки пошти на сервері" #. preference. #: src/client/accounts/accounts-editor-servers-pane.vala:666 msgid "Save sent email on server" -msgstr "Зберігати надіслано пошту на сервері" +msgstr "Зберігати надіслану пошту на сервері" #. Add a suffix for OAuth2 auth so people know they #. shouldn't expect to be prompted for a password @@ -1330,7 +1330,7 @@ msgstr "%s (%d)" #. Document (100.9MB) #. / In the composer, the filename followed by its filesize, i.e. "notes.txt (1.12KB)" #: src/client/components/components-attachment-pane.vala:107 -#: src/client/composer/composer-widget.vala:1918 +#: src/client/composer/composer-widget.vala:1920 #, c-format msgid "%s (%s)" msgstr "%s (%s)" @@ -1748,63 +1748,63 @@ msgstr "Надіслати лист без тексту?" msgid "Send message without an attachment?" msgstr "Надіслати лист без долучень?" -#: src/client/composer/composer-widget.vala:1904 +#: src/client/composer/composer-widget.vala:1906 #, c-format msgid "“%s” already attached for delivery." msgstr "«%s» уже долучено для доставлення." -#: src/client/composer/composer-widget.vala:1940 -#: src/client/composer/composer-widget.vala:1990 +#: src/client/composer/composer-widget.vala:1942 +#: src/client/composer/composer-widget.vala:1992 #, c-format msgid "“%s” is an empty file." msgstr "«%s» — порожній файл." -#: src/client/composer/composer-widget.vala:1978 +#: src/client/composer/composer-widget.vala:1980 #, c-format msgid "“%s” could not be found." msgstr "Не вдалося знайти «%s»." -#: src/client/composer/composer-widget.vala:1984 +#: src/client/composer/composer-widget.vala:1986 #, c-format msgid "“%s” is a folder." msgstr "«%s» — тека." -#: src/client/composer/composer-widget.vala:2003 +#: src/client/composer/composer-widget.vala:2005 #, c-format msgid "“%s” could not be opened for reading." msgstr "Не вдалося відкрити «%s» для читання." -#: src/client/composer/composer-widget.vala:2011 +#: src/client/composer/composer-widget.vala:2013 msgid "Cannot add attachment" msgstr "Неможливо додати долучення" #. Translators: Human-readable version of the RFC 822 To header -#: src/client/composer/composer-widget.vala:2071 +#: src/client/composer/composer-widget.vala:2073 #: src/client/conversation-viewer/conversation-email.vala:542 #: src/client/util/util-email.vala:236 ui/conversation-message.ui:312 msgid "To:" msgstr "Кому:" #. Translators: Human-readable version of the RFC 822 CC header -#: src/client/composer/composer-widget.vala:2077 +#: src/client/composer/composer-widget.vala:2079 #: src/client/conversation-viewer/conversation-email.vala:547 #: src/client/util/util-email.vala:241 ui/conversation-message.ui:357 msgid "Cc:" msgstr "Копія:" #. Translators: Human-readable version of the RFC 822 BCC header -#: src/client/composer/composer-widget.vala:2083 +#: src/client/composer/composer-widget.vala:2085 #: src/client/conversation-viewer/conversation-email.vala:552 #: ui/conversation-message.ui:402 msgid "Bcc:" msgstr "Потайна копія:" #. Translators: Human-readable version of the RFC 822 Reply-To header -#: src/client/composer/composer-widget.vala:2089 +#: src/client/composer/composer-widget.vala:2091 msgid "Reply-To: " msgstr "Відповісти:" -#: src/client/composer/composer-widget.vala:2341 +#: src/client/composer/composer-widget.vala:2343 msgid "Select Color" msgstr "Вибрати колір" @@ -1813,14 +1813,14 @@ msgstr "Вибрати колір" #. printf argument will be the alternate email address, #. and the second will be the account's primary email #. address. -#: src/client/composer/composer-widget.vala:2530 +#: src/client/composer/composer-widget.vala:2532 #, c-format msgid "%1$s via %2$s" msgstr "%1$s через %2$s" #. Translators: This is the name of the file chooser filter #. when inserting an image in the composer. -#: src/client/composer/composer-widget.vala:2887 +#: src/client/composer/composer-widget.vala:2889 msgid "Images" msgstr "Зображення" @@ -2792,17 +2792,17 @@ msgstr "Вилучені записи" msgid "Archive | Archives" msgstr "Архів | Архіви | Archive | Archives" -#: src/engine/rfc822/rfc822-message.vala:461 +#: src/engine/rfc822/rfc822-message.vala:531 #, c-format msgid "Could not determine mime type for “%s”." msgstr "Не вдалося визначити тип MIME для «%s»." -#: src/engine/rfc822/rfc822-message.vala:472 +#: src/engine/rfc822/rfc822-message.vala:542 #, c-format msgid "Could not determine content type for mime type “%s” on “%s”." msgstr "Не вдалося визначити тип даних для типу MIME «%s» у «%s»." -#: src/engine/rfc822/rfc822-message.vala:1003 +#: src/engine/rfc822/rfc822-message.vala:1001 msgid "(no subject)" msgstr "(без теми)" @@ -3586,14 +3586,10 @@ msgid "Focus next/previous message" msgstr "Фокусувати наступне або попереднє повідомлення" #: ui/gtk/help-overlay.ui:260 -#| msgctxt "shortcut window" -#| msgid "Single-key shortcuts" msgid "Single-key Shortcuts" msgstr "Одноклавішні скорочення" #: ui/gtk/help-overlay.ui:265 -#| msgctxt "shortcut window" -#| msgid "Single-key shortcuts" msgctxt "shortcut window" msgid "Single-key shortcuts (if enabled)" msgstr "Одноклавішні скорочення (якщо увімкнено)" @@ -3771,7 +3767,3 @@ msgstr "_Засвідчення" #: ui/upgrade_dialog.glade:60 msgid "Geary update in progress…" msgstr "Виконується оновлення…" - -#~ msgctxt "shortcut window" -#~ msgid "Find in current conversations" -#~ msgstr "Знайти у поточних спілкуваннях" From 5bcb9f6278ec4dcba8185b7a011fd2fdc7c5ee03 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Sat, 16 May 2020 17:38:50 +0000 Subject: [PATCH 39/41] Update Ukrainian translation --- help/uk/uk.po | 166 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/help/uk/uk.po b/help/uk/uk.po index 35add2f5..0acb1f14 100644 --- a/help/uk/uk.po +++ b/help/uk/uk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: geary mainline\n" "POT-Creation-Date: 2020-05-14 15:06+0000\n" -"PO-Revision-Date: 2020-05-16 17:46+0300\n" +"PO-Revision-Date: 2020-05-16 20:37+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "MIME-Version: 1.0\n" @@ -191,6 +191,10 @@ msgid "" "Settings must also be removed from there. To do so, open Online " "Accounts, select the account, and click Remove." msgstr "" +"Облікові записи, як додано за допомогою панелі Мережеві записи <" +"app>Параметрів GNOME, слід і вилучати за допомогою цієї ж панелі. Для" +" цього відкрийте вікно Мережевих записів, виберіть пункт" +" облікового запису і натисніть кнопку Вилучити." #. (itstool) path: section/p #: C/accounts.page:90 @@ -203,6 +207,15 @@ msgid "" "Undo in the popup notification, or by typing CtrlU." msgstr "" +"Щоб вилучити обліковий запис, який було додано за допомогою Geary, відкрийте" +" вікно редактора облікових записів і виберіть пункт облікового запису, який" +" слід вилучити. Geary покаже параметри облікового запису. Виконайте гортання" +" до нижньої частини сторінки і натисніть кнопку Вилучити обліковий" +" запис. Програма попросить вас підтвердити вилучення облікового запису." +" Після підтвердження вилучення, якщо ви передумаєте, ви зможете скасувати" +" вилучення натисканням кнопки Скасувати на панелі контекстного" +" сповіщення або натисканням комбінації клавіш CtrlU." #. (itstool) path: page/title #: C/archive.page:8 @@ -219,6 +232,12 @@ msgid "" "services, or to All Mail for GMail. Archiving helps keep your " "email organised by moving old and replied-to email out of the way." msgstr "" +"Geary надає вам змогу архівувати повідомлення, якщо на вашому сервері" +" передбачено підтримку архівування. Натискання кнопки Архівувати на панелі інструментів пересуває спілкування з поточної" +" теки до теки Архів на більшості служб електронної пошти або до" +" теки Уся пошта на GMail. Архівування допоможе вам упорядкувати" +" повідомлення, усунувши старі і оброблені повідомлення із робочих тек." #. (itstool) path: page/p #: C/archive.page:17 @@ -230,6 +249,13 @@ msgid "" "or open the conversation in the Trash folder and click Delete there." msgstr "" +"Щоб пересунути спілкування до теки Смітник, позначте його і" +" натисніть кнопку Смітник на панелі інструментів." +" Щоб остаточно вилучити спілкування, утримуйте натиснутою клавішу Shift<" +"/key> і натисніть кнопку Вилучити, яку буде" +" показано на місці кнопки Смітник, або відкрийте спілкування у" +" теці Смітник і натисніть кнопку Вилучити<" +"/gui> там." #. (itstool) path: note/title #: C/archive.page:26 @@ -244,6 +270,12 @@ msgid "" "that appears, or type CtrlZ, or open " "the folder, find the message, then move it back to your Inbox" msgstr "" +"Зауважте, що ви завжди можете скасувати архівування або пересування" +" повідомлення до смітника, якщо передумаєте. Натисніть кнопку Скасувати на контекстні панелі сповіщення, яке буде" +" показано, або натисніть комбінацію клавіш CtrlZ, або відкрийте теку, знайдіть повідомлення, а потім пересуньте" +" його назад до вашої теки Вхідні" #. (itstool) path: page/p #: C/archive.page:34 @@ -256,6 +288,13 @@ msgid "" "to be hidden from , and they will likely be deleted " "in the future." msgstr "" +"Хоча обидві кнопки Вилучити і Смітник вилучають спілкування з вашої теки Вхідні, є істотна відмінність. Натискання кнопки Архівувати зберігає ваш обмін повідомленнями — у ньому згодом можна" +" виконувати пошук. Натискання кнопки Смітник" +" призведе до приховування повідомлень з можливості ," +" ці повідомлення, ймовірно, буде надалі вилучено." #. (itstool) path: page/title #: C/bugs.page:10 @@ -269,6 +308,9 @@ msgid "" "gnome.org/Apps/Geary/Contact\">get in touch about it so it can be " "fixed." msgstr "" +"Якщо вам здається, що вами виявлено ваду у Geary, будь ласка, зв'яжіться із нами" +" щодо вади, щоб ми могли її виправити." #. (itstool) path: page/p #: C/bugs.page:16 @@ -276,6 +318,8 @@ msgid "" "To help diagnose the problem as fast as possible, please include the " "following information:" msgstr "" +"Щоб ми могли знайти причину проблеми якомога швидше, будь ласка, вкажіть такі" +" дані:" #. (itstool) path: item/p #: C/bugs.page:20 @@ -439,6 +483,9 @@ msgid "" "labels correspond to labels in Gmail, or ordinary folders in other mail " "services." msgstr "" +"Geary надає вам змогу призначити одну або декілька міток до кожного" +" спілкування. Мітки Geary відповідають міткам у Gmail або звичайним текам у" +" інших службах електронної пошти." #. (itstool) path: section/p #: C/label.page:15 @@ -446,6 +493,8 @@ msgid "" "To label one or more conversations, first select the conversation(s), then " "do either of the following:" msgstr "" +"Щоб позначити міткою одне або декілька спілкувань, спершу позначте" +" спілкування, а потім виконайте одну з таких дій:" #. (itstool) path: item/p #: C/label.page:18 @@ -453,6 +502,8 @@ msgid "" "Click the Label button on the toolbar and select a label from the " "resulting drop-down menu." msgstr "" +"Натисніть кнопку Мітка на панелі інструментів і виберіть мітку із" +" показаного програмою спадного меню." #. (itstool) path: item/p #: C/label.page:20 @@ -460,6 +511,8 @@ msgid "" "Hold down the Ctrl key and drag the conversation(s) from the " "conversation list to the label in the sidebar." msgstr "" +"Натисніть і утримуйте клавішу Ctrl, перетягніть спілкування зі" +" списку спілкувань на мітку на бічній панелі." #. (itstool) path: section/title #: C/label.page:25 @@ -472,6 +525,8 @@ msgid "" "To move one or more conversations to a folder or label, first select the " "conversation(s), then do either of the following:" msgstr "" +"Щоб пересунути одне або декілька спілкувань до теки або мітки, спершу" +" позначте спілкування, а потім виконайте одну з таких дій:" #. (itstool) path: item/p #: C/label.page:29 @@ -479,6 +534,8 @@ msgid "" "Click the Move button on the toolbar and select a folder or label " "from the resulting drop-down menu." msgstr "" +"Натисніть кнопку Пересунути на панелі інструментів і виберіть теку" +" або мітку із показаного спадного меню." #. (itstool) path: item/p #: C/label.page:31 @@ -486,6 +543,8 @@ msgid "" "Drag the conversation(s) from the conversation list to the folder or label " "in the sidebar." msgstr "" +"Перетягніть спілкування зі списку спілкувань до теки або мітки на бічній" +" панелі." #. (itstool) path: page/title #: C/limits.page:9 @@ -501,6 +560,11 @@ msgid "" "servers. At this time Geary is still missing numerous features including " "offline mode." msgstr "" +"Geary усе ще перебуває у стані початкової розробки. У Geary передбачено" +" підтримку IMAP, яку було перевірено для Gmail, Yahoo і вільного поштового" +" сервера Dovecot. Надається експериментальна підтримка Outlook.com. Поточна" +" версія Geary може не працювати із деякими серверами IMAP. На сьогодні, у" +" Geary ще не реалізовано багато можливостей, зокрема автономний режим." #. (itstool) path: page/p #: C/limits.page:17 @@ -509,6 +573,9 @@ msgid "" "please visit Geary's wiki " "page." msgstr "" +"Щоб дізнатися більше про можливості, над якими ми працюємо, та майбутнє" +" Geary, будь ласка, відвідайте сторінку вікі Geary." #. (itstool) path: page/title #. (itstool) path: section/title @@ -534,6 +601,8 @@ msgid "" "Conversations allow you to read a complete discussion without having to find " "and click from message to message." msgstr "" +"Спілкування надають вам змогу читати усе обговорення без пошуку і переходу" +" між окремими повідомленнями." #. (itstool) path: page/p #: C/overview.page:18 @@ -541,6 +610,8 @@ msgid "" "The main Geary window is divided into several areas: The folder list, the " "conversation list, and the conversation viewer." msgstr "" +"Головне вікно Geary поділено на декілька областей: список тек, список" +" спілкувань та панель перегляду спілкування." #. (itstool) path: section/title #: C/overview.page:22 @@ -554,6 +625,10 @@ msgid "" "for your email accounts. Geary uses the term label for any folder " "that you have created to organize your email messages." msgstr "" +"У списку тек буде показано усі теки і мітки для" +" ваших облікових записів електронної пошти. У Geary термін мітка" +" використовується для будь-якої теки, яку було створено для упорядковування" +" ваших повідомлень електронної пошти." #. (itstool) path: section/p #: C/overview.page:29 @@ -561,6 +636,8 @@ msgid "" "Select a folder or label to display the conversations it contains in the " "conversation list." msgstr "" +"Виберіть теку або мітку, щоб переглянути спілкування, які у ній містяться, у" +" списку спілкувань." #. (itstool) path: section/title #: C/overview.page:34 @@ -573,6 +650,8 @@ msgid "" "The conversation list displays a list of conversations in the " "selected folder. Newer conversations appear at the top." msgstr "" +"У списку спілкувань буде показано список спілкувань у позначеній" +" теці. Новіші спілкування буде показано на початку списку." #. (itstool) path: section/p #: C/overview.page:40 @@ -581,6 +660,9 @@ msgid "" "sender. If a conversation has more than one message, Geary displays a count " "of messages in the conversation." msgstr "" +"Пункт відправника буде показано напівжирним, якщо існують непрочитані" +" повідомлення цього відправника. Якщо у спілкуванні декілька повідомлень," +" Geary покаже кількість повідомлень у спілкуванні." #. (itstool) path: section/p #: C/overview.page:44 @@ -591,6 +673,11 @@ msgid "" "simply scroll down the conversation list and Geary will fetch more messages " "automatically." msgstr "" +"Geary не виконує автоматичного отримання усіх повідомлень у всіх ваших теках" +" пошти. Коли ви вперше відкриєте вашу теку «Вхідні» або будь-яку іншу теку," +" Geary отримає найсвіжіші повідомлення у цій теці. Щоб переглянути інші" +" повідомлення, просто виконайте гортання списку повідомлень і Geary отримає" +" додаткові повідомлення автоматично." #. (itstool) path: section/p #: C/overview.page:50 @@ -601,6 +688,12 @@ msgid "" "first conversation in a range, then hold down Shift and click the " "last conversation." msgstr "" +"Деякі команди у Geary можуть виконуватися над групою спілкувань. Щоб" +" позначити декілька спілкувань, натисніть і утримуйте натиснутою клавішу Ctrl, а потім клацайте на кожному спілкуванні у списку спілкувань." +" Крім того, ви можете клацнути на першому зі спілкувань у діапазоні, далі" +" натисніть і утримуйте клавішу Shift і клацніть на останньому зі" +" спілкувань у діапазоні." #. (itstool) path: section/title #: C/overview.page:58 @@ -613,6 +706,9 @@ msgid "" "The conversation viewer displays all email messages in the selected " "conversation, with the oldest message at the top." msgstr "" +"На панелі перегляду спілкувань буде показано усі повідомлення" +" електронної пошти у позначеному спілкуванні. Найстаріше повідомлення буде" +" показано на початку списку." #. (itstool) path: section/p #: C/overview.page:63 @@ -621,6 +717,9 @@ msgid "" "read. Click collapsed messages to expand them. Click an expanded message’s " "header to collapse it." msgstr "" +"При перегляді спілкування Geary згортає повідомлення, які було вже прочитано." +" Клацніть на згорнутих повідомленнях, щоб розгорнути їх. Натисніть на" +" розгорнутому повідомленні, щоб згорнути його." #. (itstool) path: section/p #: C/overview.page:67 @@ -636,6 +735,17 @@ msgid "" "them to the address book, and update the remote image loading preference for " "that address." msgstr "" +"Клацніть на будь-якому із імен або адрес електронної пошти відправників або" +" отримувачів повідомлення, щоб відкрити меню контакту, у якому буде" +" показано додаткові відомості та пункти дій, пов'язані із адресою електронної" +" пошти. Ви можете розпочати нове спілкування, скопіювати адресу електронної" +" пошти до буфера обміну даними і виконати пошук пов'язаних спілкувань. Якщо" +" адреса електронної пошти є у адресній книзі вашого стільничного середовища," +" буде показано фотографію контакту, бажане ім'я і те, чи є запис контакту" +" вибраним (улюбленим). Ви також зможете відкрити запис контакту у адресній" +" книзі. Якщо запису контакту ще немає в адресній книзі, ви зможете його" +" додати до адресної книги і оновити параметри завантаження віддалених" +" зображень для відповідної адреси." #. (itstool) path: section/p #: C/overview.page:79 @@ -645,6 +755,11 @@ msgid "" "starred, and Geary will display the first starred message in a conversation " "when returning to it." msgstr "" +"Клацніть на кнопці зірки, яку буде показано для кожного зображення, щоб" +" позначити повідомлення зіркою або зняти з нього позначення. Позначення" +" повідомлення зіркою призведе до позначення зіркою усього спілкування, —" +" Geary покаже перше повідомлення з зіркою у спілкуванні, коли повернетеся до" +" його читання." #. (itstool) path: section/p #: C/overview.page:84 @@ -654,6 +769,10 @@ msgid "" "which messages have been marked as read or unread, print a message, and so " "on." msgstr "" +"Натисніть кнопку меню будь-якого з повідомлень, щоб відкрити меню" +" повідомлення. За допомогою цього меню ви зможете відповідати на" +" повідомлення і переспрямовувати його, оновлювати стан повідомлення" +" (прочитане чи непрочитане), надрукувати повідомлення тощо." #. (itstool) path: section/p #: C/overview.page:89 @@ -662,6 +781,10 @@ msgid "" "click an attachment to open it, or use the Open and Save buttons to open and " "save selected attachments." msgstr "" +"Усі долучення до повідомлення буде показано у нижній частині панелі" +" повідомлення. Двічі клацніть на долученні, щоб відкрити долучення, або" +" скористайтеся кнопками «Відкрити» і «Зберегти», щоб відкрити чи зберегти" +" позначені долучення." #. (itstool) path: page/title #: C/preferences.page:10 @@ -676,6 +799,11 @@ msgid "" "\">Preferences from the application menu on the main window's toolbar. " "You can change the following options:" msgstr "" +"Роботу Geary можна налаштувaти за допомогою вікна Параметри. Щоб відкрити повідомлення, виберіть пункт Параметри з меню програми на панелі інструментів головного вікна" +" програми. Ви можете змінити такі параметри:" #. (itstool) path: item/title #: C/preferences.page:19 @@ -689,6 +817,9 @@ msgid "" "in a folder when you enter the folder. In addition, after archiving a " "message, Geary automatically selects an adjacent message." msgstr "" +"Якщо позначено цей пункт, після входу до теки Geary автоматично вибирає" +" найсвіжіше повідомлення у теці. Крім того, після архівування повідомлення" +" Geary автоматично позначає сусідні повідомлення." #. (itstool) path: item/title #: C/preferences.page:26 @@ -701,6 +832,9 @@ msgid "" "Enables message previews in the conversation list. Previews show the first " "few lines of each message." msgstr "" +"Вмикає попередній перегляд повідомлень у списку спілкувань. На панелі" +" попереднього перегляду буде показано перші декілька рядків кожного" +" повідомлення." #. (itstool) path: item/title #: C/preferences.page:31 @@ -714,6 +848,9 @@ msgid "" "by-side in three panes. If not selected, the folder list and conversation " "list will be stacked vertically in a single pane." msgstr "" +"Показати список повідомлень, список повідомлень і повідомлення паралельно на" +" трьох панелях. Якщо пункт не позначено, список тек і список спілкувань буде" +" показано один над одним на одній панелі." #. (itstool) path: item/title #: C/preferences.page:38 @@ -727,6 +864,9 @@ msgid "" "Ctrl. These match the shortcuts used by GMail. See for details." msgstr "" +"Увімкнути ті клавіатурні скорочення для дій з повідомленням, які не" +" потребують натискання клавіші Ctrl. Ці клавіатурні скорочення" +" використовуються у GMail. Докладніше про це тут: ." #. (itstool) path: item/title #: C/preferences.page:44 @@ -740,6 +880,10 @@ msgid "" "open. To do this, it will silently start when you log in to your computer, " "and it will continue to run after you close all windows." msgstr "" +"Geary виконуватиме пошук нових повідомлень на ваших облікових записах, якщо" +" головне вікно програми не буде відкрито. Для цього програму буде без" +" запитань запущено під час входу до вашого облікового запису на комп'ютері." +" Програма продовжуватиме працювати, навіть якщо ви закриєте усі її вікна." #. (itstool) path: page/title #: C/search.page:10 @@ -754,6 +898,12 @@ msgid "" "the search box in the toolbar (or press CtrlS) and start typing. Results will appear after a brief delay." msgstr "" +"У Geary передбачено повнотекстовий пошук для окремих облікових записів. Щоб" +" розпочати пошук, позначте теку, пов'язану із обліковим записом, на якому ви" +" хочете виконати пошук. Далі, клацніть на смужці пошуку на панелі" +" інструментів програми (або натисніть комбінацію клавіш Ctrl<" +"/key>S) і почніть вводити критерій пошуку. Результати" +" буде показано після короткої затримки." #. (itstool) path: page/p #: C/search.page:16 @@ -761,6 +911,9 @@ msgid "" "The full text search includes email text, email addresses (to, from, and " "cc), subject lines and attachment filenames." msgstr "" +"До повнотекстового пошуку буде включено текст повідомлень електронної пошти," +" адреси електронної пошти (кому, від і копія), рядки теми та назви файлів" +" долучень." #. (itstool) path: page/p #: C/search.page:19 @@ -769,6 +922,10 @@ msgid "" "will match different forms of the same word, for example searching for \"walk" "\" will also match \"walking\" and \"walked.\"" msgstr "" +"Ключові слова, які збігатимуться із критерієм пошуку, буде підсвічено на" +" панелі повідомлень. Крім того, Geary встановлюватиме відповідність із" +" різними формами того самого слова. Наприклад, якщо ви шукатимете «walk»," +" буде знайдено і слова «walking» та «walked»." #. (itstool) path: section/title #: C/search.page:23 @@ -779,6 +936,7 @@ msgstr "Оператори пошуку" #: C/search.page:24 msgid "Geary supports the following operators to limit the scope of searches:" msgstr "" +"У Geary передбачено підтримку таких операторів для обмеження області пошуку:" #. (itstool) path: td/p #: C/search.page:27 @@ -921,6 +1079,8 @@ msgid "" "The following keyboard shortcuts can be used to access on-line help from " "Geary:" msgstr "" +"Для доступу до інтерактивної довідки з вікна Geary можна скористатися такими" +" комбінаціями клавіш:" #. (itstool) path: td/p #: C/shortcuts.page:24 @@ -954,6 +1114,10 @@ msgid "" "pressing Ctrl. These match the shortcuts used by GMail. See for details." msgstr "" +"Ви можете увімкнути ті клавіатурні скорочення для дій з повідомленням, які не" +" потребують натискання клавіші Ctrl. Ці клавіатурні скорочення" +" використовуються у GMail. Докладніше про це тут: ." #. (itstool) path: section/p #: C/shortcuts.page:43 From 4287d0bd8d7d7352b25416f9508cc5cca49f2533 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Sat, 16 May 2020 21:01:26 +0000 Subject: [PATCH 40/41] Update Ukrainian translation --- help/uk/uk.po | 92 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/help/uk/uk.po b/help/uk/uk.po index 0acb1f14..b9c3b95a 100644 --- a/help/uk/uk.po +++ b/help/uk/uk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: geary mainline\n" "POT-Creation-Date: 2020-05-14 15:06+0000\n" -"PO-Revision-Date: 2020-05-16 20:37+0300\n" +"PO-Revision-Date: 2020-05-16 23:51+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "MIME-Version: 1.0\n" @@ -982,7 +982,7 @@ msgstr "cc:отримувач" msgid "Finds messages where recipient matches email CC fields." msgstr "" "Шукає повідомлення, у яких отримувач збігається із вмістом полів" -" CC." +" «Копія»." #. (itstool) path: td/p #: C/search.page:43 @@ -1058,6 +1058,11 @@ msgid "" "argument, which searches for the account's email address in the appropriate " "context." msgstr "" +"Особливим випадком для операторів bcc, cc, <" +"input>from і to є значення аргументу me," +" використання якого надає змогу шукати адресу електронної пошти облікового" +" запису у відповідному контексті." #. (itstool) path: page/title #: C/shortcuts.page:10 @@ -1072,6 +1077,12 @@ msgid "" "style=\"menuitem\">Keyboard Shortcuts from the application menu on the " "main window's toolbar, or using the keyboard shortcuts listed below." msgstr "" +"У Geary передбачено клавіатурні скорочення для типових операцій." +" Скористайтеся вбудованою довідкою для ознайомлення із повним списком. Щоб" +" відкрити довідку з клавіатурних скорочень, виберіть пункт Клавіатурні скорочення у меню програми на панелі" +" інструментів головного вікна або скористайтеся клавіатурними скороченнями із" +" наведеного нижче списку." #. (itstool) path: section/p #: C/shortcuts.page:20 @@ -1125,6 +1136,9 @@ msgid "" "The full list of single key shortcuts enabled by this preference can be " "found via the keyboard shortcuts help, above." msgstr "" +"Із повним списком одноклавішних скорочень, які вмикаються цим пунктом, можна" +" ознайомитися у довідці з клавіатурних скорочень, доступ до якої можна" +" отримати в описаний вище спосіб." #. (itstool) path: page/title #: C/star.page:10 @@ -1146,6 +1160,11 @@ msgid "" "can star an individual message by clicking the star at the upper right of " "the message itself." msgstr "" +"Ви можете позначити повідомлення зірочкою, щоб вказати важливість" +" повідомлення для вас. Щоб позначити спілкування зірочкою, клацніть на" +" піктограмі із зірочкою у списку спілкувань. Ви можете позначити зірочкою" +" окреме повідомлення, натиснувши кнопку із зірочкою у верхньому правому куті" +" повідомлення." #. (itstool) path: section/p #: C/star.page:15 @@ -1153,6 +1172,8 @@ msgid "" "With Gmail accounts, starred messages appear in the Starred folder in the " "folder list." msgstr "" +"На облікових записах Gmail повідомлення із зірочкою потрапляють до теки" +" «Зірочки» у списку тек." #. (itstool) path: section/title #: C/star.page:18 @@ -1166,6 +1187,9 @@ msgid "" "toggle a conversation as read or unread, click the circle icon in the " "conversation list." msgstr "" +"Geary автоматично позначає повідомлення як прочитані, якщо ви їх читаєте. Щоб" +" вказати спілкування як прочитане або непрочитане вручну, натисніть" +" піктограму з колом у списку спілкувань." #. (itstool) path: section/p #: C/star.page:22 @@ -1174,6 +1198,9 @@ msgid "" "the toolbar can be used to toggle the read status of the selected " "conversation(s)." msgstr "" +"Крім того, ви можете скористатися пунктом Позначити як непрочитане" +" у меню Позначення на панелі інструментів для перемикання стану" +" позначеного спілкування." #. (itstool) path: section/p #: C/star.page:25 @@ -1181,6 +1208,8 @@ msgid "" "To mark an individual message as read, select Mark as Read from " "the dropdown menu." msgstr "" +"Щоб позначити окреме повідомлення як прочитане, виберіть пункт Позначити" +" як прочитане у спадному меню." #. (itstool) path: page/title #: C/write.page:7 @@ -1203,6 +1232,15 @@ msgid "" "click Send or type CtrlEnter to send the message." msgstr "" +"Щоб розпочати нове спілкування електронною поштою, натисніть кнопку Нове повідомлення на панелі інструментів. Введіть" +" адресу електронної пошти отримувача повідомлення у поле Кому і тему повідомлення у поле Тема. Далі," +" ви можете ввести повідомлення до текстового поля, яке розташовано під цими" +" двома полями. Коли повідомлення буде готове до надсилання, натисніть кнопку" +" Надіслати або натисніть комбінацію клавіш <" +"keyseq>CtrlEnter, щоб його надіслати." #. (itstool) path: note/title #: C/write.page:23 @@ -1218,6 +1256,12 @@ msgid "" "CtrlZ to re-open the email, and make " "more changes to it." msgstr "" +"При надсиланні повідомлення електронної пошти Geary очікує 5 секунд перед" +" відправлення повідомлення. Протягом цього часу ви зможете натиснути кнопку <" +"gui style=\"button\">Скасувати на контекстній панелі сповіщення, яку" +" буде показано, або натиснути комбінацію клавіш CtrlZ для повторного відкриття повідомлення для внесення до нього" +" додаткових змін." #. (itstool) path: section/p #: C/write.page:32 @@ -1230,6 +1274,14 @@ msgid "" "be shown by selecting Show extended fields from " "the formatting toolbar menu." msgstr "" +"При введення адреси електронної пошти у поля Кому" +" і Копія Geary надаватиме пропозиції із адресної" +" книги вашого стільничного середовища та адрес у раніше надісланих і" +" отриманих повідомленнях електронної пошти. Щоб вибрати одну з пропозицій," +" просто клацніть на ній. Крім того, може бути показано поля Потайна копія і Відповідати." +" Для цього слід вибрати пункт Показувати додаткові поля<" +"/gui> з меню форматування на панелі інструментів." #. (itstool) path: section/p #: C/write.page:41 @@ -1239,6 +1291,11 @@ msgid "" "\"button\">Forward toolbar buttons. This will open a new reply or " "forwarded email composer for the latest message in the conversation." msgstr "" +"Щоб відповісти до поточного позначеного спілкування, натисніть на панелі" +" інструментів одну з таких кнопок: Відповісти, <" +"gui style=\"button\">Відповісти всім або Переспрямувати. У відповідь буде відкритого вікно редактора відповіді" +" або переспрямованого повідомлення для останнього повідомлення у спілкуванні." #. (itstool) path: section/p #: C/write.page:47 @@ -1250,6 +1307,13 @@ msgid "" "\">Reply or Reply All, only the selected " "text will be quoted." msgstr "" +"При відповіді на повідомлення початкове повідомлення буде процитовано і" +" скопійовано у нижню частину відповіді. Цю частину повідомлення можна" +" вилучити до введення відповіді натисканням клавіші Backspace." +" Крім того, текст можна вибірково процитувати позначенням бажаного фрагмента" +" тексту у повідомленні із наступним натисканням кнопки Відповісти або Відповісти усім —" +" процитовано буде лише позначений фрагмент тексту." #. (itstool) path: section/p #: C/write.page:55 @@ -1258,6 +1322,9 @@ msgid "" "corner of the message and choose Reply, Reply All or " "Forward." msgstr "" +"Щоб відповісти на певне повідомлення електронної пошти, відкрийте меню" +" повідомлення у верхньому куті повідомлення і виберіть пункт Відповісти<" +"/gui>, Відповісти усім або Переспрямувати." #. (itstool) path: section/title #: C/write.page:61 @@ -1271,6 +1338,10 @@ msgid "" "italic, indent text to quote it and links to web pages. Simply " "select the text and click the appropriate button on the formatting toolbar." msgstr "" +"У редакторі повідомлень Geary ви можете скористатися стилями тексту, зокрема" +" напівжирним та курсивом, відступами тексту для цитування" +" та посиланнями на вебсторінки. Просто позначте фрагмент тексту і натисніть" +" відповідну кнопку на панелі інструментів форматування." #. (itstool) path: section/p #: C/write.page:68 @@ -1281,6 +1352,14 @@ msgid "" "list items can be adjusted using the Indent and " "Un-indent formatting toolbar buttons." msgstr "" +"Неупорядковані та упорядковані списки можна вставити або вилучити за" +" допомогою натискання кнопок Вставити неупорядкований список та Вставити упорядкований список на панелі інструментів" +" форматування. Рівень відступів у списку можна скоригувати за допомогою" +" кнопок панелі інструментів форматування Додати" +" відступи або цитування тексту та Скасувати" +" відступи або цитування тексту." #. (itstool) path: section/p #: C/write.page:75 @@ -1291,6 +1370,12 @@ msgid "" "application into the email body and then dropping it, or by pasting an image " "that has been copied to the clipboard from another application." msgstr "" +"Зображення можна вставити до повідомлення із форматуванням натисканням кнопки" +" Вставити зображення на панелі інструментів" +" форматування із наступним вибором зображення для долучення, перетягуванням" +" пункту зображення з вікна програми Файли до вмісту повідомлення" +" електронної пошти із наступним його скиданням або вставленням зображення," +" яке було скопійовано до буфера обміну даних з іншої програми." #. (itstool) path: section/p #: C/write.page:82 @@ -1309,6 +1394,9 @@ msgid "" "A number of keyboard shortcuts are available in the composer; see for details." msgstr "" +"У редакторі повідомлень можна скористатися декількома клавіатурними" +" скороченнями. Докладніший опис можна знайти у розділі ." #. (itstool) path: section/p #: C/write.page:93 From 9f6484ea59e933e0aa2b152e2a4b4cd3fcea5833 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Sat, 16 May 2020 21:56:29 +0000 Subject: [PATCH 41/41] Update Ukrainian translation --- help/uk/uk.po | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/help/uk/uk.po b/help/uk/uk.po index b9c3b95a..251218e5 100644 --- a/help/uk/uk.po +++ b/help/uk/uk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: geary mainline\n" "POT-Creation-Date: 2020-05-14 15:06+0000\n" -"PO-Revision-Date: 2020-05-16 23:51+0300\n" +"PO-Revision-Date: 2020-05-17 00:55+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "MIME-Version: 1.0\n" @@ -1387,6 +1387,13 @@ msgid "" "dropping it either on the text fields at the top of the window or on the " "toolbar at the bottom." msgstr "" +"Документи, звукові файли, відео та інші файли можна долучити до повідомлення" +" електронної пошти натисканням кнопки Долучити файл<" +"/gui> у верхній частині вікна редактора повідомлень із наступним вибором" +" документа, який слід долучити, або перетягуванням пункту файла з вікна" +" програми Файли до вікна редактора повідомлень із наступним" +" скиданням його або на текстові поля у верхній частині вікна, або на панель" +" інструментів у нижній частині вікна." #. (itstool) path: section/p #: C/write.page:90 @@ -1404,6 +1411,9 @@ msgid "" "You may specify a signature to be inserted into the footer of email in the " "composer via the dialog." msgstr "" +"Ви можете вказати підпис, який слід вставити у нижню частину повідомлення" +" електронної пошти у редакторі повідомлень, за допомогою діалогового вікна <" +"link xref=\"accounts\"/>." #. (itstool) path: section/title #: C/write.page:98 @@ -1418,6 +1428,11 @@ msgid "" "check dictionaries installed for the desired languages. Consult your " "computer's help to determine how to install dictionaries if not present." msgstr "" +"У Geary передбачено підтримку перевірки правопису безпосередньо під час" +" введення редагованого повідомлення однією або декількома мовами. Щоб" +" увімкнути перевірку правопису, спочатку встановіть у вашій системі словники" +" перевірки правопису бажаними мовами. Зверніться до довідки з операційної" +" системи, щоб визначити спосіб встановлення словників, яких не вистачає." #. (itstool) path: section/p #: C/write.page:106 @@ -1430,6 +1445,14 @@ msgid "" "typing its name in the search box, then click the + button to add it." msgstr "" +"Щоб вибрати мови для перевірки правопису, натисніть кнопку Перевірка правопису на панелі інструментів" +" форматування. У відповідь буде відкрито контекстну панель вибору мови." +" Натисніть пункт мови у списку, щоб увімкнути або вимкнути перевірку" +" правопису цією мовою. Натисніть кнопку -, щоб" +" вилучити мову зі списку. Якщо пункту мови немає у списку, пошукайте пункт за" +" допомогою смужки пошуку, потім натисніть кнопку +, щоб додати пункт мови." #. (itstool) path: section/title #: C/write.page:117 @@ -1442,6 +1465,9 @@ msgid "" "For mail servers that support drafts, Geary will automatically save the " "message as you type on the server after a short delay." msgstr "" +"Якщо ви працюєте із поштовим сервером, на якому передбачено підтримку" +" чернеток, Geary автоматично зберігатиме повідомлення на сервері під час" +" введення з невеликою затримкою." #. (itstool) path: section/p #: C/write.page:123 @@ -1450,6 +1476,9 @@ msgid "" "list, select the message, and click \"Edit Draft\" in the conversation " "viewer." msgstr "" +"Щоб змінити наявну чернетку, виберіть теку Чернетки у списку тек," +" виберіть повідомлення і натисніть кнопку «Редагувати чернетку» на панелі" +" перегляду спілкування." #. (itstool) path: section/p #: C/write.page:127 @@ -1466,6 +1495,14 @@ msgid "" "that you will need to re-open the message via the Drafts folder, " "if present." msgstr "" +"Якщо ви зберегли або відкинули створене повідомлення електронної пошти, ви" +" можете повторно його відкрити натисканням кнопки Скасувати на контекстній панелі сповіщення, яку буде показано, або" +" натисканням комбінації клавіш CtrlZ." +" Можливість відновити збережене або відкинуте повідомлення зберігатиметься" +" протягом періоду до 30 хвилин. Після завершення цього періоду вам доведеться" +" повторно відкрити повідомлення з теки Чернетки, якщо його було" +" там збережено." #. (itstool) path: section/title #: C/write.page:141 @@ -1481,6 +1518,13 @@ msgid "" "lists that prohibit rich text (HTML) messages, or when sending email to " "people that do no use modern clients like Geary." msgstr "" +"Крім того, Geary може надсилати звичайні текстові повідомлення. У спадному" +" меню позначте або зніміть позначення з пункту Форматований текст, щоб перемкнутися між режимом звичайного тексту і" +" режимом форматованого тексту. Звичайний текстовий режим є корисним для" +" надсилання повідомлень до списків листування, які забороняють надсилання" +" повідомлень із форматованим текстом (HTML), або до тих користувачів, які не" +" можуть користуватися сучасними клієнтами електронної пошти, подібними Geary." #. (itstool) path: section/p #: C/write.page:150 @@ -1490,3 +1534,7 @@ msgid "" "will be wrapped and quoted using a “>” character for each level of " "quoting." msgstr "" +"У режимі звичайного тексту програма автоматично переноситиме рядки тексту з" +" використанням м'яких переносів так, щоб довжина рядків не перевищувала 74" +" символів, а текст із відступами буде перенесено із додаванням позначок" +" цитування, «>», для кожного з рівнів цитування."