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. 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..251218e5 --- /dev/null +++ b/help/uk/uk.po @@ -0,0 +1,1540 @@ +# 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-17 00:55+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 "" +"Облікові записи, як додано за допомогою панелі Мережеві записи <" +"app>Параметрів GNOME, слід і вилучати за допомогою цієї ж панелі. Для" +" цього відкрийте вікно Мережевих записів, виберіть пункт" +" облікового запису і натисніть кнопку Вилучити." + +#. (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 "" +"Щоб вилучити обліковий запис, який було додано за допомогою Geary, відкрийте" +" вікно редактора облікових записів і виберіть пункт облікового запису, який" +" слід вилучити. Geary покаже параметри облікового запису. Виконайте гортання" +" до нижньої частини сторінки і натисніть кнопку Вилучити обліковий" +" запис. Програма попросить вас підтвердити вилучення облікового запису." +" Після підтвердження вилучення, якщо ви передумаєте, ви зможете скасувати" +" вилучення натисканням кнопки Скасувати на панелі контекстного" +" сповіщення або натисканням комбінації клавіш CtrlU." + +#. (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 "" +"Geary надає вам змогу архівувати повідомлення, якщо на вашому сервері" +" передбачено підтримку архівування. Натискання кнопки Архівувати на панелі інструментів пересуває спілкування з поточної" +" теки до теки Архів на більшості служб електронної пошти або до" +" теки Уся пошта на GMail. Архівування допоможе вам упорядкувати" +" повідомлення, усунувши старі і оброблені повідомлення із робочих тек." + +#. (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 "" +"Щоб пересунути спілкування до теки Смітник, позначте його і" +" натисніть кнопку Смітник на панелі інструментів." +" Щоб остаточно вилучити спілкування, утримуйте натиснутою клавішу Shift<" +"/key> і натисніть кнопку Вилучити, яку буде" +" показано на місці кнопки Смітник, або відкрийте спілкування у" +" теці Смітник і натисніть кнопку Вилучити<" +"/gui> там." + +#. (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 "" +"Зауважте, що ви завжди можете скасувати архівування або пересування" +" повідомлення до смітника, якщо передумаєте. Натисніть кнопку Скасувати на контекстні панелі сповіщення, яке буде" +" показано, або натисніть комбінацію клавіш CtrlZ, або відкрийте теку, знайдіть повідомлення, а потім пересуньте" +" його назад до вашої теки Вхідні" + +#. (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 "" +"Якщо вам здається, що вами виявлено ваду у Geary, будь ласка, зв'яжіться із нами" +" щодо вади, щоб ми могли її виправити." + +#. (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 "" +"Geary надає вам змогу призначити одну або декілька міток до кожного" +" спілкування. Мітки Geary відповідають міткам у Gmail або звичайним текам у" +" інших службах електронної пошти." + +#. (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 "" +"Натисніть і утримуйте клавішу Ctrl, перетягніть спілкування зі" +" списку спілкувань на мітку на бічній панелі." + +#. (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 "" +"Geary усе ще перебуває у стані початкової розробки. У Geary передбачено" +" підтримку IMAP, яку було перевірено для Gmail, Yahoo і вільного поштового" +" сервера Dovecot. Надається експериментальна підтримка Outlook.com. Поточна" +" версія Geary може не працювати із деякими серверами IMAP. На сьогодні, у" +" Geary ще не реалізовано багато можливостей, зокрема автономний режим." + +#. (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 "" +"Щоб дізнатися більше про можливості, над якими ми працюємо, та майбутнє" +" Geary, будь ласка, відвідайте сторінку вікі Geary." + +#. (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 "" +"Головне вікно Geary поділено на декілька областей: список тек, список" +" спілкувань та панель перегляду спілкування." + +#. (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 "" +"У списку тек буде показано усі теки і мітки для" +" ваших облікових записів електронної пошти. У Geary термін мітка" +" використовується для будь-якої теки, яку було створено для упорядковування" +" ваших повідомлень електронної пошти." + +#. (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 "" +"Пункт відправника буде показано напівжирним, якщо існують непрочитані" +" повідомлення цього відправника. Якщо у спілкуванні декілька повідомлень," +" Geary покаже кількість повідомлень у спілкуванні." + +#. (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 "" +"Geary не виконує автоматичного отримання усіх повідомлень у всіх ваших теках" +" пошти. Коли ви вперше відкриєте вашу теку «Вхідні» або будь-яку іншу теку," +" Geary отримає найсвіжіші повідомлення у цій теці. Щоб переглянути інші" +" повідомлення, просто виконайте гортання списку повідомлень і Geary отримає" +" додаткові повідомлення автоматично." + +#. (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 "" +"Деякі команди у Geary можуть виконуватися над групою спілкувань. Щоб" +" позначити декілька спілкувань, натисніть і утримуйте натиснутою клавішу Ctrl, а потім клацайте на кожному спілкуванні у списку спілкувань." +" Крім того, ви можете клацнути на першому зі спілкувань у діапазоні, далі" +" натисніть і утримуйте клавішу Shift і клацніть на останньому зі" +" спілкувань у діапазоні." + +#. (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 "" +"При перегляді спілкування Geary згортає повідомлення, які було вже прочитано." +" Клацніть на згорнутих повідомленнях, щоб розгорнути їх. Натисніть на" +" розгорнутому повідомленні, щоб згорнути його." + +#. (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 "" +"Клацніть на кнопці зірки, яку буде показано для кожного зображення, щоб" +" позначити повідомлення зіркою або зняти з нього позначення. Позначення" +" повідомлення зіркою призведе до позначення зіркою усього спілкування, —" +" Geary покаже перше повідомлення з зіркою у спілкуванні, коли повернетеся до" +" його читання." + +#. (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 "" +"Роботу Geary можна налаштувaти за допомогою вікна Параметри. Щоб відкрити повідомлення, виберіть пункт Параметри з меню програми на панелі інструментів головного вікна" +" програми. Ви можете змінити такі параметри:" + +#. (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 "" +"Якщо позначено цей пункт, після входу до теки Geary автоматично вибирає" +" найсвіжіше повідомлення у теці. Крім того, після архівування повідомлення" +" Geary автоматично позначає сусідні повідомлення." + +#. (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 "" +"Увімкнути ті клавіатурні скорочення для дій з повідомленням, які не" +" потребують натискання клавіші Ctrl. Ці клавіатурні скорочення" +" використовуються у GMail. Докладніше про це тут: ." + +#. (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 "" +"Geary виконуватиме пошук нових повідомлень на ваших облікових записах, якщо" +" головне вікно програми не буде відкрито. Для цього програму буде без" +" запитань запущено під час входу до вашого облікового запису на комп'ютері." +" Програма продовжуватиме працювати, навіть якщо ви закриєте усі її вікна." + +#. (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 "" +"У Geary передбачено повнотекстовий пошук для окремих облікових записів. Щоб" +" розпочати пошук, позначте теку, пов'язану із обліковим записом, на якому ви" +" хочете виконати пошук. Далі, клацніть на смужці пошуку на панелі" +" інструментів програми (або натисніть комбінацію клавіш Ctrl<" +"/key>S) і почніть вводити критерій пошуку. Результати" +" буде показано після короткої затримки." + +#. (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 "" +"Ключові слова, які збігатимуться із критерієм пошуку, буде підсвічено на" +" панелі повідомлень. Крім того, Geary встановлюватиме відповідність із" +" різними формами того самого слова. Наприклад, якщо ви шукатимете «walk»," +" буде знайдено і слова «walking» та «walked»." + +#. (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 "" +"У Geary передбачено підтримку таких операторів для обмеження області пошуку:" + +#. (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 "" +"Шукає повідомлення, у яких отримувач збігається із вмістом полів" +" «Копія»." + +#. (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 "" +"Особливим випадком для операторів bcc, cc, <" +"input>from і to є значення аргументу me," +" використання якого надає змогу шукати адресу електронної пошти облікового" +" запису у відповідному контексті." + +#. (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 "" +"У Geary передбачено клавіатурні скорочення для типових операцій." +" Скористайтеся вбудованою довідкою для ознайомлення із повним списком. Щоб" +" відкрити довідку з клавіатурних скорочень, виберіть пункт Клавіатурні скорочення у меню програми на панелі" +" інструментів головного вікна або скористайтеся клавіатурними скороченнями із" +" наведеного нижче списку." + +#. (itstool) path: section/p +#: C/shortcuts.page:20 +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 +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 "" +"Ви можете увімкнути ті клавіатурні скорочення для дій з повідомленням, які не" +" потребують натискання клавіші Ctrl. Ці клавіатурні скорочення" +" використовуються у GMail. Докладніше про це тут: ." + +#. (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 "" +"На облікових записах Gmail повідомлення із зірочкою потрапляють до теки" +" «Зірочки» у списку тек." + +#. (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 "" +"Geary автоматично позначає повідомлення як прочитані, якщо ви їх читаєте. Щоб" +" вказати спілкування як прочитане або непрочитане вручну, натисніть" +" піктограму з колом у списку спілкувань." + +#. (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 "" +"Щоб розпочати нове спілкування електронною поштою, натисніть кнопку Нове повідомлення на панелі інструментів. Введіть" +" адресу електронної пошти отримувача повідомлення у поле Кому і тему повідомлення у поле Тема. Далі," +" ви можете ввести повідомлення до текстового поля, яке розташовано під цими" +" двома полями. Коли повідомлення буде готове до надсилання, натисніть кнопку" +" Надіслати або натисніть комбінацію клавіш <" +"keyseq>CtrlEnter, щоб його надіслати." + +#. (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 "" +"При надсиланні повідомлення електронної пошти Geary очікує 5 секунд перед" +" відправлення повідомлення. Протягом цього часу ви зможете натиснути кнопку <" +"gui style=\"button\">Скасувати на контекстній панелі сповіщення, яку" +" буде показано, або натиснути комбінацію клавіш CtrlZ для повторного відкриття повідомлення для внесення до нього" +" додаткових змін." + +#. (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 "" +"При введення адреси електронної пошти у поля Кому" +" і Копія Geary надаватиме пропозиції із адресної" +" книги вашого стільничного середовища та адрес у раніше надісланих і" +" отриманих повідомленнях електронної пошти. Щоб вибрати одну з пропозицій," +" просто клацніть на ній. Крім того, може бути показано поля Потайна копія і Відповідати." +" Для цього слід вибрати пункт Показувати додаткові поля<" +"/gui> з меню форматування на панелі інструментів." + +#. (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 "" +"Щоб відповісти до поточного позначеного спілкування, натисніть на панелі" +" інструментів одну з таких кнопок: Відповісти, <" +"gui style=\"button\">Відповісти всім або Переспрямувати. У відповідь буде відкритого вікно редактора відповіді" +" або переспрямованого повідомлення для останнього повідомлення у спілкуванні." + +#. (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 "" +"При відповіді на повідомлення початкове повідомлення буде процитовано і" +" скопійовано у нижню частину відповіді. Цю частину повідомлення можна" +" вилучити до введення відповіді натисканням клавіші Backspace." +" Крім того, текст можна вибірково процитувати позначенням бажаного фрагмента" +" тексту у повідомленні із наступним натисканням кнопки Відповісти або Відповісти усім —" +" процитовано буде лише позначений фрагмент тексту." + +#. (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 "" +"Щоб відповісти на певне повідомлення електронної пошти, відкрийте меню" +" повідомлення у верхньому куті повідомлення і виберіть пункт Відповісти<" +"/gui>, Відповісти усім або Переспрямувати." + +#. (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 "" +"У редакторі повідомлень Geary ви можете скористатися стилями тексту, зокрема" +" напівжирним та курсивом, відступами тексту для цитування" +" та посиланнями на вебсторінки. Просто позначте фрагмент тексту і натисніть" +" відповідну кнопку на панелі інструментів форматування." + +#. (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 "" +"Документи, звукові файли, відео та інші файли можна долучити до повідомлення" +" електронної пошти натисканням кнопки Долучити файл<" +"/gui> у верхній частині вікна редактора повідомлень із наступним вибором" +" документа, який слід долучити, або перетягуванням пункту файла з вікна" +" програми Файли до вікна редактора повідомлень із наступним" +" скиданням його або на текстові поля у верхній частині вікна, або на панель" +" інструментів у нижній частині вікна." + +#. (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 "" +"Ви можете вказати підпис, який слід вставити у нижню частину повідомлення" +" електронної пошти у редакторі повідомлень, за допомогою діалогового вікна <" +"link xref=\"accounts\"/>." + +#. (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 "" +"У Geary передбачено підтримку перевірки правопису безпосередньо під час" +" введення редагованого повідомлення однією або декількома мовами. Щоб" +" увімкнути перевірку правопису, спочатку встановіть у вашій системі словники" +" перевірки правопису бажаними мовами. Зверніться до довідки з операційної" +" системи, щоб визначити спосіб встановлення словників, яких не вистачає." + +#. (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 "" +"Якщо ви працюєте із поштовим сервером, на якому передбачено підтримку" +" чернеток, Geary автоматично зберігатиме повідомлення на сервері під час" +" введення з невеликою затримкою." + +#. (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 "" +"Якщо ви зберегли або відкинули створене повідомлення електронної пошти, ви" +" можете повторно його відкрити натисканням кнопки Скасувати на контекстній панелі сповіщення, яку буде показано, або" +" натисканням комбінації клавіш CtrlZ." +" Можливість відновити збережене або відкинуте повідомлення зберігатиметься" +" протягом періоду до 30 хвилин. Після завершення цього періоду вам доведеться" +" повторно відкрити повідомлення з теки Чернетки, якщо його було" +" там збережено." + +#. (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 "" +"Крім того, Geary може надсилати звичайні текстові повідомлення. У спадному" +" меню позначте або зніміть позначення з пункту Форматований текст, щоб перемкнутися між режимом звичайного тексту і" +" режимом форматованого тексту. Звичайний текстовий режим є корисним для" +" надсилання повідомлень до списків листування, які забороняють надсилання" +" повідомлень із форматованим текстом (HTML), або до тих користувачів, які не" +" можуть користуватися сучасними клієнтами електронної пошти, подібними Geary." + +#. (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 "" +"У режимі звичайного тексту програма автоматично переноситиме рядки тексту з" +" використанням м'яких переносів так, щоб довжина рядків не перевищувала 74" +" символів, а текст із відступами буде перенесено із додаванням позначок" +" цитування, «>», для кожного з рівнів цитування." 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' 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" } ], 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" diff --git a/po/ja.po b/po/ja.po index c9ed1f34..a798ad49 100644 --- a/po/ja.po +++ b/po/ja.po @@ -13,8 +13,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-03-31 17:44+0000\n" -"PO-Revision-Date: 2020-04-01 02:58+0900\n" +"POT-Creation-Date: 2020-05-07 01:10+0000\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" @@ -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,130 @@ 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" -msgstr "ネットワークのアクティビティを記録する" - -#. / Command line option -#: src/client/application/application-client.vala:119 -msgid "Log periodic activity" -msgstr "定期的なアクティビティを記録する" +#: src/client/application/application-client.vala:115 +msgid "Log IMAP network activity" +msgstr "IMAP ネットワークのアクティビティを記録する" #. / 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 +msgid "Log SMTP network activity" +msgstr "SMTP ネットワークのアクティビティを記録する" #. / 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 "" +msgstr "ディストリビューションリリース" #. / Application runtime information label -#: src/client/application/application-client.vala:337 +#: src/client/application/application-client.vala:331 msgid "Installation prefix" -msgstr "" +msgstr "インストールプレフィックス" -#: src/client/application/application-client.vala:590 +#: src/client/application/application-client.vala:584 #, c-format msgid "About %s" msgstr "%s について" @@ -958,7 +951,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 +962,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 +999,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 +1011,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 +1041,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 +1050,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 +1059,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 +1094,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 +1120,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 +1205,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 +1259,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 +1280,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 +1294,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 +1357,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 +1593,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 +1618,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 +1627,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 +1719,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 +1796,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 +1854,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 +2015,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 +2102,60 @@ 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 +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 +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 +msgid "New" +msgstr "新規" + +#. Translators: Infobar status label for an email template +#: src/client/plugin/email-templates/email-templates.vala:287 +msgid "Message template" +msgstr "" + +#. Translators: Info bar button label for sending an +#. email template +#: src/client/plugin/email-templates/email-templates.vala:291 +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 "フォルダーのハイライト" @@ -2131,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" @@ -2147,36 +2199,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 +2318,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 +2327,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 +2336,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 +2595,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 +2603,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 +2618,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 +2628,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 +2643,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 +2666,14 @@ msgid "Add an account" msgstr "アカウントを追加" #: ui/accounts_editor_add_pane.ui:53 -msgid "Create" -msgstr "作成" +msgid "_Create" +msgstr "作成(_C)" -#: 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 +3035,39 @@ 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 +msgid "Clears all log entries" +msgstr "すべてのログエントリーを消去" + #: ui/conversation-contact-popover.ui:146 msgid "New Conversation…" msgstr "新しいスレッド…" @@ -3212,7 +3268,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 +3283,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 +3323,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 +3343,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 +3383,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 +3433,120 @@ 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 +msgid "Single-key Shortcuts" msgstr "シングルキーショートカット" -#: ui/gtk/help-overlay.ui:262 +#: ui/gtk/help-overlay.ui:265 +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 +3616,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 "送信済みメール" 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" diff --git a/po/tr.po b/po/tr.po index d5b32eac..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-04-23 04:13+0000\n" -"PO-Revision-Date: 2020-04-25 15:34+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" @@ -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" @@ -1268,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)" @@ -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" @@ -1666,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ç" @@ -1731,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" @@ -2660,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)" @@ -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" @@ -3281,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" @@ -3296,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" @@ -3336,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" @@ -3356,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" @@ -3396,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" @@ -3446,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" @@ -3630,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" diff --git a/po/uk.po b/po/uk.po index 120e659b..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-03 07:37+0000\n" -"PO-Revision-Date: 2020-05-03 14:57+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 "(без теми)" @@ -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,120 @@ 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 +msgid "Single-key Shortcuts" msgstr "Одноклавішні скорочення" -#: ui/gtk/help-overlay.ui:262 +#: ui/gtk/help-overlay.ui:265 +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 "Вставити посилання" diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala index f6d5749f..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 ); @@ -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.RFC822.Error error) { + throw new ConfigError.SYNTAX( + "Invalid alternate email: %s", error.message + ); } } 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/composer/composer-email-entry.vala b/src/client/composer/composer-email-entry.vala index b5e87314..6b495510 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.RFC822.Error err) { + this._addresses = new Geary.RFC822.MailboxAddresses(); + this.is_valid = false; + } } } diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index a2186d7c..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)) { @@ -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/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/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/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( 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; } diff --git a/src/engine/api/geary-composed-email.vala b/src/engine/api/geary-composed-email.vala index 72f30ba8..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; } @@ -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. * @@ -172,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..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; @@ -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/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/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala index 36a4699b..03b49b0d 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)); @@ -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() { @@ -189,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); @@ -220,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); } @@ -272,20 +274,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 RFC822.Error { + 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 RFC822.Error { + return ( + String.is_empty_or_whitespace(str) + ? null + : new RFC822.MailboxAddresses.from_rfc822_string(str) + ); } + } - 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..b7c42a86 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: @@ -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); } @@ -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/imap/message/imap-message-data.vala b/src/engine/imap/message/imap-message-data.vala index e4d423ff..18933303 100644 --- a/src/engine/imap/message/imap-message-data.vala +++ b/src/engine/imap/message/imap-message-data.vala @@ -19,15 +19,20 @@ 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); } } 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 (RFC822.Error 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/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/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); } /** 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/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-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 6d994136..173312a7 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 = { '!', '#', '$', '%', '&', '\'', '*', '+', '-', @@ -124,9 +125,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); @@ -228,29 +231,33 @@ 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) - 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 Error.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 Error.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 Error.INVALID( + "Group lists not currently supported: %s", rfc822 + ); + } + + 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(); @@ -469,7 +476,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() ) @@ -543,7 +550,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 4afd096d..40ba2462 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. */ /** @@ -16,7 +17,8 @@ public class Geary.RFC822.MailboxAddresses : Geary.MessageData.AbstractMessageData, Geary.MessageData.SearchableMessageData, - Geary.RFC822.MessageData, Gee.Hashable { + Gee.Hashable, + DecodedMessageData { /** @@ -52,6 +54,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; } @@ -78,33 +81,40 @@ 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 Error { + var list = GMime.InternetAddressList.parse(null, rfc822); + if (list == null) { + throw new Error.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 Error { + int length = list.length(); + if (length == 0) { + throw new Error.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)); + 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 // 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)); + this.addrs.add( + new MailboxAddress.from_gmime(group_addr) + ); } } } @@ -112,16 +122,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) { diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala index d4a3aa0a..48b1d6f7 100644 --- a/src/engine/rfc822/rfc822-message-data.vala +++ b/src/engine/rfc822/rfc822-message-data.vala @@ -1,66 +1,103 @@ -/* 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. - */ - -public interface Geary.RFC822.MessageData : Geary.MessageData.AbstractMessageData { -} - -/** - * An RFC822 Message-ID. + * A base interface for objects that represent decoded RFC822 headers. * - * MessageID will normalize all strings so that they begin and end with the proper brackets ("<" and - * ">"). + * The value of these objects is the decoded form of the header + * data. Encoded forms can be obtained via {@link to_rfc822_string}. */ -public class Geary.RFC822.MessageID : Geary.MessageData.StringMessageData, Geary.RFC822.MessageData { - public MessageID(string value) { - string? normalized = normalize(value); - base (normalized ?? value); - } +public interface Geary.RFC822.DecodedMessageData : + Geary.MessageData.AbstractMessageData { - // 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; + /** Returns an RFC822-safe string representation of the data. */ + public abstract string to_rfc822_string(); - return "%s%s%s".printf(needs_prefix ? "<" : "", value, needs_suffix ? ">" : ""); - } } /** - * A Message-ID list stores its IDs from earliest to latest. + * A base interface for objects that represent encoded RFC822 header data. + * + * 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.MessageIDList : Geary.MessageData.AbstractMessageData, Geary.RFC822.MessageData { - public Gee.List list { get; private set; } +public interface Geary.RFC822.EncodedMessageData : + Geary.MessageData.BlockMessageData { - public MessageIDList() { - list = new Gee.ArrayList(); +} + +/** + * 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) { + base(value); } - public MessageIDList.from_collection(Gee.Collection collection) { - this (); + public MessageID.from_rfc822_string(string rfc822) { + base(GMime.utils_decode_message_id(rfc822)); + this.rfc822 = rfc822; + } - foreach(MessageID msg_id in collection) - this.list.add(msg_id); + /** + * 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, + DecodedMessageData { + + + /** Returns the number of ids in this list. */ + public int size { + get { return this.list.size; } + } + + /** Determines if there are no ids in the list. */ + public bool is_empty { + get { return this.list.is_empty; } + } + + 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 +180,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,87 +208,97 @@ 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, - 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 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 - ); - } - this.value = value; - this.original = rfc822; + public GLib.DateTime value { get; private set; } + + private string? rfc822; + + + public Date(GLib.DateTime datetime) { + this.value = datetime; + this.rfc822 = null; } - public Date.from_date_time(DateTime datetime) { - this.original = null; - this.value = datetime; + public Date.from_rfc822_string(string rfc822) throws Error { + var date = GMime.utils_header_decode_date(rfc822); + if (date == null) { + throw new Error.INVALID("Not ISO-8601 date: %s", rfc822); + } + this.rfc822 = rfc822; + this.value = date; } /** * 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.Size : Geary.MessageData.Int64MessageData, Geary.RFC822.MessageData { - public Size(int64 value) { - base (value); - } -} +public class Geary.RFC822.Subject : + Geary.MessageData.StringMessageData, + Geary.MessageData.SearchableMessageData, + DecodedMessageData { -public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData, - Geary.MessageData.SearchableMessageData, Geary.RFC822.MessageData { 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() { @@ -296,67 +357,75 @@ 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; - public Header(Memory.Buffer buffer) { + public Header(Memory.Buffer buffer) throws Error { 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) - throw new RFC822Error.INVALID("Unable to parse RFC 822 headers"); - - return message.get_header_list(); + this.message = parser.construct_message(null); + if (this.message == null) { + throw new Error.INVALID("Unable to parse RFC 822 headers"); + } } - 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; } + } -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); } @@ -391,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); } } @@ -403,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/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index 4ef341c8..1c780e06 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. * @@ -15,6 +16,7 @@ */ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { + /** * Callback for including non-text MIME entities in message bodies. * @@ -29,22 +31,45 @@ 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 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; } @@ -85,50 +110,112 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { private size_t? body_offset = null; - public Message(Full full) throws RFC822Error { - GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(full.buffer)); + 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 Error.INVALID("Unable to parse RFC 822 message"); + } - message = parser.construct_message(Geary.RFC822.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) { + public Message.from_gmime_message(GMime.Message message) + throws Error { 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) throws RFC822Error { + public Message.from_buffer(Memory.Buffer full_email) + throws Error { 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 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())); GMime.Parser parser = new GMime.Parser.with_stream(stream_cat); - message = parser.construct_message(Geary.RFC822.get_parser_options()); - if (message == null) - throw new RFC822Error.INVALID("Unable to parse RFC 822 message"); + var message = parser.construct_message(Geary.RFC822.get_parser_options()); + if (message == null) { + throw new Error.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, string? message_id, - GLib.Cancellable? cancellable) { + GLib.Cancellable? cancellable) + throws Error { this.message = new GMime.Message(true); + // // Required headers this.from = email.from; @@ -379,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"); @@ -449,15 +520,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) ); } @@ -468,7 +538,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) ); } @@ -490,7 +560,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 @@ -526,7 +596,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); @@ -589,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 RFC822Error { - return message_to_memory_buffer(false, false); + public Memory.Buffer get_native_buffer() throws Error { + 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 RFC822Error { - 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); } /** @@ -679,7 +748,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; @@ -746,11 +815,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; @@ -767,9 +836,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); } @@ -789,9 +858,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); } @@ -802,7 +872,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 Error { string? body = null; bool html = false; try { @@ -874,90 +945,18 @@ 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 void stock_from_gmime() { - GMime.HeaderList headers = this.message.get_header_list(); - 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; - - case "sender": - try { - this.sender = new RFC822.MailboxAddress.from_rfc822_string(value); - } catch (Error err) { - debug("Could parse subject: %s", err.message); - } - 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 RFC822.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 "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(Geary.RFC822.get_parser_options(), value); - break; - - default: - // do nothing - break; - } - }; - } - - private MailboxAddresses append_address(MailboxAddresses? existing, - string header_value) { - MailboxAddresses addresses = new MailboxAddresses.from_rfc822_string(header_value); - if (existing != null) { - addresses = existing.append(addresses); + private MailboxAddresses? to_addresses(GMime.InternetAddressList? list) + throws Error { + MailboxAddresses? addresses = null; + if (list != null && list.length() > 0) { + addresses = new MailboxAddresses.from_gmime(list); } return addresses; } @@ -974,8 +973,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(); @@ -1063,13 +1061,16 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet { } #endif - public Gee.List get_sub_messages() { + public Gee.List get_sub_messages() + throws Error { 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 Error { // If this is a multipart container, check each of its children. GMime.Multipart? multipart = root as GMime.Multipart; if (multipart != null) { @@ -1084,36 +1085,53 @@ 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"); } } } - private Memory.Buffer message_to_memory_buffer(bool encoded, bool dotstuffed) throws RFC822Error { + private Memory.Buffer message_to_memory_buffer(bool encode_lf, + RFC822FormatOptions options) + throws Error { 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 (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 RFC822Error.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 RFC822Error.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 RFC822Error.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/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/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala index f05c50a2..51fae6a3 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) { + 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.get_all()) { + 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; + } } 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" + ); + } } 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/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/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/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/engine/rfc822-mailbox-address-test.vala b/test/engine/rfc822/rfc822-mailbox-address-test.vala similarity index 97% rename from test/engine/rfc822-mailbox-address-test.vala rename to test/engine/rfc822/rfc822-mailbox-address-test.vala index 6b47a81f..7436629d 100644 --- a/test/engine/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-mailbox-addresses-test.vala b/test/engine/rfc822/rfc822-mailbox-addresses-test.vala similarity index 95% rename from test/engine/rfc822-mailbox-addresses-test.vala rename to test/engine/rfc822/rfc822-mailbox-addresses-test.vala index 70e535d5..f3fc2fa8 100644 --- a/test/engine/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-message-data-test.vala b/test/engine/rfc822/rfc822-message-data-test.vala similarity index 98% rename from test/engine/rfc822-message-data-test.vala rename to test/engine/rfc822/rfc822-message-data-test.vala index 504efaa0..c6bc1553 100644 --- a/test/engine/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) @@ -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()); } diff --git a/test/engine/rfc822-message-test.vala b/test/engine/rfc822/rfc822-message-test.vala similarity index 88% rename from test/engine/rfc822-message-test.vala rename to test/engine/rfc822/rfc822-message-test.vala index cc3f0a40..478d5633 100644 --- a/test/engine/rfc822-message-test.vala +++ b/test/engine/rfc822/rfc822-message-test.vala @@ -59,12 +59,13 @@ 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 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"); @@ -74,21 +75,21 @@ 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"); } - 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(enc.to[0].name == "potus@whitehouse.gov "); + 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,16 +98,16 @@ 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.list.size == 2); + assert(dup.references.size == 2); assert_message_id_list( dup.references, "<1234@local.machine.example> <5678@local.machine.example>" ); } - 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 +115,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 +126,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 +134,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 +142,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 +150,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 +158,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 +169,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 +177,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 +196,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,13 +211,13 @@ 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_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); } @@ -318,7 +350,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" ); @@ -371,7 +403,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 GLib.Error { return yield new Geary.RFC822.Message.from_composed_email( composed, GMime.utils_generate_message_id(composed.from.get(0).domain), @@ -379,7 +412,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); @@ -391,7 +424,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) ); @@ -399,21 +432,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()); } @@ -421,7 +454,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) { @@ -431,9 +464,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 diff --git a/test/engine/rfc822-part-test.vala b/test/engine/rfc822/rfc822-part-test.vala similarity index 92% rename from test/engine/rfc822-part-test.vala rename to test/engine/rfc822/rfc822-part-test.vala index 9ec2cabf..933d1505 100644 --- a/test/engine/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-utils-test.vala b/test/engine/rfc822/rfc822-utils-test.vala similarity index 98% rename from test/engine/rfc822-utils-test.vala rename to test/engine/rfc822/rfc822-utils-test.vala index 1691fa41..7711fa9a 100644 --- a/test/engine/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 b6c0c801..3d81a5db 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.RFC822.Error { Geary.ComposedEmail composed = new Geary.ComposedEmail( new GLib.DateTime.now_local(), new Geary.RFC822.MailboxAddresses.single(from) diff --git a/test/meson.build b/test/meson.build index 9cd4717f..57f33a86 100644 --- a/test/meson.build +++ b/test/meson.build @@ -52,14 +52,14 @@ 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', - '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', 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()); 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 { diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index d73f2c3a..c0c66461 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -251,11 +251,23 @@ + + + + + True + single-key + Single-key Shortcuts True Single-key shortcuts + context="shortcut window">Single-key shortcuts (if enabled) + + + True + + True @@ -298,6 +310,16 @@ E + + + + + True + + + True + + True @@ -329,7 +351,7 @@ True - Find in current conversations + Find in current conversation slash