From ebb51373b0f386f681d0bdc3808f3d1f5e61e766 Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Wed, 26 Jan 2022 15:59:50 +0100 Subject: [PATCH 1/6] New upstream version 0.6.0 --- NEWS | 433 ++++++++++++ debian/changelog | 113 +++ meson.build | 2 +- po/POTFILES.in | 3 + po/it.po | 187 +++-- po/nl.po | 955 ++++++++++++++++---------- po/ro.po | 80 +-- po/sv.po | 409 +++++------ po/uk.po | 401 +++++------ run.in | 2 +- src/chatty-application.c | 2 +- src/chatty-chat-view.c | 10 +- src/chatty-chat.c | 68 ++ src/chatty-chat.h | 2 + src/chatty-contact-list.c | 509 ++++++++++++++ src/chatty-contact-list.h | 32 + src/chatty-enums.h | 2 + src/chatty-history.c | 522 ++++++++++---- src/chatty-list-row.c | 69 ++ src/chatty-list-row.h | 3 + src/chatty-manager.c | 44 +- src/chatty-manager.h | 3 +- src/chatty-message.c | 20 + src/chatty-message.h | 4 + src/chatty-notification.c | 7 + src/chatty-text-item.c | 88 ++- src/chatty-utils.c | 6 +- src/chatty-window.c | 166 ++--- src/chatty-window.h | 3 +- src/chatty.gresource.xml | 1 + src/css/style.css | 7 +- src/dialogs/chatty-mm-chat-info.c | 6 + src/dialogs/chatty-new-chat-dialog.c | 741 ++++++-------------- src/dialogs/chatty-new-chat-dialog.h | 4 +- src/matrix/chatty-ma-account.c | 5 +- src/matrix/chatty-ma-chat.c | 39 +- src/matrix/matrix-api.c | 6 +- src/matrix/matrix-db.c | 35 + src/meson.build | 3 +- src/mm/chatty-mm-account.c | 83 ++- src/mm/chatty-mm-account.h | 5 +- src/mm/chatty-mm-chat.c | 78 ++- src/mm/chatty-mm-chat.h | 6 + src/mm/chatty-mmsd.c | 373 +++++----- src/mm/chatty-mmsd.h | 2 + src/mm/chatty-sms-uri.c | 293 ++++++++ src/mm/chatty-sms-uri.h | 31 + src/mm/meson.build | 1 + src/ui/chatty-contact-list.ui | 79 +++ src/ui/chatty-dialog-new-chat.ui | 568 +++++++-------- src/ui/chatty-list-row.ui | 46 ++ src/ui/chatty-settings-dialog.ui | 1 + src/users/chatty-contact.c | 16 +- src/users/chatty-contact.h | 2 + tests/history-db/empty-v4.sql | 96 +++ tests/history-db/matrix-a-v3.sql | 150 ++++ tests/history-db/matrix-a-v4.sql | 155 +++++ tests/history-db/matrix-v4.sql | 129 ++++ tests/history-db/sms-DE-v4.sql | 132 ++++ tests/history-db/sms-IN-v4.sql | 132 ++++ tests/history-db/sms-v4.sql | 126 ++++ tests/history-db/telegram-chat-v4.sql | 127 ++++ tests/history-db/telegram-im-v4.sql | 126 ++++ tests/history-db/xmpp-im-v4.sql | 126 ++++ tests/history-db/xmpp-muc-v4.sql | 123 ++++ tests/history.c | 141 +++- tests/meson.build | 1 + tests/message-text-item.c | 13 + tests/mm-account.c | 2 +- tests/sms-uri.c | 123 ++++ 70 files changed, 5934 insertions(+), 2344 deletions(-) create mode 100644 NEWS create mode 100644 src/chatty-contact-list.c create mode 100644 src/chatty-contact-list.h create mode 100644 src/mm/chatty-sms-uri.c create mode 100644 src/mm/chatty-sms-uri.h create mode 100644 src/ui/chatty-contact-list.ui create mode 100644 tests/history-db/empty-v4.sql create mode 100644 tests/history-db/matrix-a-v3.sql create mode 100644 tests/history-db/matrix-a-v4.sql create mode 100644 tests/history-db/matrix-v4.sql create mode 100644 tests/history-db/sms-DE-v4.sql create mode 100644 tests/history-db/sms-IN-v4.sql create mode 100644 tests/history-db/sms-v4.sql create mode 100644 tests/history-db/telegram-chat-v4.sql create mode 100644 tests/history-db/telegram-im-v4.sql create mode 100644 tests/history-db/xmpp-im-v4.sql create mode 100644 tests/history-db/xmpp-muc-v4.sql create mode 100644 tests/sms-uri.c diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..18dd2b3 --- /dev/null +++ b/NEWS @@ -0,0 +1,433 @@ +Overview of Changes in Chats 0.6.0. Tue, 25 Jan 2022 +==================================================== +* MMS + - Implement new Group message work flow + - Fix setting proxy +* Fix various memory leaks and warnings +* Fix issue(s) #235 #670 +* Update Translations + - Ukrainian + - Swedish + + +Overview of Changes in Chats 0.6.0~beta. Tue, 11 Jan 2022 +========================================================= +This version of Chats updates the database schema and thus once you update +to 0.6.0~beta, you shall NOT be able to go back to any older version. When +the db schema is updated, a copy of older version of the db is stored as +~/.purple/chatty/db/chatty-history.db.xxxx (where xxxx is a unix timestamp) + +Right now in any of the 0.5.0~beta, there are several things that are not being +explicitly saved in the chatty database (such as the subject, multiple attachments, etc). +!1023 fixed those issues so that chatty can appropriately handle them. However, +once one runs that MR, one cannot backport the database, hence the reasoning to go +to 0.6.0~beta instead of 0.5.0~beta5. It makes it obvious that this is a major upgrade. + +* Update database schema to handle MMS subject, multi file attachments, etc. +* Improve database tests to avoid incompatible changes +* Improve auto generated names for multi user MMS chats +* Allow calling contacts from info page +* Fixes issue(s) #666, #668 +* Update Translations + - Italian + - Ukrainian + - Romanian + - Dutch + + +Overview of Changes in Chats 0.5.0~beta4. Wed, 15 Dec 2021 +========================================================== +* MMS + - Add Support for expired MMS messages + - delete orphaned MMSes +* Matrix + - Request password if it's initially empty +* Update Translations + - Ukrainian + - Swedish + +Overview of Changes in Chats 0.5.0~beta3. Fri, 10 Dec 2021 +========================================================== +* Show URLs for file only messages +* SMS/MMS + - Don't show author for outgoing SMS/MMS + - Write settings directly to mmsd-tng (mmsd daemon) +* Matrix + - Regenerate encryption keys only if empty + - Fix tests with olm account pickle v4 +* Update Translations + - Romanian + - Swedish + - Ukrainian + + +Overview of Changes in Chats 0.5.0~beta2. Thu, 02 Dec 2021 +========================================================== +* Improve MMS support +* Use more libhandy widgets +* Show an empty page on empty view +* Improve keyboard navigation +* Update Translations +* Matrix + - Improve handling network changes + - Avoid resync when asked to stop sync +* build + - Avoid testing some UI files (ui files with libhandy widgets fails test) + - bump flatpak olm dependency + + +Overview of Changes in Chats 0.5.0~beta. Tue, 16 Nov 2021 +========================================================= +* Add MMS support +* Fix various memory leaks +* Use HdyStatusPage to show empty label +* Withdraw notification when message is read +* Matrix + - Support login with email + - Implement setting encryption + - Add sync filter and use it +* build + - Make libpurple optional + + +Overview of Changes in Chats 0.4.0. Sat, 11 Sep 2021 +==================================================== +* Fix various memory leaks +* Improve 'Add in contacts' workflow +* Update evolution-data-server contacts on refresh +* Don't list accounts with unknown status + + +Overview of Changes in Chats 0.4.0~beta3. Mon, 06 Sep 2021 +========================================================== +* Anonymize chat and account details in log +* SMS + - Add a way to call numbers + - Don't show intials for chats with no name + - Remove purple-mm-sms completely in favor in native SMS support +* Matrix + - Verify homeserver before saving + + +Overview of Changes in Chats 0.4.0~beta2. Mon, 30 Aug 2021 +========================================================== +* SMS + - Allow configuring delivery reports + - Prefer locally parsed phone number + + +Overview of Changes in Chats 0.4.0~beta. Wed, 25 Aug 2021 +========================================================= +* Add native SMS support +* Always show SMS chats +* Matrix + - Load user avatars + - Allow deleting user avatars + - Improve key exchanges +* Fix issue(s) #514 + + +Overview of Changes in Chats 0.3.4. Wed, 28 Jul 2021 +==================================================== +* Work around gnome-keyring unlock if not unlocked on boot +* Add matrix specific info dialog +* Matrix + - Load saved account details + - Implement getting account avatars + + +Overview of Changes in Chats 0.3.3. Wed, 14 Jul 2021 +==================================================== +* Matrix + - Allow getting/deleting 3pid (email/phone numbers) + - Implement file downloads + - Implement setting display name +* Handle opening chats from notifications + + +Overview of Changes in Chats 0.3.2. Tue, 29 Jun 2021 +==================================================== +* Keep last modified time up to date in chat list +* Various code cleanups +* Matrix + - Load room name and use it + - Load avatars async + - Load room avatar when creating chat + + +Overview of Changes in Chats 0.3.1. Thu, 27 May 2021 +==================================================== +* Show notification for new matrix messages +* Show message time of they differ by a minute or more +* Avoid animating when messages are shown + + +Overview of Changes in Chats 0.3.0. Tue, 04 May 2021 +==================================================== +* Fix avatar chooser dialog +* Speed up matrix buddy search +* Update Translations + + +Overview of Changes in Chats 0.3.0~beta2. Wed, 14 Apr 2021 +========================================================== +* Improve matrix encryption +* Prefer logging to journald if available +* Various code cleanups +* Update Translations + + +Overview of Changes in Chats 0.3.0~beta. Thu, 25 Mar 2021 +========================================================= +* Add initial support for matrix chat +* Add flatpak manifest +* Fix various memory leaks +* Update Translations + + +Overview of Changes in Chats 0.2.0. Mon, 16 Nov 2020 +==================================================== +This version of Chats updates the database schema and thus once you update +to 0.2.0, you shall NOT be able to go back to any older version. when the +db schema is updated, a copy of older version of the db is stored as +~/.purple/chatty/db/chatty-history.db.xxxx (where xxxx is the unix timestamp) + +* Implement new Database design +* Allow numbers prefixed with 'sms://' +* Show an error dialog for invalid numbers +* Add an empty search view +* Add a minimal user id validation +* Port to libhandy-1 +* Add more tests +* Various code cleanups +* Update Translations + + +Overview of Changes in Chats 0.1.17. Mon, 02 Nov 2020 +===================================================== +* Hide chats with empty chat when folded +* Don't strip html from SMS messages +* Hide avatar for outgoing messages +* Update Translations + + +Overview of Changes in Chats 0.1.16. Wed, 23 Sep 2020 +===================================================== +* Various code cleanups +* Hide chats from disconnected accounts +* Update Translations + + +Overview of Changes in Chats 0.1.15. Thu, 20 Aug 2020 +===================================================== +* Various code cleanups +* Inform user if contacts app failed to open +* Improve Some translatable strings +* Update Translations + + +Overview of Changes in Chats 0.1.14. Tue, 14 Jul 2020 +===================================================== +* Add bash completion support +* Use SIM provider country code for parsing phone number +* Update Translations + + +Overview of Changes in Chats 0.1.13. Thu, 25 Jun 2020 +===================================================== +* Revert "window: Select the first chat if in non-folded mode" + + +Overview of Changes in Chats 0.1.12. Wed, 24 Jun 2020 +===================================================== +* Improve avatar presentation on buddy/chat state changes +* Trigger (in)activity on screen blank/unblank for xep-0352 +* Various code cleanups + + +Overview of Changes in Chats 0.1.11. Thu, 28 May 2020 +===================================================== +* Various UI fixes +* Various code cleanups +* Improve keyboard navigation +* Fix various memory leaks and invalid free +* Fix issue(s) #340 + + +Overview of Changes in Chats 0.1.10. Wed, 22 Apr 2020 +===================================================== +* Various UI fixes +* Enable showing notifications on first message +* List chats only from connected accounts +* Replace libfolks with evolution-data-server for contacts +* Update Translations + + +Overview of Changes in Chats 0.1.9. Thu, 12 Mar 2020 +==================================================== +* Various code cleanups +* Update Translations +* Add about dialog +* Fix build on GCC 10 +* Fix issue(s) #284, #293 + + +Overview of Changes in Chats 0.1.8. Wed, 26 Feb 2020 +==================================================== +* Various code cleanups +* Use phonenumber for SMS alias +* Update password entry icons +* Fix issue(s) #264, #289, #292 + + +Overview of Changes in Chats 0.1.7. Wed, 22 Jan 2020 +==================================================== +* Update avatar when user gets deleted + + +Overview of Changes in Chats 0.1.6. Wed, 22 Jan 2020 +==================================================== +* Various code cleanups +* Improve avatar support +* Update Translations +* Fix issue(s) #267, #274 + + +Overview of Changes in Chats 0.1.5. Mon, 13 Jan 2020 +==================================================== +* Add initial MAM implementation +* Fix various memory leaks +* Update Translations +* Fix issue(s) #259, #262 + + +Overview of Changes in Chats 0.1.4. Sun, 15 Dec 2019 +==================================================== +* Add unit tests +* Add librem.one as default jabber provider +* Improve empty-state overlay handling + + +Overview of Changes in Chats 0.1.3. Mon, 09 Dec 2019 +==================================================== +* Add support for muc room and user aliases +* Add support for account icons +* Fix various memory leaks +* Update Translations +* Fix issue(s) #231, #225 + + +Overview of Changes in Chats 0.1.2. Tue, 19 Nov 2019 +==================================================== +* Add contacts to gnome-contacts when created in chatty +* Enable folks SMS contacts only when modem is available +* Fix various memory leaks +* Update Translations +* Fix issue(s) #217, #218 + + +Overview of Changes in Chats 0.1.1. Mon, 04 Nov 2019 +==================================================== +* Improve buddy list +* Only show contacts of connected accounts +* Add libfolks support for contacts +* Autojoin SMS contacts having chat history +* Show user icons in message notifications +* Update Translations +* Fix issue(s) #52, #203, #209 + + +Overview of Changes in Chats 0.1.0. Sun, 06 Oct 2019 +==================================================== +* Change app release description + + +Overview of Changes in Chats 0.0.8. Sat, 05 Oct 2019 +==================================================== +* Change app name from Chatty to Chats +* Fix a bug that led to a crash when adding a new contact without an active acount +* Add support for XMPP http file upload plugin +* Chats switches directly to the conversation view when a new contact is added +* Add conversation notifications +* Add notifications for XMPP account and modem (re)connections +* Set first account in the 'Add New Chat' dialog as default +* Add timestamp to incoming messages +* Add daemon mode +* Add support for SMS uri scheme +* Add handling for libpurple TLS notifications +* Added dialog for TLS connection handling +* Improve connection handling +* Add spinner for connection status to each entry in the accounts list +* Rework connection error dialog +* Add OMEMO fingerprints and device IDs to the XMPP account info dialog and the chat details dialog +* Add phone number formatting according to E164 +* Add lazy-loading for the chat history +* Add an about dialog +* Add auto reconnect for SMS and IM accounts +* Add acount setup verification +* Replace purple conversation logging by SQLite based logging +* Fix many visual bugs in the UI + + +Overview of Changes in Chats 0.0.7. Tue, 16 Apr 2019 +==================================================== +* Add application info dialog +* Fix a core dump issue caused by invoking another instance of Chatty +* Chatty won't start anymore if another libpurple client, like Pidgin, is running already + + +Overview of Changes in Chats 0.0.6. Thu, 07 Mar 2019 +==================================================== +* Set the spinner-widget for account-connection status +* Select the first 'Chats' list entry after leaving/deleting a chat and at application start +* Add HdyLeaflet notification handler for headerbar update +* Improve css styling of message panel +* Show 'close' button when leaflet is folded +* Fix issue(s) #97 + + +Overview of Changes in Chats 0.0.5. Mon, 04 Mar 2019 +==================================================== +* Add "Leave Chat" menu entry +* Add handling and settings for messages from unknown users +* Add group chat dialog +* Add 'Welcome' dialog +* Fix crash on conversation with not yet buddies +* Fix issue(s) #87, #54 + + +Overview of Changes in Chats 0.0.4. Wed, 30 Jan 2019 +==================================================== +* Port to use HdyDialog +* Introduce HdyLeaflet +* Add close button to header-bar which is visible when msg-view is unfolded +* Indicate selected chat in chats-list when msg-view is unfolded +* Introduce XMPP multi user chat + + +Overview of Changes in Chats 0.0.3. Mon, 07 Jan 2019 +==================================================== +* Add contacts list refresh handling +* Add 'edit account' dialog +* Add setting for return=send message +* Add setting for enabling/disabling libpurple message carbons +* Add settings view +* Add emoticon translation +* Add support for sending typing messages +* Replace 'add account' view with dialog +* Rework 'add contact' view +* Fix issue(s) #73, #75, #77 + + +Overview of Changes in Chats 0.0.2. Fri, 14 Dec 2018 +==================================================== +* Add app icon +* Add purple-command support +* Add SMS send receipts +* Replace GtkSearchBar with HdySearchBar +* handle XMPP authorization requests + + +Overview of Changes in Chats 0.0.1. Thu, 08 Nov 2018 +==================================================== +* Initial release diff --git a/debian/changelog b/debian/changelog index 9daeba6..4c6ec93 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,116 @@ +chatty (0.6.0) byzantium; urgency=medium + + [ Mohammed Sadiq ] + * new-chat-dialog: Use a single variable for account + * contact: Add API to create dummy contact + * Add chatty-contact-list + * new-chat-dialog: Use the new contact-list to list contacts + * new-chat-dialog: Return a GListModel of selected chat list + * new-chat-dialog: Port to use HdyPreferencesPage + * new-chat-dialog: Implement New Message Flow + * list-row: Add close button + * chat-view: Let the message entry be always sensitive + * css: Apply button style only if sensitive + * new-chat-dialog: Fix title for SMS row + * contact-list: don't expand selected contact list + * chat: Fix autogenerated name for mm-buddy + * window: Create settings dialog only once + * window: Hide new chat dialog on chat selection + * window: Fix opening non SMS contacts + * mm-chat-info: Avoid criticals when chat is NULL + + [ Yuri Chornoivan ] + * po: Update Ukrainian translation + * po: Update Ukrainian translation + + [ Chris Talbot ] + * mmsd: fix a couple memory leaks + * mmsd: Only clear proxy and modem number if string is NULL or empty + * mmsd: Set auto_create_smil variable + * mmsd: Don't trust the MMS file type + * Utils: Account for g_file_info_get_content_type() returning NULL + + [ Anders Jonsson ] + * po: Update Swedish translation + + -- Mohammed Sadiq Tue, 25 Jan 2022 16:07:05 +0530 + +chatty (0.6.0~beta) byzantium; urgency=medium + + [ Mohammed Sadiq ] + * This version changes the DB schema so we bumped the version number to 0.6.0 to indicate that. It is still supposed to be the last beta before the next stable release. + * Add NEWS + * mm: Add an SMS URI parser + * mm-chat: Add API to create chat from SMS URI + * mm-account: Add API start chat from SMS URI + * manager: Use ChattySmsUri to handle SMS URIs + * window: Avoid validating SMS URI + * chat: Add API to generate chat name + * ma-chat: Use the new API to generate name + * mm-chat: Use the new API to generate name + * chat-view: Show send button for file only messages + * tests: Improve history tests + * message: Add API for message subject + * history: Update db design to handle more MMS features + * mmsd: Add files as attachments to message + * text-item: Generate text content for multi file messages + + [ Anders Jonsson ] + * po: Update Swedish translation + + [ Yuri Chornoivan ] + * po: Update Ukrainian translation + + [ Vittorio Monti ] + * po: Update Italian translation + + [ Daniel Șerbănescu ] + * po: Update Romanian translation + + [ Jan Jasper de Kroon ] + * po/nl.po: Dutch translation updates + + [ Chris Talbot ] + * mmsd: Add uid to folder + * list-row: Add call button + * mm-chat-info: Add call button next to contacts for group chats + + [ Kyle Evans ] + * run.in: show gdb the source, debug from anywhere + + -- Mohammed Sadiq Tue, 11 Jan 2022 14:36:10 +0530 + +chatty (0.5.0~beta4) byzantium; urgency=medium + + [ Chris Talbot ] + * mm-account: Only try to search for MMS if the message status is sent or delivered + * mmsd: Add Support for expired MMS messages + * po: add chatty-mmsd to list of files to be translated + * mmsd: make delete_mms() an API + * mm-account: delete orphaned MMSes + * mmsd: Only close files if they exist + * mmsd: Get file size if file already exists + + [ Mohammed Sadiq ] + * matrix-db: Close db on dispose() + * history: Keep the first distinct match when migrating db + * chat-view: Fix a conditional + * mm-chat: Add API to find message by uid + * mm-account: Find MMS messages by uid + * chat-view: Update file upload button on state change + * matrix-api: Request password if empty + * ma-account: Don't warn if password is empty + * text-item: Fix urls followed by common delimiters + * contact: Allow EContact to be NULL + + [ Anders Jonsson ] + * po: Update Swedish translation + + [ Yuri Chornoivan ] + * po: Update Ukrainian translation + + -- Mohammed Sadiq Wed, 15 Dec 2021 22:20:35 +0530 + chatty (0.5.0~beta3) byzantium; urgency=medium [ Mohammed Sadiq ] diff --git a/meson.build b/meson.build index deae3e0..9733f39 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'chatty', 'c', 'cpp', - version: '0.5.0.beta3', + version: '0.6.0', meson_version: '>= 0.53.0', ) diff --git a/po/POTFILES.in b/po/POTFILES.in index 33f802a..746b003 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -9,6 +9,7 @@ src/chatty-chat-list.c src/chatty-chat-view.c src/chatty-chat.c src/chatty-chat.h +src/chatty-contact-list.c src/chatty-contact-provider.c src/chatty-contact-provider.h src/chatty-history.c @@ -62,6 +63,8 @@ src/matrix/chatty-ma-chat.c src/matrix/chatty-ma-chat.h src/matrix/matrix-utils.c src/matrix/matrix-utils.h +src/mm/chatty-mmsd.c +src/mm/chatty-mmsd.h src/ui/chatty-chat-view.ui src/ui/chatty-contact-row.ui src/ui/chatty-dialog-join-muc.ui diff --git a/po/it.po b/po/it.po index 5529de4..6cbabeb 100644 --- a/po/it.po +++ b/po/it.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: purism-chatty\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/chatty/issues\n" -"POT-Creation-Date: 2021-11-28 15:25+0000\n" -"PO-Revision-Date: 2021-11-28 19:00+0100\n" +"POT-Creation-Date: 2021-12-19 15:24+0000\n" +"PO-Revision-Date: 2021-12-19 22:18+0100\n" "Last-Translator: antpanlinux \n" "Language-Team: Italian\n" "Language: it\n" @@ -57,7 +57,7 @@ msgstr "Se inviare che il messaggio è stato letto" msgid "Message carbon copies" msgstr "Copie carbone dei messaggi" -#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:483 +#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:478 msgid "Share chat history among devices" msgstr "Condividi la cronologia chat tra i dispositivi" @@ -73,7 +73,7 @@ msgstr "Attiva la sincronizzazione dell'archivio GAM dal server" msgid "Enable purple" msgstr "Attiva purple" -#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:440 +#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:435 msgid "Enable purple accounts" msgstr "Attiva gli account purple" @@ -118,58 +118,26 @@ msgid "Whether to request delivery reports for outgoing SMS" msgstr "Se richiedere rapporto di consegna per gli SMS inviati" #: data/sm.puri.Chatty.gschema.xml:79 -msgid "Request mmsd to handle SMIL" -msgstr "Richiedere a MMSD di gestire SMIL" - -#: data/sm.puri.Chatty.gschema.xml:80 -msgid "Whether to request mmsd to create SMIL" -msgstr "Se richiedere a MMSD di creare SMIL" - -#: data/sm.puri.Chatty.gschema.xml:85 -msgid "Carrier mmsc for mmsd" -msgstr "Operatore del MMSC per MMSD" - -#: data/sm.puri.Chatty.gschema.xml:86 -msgid "The carrier mmsc to set for mmsd" -msgstr "L'operatore del MMSC da impostare per MMSD" - -#: data/sm.puri.Chatty.gschema.xml:91 -msgid "Carrier mms apn for mmsd" -msgstr "APN del operatore degli MMS per MMSD" - -#: data/sm.puri.Chatty.gschema.xml:92 -msgid "The mms APN to set for mmsd" -msgstr "L'APN degli MMS da impostare per MMSD" - -#: data/sm.puri.Chatty.gschema.xml:97 -msgid "Carrier mms proxy for mmsd" -msgstr "Proxy del operatore degli MMS per MMSD" - -#: data/sm.puri.Chatty.gschema.xml:98 -msgid "The mms proxy to set for mmsd" -msgstr "Il proxy degli MMS da impostare per MMSD" - -#: data/sm.puri.Chatty.gschema.xml:103 msgid "Enable experimental features" msgstr "Abilita le caratteristiche sperimentali" -#: data/sm.puri.Chatty.gschema.xml:104 +#: data/sm.puri.Chatty.gschema.xml:80 msgid "Whether to enable experimental features" msgstr "Se abilitare le caratteristiche sperimentali" -#: data/sm.puri.Chatty.gschema.xml:109 +#: data/sm.puri.Chatty.gschema.xml:85 msgid "Window maximized" msgstr "Finestra massimizzata" -#: data/sm.puri.Chatty.gschema.xml:110 +#: data/sm.puri.Chatty.gschema.xml:86 msgid "Window maximized state" msgstr "Stato della finestra massimizzata" -#: data/sm.puri.Chatty.gschema.xml:115 +#: data/sm.puri.Chatty.gschema.xml:91 msgid "Window size" msgstr "Dimensioni della finestra" -#: data/sm.puri.Chatty.gschema.xml:116 +#: data/sm.puri.Chatty.gschema.xml:92 msgid "Window size (width, height)." msgstr "Dimensioni della finestra (larghezza, altezza)." @@ -214,7 +182,7 @@ msgstr "" "Errore nella visualizzazione dell'aiuto:\n" "%s" -#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:258 +#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:257 msgid "Send To" msgstr "Invia a" @@ -261,11 +229,11 @@ msgstr "Il tuo messaggio è cifrato" msgid "Your messages are not encrypted" msgstr "Il tuo messaggio non è cifrato" -#: src/chatty-chat-view.c:394 +#: src/chatty-chat-view.c:396 msgid "Select File..." msgstr "Seleziona file..." -#: src/chatty-chat-view.c:397 src/purple/chatty-purple-request.c:175 +#: src/chatty-chat-view.c:399 src/purple/chatty-purple-request.c:175 #: src/chatty-window.c:395 src/dialogs/chatty-pp-chat-info.c:90 #: src/dialogs/chatty-ma-account-details.c:119 #: src/dialogs/chatty-pp-account-details.c:91 @@ -274,7 +242,7 @@ msgstr "Seleziona file..." msgid "Cancel" msgstr "Annulla" -#: src/chatty-chat-view.c:398 src/purple/chatty-purple-request.c:177 +#: src/chatty-chat-view.c:400 src/purple/chatty-purple-request.c:177 #: src/dialogs/chatty-pp-chat-info.c:89 #: src/dialogs/chatty-ma-account-details.c:118 #: src/dialogs/chatty-pp-account-details.c:90 @@ -375,6 +343,11 @@ msgstr "Moderatore" msgid "Member" msgstr "Membro" +#: src/chatty-manager.c:726 +#, c-format +msgid "“%s” is not a valid URI" +msgstr "“%s” non è un URI valido" + #: src/chatty-message-row.c:81 msgid "Copy" msgstr "Copia" @@ -383,12 +356,12 @@ msgstr "Copia" msgid "Open Message" msgstr "Apri messaggio" -#: src/chatty-notification.c:213 +#: src/chatty-notification.c:214 #, c-format msgid "New message from %s" msgstr "Nuovo messaggio da %s" -#: src/chatty-notification.c:215 +#: src/chatty-notification.c:216 msgid "Message Received" msgstr "Messaggio ricevuto" @@ -501,33 +474,28 @@ msgstr "" "Pandolfo Antonio \n" "Vittorio , 2021" -#: src/chatty-window.c:803 +#: src/chatty-window.c:804 msgid "Any Protocol" msgstr "Qualsiasi Protocollo" -#: src/chatty-window.c:804 src/ui/chatty-settings-dialog.ui:556 +#: src/chatty-window.c:805 src/ui/chatty-settings-dialog.ui:551 msgid "Matrix" msgstr "Matrix" -#: src/chatty-window.c:805 +#: src/chatty-window.c:806 msgid "SMS/MMS" msgstr "SMS/MMS" -#: src/chatty-window.c:808 src/ui/chatty-settings-dialog.ui:544 +#: src/chatty-window.c:809 src/ui/chatty-settings-dialog.ui:539 msgid "XMPP" msgstr "XMPP" -#: src/chatty-window.c:811 src/ui/chatty-settings-dialog.ui:570 +#: src/chatty-window.c:812 src/ui/chatty-settings-dialog.ui:565 msgid "Telegram" msgstr "Telegram" -#: src/chatty-window.c:848 -#, c-format -msgid "“%s” is not a valid phone number" -msgstr "“%s” non è un numero di telefono valido" - #: src/dialogs/chatty-mm-chat-info.c:116 -#: src/dialogs/chatty-new-chat-dialog.c:553 +#: src/dialogs/chatty-new-chat-dialog.c:552 msgid "Unknown Contact" msgstr "Contatto sconosciuto" @@ -587,7 +555,7 @@ msgstr "ID Matrix:" msgid "Telegram ID:" msgstr "ID Telegram:" -#: src/dialogs/chatty-new-chat-dialog.c:305 +#: src/dialogs/chatty-new-chat-dialog.c:304 #, c-format msgid "Error opening GNOME Contacts: %s" msgstr "Errore durante l'apertura dei Contatti GNOME: %s" @@ -607,24 +575,23 @@ msgstr "connessione in corso…" msgid "disconnected" msgstr "disconnesso" -#: src/dialogs/chatty-settings-dialog.c:227 -#: src/dialogs/chatty-settings-dialog.c:391 +#: src/dialogs/chatty-settings-dialog.c:210 +#: src/dialogs/chatty-settings-dialog.c:374 msgid "Failed to verify server" msgstr "Impossibile verificare il server" -#: src/dialogs/chatty-settings-dialog.c:278 -#: src/dialogs/chatty-settings-dialog.c:371 -#| msgid "Enter the matrix home server address." +#: src/dialogs/chatty-settings-dialog.c:261 +#: src/dialogs/chatty-settings-dialog.c:354 msgid "Couldn't get Home server address" msgstr "Impossibile ottenere l'indirizzo del server personale" -#: src/dialogs/chatty-settings-dialog.c:498 +#: src/dialogs/chatty-settings-dialog.c:479 #: src/ui/chatty-ma-account-details.ui:182 #: src/ui/chatty-pp-account-details.ui:199 msgid "Delete Account" msgstr "Elimina l'account" -#: src/dialogs/chatty-settings-dialog.c:501 +#: src/dialogs/chatty-settings-dialog.c:482 #, c-format msgid "Delete account %s?" msgstr "Eliminare l'account %s?" @@ -634,30 +601,38 @@ msgid "Restart chatty to disable purple" msgstr "Riavvia Chatty per disattivare purple" #: src/dialogs/chatty-settings-dialog.c:620 -#: src/ui/chatty-settings-dialog.ui:441 +#: src/ui/chatty-settings-dialog.ui:436 msgid "Enable purple plugin" msgstr "Attiva il plugin purple" #: src/dialogs/chatty-settings-dialog.c:634 -#: src/ui/chatty-settings-dialog.ui:285 +#: src/ui/chatty-settings-dialog.ui:278 msgid "SMS and MMS Settings" msgstr "Impostazioni SMS e MMS" #: src/dialogs/chatty-settings-dialog.c:636 -#: src/ui/chatty-settings-dialog.ui:304 -#| msgid "MMS Carrier Settings" +#: src/ui/chatty-settings-dialog.ui:297 msgid "Purple Settings" msgstr "Impostazioni purple" -#: src/dialogs/chatty-settings-dialog.c:638 src/ui/chatty-settings-dialog.ui:7 +#: src/dialogs/chatty-settings-dialog.c:638 +msgid "New Account" +msgstr "Nuovo account" + +#: src/dialogs/chatty-settings-dialog.c:640 src/ui/chatty-settings-dialog.ui:7 #: src/ui/chatty-window.ui:17 msgid "Preferences" msgstr "Preferenze" -#: src/dialogs/chatty-settings-dialog.c:667 +#: src/dialogs/chatty-settings-dialog.c:669 msgid "Select Protocol" msgstr "Seleziona Protocollo" +#. TRANSLATORS: Only translate 'or' +#: src/dialogs/chatty-settings-dialog.c:865 +msgid "@user:matrix.org or user@example.com" +msgstr "@user:matrix.org oppure user@example.com" + #: src/matrix/chatty-ma-account.c:296 msgid "Incorrect password" msgstr "Password errata" @@ -717,6 +692,22 @@ msgstr "Il certificato per ‘%s’ è stato revocato" msgid "Error validating certificate for ‘%s’" msgstr "Errore durante la convalida del certificato per ‘%s’" +#. TRANSLATORS: Timestamp for minute accuracy, e.g. “2020-08-11 15:27”. +#. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format +#. +#: src/mm/chatty-mmsd.c:867 +msgid "%Y-%m-%d %H:%M" +msgstr "%Y-%m-%d %H:%M" + +#: src/mm/chatty-mmsd.c:1149 +#, c-format +msgid "You received an MMS, but it expired on: %s" +msgstr "Hai ricevuto un MMS, ma è scaduto il: %s" + +#: src/mm/chatty-mmsd.c:1152 +msgid "You received an empty MMS." +msgstr "Hai ricevuto un MMS vuoto." + #: src/ui/chatty-dialog-join-muc.ui:17 msgid "New Group Chat" msgstr "Nuova chat di gruppo" @@ -881,7 +872,7 @@ msgstr "ID Account" msgid "Protocol" msgstr "Protocollo" -#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:629 +#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:625 msgid "Password" msgstr "Password" @@ -909,93 +900,91 @@ msgstr "_Applica" msgid "Accounts" msgstr "Account" -#: src/ui/chatty-settings-dialog.ui:181 -msgid "Add _new account…" -msgstr "Aggiungi _nuovo account…" - -#: src/ui/chatty-settings-dialog.ui:195 src/ui/chatty-settings-dialog.ui:460 +#: src/ui/chatty-settings-dialog.ui:188 src/ui/chatty-settings-dialog.ui:455 msgid "Privacy" msgstr "Privacy" -#: src/ui/chatty-settings-dialog.ui:201 +#: src/ui/chatty-settings-dialog.ui:194 msgid "Message Receipts" msgstr "Conferme messaggi" -#: src/ui/chatty-settings-dialog.ui:202 +#: src/ui/chatty-settings-dialog.ui:195 msgid "Confirm received messages" msgstr "Conferma i messaggi ricevuti" -#: src/ui/chatty-settings-dialog.ui:217 +#: src/ui/chatty-settings-dialog.ui:210 msgid "Typing Notification" msgstr "Notifica di scrittura " -#: src/ui/chatty-settings-dialog.ui:218 +#: src/ui/chatty-settings-dialog.ui:211 msgid "Send typing messages" msgstr "Invia notifiche di scrittura" -#: src/ui/chatty-settings-dialog.ui:236 +#: src/ui/chatty-settings-dialog.ui:229 msgid "Editor" msgstr "Editor" -#: src/ui/chatty-settings-dialog.ui:241 +#: src/ui/chatty-settings-dialog.ui:234 msgid "Graphical Emoticons" msgstr "Faccine grafiche" -#: src/ui/chatty-settings-dialog.ui:242 +#: src/ui/chatty-settings-dialog.ui:235 msgid "if you type :) it will be changed to 😃" msgstr "se scrivi :) sarà cambiato in 😃" #. TRANSLATORS: Return is the Enter key. -#: src/ui/chatty-settings-dialog.ui:257 +#: src/ui/chatty-settings-dialog.ui:250 msgid "Send Messages with Return" msgstr "Invia messaggi col tasto invio" -#: src/ui/chatty-settings-dialog.ui:273 -#| msgid "Protocol" +#: src/ui/chatty-settings-dialog.ui:266 msgid "Protocol Settings" msgstr "Impostazioni Protocollo" -#: src/ui/chatty-settings-dialog.ui:339 +#: src/ui/chatty-settings-dialog.ui:332 msgid "Request Delivery Reports" msgstr "Richiedi rapporto di consegna" -#: src/ui/chatty-settings-dialog.ui:353 +#: src/ui/chatty-settings-dialog.ui:347 msgid "SMIL for MMS" msgstr "SMIL per gli MMS" -#: src/ui/chatty-settings-dialog.ui:370 +#: src/ui/chatty-settings-dialog.ui:365 msgid "MMS Carrier Settings" msgstr "Impostazioni MMS" -#: src/ui/chatty-settings-dialog.ui:374 +#: src/ui/chatty-settings-dialog.ui:369 msgid "MMSC" msgstr "MMSC" -#: src/ui/chatty-settings-dialog.ui:389 +#: src/ui/chatty-settings-dialog.ui:384 msgid "APN" msgstr "APN" -#: src/ui/chatty-settings-dialog.ui:404 +#: src/ui/chatty-settings-dialog.ui:399 msgid "Proxy" msgstr "Proxy" -#: src/ui/chatty-settings-dialog.ui:466 +#: src/ui/chatty-settings-dialog.ui:461 msgid "Message Archive Management" msgstr "Gestione dell'Archivio dei Messaggi" -#: src/ui/chatty-settings-dialog.ui:467 +#: src/ui/chatty-settings-dialog.ui:462 msgid "Sync conversations with chat server" msgstr "Sincronizza le conversazioni con il server di chat" -#: src/ui/chatty-settings-dialog.ui:482 +#: src/ui/chatty-settings-dialog.ui:477 msgid "Message Carbon Copies" msgstr "Copie carbone del messaggio" -#: src/ui/chatty-settings-dialog.ui:665 -#| msgid "Homeserver" +#: src/ui/chatty-settings-dialog.ui:661 msgid "Home server" msgstr "Server personale" +#: src/ui/chatty-settings-dialog.ui:697 +msgid "Add _new account…" +msgstr "Aggiungi _nuovo account…" + #: src/ui/chatty-window.ui:28 msgid "Keyboard _Shortcuts" msgstr "_Scorciatoie da tastiera" diff --git a/po/nl.po b/po/nl.po index 7d3beae..918b01e 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,27 +1,27 @@ # Dutch translation for chatty. # Copyright (C) 2021 chatty's COPYRIGHT HOLDER # This file is distributed under the same license as the chatty package. -# Jan jasper de kroon , 2021. -# Nathan Follens , 2021. +# Jan Jasper de Kroon , 2021. +# Nathan Follens , 2021. # # msgid "" msgstr "" "Project-Id-Version: chatty master\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/chatty/issues\n" -"POT-Creation-Date: 2021-04-04 03:25+0000\n" -"PO-Revision-Date: 2021-04-05 17:57+0200\n" -"Last-Translator: Nathan Follens \n" +"POT-Creation-Date: 2021-12-26 03:25+0000\n" +"PO-Revision-Date: 2021-12-27 11:23+0100\n" +"Last-Translator: Nathan Follens \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.2\n" +"X-Generator: Poedit 3.0.1\n" #: data/sm.puri.Chatty.desktop.in:3 data/sm.puri.Chatty.metainfo.xml.in:6 -#: src/chatty-application.c:326 src/ui/chatty-window.ui:221 +#: src/chatty-application.c:313 src/ui/chatty-window.ui:200 msgid "Chats" msgstr "Berichten" @@ -62,7 +62,7 @@ msgstr "" msgid "Message carbon copies" msgstr "Kopieën van berichten" -#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:177 +#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:478 msgid "Share chat history among devices" msgstr "Deel berichtengeschiedenis tussen apparaten" @@ -75,17 +75,21 @@ msgid "Enable MAM archive synchronization from the server" msgstr "Schakel MAM-archiefsynchronisatie vanaf de server in" #: data/sm.puri.Chatty.gschema.xml:37 +msgid "Enable purple" +msgstr "Purple inschakelen" + +#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:435 +msgid "Enable purple accounts" +msgstr "Purple-accounts inschakelen" + +#: data/sm.puri.Chatty.gschema.xml:43 msgid "Send typing notifications" msgstr "Typmeldingen verzenden" -#: data/sm.puri.Chatty.gschema.xml:38 +#: data/sm.puri.Chatty.gschema.xml:44 msgid "Whether to Send typing notifications" msgstr "Of u typmeldingen wilt verzenden" -#: data/sm.puri.Chatty.gschema.xml:43 data/sm.puri.Chatty.gschema.xml:44 -msgid "Mark offline users differently" -msgstr "Offline gebruikers anders markeren" - #: data/sm.puri.Chatty.gschema.xml:49 data/sm.puri.Chatty.gschema.xml:50 msgid "Mark Idle users differently" msgstr "Inactieve gebruikers anders markeren" @@ -111,26 +115,34 @@ msgid "Whether pressing Enter key sends the message" msgstr "Of het indrukken van de Enter-toets het bericht verzendt" #: data/sm.puri.Chatty.gschema.xml:73 +msgid "Request SMS delivery reports" +msgstr "Sms-ontvangstbevestiging vragen" + +#: data/sm.puri.Chatty.gschema.xml:74 +msgid "Whether to request delivery reports for outgoing SMS" +msgstr "Ontvangstbevestiging voor uitgaande sms’en aanvragen" + +#: data/sm.puri.Chatty.gschema.xml:79 msgid "Enable experimental features" msgstr "Experimentele functies inschakelen" -#: data/sm.puri.Chatty.gschema.xml:74 +#: data/sm.puri.Chatty.gschema.xml:80 msgid "Whether to enable experimental features" msgstr "Of experimentele functies ingeschakeld moeten worden" -#: data/sm.puri.Chatty.gschema.xml:79 +#: data/sm.puri.Chatty.gschema.xml:85 msgid "Window maximized" msgstr "Venster gemaximaliseerd" -#: data/sm.puri.Chatty.gschema.xml:80 +#: data/sm.puri.Chatty.gschema.xml:86 msgid "Window maximized state" msgstr "Venstermaximalisatiestaat" -#: data/sm.puri.Chatty.gschema.xml:85 +#: data/sm.puri.Chatty.gschema.xml:91 msgid "Window size" msgstr "Venstergrootte" -#: data/sm.puri.Chatty.gschema.xml:86 +#: data/sm.puri.Chatty.gschema.xml:92 msgid "Window size (width, height)." msgstr "Venstergrootte (breedte, hoogte)." @@ -146,89 +158,99 @@ msgstr "Berichten is een berichtentoepassing die XMPP en sms ondersteunt." msgid "Chats message window" msgstr "Chatberichtvenster" -#: src/chatty-application.c:73 +#: src/chatty-application.c:75 msgid "Show release version" msgstr "Uitgaveversie tonen" -#: src/chatty-application.c:74 +#: src/chatty-application.c:76 msgid "Start in daemon mode" msgstr "Opstarten in daemonmodus" -#: src/chatty-application.c:75 +#: src/chatty-application.c:77 msgid "Disable all accounts" msgstr "Alle accounts uitschakelen" -#: src/chatty-application.c:76 +#: src/chatty-application.c:78 msgid "Enable libpurple debug messages" msgstr "Libpurple-foutopsporingsberichten inschakelen" -#: src/chatty-application.c:78 +#: src/chatty-application.c:80 msgid "Enable verbose libpurple debug messages" msgstr "Uitgebreide libpurple-foutopsporingsberichten inschakelen" -#: src/chatty-application.c:128 -#, c-format -msgid "Authorize %s?" -msgstr "%s autoriseren?" - -#: src/chatty-application.c:132 src/matrix/matrix-utils.c:508 -msgid "Reject" -msgstr "Weigeren" - -#: src/chatty-application.c:134 src/matrix/matrix-utils.c:509 -msgid "Accept" -msgstr "Accepteren" - -#: src/chatty-application.c:139 -#, c-format -msgid "Add %s to contact list" -msgstr "%s toevoegen aan contacten" - -#: src/chatty-application.c:162 -msgid "Contact added" -msgstr "Contact toegevoegd" - -#: src/chatty-application.c:165 +#: src/chatty-application.c:141 #, c-format -msgid "User %s has added %s to the contacts" -msgstr "Gebruiker %s heeft %s toegevoegd aan de contacten" +msgid "" +"There was an error displaying help:\n" +"%s" +msgstr "" +"Er is een fout opgetreden bij het weergeven van de hulptekst:\n" +"%s" -#: src/chatty-application.c:185 -msgid "Login failed" -msgstr "Aanmelden mislukt" +#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:257 +msgid "Send To" +msgstr "Verzenden naar" -#: src/chatty-application.c:191 -msgid "Please check ID and password" -msgstr "Controleer ID en wachtwoord" +#: src/chatty-chat-list.c:152 +msgid "Select a contact with the “+” button in the titlebar." +msgstr "Selecteer een contact met de ‘+’-knop in de titelbalk." -#: src/chatty-chat-view.c:71 src/chatty-chat-view.c:76 -msgid "This is an IM conversation." -msgstr "Dit is een chatgesprek." +#: src/chatty-chat-list.c:156 +msgid "Add instant messaging accounts in Preferences." +msgstr "Voeg chataccounts toe in de Voorkeuren." -#: src/chatty-chat-view.c:72 src/chatty-chat-view.c:82 -msgid "Your messages are not encrypted," -msgstr "Uw berichten zijn niet versleuteld," +#: src/chatty-chat-list.c:192 src/ui/chatty-dialog-new-chat.ui:258 +msgid "No Search Results" +msgstr "Geen resultaten gevonden" -#: src/chatty-chat-view.c:73 -msgid "ask your counterpart to use E2EE." -msgstr "vraag uw gesprekspartner om versleuteling te gebruiken." +#: src/chatty-chat-list.c:193 +msgid "Try different search" +msgstr "Probeer een andere zoekopdracht" -#: src/chatty-chat-view.c:77 -msgid "Your messages are secured" -msgstr "Uw berichten zijn beveiligd" +#: src/chatty-chat-list.c:196 +msgid "Start Chatting" +msgstr "Begin een gesprek" -#: src/chatty-chat-view.c:78 -msgid "by end-to-end encryption." -msgstr "door eind-tot-eind-versleuteling." +#: src/chatty-chat-view.c:203 +msgid "This is an SMS conversation" +msgstr "Dit is een sms-gesprek" -#: src/chatty-chat-view.c:81 -msgid "This is an SMS conversation." -msgstr "Dit is een sms-gesprek." +#: src/chatty-chat-view.c:205 src/chatty-chat-view.c:211 +msgid "Your messages are not encrypted, and carrier rates may apply" +msgstr "" +"Uw berichten zijn niet versleuteld, en er kunnen tarieven van toepassing zijn" + +#: src/chatty-chat-view.c:209 +msgid "This is an IM conversation" +msgstr "Dit is een chatgesprek" + +#: src/chatty-chat-view.c:215 +msgid "Your messages are encrypted" +msgstr "Uw berichten zijn versleuteld" + +#: src/chatty-chat-view.c:218 +msgid "Your messages are not encrypted" +msgstr "Uw berichten zijn niet versleuteld" + +#: src/chatty-chat-view.c:396 +msgid "Select File..." +msgstr "Selecteer bestand…" + +#: src/chatty-chat-view.c:399 src/purple/chatty-purple-request.c:175 +#: src/chatty-window.c:395 src/dialogs/chatty-pp-chat-info.c:90 +#: src/dialogs/chatty-ma-account-details.c:119 +#: src/dialogs/chatty-pp-account-details.c:91 +#: src/ui/chatty-dialog-join-muc.ui:21 src/ui/chatty-info-dialog.ui:44 +#: src/ui/chatty-info-dialog.ui:54 +msgid "Cancel" +msgstr "Annuleren" -# De voorgaande zin eindigt met een punt, dus de bron zou hier ook met een hoofdletter moeten beginnen. - Nathan -#: src/chatty-chat-view.c:83 -msgid "and carrier rates may apply." -msgstr "Er kunnen kosten aan verbonden zijn." +#: src/chatty-chat-view.c:400 src/purple/chatty-purple-request.c:177 +#: src/dialogs/chatty-pp-chat-info.c:89 +#: src/dialogs/chatty-ma-account-details.c:118 +#: src/dialogs/chatty-pp-account-details.c:90 +msgid "Open" +msgstr "Openen" #. TRANSLATORS: %s is the Device ID #: src/chatty-fp-row.c:131 @@ -237,389 +259,473 @@ msgid "Device ID %s fingerprint:" msgstr "Vingerafdruk van apparaat-ID %s:" #. Translators: Timestamp seconds suffix -#: src/chatty-list-row.c:73 +#: src/chatty-list-row.c:80 msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "s" #. Translators: Timestamp minute suffix -#: src/chatty-list-row.c:75 +#: src/chatty-list-row.c:82 msgctxt "timestamp-suffix-minute" msgid "m" msgstr "m" #. Translators: Timestamp minutes suffix -#: src/chatty-list-row.c:77 +#: src/chatty-list-row.c:84 msgctxt "timestamp-suffix-minutes" msgid "m" msgstr "m" #. Translators: Timestamp hour suffix -#: src/chatty-list-row.c:79 +#: src/chatty-list-row.c:86 msgctxt "timestamp-suffix-hour" msgid "h" msgstr "u" #. Translators: Timestamp hours suffix -#: src/chatty-list-row.c:81 +#: src/chatty-list-row.c:88 msgctxt "timestamp-suffix-hours" msgid "h" msgstr "u" #. Translators: Timestamp day suffix -#: src/chatty-list-row.c:83 +#: src/chatty-list-row.c:90 msgctxt "timestamp-suffix-day" msgid "d" msgstr "d" #. Translators: Timestamp days suffix -#: src/chatty-list-row.c:85 +#: src/chatty-list-row.c:92 msgctxt "timestamp-suffix-days" msgid "d" msgstr "d" #. Translators: Timestamp month suffix -#: src/chatty-list-row.c:87 +#: src/chatty-list-row.c:94 msgctxt "timestamp-suffix-month" msgid "mo" msgstr "mnd" #. Translators: Timestamp months suffix -#: src/chatty-list-row.c:89 +#: src/chatty-list-row.c:96 msgctxt "timestamp-suffix-months" msgid "mos" msgstr "mnd" #. Translators: Timestamp year suffix -#: src/chatty-list-row.c:91 +#: src/chatty-list-row.c:98 msgctxt "timestamp-suffix-year" msgid "y" msgstr "j" #. Translators: Timestamp years suffix -#: src/chatty-list-row.c:93 +#: src/chatty-list-row.c:100 msgctxt "timestamp-suffix-years" msgid "y" msgstr "j" #. Translators: Timestamp prefix (e.g. Over 5h) -#: src/chatty-list-row.c:195 +#: src/chatty-list-row.c:202 msgid "Over" msgstr "Over" #. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/chatty-list-row.c:200 +#: src/chatty-list-row.c:207 msgid "Almost" msgstr "Bijna" -#: src/chatty-list-row.c:217 +#: src/chatty-list-row.c:270 msgid "Owner" msgstr "Eigenaar" -#: src/chatty-list-row.c:220 +#: src/chatty-list-row.c:273 msgid "Moderator" msgstr "Moderator" -#: src/chatty-list-row.c:223 +#: src/chatty-list-row.c:276 msgid "Member" msgstr "Lid" -#: src/chatty-message-row.c:91 +#: src/chatty-manager.c:726 +#, c-format +msgid "“%s” is not a valid URI" +msgstr "‘%s’ is geen geldige URI" + +#: src/chatty-message-row.c:81 msgid "Copy" msgstr "Kopiëren" -#: src/chatty-notification.c:166 +#: src/chatty-notification.c:181 msgid "Open Message" msgstr "Bericht openen" -#: src/chatty-notification.c:201 +#: src/chatty-notification.c:214 #, c-format msgid "New message from %s" msgstr "Nieuw bericht van %s" -#: src/chatty-notification.c:203 +#: src/chatty-notification.c:216 msgid "Message Received" msgstr "Bericht ontvangen" -#: src/chatty-purple-notify.c:44 src/matrix/matrix-utils.c:504 +#: src/purple/chatty-purple-notify.c:44 src/matrix/matrix-utils.c:505 msgid "Close" msgstr "Sluiten" -#: src/chatty-purple-request.c:186 +#: src/purple/chatty-purple-request.c:170 msgid "Save File..." msgstr "Bestand opslaan…" -#: src/chatty-purple-request.c:187 +#: src/purple/chatty-purple-request.c:171 msgid "Open File..." msgstr "Bestand openen…" -#: src/chatty-purple-request.c:191 src/chatty-window.c:583 -#: src/dialogs/chatty-settings-dialog.c:580 src/ui/chatty-dialog-join-muc.ui:16 -#: src/ui/chatty-info-dialog.ui:44 src/ui/chatty-info-dialog.ui:551 -msgid "Cancel" -msgstr "Annuleren" - -#: src/chatty-purple-request.c:193 +#: src/purple/chatty-purple-request.c:177 msgid "Save" msgstr "Opslaan" -#: src/chatty-purple-request.c:193 src/dialogs/chatty-settings-dialog.c:579 -#: src/ui/chatty-info-dialog.ui:558 -msgid "Open" -msgstr "Openen" +#: src/purple/chatty-purple.c:240 +msgid "Contact added" +msgstr "Contact toegevoegd" + +#: src/purple/chatty-purple.c:242 +#, c-format +msgid "User %s has added %s to the contacts" +msgstr "Gebruiker %s heeft %s toegevoegd aan de contacten" -#: src/chatty-secret-store.c:81 +#: src/purple/chatty-purple.c:262 +#, c-format +msgid "Authorize %s?" +msgstr "%s autoriseren?" + +#: src/purple/chatty-purple.c:264 src/matrix/matrix-utils.c:509 +msgid "Reject" +msgstr "Weigeren" + +#: src/purple/chatty-purple.c:265 src/matrix/matrix-utils.c:510 +msgid "Accept" +msgstr "Accepteren" + +#: src/purple/chatty-purple.c:268 +#, c-format +msgid "Add %s to contact list" +msgstr "%s toevoegen aan contacten" + +#: src/purple/chatty-purple.c:587 +msgid "Login failed" +msgstr "Aanmelden mislukt" + +#: src/purple/chatty-purple.c:592 +msgid "Please check ID and password" +msgstr "Controleer ID en wachtwoord" + +#: src/chatty-secret-store.c:98 #, c-format msgid "Chatty password for \"%s\"" -msgstr "Chatty-wachtwoord voor \"%s\"" +msgstr "Chatty-wachtwoord voor ‘%s’" #. TRANSLATORS: Timestamp from the last week with 24 hour time, e.g. “Tuesday 18∶42”. #. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format #. -#: src/chatty-utils.c:377 +#: src/chatty-utils.c:398 msgid "%A %H∶%M" msgstr "%A, %H∶%M" #. TRANSLATORS: Timestamp from the last week with 12 hour time, e.g. “Tuesday 06∶42 PM”. #. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format #. -#: src/chatty-utils.c:382 +#: src/chatty-utils.c:403 msgid "%A %I∶%M %p" msgstr "%A, %I∶%M %p" #. TRANSLATORS: Timestamp from more than 7 days ago, e.g. “2020-08-11”. #. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format #. -#: src/chatty-utils.c:389 +#: src/chatty-utils.c:410 msgid "%Y-%m-%d" msgstr "%d-%m-%Y" -#: src/chatty-window.c:106 src/chatty-window.c:111 src/chatty-window.c:116 -msgid "Choose a contact" -msgstr "Kies een contact" - -#: src/chatty-window.c:107 -msgid "" -"Select an SMS or Instant Message contact with the \"+\" " -"button in the titlebar." -msgstr "" -"Selecteer een sms- of chatcontact met de ‘+’-knop in de " -"titelbalk." - -#: src/chatty-window.c:112 -msgid "" -"Select an Instant Message contact with the \"+\" button in the " -"titlebar." -msgstr "Selecteer een chatcontact met de ‘+’-knop in de titelbalk." - -#: src/chatty-window.c:117 -msgid "Start a SMS chat with the \"+\" button in the titlebar." -msgstr "Begin een sms-gesprek met de ‘+’-knop in de titelbalk." - -#: src/chatty-window.c:118 src/chatty-window.c:122 -msgid "" -"For Instant Messaging add or activate an account in \"preferences" -"\"." -msgstr "" -"Voor chatdiensten kunt u een account toevoegen of activeren in de " -"voorkeuren." - -#: src/chatty-window.c:121 -msgid "Start chatting" -msgstr "Begin het gesprek" - -#: src/chatty-window.c:568 -msgid "Delete chat with" -msgstr "Gesprek verwijderen met" +#: src/chatty-window.c:381 +#, c-format +msgid "Delete chat with “%s”" +msgstr "Gesprek met ‘%s’ verwijderen" -#: src/chatty-window.c:569 +#: src/chatty-window.c:382 msgid "This deletes the conversation history" msgstr "Hiermee wordt de gespreksgeschiedenis verwijderd" -#: src/chatty-window.c:571 -msgid "Disconnect group chat" -msgstr "Groepsgesprek verlaten" +#: src/chatty-window.c:384 +#, c-format +msgid "Disconnect group chat “%s”" +msgstr "Groepsgesprek ‘%s’ verlaten" -#: src/chatty-window.c:572 +#: src/chatty-window.c:385 msgid "This removes chat from chats list" msgstr "Dit verwijdert het gesprek uit de gesprekslijst" -#: src/chatty-window.c:585 +#: src/chatty-window.c:397 msgid "Delete" msgstr "Verwijderen" -#: src/chatty-window.c:677 -#, c-format -msgid "Error saving contact: %s" -msgstr "Fout bij opslaan van contact: %s" - -#: src/chatty-window.c:822 +#: src/chatty-window.c:522 msgid "An SMS and XMPP messaging client" msgstr "Een sms- en XMPP-berichtencliënt" -#: src/chatty-window.c:829 +#: src/chatty-window.c:529 msgid "translator-credits" msgstr "" -"Jan jasper de kroon \n" -"Nathan Follens \n" +"Jan Jasper de Kroon \n" +"Nathan Follens \n" "\n" "Meer info over Gnome-NL http://nl.gnome.org" -#: src/chatty-window.c:1129 -#, c-format -msgid "“%s” is not a valid phone number" -msgstr "\"%s\" is geen geldig telefoonnummer" +#: src/chatty-window.c:804 +msgid "Any Protocol" +msgstr "Elk protocol" -#: src/dialogs/chatty-info-dialog.c:78 -#, c-format -msgid "%u Member" -msgid_plural "%u Members" -msgstr[0] "%u lid" -msgstr[1] "%u leden" +#: src/chatty-window.c:805 src/ui/chatty-settings-dialog.ui:551 +msgid "Matrix" +msgstr "Matrix" + +#: src/chatty-window.c:806 +msgid "SMS/MMS" +msgstr "Sms/mms" + +#: src/chatty-window.c:809 src/ui/chatty-settings-dialog.ui:539 +msgid "XMPP" +msgstr "XMPP" + +#: src/chatty-window.c:812 src/ui/chatty-settings-dialog.ui:565 +msgid "Telegram" +msgstr "Telegram" + +#: src/dialogs/chatty-mm-chat-info.c:116 +#: src/dialogs/chatty-new-chat-dialog.c:552 +msgid "Unknown Contact" +msgstr "Onbekend contact" + +#: src/dialogs/chatty-mm-chat-info.c:134 +msgctxt "Refer to self in contact list" +msgid "You" +msgstr "U" + +#: src/dialogs/chatty-pp-chat-info.c:86 +#: src/dialogs/chatty-ma-account-details.c:115 +#: src/dialogs/chatty-pp-account-details.c:87 +msgid "Set Avatar" +msgstr "Avatar instellen" + +#: src/dialogs/chatty-pp-chat-info.c:96 +#: src/dialogs/chatty-ma-account-details.c:125 +#: src/dialogs/chatty-pp-account-details.c:97 +msgid "Images" +msgstr "Afbeeldingen" -#: src/dialogs/chatty-info-dialog.c:106 +#: src/dialogs/chatty-pp-chat-info.c:206 msgid "Encryption is not available" msgstr "Versleuteling is niet beschikbaar" -#: src/dialogs/chatty-info-dialog.c:110 +#: src/dialogs/chatty-pp-chat-info.c:210 msgid "This chat is encrypted" msgstr "Dit gesprek is versleuteld" -#: src/dialogs/chatty-info-dialog.c:114 +#: src/dialogs/chatty-pp-chat-info.c:214 msgid "This chat is not encrypted" msgstr "Dit gesprek is niet versleuteld" -#: src/dialogs/chatty-info-dialog.c:138 +#: src/dialogs/chatty-pp-chat-info.c:238 msgid "Encryption not available" msgstr "Versleuteling niet beschikbaar" -#: src/dialogs/chatty-info-dialog.c:174 +#: src/dialogs/chatty-pp-chat-info.c:259 +#, c-format +msgid "%u Member" +msgid_plural "%u Members" +msgstr[0] "%u lid" +msgstr[1] "%u leden" + +#: src/dialogs/chatty-pp-chat-info.c:293 msgid "Phone Number:" msgstr "Telefoonnummer:" -#: src/dialogs/chatty-info-dialog.c:176 +#: src/dialogs/chatty-pp-chat-info.c:295 msgid "XMPP ID:" msgstr "XMPP-ID:" -#: src/dialogs/chatty-info-dialog.c:181 +#: src/dialogs/chatty-pp-chat-info.c:300 msgid "Matrix ID:" msgstr "Matrix-ID:" -#: src/dialogs/chatty-info-dialog.c:185 +#: src/dialogs/chatty-pp-chat-info.c:303 msgid "Telegram ID:" msgstr "Telegram-ID:" -#: src/dialogs/chatty-new-chat-dialog.c:152 -msgid "Send To" -msgstr "Verzenden naar" - -#: src/dialogs/chatty-new-chat-dialog.c:196 +#: src/dialogs/chatty-new-chat-dialog.c:304 #, c-format msgid "Error opening GNOME Contacts: %s" msgstr "Fout bij openen van Gnome Contacten: %s" -#: src/dialogs/chatty-settings-dialog.c:425 -msgid "Select Protocol" -msgstr "Selecteer protocol" - -#: src/dialogs/chatty-settings-dialog.c:455 +#: src/dialogs/chatty-ma-account-details.c:385 +#: src/dialogs/chatty-pp-account-details.c:178 msgid "connected" msgstr "verbonden" -#: src/dialogs/chatty-settings-dialog.c:457 +#: src/dialogs/chatty-ma-account-details.c:387 +#: src/dialogs/chatty-pp-account-details.c:180 msgid "connecting…" msgstr "verbinden…" -#: src/dialogs/chatty-settings-dialog.c:459 +#: src/dialogs/chatty-ma-account-details.c:389 +#: src/dialogs/chatty-pp-account-details.c:182 msgid "disconnected" msgstr "verbinding verbroken" -#: src/dialogs/chatty-settings-dialog.c:576 src/ui/chatty-info-dialog.ui:546 -msgid "Set Avatar" -msgstr "Avatar instellen" +#: src/dialogs/chatty-settings-dialog.c:210 +#: src/dialogs/chatty-settings-dialog.c:374 +msgid "Failed to verify server" +msgstr "Kan server niet verifiëren" -#: src/dialogs/chatty-settings-dialog.c:660 -#: src/ui/chatty-settings-dialog.ui:476 +#: src/dialogs/chatty-settings-dialog.c:261 +#: src/dialogs/chatty-settings-dialog.c:354 +msgid "Couldn't get Home server address" +msgstr "Kan thuisserveradres niet ophalen" + +#: src/dialogs/chatty-settings-dialog.c:479 +#: src/ui/chatty-ma-account-details.ui:182 +#: src/ui/chatty-pp-account-details.ui:199 msgid "Delete Account" msgstr "Account verwijderen" -#: src/dialogs/chatty-settings-dialog.c:663 +#: src/dialogs/chatty-settings-dialog.c:482 #, c-format msgid "Delete account %s?" msgstr "Account %s verwijderen?" -#: src/matrix/chatty-ma-account.c:250 +#: src/dialogs/chatty-settings-dialog.c:618 +msgid "Restart chatty to disable purple" +msgstr "Herstart Chatty om Purple uit te schakelen" + +#: src/dialogs/chatty-settings-dialog.c:620 +#: src/ui/chatty-settings-dialog.ui:436 +msgid "Enable purple plugin" +msgstr "Purple-plug-in inschakelen" + +#: src/dialogs/chatty-settings-dialog.c:634 +#: src/ui/chatty-settings-dialog.ui:278 +msgid "SMS and MMS Settings" +msgstr "Sms- en mms-instellingen" + +#: src/dialogs/chatty-settings-dialog.c:636 +#: src/ui/chatty-settings-dialog.ui:297 +msgid "Purple Settings" +msgstr "Purple-instellingen" + +#: src/dialogs/chatty-settings-dialog.c:638 +msgid "New Account" +msgstr "Nieuwe account" + +#: src/dialogs/chatty-settings-dialog.c:640 src/ui/chatty-settings-dialog.ui:7 +#: src/ui/chatty-window.ui:17 +msgid "Preferences" +msgstr "Voorkeuren" + +#: src/dialogs/chatty-settings-dialog.c:669 +msgid "Select Protocol" +msgstr "Selecteer protocol" + +#. TRANSLATORS: Only translate 'or' +#: src/dialogs/chatty-settings-dialog.c:865 +msgid "@user:matrix.org or user@example.com" +msgstr "@gebruiker:matrix.org of gebruiker@voorbeeld.nl" + +#: src/matrix/chatty-ma-account.c:296 msgid "Incorrect password" msgstr "Onjuist wachtwoord" -#: src/matrix/chatty-ma-account.c:253 +#: src/matrix/chatty-ma-account.c:299 msgid "_OK" msgstr "_Oké" -#: src/matrix/chatty-ma-account.c:254 src/ui/chatty-settings-dialog.ui:41 -#: src/ui/chatty-settings-dialog.ui:735 +#: src/matrix/chatty-ma-account.c:300 src/ui/chatty-dialog-new-chat.ui:52 +#: src/ui/chatty-settings-dialog.ui:46 src/ui/chatty-settings-dialog.ui:107 msgid "_Cancel" msgstr "_Annuleren" -#: src/matrix/chatty-ma-account.c:260 +#: src/matrix/chatty-ma-account.c:306 #, c-format msgid "Please enter password for “%s”" -msgstr "Voer het wachtwoord in voor \"%s\"" +msgstr "Voer het wachtwoord in voor ‘%s’" -#: src/matrix/chatty-ma-chat.c:158 +#: src/matrix/chatty-ma-chat.c:164 msgid "Empty room" msgstr "Leeg gesprek" -#: src/matrix/chatty-ma-chat.c:162 +#: src/matrix/chatty-ma-chat.c:168 #, c-format msgid "%s and %s" msgstr "%s en %s" -#: src/matrix/chatty-ma-chat.c:164 +#: src/matrix/chatty-ma-chat.c:170 #, c-format msgid "%s and %u other" msgid_plural "%s and %u others" msgstr[0] "%s en %u andere" msgstr[1] "%s en %u anderen" -#: src/matrix/matrix-utils.c:473 +#: src/matrix/matrix-utils.c:474 #, c-format msgid "The certificate for ‘%s’ has unknown CA" msgstr "Het certificaat voor ‘%s’ heeft een onbekende CA" -#: src/matrix/matrix-utils.c:475 +#: src/matrix/matrix-utils.c:476 #, c-format msgid "The certificate for ‘%s’ is self-signed" msgstr "Het certificaat voor ‘%s’ is zelfondertekend" -#: src/matrix/matrix-utils.c:479 +#: src/matrix/matrix-utils.c:480 #, c-format msgid "The certificate for ‘%s’ has expired" msgstr "Het certificaat voor ‘%s’ is verlopen" -#: src/matrix/matrix-utils.c:483 +#: src/matrix/matrix-utils.c:484 #, c-format msgid "The certificate for ‘%s’ has been revoked" msgstr "Het certificaat voor ‘%s’ is ingetrokken" -#: src/matrix/matrix-utils.c:492 +#: src/matrix/matrix-utils.c:493 #, c-format msgid "Error validating certificate for ‘%s’" msgstr "Fout bij valideren van certificaat voor ‘%s’" -#: src/ui/chatty-dialog-join-muc.ui:12 +#. TRANSLATORS: Timestamp for minute accuracy, e.g. “2020-08-11 15:27”. +#. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format +#. +#: src/mm/chatty-mmsd.c:867 +msgid "%Y-%m-%d %H:%M" +msgstr "%d-%m-%Y %H:%M" + +#: src/mm/chatty-mmsd.c:1149 +#, c-format +msgid "You received an MMS, but it expired on: %s" +msgstr "U hebt een mms ontvangen, maar deze is verlopen op: %s" + +#: src/mm/chatty-mmsd.c:1152 +msgid "You received an empty MMS." +msgstr "U hebt een lege mms ontvangen." + +#: src/ui/chatty-dialog-join-muc.ui:17 msgid "New Group Chat" msgstr "Nieuw groepsbericht" -#: src/ui/chatty-dialog-join-muc.ui:28 +#: src/ui/chatty-dialog-join-muc.ui:34 msgid "Join Chat" msgstr "Deelnemen aan gesprek" -#: src/ui/chatty-dialog-join-muc.ui:80 src/ui/chatty-dialog-new-chat.ui:296 +#: src/ui/chatty-dialog-join-muc.ui:82 src/ui/chatty-dialog-new-chat.ui:313 msgid "Select chat account" msgstr "Selecteer een gespreksaccount" -#: src/ui/chatty-dialog-join-muc.ui:150 +#: src/ui/chatty-dialog-join-muc.ui:152 msgid "Password (optional)" msgstr "Wachtwoord (optioneel)" @@ -627,260 +733,389 @@ msgstr "Wachtwoord (optioneel)" msgid "Start Chat" msgstr "Gesprek beginnen" -#: src/ui/chatty-dialog-new-chat.ui:55 +#: src/ui/chatty-dialog-new-chat.ui:63 +msgid "_Create" +msgstr "Aanma_ken" + +#: src/ui/chatty-dialog-new-chat.ui:80 msgid "New Contact" msgstr "Nieuw contact" -#: src/ui/chatty-dialog-new-chat.ui:83 src/ui/chatty-window.ui:125 +#: src/ui/chatty-dialog-new-chat.ui:108 msgid "Add Contact" msgstr "Contact toevoegen" -#: src/ui/chatty-dialog-new-chat.ui:148 +#: src/ui/chatty-dialog-new-chat.ui:183 msgid "Send To:" msgstr "Verzenden naar:" -#: src/ui/chatty-dialog-new-chat.ui:224 -msgid "No Search Results" -msgstr "Geen resultaten gevonden" - -#: src/ui/chatty-dialog-new-chat.ui:237 +#: src/ui/chatty-dialog-new-chat.ui:259 msgid "Try different search, or type a valid number to create new chat" msgstr "" "Probeer een andere zoekopdracht, of voer een geldig nummer in om een nieuw " "gesprek te beginnen" -#: src/ui/chatty-dialog-new-chat.ui:343 +#: src/ui/chatty-dialog-new-chat.ui:360 msgid "Name (optional)" msgstr "Naam (optioneel)" -#: src/ui/chatty-dialog-new-chat.ui:383 src/ui/chatty-window.ui:151 +#: src/ui/chatty-dialog-new-chat.ui:400 msgid "Add to Contacts" msgstr "Toevoegen aan contacten" -#: src/ui/chatty-info-dialog.ui:17 src/ui/chatty-window.ui:111 +#: src/ui/chatty-file-item.ui:28 +msgid "Remove Attachment" +msgstr "Bijlage verwijderen" + +#: src/ui/chatty-info-dialog.ui:17 src/ui/chatty-window.ui:126 msgid "Chat Details" msgstr "Gespreksgegevens" -#: src/ui/chatty-info-dialog.ui:56 +#: src/ui/chatty-info-dialog.ui:64 +msgid "Apply" +msgstr "Toepassen" + +#: src/ui/chatty-info-dialog.ui:82 msgid "Invite" msgstr "Uitnodigen" -#: src/ui/chatty-info-dialog.ui:138 +#: src/ui/chatty-ma-chat-info.ui:67 src/ui/chatty-ma-account-details.ui:233 +msgid "Matrix ID" +msgstr "Matrix-ID" + +#: src/ui/chatty-ma-chat-info.ui:93 src/ui/chatty-pp-chat-info.ui:289 +msgid "Chat settings" +msgstr "Gespreksinstellingen" + +#: src/ui/chatty-ma-chat-info.ui:113 src/ui/chatty-pp-chat-info.ui:238 +#: src/ui/chatty-pp-chat-info.ui:344 +msgid "Encryption" +msgstr "Versleuteling" + +#: src/ui/chatty-ma-chat-info.ui:114 src/ui/chatty-pp-chat-info.ui:345 +msgid "Encrypt Messages" +msgstr "Berichten versleutelen" + +#: src/ui/chatty-pp-chat-info.ui:43 src/ui/chatty-pp-account-details.ui:60 +msgid "Change Avatar" +msgstr "Avatar veranderen" + +#: src/ui/chatty-pp-chat-info.ui:69 src/ui/chatty-pp-account-details.ui:34 +msgid "Delete Avatar" +msgstr "Avatar verwijderen" + +#: src/ui/chatty-pp-chat-info.ui:108 msgid "Room topic" msgstr "Gespreksonderwerp" -#: src/ui/chatty-info-dialog.ui:242 +#: src/ui/chatty-pp-chat-info.ui:211 msgid "XMPP ID" msgstr "XMPP-ID" -#: src/ui/chatty-info-dialog.ui:268 src/ui/chatty-info-dialog.ui:374 -msgid "Encryption" -msgstr "Versleuteling" - -#: src/ui/chatty-info-dialog.ui:294 src/ui/chatty-settings-dialog.ui:389 +#: src/ui/chatty-pp-chat-info.ui:264 src/ui/chatty-ma-account-details.ui:67 +#: src/ui/chatty-pp-account-details.ui:142 msgid "Status" msgstr "Status" -#: src/ui/chatty-info-dialog.ui:319 -msgid "Chat settings" -msgstr "Gespreksinstellingen" - -#: src/ui/chatty-info-dialog.ui:340 +#: src/ui/chatty-pp-chat-info.ui:310 msgid "Notifications" msgstr "Meldingen" -#: src/ui/chatty-info-dialog.ui:357 +#: src/ui/chatty-pp-chat-info.ui:327 msgid "Status Messages" msgstr "Statusberichten" -#: src/ui/chatty-info-dialog.ui:358 +#: src/ui/chatty-pp-chat-info.ui:328 msgid "Show status messages in chat" msgstr "Toon statusberichten in het gesprek" -#: src/ui/chatty-info-dialog.ui:375 -msgid "Encrypt Messages" -msgstr "Berichten versleutelen" - -#: src/ui/chatty-info-dialog.ui:397 +#: src/ui/chatty-pp-chat-info.ui:367 msgid "Fingerprints" msgstr "Vingerafdrukken" -#: src/ui/chatty-settings-dialog.ui:12 src/ui/chatty-window.ui:17 -msgid "Preferences" -msgstr "Voorkeuren" +#: src/ui/chatty-mm-chat-info.ui:29 +msgid "Title" +msgstr "Titel" + +#: src/ui/chatty-mm-chat-info.ui:33 +msgid "Blank for default" +msgstr "Laat leeg voor standaardinstelling" + +#: src/ui/chatty-mm-chat-info.ui:43 +msgid "Group Members" +msgstr "Groepsleden" + +#: src/ui/chatty-ma-account-details.ui:93 +msgid "Name" +msgstr "Naam" + +#: src/ui/chatty-ma-account-details.ui:123 +msgid "Email" +msgstr "Email" + +#: src/ui/chatty-ma-account-details.ui:152 +msgid "Phone" +msgstr "Telefoon" + +#: src/ui/chatty-ma-account-details.ui:196 +msgid "Advanced information" +msgstr "Geavanceerde informatie" + +#: src/ui/chatty-ma-account-details.ui:207 +msgid "Homeserver" +msgstr "Thuisserver" + +#: src/ui/chatty-ma-account-details.ui:259 +msgid "Device ID" +msgstr "Apparaat-ID" + +#: src/ui/chatty-pp-account-details.ui:92 +msgid "Account ID" +msgstr "Account-ID" + +#: src/ui/chatty-pp-account-details.ui:116 +msgid "Protocol" +msgstr "Protocol" + +#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:625 +msgid "Password" +msgstr "Wachtwoord" + +#: src/ui/chatty-pp-account-details.ui:213 +msgid "Own Fingerprint" +msgstr "Eigen vingerafdruk" -#: src/ui/chatty-settings-dialog.ui:21 +#: src/ui/chatty-settings-dialog.ui:26 msgid "Back" msgstr "Terug" -#: src/ui/chatty-settings-dialog.ui:54 +#: src/ui/chatty-settings-dialog.ui:59 msgid "_Add" msgstr "_Toevoegen" -#: src/ui/chatty-settings-dialog.ui:80 +#: src/ui/chatty-settings-dialog.ui:75 msgid "_Save" msgstr "Op_slaan" -#: src/ui/chatty-settings-dialog.ui:114 +#: src/ui/chatty-settings-dialog.ui:91 +msgid "_Apply" +msgstr "Toep_assen" + +#: src/ui/chatty-settings-dialog.ui:168 msgid "Accounts" msgstr "Accounts" -#: src/ui/chatty-settings-dialog.ui:128 -msgid "Add new account…" -msgstr "Nieuwe account toevoegen…" - -#: src/ui/chatty-settings-dialog.ui:141 +#: src/ui/chatty-settings-dialog.ui:188 src/ui/chatty-settings-dialog.ui:455 msgid "Privacy" msgstr "Privacy" -#: src/ui/chatty-settings-dialog.ui:146 +#: src/ui/chatty-settings-dialog.ui:194 msgid "Message Receipts" msgstr "Ontvangstbevestigingen" -#: src/ui/chatty-settings-dialog.ui:147 +#: src/ui/chatty-settings-dialog.ui:195 msgid "Confirm received messages" msgstr "Bevestig ontvangen berichten" -#: src/ui/chatty-settings-dialog.ui:161 -msgid "Message Archive Management" -msgstr "Message Archive Management" - -#: src/ui/chatty-settings-dialog.ui:162 -msgid "Sync conversations with chat server" -msgstr "Synchroniseer gesprekken met de gespreksserver" - -#: src/ui/chatty-settings-dialog.ui:176 -msgid "Message Carbon Copies" -msgstr "Message Carbons" - -#: src/ui/chatty-settings-dialog.ui:191 +#: src/ui/chatty-settings-dialog.ui:210 msgid "Typing Notification" msgstr "Typmeldingen" -#: src/ui/chatty-settings-dialog.ui:192 +#: src/ui/chatty-settings-dialog.ui:211 msgid "Send typing messages" msgstr "Verzend typmeldingen" -#: src/ui/chatty-settings-dialog.ui:209 -msgid "Chats List" -msgstr "Gesprekslijst" - -#: src/ui/chatty-settings-dialog.ui:214 -msgid "Indicate Offline Contacts" -msgstr "Offline contacten aanduiden" - -#: src/ui/chatty-settings-dialog.ui:215 -msgid "Grey out avatars from offline contacts" -msgstr "Maak avatars van offline contacten grijs" - #: src/ui/chatty-settings-dialog.ui:229 -msgid "Indicate Idle Contacts" -msgstr "Inactieve contacten aanduiden" - -#: src/ui/chatty-settings-dialog.ui:230 -msgid "Blur avatars from idle contacts" -msgstr "Vervaag avatars van inactieve contacten" - -#: src/ui/chatty-settings-dialog.ui:244 -msgid "Indicate Unknown Contacts" -msgstr "Onbekende contacten aanduiden" - -#: src/ui/chatty-settings-dialog.ui:245 -msgid "Color unknown contact ID red" -msgstr "Kleur ID’s van onbekende contacten rood" - -#: src/ui/chatty-settings-dialog.ui:262 msgid "Editor" msgstr "Editor" -#: src/ui/chatty-settings-dialog.ui:267 +#: src/ui/chatty-settings-dialog.ui:234 msgid "Graphical Emoticons" msgstr "Grafische emoticons" -#: src/ui/chatty-settings-dialog.ui:268 -msgid "Convert ASCII emoticons" -msgstr "ASCII-emoticons converteren" +#: src/ui/chatty-settings-dialog.ui:235 +msgid "if you type :) it will be changed to 😃" +msgstr "als je u typt, wordt dit veranderd in 😃" -#: src/ui/chatty-settings-dialog.ui:282 -msgid "Return = Send Message" -msgstr "Enter = bericht verzenden" +#. TRANSLATORS: Return is the Enter key. +#: src/ui/chatty-settings-dialog.ui:250 +msgid "Send Messages with Return" +msgstr "Berichten verzenden met Enter" -#: src/ui/chatty-settings-dialog.ui:283 -msgid "Send message with return key" -msgstr "Verzend berichten met Enter" +#: src/ui/chatty-settings-dialog.ui:266 +msgid "Protocol Settings" +msgstr "Protocolinstellingen" -#: src/ui/chatty-settings-dialog.ui:334 -msgid "Account ID" -msgstr "Account-ID" +#: src/ui/chatty-settings-dialog.ui:332 +msgid "Request Delivery Reports" +msgstr "Ontvangstbevestiging vragen" -#: src/ui/chatty-settings-dialog.ui:360 -msgid "Protocol" -msgstr "Protocol" +#: src/ui/chatty-settings-dialog.ui:347 +msgid "SMIL for MMS" +msgstr "SMIL voor mms" -#: src/ui/chatty-settings-dialog.ui:418 src/ui/chatty-settings-dialog.ui:645 -msgid "Password" -msgstr "Wachtwoord" +#: src/ui/chatty-settings-dialog.ui:365 +msgid "MMS Carrier Settings" +msgstr "Mms-providerinstellingen" -#: src/ui/chatty-settings-dialog.ui:494 -msgid "Own Fingerprint" -msgstr "Eigen vingerafdruk" +#: src/ui/chatty-settings-dialog.ui:369 +msgid "MMSC" +msgstr "MMSC" -#: src/ui/chatty-settings-dialog.ui:553 -msgid "XMPP" -msgstr "XMPP" +#: src/ui/chatty-settings-dialog.ui:384 +msgid "APN" +msgstr "APN" -#: src/ui/chatty-settings-dialog.ui:567 -msgid "Matrix" -msgstr "Matrix" +#: src/ui/chatty-settings-dialog.ui:399 +msgid "Proxy" +msgstr "Proxy" -#: src/ui/chatty-settings-dialog.ui:582 -msgid "Telegram" -msgstr "Telegram" +#: src/ui/chatty-settings-dialog.ui:461 +msgid "Message Archive Management" +msgstr "Message Archive Management" -#: src/ui/chatty-settings-dialog.ui:691 -msgid "Matrix Home Server" -msgstr "Matrix-thuisserver" +#: src/ui/chatty-settings-dialog.ui:462 +msgid "Sync conversations with chat server" +msgstr "Synchroniseer gesprekken met de gespreksserver" + +#: src/ui/chatty-settings-dialog.ui:477 +msgid "Message Carbon Copies" +msgstr "Message Carbons" -#: src/ui/chatty-settings-dialog.ui:708 -msgid "Enter the matrix home server address." -msgstr "Voer het adres van de Matrix-thuisserver in." +#: src/ui/chatty-settings-dialog.ui:661 +msgid "Home server" +msgstr "Thuisserver" -#: src/ui/chatty-settings-dialog.ui:726 -msgid "_Accept" -msgstr "_Accepteren" +#: src/ui/chatty-settings-dialog.ui:697 +msgid "Add _new account…" +msgstr "_Nieuwe account toevoegen…" -#: src/ui/chatty-window.ui:30 +#: src/ui/chatty-window.ui:28 +msgid "Keyboard _Shortcuts" +msgstr "_Sneltoetsen" + +#: src/ui/chatty-window.ui:35 +msgid "Help" +msgstr "Hulp" + +#: src/ui/chatty-window.ui:44 msgid "About Chats" msgstr "Over Berichten" -#: src/ui/chatty-window.ui:58 +#: src/ui/chatty-window.ui:72 msgid "New Message…" msgstr "Nieuw bericht…" -#: src/ui/chatty-window.ui:71 +#: src/ui/chatty-window.ui:85 +msgid "New SMS/MMS Message…" +msgstr "Nieuwe sms/mms…" + +#: src/ui/chatty-window.ui:98 msgid "New Group Message…" msgstr "Nieuw groepsbericht…" -#: src/ui/chatty-window.ui:84 -msgid "New Bulk SMS…" -msgstr "Nieuwe bulk-sms…" - -#: src/ui/chatty-window.ui:176 +#: src/ui/chatty-window.ui:151 msgid "Leave Chat" msgstr "Gesprek verlaten" -#: src/ui/chatty-window.ui:189 +#: src/ui/chatty-window.ui:164 msgid "Delete Chat" msgstr "Gesprek verwijderen" -#: src/users/chatty-contact.c:317 +#: src/ui/chatty-window.ui:353 +msgid "Call" +msgstr "Bellen" + +#: src/ui/help-overlay.ui:14 +msgctxt "shortcut window" +msgid "General" +msgstr "Algemeen" + +#: src/ui/help-overlay.ui:19 +msgctxt "shortcut window" +msgid "Open Menu" +msgstr "Menu openen" + +#: src/ui/help-overlay.ui:27 +msgctxt "shortcut window" +msgid "Open Search" +msgstr "Zoekweergave openen" + +#: src/ui/help-overlay.ui:35 +msgctxt "shortcut window" +msgid "Show Shortcuts" +msgstr "Sneltoetsen tonen" + +#: src/users/chatty-contact.c:311 msgid "Mobile: " msgstr "Mobiel: " -#: src/users/chatty-contact.c:319 +#: src/users/chatty-contact.c:313 msgid "Work: " msgstr "Werk: " -#: src/users/chatty-contact.c:321 +#: src/users/chatty-contact.c:315 msgid "Other: " msgstr "Overige: " + +#~ msgid "Mark offline users differently" +#~ msgstr "Offline gebruikers anders markeren" + +#~ msgid "ask your counterpart to use E2EE." +#~ msgstr "vraag uw gesprekspartner om versleuteling te gebruiken." + +#~ msgid "Your messages are secured" +#~ msgstr "Uw berichten zijn beveiligd" + +#~ msgid "by end-to-end encryption." +#~ msgstr "door eind-tot-eind-versleuteling." + +# De voorgaande zin eindigt met een punt, dus de bron zou hier ook met een hoofdletter moeten beginnen. - Nathan +#~ msgid "and carrier rates may apply." +#~ msgstr "Er kunnen kosten aan verbonden zijn." + +#~ msgid "Choose a contact" +#~ msgstr "Kies een contact" + +#~ msgid "" +#~ "Select an SMS or Instant Message contact with the \"+\" button in the titlebar." +#~ msgstr "" +#~ "Selecteer een sms- of chatcontact met de ‘+’-knop in " +#~ "de titelbalk." + +#~ msgid "Start a SMS chat with the \"+\" button in the titlebar." +#~ msgstr "Begin een sms-gesprek met de ‘+’-knop in de titelbalk." + +#~ msgid "Error saving contact: %s" +#~ msgstr "Fout bij opslaan van contact: %s" + +#~ msgid "Chats List" +#~ msgstr "Gesprekslijst" + +#~ msgid "Indicate Offline Contacts" +#~ msgstr "Offline contacten aanduiden" + +#~ msgid "Grey out avatars from offline contacts" +#~ msgstr "Maak avatars van offline contacten grijs" + +#~ msgid "Indicate Idle Contacts" +#~ msgstr "Inactieve contacten aanduiden" + +#~ msgid "Blur avatars from idle contacts" +#~ msgstr "Vervaag avatars van inactieve contacten" + +#~ msgid "Color unknown contact ID red" +#~ msgstr "Kleur ID’s van onbekende contacten rood" + +#~ msgid "Convert ASCII emoticons" +#~ msgstr "ASCII-emoticons converteren" + +#~ msgid "Return = Send Message" +#~ msgstr "Enter = bericht verzenden" + +#~ msgid "_Accept" +#~ msgstr "_Accepteren" + +#~ msgid "New Bulk SMS…" +#~ msgstr "Nieuwe bulk-sms…" diff --git a/po/ro.po b/po/ro.po index 34238dd..228ce82 100644 --- a/po/ro.po +++ b/po/ro.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: chatty master\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/chatty/issues\n" -"POT-Creation-Date: 2021-12-07 15:25+0000\n" -"PO-Revision-Date: 2021-12-03 13:21+0100\n" +"POT-Creation-Date: 2021-12-17 15:24+0000\n" +"PO-Revision-Date: 2021-12-20 21:49+0100\n" "Last-Translator: Florentina Mușat \n" "Language-Team: Romanian \n" "Language: ro\n" @@ -187,13 +187,13 @@ msgstr "" "S-a produs o eroare la afișarea ajutorului:\n" "%s" -#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:258 +#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:257 msgid "Send To" msgstr "Trimite la" #: src/chatty-chat-list.c:152 msgid "Select a contact with the “+” button in the titlebar." -msgstr "Selectați un contact cu butonul „+” din bara de titlu." +msgstr "Alege un contact cu butonul „+” din bara de titlu." #: src/chatty-chat-list.c:156 msgid "Add instant messaging accounts in Preferences." @@ -231,11 +231,11 @@ msgstr "Mesajele sunt codate" msgid "Your messages are not encrypted" msgstr "Mesajele nu sunt codate" -#: src/chatty-chat-view.c:394 +#: src/chatty-chat-view.c:396 msgid "Select File..." msgstr "Alege fișierul..." -#: src/chatty-chat-view.c:397 src/purple/chatty-purple-request.c:175 +#: src/chatty-chat-view.c:399 src/purple/chatty-purple-request.c:175 #: src/chatty-window.c:395 src/dialogs/chatty-pp-chat-info.c:90 #: src/dialogs/chatty-ma-account-details.c:119 #: src/dialogs/chatty-pp-account-details.c:91 @@ -244,7 +244,7 @@ msgstr "Alege fișierul..." msgid "Cancel" msgstr "Anulează" -#: src/chatty-chat-view.c:398 src/purple/chatty-purple-request.c:177 +#: src/chatty-chat-view.c:400 src/purple/chatty-purple-request.c:177 #: src/dialogs/chatty-pp-chat-info.c:89 #: src/dialogs/chatty-ma-account-details.c:118 #: src/dialogs/chatty-pp-account-details.c:90 @@ -345,6 +345,11 @@ msgstr "Moderator" msgid "Member" msgstr "Membru" +#: src/chatty-manager.c:726 +#, c-format +msgid "“%s” is not a valid URI" +msgstr "„%s” nu este un URI valabil" + #: src/chatty-message-row.c:81 msgid "Copy" msgstr "Copiază" @@ -390,7 +395,7 @@ msgstr "Utilizatorul %s a adăugat %s la contacte" #: src/purple/chatty-purple.c:262 #, c-format msgid "Authorize %s?" -msgstr "Autorizați %s?" +msgstr "Autorizezi %s?" #: src/purple/chatty-purple.c:264 src/matrix/matrix-utils.c:509 msgid "Reject" @@ -471,33 +476,28 @@ msgstr "" "Florentina Mușat , " "2020-2021" -#: src/chatty-window.c:803 +#: src/chatty-window.c:804 msgid "Any Protocol" msgstr "Orice Protocol" -#: src/chatty-window.c:804 src/ui/chatty-settings-dialog.ui:551 +#: src/chatty-window.c:805 src/ui/chatty-settings-dialog.ui:551 msgid "Matrix" msgstr "Matrix" -#: src/chatty-window.c:805 +#: src/chatty-window.c:806 msgid "SMS/MMS" msgstr "SMS/MMS" -#: src/chatty-window.c:808 src/ui/chatty-settings-dialog.ui:539 +#: src/chatty-window.c:809 src/ui/chatty-settings-dialog.ui:539 msgid "XMPP" msgstr "XMPP" -#: src/chatty-window.c:811 src/ui/chatty-settings-dialog.ui:565 +#: src/chatty-window.c:812 src/ui/chatty-settings-dialog.ui:565 msgid "Telegram" msgstr "Telegram" -#: src/chatty-window.c:848 -#, c-format -msgid "“%s” is not a valid phone number" -msgstr "„%s” nu este un număr de telefon valabil" - #: src/dialogs/chatty-mm-chat-info.c:116 -#: src/dialogs/chatty-new-chat-dialog.c:553 +#: src/dialogs/chatty-new-chat-dialog.c:552 msgid "Unknown Contact" msgstr "Contact necunoscut" @@ -558,7 +558,7 @@ msgstr "ID Matrix:" msgid "Telegram ID:" msgstr "ID Telegram:" -#: src/dialogs/chatty-new-chat-dialog.c:305 +#: src/dialogs/chatty-new-chat-dialog.c:304 #, c-format msgid "Error opening GNOME Contacts: %s" msgstr "Eroare la deschiderea Contacte GNOME: %s" @@ -696,6 +696,22 @@ msgstr "Certificatul pentru „%s” a fost anulat" msgid "Error validating certificate for ‘%s’" msgstr "Eroare la validarea certificatului pentru „%s”" +#. TRANSLATORS: Timestamp for minute accuracy, e.g. “2020-08-11 15:27”. +#. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format +#. +#: src/mm/chatty-mmsd.c:867 +msgid "%Y-%m-%d %H:%M" +msgstr "%Y-%m-%d %H:%M" + +#: src/mm/chatty-mmsd.c:1149 +#, c-format +msgid "You received an MMS, but it expired on: %s" +msgstr "Ai primit un MMS, dar a expirat în: %s" + +#: src/mm/chatty-mmsd.c:1152 +msgid "You received an empty MMS." +msgstr "Ai primit un MMS gol." + #: src/ui/chatty-dialog-join-muc.ui:17 msgid "New Group Chat" msgstr "Grup nou de discuții" @@ -1038,27 +1054,3 @@ msgstr "Serviciu: " #: src/users/chatty-contact.c:315 msgid "Other: " msgstr "Altele: " - -#~ msgid "Request mmsd to handle SMIL" -#~ msgstr "Solicită ca MMSD să gestioneze SMIL" - -#~ msgid "Whether to request mmsd to create SMIL" -#~ msgstr "Dacă să se solicite ca MMSD să creeze SMIL" - -#~ msgid "Carrier mmsc for mmsd" -#~ msgstr "Operatorul MMSC-ului pentru MMSD" - -#~ msgid "The carrier mmsc to set for mmsd" -#~ msgstr "Operatorul MMSC-ului de stabilit pentru MMSD" - -#~ msgid "Carrier mms apn for mmsd" -#~ msgstr "APN-ul operatorului de MMS pentru MMSD" - -#~ msgid "The mms APN to set for mmsd" -#~ msgstr "APN-ul pentru MMS de stabilit pentru MMSD" - -#~ msgid "Carrier mms proxy for mmsd" -#~ msgstr "Proxy-ul operatorului de MMS pentru MMSD" - -#~ msgid "The mms proxy to set for mmsd" -#~ msgstr "Proxy-ul pentru MMS de stabilit pentru MMSD" diff --git a/po/sv.po b/po/sv.po index 521ddb2..6da2f73 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1,23 +1,23 @@ # Swedish translation for chatty. -# Copyright © 2020, 2021 chatty's COPYRIGHT HOLDER +# Copyright © 2020-2022 chatty's COPYRIGHT HOLDER # This file is distributed under the same license as the chatty package. -# Anders Jonsson , 2020, 2021. -# Luna Jernberg , 2021. +# Anders Jonsson , 2020, 2021, 2022. +# Luna Jernberg , 2021, 2022. # msgid "" msgstr "" "Project-Id-Version: chatty master\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/chatty/issues\n" -"POT-Creation-Date: 2021-12-02 03:25+0000\n" -"PO-Revision-Date: 2021-12-02 14:00+0100\n" -"Last-Translator: Luna Jernberg \n" +"POT-Creation-Date: 2022-01-18 15:25+0000\n" +"PO-Revision-Date: 2022-01-21 22:28+0100\n" +"Last-Translator: Anders Jonsson \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.0\n" +"X-Generator: Poedit 3.0.1\n" #: data/sm.puri.Chatty.desktop.in:3 data/sm.puri.Chatty.metainfo.xml.in:6 #: src/chatty-application.c:313 src/ui/chatty-window.ui:200 @@ -60,7 +60,7 @@ msgstr "Huruvida status för meddelandet ska skickas om det läses" msgid "Message carbon copies" msgstr "Meddelandekopior" -#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:484 +#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:479 msgid "Share chat history among devices" msgstr "Dela chatthistorik mellan enheter" @@ -76,7 +76,7 @@ msgstr "Aktivera MAM-arkivsynkronisering från servern" msgid "Enable purple" msgstr "Aktivera purple" -#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:441 +#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:436 msgid "Enable purple accounts" msgstr "Aktivera purple-konton" @@ -121,58 +121,26 @@ msgid "Whether to request delivery reports for outgoing SMS" msgstr "Huruvida leveransrapporter ska begäras för utgående SMS" #: data/sm.puri.Chatty.gschema.xml:79 -msgid "Request mmsd to handle SMIL" -msgstr "Begär att mmsd hanterar SMIL" - -#: data/sm.puri.Chatty.gschema.xml:80 -msgid "Whether to request mmsd to create SMIL" -msgstr "Huruvida mmsd ska begäras att skapa SMIL" - -#: data/sm.puri.Chatty.gschema.xml:85 -msgid "Carrier mmsc for mmsd" -msgstr "Operatörens mmsc för mmsd" - -#: data/sm.puri.Chatty.gschema.xml:86 -msgid "The carrier mmsc to set for mmsd" -msgstr "Den operatörs-mmsc som ska ställas in för mmsd" - -#: data/sm.puri.Chatty.gschema.xml:91 -msgid "Carrier mms apn for mmsd" -msgstr "Operatörens mms-apn för mmsd" - -#: data/sm.puri.Chatty.gschema.xml:92 -msgid "The mms APN to set for mmsd" -msgstr "Den mms-APN som ska ställas in för mmsd" - -#: data/sm.puri.Chatty.gschema.xml:97 -msgid "Carrier mms proxy for mmsd" -msgstr "Operatörens mms-proxy för mmsd" - -#: data/sm.puri.Chatty.gschema.xml:98 -msgid "The mms proxy to set for mmsd" -msgstr "Den mms-proxy som ska ställas in för mmsd" - -#: data/sm.puri.Chatty.gschema.xml:103 msgid "Enable experimental features" msgstr "Aktivera experimentella funktioner" -#: data/sm.puri.Chatty.gschema.xml:104 +#: data/sm.puri.Chatty.gschema.xml:80 msgid "Whether to enable experimental features" msgstr "Huruvida experimentella funktioner ska aktiveras" -#: data/sm.puri.Chatty.gschema.xml:109 +#: data/sm.puri.Chatty.gschema.xml:85 msgid "Window maximized" msgstr "Fönster maximerat" -#: data/sm.puri.Chatty.gschema.xml:110 +#: data/sm.puri.Chatty.gschema.xml:86 msgid "Window maximized state" msgstr "Maximerat tillstånd för fönster" -#: data/sm.puri.Chatty.gschema.xml:115 +#: data/sm.puri.Chatty.gschema.xml:91 msgid "Window size" msgstr "Fönsterstorlek" -#: data/sm.puri.Chatty.gschema.xml:116 +#: data/sm.puri.Chatty.gschema.xml:92 msgid "Window size (width, height)." msgstr "Fönsterstorlek (bredd, höjd)." @@ -217,7 +185,7 @@ msgstr "" "Det uppstod ett fel vid visning av hjälp:\n" "%s" -#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:258 +#: src/chatty-avatar.c:158 src/chatty-contact-list.c:391 msgid "Send To" msgstr "Skicka till" @@ -229,7 +197,7 @@ msgstr "Välj en kontakt med ”+”-knappen i namnlisten." msgid "Add instant messaging accounts in Preferences." msgstr "Lägg till snabbmeddelandekonton i Inställningar." -#: src/chatty-chat-list.c:192 src/ui/chatty-dialog-new-chat.ui:258 +#: src/chatty-chat-list.c:192 src/chatty-contact-list.c:282 msgid "No Search Results" msgstr "Inga sökresultat" @@ -261,12 +229,12 @@ msgstr "Dina meddelanden krypteras" msgid "Your messages are not encrypted" msgstr "Dina meddelanden krypteras inte" -#: src/chatty-chat-view.c:394 +#: src/chatty-chat-view.c:395 msgid "Select File..." msgstr "Välj fil…" -#: src/chatty-chat-view.c:397 src/purple/chatty-purple-request.c:175 -#: src/chatty-window.c:395 src/dialogs/chatty-pp-chat-info.c:90 +#: src/chatty-chat-view.c:398 src/purple/chatty-purple-request.c:175 +#: src/chatty-window.c:347 src/dialogs/chatty-pp-chat-info.c:90 #: src/dialogs/chatty-ma-account-details.c:119 #: src/dialogs/chatty-pp-account-details.c:91 #: src/ui/chatty-dialog-join-muc.ui:21 src/ui/chatty-info-dialog.ui:44 @@ -274,13 +242,44 @@ msgstr "Välj fil…" msgid "Cancel" msgstr "Avbryt" -#: src/chatty-chat-view.c:398 src/purple/chatty-purple-request.c:177 +#: src/chatty-chat-view.c:399 src/purple/chatty-purple-request.c:177 #: src/dialogs/chatty-pp-chat-info.c:89 #: src/dialogs/chatty-ma-account-details.c:118 #: src/dialogs/chatty-pp-account-details.c:90 msgid "Open" msgstr "Öppna" +#: src/chatty-chat.c:632 +msgid "Empty room" +msgstr "Tomt rum" + +#. TRANSLATORS: %s are name/user-id/phone numbers of two users +#: src/chatty-chat.c:639 +#, c-format +msgid "%s and %s" +msgstr "%s och %s" + +#: src/chatty-chat.c:641 +#, c-format +msgid "%s and %u other" +msgid_plural "%s and %u others" +msgstr[0] "%s och %u till" +msgstr[1] "%s och %u till" + +#: src/chatty-contact-list.c:247 src/dialogs/chatty-mm-chat-info.c:118 +msgid "Unknown Contact" +msgstr "Okänd kontakt" + +#: src/chatty-contact-list.c:283 +msgid "Try different search, or type a valid number to create new chat" +msgstr "" +"Försök med en annan sökning, eller skriv in ett giltigt nummer för att skapa " +"en ny chatt" + +#: src/chatty-contact-list.c:287 +msgid "No Contacts" +msgstr "Inga kontakter" + #. TRANSLATORS: %s is the Device ID #: src/chatty-fp-row.c:131 #, c-format @@ -288,93 +287,98 @@ msgid "Device ID %s fingerprint:" msgstr "Fingeravtryck för enhets-ID %s:" #. Translators: Timestamp seconds suffix -#: src/chatty-list-row.c:80 +#: src/chatty-list-row.c:83 msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "s" #. Translators: Timestamp minute suffix -#: src/chatty-list-row.c:82 +#: src/chatty-list-row.c:85 msgctxt "timestamp-suffix-minute" msgid "m" msgstr "m" #. Translators: Timestamp minutes suffix -#: src/chatty-list-row.c:84 +#: src/chatty-list-row.c:87 msgctxt "timestamp-suffix-minutes" msgid "m" msgstr "m" #. Translators: Timestamp hour suffix -#: src/chatty-list-row.c:86 +#: src/chatty-list-row.c:89 msgctxt "timestamp-suffix-hour" msgid "h" msgstr "h" #. Translators: Timestamp hours suffix -#: src/chatty-list-row.c:88 +#: src/chatty-list-row.c:91 msgctxt "timestamp-suffix-hours" msgid "h" msgstr "h" #. Translators: Timestamp day suffix -#: src/chatty-list-row.c:90 +#: src/chatty-list-row.c:93 msgctxt "timestamp-suffix-day" msgid "d" msgstr "d" #. Translators: Timestamp days suffix -#: src/chatty-list-row.c:92 +#: src/chatty-list-row.c:95 msgctxt "timestamp-suffix-days" msgid "d" msgstr "d" #. Translators: Timestamp month suffix -#: src/chatty-list-row.c:94 +#: src/chatty-list-row.c:97 msgctxt "timestamp-suffix-month" msgid "mo" msgstr "mån" #. Translators: Timestamp months suffix -#: src/chatty-list-row.c:96 +#: src/chatty-list-row.c:99 msgctxt "timestamp-suffix-months" msgid "mos" msgstr "mån" #. Translators: Timestamp year suffix -#: src/chatty-list-row.c:98 +#: src/chatty-list-row.c:101 msgctxt "timestamp-suffix-year" msgid "y" msgstr "å" #. Translators: Timestamp years suffix -#: src/chatty-list-row.c:100 +#: src/chatty-list-row.c:103 msgctxt "timestamp-suffix-years" msgid "y" msgstr "å" #. Translators: Timestamp prefix (e.g. Over 5h) -#: src/chatty-list-row.c:202 +#: src/chatty-list-row.c:205 msgid "Over" msgstr "Över" #. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/chatty-list-row.c:207 +#: src/chatty-list-row.c:210 msgid "Almost" msgstr "Nästan" -#: src/chatty-list-row.c:270 +#: src/chatty-list-row.c:273 msgid "Owner" msgstr "Ägare" -#: src/chatty-list-row.c:273 +#: src/chatty-list-row.c:276 msgid "Moderator" msgstr "Moderator" -#: src/chatty-list-row.c:276 +#: src/chatty-list-row.c:279 msgid "Member" msgstr "Medlem" +#: src/chatty-manager.c:727 +#, c-format +msgid "“%s” is not a valid URI" +msgstr "”%s” är inte en giltig URI" + #: src/chatty-message-row.c:81 msgid "Copy" msgstr "Kopiera" @@ -383,12 +387,12 @@ msgstr "Kopiera" msgid "Open Message" msgstr "Öppna meddelande" -#: src/chatty-notification.c:213 +#: src/chatty-notification.c:214 #, c-format msgid "New message from %s" msgstr "Nytt meddelande från %s" -#: src/chatty-notification.c:215 +#: src/chatty-notification.c:216 msgid "Message Received" msgstr "Meddelande togs emot" @@ -469,69 +473,59 @@ msgstr "%A %I∶%M %p" msgid "%Y-%m-%d" msgstr "%Y-%m-%d" -#: src/chatty-window.c:381 +#: src/chatty-window.c:333 #, c-format msgid "Delete chat with “%s”" msgstr "Ta bort chatt med ”%s”" -#: src/chatty-window.c:382 +#: src/chatty-window.c:334 msgid "This deletes the conversation history" msgstr "Det här tar bort meddelandehistoriken" -#: src/chatty-window.c:384 +#: src/chatty-window.c:336 #, c-format msgid "Disconnect group chat “%s”" msgstr "Lämna gruppchatten ”%s”" -#: src/chatty-window.c:385 +#: src/chatty-window.c:337 msgid "This removes chat from chats list" msgstr "Detta tar bort chatten från chattlistan" -#: src/chatty-window.c:397 +#: src/chatty-window.c:349 msgid "Delete" msgstr "Ta bort" -#: src/chatty-window.c:522 +#: src/chatty-window.c:473 msgid "An SMS and XMPP messaging client" msgstr "En SMS- och XMPP-meddelandeklient" -#: src/chatty-window.c:529 +#: src/chatty-window.c:480 msgid "translator-credits" msgstr "" "Anders Jonsson \n" "Luna Jernberg " -#: src/chatty-window.c:803 +#: src/chatty-window.c:807 msgid "Any Protocol" msgstr "Alla protokoll" -#: src/chatty-window.c:804 src/ui/chatty-settings-dialog.ui:557 +#: src/chatty-window.c:808 src/ui/chatty-settings-dialog.ui:552 msgid "Matrix" msgstr "Matrix" -#: src/chatty-window.c:805 +#: src/chatty-window.c:809 msgid "SMS/MMS" msgstr "SMS/MMS" -#: src/chatty-window.c:808 src/ui/chatty-settings-dialog.ui:545 +#: src/chatty-window.c:812 src/ui/chatty-settings-dialog.ui:540 msgid "XMPP" msgstr "XMPP" -#: src/chatty-window.c:811 src/ui/chatty-settings-dialog.ui:571 +#: src/chatty-window.c:815 src/ui/chatty-settings-dialog.ui:566 msgid "Telegram" msgstr "Telegram" -#: src/chatty-window.c:848 -#, c-format -msgid "“%s” is not a valid phone number" -msgstr "”%s” är inte ett giltigt telefonnummer" - -#: src/dialogs/chatty-mm-chat-info.c:116 -#: src/dialogs/chatty-new-chat-dialog.c:553 -msgid "Unknown Contact" -msgstr "Okänd kontakt" - -#: src/dialogs/chatty-mm-chat-info.c:134 +#: src/dialogs/chatty-mm-chat-info.c:137 msgctxt "Refer to self in contact list" msgid "You" msgstr "Du" @@ -587,11 +581,31 @@ msgstr "Matrix-ID:" msgid "Telegram ID:" msgstr "Telegram-ID:" -#: src/dialogs/chatty-new-chat-dialog.c:305 +#: src/dialogs/chatty-new-chat-dialog.c:171 +msgid "Add" +msgstr "Lägg till" + +#: src/dialogs/chatty-new-chat-dialog.c:181 +msgid "Create" +msgstr "Skapa" + +#: src/dialogs/chatty-new-chat-dialog.c:187 +msgid "Add Contact" +msgstr "Lägg till kontakt" + +#: src/dialogs/chatty-new-chat-dialog.c:224 #, c-format msgid "Error opening GNOME Contacts: %s" msgstr "Fel vid öppnande av GNOME Kontakter: %s" +#: src/dialogs/chatty-new-chat-dialog.c:452 +msgid "SMS" +msgstr "SMS" + +#: src/dialogs/chatty-new-chat-dialog.c:640 +msgid "You" +msgstr "Du" + #: src/dialogs/chatty-ma-account-details.c:385 #: src/dialogs/chatty-pp-account-details.c:178 msgid "connected" @@ -607,23 +621,23 @@ msgstr "ansluter…" msgid "disconnected" msgstr "frånkopplad" -#: src/dialogs/chatty-settings-dialog.c:227 -#: src/dialogs/chatty-settings-dialog.c:391 +#: src/dialogs/chatty-settings-dialog.c:210 +#: src/dialogs/chatty-settings-dialog.c:374 msgid "Failed to verify server" msgstr "Misslyckades med att verifiera server" -#: src/dialogs/chatty-settings-dialog.c:278 -#: src/dialogs/chatty-settings-dialog.c:371 +#: src/dialogs/chatty-settings-dialog.c:261 +#: src/dialogs/chatty-settings-dialog.c:354 msgid "Couldn't get Home server address" msgstr "Kunde inte erhålla hemserverns adress" -#: src/dialogs/chatty-settings-dialog.c:498 +#: src/dialogs/chatty-settings-dialog.c:479 #: src/ui/chatty-ma-account-details.ui:182 #: src/ui/chatty-pp-account-details.ui:199 msgid "Delete Account" msgstr "Ta bort konto" -#: src/dialogs/chatty-settings-dialog.c:501 +#: src/dialogs/chatty-settings-dialog.c:482 #, c-format msgid "Delete account %s?" msgstr "Ta bort kontot %s?" @@ -633,17 +647,17 @@ msgid "Restart chatty to disable purple" msgstr "Starta om chatty för att inaktivera purple" #: src/dialogs/chatty-settings-dialog.c:620 -#: src/ui/chatty-settings-dialog.ui:442 +#: src/ui/chatty-settings-dialog.ui:437 msgid "Enable purple plugin" msgstr "Aktivera purple-insticksmodul" #: src/dialogs/chatty-settings-dialog.c:634 -#: src/ui/chatty-settings-dialog.ui:286 +#: src/ui/chatty-settings-dialog.ui:279 msgid "SMS and MMS Settings" msgstr "SMS och MMS-inställningar" #: src/dialogs/chatty-settings-dialog.c:636 -#: src/ui/chatty-settings-dialog.ui:305 +#: src/ui/chatty-settings-dialog.ui:298 msgid "Purple Settings" msgstr "Purple-inställningar" @@ -660,7 +674,8 @@ msgstr "Inställningar" msgid "Select Protocol" msgstr "Välj protokoll" -#: src/dialogs/chatty-settings-dialog.c:899 +#. TRANSLATORS: Only translate 'or' +#: src/dialogs/chatty-settings-dialog.c:865 msgid "@user:matrix.org or user@example.com" msgstr "@user:matrix.org eller user@example.com" @@ -672,8 +687,8 @@ msgstr "Felaktigt lösenord" msgid "_OK" msgstr "_OK" -#: src/matrix/chatty-ma-account.c:300 src/ui/chatty-dialog-new-chat.ui:52 -#: src/ui/chatty-settings-dialog.ui:46 src/ui/chatty-settings-dialog.ui:107 +#: src/matrix/chatty-ma-account.c:300 src/ui/chatty-dialog-new-chat.ui:74 +#: src/ui/chatty-settings-dialog.ui:47 src/ui/chatty-settings-dialog.ui:108 msgid "_Cancel" msgstr "A_vbryt" @@ -682,22 +697,6 @@ msgstr "A_vbryt" msgid "Please enter password for “%s”" msgstr "Ange lösenordet för ”%s”" -#: src/matrix/chatty-ma-chat.c:164 -msgid "Empty room" -msgstr "Tomt rum" - -#: src/matrix/chatty-ma-chat.c:168 -#, c-format -msgid "%s and %s" -msgstr "%s och %s" - -#: src/matrix/chatty-ma-chat.c:170 -#, c-format -msgid "%s and %u other" -msgid_plural "%s and %u others" -msgstr[0] "%s och %u till" -msgstr[1] "%s och %u till" - #: src/matrix/matrix-utils.c:474 #, c-format msgid "The certificate for ‘%s’ has unknown CA" @@ -723,6 +722,22 @@ msgstr "Certifikatet för ”%s” har återkallats" msgid "Error validating certificate for ‘%s’" msgstr "Fel vid validering av certifikat för ”%s”" +#. TRANSLATORS: Timestamp for minute accuracy, e.g. “2020-08-11 15:27”. +#. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format +#. +#: src/mm/chatty-mmsd.c:824 +msgid "%Y-%m-%d %H:%M" +msgstr "%Y-%m-%d %H:%M" + +#: src/mm/chatty-mmsd.c:1084 +#, c-format +msgid "You received an MMS, but it expired on: %s" +msgstr "Du tog emot ett MMS, men det gick ut: %s" + +#: src/mm/chatty-mmsd.c:1087 +msgid "You received an empty MMS." +msgstr "Du tog emot ett tomt MMS." + #: src/ui/chatty-dialog-join-muc.ui:17 msgid "New Group Chat" msgstr "Ny gruppchatt" @@ -731,7 +746,7 @@ msgstr "Ny gruppchatt" msgid "Join Chat" msgstr "Gå in i chatt" -#: src/ui/chatty-dialog-join-muc.ui:82 src/ui/chatty-dialog-new-chat.ui:313 +#: src/ui/chatty-dialog-join-muc.ui:82 src/ui/chatty-dialog-new-chat.ui:269 msgid "Select chat account" msgstr "Välj chattkonto" @@ -739,37 +754,23 @@ msgstr "Välj chattkonto" msgid "Password (optional)" msgstr "Lösenord (valfritt)" -#: src/ui/chatty-dialog-new-chat.ui:26 -msgid "Start Chat" -msgstr "Starta chatt" +#: src/ui/chatty-dialog-new-chat.ui:126 +msgid "Group Title" +msgstr "Grupptitel" -#: src/ui/chatty-dialog-new-chat.ui:63 -msgid "_Create" -msgstr "S_kapa" +#: src/ui/chatty-dialog-new-chat.ui:177 +msgid "Add members from contacts…" +msgstr "Lägg till medlemmar från kontakter…" -#: src/ui/chatty-dialog-new-chat.ui:80 -msgid "New Contact" -msgstr "Ny kontakt" - -#: src/ui/chatty-dialog-new-chat.ui:108 -msgid "Add Contact" -msgstr "Lägg till kontakt" - -#: src/ui/chatty-dialog-new-chat.ui:183 +#: src/ui/chatty-dialog-new-chat.ui:223 msgid "Send To:" msgstr "Skicka till:" -#: src/ui/chatty-dialog-new-chat.ui:259 -msgid "Try different search, or type a valid number to create new chat" -msgstr "" -"Försök med en annan sökning, eller skriv in ett giltigt nummer för att skapa " -"en ny chatt" - -#: src/ui/chatty-dialog-new-chat.ui:360 +#: src/ui/chatty-dialog-new-chat.ui:308 msgid "Name (optional)" msgstr "Namn (valfritt)" -#: src/ui/chatty-dialog-new-chat.ui:400 +#: src/ui/chatty-dialog-new-chat.ui:351 msgid "Add to Contacts" msgstr "Lägg till i Kontakter" @@ -855,6 +856,10 @@ msgstr "Tom för standard" msgid "Group Members" msgstr "Gruppmedlemmar" +#: src/ui/chatty-list-row.ui:151 src/ui/chatty-window.ui:353 +msgid "Call" +msgstr "Ring" + #: src/ui/chatty-ma-account-details.ui:93 msgid "Name" msgstr "Namn" @@ -887,7 +892,7 @@ msgstr "Konto-ID" msgid "Protocol" msgstr "Protokoll" -#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:631 +#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:626 msgid "Password" msgstr "Lösenord" @@ -895,111 +900,111 @@ msgstr "Lösenord" msgid "Own Fingerprint" msgstr "Eget fingeravtryck" -#: src/ui/chatty-settings-dialog.ui:26 +#: src/ui/chatty-settings-dialog.ui:27 msgid "Back" msgstr "Tillbaka" -#: src/ui/chatty-settings-dialog.ui:59 +#: src/ui/chatty-settings-dialog.ui:60 msgid "_Add" msgstr "_Lägg till" -#: src/ui/chatty-settings-dialog.ui:75 +#: src/ui/chatty-settings-dialog.ui:76 msgid "_Save" msgstr "_Spara" -#: src/ui/chatty-settings-dialog.ui:91 +#: src/ui/chatty-settings-dialog.ui:92 msgid "_Apply" msgstr "_Verkställ" -#: src/ui/chatty-settings-dialog.ui:168 +#: src/ui/chatty-settings-dialog.ui:169 msgid "Accounts" msgstr "Konton" -#: src/ui/chatty-settings-dialog.ui:182 -msgid "Add _new account…" -msgstr "Lägg till _nytt konto…" - -#: src/ui/chatty-settings-dialog.ui:196 src/ui/chatty-settings-dialog.ui:461 +#: src/ui/chatty-settings-dialog.ui:189 src/ui/chatty-settings-dialog.ui:456 msgid "Privacy" msgstr "Sekretess" -#: src/ui/chatty-settings-dialog.ui:202 +#: src/ui/chatty-settings-dialog.ui:195 msgid "Message Receipts" msgstr "Meddelandekvitton" -#: src/ui/chatty-settings-dialog.ui:203 +#: src/ui/chatty-settings-dialog.ui:196 msgid "Confirm received messages" msgstr "Bekräfta mottagna meddelanden" -#: src/ui/chatty-settings-dialog.ui:218 +#: src/ui/chatty-settings-dialog.ui:211 msgid "Typing Notification" msgstr "Inmatningsavisering" -#: src/ui/chatty-settings-dialog.ui:219 +#: src/ui/chatty-settings-dialog.ui:212 msgid "Send typing messages" msgstr "Skicka att meddelanden skrivs" -#: src/ui/chatty-settings-dialog.ui:237 +#: src/ui/chatty-settings-dialog.ui:230 msgid "Editor" msgstr "Redigerare" -#: src/ui/chatty-settings-dialog.ui:242 +#: src/ui/chatty-settings-dialog.ui:235 msgid "Graphical Emoticons" msgstr "Grafiska humörsymboler" -#: src/ui/chatty-settings-dialog.ui:243 +#: src/ui/chatty-settings-dialog.ui:236 msgid "if you type :) it will be changed to 😃" msgstr "om du skriver :) så kommer det att ändras till 😃" #. TRANSLATORS: Return is the Enter key. -#: src/ui/chatty-settings-dialog.ui:258 +#: src/ui/chatty-settings-dialog.ui:251 msgid "Send Messages with Return" msgstr "Skicka meddelanden med Retur" -#: src/ui/chatty-settings-dialog.ui:274 +#: src/ui/chatty-settings-dialog.ui:267 msgid "Protocol Settings" msgstr "Protokollinställningar" -#: src/ui/chatty-settings-dialog.ui:340 +#: src/ui/chatty-settings-dialog.ui:333 msgid "Request Delivery Reports" msgstr "Begär leveransrapporter" -#: src/ui/chatty-settings-dialog.ui:354 +#: src/ui/chatty-settings-dialog.ui:348 msgid "SMIL for MMS" msgstr "SMIL för MMS" -#: src/ui/chatty-settings-dialog.ui:371 +#: src/ui/chatty-settings-dialog.ui:366 msgid "MMS Carrier Settings" msgstr "MMS-operatörsinställningar" -#: src/ui/chatty-settings-dialog.ui:375 +#: src/ui/chatty-settings-dialog.ui:370 msgid "MMSC" msgstr "MMSC" -#: src/ui/chatty-settings-dialog.ui:390 +#: src/ui/chatty-settings-dialog.ui:385 msgid "APN" msgstr "APN" -#: src/ui/chatty-settings-dialog.ui:405 +#: src/ui/chatty-settings-dialog.ui:400 msgid "Proxy" msgstr "Proxy" -#: src/ui/chatty-settings-dialog.ui:467 +#: src/ui/chatty-settings-dialog.ui:462 msgid "Message Archive Management" msgstr "Meddelandearkivhantering" -#: src/ui/chatty-settings-dialog.ui:468 +#: src/ui/chatty-settings-dialog.ui:463 msgid "Sync conversations with chat server" msgstr "Synka konversationer med chattserver" -#: src/ui/chatty-settings-dialog.ui:483 +#: src/ui/chatty-settings-dialog.ui:478 msgid "Message Carbon Copies" msgstr "Meddelandekopior" -#: src/ui/chatty-settings-dialog.ui:667 +#: src/ui/chatty-settings-dialog.ui:662 msgid "Home server" msgstr "Hemserver" +#: src/ui/chatty-settings-dialog.ui:698 +msgid "Add _new account…" +msgstr "Lägg till _nytt konto…" + #: src/ui/chatty-window.ui:28 msgid "Keyboard _Shortcuts" msgstr "_Tangentbordsgenvägar" @@ -1032,10 +1037,6 @@ msgstr "Lämna chatt" msgid "Delete Chat" msgstr "Ta bort chatt" -#: src/ui/chatty-window.ui:353 -msgid "Call" -msgstr "Ring" - #: src/ui/help-overlay.ui:14 msgctxt "shortcut window" msgid "General" @@ -1056,56 +1057,14 @@ msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Visa kortkommandon" -#: src/users/chatty-contact.c:311 +#: src/users/chatty-contact.c:325 msgid "Mobile: " msgstr "Mobil: " -#: src/users/chatty-contact.c:313 +#: src/users/chatty-contact.c:327 msgid "Work: " msgstr "Arbete: " -#: src/users/chatty-contact.c:315 +#: src/users/chatty-contact.c:329 msgid "Other: " msgstr "Annat: " - -#~ msgid "Chatty requires Client-Server API to be ‘r0.5.x’ or ‘r0.6.x’" -#~ msgstr "Chatty kräver att klient-server-API:t är ‘r0.5.x’ eller ‘r0.6.x’" - -#~ msgid "Matrix Home Server" -#~ msgstr "Matrix-hemserver" - -#~ msgid "_Accept" -#~ msgstr "_Acceptera" - -#~ msgid "No chat selected" -#~ msgstr "Ingen chatt vald" - -#~ msgid "_Message Settings" -#~ msgstr "_Meddelandeinställningar" - -#~ msgid "Chats List" -#~ msgstr "Chattlista" - -#~ msgid "Indicate Idle Contacts" -#~ msgstr "Indikera inaktiva kontakter" - -#~ msgid "Blur avatars from idle contacts" -#~ msgstr "Gör profilbilder för inaktiva kontakter suddiga" - -#~ msgid "Indicate Unknown Contacts" -#~ msgstr "Indikera okända kontakter" - -#~ msgid "Color unknown contact ID red" -#~ msgstr "Färga okänt kontakt-ID rött" - -#~ msgid "Convert ASCII emoticons" -#~ msgstr "Konvertera ASCII-humörsymboler" - -#~ msgid "Return = Send Message" -#~ msgstr "Retur = Skicka meddelande" - -#~ msgid "Delivery Reports" -#~ msgstr "Leveransrapporter" - -#~ msgid "Request delivery reports for SMS and MMS" -#~ msgstr "Begär leveransrapporter för SMS och MMS" diff --git a/po/uk.po b/po/uk.po index 556d6f8..d3d48fa 100644 --- a/po/uk.po +++ b/po/uk.po @@ -2,13 +2,13 @@ # This file is distributed under the same license as the chatty package. # # Roman Riabenko , 2020. -# Yuri Chornoivan , 2020, 2021. +# Yuri Chornoivan , 2020, 2021, 2022. msgid "" msgstr "" "Project-Id-Version: purism-chatty\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/chatty/issues\n" -"POT-Creation-Date: 2021-12-02 03:25+0000\n" -"PO-Revision-Date: 2021-12-03 13:24+0200\n" +"POT-Creation-Date: 2022-01-18 03:25+0000\n" +"PO-Revision-Date: 2022-01-19 19:01+0200\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -61,7 +61,7 @@ msgstr "Чи слід надсилати дані щодо того, що пов msgid "Message carbon copies" msgstr "Копії повідомлень" -#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:484 +#: data/sm.puri.Chatty.gschema.xml:26 src/ui/chatty-settings-dialog.ui:478 msgid "Share chat history among devices" msgstr "Спільний з іншими пристроями журнал спілкування" @@ -77,7 +77,7 @@ msgstr "Увімкнути синхронізацію архіву MAM з сер msgid "Enable purple" msgstr "Увімкнути purple" -#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:441 +#: data/sm.puri.Chatty.gschema.xml:38 src/ui/chatty-settings-dialog.ui:435 msgid "Enable purple accounts" msgstr "Вимкнути облікові записи purple" @@ -123,58 +123,26 @@ msgstr "" "Визначає, чи слід надсилати запит щодо звітів про доставлення вихідних SMS" #: data/sm.puri.Chatty.gschema.xml:79 -msgid "Request mmsd to handle SMIL" -msgstr "Запит щодо mmsd для обробки SMIL" - -#: data/sm.puri.Chatty.gschema.xml:80 -msgid "Whether to request mmsd to create SMIL" -msgstr "Чи слід надсилати запит щодо mmsd для створення SMIL" - -#: data/sm.puri.Chatty.gschema.xml:85 -msgid "Carrier mmsc for mmsd" -msgstr "Носій сигналу mmsc для mmsd" - -#: data/sm.puri.Chatty.gschema.xml:86 -msgid "The carrier mmsc to set for mmsd" -msgstr "Носій сигналу mmsc, який слід встановити для mmsd" - -#: data/sm.puri.Chatty.gschema.xml:91 -msgid "Carrier mms apn for mmsd" -msgstr "Носій сигналу apn mms для mmsd" - -#: data/sm.puri.Chatty.gschema.xml:92 -msgid "The mms APN to set for mmsd" -msgstr "APN mms, який слід встановити для mmsd" - -#: data/sm.puri.Chatty.gschema.xml:97 -msgid "Carrier mms proxy for mmsd" -msgstr "Носій сигналу проксі mms для mmsd" - -#: data/sm.puri.Chatty.gschema.xml:98 -msgid "The mms proxy to set for mmsd" -msgstr "Проксі mms, який слід встановити для mmsd" - -#: data/sm.puri.Chatty.gschema.xml:103 msgid "Enable experimental features" msgstr "Увімкнути експериментальні можливості" -#: data/sm.puri.Chatty.gschema.xml:104 +#: data/sm.puri.Chatty.gschema.xml:80 msgid "Whether to enable experimental features" msgstr "Чи слід вмикати експериментальні можливості" -#: data/sm.puri.Chatty.gschema.xml:109 +#: data/sm.puri.Chatty.gschema.xml:85 msgid "Window maximized" msgstr "Вікно розгорнуто" -#: data/sm.puri.Chatty.gschema.xml:110 +#: data/sm.puri.Chatty.gschema.xml:86 msgid "Window maximized state" msgstr "Стан розгорнутого вікна" -#: data/sm.puri.Chatty.gschema.xml:115 +#: data/sm.puri.Chatty.gschema.xml:91 msgid "Window size" msgstr "Розмір вікна" -#: data/sm.puri.Chatty.gschema.xml:116 +#: data/sm.puri.Chatty.gschema.xml:92 msgid "Window size (width, height)." msgstr "Розмір вікна (ширина, висота)." @@ -220,7 +188,7 @@ msgstr "" "Спроба показати довідку завершилася помилкою:\n" "%s" -#: src/chatty-avatar.c:158 src/dialogs/chatty-new-chat-dialog.c:258 +#: src/chatty-avatar.c:158 src/chatty-contact-list.c:391 msgid "Send To" msgstr "Надіслати" @@ -233,7 +201,7 @@ msgid "Add instant messaging accounts in Preferences." msgstr "" "Додайте облікові записи миттєвого обміну повідомленнями у «Параметрах»." -#: src/chatty-chat-list.c:192 src/ui/chatty-dialog-new-chat.ui:258 +#: src/chatty-chat-list.c:192 src/chatty-contact-list.c:282 msgid "No Search Results" msgstr "Нічого не знайдено" @@ -267,12 +235,12 @@ msgstr "Ваші повідомлення зашифровано" msgid "Your messages are not encrypted" msgstr "Ваші повідомлення не зашифровано" -#: src/chatty-chat-view.c:394 +#: src/chatty-chat-view.c:395 msgid "Select File..." msgstr "Вибір файла…" -#: src/chatty-chat-view.c:397 src/purple/chatty-purple-request.c:175 -#: src/chatty-window.c:395 src/dialogs/chatty-pp-chat-info.c:90 +#: src/chatty-chat-view.c:398 src/purple/chatty-purple-request.c:175 +#: src/chatty-window.c:346 src/dialogs/chatty-pp-chat-info.c:90 #: src/dialogs/chatty-ma-account-details.c:119 #: src/dialogs/chatty-pp-account-details.c:91 #: src/ui/chatty-dialog-join-muc.ui:21 src/ui/chatty-info-dialog.ui:44 @@ -280,13 +248,45 @@ msgstr "Вибір файла…" msgid "Cancel" msgstr "Скасувати" -#: src/chatty-chat-view.c:398 src/purple/chatty-purple-request.c:177 +#: src/chatty-chat-view.c:399 src/purple/chatty-purple-request.c:177 #: src/dialogs/chatty-pp-chat-info.c:89 #: src/dialogs/chatty-ma-account-details.c:118 #: src/dialogs/chatty-pp-account-details.c:90 msgid "Open" msgstr "Відкрити" +#: src/chatty-chat.c:618 +msgid "Empty room" +msgstr "Порожня кімната" + +#. TRANSLATORS: %s are name/user-id/phone numbers of two users +#: src/chatty-chat.c:625 +#, c-format +msgid "%s and %s" +msgstr "%s і %s" + +#: src/chatty-chat.c:627 +#, c-format +msgid "%s and %u other" +msgid_plural "%s and %u others" +msgstr[0] "%s і %u інший" +msgstr[1] "%s і %u інших" +msgstr[2] "%s і %u інших" + +#: src/chatty-contact-list.c:247 src/dialogs/chatty-mm-chat-info.c:118 +msgid "Unknown Contact" +msgstr "Невідомий контакт" + +#: src/chatty-contact-list.c:283 +msgid "Try different search, or type a valid number to create new chat" +msgstr "" +"Спробуйте інший критерій пошуку або введіть коректне число, щоб розпочати " +"нове спілкування" + +#: src/chatty-contact-list.c:287 +msgid "No Contacts" +msgstr "Немає контактів" + #. TRANSLATORS: %s is the Device ID #: src/chatty-fp-row.c:131 #, c-format @@ -294,93 +294,98 @@ msgid "Device ID %s fingerprint:" msgstr "Відбиток ідентифікатора пристрою %s:" #. Translators: Timestamp seconds suffix -#: src/chatty-list-row.c:80 +#: src/chatty-list-row.c:83 msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "с" #. Translators: Timestamp minute suffix -#: src/chatty-list-row.c:82 +#: src/chatty-list-row.c:85 msgctxt "timestamp-suffix-minute" msgid "m" msgstr "хв" #. Translators: Timestamp minutes suffix -#: src/chatty-list-row.c:84 +#: src/chatty-list-row.c:87 msgctxt "timestamp-suffix-minutes" msgid "m" msgstr "хв" #. Translators: Timestamp hour suffix -#: src/chatty-list-row.c:86 +#: src/chatty-list-row.c:89 msgctxt "timestamp-suffix-hour" msgid "h" msgstr "г" #. Translators: Timestamp hours suffix -#: src/chatty-list-row.c:88 +#: src/chatty-list-row.c:91 msgctxt "timestamp-suffix-hours" msgid "h" msgstr "г" #. Translators: Timestamp day suffix -#: src/chatty-list-row.c:90 +#: src/chatty-list-row.c:93 msgctxt "timestamp-suffix-day" msgid "d" msgstr "д" #. Translators: Timestamp days suffix -#: src/chatty-list-row.c:92 +#: src/chatty-list-row.c:95 msgctxt "timestamp-suffix-days" msgid "d" msgstr "д" #. Translators: Timestamp month suffix -#: src/chatty-list-row.c:94 +#: src/chatty-list-row.c:97 msgctxt "timestamp-suffix-month" msgid "mo" msgstr "м" #. Translators: Timestamp months suffix -#: src/chatty-list-row.c:96 +#: src/chatty-list-row.c:99 msgctxt "timestamp-suffix-months" msgid "mos" msgstr "міс" #. Translators: Timestamp year suffix -#: src/chatty-list-row.c:98 +#: src/chatty-list-row.c:101 msgctxt "timestamp-suffix-year" msgid "y" msgstr "р" #. Translators: Timestamp years suffix -#: src/chatty-list-row.c:100 +#: src/chatty-list-row.c:103 msgctxt "timestamp-suffix-years" msgid "y" msgstr "р" #. Translators: Timestamp prefix (e.g. Over 5h) -#: src/chatty-list-row.c:202 +#: src/chatty-list-row.c:205 msgid "Over" msgstr "Понад" #. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/chatty-list-row.c:207 +#: src/chatty-list-row.c:210 msgid "Almost" msgstr "Майже" -#: src/chatty-list-row.c:270 +#: src/chatty-list-row.c:273 msgid "Owner" msgstr "Власник" -#: src/chatty-list-row.c:273 +#: src/chatty-list-row.c:276 msgid "Moderator" msgstr "Модератор" -#: src/chatty-list-row.c:276 +#: src/chatty-list-row.c:279 msgid "Member" msgstr "Член" +#: src/chatty-manager.c:727 +#, c-format +msgid "“%s” is not a valid URI" +msgstr "«%s» не є коректною адресою" + #: src/chatty-message-row.c:81 msgid "Copy" msgstr "Копіювати" @@ -389,12 +394,12 @@ msgstr "Копіювати" msgid "Open Message" msgstr "Відкрити повідомлення" -#: src/chatty-notification.c:213 +#: src/chatty-notification.c:214 #, c-format msgid "New message from %s" msgstr "Нове повідомлення від %s" -#: src/chatty-notification.c:215 +#: src/chatty-notification.c:216 msgid "Message Received" msgstr "Надійшло повідомлення" @@ -475,67 +480,57 @@ msgstr "%a %I∶%M %p" msgid "%Y-%m-%d" msgstr "%d-%m-%Y" -#: src/chatty-window.c:381 +#: src/chatty-window.c:332 #, c-format msgid "Delete chat with “%s”" msgstr "Вилучити спілкування з «%s»" -#: src/chatty-window.c:382 +#: src/chatty-window.c:333 msgid "This deletes the conversation history" msgstr "У результаті буде вилучено журнал спілкування" -#: src/chatty-window.c:384 +#: src/chatty-window.c:335 #, c-format msgid "Disconnect group chat “%s”" msgstr "Від'єднатися від групового спілкування «%s»" -#: src/chatty-window.c:385 +#: src/chatty-window.c:336 msgid "This removes chat from chats list" msgstr "У результаті спілкування буде вилучено зі списку спілкувань" -#: src/chatty-window.c:397 +#: src/chatty-window.c:348 msgid "Delete" msgstr "Вилучити" -#: src/chatty-window.c:522 +#: src/chatty-window.c:473 msgid "An SMS and XMPP messaging client" msgstr "Клієнт обміну повідомленнями SMS і XMPP" -#: src/chatty-window.c:529 +#: src/chatty-window.c:480 msgid "translator-credits" msgstr "Юрій Чорноіван , 2020" -#: src/chatty-window.c:803 +#: src/chatty-window.c:807 msgid "Any Protocol" msgstr "Будь-який протокол" -#: src/chatty-window.c:804 src/ui/chatty-settings-dialog.ui:557 +#: src/chatty-window.c:808 src/ui/chatty-settings-dialog.ui:551 msgid "Matrix" msgstr "Matrix" -#: src/chatty-window.c:805 +#: src/chatty-window.c:809 msgid "SMS/MMS" msgstr "SMS/MMS" -#: src/chatty-window.c:808 src/ui/chatty-settings-dialog.ui:545 +#: src/chatty-window.c:812 src/ui/chatty-settings-dialog.ui:539 msgid "XMPP" msgstr "XMPP" -#: src/chatty-window.c:811 src/ui/chatty-settings-dialog.ui:571 +#: src/chatty-window.c:815 src/ui/chatty-settings-dialog.ui:565 msgid "Telegram" msgstr "Telegram" -#: src/chatty-window.c:848 -#, c-format -msgid "“%s” is not a valid phone number" -msgstr "«%s» не є коректним номером телефону" - -#: src/dialogs/chatty-mm-chat-info.c:116 -#: src/dialogs/chatty-new-chat-dialog.c:553 -msgid "Unknown Contact" -msgstr "Невідомий контакт" - -#: src/dialogs/chatty-mm-chat-info.c:134 +#: src/dialogs/chatty-mm-chat-info.c:137 msgctxt "Refer to self in contact list" msgid "You" msgstr "Ви" @@ -592,11 +587,32 @@ msgstr "Ід. Matrix:" msgid "Telegram ID:" msgstr "Ід. Telegram:" -#: src/dialogs/chatty-new-chat-dialog.c:305 +#: src/dialogs/chatty-new-chat-dialog.c:171 +msgid "Add" +msgstr "Додати" + +#: src/dialogs/chatty-new-chat-dialog.c:181 +msgid "Create" +msgstr "Створити" + +#: src/dialogs/chatty-new-chat-dialog.c:187 +msgid "Add Contact" +msgstr "Додати контакт" + +#: src/dialogs/chatty-new-chat-dialog.c:224 #, c-format msgid "Error opening GNOME Contacts: %s" msgstr "Помилка під час спроби відкрити «Контакти» GNOME: %s" +#: src/dialogs/chatty-new-chat-dialog.c:452 +#| msgid "SMS/MMS" +msgid "SMS" +msgstr "SMS" + +#: src/dialogs/chatty-new-chat-dialog.c:640 +msgid "You" +msgstr "Ви" + #: src/dialogs/chatty-ma-account-details.c:385 #: src/dialogs/chatty-pp-account-details.c:178 msgid "connected" @@ -612,23 +628,23 @@ msgstr "З'єднання…" msgid "disconnected" msgstr "від'єднано" -#: src/dialogs/chatty-settings-dialog.c:227 -#: src/dialogs/chatty-settings-dialog.c:391 +#: src/dialogs/chatty-settings-dialog.c:210 +#: src/dialogs/chatty-settings-dialog.c:374 msgid "Failed to verify server" msgstr "Не вдалося перевірити сервер" -#: src/dialogs/chatty-settings-dialog.c:278 -#: src/dialogs/chatty-settings-dialog.c:371 +#: src/dialogs/chatty-settings-dialog.c:261 +#: src/dialogs/chatty-settings-dialog.c:354 msgid "Couldn't get Home server address" msgstr "Не вдалося отримати адресу домашнього сервера." -#: src/dialogs/chatty-settings-dialog.c:498 +#: src/dialogs/chatty-settings-dialog.c:479 #: src/ui/chatty-ma-account-details.ui:182 #: src/ui/chatty-pp-account-details.ui:199 msgid "Delete Account" msgstr "Вилучити запис" -#: src/dialogs/chatty-settings-dialog.c:501 +#: src/dialogs/chatty-settings-dialog.c:482 #, c-format msgid "Delete account %s?" msgstr "Вилучити запис %s?" @@ -638,22 +654,21 @@ msgid "Restart chatty to disable purple" msgstr "Перезапустіть chatty, щоб вимкнути purple" #: src/dialogs/chatty-settings-dialog.c:620 -#: src/ui/chatty-settings-dialog.ui:442 +#: src/ui/chatty-settings-dialog.ui:436 msgid "Enable purple plugin" msgstr "Увімкнути додаток purple" #: src/dialogs/chatty-settings-dialog.c:634 -#: src/ui/chatty-settings-dialog.ui:286 +#: src/ui/chatty-settings-dialog.ui:278 msgid "SMS and MMS Settings" msgstr "Параметри SMS і MMS" #: src/dialogs/chatty-settings-dialog.c:636 -#: src/ui/chatty-settings-dialog.ui:305 +#: src/ui/chatty-settings-dialog.ui:297 msgid "Purple Settings" msgstr "Параметри Purple" #: src/dialogs/chatty-settings-dialog.c:638 -#| msgid "Accounts" msgid "New Account" msgstr "Новий обліковий запис" @@ -666,10 +681,10 @@ msgstr "Параметри" msgid "Select Protocol" msgstr "Виберіть протокол" -#: src/dialogs/chatty-settings-dialog.c:899 +#. TRANSLATORS: Only translate 'or' +#: src/dialogs/chatty-settings-dialog.c:865 msgid "@user:matrix.org or user@example.com" -msgstr "" -"@user:matrix.org або user@example.com" +msgstr "@user:matrix.org або user@example.com" #: src/matrix/chatty-ma-account.c:296 msgid "Incorrect password" @@ -679,7 +694,7 @@ msgstr "Помилковий пароль" msgid "_OK" msgstr "_Гаразд" -#: src/matrix/chatty-ma-account.c:300 src/ui/chatty-dialog-new-chat.ui:52 +#: src/matrix/chatty-ma-account.c:300 src/ui/chatty-dialog-new-chat.ui:74 #: src/ui/chatty-settings-dialog.ui:46 src/ui/chatty-settings-dialog.ui:107 msgid "_Cancel" msgstr "_Скасувати" @@ -689,23 +704,6 @@ msgstr "_Скасувати" msgid "Please enter password for “%s”" msgstr "Будь ласка, введіть пароль до «%s»" -#: src/matrix/chatty-ma-chat.c:164 -msgid "Empty room" -msgstr "Порожня кімната" - -#: src/matrix/chatty-ma-chat.c:168 -#, c-format -msgid "%s and %s" -msgstr "%s і %s" - -#: src/matrix/chatty-ma-chat.c:170 -#, c-format -msgid "%s and %u other" -msgid_plural "%s and %u others" -msgstr[0] "%s і %u інший" -msgstr[1] "%s і %u інших" -msgstr[2] "%s і %u інших" - #: src/matrix/matrix-utils.c:474 #, c-format msgid "The certificate for ‘%s’ has unknown CA" @@ -731,6 +729,22 @@ msgstr "Сертифікат «%s» було відкликано" msgid "Error validating certificate for ‘%s’" msgstr "Помилка під час спроби перевірити чинність сертифіката «%s»" +#. TRANSLATORS: Timestamp for minute accuracy, e.g. “2020-08-11 15:27”. +#. See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format +#. +#: src/mm/chatty-mmsd.c:824 +msgid "%Y-%m-%d %H:%M" +msgstr "%Y.%m.%d %H:%M" + +#: src/mm/chatty-mmsd.c:1084 +#, c-format +msgid "You received an MMS, but it expired on: %s" +msgstr "Вами отримано MMS, але строк його дії вичерпано %s" + +#: src/mm/chatty-mmsd.c:1087 +msgid "You received an empty MMS." +msgstr "Вами отримано порожнє MMS." + #: src/ui/chatty-dialog-join-muc.ui:17 msgid "New Group Chat" msgstr "Нове групове спілкування" @@ -739,7 +753,7 @@ msgstr "Нове групове спілкування" msgid "Join Chat" msgstr "Долучитися до спілкування" -#: src/ui/chatty-dialog-join-muc.ui:82 src/ui/chatty-dialog-new-chat.ui:313 +#: src/ui/chatty-dialog-join-muc.ui:82 src/ui/chatty-dialog-new-chat.ui:269 msgid "Select chat account" msgstr "Виберіть обліковий запис" @@ -747,37 +761,23 @@ msgstr "Виберіть обліковий запис" msgid "Password (optional)" msgstr "Пароль (необов'язковий)" -#: src/ui/chatty-dialog-new-chat.ui:26 -msgid "Start Chat" -msgstr "Почати спілкування" +#: src/ui/chatty-dialog-new-chat.ui:126 +msgid "Group Title" +msgstr "Заголовок групи" -#: src/ui/chatty-dialog-new-chat.ui:63 -msgid "_Create" -msgstr "С_творити" +#: src/ui/chatty-dialog-new-chat.ui:177 +msgid "Add members from contacts…" +msgstr "Додати учасників з контактів…" -#: src/ui/chatty-dialog-new-chat.ui:80 -msgid "New Contact" -msgstr "Створити контакт" - -#: src/ui/chatty-dialog-new-chat.ui:108 -msgid "Add Contact" -msgstr "Додати контакт" - -#: src/ui/chatty-dialog-new-chat.ui:183 +#: src/ui/chatty-dialog-new-chat.ui:223 msgid "Send To:" msgstr "Надіслати:" -#: src/ui/chatty-dialog-new-chat.ui:259 -msgid "Try different search, or type a valid number to create new chat" -msgstr "" -"Спробуйте інший критерій пошуку або введіть коректне число, щоб розпочати " -"нове спілкування" - -#: src/ui/chatty-dialog-new-chat.ui:360 +#: src/ui/chatty-dialog-new-chat.ui:308 msgid "Name (optional)" msgstr "Назва (необов’язково):" -#: src/ui/chatty-dialog-new-chat.ui:400 +#: src/ui/chatty-dialog-new-chat.ui:351 msgid "Add to Contacts" msgstr "Додати до контактів" @@ -863,6 +863,10 @@ msgstr "Типово порожній" msgid "Group Members" msgstr "Учасники групи" +#: src/ui/chatty-list-row.ui:151 src/ui/chatty-window.ui:353 +msgid "Call" +msgstr "Виклик" + #: src/ui/chatty-ma-account-details.ui:93 msgid "Name" msgstr "Ім'я" @@ -895,7 +899,7 @@ msgstr "Ідентифікатор запису" msgid "Protocol" msgstr "Протокол" -#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:631 +#: src/ui/chatty-pp-account-details.ui:168 src/ui/chatty-settings-dialog.ui:625 msgid "Password" msgstr "Пароль" @@ -923,91 +927,91 @@ msgstr "З_астосувати" msgid "Accounts" msgstr "Облікові записи" -#: src/ui/chatty-settings-dialog.ui:182 -msgid "Add _new account…" -msgstr "Додати _новий обліковий запис…" - -#: src/ui/chatty-settings-dialog.ui:196 src/ui/chatty-settings-dialog.ui:461 +#: src/ui/chatty-settings-dialog.ui:188 src/ui/chatty-settings-dialog.ui:455 msgid "Privacy" msgstr "Конфіденційність" -#: src/ui/chatty-settings-dialog.ui:202 +#: src/ui/chatty-settings-dialog.ui:194 msgid "Message Receipts" msgstr "Отримання повідомлень" -#: src/ui/chatty-settings-dialog.ui:203 +#: src/ui/chatty-settings-dialog.ui:195 msgid "Confirm received messages" msgstr "Підтверджувати отримання повідомлень" -#: src/ui/chatty-settings-dialog.ui:218 +#: src/ui/chatty-settings-dialog.ui:210 msgid "Typing Notification" msgstr "Сповіщення щодо набирання" -#: src/ui/chatty-settings-dialog.ui:219 +#: src/ui/chatty-settings-dialog.ui:211 msgid "Send typing messages" msgstr "Надсилати повідомлення щодо набирання" -#: src/ui/chatty-settings-dialog.ui:237 +#: src/ui/chatty-settings-dialog.ui:229 msgid "Editor" msgstr "Редактор" -#: src/ui/chatty-settings-dialog.ui:242 +#: src/ui/chatty-settings-dialog.ui:234 msgid "Graphical Emoticons" msgstr "Графічні емоційки" -#: src/ui/chatty-settings-dialog.ui:243 +#: src/ui/chatty-settings-dialog.ui:235 msgid "if you type :) it will be changed to 😃" msgstr "якщо ви введете :), програма виконає заміну на 😃" #. TRANSLATORS: Return is the Enter key. -#: src/ui/chatty-settings-dialog.ui:258 +#: src/ui/chatty-settings-dialog.ui:250 msgid "Send Messages with Return" msgstr "Надсилати повідомлення клавішею вводу" -#: src/ui/chatty-settings-dialog.ui:274 +#: src/ui/chatty-settings-dialog.ui:266 msgid "Protocol Settings" msgstr "Параметри протоколу" -#: src/ui/chatty-settings-dialog.ui:340 +#: src/ui/chatty-settings-dialog.ui:332 msgid "Request Delivery Reports" msgstr "Надсилати запит щодо доставлення" -#: src/ui/chatty-settings-dialog.ui:354 +#: src/ui/chatty-settings-dialog.ui:347 msgid "SMIL for MMS" msgstr "SMIL для MMS" -#: src/ui/chatty-settings-dialog.ui:371 +#: src/ui/chatty-settings-dialog.ui:365 msgid "MMS Carrier Settings" msgstr "Параметри MMS носія сигналу" -#: src/ui/chatty-settings-dialog.ui:375 +#: src/ui/chatty-settings-dialog.ui:369 msgid "MMSC" msgstr "MMSC" -#: src/ui/chatty-settings-dialog.ui:390 +#: src/ui/chatty-settings-dialog.ui:384 msgid "APN" msgstr "APN" -#: src/ui/chatty-settings-dialog.ui:405 +#: src/ui/chatty-settings-dialog.ui:399 msgid "Proxy" msgstr "Проксі" -#: src/ui/chatty-settings-dialog.ui:467 +#: src/ui/chatty-settings-dialog.ui:461 msgid "Message Archive Management" msgstr "Керування архівом повідомлень" -#: src/ui/chatty-settings-dialog.ui:468 +#: src/ui/chatty-settings-dialog.ui:462 msgid "Sync conversations with chat server" msgstr "Синхронізувати спілкування із сервером" -#: src/ui/chatty-settings-dialog.ui:483 +#: src/ui/chatty-settings-dialog.ui:477 msgid "Message Carbon Copies" msgstr "Копії повідомлень" -#: src/ui/chatty-settings-dialog.ui:667 +#: src/ui/chatty-settings-dialog.ui:661 msgid "Home server" msgstr "Домашній сервер" +#: src/ui/chatty-settings-dialog.ui:697 +msgid "Add _new account…" +msgstr "Додати _новий обліковий запис…" + #: src/ui/chatty-window.ui:28 msgid "Keyboard _Shortcuts" msgstr "_Клавіатурні скорочення" @@ -1040,10 +1044,6 @@ msgstr "Полишити спілкування" msgid "Delete Chat" msgstr "Вилучити спілкування" -#: src/ui/chatty-window.ui:353 -msgid "Call" -msgstr "Виклик" - #: src/ui/help-overlay.ui:14 msgctxt "shortcut window" msgid "General" @@ -1064,61 +1064,14 @@ msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Показати скорочення" -#: src/users/chatty-contact.c:311 +#: src/users/chatty-contact.c:325 msgid "Mobile: " msgstr "Мобільний: " -#: src/users/chatty-contact.c:313 +#: src/users/chatty-contact.c:327 msgid "Work: " msgstr "Робочий: " -#: src/users/chatty-contact.c:315 +#: src/users/chatty-contact.c:329 msgid "Other: " msgstr "Інший: " - -#~ msgid "Chatty requires Client-Server API to be ‘r0.5.x’ or ‘r0.6.x’" -#~ msgstr "" -#~ "Для роботи Chatty потрібен програмний інтерфейс клієнт-сервер «r0.5.x» " -#~ "або «r0.6.x»" - -#~ msgid "Matrix Home Server" -#~ msgstr "Домашній сервер Matrix" - -#~ msgid "_Accept" -#~ msgstr "При_йняти" - -#~ msgid "No chat selected" -#~ msgstr "Не вибрано спілкування" - -#~ msgid "Chats List" -#~ msgstr "Список спілкувань" - -#~ msgid "Indicate Idle Contacts" -#~ msgstr "Позначати бездіяльні контакти" - -#~ msgid "Blur avatars from idle contacts" -#~ msgstr "Розмивати аватари бездіяльних контактів" - -#~ msgid "Indicate Unknown Contacts" -#~ msgstr "Позначати невідомі контакти" - -#~ msgid "Color unknown contact ID red" -#~ msgstr "Позначати ідентифікатори невідомих контактів червоним" - -#~ msgid "Convert ASCII emoticons" -#~ msgstr "Перетворювати емоційки в ASCII" - -#~ msgid "Return = Send Message" -#~ msgstr "Ввід = надіслати повідомлення" - -#~ msgid "_Message Settings" -#~ msgstr "П_араметри повідомлень" - -#~ msgid "Delivery Reports" -#~ msgstr "Звіти щодо доставлення" - -#~ msgid "Request delivery reports for SMS and MMS" -#~ msgstr "Надсилати запит щодо звіту про доставлення SMS та MMS" - -#~ msgid "Error saving contact: %s" -#~ msgstr "Помилка під час спроби зберегти контакт: %s" diff --git a/run.in b/run.in index ba6b33c..37ce145 100755 --- a/run.in +++ b/run.in @@ -6,7 +6,7 @@ ABS_SRCDIR='@ABS_SRCDIR@' if [ "${CHATTY_GDB}" = 1 ]; then echo "Running chatty under gdb" - WRAPPER="gdb --args" + WRAPPER="gdb --directory=${ABS_BUILDDIR}/src --args" fi export GSETTINGS_SCHEMA_DIR="${ABS_BUILDDIR}/data" diff --git a/src/chatty-application.c b/src/chatty-application.c index 4e97115..ef3ea0f 100644 --- a/src/chatty-application.c +++ b/src/chatty-application.c @@ -111,7 +111,7 @@ application_open_uri (ChattyApplication *self) CHATTY_INFO (self->uri, "Opening uri:"); if (self->main_window && self->uri) - chatty_window_set_uri (CHATTY_WINDOW (self->main_window), self->uri); + chatty_window_set_uri (CHATTY_WINDOW (self->main_window), self->uri, NULL); g_clear_pointer (&self->uri, g_free); diff --git a/src/chatty-chat-view.c b/src/chatty-chat-view.c index 9c72993..11a56cc 100644 --- a/src/chatty-chat-view.c +++ b/src/chatty-chat-view.c @@ -288,9 +288,10 @@ chat_account_status_changed_cb (ChattyChatView *self) g_return_if_fail (account); enabled = chatty_account_get_status (account) == CHATTY_CONNECTED; - gtk_widget_set_sensitive (self->message_input, enabled); gtk_widget_set_sensitive (self->send_file_button, enabled); gtk_widget_set_sensitive (self->send_message_button, enabled); + + gtk_widget_set_visible (self->send_file_button, chatty_chat_has_file_upload (self->chat)); } static GtkWidget * @@ -424,7 +425,7 @@ chat_view_send_file_button_clicked_cb (ChattyChatView *self, if (CHATTY_IS_MM_CHAT (self->chat)) { chat_view_show_file_chooser (self); - } if (CHATTY_IS_MA_CHAT (self->chat)) { + } else if (CHATTY_IS_MA_CHAT (self->chat)) { /* TODO */ } else { @@ -525,12 +526,13 @@ chat_view_input_key_pressed_cb (ChattyChatView *self, static void chat_view_message_input_changed_cb (ChattyChatView *self) { - gboolean has_text; + gboolean has_text, has_files; g_assert (CHATTY_IS_CHAT_VIEW (self)); has_text = gtk_text_buffer_get_char_count (self->message_input_buffer) > 0; - gtk_widget_set_visible (self->send_message_button, has_text); + has_files = gtk_revealer_get_reveal_child (GTK_REVEALER (self->attachment_revealer)); + gtk_widget_set_visible (self->send_message_button, has_text || has_files); if (chatty_settings_get_send_typing (chatty_settings_get_default ())) chatty_update_typing_status (self); diff --git a/src/chatty-chat.c b/src/chatty-chat.c index 1ffdfb3..ce2afaa 100644 --- a/src/chatty-chat.c +++ b/src/chatty-chat.c @@ -17,7 +17,9 @@ #define _GNU_SOURCE #include +#include +#include "chatty-mm-buddy.h" #include "chatty-notification.h" #include "chatty-history.h" #include "chatty-chat.h" @@ -575,6 +577,72 @@ chatty_chat_is_im (ChattyChat *self) return CHATTY_CHAT_GET_CLASS (self)->is_im (self); } +/** + * chatty_chat_generate_name: + * @self: A #ChattyChat + * + * Generate custom name from chat members. + * + * Returns: A string that can be used to represent + * @self chat. Free with g_free(). + */ +char * +chatty_chat_generate_name (ChattyChat *self, + GListModel *members) +{ + const char *name_a = NULL, *name_b = NULL; + guint n_items, count; + + g_return_val_if_fail (CHATTY_IS_CHAT (self), NULL); + g_return_val_if_fail (G_IS_LIST_MODEL (members), NULL); + + count = n_items = g_list_model_get_n_items (members); + + for (guint i = 0; i < MIN (3, n_items); i++) { + g_autoptr(ChattyItem) buddy = NULL; + + buddy = g_list_model_get_item (members, i); + + /* Don't add self to create room name */ + if (g_strcmp0 (chatty_item_get_username (buddy), chatty_item_get_username (CHATTY_ITEM (self))) == 0) { + count--; + continue; + } + + if (!name_a) { + name_a = chatty_item_get_name (buddy); + + if (!name_a || !*name_a) + name_a = chatty_item_get_username (buddy); + + if ((!name_a || !*name_a) && CHATTY_IS_MM_BUDDY (buddy)) + name_a = chatty_mm_buddy_get_number (CHATTY_MM_BUDDY (buddy)); + } else { + name_b = chatty_item_get_name (buddy); + + if (!name_b || !*name_b) + name_b = chatty_item_get_username (buddy); + + if ((!name_b || !*name_b) && CHATTY_IS_MM_BUDDY (buddy)) + name_b = chatty_mm_buddy_get_number (CHATTY_MM_BUDDY (buddy)); + } + } + + if (count == 0) + return g_strdup (_("Empty room")); + + if (count == 1) + return g_strdup (name_a); + + if (count == 2) + /* TRANSLATORS: %s are name/user-id/phone numbers of two users */ + return g_strdup_printf (_("%s and %s"), name_a ?: "", name_b ?: ""); + + return g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%s and %u other", + "%s and %u others", count - 1), + name_a ?: "", count - 1); +} + gboolean chatty_chat_has_file_upload (ChattyChat *self) { diff --git a/src/chatty-chat.h b/src/chatty-chat.h index 657d7d0..2ac607e 100644 --- a/src/chatty-chat.h +++ b/src/chatty-chat.h @@ -94,6 +94,8 @@ void chatty_chat_set_data (ChattyChat *self, gpointer account, gpointer history_db); gboolean chatty_chat_is_im (ChattyChat *self); +char *chatty_chat_generate_name (ChattyChat *self, + GListModel *members); gboolean chatty_chat_has_file_upload (ChattyChat *self); const char *chatty_chat_get_chat_name (ChattyChat *self); ChattyAccount *chatty_chat_get_account (ChattyChat *self); diff --git a/src/chatty-contact-list.c b/src/chatty-contact-list.c new file mode 100644 index 0000000..a868143 --- /dev/null +++ b/src/chatty-contact-list.c @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2022 Purism SPC + * + * Authors: + * Mohammed Sadiq + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "chatty-contact-list" + +#include "config.h" + +#include +#include "contrib/gtk.h" + +#include "chatty-chat.h" +#include "chatty-purple.h" +#include "chatty-list-row.h" +#include "chatty-manager.h" +#include "chatty-contact-list.h" + +#define ITEMS_COUNT 50 + +struct _ChattyContactList +{ + GtkBox parent_instance; + + GtkWidget *scrolled_window; + GtkWidget *main_stack; + GtkWidget *empty_view; + GtkWidget *contact_list_view; + + GtkWidget *selected_contact_list; + GtkWidget *new_contact_list; + GtkWidget *new_contact_row; + GtkWidget *contact_list; + + ChattyItem *dummy_contact; + GListStore *selection_store; + GtkSliceListModel *slice_model; + GtkFilter *filter; + char *search_str; + + ChattyManager *manager; + + ChattyProtocol active_protocols; + ChattyProtocol filter_protocols; + gboolean can_multi_select; +}; + +G_DEFINE_TYPE (ChattyContactList, chatty_contact_list, GTK_TYPE_BOX) + +enum { + DELETE_ROW, + SELECTION_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + +static GtkWidget * +new_chat_contact_row_new (ChattyItem *item, + ChattyContactList *self) +{ + GtkWidget *row; + + row = chatty_list_contact_row_new (item); + chatty_list_row_set_selectable (CHATTY_LIST_ROW (row), self->can_multi_select); + + return row; +} + +static GtkWidget * +new_selected_contact_row_new (ChattyItem *item, + ChattyContactList *self) +{ + GtkWidget *row; + + row = new_chat_contact_row_new (item, self); + chatty_list_row_select (CHATTY_LIST_ROW (row), TRUE); + + if (!gtk_widget_is_visible (self->contact_list)) + chatty_list_row_show_delete_button (CHATTY_LIST_ROW (row)); + + return row; +} + +static gboolean +new_chat_dialog_contact_is_selected (ChattyContact *contact) +{ + g_return_val_if_fail (CHATTY_IS_CONTACT (contact), FALSE); + + return !!g_object_get_data (G_OBJECT (contact), "selected"); +} + +static void +update_new_contact_row (ChattyContactList *self) +{ + const char *dummy_value; + guint end_len, n_items; + gboolean valid = FALSE; + + chatty_contact_set_value (CHATTY_CONTACT (self->dummy_contact), self->search_str); + chatty_list_row_set_item (CHATTY_LIST_ROW (self->new_contact_row), self->dummy_contact); + + if (!self->search_str || !*self->search_str || + !(self->active_protocols & CHATTY_PROTOCOL_MMS_SMS)) { + gtk_widget_hide (self->new_contact_row); + return; + } + + end_len = strspn (self->search_str, "0123456789"); + valid = end_len == strlen (self->search_str); + valid = valid || !!chatty_utils_username_is_valid (self->search_str, CHATTY_PROTOCOL_MMS_SMS); + gtk_widget_set_visible (self->new_contact_row, valid); + + if (!self->can_multi_select) + return; + + dummy_value = chatty_item_get_username (self->dummy_contact); + n_items = g_list_model_get_n_items (G_LIST_MODEL (self->selection_store)); + + /* If new custom contact row match any of the selected contact, hide it */ + for (guint i = 0; i < n_items; i++) { + g_autoptr(ChattyItem) item = NULL; + const char *value; + + item = g_list_model_get_item (G_LIST_MODEL (self->selection_store), i); + value = chatty_item_get_username (item); + + if (g_strcmp0 (value, dummy_value) == 0) { + gtk_widget_hide (self->new_contact_row); + break; + } + } +} + +static gboolean +contact_list_filter_item_cb (ChattyItem *item, + ChattyContactList *self) +{ + ChattyAccount *account; + ChattyProtocol protocols; + + g_return_val_if_fail (CHATTY_IS_CONTACT_LIST (self), FALSE); + + if (self->can_multi_select) { + account = chatty_manager_get_mm_account (self->manager); + + if (chatty_account_get_status (account) == CHATTY_CONNECTED) { + /* Show only non-selected items, selected items are shown elsewhere */ + if (CHATTY_IS_CONTACT (item) && + !new_chat_dialog_contact_is_selected (CHATTY_CONTACT (item)) && + chatty_item_matches (item, self->search_str, CHATTY_PROTOCOL_MMS_SMS, TRUE)) + return TRUE; + } + + return FALSE; + } + +#ifdef PURPLE_ENABLED + if (CHATTY_IS_PP_BUDDY (item)) { + account = chatty_pp_buddy_get_account (CHATTY_PP_BUDDY (item)); + + if (chatty_account_get_status (account) != CHATTY_CONNECTED) + return FALSE; + } +#endif + + if (CHATTY_IS_CHAT (item)) { +#ifdef PURPLE_ENABLED + /* Hide chat if it's buddy chat as the buddy is shown separately */ + if (CHATTY_IS_PP_CHAT (item) && + chatty_pp_chat_get_purple_buddy (CHATTY_PP_CHAT (item))) + return FALSE; +#endif + + account = chatty_chat_get_account (CHATTY_CHAT (item)); + + if (!account || chatty_account_get_status (account) != CHATTY_CONNECTED) + return FALSE; + } + + protocols = self->active_protocols & self->filter_protocols; + + return chatty_item_matches (item, self->search_str, protocols, TRUE); +} + +static void +contact_list_edge_reached_cb (ChattyContactList *self, + GtkPositionType position) +{ + g_assert (CHATTY_IS_CONTACT_LIST (self)); + + if (position != GTK_POS_BOTTOM || + gtk_stack_get_visible_child (GTK_STACK (self->main_stack)) != self->contact_list_view) + return; + + gtk_slice_list_model_set_size (self->slice_model, + gtk_slice_list_model_get_size (self->slice_model) + ITEMS_COUNT); +} + +static void +selected_contact_row_activated_cb (ChattyContactList *self, + ChattyListRow *row, + GtkListBox *list) +{ + ChattyItem *item; + + item = chatty_list_row_get_item (row); + g_object_set_data (G_OBJECT (item), "selected", GINT_TO_POINTER (FALSE)); + + if (chatty_contact_is_dummy (CHATTY_CONTACT (item))) { + /* If the deselected item value matches the search string, show new contact row */ + if (self->search_str && + g_strcmp0 (chatty_item_get_username (item), self->search_str) == 0) + gtk_widget_show (self->new_contact_row); + } else { + guint position; + + /* Emit items-changed so that it will be re-filtered and thus shown as it's no longer selected */ + if (chatty_utils_get_item_position (chatty_manager_get_contact_list (self->manager), item, &position)) + g_list_model_items_changed (chatty_manager_get_contact_list (self->manager), position, 1, 1); + } + + chatty_utils_remove_list_item (self->selection_store, item); + g_signal_emit (self, signals[SELECTION_CHANGED], 0); +} + +static void +contact_list_row_activated_cb (ChattyContactList *self, + ChattyListRow *row, + GtkListBox *list) +{ + ChattyItem *item; + + g_assert (CHATTY_IS_CONTACT_LIST (self)); + g_assert (CHATTY_IS_LIST_ROW (row)); + g_assert (GTK_IS_LIST_BOX (list)); + g_assert (self->selection_store); + + item = chatty_list_row_get_item (row); + if (CHATTY_IS_CONTACT (item) && chatty_contact_is_dummy (CHATTY_CONTACT (item))) { + g_autoptr(ChattyContact) contact = NULL; + + contact = chatty_contact_dummy_new (_("Unknown Contact"), + chatty_item_get_username (item)); + g_list_store_append (self->selection_store, contact); + } else { + g_object_set_data (G_OBJECT (item), "selected", GINT_TO_POINTER (TRUE)); + g_list_store_append (self->selection_store, item); + } + + if (self->can_multi_select) + gtk_widget_hide (GTK_WIDGET (row)); + + g_signal_emit (self, signals[SELECTION_CHANGED], 0); +} + +static void +contact_list_changed_cb (ChattyContactList *self) +{ + HdyStatusPage *page; + gboolean empty; + + g_assert (CHATTY_IS_CONTACT_LIST (self)); + + empty = !gtk_widget_get_visible (self->new_contact_row); + empty = empty && g_list_model_get_n_items (G_LIST_MODEL (self->slice_model)) == 0; + if (self->selection_store) + empty = empty && g_list_model_get_n_items (G_LIST_MODEL (self->selection_store)) == 0; + + if (empty) + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->empty_view); + else + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->contact_list_view); + + page = HDY_STATUS_PAGE (self->empty_view); + if (self->search_str && *self->search_str) { + hdy_status_page_set_icon_name (page, "system-search-symbolic"); + hdy_status_page_set_title (page, _("No Search Results")); + hdy_status_page_set_description (page, _("Try different search, or type a valid " + "number to create new chat")); + } else { + hdy_status_page_set_icon_name (page, "sm.puri.Chatty-symbolic"); + hdy_status_page_set_title (page, _("No Contacts")); + hdy_status_page_set_description (page, NULL); + } +} + +static void +contact_list_active_protocols_changed_cb (ChattyContactList *self) +{ + ChattyAccount *mm_account; + ChattyProtocol protocol; + gboolean valid; + + g_assert (CHATTY_IS_CONTACT_LIST (self)); + + self->active_protocols = chatty_manager_get_active_protocols (self->manager); + gtk_filter_changed (self->filter, GTK_FILTER_CHANGE_DIFFERENT); + + protocol = CHATTY_PROTOCOL_MMS_SMS; + valid = protocol == chatty_utils_username_is_valid (self->search_str, protocol); + mm_account = chatty_manager_get_mm_account (self->manager); + valid = valid && chatty_account_get_status (mm_account) == CHATTY_CONNECTED; + gtk_widget_set_visible (self->new_contact_row, valid); + contact_list_changed_cb (self); +} + +static void +contact_list_delete_item (ChattyContactList *self, + ChattyListRow *row) +{ + g_assert (CHATTY_IS_CONTACT_LIST (self)); + g_assert (CHATTY_IS_LIST_ROW (row)); + + selected_contact_row_activated_cb (self, row, GTK_LIST_BOX (self->selected_contact_list)); +} + +static void +chatty_contact_list_finalize (GObject *object) +{ + ChattyContactList *self = (ChattyContactList *)object; + + g_clear_object (&self->dummy_contact); + g_clear_object (&self->slice_model); + g_clear_object (&self->selection_store); + g_clear_object (&self->filter); + g_clear_object (&self->manager); + g_free (self->search_str); + + G_OBJECT_CLASS (chatty_contact_list_parent_class)->finalize (object); +} + +static void +chatty_contact_list_class_init (ChattyContactListClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = chatty_contact_list_finalize; + + signals [DELETE_ROW] = + g_signal_new ("delete-row", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, CHATTY_TYPE_LIST_ROW); + + signals [SELECTION_CHANGED] = + g_signal_new ("selection-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/Chatty/" + "ui/chatty-contact-list.ui"); + + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, scrolled_window); + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, main_stack); + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, empty_view); + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, contact_list_view); + + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, selected_contact_list); + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, new_contact_list); + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, new_contact_row); + gtk_widget_class_bind_template_child (widget_class, ChattyContactList, contact_list); + + gtk_widget_class_bind_template_callback (widget_class, contact_list_edge_reached_cb); + gtk_widget_class_bind_template_callback (widget_class, selected_contact_row_activated_cb); + gtk_widget_class_bind_template_callback (widget_class, contact_list_row_activated_cb); + gtk_widget_class_bind_template_callback (widget_class, contact_list_changed_cb); +} + +static void +chatty_contact_list_init (ChattyContactList *self) +{ + g_autoptr(GtkFilterListModel) filter_model = NULL; + g_autoptr(GtkSortListModel) sort_model = NULL; + g_autoptr(GtkSorter) sorter = NULL; + + gtk_widget_init_template (GTK_WIDGET (self)); + + self->manager = g_object_ref (chatty_manager_get_default ()); + self->filter_protocols = CHATTY_PROTOCOL_ANY; + + self->dummy_contact = CHATTY_ITEM (chatty_contact_dummy_new (_("Send To"), NULL)); + chatty_list_row_set_item (CHATTY_LIST_ROW (self->new_contact_row), self->dummy_contact); + + sorter = gtk_custom_sorter_new ((GCompareDataFunc)chatty_item_compare, NULL, NULL); + sort_model = gtk_sort_list_model_new (chatty_manager_get_contact_list (self->manager), sorter); + + self->filter = gtk_custom_filter_new ((GtkCustomFilterFunc)contact_list_filter_item_cb, self, NULL); + filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), self->filter); + + self->slice_model = gtk_slice_list_model_new (G_LIST_MODEL (filter_model), 0, ITEMS_COUNT); + g_signal_connect_object (self->slice_model, "items-changed", + G_CALLBACK (contact_list_changed_cb), self, + G_CONNECT_SWAPPED); + gtk_list_box_bind_model (GTK_LIST_BOX (self->contact_list), + G_LIST_MODEL (self->slice_model), + (GtkListBoxCreateWidgetFunc)new_chat_contact_row_new, + g_object_ref (self), g_object_unref); + g_signal_connect_object (self->manager, "notify::active-protocols", + G_CALLBACK (contact_list_active_protocols_changed_cb), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self, "delete-row", + G_CALLBACK (contact_list_delete_item), + self, G_CONNECT_AFTER); + contact_list_active_protocols_changed_cb (self); + contact_list_changed_cb (self); +} + +GtkWidget * +chatty_contact_list_new (void) +{ + return g_object_new (CHATTY_TYPE_CONTACT_LIST, NULL); +} + +void +chatty_contact_list_set_selection_store (ChattyContactList *self, + GListStore *list_store) +{ + g_return_if_fail (CHATTY_IS_CONTACT_LIST (self)); + g_return_if_fail (G_IS_LIST_STORE (list_store)); + g_return_if_fail (g_list_model_get_item_type (G_LIST_MODEL (list_store)) == CHATTY_TYPE_ITEM); + + g_set_object (&self->selection_store, list_store); + + gtk_list_box_bind_model (GTK_LIST_BOX (self->selected_contact_list), + (gpointer) list_store, + (GtkListBoxCreateWidgetFunc)new_selected_contact_row_new, + g_object_ref (self), g_object_unref); + g_signal_connect_object (list_store, "items-changed", + G_CALLBACK (contact_list_changed_cb), self, + G_CONNECT_SWAPPED); +} + +void +chatty_contact_list_show_selected_only (ChattyContactList *self) +{ + g_return_if_fail (CHATTY_IS_CONTACT_LIST (self)); + + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->contact_list_view); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->scrolled_window), + GTK_POLICY_NEVER, GTK_POLICY_NEVER); + gtk_widget_hide (self->new_contact_row); + gtk_widget_hide (self->contact_list); +} + +static void +contact_list_update_selectable (GtkWidget *widget, + gpointer callback_data) +{ + ChattyContactList *self = callback_data; + + g_assert (CHATTY_IS_CONTACT_LIST (self)); + + chatty_list_row_set_selectable ((ChattyListRow *)widget, self->can_multi_select); +} + +void +chatty_contact_list_can_multi_select (ChattyContactList *self, + gboolean can_multi_select) +{ + GListModel *model; + guint n_items; + + g_return_if_fail (CHATTY_IS_CONTACT_LIST (self)); + g_return_if_fail (self->selection_store); + + self->can_multi_select = !!can_multi_select; + + gtk_widget_set_visible (self->selected_contact_list, can_multi_select); + chatty_list_row_set_selectable (CHATTY_LIST_ROW (self->new_contact_row), can_multi_select); + gtk_container_foreach (GTK_CONTAINER (self->contact_list), + (GtkCallback)contact_list_update_selectable, self); + + model = G_LIST_MODEL (self->selection_store); + n_items = g_list_model_get_n_items (model); + + for (guint i = 0; i < n_items; i++) { + g_autoptr(GObject) item = NULL; + + item = g_list_model_get_item (model, i); + g_object_set_data (item, "selected", GINT_TO_POINTER (FALSE)); + } + + g_list_store_remove_all (self->selection_store); +} + +void +chatty_contact_list_set_filter (ChattyContactList *self, + ChattyProtocol protocol, + const char *needle) +{ + g_return_if_fail (CHATTY_IS_CONTACT_LIST (self)); + + self->filter_protocols = protocol; + g_free (self->search_str); + self->search_str = g_utf8_casefold (needle, -1); + + update_new_contact_row (self); + gtk_slice_list_model_set_size (self->slice_model, ITEMS_COUNT); + gtk_filter_changed (self->filter, GTK_FILTER_CHANGE_DIFFERENT); +} diff --git a/src/chatty-contact-list.h b/src/chatty-contact-list.h new file mode 100644 index 0000000..0b25a2e --- /dev/null +++ b/src/chatty-contact-list.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 Purism SPC + * + * Authors: + * Mohammed Sadiq + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include "chatty-enums.h" + +G_BEGIN_DECLS + +#define CHATTY_TYPE_CONTACT_LIST (chatty_contact_list_get_type ()) + +G_DECLARE_FINAL_TYPE (ChattyContactList, chatty_contact_list, CHATTY, CONTACT_LIST, GtkBox) + +GtkWidget *chatty_contact_list_new (void); +void chatty_contact_list_set_selection_store (ChattyContactList *self, + GListStore *list_store); +void chatty_contact_list_show_selected_only (ChattyContactList *self); +void chatty_contact_list_can_multi_select (ChattyContactList *self, + gboolean can_multi_select); +void chatty_contact_list_set_filter (ChattyContactList *self, + ChattyProtocol protocol, + const char *needle); + +G_END_DECLS diff --git a/src/chatty-enums.h b/src/chatty-enums.h index 2126217..93cffb4 100644 --- a/src/chatty-enums.h +++ b/src/chatty-enums.h @@ -131,6 +131,8 @@ typedef enum CHATTY_MESSAGE_IMAGE, CHATTY_MESSAGE_VIDEO, CHATTY_MESSAGE_AUDIO, + /* An MMS can have a several files in different formats */ + CHATTY_MESSAGE_MMS, } ChattyMsgType; typedef enum diff --git a/src/chatty-history.c b/src/chatty-history.c index 393189c..27efab8 100644 --- a/src/chatty-history.c +++ b/src/chatty-history.c @@ -29,11 +29,14 @@ #include "chatty-mm-chat.h" #include "chatty-history.h" +/* Used as placeholders until we get the real values */ +#define MM_NUMBER "invalid-0000000000000000" + #define STRING(arg) STRING_VALUE(arg) #define STRING_VALUE(arg) #arg /* increment when DB changes */ -#define HISTORY_VERSION 3 +#define HISTORY_VERSION 4 /* Shouldn't be modified, new values should be appended */ #define MESSAGE_DIRECTION_OUT -1 @@ -58,6 +61,10 @@ #define PROTOCOL_TELEGRAM 5 #define PROTOCOL_SIP 6 +#define MM_PROTOCOL_UNKNOWN 0 +#define MM_PROTOCOL_MMS 1 +#define MM_PROTOCOL_SMS 1 + /* Chat thread type */ /* For SMS/MMS, if it's THREAD_GROUP_CHAT it's always MMS, * If it's THREAD_DIRECT_CHAT with 2+ members, it's always @@ -84,6 +91,8 @@ #define MESSAGE_TYPE_IMAGE 9 #define MESSAGE_TYPE_VIDEO 10 #define MESSAGE_TYPE_AUDIO 11 +/* An MMS message may have several files of different type */ +#define MESSAGE_TYPE_MMS 12 /* Temporary until the link is parsed */ #define MESSAGE_TYPE_LINK 20 @@ -104,7 +113,6 @@ struct _ChattyHistory { GObject parent_instance; - GAsyncQueue *queue; GThread *worker_thread; sqlite3 *db; @@ -246,6 +254,9 @@ history_message_type_to_value (ChattyMsgType type) case CHATTY_MESSAGE_VIDEO: return MESSAGE_TYPE_VIDEO; + case CHATTY_MESSAGE_MMS: + return MESSAGE_TYPE_MMS; + default: g_return_val_if_reached (MESSAGE_TYPE_HTML); } @@ -273,6 +284,8 @@ history_value_to_message_type (int value) return CHATTY_MESSAGE_AUDIO; else if (value == MESSAGE_TYPE_VIDEO) return CHATTY_MESSAGE_VIDEO; + else if (value == MESSAGE_TYPE_MMS) + return CHATTY_MESSAGE_MMS; g_return_val_if_reached (CHATTY_MESSAGE_HTML); } @@ -493,26 +506,13 @@ chatty_history_create_schema (ChattyHistory *self, "status INT, " "size INTEGER);" - "CREATE TABLE IF NOT EXISTS audio (" - "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " - "file_id INTEGER NOT NULL UNIQUE, " - "duration INTEGER, " - "FOREIGN KEY(file_id) REFERENCES files(id));" - - "CREATE TABLE IF NOT EXISTS image (" - "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " - "file_id INTEGER NOT NULL UNIQUE, " - "width INTEGER, " - "height INTEGER, " - "FOREIGN KEY(file_id) REFERENCES files(id));" - - "CREATE TABLE IF NOT EXISTS video (" + /* Introduced in version 4, replaces 'audio', 'image' and 'video' */ + "CREATE TABLE IF NOT EXISTS file_metadata (" "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " - "file_id INTEGER NOT NULL UNIQUE, " + "file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, " "width INTEGER, " "height INTEGER, " - "duration INTEGER, " - "FOREIGN KEY(file_id) REFERENCES files(id));" + "duration INTEGER);" /* TODO: Someday */ /* "CREATE TABLE IF NOT EXISTS devices (" */ @@ -539,17 +539,8 @@ chatty_history_create_schema (ChattyHistory *self, "UNIQUE (user_id, protocol));" "INSERT OR IGNORE INTO users(username,type) VALUES " - "('SMS'," STRING (CHATTY_ID_PHONE_VALUE) ")," - "('MMS'," STRING (CHATTY_ID_PHONE_VALUE) ");" - - "INSERT OR IGNORE INTO accounts(user_id,protocol) " - "SELECT users.id," - "CASE " - "WHEN users.username='SMS' " - "THEN " STRING (PROTOCOL_MMS_SMS) " " - "ELSE " STRING (PROTOCOL_MMS) " " - "END " - "FROM users;" + /* Some Invalid value */ + "('"MM_NUMBER"'," STRING (CHATTY_ID_PHONE_VALUE) ");" "CREATE TABLE IF NOT EXISTS threads (" "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " @@ -582,8 +573,35 @@ chatty_history_create_schema (ChattyHistory *self, "encrypted INTEGER DEFAULT 0, " /* preview file: Introduced in version 2 */ "preview_id INTEGER REFERENCES files(id), " + /* Introduced in version 4 */ + "subject TEXT, " "UNIQUE (uid, thread_id, body, time));" + /* Introduced in version 4 */ + "CREATE TABLE IF NOT EXISTS mm_messages (" + "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + "message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, " + /* messages in same thread can be sent from different SIM */ + "account_id INTEGER NOT NULL REFERENCES accounts(id), " + /* MM_PROTOCOL_MMS, MM_PROTOCOL_SMS etc. */ + "protocol INTEGER NOT NULL, " + "smsc TEXT, " + /* For outgoing messages: the time message was delivered */ + /* For incoming messages: the time message was sent */ + "time_sent INTEGER, " + "validity INTEGER, " + /* TODO: Create a modem table with iccid when multiple SIMs are supported */ + /* "modem_id INTEGER NOT NULL REFERENCES modem(id), " */ + "reference_number INTEGER);" + + /* Introduced in version 4 */ + "CREATE TABLE IF NOT EXISTS message_files (" + "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + "message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, " + "file_id INTEGER NOT NULL REFERENCES files(id), " + "preview_id INTEGER REFERENCES files(id), " + "UNIQUE (message_id, file_id));" + /* Alter threads after the messages table is created */ "ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id);" @@ -591,6 +609,14 @@ chatty_history_create_schema (ChattyHistory *self, "ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT " STRING(THREAD_VISIBILITY_VISIBLE) ";" + /* Introduced in Version 4 */ + "ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1;" + + "INSERT OR IGNORE INTO accounts(user_id,protocol) " + "SELECT users.id,"STRING (PROTOCOL_MMS_SMS)" " + "FROM users " + "WHERE users.username='"MM_NUMBER"';" + "COMMIT;"; status = sqlite3_exec (self->db, sql, NULL, NULL, &error); @@ -598,6 +624,7 @@ chatty_history_create_schema (ChattyHistory *self, if (status == SQLITE_OK) return TRUE; + g_warning ("error: %s", error); db = g_steal_pointer (&self->db); g_task_return_new_error (task, G_IO_ERROR, @@ -1043,6 +1070,12 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, return FALSE; status = sqlite3_exec (self->db, + + "BEGIN TRANSACTION;" + "UPDATE chatty_im SET account='"MM_NUMBER"' " + "WHERE chatty_im.account='SMS';" + "COMMIT;" + "BEGIN TRANSACTION;" /*** Users ***/ @@ -1051,7 +1084,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, "SELECT DISTINCT account," STRING(CHATTY_ID_XMPP_VALUE) " FROM chatty_im " /* A Rough match for XMPP accounts */ "WHERE chatty_im.account GLOB '[^@+]*' " - "AND chatty_im.account!='SMS' " + "AND chatty_im.account!='"MM_NUMBER"' " "AND chatty_im.who GLOB '[^@+]*@*';" /* XMPP MUC accounts */ @@ -1064,7 +1097,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, /* SMS account */ "INSERT OR IGNORE INTO users(username,type) " "SELECT DISTINCT account," STRING(CHATTY_ID_PHONE_VALUE) " FROM chatty_im " - "WHERE account='SMS';" + "WHERE account='"MM_NUMBER"';" /* Matrix accounts */ "INSERT OR IGNORE INTO users(username,type) " @@ -1073,7 +1106,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, "WHERE chatty_chat.room GLOB '!?*:?*' " "AND chatty_chat.account NOT GLOB '?*@?*' " "AND chatty_chat.account NOT GLOB '+?*' " - "AND chatty_chat.account!='SMS';" + "AND chatty_chat.account!='"MM_NUMBER"';" /* XMPP IM users */ "INSERT OR IGNORE INTO users(username,type) " @@ -1085,7 +1118,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, STRING(CHATTY_ID_XMPP_VALUE) " FROM chatty_im " /* A Rough match for XMPP users */ "WHERE chatty_im.account GLOB '[^@+]*' " - "AND chatty_im.account!='SMS' " + "AND chatty_im.account!='"MM_NUMBER"' " "AND chatty_im.who GLOB '[^@]*@*';" /* XMPP MUC users */ @@ -1116,7 +1149,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, /* We have exactly one account for SMS */ "INSERT OR IGNORE INTO accounts(user_id,protocol,enabled) " "SELECT DISTINCT users.id," STRING(PROTOCOL_MMS_SMS) ",1 FROM users " - "WHERE users.username='SMS';" + "WHERE users.username='"MM_NUMBER"';" /* XMPP IM accounts */ "INSERT OR IGNORE INTO accounts(user_id,protocol) " @@ -1184,7 +1217,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, " ON accounts.user_id=users.id " "INNER JOIN users " " ON users.username=chatty_im.account " - "WHERE chatty_im.account!='SMS' AND users.type=" STRING(CHATTY_ID_PHONE_VALUE) ";" + "WHERE chatty_im.account!='"MM_NUMBER"' AND users.type=" STRING(CHATTY_ID_PHONE_VALUE) ";" /* Telegram MUC chats */ "INSERT OR IGNORE INTO threads(name,account_id,type) " @@ -1342,7 +1375,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, /* Fill in accounts */ if (!history_add_phone_account (self, task, account_number ? account_number : account, - g_strcmp0 (account, "SMS") == 0 ? PROTOCOL_MMS_SMS : PROTOCOL_TELEGRAM)) + g_strcmp0 (account, MM_NUMBER) == 0 ? PROTOCOL_MMS_SMS : PROTOCOL_TELEGRAM)) return FALSE; if (!history_add_phone_user (self, task, @@ -1428,7 +1461,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, /* Fill in accounts */ if (!history_add_phone_account (self, task, account_number ? account_number : account, - g_strcmp0 (account, "SMS") == 0 ? PROTOCOL_MMS_SMS : PROTOCOL_TELEGRAM)) + g_strcmp0 (account, MM_NUMBER) == 0 ? PROTOCOL_MMS_SMS : PROTOCOL_TELEGRAM)) return FALSE; if (sender && @@ -1537,9 +1570,14 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, sqlite3_stmt *stmt; status = sqlite3_prepare_v2 (self->db, /* SMS users with phone numbers sorted */ - "SELECT DISTINCT generated.who FROM " - "(SELECT who,id FROM chatty_im WHERE account='SMS' ORDER BY id ASC) " - "AS generated ORDER BY generated.id;", + /* HACK: empty LEFT JOIN is used to keep the first distinct match + * instead of the last in the list. + * We are still relying on implementation details of sqlite, + * which is not good. + */ + "SELECT DISTINCT chatty_im.who FROM chatty_im " + "LEFT JOIN chatty_im as im " + "WHERE chatty_im.account='"MM_NUMBER"' ORDER BY chatty_im.id ASC;", -1, &stmt, NULL); if (status == SQLITE_OK) @@ -1559,7 +1597,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, sender_number ? sender_number : sender, NULL); - history_add_thread (self, task, "SMS", + history_add_thread (self, task, MM_NUMBER, sender_number ? sender_number : sender, sender, THREAD_DIRECT_CHAT); @@ -1573,7 +1611,7 @@ chatty_history_migrate_db_to_v1_to_v3 (ChattyHistory *self, "ON threads.account_id=accounts.id " "INNER JOIN users AS a " "ON accounts.user_id=a.id AND a.username=chatty_im.account " - "AND chatty_im.account='SMS' " + "AND chatty_im.account='"MM_NUMBER"' " "INNER JOIN users as u " "ON u.username=? " "ORDER BY timestamp ASC, chatty_im.id ASC;", @@ -1772,6 +1810,138 @@ chatty_history_migrate_db_to_v3 (ChattyHistory *self, return FALSE; } +/* For migrating from v3 to v4 */ +static gboolean +chatty_history_migrate_db_to_v4 (ChattyHistory *self, + GTask *task) +{ + char *error = NULL; + int status; + + g_assert (CHATTY_IS_HISTORY (self)); + g_assert (G_IS_TASK (task)); + g_assert (g_thread_self () == self->worker_thread); + + chatty_history_backup (self); + + status = sqlite3_exec (self->db, + "BEGIN TRANSACTION;" + "PRAGMA foreign_keys=OFF;" + + "ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1;" + "ALTER TABLE messages ADD COLUMN subject TEXT;" + + "CREATE TABLE IF NOT EXISTS mm_messages (" + "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + "message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, " + /* messages in same thread can be sent from different SIM */ + "account_id INTEGER NOT NULL REFERENCES accounts(id), " + /* MM_PROTOCOL_MMS, MM_PROTOCOL_SMS etc. */ + "protocol INTEGER NOT NULL, " + "smsc TEXT, " + /* For outgoing messages: the time message was delivered */ + /* For incoming messages: the time message was sent */ + "time_sent INTEGER, " + "validity INTEGER, " + "reference_number INTEGER);" + + "CREATE TABLE IF NOT EXISTS message_files (" + "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + "message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, " + "file_id INTEGER NOT NULL REFERENCES files(id), " + "preview_id INTEGER REFERENCES files(id), " + "UNIQUE (message_id, file_id));" + + /* Introduced in version 4, replaces 'audio', 'image' and 'video' */ + "CREATE TABLE IF NOT EXISTS file_metadata (" + "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + "file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, " + "width INTEGER, " + "height INTEGER, " + "duration INTEGER);" + + "DELETE FROM accounts " + "WHERE protocol="STRING (PROTOCOL_MMS)" " + "AND accounts.user_id IN (" + "SELECT users.id FROM users " + "WHERE users.id=accounts.user_id " + "AND users.username='MMS' AND " + "users.type="STRING (CHATTY_ID_PHONE_VALUE)");" + + "DELETE FROM users " + "WHERE username='MMS' AND type="STRING (CHATTY_ID_PHONE_VALUE)";" + + "UPDATE users SET username='"MM_NUMBER"' " + "WHERE username='SMS' AND type="STRING (CHATTY_ID_PHONE_VALUE)";" + + "INSERT INTO message_files(message_id,file_id) SELECT messages.id,files.id " + "FROM messages " + "INNER JOIN files ON messages.body=files.id " + "AND messages.body_type >=" STRING (MESSAGE_TYPE_FILE) " " + "AND messages.body_type <=" STRING (MESSAGE_TYPE_AUDIO)";" + + "UPDATE messages SET body='' " + "WHERE body_type >=" STRING (MESSAGE_TYPE_FILE) " " + "AND body_type <=" STRING (MESSAGE_TYPE_AUDIO)";" + + "INSERT INTO file_metadata(file_id,width,height,duration) " + "SELECT body,width,height,duration " + "FROM messages " + "INNER JOIN files ON files.id=body " + "INNER JOIN video ON video.file_id=files.id " + "AND messages.body_type =" STRING (MESSAGE_TYPE_VIDEO) ";" + + "INSERT INTO file_metadata(file_id,width,height) " + "SELECT body,width,height " + "FROM messages " + "INNER JOIN files ON files.id=body " + "INNER JOIN image ON image.file_id=files.id " + "AND messages.body_type =" STRING (MESSAGE_TYPE_IMAGE) ";" + + "INSERT INTO file_metadata(file_id,duration) " + "SELECT body,duration " + "FROM messages " + "INNER JOIN files ON files.id=body " + "INNER JOIN audio ON audio.file_id=files.id " + "AND messages.body_type =" STRING (MESSAGE_TYPE_AUDIO) ";" + + /* We now have a single user for both sms and mms */ + "DELETE FROM accounts " + "WHERE protocol="STRING(PROTOCOL_MMS)" " + "AND accounts.user_id IN (" + "SELECT users.id FROM users " + "WHERE users.id=accounts.user_id " + "AND users.username='MMS' AND " + "users.type="STRING (CHATTY_ID_PHONE_VALUE)");" + + /* "UPDATE users SET username='"MM_NUMBER"' " */ + /* "WHERE users.username='SMS' AND type="STRING (CHATTY_ID_PHONE_VALUE)";" */ + + /* We now have single 'meta_data' for */ + "DROP TABLE IF EXISTS audio;" + "DROP TABLE IF EXISTS image;" + "DROP TABLE IF EXISTS video;" + + "COMMIT;", + NULL, NULL, &error); + + if (status == SQLITE_OK || status == SQLITE_DONE) { + /* Update user_version pragma */ + if (!chatty_history_update_version (self, task)) + return FALSE; + return TRUE; + } + + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Couldn't set db version. errno: %d, desc: %s. %s", + status, sqlite3_errstr (status), error); + sqlite3_free (error); + + return FALSE; +} + static gboolean chatty_history_migrate (ChattyHistory *self, GTask *task) @@ -1805,6 +1975,11 @@ chatty_history_migrate (ChattyHistory *self, case 2: if (!chatty_history_migrate_db_to_v3 (self, task)) return FALSE; + /* fallthrough */ + + case 3: + if (!chatty_history_migrate_db_to_v4 (self, task)) + return FALSE; break; default: @@ -1905,6 +2080,49 @@ history_close_db (ChattyHistory *self, } } +static GList * +history_get_files (ChattyHistory *self, + int message_id) +{ + sqlite3_stmt *stmt; + GList *files = NULL; + + if (!message_id) + return NULL; + + /* 0 1 2 3 4 5 6 7 8 */ + sqlite3_prepare_v2 (self->db, "SELECT url,path,files.name,size,status,width,height,duration,mime_type.name FROM files " + "INNER JOIN message_files " + "ON message_files.file_id=files.id " + "LEFT JOIN mime_type " + "ON mime_type.id=files.mime_type_id " + "LEFT JOIN file_metadata " + "ON file_metadata.file_id=files.id " + "WHERE message_files.message_id=?;", -1, &stmt, NULL); + history_bind_int (stmt, 1, message_id, "binding when getting timestamp"); + + while (sqlite3_step (stmt) == SQLITE_ROW) { + ChattyFileInfo *file; + + file = g_new0 (ChattyFileInfo, 1); + file->url = g_strdup ((const char *)sqlite3_column_text (stmt, 0)); + file->path = g_strdup ((const char *)sqlite3_column_text (stmt, 1)); + file->file_name = g_strdup ((const char *)sqlite3_column_text (stmt, 2)); + file->size = sqlite3_column_int (stmt, 3); + file->status = sqlite3_column_int (stmt, 4); + file->width = sqlite3_column_int (stmt, 5); + file->height = sqlite3_column_int (stmt, 6); + file->duration = sqlite3_column_int (stmt, 7); + file->mime_type = g_strdup ((const char *)sqlite3_column_text (stmt, 8)); + + files = g_list_append (files, file); + } + + sqlite3_finalize (stmt); + + return files; +} + static GPtrArray * get_messages_before_time (ChattyHistory *self, ChattyChat *chat, @@ -1929,35 +2147,22 @@ get_messages_before_time (ChattyHistory *self, status = sqlite3_prepare_v2 (self->db, /* 0 1 2 3 4 5 */ "SELECT DISTINCT time,direction,body,uid,coalesce(users.alias,users.username),body_type," - /* 6 7 8 9 10 11 */ - "files.name,files.url,files.path,mime_type.name,files.size,files.status," - "coalesce(video.width,image.width)," /* 12 */ - "coalesce(video.height,image.height)," /* 13 */ - "coalesce(video.duration,audio.duration)," /* 14 */ - /* 15 16 17 18 19 20 */ + /* 6 7 8 9 10 11 */ "p_files.name,p_files.url,p_files.path,p_mime_type.name,p_files.size,p_files.status," - "coalesce(p_video.width,p_image.width)," /* 21 */ - "coalesce(p_video.height,p_image.height)," /* 22 */ - "coalesce(p_video.duration,p_audio.duration)," /* 23 */ - /* 24 */ - "messages.status " + /* 12 13 14 */ + "m.width,m.height,m.duration," + /* 15 16 17 */ + "messages.status,messages.id,subject " "FROM messages " - "LEFT JOIN files ON body_type>=8 AND body_type<=11 AND files.id=body " - "LEFT JOIN mime_type ON body_type>=8 AND body_type<=11 AND files.mime_type_id=mime_type.id " - "LEFT JOIN image ON body_type=9 AND files.id=image.file_id " - "LEFT JOIN video ON body_type=10 AND files.id=video.file_id " - "LEFT JOIN audio ON body_type=11 AND files.id=audio.file_id " "LEFT JOIN files AS p_files ON messages.preview_id=p_files.id " "LEFT JOIN mime_type AS p_mime_type ON p_files.mime_type_id=p_mime_type.id " - "LEFT JOIN image AS p_image ON p_files.id=p_image.file_id " - "LEFT JOIN video AS p_video ON p_files.id=p_video.file_id " - "LEFT JOIN audio AS p_audio ON p_files.id=p_audio.file_id " + "LEFT JOIN file_metadata AS m on p_files.id=m.file_id " "LEFT JOIN users " "ON messages.sender_id=users.id " "WHERE thread_id=? " "AND messages.time <= ? " - "AND body NOT NULL AND body !='' " + "AND body NOT NULL " "ORDER BY time DESC, messages.id DESC LIMIT ?;", -1, &stmt, NULL); history_bind_int (stmt, 1, thread_id, "binding when getting messages"); @@ -1965,10 +2170,10 @@ get_messages_before_time (ChattyHistory *self, history_bind_int (stmt, 3, limit, "binding when getting messages"); while (sqlite3_step (stmt) == SQLITE_ROW) { - ChattyFileInfo *file = NULL, *preview = NULL; + ChattyFileInfo *preview = NULL; ChattyMessage *message; const char *msg = NULL, *uid; - const char *who = NULL; + const char *who = NULL, *subject; ChattyMsgType type; guint time_stamp; int direction; @@ -1992,43 +2197,51 @@ get_messages_before_time (ChattyHistory *self, time_stamp = sqlite3_column_int (stmt, 0); direction = sqlite3_column_int (stmt, 1); type = history_value_to_message_type (sqlite3_column_int (stmt, 5)); - - /* preview is not limitted to media messages */ - if (sqlite3_column_text (stmt, 16)) { - preview = g_new0 (ChattyFileInfo, 1); - preview->file_name = g_strdup ((const char *)sqlite3_column_text (stmt, 15)); - preview->url = g_strdup ((const char *)sqlite3_column_text (stmt, 16)); - preview->path = g_strdup ((const char *)sqlite3_column_text (stmt, 17)); - preview->mime_type = g_strdup ((const char *)sqlite3_column_text (stmt, 18)); - preview->size = sqlite3_column_int (stmt, 19); - preview->status = sqlite3_column_int (stmt, 20); - preview->width = sqlite3_column_int (stmt, 21); - preview->height = sqlite3_column_int (stmt, 22); - preview->duration = sqlite3_column_int (stmt, 23); + subject = (const char *)sqlite3_column_text (stmt, 17); + msg = (const char *)sqlite3_column_text (stmt, 2); + + /* Skip if the message is empty and has no attachment */ + if ((!msg || !*msg) && (!subject || !*subject)) { + sqlite3_stmt *check_stmt; + + status = sqlite3_prepare_v2 (self->db, + "SELECT file_id " + "FROM message_files " + "WHERE message_id=? " + "LIMIT 1;", + -1, &check_stmt, NULL); + history_bind_int (check_stmt, 1, sqlite3_column_int (stmt, 16), "binding when checking message files"); + + status = sqlite3_step (check_stmt); + sqlite3_finalize (check_stmt); + + if (status != SQLITE_ROW) + continue; } + /* preview is not limitted to media messages */ if (sqlite3_column_text (stmt, 7)) { - file = g_new0 (ChattyFileInfo, 1); - file->file_name = g_strdup ((const char *)sqlite3_column_text (stmt, 6)); - file->url = g_strdup ((const char *)sqlite3_column_text (stmt, 7)); - file->path = g_strdup ((const char *)sqlite3_column_text (stmt, 8)); - file->mime_type = g_strdup ((const char *)sqlite3_column_text (stmt, 9)); - file->size = sqlite3_column_int (stmt, 10); - file->status = sqlite3_column_int (stmt, 11); - file->width = sqlite3_column_int (stmt, 12); - file->height = sqlite3_column_int (stmt, 13); - file->duration = sqlite3_column_int (stmt, 14); + preview = g_new0 (ChattyFileInfo, 1); + preview->file_name = g_strdup ((const char *)sqlite3_column_text (stmt, 6)); + preview->url = g_strdup ((const char *)sqlite3_column_text (stmt, 7)); + preview->path = g_strdup ((const char *)sqlite3_column_text (stmt, 8)); + preview->mime_type = g_strdup ((const char *)sqlite3_column_text (stmt, 9)); + preview->size = sqlite3_column_int (stmt, 10); + preview->status = sqlite3_column_int (stmt, 11); + preview->width = sqlite3_column_int (stmt, 12); + preview->height = sqlite3_column_int (stmt, 13); + preview->duration = sqlite3_column_int (stmt, 14); } - else - msg = (const char *)sqlite3_column_text (stmt, 2); if (!chatty_chat_is_im (chat) || CHATTY_IS_MA_CHAT (chat)) who = (const char *)sqlite3_column_text (stmt, 4); - status = sqlite3_column_int (stmt, 24); + status = sqlite3_column_int (stmt, 15); { g_autoptr(ChattyContact) contact = NULL; + GList *files = NULL; + int message_id; contact = g_object_new (CHATTY_TYPE_CONTACT, NULL); chatty_contact_set_name (contact, who); @@ -2036,9 +2249,12 @@ get_messages_before_time (ChattyHistory *self, message = chatty_message_new (CHATTY_ITEM (contact), msg, uid, time_stamp, type, history_direction_from_value (direction), history_msg_status_from_value (status)); + message_id = sqlite3_column_int (stmt, 16); + files = history_get_files (self, message_id); + chatty_message_set_files (message, files); } - chatty_message_set_files (message, g_list_append (NULL, file)); + chatty_message_set_subject (message, subject); chatty_message_set_preview (message, preview); g_ptr_array_insert (messages, 0, message); } @@ -2161,38 +2377,60 @@ add_file_info (ChattyHistory *self, file_id = sqlite3_last_insert_rowid (self->db); - if (file->mime_type && - ((file->width && file->height) || file->duration)) { - if (g_str_has_prefix (file->mime_type, "video/")) - sqlite3_prepare_v2 (self->db, - "INSERT INTO video(file_id,width,height,duration) " - "VALUES(?1,?2,?3,?4)", - -1, &stmt, NULL); - else if (g_str_has_prefix (file->mime_type, "image/")) - sqlite3_prepare_v2 (self->db, - "INSERT INTO image(file_id,width,height) " - "VALUES(?1,?2,?3)", - -1, &stmt, NULL); - else if (g_str_has_prefix (file->mime_type, "audio/")) - sqlite3_prepare_v2 (self->db, - "INSERT INTO audio(file_id,duration) " - "VALUES(?1,?4)", - -1, &stmt, NULL); - else - return file_id; - - history_bind_int (stmt, 1, file_id, "binding when adding media"); - if (file->width && !g_str_has_prefix (file->mime_type, "audio/")) - history_bind_int (stmt, 2, file->width, "binding when adding media"); - if (file->height && !g_str_has_prefix (file->mime_type, "audio/")) - history_bind_int (stmt, 3, file->height, "binding when adding media"); - if (file->duration && !g_str_has_prefix (file->mime_type, "image/")) - history_bind_int (stmt, 4, file->duration, "binding when adding media"); + if (!file->width && !file->height && !file->duration) + return file_id; + + sqlite3_prepare_v2 (self->db, + "INSERT INTO file_metadata(file_id,width,height,duration) " + "VALUES(?1,?2,?3,?4)", + -1, &stmt, NULL); + + history_bind_int (stmt, 1, file_id, "binding when adding media"); + + if (file->width) + history_bind_int (stmt, 2, file->width, "binding when adding media"); + if (file->height) + history_bind_int (stmt, 3, file->height, "binding when adding media"); + if (file->duration) + history_bind_int (stmt, 4, file->duration, "binding when adding media"); + + sqlite3_step (stmt); + sqlite3_finalize (stmt); + + return file_id; +} + +static void +history_add_files (ChattyHistory *self, + ChattyMessage *message, + int message_id) +{ + GList *files; + + if (!CHATTY_IS_MESSAGE (message) || !message_id) + return; + + files = chatty_message_get_files (message); + + for (GList *file = files; file; file = file->next) { + sqlite3_stmt *stmt; + int file_id; + + file_id = add_file_info (self, file->data); + + if (!file_id) + continue; + + sqlite3_prepare_v2 (self->db, + "INSERT OR IGNORE INTO message_files(message_id,file_id) " + "VALUES(?1,?2)", + -1, &stmt, NULL); + + history_bind_int (stmt, 1, message_id, "binding when adding message file"); + history_bind_int (stmt, 2, file_id, "binding when adding message file"); sqlite3_step (stmt); sqlite3_finalize (stmt); } - - return file_id; } static void @@ -2205,7 +2443,7 @@ history_add_message (ChattyHistory *self, const char *who, *uid, *msg, *alias; ChattyMsgDirection direction; ChattyMsgType type; - int thread_id = 0, sender_id = 0, file_id = 0, preview_id = 0; + int thread_id = 0, sender_id = 0, preview_id = 0; int status, dir; time_t time_stamp; @@ -2257,26 +2495,11 @@ history_add_message (ChattyHistory *self, sqlite3_finalize (stmt); } - if (type == CHATTY_MESSAGE_IMAGE || - type == CHATTY_MESSAGE_AUDIO || - type == CHATTY_MESSAGE_VIDEO || - type == CHATTY_MESSAGE_FILE) { - GList *files = NULL; - - files = chatty_message_get_files (message); - preview_id = add_file_info (self, chatty_message_get_preview (message)); - file_id = add_file_info (self, files ? files->data : NULL); - } - + preview_id = add_file_info (self, chatty_message_get_preview (message)); sqlite3_prepare_v2 (self->db, - "INSERT INTO messages(uid,thread_id,sender_id,body,body_type,direction,time,preview_id,encrypted,status) " - "VALUES(?1,?2,?3," - "CASE " - " WHEN ?5>="STRING (MESSAGE_TYPE_FILE) " AND ?5<="STRING (MESSAGE_TYPE_AUDIO) " " - " THEN ?8 " - " ELSE ?4 " - "END," - "?5,?6,?7,?9,?10,?11) " + "INSERT INTO messages(uid,thread_id,sender_id,body,body_type,direction,time,preview_id,encrypted,status,subject) " + "VALUES(?1,?2,?3,?4," + "?5,?6,?7,?9,?10,?11,?12) " "ON CONFLICT (uid,thread_id,body,time) DO UPDATE " "SET status=?11", -1, &stmt, NULL); @@ -2290,8 +2513,6 @@ history_add_message (ChattyHistory *self, "binding when adding message"); history_bind_int (stmt, 6, dir, "binding when adding message"); history_bind_int (stmt, 7, time_stamp, "binding when adding message"); - if (file_id) - history_bind_int (stmt, 8, file_id, "binding when adding message"); if (preview_id) history_bind_int (stmt, 9, preview_id, "binding when adding message"); history_bind_int (stmt, 10, chatty_message_get_encrypted (message), @@ -2299,11 +2520,24 @@ history_add_message (ChattyHistory *self, status = history_msg_status_to_value (chatty_message_get_status (message)); if (status != MESSAGE_STATUS_UNKNOWN) history_bind_int (stmt, 11, status, "binding when adding message"); + history_bind_text (stmt, 12, chatty_message_get_subject (message), "binding when adding message"); status = sqlite3_step (stmt); sqlite3_finalize (stmt); - if (status == SQLITE_DONE) + /* We can't use last_row_id as we may ignore the last insert */ + sqlite3_prepare_v2 (self->db, + "SELECT messages.id FROM messages " + "WHERE messages.uid=?;", + -1, &stmt, NULL); + history_bind_text (stmt, 1, uid, "binding when getting message id"); + status = sqlite3_step (stmt); + + if (status == SQLITE_ROW) + history_add_files (self, message, sqlite3_column_int (stmt, 0)); + sqlite3_finalize (stmt); + + if (status == SQLITE_DONE || status == SQLITE_ROW) g_task_return_boolean (task, TRUE); else g_task_return_new_error (task, diff --git a/src/chatty-list-row.c b/src/chatty-list-row.c index a3cf108..2a7fb0e 100644 --- a/src/chatty-list-row.c +++ b/src/chatty-list-row.c @@ -18,6 +18,7 @@ #include "chatty-purple.h" #include "chatty-contact.h" +#include "chatty-contact-list.h" #include "chatty-chat.h" #include "chatty-avatar.h" #include "chatty-list-row.h" @@ -39,7 +40,9 @@ struct _ChattyListRow GtkWidget *last_modified; GtkWidget *unread_message_count; GtkWidget *checkbox; + GtkWidget *close_button; GtkWidget *add_contact_button; + GtkWidget *call_button; ChattyItem *item; gboolean hide_chat_details; @@ -381,6 +384,24 @@ write_eds_contact_cb (GObject *object, } } +static void +chatty_list_row_delete_clicked_cb (ChattyListRow *self) +{ + GtkWidget *scrolled, *list; + + g_assert (CHATTY_IS_LIST_ROW (self)); + + /* We can't directly use CHATTY_TYPE_CONTACT_LIST as it's not linked with the shared library */ + scrolled = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_SCROLLED_WINDOW); + + if (!scrolled) + return; + + list = gtk_widget_get_parent (scrolled); + if (list) + g_signal_emit_by_name (list, "delete-row", self); +} + static void chatty_list_row_add_contact_clicked_cb (ChattyListRow *self) { @@ -394,6 +415,21 @@ chatty_list_row_add_contact_clicked_cb (ChattyListRow *self) g_object_ref (self)); } +static void +chatty_list_row_call_button_clicked_cb (ChattyListRow *self) +{ + g_autoptr(GError) error = NULL; + g_autofree char *uri = NULL; + + g_return_if_fail (CHATTY_IS_CONTACT (self->item)); + + uri = g_strconcat ("tel://", chatty_item_get_username (self->item), NULL); + + g_debug ("Calling uri: %s", uri); + if (!gtk_show_uri_on_window (NULL, uri, GDK_CURRENT_TIME, &error)) + g_warning ("Failed to launch call: %s", error->message); +} + static void chatty_list_row_finalize (GObject *object) { @@ -418,13 +454,17 @@ chatty_list_row_class_init (ChattyListRowClass *klass) "ui/chatty-list-row.ui"); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, avatar); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, checkbox); + gtk_widget_class_bind_template_child (widget_class, ChattyListRow, close_button); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, title); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, subtitle); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, last_modified); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, unread_message_count); gtk_widget_class_bind_template_child (widget_class, ChattyListRow, add_contact_button); + gtk_widget_class_bind_template_child (widget_class, ChattyListRow, call_button); + gtk_widget_class_bind_template_callback (widget_class, chatty_list_row_delete_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, chatty_list_row_add_contact_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, chatty_list_row_call_button_clicked_cb); } static void @@ -522,3 +562,32 @@ chatty_list_row_set_contact (ChattyListRow *self, gboolean enable) gtk_widget_set_visible (self->add_contact_button, enable); } + +void +chatty_list_row_set_call (ChattyListRow *self, gboolean enable) +{ + g_autoptr(GAppInfo) app_info = NULL; + + g_return_if_fail (CHATTY_IS_LIST_ROW (self)); + + app_info = g_app_info_get_default_for_uri_scheme ("tel"); + + if (app_info) { + gboolean user_valid; + user_valid = CHATTY_IS_CONTACT (self->item) && + chatty_utils_username_is_valid (chatty_item_get_username (self->item), + CHATTY_PROTOCOL_MMS_SMS); + + gtk_widget_set_visible (self->call_button, enable && user_valid); + } else + gtk_widget_hide (self->call_button); +} + +void +chatty_list_row_show_delete_button (ChattyListRow *self) +{ + g_return_if_fail (CHATTY_IS_LIST_ROW (self)); + + gtk_widget_show (self->close_button); + gtk_widget_hide (self->checkbox); +} diff --git a/src/chatty-list-row.h b/src/chatty-list-row.h index bb7e363..b826549 100644 --- a/src/chatty-list-row.h +++ b/src/chatty-list-row.h @@ -30,5 +30,8 @@ void chatty_list_row_set_selectable (ChattyListRow *self, gboolean enable void chatty_list_row_select (ChattyListRow *self, gboolean enable); void chatty_list_row_set_contact (ChattyListRow *self, gboolean enable); +void chatty_list_row_set_call (ChattyListRow *self, + gboolean enable); +void chatty_list_row_show_delete_button (ChattyListRow *self); G_END_DECLS diff --git a/src/chatty-manager.c b/src/chatty-manager.c index 8ed362c..3868ecb 100644 --- a/src/chatty-manager.c +++ b/src/chatty-manager.c @@ -701,34 +701,38 @@ chatty_manager_find_chat_with_name (ChattyManager *self, gboolean chatty_manager_set_uri (ChattyManager *self, - const char *uri) + const char *uri, + const char *name) { - ChattyChat *chat = NULL; - g_autofree char *who = NULL; + g_autoptr(ChattySmsUri) sms_uri = NULL; ChattyAccount *account; - const char *country_code; - g_auto(GStrv) recipients = NULL; - guint num; - - if (!uri || !*uri) - return FALSE; + ChattyChat *chat; account = chatty_manager_get_mm_account (self); + if (chatty_account_get_status (account) != CHATTY_CONNECTED) return FALSE; - country_code = chatty_settings_get_country_iso_code (chatty_settings_get_default ()); - recipients = g_strsplit (uri, ",", -1); - num = g_strv_length (recipients); - for (int i = 0; i < num; i++) { - who = chatty_utils_check_phonenumber (recipients[i], country_code); - if (!who) - return FALSE; + sms_uri = chatty_sms_uri_new (uri); + + if (!chatty_sms_uri_is_valid (sms_uri)) { + GtkApplication *app; + GtkWidget *dialog; + + app = GTK_APPLICATION (g_application_get_default ()); + dialog = gtk_message_dialog_new (gtk_application_get_active_window (app), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CLOSE, + _("“%s” is not a valid URI"), uri); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return FALSE; } - if (num == 1) - chat = chatty_mm_account_start_chat (CHATTY_MM_ACCOUNT (account), who); - else - chat = chatty_mm_account_start_chat (CHATTY_MM_ACCOUNT (account), uri); + + chat = chatty_mm_account_start_chat_with_uri (CHATTY_MM_ACCOUNT (account), sms_uri); + chatty_item_set_name (CHATTY_ITEM (chat), name); g_signal_emit (self, signals[OPEN_CHAT], 0, chat); diff --git a/src/chatty-manager.h b/src/chatty-manager.h index 3f8b777..47e690a 100644 --- a/src/chatty-manager.h +++ b/src/chatty-manager.h @@ -61,7 +61,8 @@ ChattyChat *chatty_manager_find_chat_with_name (ChattyManager *self, const char *chat_id); ChattyAccount *chatty_manager_get_mm_account (ChattyManager *self); gboolean chatty_manager_set_uri (ChattyManager *self, - const char *uri); + const char *uri, + const char *name); ChattyHistory *chatty_manager_get_history (ChattyManager *self); G_END_DECLS diff --git a/src/chatty-message.c b/src/chatty-message.c index 9ee9db3..3097d75 100644 --- a/src/chatty-message.c +++ b/src/chatty-message.c @@ -32,6 +32,7 @@ struct _ChattyMessage ChattyItem *user; char *user_name; + char *subject; char *message; char *uid; char *id; @@ -66,6 +67,7 @@ chatty_message_finalize (GObject *object) g_clear_object (&self->user); g_free (self->message); + g_free (self->subject); g_free (self->uid); g_free (self->user_name); g_free (self->id); @@ -131,6 +133,24 @@ chatty_message_new (ChattyItem *user, return self; } +const char * +chatty_message_get_subject (ChattyMessage *self) +{ + g_return_val_if_fail (CHATTY_IS_MESSAGE (self), NULL); + + return self->subject; +} + +void +chatty_message_set_subject (ChattyMessage *self, + const char *subject) +{ + g_return_if_fail (CHATTY_IS_MESSAGE (self)); + + g_free (self->subject); + self->subject = g_strdup (subject); +} + gboolean chatty_message_get_encrypted (ChattyMessage *self) { diff --git a/src/chatty-message.h b/src/chatty-message.h index f40141a..f7ce575 100644 --- a/src/chatty-message.h +++ b/src/chatty-message.h @@ -30,6 +30,10 @@ ChattyMessage *chatty_message_new (ChattyItem *user, ChattyMsgDirection direction, ChattyMsgStatus status); +const char *chatty_message_get_subject (ChattyMessage *self); +void chatty_message_set_subject (ChattyMessage *self, + const char *subject); + gboolean chatty_message_get_encrypted (ChattyMessage *self); void chatty_message_set_encrypted (ChattyMessage *self, gboolean is_encrypted); diff --git a/src/chatty-notification.c b/src/chatty-notification.c index b096cd9..db1e192 100644 --- a/src/chatty-notification.c +++ b/src/chatty-notification.c @@ -256,6 +256,13 @@ chatty_notification_show_message (ChattyNotification *self, g_notification_set_body (self->notification, "Audio File"); break; + case CHATTY_MESSAGE_MMS: + if (chatty_message_get_text (message) && *chatty_message_get_text (message)) + g_notification_set_body (self->notification, chatty_message_get_text (message)); + else + g_notification_set_body (self->notification, "MMS"); + break; + default: g_notification_set_body (self->notification, chatty_message_get_text (message)); break; diff --git a/src/chatty-text-item.c b/src/chatty-text-item.c index 065e692..1fddffb 100644 --- a/src/chatty-text-item.c +++ b/src/chatty-text-item.c @@ -86,25 +86,29 @@ find_url (const char *buffer, break; } - if (url) - *end = strchrnul (url, ' '); + if (url) { + size_t url_end; + + url_end = strcspn (url, " \n()[],\t\r"); + if (url_end) + *end = url + url_end; + else + *end = url + strlen (url); + } return url; } -static void -text_item_linkify_and_add (ChattyTextItem *self, - const char *message) +static char * +text_item_linkify (ChattyTextItem *self, + const char *message) { g_autoptr(GString) link_str = NULL; - g_autoptr(GString) str = NULL; + GString *str = NULL; char *start, *end, *url; - GtkLabel *label; - - label = GTK_LABEL (self->content_label); - if (!message) - message = ""; + if (!message || !*message) + return NULL; str = g_string_sized_new (256); link_str = g_string_sized_new (256); @@ -138,11 +142,7 @@ text_item_linkify_and_add (ChattyTextItem *self, g_string_append (str, escaped); } - /* The string is generated only if there is at least one url, hence set as markup */ - if (str->len) - gtk_label_set_markup (label, str->str); - else - gtk_label_set_text (label, message); + return g_string_free (str, FALSE); } static gchar * @@ -219,6 +219,7 @@ text_item_update_quotes (ChattyTextItem *self) static void text_item_update_message (ChattyTextItem *self) { + g_autoptr(GString) str = NULL; ChattySettings *settings; const char *text; @@ -227,40 +228,65 @@ text_item_update_message (ChattyTextItem *self) settings = chatty_settings_get_default (); text = chatty_message_get_text (self->message); + str = g_string_sized_new (256); - if (!text || !*text) { - g_autoptr(GString) files_str = NULL; + if (chatty_message_get_files (self->message)) { GList *files; - files_str = g_string_sized_new (256); files = chatty_message_get_files (self->message); for (GList *item = files; item; item = item->next) { ChattyFileInfo *file = item->data; + if (!file || !file->url) + continue; + /* file->path is the path to locally saved file */ if (file->path) { if (g_str_has_prefix (file->path, "file://")) - g_string_append (files_str, file->path); + g_string_append (str, file->path); + else if (self->protocol & (CHATTY_PROTOCOL_MMS_SMS | CHATTY_PROTOCOL_MMS)) + g_string_append_printf (str, "file://%s/%s/%s", g_get_user_data_dir (), "chatty", file->path); else - g_string_append_printf (files_str, "file://%s", file->path); + g_string_append_printf (str, "file://%s", file->path); } else { - g_string_append (files_str, file->url); + g_string_append (str, file->url); } if (item->next) - g_string_append_c (files_str, ' '); + g_string_append (str, "\n\n"); } + } - if (files_str->len) - text_item_linkify_and_add (self, files_str->str); - else - gtk_label_set_label (GTK_LABEL (self->content_label), ""); + if ((self->protocol == CHATTY_PROTOCOL_MATRIX && + chatty_settings_get_experimental_features (settings)) || + self->protocol & (CHATTY_PROTOCOL_MMS_SMS | CHATTY_PROTOCOL_MMS)) { + g_autofree char *content = NULL; + const char *subject; + + subject = chatty_message_get_subject (self->message); + + if (text && *text) { + if (str->len) + g_string_prepend (str, "\n\n"); + g_string_prepend (str, text); + + if (subject && *subject) + g_string_prepend (str, "\n\nMessage: "); + } + + if (subject && *subject) { + g_string_prepend (str, subject); + g_string_prepend (str, "Subject: "); + } - } else if ((self->protocol == CHATTY_PROTOCOL_MATRIX && - chatty_settings_get_experimental_features (settings)) || - self->protocol & (CHATTY_PROTOCOL_MMS_SMS | CHATTY_PROTOCOL_MMS)) { - text_item_linkify_and_add (self, text); + content = text_item_linkify (self, str->str); + + /* The string is generated only if there is at least one url, hence set as markup */ + if (content && *content) + gtk_label_set_markup (GTK_LABEL (self->content_label), content); + else + gtk_label_set_text (GTK_LABEL (self->content_label), str->str ?: ""); } else { /* This happens only for purple messages */ g_autofree char *message = NULL; diff --git a/src/chatty-utils.c b/src/chatty-utils.c index ab07b08..b409a00 100644 --- a/src/chatty-utils.c +++ b/src/chatty-utils.c @@ -496,7 +496,11 @@ chatty_file_info_new_for_path (const char *path) * https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types */ attachment->file_name = g_file_get_basename (file); - attachment->mime_type = g_content_type_get_mime_type (g_file_info_get_content_type (file_info)); + if (g_file_info_get_content_type (file_info) == NULL) + attachment->mime_type = g_strdup ("application/octet-stream"); + else + attachment->mime_type = g_content_type_get_mime_type (g_file_info_get_content_type (file_info)); + if (attachment->mime_type == NULL) { g_warning ("Could not get MIME type! Trying Content Type instead"); if (g_file_info_get_content_type (file_info) != NULL) { diff --git a/src/chatty-window.c b/src/chatty-window.c index a34e085..583e4ed 100644 --- a/src/chatty-window.c +++ b/src/chatty-window.c @@ -74,6 +74,7 @@ struct _ChattyWindow GtkWidget *delete_button; GtkWidget *chat_view; + GtkWidget *settings_dialog; GtkWidget *protocol_list; GtkWidget *protocol_any_row; @@ -140,7 +141,7 @@ chatty_window_open_item (ChattyWindow *self, const char *number; number = chatty_item_get_username (item); - chatty_window_set_uri (self, number); + chatty_window_set_uri (self, number, NULL); return; } @@ -268,77 +269,28 @@ notify_fold_cb (ChattyWindow *self) } static void -window_new_message_clicked_cb (ChattyWindow *self) +window_show_new_chat_dialog (ChattyWindow *self, + gboolean can_multi_select) { ChattyNewChatDialog *dialog; - ChattyItem *item; - const char *phone_number = NULL; - gint response; g_assert (CHATTY_IS_WINDOW (self)); dialog = CHATTY_NEW_CHAT_DIALOG (self->new_chat_dialog); - chatty_new_chat_dialog_set_multi_selection (dialog, FALSE); - - response = gtk_dialog_run (GTK_DIALOG (self->new_chat_dialog)); - gtk_widget_hide (self->new_chat_dialog); - - if (response != GTK_RESPONSE_OK) - return; - - item = chatty_new_chat_dialog_get_selected_item (dialog); - - if (CHATTY_IS_CONTACT (item) && - chatty_contact_is_dummy (CHATTY_CONTACT (item))) - phone_number = chatty_item_get_username (item); + chatty_new_chat_dialog_set_multi_selection (dialog, can_multi_select); + gtk_window_present (GTK_WINDOW (self->new_chat_dialog)); +} - if (phone_number) - chatty_window_set_uri (self, phone_number); - else if (item) - chatty_window_open_item (self, item); - else - g_return_if_reached (); +static void +window_new_message_clicked_cb (ChattyWindow *self) +{ + window_show_new_chat_dialog (self, FALSE); } static void window_new_sms_mms_message_clicked_cb (ChattyWindow *self) { - g_autoptr(GString) sendlist = g_string_new (NULL); - ChattyNewChatDialog *dialog; - GPtrArray *items; - gint response; - - g_assert (CHATTY_IS_WINDOW (self)); - - dialog = CHATTY_NEW_CHAT_DIALOG (self->new_chat_dialog); - chatty_new_chat_dialog_set_multi_selection (dialog, TRUE); - - response = gtk_dialog_run (GTK_DIALOG (self->new_chat_dialog)); - gtk_widget_hide (self->new_chat_dialog); - - if (response != GTK_RESPONSE_OK) - return; - - items = chatty_new_chat_dialog_get_selected_items (dialog); - - for (guint i = 0; i < items->len; i++) { - const char *phone_number; - ChattyItem *item; - - item = items->pdata[i]; - - if (CHATTY_IS_CONTACT (item)) { - phone_number = chatty_item_get_username (item); - sendlist = g_string_append (sendlist, phone_number); - g_string_append (sendlist, ","); - } - } - - /* Remove the trailing "," */ - if (sendlist->len >= 1) - g_string_truncate (sendlist, sendlist->len - 1); - - chatty_window_set_uri (self, sendlist->str); + window_show_new_chat_dialog (self, TRUE); } static void @@ -475,12 +427,11 @@ window_show_chat_info_clicked_cb (ChattyWindow *self) static void chatty_window_show_settings_dialog (ChattyWindow *self) { - GtkWidget *dialog; - g_assert (CHATTY_IS_WINDOW (self)); - dialog = chatty_settings_dialog_new (GTK_WINDOW (self)); - gtk_window_present (GTK_WINDOW (dialog)); + if (!self->settings_dialog) + self->settings_dialog = chatty_settings_dialog_new (GTK_WINDOW (self)); + gtk_window_present (GTK_WINDOW (self->settings_dialog)); } /* Copied from chatty-dialogs.c written by Andrea Schäfer */ @@ -615,6 +566,59 @@ protocol_list_header_func (GtkListBoxRow *row, } } +static void +new_chat_selection_changed_cb (ChattyWindow *self, + ChattyNewChatDialog *dialog) +{ + g_autoptr(GString) users = g_string_new (NULL); + GListModel *model; + guint n_items; + const char *name; + + g_assert (CHATTY_IS_WINDOW (self)); + g_assert (CHATTY_IS_NEW_CHAT_DIALOG (dialog)); + + model = chatty_new_chat_dialog_get_selected_items (dialog); + n_items = g_list_model_get_n_items (model); + + if (n_items == 0) + goto end; + + for (guint i = 0; i < n_items; i++) { + g_autoptr(ChattyItem) item = NULL; + const char *phone_number; + + item = g_list_model_get_item (model, i); + + if (CHATTY_IS_CONTACT (item)) { + phone_number = chatty_item_get_username (item); + g_string_append (users, phone_number); + g_string_append (users, ","); + } + } + + /* Remove the trailing "," */ + if (users->len >= 1) + g_string_truncate (users, users->len - 1); + + if (n_items == 1) { + g_autoptr(ChattyItem) item = NULL; + + item = g_list_model_get_item (model, 0); + + if (!CHATTY_IS_CONTACT (item) || + !chatty_contact_is_dummy (CHATTY_CONTACT (item))) { + chatty_window_open_item (self, item); + goto end; + } + } + + name = chatty_new_chat_dialog_get_chat_title (dialog); + chatty_window_set_uri (self, users->str, name); + + end: + gtk_widget_hide (GTK_WIDGET (dialog)); +} static void chatty_window_unmap (GtkWidget *widget) @@ -671,6 +675,10 @@ chatty_window_constructed (GObject *object) gtk_window_maximize (window); self->new_chat_dialog = chatty_new_chat_dialog_new (GTK_WINDOW (self)); + g_signal_connect_object (self->new_chat_dialog, "selection-changed", + G_CALLBACK (new_chat_selection_changed_cb), + self, + G_CONNECT_SWAPPED); self->chat_info_dialog = chatty_info_dialog_new (GTK_WINDOW (self)); G_OBJECT_CLASS (chatty_window_parent_class)->constructed (object); @@ -829,32 +837,10 @@ chatty_window_new (GtkApplication *application) void chatty_window_set_uri (ChattyWindow *self, - const char *uri) -{ - g_autofree char *who = NULL; - g_auto(GStrv) recipients = NULL; - guint num; - - recipients = g_strsplit (uri, ",", -1); - num = g_strv_length (recipients); - for (int i = 0; i < num; i++) { - who = chatty_utils_check_phonenumber (recipients[i], chatty_settings_get_country_iso_code (self->settings)); - if (!who) { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (self), - GTK_DIALOG_MODAL, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_CLOSE, - _("“%s” is not a valid phone number"), uri); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - - return; - } - } - - if (!chatty_manager_set_uri (self->manager, uri)) + const char *uri, + const char *name) +{ + if (!chatty_manager_set_uri (self->manager, uri, name)) return; gtk_widget_hide (self->new_chat_dialog); diff --git a/src/chatty-window.h b/src/chatty-window.h index 7420292..25122d7 100644 --- a/src/chatty-window.h +++ b/src/chatty-window.h @@ -20,7 +20,8 @@ G_DECLARE_FINAL_TYPE (ChattyWindow, chatty_window, CHATTY, WINDOW, HdyApplicatio GtkWidget *chatty_window_new (GtkApplication *application); void chatty_window_set_uri (ChattyWindow *self, - const char *uri); + const char *uri, + const char *name); ChattyChat *chatty_window_get_active_chat (ChattyWindow *self); void chatty_window_open_chat (ChattyWindow *self, ChattyChat *chat); diff --git a/src/chatty.gresource.xml b/src/chatty.gresource.xml index 1bf8b36..b9f8a8d 100644 --- a/src/chatty.gresource.xml +++ b/src/chatty.gresource.xml @@ -8,6 +8,7 @@ ui/chatty-list-row.ui ui/chatty-chat-list.ui ui/chatty-chat-view.ui + ui/chatty-contact-list.ui ui/chatty-contact-row.ui ui/chatty-file-item.ui ui/chatty-image-item.ui diff --git a/src/css/style.css b/src/css/style.css index 7668747..2fb6a34 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -18,7 +18,7 @@ border-color: @theme_selected_bg_color; } -.button_send_green { +.button_send_green:not(:disabled) { background: #6cba3d; border-color: #6cba3d; color: white; @@ -147,3 +147,8 @@ button.delete-button { min-height: 27px; min-width: 27px; } + +.no-margin, +.no-margin > scrolledwindow > viewport > clamp { + margin: 0; +} diff --git a/src/dialogs/chatty-mm-chat-info.c b/src/dialogs/chatty-mm-chat-info.c index e9b47b2..806ae61 100644 --- a/src/dialogs/chatty-mm-chat-info.c +++ b/src/dialogs/chatty-mm-chat-info.c @@ -82,6 +82,9 @@ chatty_mm_chat_info_set_item (ChattyChatInfo *info, gtk_container_foreach (GTK_CONTAINER (self->contacts_list_box), (GtkCallback)gtk_widget_destroy, NULL); + if (!chat) + return; + chatty_avatar_set_item (CHATTY_AVATAR (self->avatar), CHATTY_ITEM (chat)); if (chatty_chat_is_im (chat)) { @@ -104,6 +107,8 @@ chatty_mm_chat_info_set_item (ChattyChatInfo *info, contact = chatty_mm_buddy_get_contact (buddy); if (contact) { contact_row = chatty_list_row_new (CHATTY_ITEM (contact)); + chatty_list_row_set_call ((ChattyListRow *)contact_row, TRUE); + gtk_list_box_prepend (GTK_LIST_BOX (self->contacts_list_box), GTK_WIDGET (contact_row)); } else { @@ -118,6 +123,7 @@ chatty_mm_chat_info_set_item (ChattyChatInfo *info, contact_row = chatty_list_row_new (CHATTY_ITEM (new_contact)); chatty_list_row_set_contact ((ChattyListRow *)contact_row, TRUE); + chatty_list_row_set_call ((ChattyListRow *)contact_row, TRUE); /* We validate all multi-user chat users on creation. If there is * only one contact, it's possible that it's not a phone number, diff --git a/src/dialogs/chatty-new-chat-dialog.c b/src/dialogs/chatty-new-chat-dialog.c index c0dd950..2a5f3e9 100644 --- a/src/dialogs/chatty-new-chat-dialog.c +++ b/src/dialogs/chatty-new-chat-dialog.c @@ -20,10 +20,10 @@ #include "chatty-manager.h" #include "chatty-chat.h" #include "chatty-purple.h" -#include "chatty-contact.h" +#include "chatty-contact-list.h" +#include "chatty-list-row.h" #include "chatty-mm-account.h" #include "chatty-ma-account.h" -#include "chatty-list-row.h" #include "chatty-log.h" #include "chatty-utils.h" #include "chatty-new-chat-dialog.h" @@ -36,155 +36,71 @@ static void chatty_new_chat_name_check (ChattyNewChatDialog *self, GtkWidget *button); -#define ITEMS_COUNT 50 - struct _ChattyNewChatDialog { - GtkDialog parent_instance; + HdyWindow parent_instance; + + GtkWidget *header_bar; + GtkWidget *edit_contact_button; + GtkWidget *back_button; + GtkWidget *cancel_button; + GtkWidget *apply_button; + GtkWidget *progress_spinner; + + GtkWidget *group_title_entry; + GtkWidget *self_contact_row; + GtkWidget *selected_contact_list; + GtkWidget *add_more_row; - GtkWidget *chats_listbox; - GtkWidget *contacts_listbox; - GtkWidget *new_contact_row; + GtkWidget *contact_list; GtkWidget *contacts_search_entry; GtkWidget *contact_edit_grid; GtkWidget *new_chat_stack; GtkWidget *accounts_list; GtkWidget *contact_name_entry; GtkWidget *contact_alias_entry; - GtkWidget *back_button; - GtkWidget *add_contact_button; - GtkWidget *edit_contact_button; - GtkWidget *start_button; - GtkWidget *cancel_button; GtkWidget *add_in_contacts_button; - GtkWidget *dummy_prefix_radio; - GtkWidget *header_view_new_chat; - GtkWidget *contact_list_stack; + GtkWidget *main_stack; + GtkWidget *new_group_chat_view; GtkWidget *contact_list_view; - GtkWidget *empty_search_view; + GtkWidget *add_contact_view; - GtkSliceListModel *slice_model; - GtkFilter *filter; - char *search_str; + GtkWidget *dummy_prefix_radio; + ChattyItem *self_contact; ChattyAccount *selected_account; ChattyManager *manager; - ChattyProtocol active_protocols; - - GPtrArray *selected_items; - ChattyItem *selected_item; + GListStore *selection_list; - ChattyContact *dummy_contact; GCancellable *cancellable; gboolean multi_selection; }; -G_DEFINE_TYPE (ChattyNewChatDialog, chatty_new_chat_dialog, GTK_TYPE_DIALOG) - +G_DEFINE_TYPE (ChattyNewChatDialog, chatty_new_chat_dialog, HDY_TYPE_WINDOW) -static GtkWidget * -new_chat_contact_row_new (ChattyItem *item, - ChattyNewChatDialog *self) -{ - GtkWidget *row; - - row = chatty_list_contact_row_new (item); - chatty_list_row_set_selectable (CHATTY_LIST_ROW (row), self->multi_selection); +enum { + SELECTION_CHANGED, + N_SIGNALS +}; - return row; -} +static guint signals[N_SIGNALS]; static void -dialog_active_protocols_changed_cb (ChattyNewChatDialog *self) +start_button_clicked_cb (ChattyNewChatDialog *self) { - ChattyAccount *mm_account; - ChattyProtocol protocol; - gboolean valid; + GListModel *model; g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - self->active_protocols = chatty_manager_get_active_protocols (self->manager); - gtk_filter_changed (self->filter, GTK_FILTER_CHANGE_DIFFERENT); - - protocol = CHATTY_PROTOCOL_MMS_SMS; - valid = protocol == chatty_utils_username_is_valid (self->search_str, protocol); - mm_account = chatty_manager_get_mm_account (self->manager); - valid = valid && chatty_account_get_status (mm_account) == CHATTY_CONNECTED; - gtk_widget_set_visible (self->new_contact_row, valid); - - if (valid || g_list_model_get_n_items (G_LIST_MODEL (self->slice_model)) > 0) - gtk_stack_set_visible_child (GTK_STACK (self->contact_list_stack), self->contact_list_view); - else - gtk_stack_set_visible_child (GTK_STACK (self->contact_list_stack), self->empty_search_view); -} - -static gboolean -new_chat_dialog_contact_is_selected (ChattyContact *contact) -{ - g_return_val_if_fail (CHATTY_IS_CONTACT (contact), FALSE); - - return !!g_object_get_data (G_OBJECT (contact), "selected"); -} - -static gboolean -dialog_filter_item_cb (ChattyItem *item, - ChattyNewChatDialog *self) -{ - g_return_val_if_fail (CHATTY_IS_NEW_CHAT_DIALOG (self), FALSE); - - if (self->multi_selection) { - ChattyAccount *mm_account; - - mm_account = chatty_manager_get_mm_account (self->manager); - if (chatty_account_get_status (mm_account) == CHATTY_CONNECTED) { - if (chatty_item_matches (item, self->search_str, CHATTY_PROTOCOL_MMS_SMS, TRUE) && - !new_chat_dialog_contact_is_selected (CHATTY_CONTACT (item))) - return TRUE; - else - return FALSE; - } else - return FALSE; - } - -#ifdef PURPLE_ENABLED - if (CHATTY_IS_PP_BUDDY (item)) { - ChattyAccount *account; - - account = chatty_pp_buddy_get_account (CHATTY_PP_BUDDY (item)); - - if (chatty_account_get_status (account) != CHATTY_CONNECTED) - return FALSE; - } -#endif - - if (CHATTY_IS_CHAT (item)) { - ChattyAccount *account; - -#ifdef PURPLE_ENABLED - /* Hide chat if it's buddy chat as the buddy is shown separately */ - if (CHATTY_IS_PP_CHAT (item) && - chatty_pp_chat_get_purple_buddy (CHATTY_PP_CHAT (item))) - return FALSE; -#endif - - account = chatty_chat_get_account (CHATTY_CHAT (item)); - - if (!account || chatty_account_get_status (account) != CHATTY_CONNECTED) - return FALSE; - } - - return chatty_item_matches (item, self->search_str, self->active_protocols, TRUE); -} + model = G_LIST_MODEL (self->selection_list); -static void -start_button_clicked_cb (ChattyNewChatDialog *self) -{ - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); + if (g_list_model_get_n_items (model) < 1) + return; - gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK); + g_signal_emit (self, signals[SELECTION_CHANGED], 0); } static void @@ -192,18 +108,7 @@ cancel_button_clicked_cb (ChattyNewChatDialog *self) { g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CANCEL); -} - -static void -chatty_new_chat_dialog_update_selectable (GtkWidget *widget, - gpointer callback_data) -{ - ChattyNewChatDialog *self = callback_data; - - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - - chatty_list_row_set_selectable ((ChattyListRow *)widget, self->multi_selection); + gtk_widget_hide (GTK_WIDGET (self)); } void @@ -213,68 +118,83 @@ chatty_new_chat_dialog_set_multi_selection (ChattyNewChatDialog *self, g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); self->multi_selection = enable; - gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (self->header_view_new_chat), !enable); - - chatty_list_row_set_selectable (CHATTY_LIST_ROW (self->new_contact_row), enable); - gtk_container_foreach (GTK_CONTAINER (self->chats_listbox), - (GtkCallback)chatty_new_chat_dialog_update_selectable, self); + hdy_header_bar_set_show_close_button (HDY_HEADER_BAR (self->header_bar), !enable); + chatty_contact_list_can_multi_select (CHATTY_CONTACT_LIST (self->contact_list), enable); + gtk_widget_set_sensitive (self->apply_button, FALSE); if (enable) { - gtk_widget_show (self->start_button); - gtk_widget_show (self->contacts_listbox); - gtk_widget_show (self->cancel_button); - gtk_widget_hide (self->edit_contact_button); - gtk_widget_set_sensitive (self->start_button, FALSE); - } else { - gtk_widget_show (self->edit_contact_button); - gtk_widget_hide (self->contacts_listbox); - gtk_widget_hide (self->start_button); - gtk_widget_hide (self->cancel_button); + gtk_widget_set_sensitive (self->apply_button, FALSE); + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->new_group_chat_view); } } static void -new_chat_list_changed_cb (ChattyNewChatDialog *self) +back_button_clicked_cb (ChattyNewChatDialog *self) { - guint n_items; - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - n_items = g_list_model_get_n_items (G_LIST_MODEL (self->slice_model)); - - if (n_items > 0 || gtk_widget_get_visible (self->new_contact_row)) - gtk_stack_set_visible_child (GTK_STACK (self->contact_list_stack), self->contact_list_view); + if (self->multi_selection) + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->new_group_chat_view); else - gtk_stack_set_visible_child (GTK_STACK (self->contact_list_stack), self->empty_search_view); + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->contact_list_view); } + static void -chatty_new_chat_dialog_update_new_contact_row (ChattyNewChatDialog *self) +edit_contact_button_clicked_cb (ChattyNewChatDialog *self) { g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - self->dummy_contact = g_object_new (CHATTY_TYPE_CONTACT, NULL); - chatty_contact_set_name (self->dummy_contact, _("Send To")); - g_object_set_data (G_OBJECT (self->dummy_contact), "dummy", GINT_TO_POINTER (TRUE)); + chatty_new_chat_dialog_update (self); + + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->add_contact_view); } static void -back_button_clicked_cb (ChattyNewChatDialog *self) +new_chat_dialog_page_changed_cb (ChattyNewChatDialog *self) { + GtkWidget *visible_child; + g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - gtk_stack_set_visible_child_name (GTK_STACK (self->new_chat_stack), "view-new-chat"); -} + gtk_widget_hide (self->back_button); + gtk_widget_hide (self->cancel_button); + gtk_widget_hide (self->apply_button); + gtk_widget_hide (self->edit_contact_button); + gtk_widget_show (self->apply_button); + hdy_header_bar_set_show_close_button (HDY_HEADER_BAR (self->header_bar), FALSE); + visible_child = gtk_stack_get_visible_child (GTK_STACK (self->main_stack)); + + if (visible_child == self->contact_list_view) { + if (self->multi_selection) { + gtk_button_set_label (GTK_BUTTON (self->apply_button), _("Add")); + gtk_widget_show (self->back_button); + } else { + gtk_widget_hide (self->apply_button); + hdy_header_bar_set_show_close_button (HDY_HEADER_BAR (self->header_bar), TRUE); + gtk_widget_show (self->edit_contact_button); + } + } else if (visible_child == self->new_group_chat_view) { + gboolean can_create; + + gtk_button_set_label (GTK_BUTTON (self->apply_button), _("Create")); + gtk_widget_show (self->cancel_button); + + can_create = g_list_model_get_n_items (G_LIST_MODEL (self->selection_list)) > 0; + gtk_widget_set_sensitive (self->apply_button, can_create); + } else { + gtk_button_set_label (GTK_BUTTON (self->apply_button), _("Add Contact")); + gtk_widget_show (self->back_button); + } +} static void -edit_contact_button_clicked_cb (ChattyNewChatDialog *self) +add_more_contact_row_activated_cb (ChattyNewChatDialog *self) { g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - chatty_new_chat_dialog_update (self); - - gtk_stack_set_visible_child_name (GTK_STACK (self->new_chat_stack), "view-new-contact"); + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->contact_list_view); } static void @@ -292,7 +212,7 @@ open_contacts_finish_cb (GObject *object, chatty_eds_open_contacts_app_finish (chatty_eds, result, &error); gtk_widget_set_sensitive (self->add_in_contacts_button, TRUE); - gtk_stack_set_visible_child_name (GTK_STACK (self->new_chat_stack), "view-new-chat"); + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->contact_list_view); if (!error) return; @@ -321,299 +241,50 @@ add_in_contacts_button_clicked_cb (ChattyNewChatDialog *self) open_contacts_finish_cb, self); } - - static void -contact_stroll_edge_reached_cb (ChattyNewChatDialog *self, - GtkPositionType position) +contact_list_selection_changed_cb (ChattyNewChatDialog *self) { - const char *name; + GListModel *model; + guint n_items; g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - if (position != GTK_POS_BOTTOM) - return; - - name = gtk_stack_get_visible_child_name (GTK_STACK (self->new_chat_stack)); - - if (!g_str_equal (name, "view-new-chat")) - return; + model = G_LIST_MODEL (self->selection_list); + n_items = g_list_model_get_n_items (model); - gtk_slice_list_model_set_size (self->slice_model, - gtk_slice_list_model_get_size (self->slice_model) + ITEMS_COUNT); + if (self->multi_selection) { + gtk_widget_set_sensitive (self->apply_button, n_items > 0); + } else if (n_items > 0) { + g_signal_emit (self, signals[SELECTION_CHANGED], 0); + } } static void contact_search_entry_activated_cb (ChattyNewChatDialog *self) { - GtkListBox *box; - GtkWidget *row; - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - box = GTK_LIST_BOX (self->chats_listbox); - - if (gtk_widget_is_visible (self->new_contact_row)) - row = self->new_contact_row; + if (self->multi_selection) + start_button_clicked_cb (self); else - row = (GtkWidget *)gtk_list_box_get_row_at_index (box, 0); - - if (row) { - self->selected_item = chatty_list_row_get_item (CHATTY_LIST_ROW (row)); - - gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK); - } + contact_list_selection_changed_cb (self); } static void contact_search_entry_changed_cb (ChattyNewChatDialog *self, GtkEntry *entry) { - ChattyAccount *account; - g_autofree char *old_needle = NULL; const char *str; - GtkFilterChange change; - ChattyProtocol protocol; - gboolean valid; - guint len; g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); g_assert (GTK_IS_ENTRY (entry)); str = gtk_entry_get_text (entry); - if (!str) - str = ""; - - old_needle = self->search_str; - self->search_str = g_utf8_casefold (str, -1); - len = strlen (self->search_str); - - if (!old_needle) - old_needle = g_strdup (""); - - if (g_str_has_prefix (self->search_str, old_needle)) - change = GTK_FILTER_CHANGE_MORE_STRICT; - else if (g_str_has_prefix (old_needle, self->search_str)) - change = GTK_FILTER_CHANGE_LESS_STRICT; - else - change = GTK_FILTER_CHANGE_DIFFERENT; - - gtk_slice_list_model_set_size (self->slice_model, ITEMS_COUNT); - gtk_filter_changed (self->filter, change); - - chatty_contact_set_value (self->dummy_contact, self->search_str); - chatty_list_row_set_item (CHATTY_LIST_ROW (self->new_contact_row), - CHATTY_ITEM (self->dummy_contact)); - - protocol = CHATTY_PROTOCOL_MMS_SMS; - valid = protocol == chatty_utils_username_is_valid (self->search_str, protocol); - /* It is confusing for the dummy contact to disappear if the length is less than 3 */ - if (!valid && len < 3 && len > 0) { - guint end_len; - end_len = strspn (self->search_str, "0123456789"); - - if (end_len == len) - valid = TRUE; - } - account = chatty_manager_get_mm_account (self->manager); - valid = valid && chatty_account_get_status (account) == CHATTY_CONNECTED; - gtk_widget_set_visible (self->new_contact_row, valid); - - if (valid || g_list_model_get_n_items (G_LIST_MODEL (self->slice_model)) > 0) { - gtk_stack_set_visible_child (GTK_STACK (self->contact_list_stack), self->contact_list_view); - if (self->multi_selection) { - ChattyItem *selected_item; - const char *phone_number; - gboolean has_match = FALSE; - - selected_item = chatty_list_row_get_item (CHATTY_LIST_ROW (self->new_contact_row)); - phone_number = chatty_item_get_username (selected_item); - - /* Check if search string matches an item in the selected list */ - for (guint i = 0; i < self->selected_items->len; i++) { - const char *item_number = NULL; - ChattyItem *item; - - item = self->selected_items->pdata[i]; - if (item) - item_number = chatty_item_get_username (item); - - if (g_strcmp0 (item_number, phone_number) == 0) { - has_match = TRUE; - break; - } - } - - chatty_list_row_select (CHATTY_LIST_ROW (self->new_contact_row), has_match); - - gtk_container_foreach (GTK_CONTAINER (self->chats_listbox), - (GtkCallback)chatty_new_chat_dialog_update_selectable, - self); - } - } else - gtk_stack_set_visible_child (GTK_STACK (self->contact_list_stack), self->empty_search_view); -} - -static void -selected_contact_row_activated_cb (ChattyNewChatDialog *self, - ChattyListRow *row) -{ - const char *phone_number = NULL; - ChattyItem *selected_item; - - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - g_assert (CHATTY_IS_LIST_ROW (row)); - - selected_item = chatty_list_row_get_item (row); - phone_number = chatty_item_get_username (selected_item); - - for (guint i = 0; i < self->selected_items->len; i++) { - const char *item_number = NULL; - ChattyItem *item; - - item = self->selected_items->pdata[i]; - if (item) - item_number = chatty_item_get_username (item); - - if (g_strcmp0 (item_number, phone_number) == 0) { - CHATTY_DEBUG (phone_number, "Removing item from list:"); - g_ptr_array_remove_index (self->selected_items, i); - - if (!self->selected_items->len) - gtk_widget_set_sensitive (self->start_button, FALSE); - - break; - } - } - if (chatty_contact_is_dummy (CHATTY_CONTACT (selected_item))) { - ChattyItem *dummy_item; - const char *dummy_number; - - dummy_item = chatty_list_row_get_item (CHATTY_LIST_ROW (self->new_contact_row)); - dummy_number = chatty_item_get_username (dummy_item); - if (g_strcmp0 (dummy_number, phone_number) == 0) - chatty_list_row_select (CHATTY_LIST_ROW (self->new_contact_row), FALSE); - - } else { - g_autofree char *contacts_search_entry = NULL; - - contacts_search_entry = g_strdup(gtk_entry_get_text (GTK_ENTRY (self->contacts_search_entry))); - g_object_set_data (G_OBJECT (selected_item), "selected", GINT_TO_POINTER (FALSE)); - if (!*contacts_search_entry) - gtk_entry_set_text (GTK_ENTRY (self->contacts_search_entry), "reset"); - else - gtk_entry_set_text (GTK_ENTRY (self->contacts_search_entry), ""); - - contact_search_entry_changed_cb (self, GTK_ENTRY (self->contacts_search_entry)); - gtk_entry_set_text (GTK_ENTRY (self->contacts_search_entry), contacts_search_entry); - } - gtk_widget_destroy (GTK_WIDGET (row)); -} - -static void -contact_row_activated_cb (ChattyNewChatDialog *self, - ChattyListRow *row) -{ - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - g_assert (CHATTY_IS_LIST_ROW (row)); - - if (self->multi_selection) { - GtkListBoxRow *chats_listbox_row; - GtkWidget *new_row = NULL; - ChattyItem *selected_item; - const char *phone_number; - - selected_item = chatty_list_row_get_item (row); - phone_number = chatty_item_get_username (selected_item); - /* If there is a dummy contact, make sure it is not already selected */ - if (chatty_contact_is_dummy (CHATTY_CONTACT (selected_item))) { - guint i = 0; - - chatty_list_row_select (CHATTY_LIST_ROW (self->new_contact_row), TRUE); - chats_listbox_row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->contacts_listbox), 0); - while (chats_listbox_row != NULL) { - ChattyItem *item = chatty_list_row_get_item (CHATTY_LIST_ROW (chats_listbox_row)); - const char *item_number = chatty_item_get_username (item); - if (g_strcmp0 (item_number, phone_number) == 0) { - selected_contact_row_activated_cb (self, (CHATTY_LIST_ROW (chats_listbox_row))); - return; - } - i++; - chats_listbox_row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->contacts_listbox), i); - } - } - - CHATTY_DEBUG_MSG ("Adding %s to list", phone_number); - if (chatty_contact_is_dummy (CHATTY_CONTACT (selected_item))) { - ChattyContact *dummy_contact = NULL; - - dummy_contact = g_object_new (CHATTY_TYPE_CONTACT, NULL); - chatty_contact_set_name (dummy_contact, _("Unknown Contact")); - chatty_contact_set_value (dummy_contact, - gtk_entry_get_text (GTK_ENTRY (self->contacts_search_entry))); - g_object_set_data (G_OBJECT (dummy_contact), "dummy", GINT_TO_POINTER (TRUE)); - new_row = chatty_list_row_new (CHATTY_ITEM (dummy_contact)); - g_ptr_array_add (self->selected_items, dummy_contact); - } else { - ChattyItem *dummy_item; - const char *dummy_number; - - dummy_item = chatty_list_row_get_item (CHATTY_LIST_ROW (self->new_contact_row)); - dummy_number = chatty_item_get_username (dummy_item); - new_row = chatty_list_row_new (chatty_list_row_get_item (row)); - g_ptr_array_add (self->selected_items, g_object_ref (selected_item)); - - g_object_set_data (G_OBJECT (selected_item), "selected", GINT_TO_POINTER (TRUE)); - gtk_widget_hide (GTK_WIDGET (row)); - if (g_strcmp0 (dummy_number, phone_number) == 0) { - chatty_list_row_select (CHATTY_LIST_ROW (self->new_contact_row), TRUE); - } - } - - chatty_list_row_set_selectable (CHATTY_LIST_ROW (new_row), TRUE); - chatty_list_row_select (CHATTY_LIST_ROW (new_row), TRUE); - gtk_list_box_prepend (GTK_LIST_BOX (self->contacts_listbox), - GTK_WIDGET (new_row)); - gtk_widget_set_sensitive (self->start_button, TRUE); - } else { - self->selected_item = chatty_list_row_get_item (row); - - gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK); - } -} - -static void -add_contact_button_clicked_cb (ChattyNewChatDialog *self) -{ -#ifdef PURPLE_ENABLED - GPtrArray *buddies; - const char *who, *alias; - - g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); - - if (!gtk_widget_get_sensitive (self->add_contact_button)) - return; - - buddies = g_ptr_array_new_full (1, g_free); - - who = gtk_entry_get_text (GTK_ENTRY (self->contact_name_entry)); - alias = gtk_entry_get_text (GTK_ENTRY (self->contact_alias_entry)); - chatty_pp_account_add_buddy (CHATTY_PP_ACCOUNT (self->selected_account), who, alias); - - g_ptr_array_add (buddies, g_strdup (who)); - chatty_account_start_direct_chat_async (self->selected_account, buddies, NULL, NULL); -#endif - - gtk_widget_hide (GTK_WIDGET (self)); - - gtk_entry_set_text (GTK_ENTRY (self->contact_name_entry), ""); - gtk_entry_set_text (GTK_ENTRY (self->contact_alias_entry), ""); - - gtk_stack_set_visible_child_name (GTK_STACK (self->new_chat_stack), "view-new-chat"); + chatty_contact_list_set_filter (CHATTY_CONTACT_LIST (self->contact_list), + CHATTY_PROTOCOL_ANY, str ?: ""); } - static void contact_name_text_changed_cb (ChattyNewChatDialog *self) { @@ -621,7 +292,7 @@ contact_name_text_changed_cb (ChattyNewChatDialog *self) chatty_new_chat_name_check (self, GTK_ENTRY (self->contact_name_entry), - self->add_contact_button); + self->apply_button); } @@ -647,6 +318,50 @@ account_list_row_activated_cb (ChattyNewChatDialog *self, chatty_new_chat_set_edit_mode (self, TRUE); } +static void +new_chat_dialog_apply_button_clicked_cb (ChattyNewChatDialog *self) +{ + g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); + + if (gtk_stack_get_visible_child (GTK_STACK (self->main_stack)) == self->add_contact_view) { +#ifdef PURPLE_ENABLED + GPtrArray *buddies; + const char *who, *alias; + + g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); + + if (!gtk_widget_get_sensitive (self->apply_button)) + return; + + buddies = g_ptr_array_new_full (1, g_free); + + who = gtk_entry_get_text (GTK_ENTRY (self->contact_name_entry)); + alias = gtk_entry_get_text (GTK_ENTRY (self->contact_alias_entry)); + chatty_pp_account_add_buddy (CHATTY_PP_ACCOUNT (self->selected_account), who, alias); + + g_ptr_array_add (buddies, g_strdup (who)); + chatty_account_start_direct_chat_async (self->selected_account, buddies, NULL, NULL); +#endif + + gtk_widget_hide (GTK_WIDGET (self)); + } else if (gtk_stack_get_visible_child (GTK_STACK (self->main_stack)) == self->contact_list_view) { + GListModel *model; + + g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); + + model = G_LIST_MODEL (self->selection_list); + + if (g_list_model_get_n_items (model) == 0) + return; + + if (self->multi_selection) + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->new_group_chat_view); + else + g_signal_emit (self, signals[SELECTION_CHANGED], 0); + } else { + g_signal_emit (self, signals[SELECTION_CHANGED], 0); + } +} static void chatty_new_chat_name_check (ChattyNewChatDialog *self, @@ -680,11 +395,11 @@ chatty_new_chat_set_edit_mode (ChattyNewChatDialog *self, if (edit) { gtk_widget_show (GTK_WIDGET (self->contact_edit_grid)); - gtk_widget_show (GTK_WIDGET (self->add_contact_button)); + gtk_widget_show (GTK_WIDGET (self->apply_button)); gtk_widget_hide (GTK_WIDGET (self->add_in_contacts_button)); } else { gtk_widget_hide (GTK_WIDGET (self->contact_edit_grid)); - gtk_widget_hide (GTK_WIDGET (self->add_contact_button)); + gtk_widget_hide (GTK_WIDGET (self->apply_button)); gtk_widget_show (GTK_WIDGET (self->add_in_contacts_button)); } } @@ -733,8 +448,11 @@ chatty_new_chat_add_account_to_list (ChattyNewChatDialog *self, (gpointer)prefix_radio_button); hdy_action_row_add_prefix (row, GTK_WIDGET (prefix_radio_button )); - hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (row), - chatty_item_get_username (CHATTY_ITEM (account))); + if (CHATTY_IS_MM_ACCOUNT (account)) + hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (row), _("SMS")); + else + hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (row), + chatty_item_get_username (CHATTY_ITEM (account))); gtk_container_add (GTK_CONTAINER (self->accounts_list), GTK_WIDGET (row)); @@ -806,43 +524,33 @@ chatty_new_chat_dialog_update (ChattyNewChatDialog *self) } static void -chatty_new_chat_unset_items (gpointer data, - gpointer user_data) +new_chat_dialog_selected_contacts_changed_cb (ChattyNewChatDialog *self) { - g_object_set_data (data, "selected", GINT_TO_POINTER (FALSE)); + guint n_items; + + g_assert (CHATTY_IS_NEW_CHAT_DIALOG (self)); + + n_items = g_list_model_get_n_items (G_LIST_MODEL (self->selection_list)); + gtk_widget_set_visible (GTK_WIDGET (self->selected_contact_list), n_items > 0); + gtk_widget_set_sensitive (GTK_WIDGET (self->apply_button), n_items > 0); } static void chatty_new_chat_dialog_show (GtkWidget *widget) { ChattyNewChatDialog *self = (ChattyNewChatDialog *)widget; - const char *contacts_search_entry; g_return_if_fail (CHATTY_IS_NEW_CHAT_DIALOG (self)); - g_ptr_array_foreach (self->selected_items, - chatty_new_chat_unset_items, NULL); - g_ptr_array_set_size (self->selected_items, 0); - self->selected_items->pdata[0] = NULL; - - /* Re-filter so that selection changes are reverted */ - gtk_filter_changed (self->filter, GTK_FILTER_CHANGE_DIFFERENT); - chatty_list_row_select (CHATTY_LIST_ROW (self->new_contact_row), FALSE); - - gtk_widget_set_sensitive (self->start_button, FALSE); - - gtk_container_foreach (GTK_CONTAINER (self->contacts_listbox), - (GtkCallback)gtk_widget_destroy, NULL); - /* Reset selection list */ - self->selected_item = NULL; + g_list_store_remove_all (self->selection_list); - contacts_search_entry = gtk_entry_get_text (GTK_ENTRY (self->contacts_search_entry)); - if (!*contacts_search_entry) { - gtk_entry_set_text (GTK_ENTRY (self->contacts_search_entry), "reset"); - contact_search_entry_changed_cb (self, GTK_ENTRY (self->contacts_search_entry)); - } + gtk_widget_set_sensitive (self->apply_button, FALSE); gtk_entry_set_text (GTK_ENTRY (self->contacts_search_entry), ""); + gtk_stack_set_visible_child (GTK_STACK (self->main_stack), self->contact_list_view); + new_chat_dialog_page_changed_cb (self); + chatty_new_chat_dialog_set_multi_selection (self, self->multi_selection); + new_chat_dialog_selected_contacts_changed_cb (self); GTK_WIDGET_CLASS (chatty_new_chat_dialog_parent_class)->show (widget); } @@ -855,15 +563,8 @@ chatty_new_chat_dialog_dispose (GObject *object) if (self->cancellable) g_cancellable_cancel (self->cancellable); - if (self->selected_items) - g_ptr_array_foreach (self->selected_items, - chatty_new_chat_unset_items, NULL); - - g_clear_pointer (&self->selected_items, g_ptr_array_unref); g_clear_object (&self->cancellable); g_clear_object (&self->manager); - g_clear_object (&self->slice_model); - g_clear_object (&self->filter); G_OBJECT_CLASS (chatty_new_chat_dialog_parent_class)->dispose (object); } @@ -878,83 +579,82 @@ chatty_new_chat_dialog_class_init (ChattyNewChatDialogClass *klass) widget_class->show = chatty_new_chat_dialog_show; + signals [SELECTION_CHANGED] = + g_signal_new ("selection-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/Chatty/" "ui/chatty-dialog-new-chat.ui"); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, new_chat_stack); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, header_view_new_chat); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, header_bar); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, edit_contact_button); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, back_button); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, cancel_button); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, apply_button); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, progress_spinner); + + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, group_title_entry); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, self_contact_row); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, selected_contact_list); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, add_more_row); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contacts_search_entry); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, new_contact_row); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contacts_listbox); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, chats_listbox); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contact_list); gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contact_edit_grid); gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contact_name_entry); gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contact_alias_entry); gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, accounts_list); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, back_button); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, edit_contact_button); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, add_contact_button); gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, add_in_contacts_button); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, start_button); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, cancel_button); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contact_list_stack); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, main_stack); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, new_group_chat_view); gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, contact_list_view); - gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, empty_search_view); + gtk_widget_class_bind_template_child (widget_class, ChattyNewChatDialog, add_contact_view); - gtk_widget_class_bind_template_callback (widget_class, back_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, edit_contact_button_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, contact_stroll_edge_reached_cb); + gtk_widget_class_bind_template_callback (widget_class, back_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, cancel_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, new_chat_dialog_apply_button_clicked_cb); + + gtk_widget_class_bind_template_callback (widget_class, new_chat_dialog_page_changed_cb); + gtk_widget_class_bind_template_callback (widget_class, add_more_contact_row_activated_cb); gtk_widget_class_bind_template_callback (widget_class, contact_search_entry_activated_cb); gtk_widget_class_bind_template_callback (widget_class, contact_search_entry_changed_cb); - gtk_widget_class_bind_template_callback (widget_class, selected_contact_row_activated_cb); - gtk_widget_class_bind_template_callback (widget_class, contact_row_activated_cb); - gtk_widget_class_bind_template_callback (widget_class, add_contact_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, contact_list_selection_changed_cb); gtk_widget_class_bind_template_callback (widget_class, add_in_contacts_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, contact_name_text_changed_cb); gtk_widget_class_bind_template_callback (widget_class, account_list_row_activated_cb); - gtk_widget_class_bind_template_callback (widget_class, start_button_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, cancel_button_clicked_cb); } static void chatty_new_chat_dialog_init (ChattyNewChatDialog *self) { - g_autoptr(GtkFilterListModel) filter_model = NULL; - g_autoptr(GtkSortListModel) sort_model = NULL; - g_autoptr(GtkSorter) sorter = NULL; - gtk_widget_init_template (GTK_WIDGET (self)); self->cancellable = g_cancellable_new (); + self->self_contact = CHATTY_ITEM (chatty_contact_dummy_new (_("You"), "MMS")); + chatty_list_row_set_item (CHATTY_LIST_ROW (self->self_contact_row), self->self_contact); + + self->selection_list = g_list_store_new (CHATTY_TYPE_ITEM); + g_signal_connect_object (self->selection_list, "items-changed", + G_CALLBACK (new_chat_dialog_selected_contacts_changed_cb), + self, G_CONNECT_SWAPPED); + chatty_contact_list_set_selection_store (CHATTY_CONTACT_LIST (self->contact_list), + self->selection_list); + chatty_contact_list_show_selected_only (CHATTY_CONTACT_LIST (self->selected_contact_list)); + chatty_contact_list_set_selection_store (CHATTY_CONTACT_LIST (self->selected_contact_list), + self->selection_list); + chatty_contact_list_can_multi_select (CHATTY_CONTACT_LIST (self->selected_contact_list), TRUE); + self->multi_selection = FALSE; - self->selected_items = g_ptr_array_new_full (1, g_object_unref); self->dummy_prefix_radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (NULL)); self->manager = g_object_ref (chatty_manager_get_default ()); - - sorter = gtk_custom_sorter_new ((GCompareDataFunc)chatty_item_compare, NULL, NULL); - sort_model = gtk_sort_list_model_new (chatty_manager_get_contact_list (self->manager), sorter); - - self->filter = gtk_custom_filter_new ((GtkCustomFilterFunc)dialog_filter_item_cb, self, NULL); - filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), self->filter); - - self->slice_model = gtk_slice_list_model_new (G_LIST_MODEL (filter_model), 0, ITEMS_COUNT); - g_signal_connect_object (self->slice_model, "items-changed", - G_CALLBACK (new_chat_list_changed_cb), self, - G_CONNECT_SWAPPED); - gtk_list_box_bind_model (GTK_LIST_BOX (self->chats_listbox), - G_LIST_MODEL (self->slice_model), - (GtkListBoxCreateWidgetFunc)new_chat_contact_row_new, - g_object_ref (self), g_object_unref); - - g_signal_connect_object (self->manager, "notify::active-protocols", - G_CALLBACK (dialog_active_protocols_changed_cb), self, G_CONNECT_SWAPPED); - dialog_active_protocols_changed_cb (self); - - chatty_new_chat_dialog_update_new_contact_row (self); } @@ -965,23 +665,28 @@ chatty_new_chat_dialog_new (GtkWindow *parent_window) return g_object_new (CHATTY_TYPE_NEW_CHAT_DIALOG, "transient-for", parent_window, - "use-header-bar", 1, NULL); } - -ChattyItem * -chatty_new_chat_dialog_get_selected_item (ChattyNewChatDialog *self) +GListModel * +chatty_new_chat_dialog_get_selected_items (ChattyNewChatDialog *self) { g_return_val_if_fail (CHATTY_IS_NEW_CHAT_DIALOG (self), NULL); - return self->selected_item; + return G_LIST_MODEL (self->selection_list); } -GPtrArray * -chatty_new_chat_dialog_get_selected_items (ChattyNewChatDialog *self) +const char * +chatty_new_chat_dialog_get_chat_title (ChattyNewChatDialog *self) { + const char *group_title; + g_return_val_if_fail (CHATTY_IS_NEW_CHAT_DIALOG (self), NULL); - return self->selected_items; + group_title = gtk_entry_get_text (GTK_ENTRY (self->group_title_entry)); + + if (group_title && *group_title) + return group_title; + + return NULL; } diff --git a/src/dialogs/chatty-new-chat-dialog.h b/src/dialogs/chatty-new-chat-dialog.h index 3499a55..5fe5ced 100644 --- a/src/dialogs/chatty-new-chat-dialog.h +++ b/src/dialogs/chatty-new-chat-dialog.h @@ -19,9 +19,9 @@ G_DECLARE_FINAL_TYPE (ChattyNewChatDialog, chatty_new_chat_dialog, CHATTY, NEW_C GtkWidget *chatty_new_chat_dialog_new (GtkWindow *parent_window); void chatty_new_chat_set_edit_mode (ChattyNewChatDialog *self, gboolean edit); -ChattyItem *chatty_new_chat_dialog_get_selected_item (ChattyNewChatDialog *self); +GListModel *chatty_new_chat_dialog_get_selected_items (ChattyNewChatDialog *self); void chatty_new_chat_dialog_set_multi_selection (ChattyNewChatDialog *self, gboolean enable); -GPtrArray *chatty_new_chat_dialog_get_selected_items (ChattyNewChatDialog *self); +const char *chatty_new_chat_dialog_get_chat_title (ChattyNewChatDialog *self); G_END_DECLS diff --git a/src/matrix/chatty-ma-account.c b/src/matrix/chatty-ma-account.c index 23bb925..54cc9a6 100644 --- a/src/matrix/chatty-ma-account.c +++ b/src/matrix/chatty-ma-account.c @@ -1397,7 +1397,10 @@ chatty_ma_account_save_async (ChattyMaAccount *self, g_return_if_fail (CHATTY_IS_MA_ACCOUNT (self)); g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (*chatty_ma_account_get_login_username (self)); - g_return_if_fail (*chatty_account_get_password (CHATTY_ACCOUNT (self))); + + if (!*chatty_account_get_password (CHATTY_ACCOUNT (self))) + return; + g_return_if_fail (*chatty_ma_account_get_homeserver (self)); task = g_task_new (self, cancellable, callback, user_data); diff --git a/src/matrix/chatty-ma-chat.c b/src/matrix/chatty-ma-chat.c index 0c3e44a..e6bd91a 100644 --- a/src/matrix/chatty-ma-chat.c +++ b/src/matrix/chatty-ma-chat.c @@ -129,47 +129,14 @@ sort_message (gconstpointer a, static void chatty_mat_chat_update_name (ChattyMaChat *self) { - const char *name_a = NULL, *name_b = NULL; - guint n_items, count; - g_assert (CHATTY_IS_MA_CHAT (self)); - n_items = g_list_model_get_n_items (G_LIST_MODEL (self->buddy_list)); - - if (self->room_name || n_items == 0) + if (self->room_name) return; - count = n_items; - - for (guint i = 0; i < MIN (3, n_items); i++) { - g_autoptr(ChattyItem) buddy = NULL; - - buddy = g_list_model_get_item (G_LIST_MODEL (self->buddy_list), i); - - /* Don't add self to create room name */ - if (g_strcmp0 (chatty_item_get_username (buddy), chatty_item_get_username (CHATTY_ITEM (self))) == 0) { - count--; - continue; - } - - if (!name_a) - name_a = chatty_item_get_name (buddy); - else - name_b = chatty_item_get_name (buddy); - } - g_free (self->generated_name); - - if (count == 0) - self->generated_name = g_strdup (_("Empty room")); - else if (count == 1) - self->generated_name = g_strdup (name_a); - else if (count == 2) - self->generated_name = g_strdup_printf (_("%s and %s"), name_a, name_b); - else - self->generated_name = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%s and %u other", - "%s and %u others", count - 1), - name_a, count - 1); + self->generated_name = chatty_chat_generate_name (CHATTY_CHAT (self), + G_LIST_MODEL (self->buddy_list)); g_signal_emit_by_name (self, "avatar-changed"); chatty_history_update_chat (self->history_db, CHATTY_CHAT (self)); } diff --git a/src/matrix/matrix-api.c b/src/matrix/matrix-api.c index 203cb6f..62b1841 100644 --- a/src/matrix/matrix-api.c +++ b/src/matrix/matrix-api.c @@ -930,6 +930,11 @@ matrix_start_sync (MatrixApi *self) } } else if (!self->homeserver_verified) { matrix_verify_homeserver (self); + } else if (!self->password){ + g_autoptr(GError) error = NULL; + + error = g_error_new (MATRIX_ERROR, M_BAD_PASSWORD, "Empty password"); + self->callback (self->cb_object, self, MATRIX_PASSWORD_LOGIN, NULL, error); } else if (!self->access_token) { matrix_login (self); } else if (!self->filter_id){ @@ -1370,7 +1375,6 @@ matrix_api_start_sync (MatrixApi *self) g_return_if_fail (MATRIX_IS_API (self)); g_return_if_fail (self->callback); g_return_if_fail (self->login_username); - g_return_if_fail (self->password || self->access_token); if (self->is_sync && !self->sync_failed) return; diff --git a/src/matrix/matrix-db.c b/src/matrix/matrix-db.c index 3ffbc3d..d0e5731 100644 --- a/src/matrix/matrix-db.c +++ b/src/matrix/matrix-db.c @@ -739,11 +739,46 @@ matrix_db_worker (gpointer user_data) return NULL; } +static void +ma_finish_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + + g_task_propagate_boolean (G_TASK (result), &error); + + if (error) + g_warning ("Error: %s", error->message); + + g_task_return_boolean (G_TASK (user_data), !error); +} + +static void +matrix_db_close (MatrixDb *self) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (MATRIX_IS_DB (self)); + + if (!self->db) + return; + + task = g_task_new (NULL, NULL, NULL, NULL); + matrix_db_close_async (self, ma_finish_cb, task); + + /* Wait until the task is completed */ + while (!g_task_get_completed (task)) + g_main_context_iteration (NULL, TRUE); +} + static void matrix_db_dispose (GObject *object) { MatrixDb *self = (MatrixDb *)object; + matrix_db_close (self); + g_clear_pointer (&self->worker_thread, g_thread_unref); G_OBJECT_CLASS (matrix_db_parent_class)->dispose (object); diff --git a/src/meson.build b/src/meson.build index 4a91cce..05e8c9f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -69,7 +69,7 @@ ui_files = files ( # but works fine locally # 'ui/chatty-info-dialog.ui', # 'ui/chatty-dialog-join-muc.ui', - 'ui/chatty-dialog-new-chat.ui', + # 'ui/chatty-dialog-new-chat.ui', 'ui/chatty-fp-row.ui', 'ui/chatty-list-row.ui', 'ui/chatty-message-row.ui', @@ -88,6 +88,7 @@ chatty_sources += [ 'chatty-manager.c', 'chatty-application.c', 'chatty-chat-list.c', + 'chatty-contact-list.c', 'chatty-window.c', 'dialogs/chatty-info-dialog.c', 'dialogs/chatty-settings-dialog.c', diff --git a/src/mm/chatty-mm-account.c b/src/mm/chatty-mm-account.c index d76cd1f..be62794 100644 --- a/src/mm/chatty-mm-account.c +++ b/src/mm/chatty-mm-account.c @@ -394,7 +394,7 @@ chatty_mm_account_append_message (ChattyMmAccount *self, g_list_model_items_changed (G_LIST_MODEL (self->chat_list), position, 1, 1); } -void +gboolean chatty_mm_account_recieve_mms_cb (ChattyMmAccount *self, ChattyMessage *message, const char *sender, @@ -403,29 +403,45 @@ chatty_mm_account_recieve_mms_cb (ChattyMmAccount *self, ChattyChat *chat; g_autoptr(ChattyMmBuddy) senderbuddy = NULL; ChattyMsgDirection message_dir; - ChattyMessage *messagecheck; + ChattyMsgStatus msg_status; - chat = chatty_mm_account_start_chat (self, recipientlist); - g_return_if_fail (CHATTY_IS_MM_CHAT (chat)); + message_dir = chatty_message_get_msg_direction (message); + msg_status = chatty_message_get_status (message); /* - * Check to see if this message exists (e.g. draft MMS sent) + * MMS Messages from Chatty will always start our as a Draft, then will + * transition to sent, and if deliver reports is on, to delivered. + * Thus, if we get a sent message that is sent or delivered, it is already + * in the chat */ + if (message_dir == CHATTY_DIRECTION_OUT && + (msg_status == CHATTY_STATUS_SENT || msg_status == CHATTY_STATUS_DELIVERED)) { + ChattyMessage *messagecheck; - /* - * TODO: I think it would be nicer if I could have a - * chatty_mm_chat_find_message_with_uid (), then this will work if - * chatty is closed and then reopened. - */ - messagecheck = chatty_mm_chat_find_message_with_id (CHATTY_MM_CHAT (chat), - chatty_message_get_id(message)); - if (messagecheck != NULL) { - chatty_message_set_status (messagecheck, chatty_message_get_status (message), 0); - chatty_history_add_message (self->history_db, chat, message); - return; + chat = chatty_mm_account_find_chat (self, recipientlist); + + /* The chat was deleted before the update, so just delete the MMS */ + if (!chat) { + chatty_mmsd_delete_mms (self->mmsd, chatty_message_get_uid (message)); + return FALSE; + } + + messagecheck = chatty_mm_chat_find_message_with_uid (CHATTY_MM_CHAT (chat), + chatty_message_get_uid (message)); + if (messagecheck != NULL) { + chatty_message_set_status (messagecheck, chatty_message_get_status (message), 0); + chatty_history_add_message (self->history_db, chat, message); + } else { /* The MMS was deleted before the update, so just delete the MMS */ + chatty_mmsd_delete_mms (self->mmsd, chatty_message_get_uid (message)); + return FALSE; + } + + return TRUE; } - message_dir = chatty_message_get_msg_direction (message); + chat = chatty_mm_account_start_chat (self, recipientlist); + g_return_val_if_fail (CHATTY_IS_MM_CHAT (chat), FALSE); + if (message_dir == CHATTY_DIRECTION_IN) { GListModel *users; guint items; @@ -460,6 +476,8 @@ chatty_mm_account_recieve_mms_cb (ChattyMmAccount *self, chatty_message_set_user (message, CHATTY_ITEM (senderbuddy)); chatty_mm_account_append_message (self, message, chat); + + return TRUE; } static void @@ -987,7 +1005,7 @@ chatty_mm_account_get_protocols (ChattyItem *item) static const char * chatty_mm_account_get_username (ChattyItem *item) { - return "SMS"; + return "invalid-0000000000000000"; } static void @@ -1248,6 +1266,35 @@ chatty_mm_account_start_chat (ChattyMmAccount *self, return chat; } +ChattyChat * +chatty_mm_account_start_chat_with_uri (ChattyMmAccount *self, + ChattySmsUri *uri) +{ + ChattyChat *chat; + + g_return_val_if_fail (CHATTY_IS_MM_ACCOUNT (self), NULL); + g_return_val_if_fail (CHATTY_IS_SMS_URI (uri), NULL); + + chat = chatty_mm_account_find_chat (self, chatty_sms_uri_get_numbers_str (uri)); + if (!chat) { + GPtrArray *members; + + members = chatty_sms_uri_get_numbers (uri); + + if (members->len == 1) + chat = (ChattyChat *)chatty_mm_chat_new_with_uri (uri, CHATTY_PROTOCOL_MMS_SMS, TRUE); + else /* Only MMS has multiple recipients */ + chat = (ChattyChat *)chatty_mm_chat_new_with_uri (uri, CHATTY_PROTOCOL_MMS, FALSE); + + chatty_chat_set_data (chat, self, self->history_db); + chatty_mm_chat_set_eds (CHATTY_MM_CHAT (chat), self->chatty_eds); + + g_list_store_append (self->chat_list, chat); + g_object_unref (chat); + } + + return chat; +} void chatty_mm_account_delete_chat (ChattyMmAccount *self, ChattyChat *chat) diff --git a/src/mm/chatty-mm-account.h b/src/mm/chatty-mm-account.h index 1402c46..fc71c32 100644 --- a/src/mm/chatty-mm-account.h +++ b/src/mm/chatty-mm-account.h @@ -18,6 +18,7 @@ #include "chatty-mm-buddy.h" #include "chatty-account.h" #include "chatty-contact-provider.h" +#include "chatty-sms-uri.h" #include "chatty-enums.h" G_BEGIN_DECLS @@ -42,6 +43,8 @@ ChattyChat *chatty_mm_account_find_chat (ChattyMmAccount *sel const char *phone); ChattyChat *chatty_mm_account_start_chat (ChattyMmAccount *self, const char *phone); +ChattyChat *chatty_mm_account_start_chat_with_uri (ChattyMmAccount *self, + ChattySmsUri *uri); void chatty_mm_account_delete_chat (ChattyMmAccount *self, ChattyChat *chat); gboolean chatty_mm_account_has_mms_feature (ChattyMmAccount *self); @@ -56,7 +59,7 @@ void chatty_mm_account_send_message_async (ChattyMmAccount *sel gboolean chatty_mm_account_send_message_finish (ChattyMmAccount *self, GAsyncResult *result, GError **error); -void chatty_mm_account_recieve_mms_cb (ChattyMmAccount *self, +gboolean chatty_mm_account_recieve_mms_cb (ChattyMmAccount *self, ChattyMessage *message, const char *sender, const char *recipientlist); diff --git a/src/mm/chatty-mm-chat.c b/src/mm/chatty-mm-chat.c index cc5fd43..9da694e 100644 --- a/src/mm/chatty-mm-chat.c +++ b/src/mm/chatty-mm-chat.c @@ -38,6 +38,7 @@ struct _ChattyMmChat ChattyEds *chatty_eds; ChattyMmAccount *account; ChattyHistory *history_db; + ChattySmsUri *sms_uri; GListStore *chat_users; GListStore *message_store; /* A Queue of #GTask */ @@ -79,43 +80,29 @@ static void chatty_mm_chat_update_contact (ChattyMmChat *self) { guint n_items; - GString *title = NULL; g_assert (CHATTY_IS_MM_CHAT (self)); if (!self->chatty_eds) return; - title = g_string_new (NULL); n_items = g_list_model_get_n_items (G_LIST_MODEL (self->chat_users)); for (guint i = 0; i < n_items; i++) { g_autoptr(ChattyMmBuddy) buddy = NULL; ChattyContact *contact; - const char *phone, *name; + const char *phone; buddy = g_list_model_get_item (G_LIST_MODEL (self->chat_users), i); phone = chatty_mm_buddy_get_number (buddy); contact = chatty_eds_find_by_number (self->chatty_eds, phone); - if (contact) { + if (contact) chatty_mm_buddy_set_contact (buddy, contact); - name = chatty_item_get_name (CHATTY_ITEM (contact)); - } else { - name = phone; - } - - g_string_append (title, name); - /* TODO: Improve so that this is translatable */ - g_string_append (title, ", "); } - /* Delete the trailing ", " */ - if (title->len > 2) - g_string_truncate (title, title->len - 2); - - if (title->len && (!self->name || !*self->name || !self->has_custom_name || n_items == 1)) { + if (!self->name || !*self->name || !self->has_custom_name || n_items == 1) { g_free (self->name); - self->name = g_string_free (title, FALSE); + self->name = chatty_chat_generate_name (CHATTY_CHAT (self), G_LIST_MODEL (self->chat_users)); self->has_custom_name = FALSE; g_object_notify (G_OBJECT (self), "name"); @@ -495,7 +482,7 @@ chatty_mm_chat_set_name (ChattyItem *item, static const char * chatty_mm_chat_get_username (ChattyItem *item) { - return "SMS"; + return "invalid-0000000000000000"; } static ChattyProtocol @@ -537,6 +524,7 @@ chatty_mm_chat_finalize (GObject *object) g_clear_object (&self->history_db); g_clear_object (&self->chatty_eds); g_clear_object (&self->account); + g_clear_object (&self->sms_uri); g_object_unref (self->message_store); g_object_unref (self->chat_users); g_free (self->last_message); @@ -606,6 +594,32 @@ chatty_mm_chat_new (const char *name, return self; } +ChattyMmChat * +chatty_mm_chat_new_with_uri (ChattySmsUri *uri, + ChattyProtocol protocol, + gboolean is_im) +{ + ChattyMmChat *self; + GPtrArray *members; + + g_return_val_if_fail (CHATTY_IS_SMS_URI (uri), NULL); + + self = chatty_mm_chat_new (chatty_sms_uri_get_numbers_str (uri), + NULL, protocol, is_im); + self->sms_uri = g_object_ref (uri); + + members = chatty_sms_uri_get_numbers (uri); + + for (guint i = 0; i < members->len; i++) { + g_autoptr(ChattyMmBuddy) buddy = NULL; + + buddy = chatty_mm_buddy_new (members->pdata[i], NULL); + g_list_store_append (self->chat_users, buddy); + } + + return self; +} + gboolean chatty_mm_chat_has_custom_name (ChattyMmChat *self) { @@ -670,6 +684,32 @@ chatty_mm_chat_find_message_with_id (ChattyMmChat *self, return NULL; } +ChattyMessage * +chatty_mm_chat_find_message_with_uid (ChattyMmChat *self, + const char *uid) +{ + guint n_items; + + g_return_val_if_fail (CHATTY_IS_MM_CHAT (self), NULL); + g_return_val_if_fail (uid && *uid, NULL); + + n_items = g_list_model_get_n_items (G_LIST_MODEL (self->message_store)); + + /* Search from end, the item is more likely to be at the end */ + for (guint i = n_items; i > 0; i--) { + g_autoptr(ChattyMessage) message = NULL; + const char *message_uid; + + message = g_list_model_get_item (G_LIST_MODEL (self->message_store), i - 1); + message_uid = chatty_message_get_uid (message); + + if (g_str_equal (uid, message_uid)) + return message; + } + + return NULL; +} + ChattyMmBuddy * chatty_mm_chat_find_user (ChattyMmChat *self, const char *phone) diff --git a/src/mm/chatty-mm-chat.h b/src/mm/chatty-mm-chat.h index 0050f74..9bd70a3 100644 --- a/src/mm/chatty-mm-chat.h +++ b/src/mm/chatty-mm-chat.h @@ -16,6 +16,7 @@ #include "chatty-chat.h" #include "chatty-mm-buddy.h" #include "chatty-message.h" +#include "chatty-sms-uri.h" #include "chatty-contact-provider.h" #include "chatty-enums.h" @@ -29,6 +30,9 @@ ChattyMmChat *chatty_mm_chat_new (const char *name, const char *alias, ChattyProtocol protocol, gboolean is_im); +ChattyMmChat *chatty_mm_chat_new_with_uri (ChattySmsUri *uri, + ChattyProtocol protocol, + gboolean is_im); gboolean chatty_mm_chat_has_custom_name (ChattyMmChat *self); void chatty_mm_chat_set_eds (ChattyMmChat *self, ChattyEds *chatty_eds); @@ -40,6 +44,8 @@ void chatty_mm_chat_prepend_messages (ChattyMmChat *self, GPtrArray *messages); ChattyMessage *chatty_mm_chat_find_message_with_id (ChattyMmChat *self, const char *id); +ChattyMessage *chatty_mm_chat_find_message_with_uid (ChattyMmChat *self, + const char *uid); ChattyMmBuddy *chatty_mm_chat_find_user (ChattyMmChat *self, const char *phone); void chatty_mm_chat_add_user (ChattyMmChat *self, diff --git a/src/mm/chatty-mmsd.c b/src/mm/chatty-mmsd.c index f9ee14f..2ca5a1b 100644 --- a/src/mm/chatty-mmsd.c +++ b/src/mm/chatty-mmsd.c @@ -19,6 +19,7 @@ # include "config.h" #endif +#include #include "chatty-settings.h" #include "chatty-account.h" #include "chatty-mm-chat.h" @@ -105,7 +106,6 @@ struct _mms_payload { G_DEFINE_TYPE (ChattyMmsd, chatty_mmsd, G_TYPE_OBJECT) static void chatty_mmsd_process_mms (ChattyMmsd *self, mms_payload *payload); -static void chatty_mmsd_delete_mms (ChattyMmsd *self, char *objectpath); static void mms_payload_free (gpointer data) @@ -115,6 +115,12 @@ mms_payload_free (gpointer data) if (!payload) return; + if (payload->mmsd_message_proxy_watch_id != 0) { + g_debug ("Unsubscribing from MMS watch"); + g_dbus_connection_signal_unsubscribe (payload->self->connection, + payload->mmsd_message_proxy_watch_id); + } + g_free (payload->objectpath); g_free (payload->sender); g_free (payload->chat); @@ -135,8 +141,9 @@ mmsd_set_value (ChattyMmsd *self, if (g_variant_dict_lookup (dict, key, "s", &value)) *out = g_steal_pointer (&value); - if (*out == self->carrier_proxy || - *out == self->default_modem_number) + if ((*out == self->carrier_proxy || + *out == self->default_modem_number) && + ((g_strcmp0 (*out, "NULL") == 0) || !*out)) g_clear_pointer (&*out, g_free); g_debug ("%s is set to %s", key, *out); @@ -182,16 +189,22 @@ chatty_mmsd_get_message_proxy_cb (GObject *service, } } -static void +void chatty_mmsd_delete_mms (ChattyMmsd *self, - char *objectpath) + const char *uid) { + g_autofree char *objectpath = NULL; + if (g_str_has_prefix (uid, MMSD_MODEMMANAGER_PATH)) + objectpath = g_strdup (uid); + else + objectpath = g_strdup_printf ("%s/%s", MMSD_MODEMMANAGER_PATH, uid); + g_debug ("Deleting MMS with Object Path: %s", objectpath); - /* - * I see you thinking you can move this, DONT! the objectpath is unique - * based on the message. - */ + if (g_hash_table_lookup (self->mms_hash_table, objectpath) == NULL) { + g_debug ("MMS not found. Was it already deleted?"); + return; + } g_dbus_proxy_new (self->connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, @@ -203,6 +216,7 @@ chatty_mmsd_delete_mms (ChattyMmsd *self, chatty_mmsd_get_message_proxy_cb, self); + g_hash_table_remove (self->mms_hash_table, objectpath); } static void @@ -277,10 +291,13 @@ chatty_mmsd_process_mms (ChattyMmsd *self, recipientlist = g_strdup (payload->chat); g_return_if_fail (recipientlist && *recipientlist); - chatty_mm_account_recieve_mms_cb (self->mm_account, - message, - sender, - recipientlist); + if (!chatty_mm_account_recieve_mms_cb (self->mm_account, + message, + sender, + recipientlist)) { + g_debug ("Message was deleted!"); + return; + } /* * Message is still a draft in mmsd and hasn't been sent. @@ -307,13 +324,7 @@ chatty_mmsd_process_mms (ChattyMmsd *self, } } else { g_debug ("MMS is finished sending/delivering/receiving. Deleting...."); - if (payload->mmsd_message_proxy_watch_id != 0) { - g_debug ("Unsubscribing from MMS watch"); - g_dbus_connection_signal_unsubscribe (self->connection, - payload->mmsd_message_proxy_watch_id); - } chatty_mmsd_delete_mms (self, payload->objectpath); - g_hash_table_remove (self->mms_hash_table, payload->objectpath); } } @@ -642,119 +653,77 @@ chatty_mmsd_send_mms_async (ChattyMmsd *self, * all attachments along with the Message and Subject. */ static char * -chatty_mmsd_process_mms_message_attachments (GList *files, char *subject) +chatty_mmsd_process_mms_message_attachments (GList **filesp) { GString *message_contents; - GFile *text_file = NULL; - gboolean first_attachment = FALSE; + gboolean content_set = FALSE; message_contents = g_string_new (NULL); - for (GList *l = files; l != NULL; l = l->next) { + + for (GList *l = *filesp; l != NULL;) { ChattyFileInfo *attachment = l->data; + l = l->next; if (g_strcmp0(attachment->mime_type, "application/smil") == 0) { - continue; - } - - if (g_str_match_string ("text/plain", attachment->mime_type, TRUE)) { - /* If an MMS has a message, it tends to be the first text/plain attachment */ - if (text_file == NULL) { + *filesp = g_list_remove (*filesp, attachment); + if (attachment->url) { + g_autoptr(GFile) file = NULL; g_autoptr(GError) error = NULL; - char *contents; - gsize length; - - text_file = g_file_new_build_filename (g_get_user_data_dir (), - "chatty", attachment->path, NULL); - g_file_load_contents (text_file, - NULL, - &contents, - &length, - NULL, - &error); - message_contents = g_string_prepend (message_contents, "\n\n"); - message_contents = g_string_prepend (message_contents, contents); - if (subject != NULL) { - message_contents = g_string_prepend (message_contents, "Message: "); - } - g_object_unref (text_file); - } else { - g_debug ("Already found text file, skipping...."); - if (first_attachment) - message_contents = g_string_append (message_contents, "\n\n"); - else - first_attachment = TRUE; - message_contents = g_string_append (message_contents, attachment->url); + file = g_file_new_for_uri (attachment->url); + g_file_delete (file, NULL, &error); + + if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + g_warning ("Deleting file failed: %s", error->message); } - } else { - if (first_attachment) - message_contents = g_string_append (message_contents, "\n\n"); - else - first_attachment = TRUE; + chatty_file_info_free (attachment); - message_contents = g_string_append (message_contents, attachment->url); + continue; } - } - if (subject != NULL) { - message_contents = g_string_prepend (message_contents, "\n\n"); - message_contents = g_string_prepend (message_contents, subject); - message_contents = g_string_prepend (message_contents, "Subject: "); - } + /* If an MMS has a message, it tends to be the first text/plain attachment */ + if (!content_set && g_str_match_string ("text/plain", attachment->mime_type, TRUE)) { + g_autoptr(GFile) text_file = NULL; + g_autofree char *contents = NULL; + g_autoptr(GError) error = NULL; + gsize length; - return g_string_free (message_contents, FALSE); -} + text_file = g_file_new_build_filename (g_get_user_data_dir (), + "chatty", attachment->path, NULL); + g_file_load_contents (text_file, + NULL, + &contents, + &length, + NULL, + &error); + if (error) { + g_warning ("error opening file: %s", error->message); + break; + } -static char * -chatty_mmsd_process_mms_message_text (GList *files, char *subject) -{ - GString *message_contents; - GFile *text_file = NULL; + if (contents && *contents) + g_string_append (message_contents, contents); + content_set = TRUE; - message_contents = g_string_new (NULL); - for (GList *l = files; l != NULL; l = l->next) { - ChattyFileInfo *attachment = l->data; + /* We don't want the message content to be saved as a file */ + *filesp = g_list_remove (*filesp, attachment); + if (attachment->url) { + g_autoptr(GFile) file = NULL; - if (g_strcmp0(attachment->mime_type, "application/smil") == 0) { - continue; - } + file = g_file_new_for_uri (attachment->url); + g_file_delete (file, NULL, &error); - if (g_str_match_string ("text/plain", attachment->mime_type, TRUE)) { - /* If an MMS has a message, it tends to be the first text/plain attachment */ - if (text_file == NULL) { - g_autoptr(GError) error = NULL; - char *contents; - gsize length; - - g_debug ("Found Text file!"); - text_file = g_file_new_build_filename (g_get_user_data_dir (), - "chatty", attachment->path, NULL); - g_file_load_contents (text_file, - NULL, - &contents, - &length, - NULL, - &error); - message_contents = g_string_prepend (message_contents, contents); - if (subject != NULL) { - message_contents = g_string_prepend (message_contents, "Message: "); - } - g_object_unref (text_file); - } else { - g_debug ("Already found text file, skipping...."); + if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + g_warning ("Deleting file failed: %s", error->message); } + chatty_file_info_free (attachment); } } - if (subject != NULL) { - message_contents = g_string_prepend (message_contents, "\n\n"); - message_contents = g_string_prepend (message_contents, subject); - message_contents = g_string_prepend (message_contents, "Subject: "); - } - - g_debug ("MMS Message: %s", message_contents->str); + if (message_contents->len) + return g_string_free (message_contents, FALSE); - return g_string_free (message_contents, FALSE); + return NULL; } static mms_payload * @@ -769,6 +738,7 @@ chatty_mmsd_receive_message (ChattyMmsd *self, ChattyMsgStatus mms_status = CHATTY_STATUS_UNKNOWN; ChattyMsgType chatty_msg_type = CHATTY_MESSAGE_TEXT; g_autoptr(GVariant) properties = NULL; + g_autoptr(GFileInfo) attachment_info = NULL; GVariant *reciever, *attach; GVariantDict dict; GVariantIter iter; @@ -784,12 +754,12 @@ chatty_mmsd_receive_message (ChattyMmsd *self, g_autofree char *rx_modem_number = NULL; g_autofree char *mms_message = NULL; g_autofree char *contents = NULL; + g_autofree char *expire_time_string = NULL; GString *who; GVariantIter recipientiter; mms_payload *payload; gint64 unix_time = 0; int delivery_report = FALSE; - guint num_files; parent = g_file_new_build_filename (g_get_user_data_dir (), "chatty", NULL); @@ -810,9 +780,9 @@ chatty_mmsd_receive_message (ChattyMmsd *self, /* Android seems to put this on the subject */ if (g_strcmp0 ("NoSubject", subject) == 0) - subject = NULL; - else if (strlen (subject) < 1) - subject = NULL; + g_clear_pointer (&subject, g_free); + else if (subject && !*subject) + g_clear_pointer (&subject, g_free); /* Determine what type of MMS we have */ if (g_strcmp0 (status, "draft") == 0) { @@ -838,6 +808,22 @@ chatty_mmsd_receive_message (ChattyMmsd *self, */ direction = CHATTY_DIRECTION_IN; mms_status = CHATTY_STATUS_RECIEVED; + } else if (g_strcmp0 (status, "expired") == 0) { + g_autoptr(GDateTime) expire_time = NULL; + g_autofree char *expire_date = NULL; + direction = CHATTY_DIRECTION_IN; + mms_status = CHATTY_STATUS_RECIEVED; + + g_variant_dict_lookup (&dict, "Expire", "s", &expire_date); + + expire_time = g_date_time_new_from_iso8601 (expire_date, NULL); + if (!expire_time) + expire_time = g_date_time_new_now_local (); + + /* TRANSLATORS: Timestamp for minute accuracy, e.g. “2020-08-11 15:27”. + See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format + */ + expire_time_string = g_date_time_format (expire_time, _("%Y-%m-%d %H:%M")); } else { /* This is a state Chatty cannot support yet */ return NULL; @@ -885,8 +871,10 @@ chatty_mmsd_receive_message (ChattyMmsd *self, } else { who = g_string_new (NULL); } - g_variant_iter_init (&recipientiter, recipients); - while ((reciever = g_variant_iter_next_value (&recipientiter))) { + if (recipients) + g_variant_iter_init (&recipientiter, recipients); + + while (recipients && (reciever = g_variant_iter_next_value (&recipientiter))) { g_autofree char *temp = NULL; g_autofree char *temp2 = NULL; const char *country_code = chatty_settings_get_country_iso_code (chatty_settings_get_default ()); @@ -910,9 +898,10 @@ chatty_mmsd_receive_message (ChattyMmsd *self, /* Go through the attachments */ attachments = g_variant_dict_lookup_value (&dict, "Attachments", G_VARIANT_TYPE_ARRAY); - g_variant_iter_init (&iter, attachments); + if (attachments) + g_variant_iter_init (&iter, attachments); - while ((attach = g_variant_iter_next_value (&iter))) { + while (attachments && (attach = g_variant_iter_next_value (&iter))) { ChattyFileInfo *attachment = NULL; GFile *new; GFileOutputStream *out; @@ -934,7 +923,9 @@ chatty_mmsd_receive_message (ChattyMmsd *self, if (!container) { g_autofree char *tag = NULL; + g_autofree char *uid = NULL; + uid = g_path_get_basename (objectpath); container = g_file_new_for_path (containerpath); g_file_load_contents (container, NULL, @@ -946,14 +937,13 @@ chatty_mmsd_receive_message (ChattyMmsd *self, if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_debug ("MMS Payload does not exist, deleting..."); chatty_mmsd_delete_mms (self, payload->objectpath); - g_hash_table_remove (self->mms_hash_table, payload->objectpath); return NULL; } else if (error) { g_warning ("Error loading MMSD Payload: %s", error->message); return NULL; } - tag = g_strconcat (date, payload->sender, NULL); + tag = g_strconcat (date, payload->sender, uid, NULL); /* Save MMS in $XDG_DATA_HOME/chatty/mms/ */ savepath = g_file_new_build_filename (g_get_user_data_dir (), "chatty", "mms", tag, NULL); @@ -972,9 +962,21 @@ chatty_mmsd_receive_message (ChattyMmsd *self, new = g_file_get_child (savepath, "mms.smil"); out = g_file_create (new, G_FILE_CREATE_PRIVATE, NULL, &error); - if (out == NULL) { + if (error) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { + g_autoptr(GFileInfo) file_info = NULL; g_debug ("%s Exists, Skipping Error....", g_file_peek_path (new)); + g_clear_error (&error); + file_info = g_file_query_info (new, + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + if (error) + g_warning ("Error getting file info: %s", error->message); + else + written = g_file_info_get_size (file_info); + } else { g_warning ("Failed to create %s: %s", g_file_peek_path (new), error->message); @@ -990,20 +992,21 @@ chatty_mmsd_receive_message (ChattyMmsd *self, g_warning ("Failed to write to file %s: %s", g_file_peek_path (new), error->message); g_clear_error (&error); - } else { - attachment->file_name = g_strdup ("mms.smil"); - attachment->mime_type = g_strdup ("application/smil"); - attachment->size = written; - attachment->path = g_file_get_relative_path (parent, new); - attachment->url = g_file_get_uri (new); - attachment->status = CHATTY_FILE_DOWNLOADED; - - - files = g_list_append (files, attachment); - attachment = NULL; - attachment = g_try_new0 (ChattyFileInfo, 1); } } + if (out) + g_output_stream_close (G_OUTPUT_STREAM (out), NULL, NULL); + + attachment->file_name = g_strdup ("mms.smil"); + attachment->mime_type = g_strdup ("application/smil"); + attachment->size = written; + attachment->path = g_file_get_relative_path (parent, new); + attachment->url = g_file_get_uri (new); + attachment->status = CHATTY_FILE_DOWNLOADED; + + files = g_list_append (files, attachment); + attachment = NULL; + attachment = g_try_new0 (ChattyFileInfo, 1); } } filename = g_strdup (filenode); @@ -1014,8 +1017,18 @@ chatty_mmsd_receive_message (ChattyMmsd *self, out = g_file_create (new, G_FILE_CREATE_PRIVATE, NULL, &error); if (error) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { - g_debug ("%s Exists, Skipping Error....", - g_file_peek_path (new)); + g_autoptr(GFileInfo) file_info = NULL; + g_debug ("%s Exists, Skipping Error....", g_file_peek_path (new)); + g_clear_error (&error); + file_info = g_file_query_info (new, + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + if (error) + g_warning ("Error getting file info: %s", error->message); + else + written = g_file_info_get_size (file_info); } else { g_warning ("Failed to create %s: %s", g_file_peek_path (new), error->message); @@ -1033,10 +1046,32 @@ chatty_mmsd_receive_message (ChattyMmsd *self, g_clear_error (&error); } } - g_output_stream_close (G_OUTPUT_STREAM (out), NULL, NULL); + if (out) + g_output_stream_close (G_OUTPUT_STREAM (out), NULL, NULL); + + attachment_info = g_file_query_info (new, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + + if (error != NULL) { + g_clear_error (&error); + attachment->mime_type = g_strdup (mimetype); + } else if (g_file_info_get_content_type (attachment_info) == NULL) { + /* If we can't figure out content type, do not trust what the MMS tells it is */ + attachment->mime_type = g_strdup ("application/octet-stream"); + } else { + attachment->mime_type = g_content_type_get_mime_type (g_file_info_get_content_type (attachment_info)); + if (attachment->mime_type == NULL) { + if (g_file_info_get_content_type (attachment_info) != NULL) + attachment->mime_type = g_strdup (g_file_info_get_content_type (attachment_info)); + else + attachment->mime_type = g_strdup ("application/octet-stream"); + } + } attachment->file_name = g_strdup (filename); - attachment->mime_type = g_strdup (mimetype); attachment->size = written; attachment->path = g_file_get_relative_path (parent, new); attachment->url = g_file_get_uri (new); @@ -1045,49 +1080,34 @@ chatty_mmsd_receive_message (ChattyMmsd *self, files = g_list_prepend (files, attachment); attachment = NULL; } - g_object_unref (container); + if (attachments) + g_object_unref (container); - num_files = g_list_length (files); + mms_message = chatty_mmsd_process_mms_message_attachments (&files); - if (num_files == 2) { - GList *l = files->next; - ChattyFileInfo *smil_file = l->data; - /* - * If there is only one file and SMIL, there is no reason to keep the SMIL - * treat it just like there is only one attachment - */ - if (g_strcmp0(smil_file->mime_type, "application/smil") == 0) { - files = g_list_delete_link (files, l); - num_files = g_list_length (files); - chatty_file_info_free (smil_file); - } + if ((!files || !files->data) && savepath) { + g_autoptr(GError) error = NULL; + + g_file_delete (savepath, NULL, &error); + + if (error) + g_warning ("Error deleting empty MMS directory: %s", error->message); } - if (num_files == 1) { + if (!subject && !mms_message && files && g_list_length (files) == 1) { ChattyFileInfo *attachment = files->data; - if (g_str_has_prefix (attachment->mime_type, "image")) { + + if (attachment && attachment->mime_type && + g_str_has_prefix (attachment->mime_type, "image")) chatty_msg_type = CHATTY_MESSAGE_IMAGE; - } else if (g_str_has_prefix (attachment->mime_type, "video")) { - /* TODO: Support for inline video */ - //chatty_msg_type = CHATTY_MESSAGE_VIDEO; - mms_message = chatty_mmsd_process_mms_message_attachments (files, subject); - } else if (g_str_has_prefix (attachment->mime_type, "audio")) { - /* TODO: Support for inline audio */ - //chatty_msg_type = CHATTY_MESSAGE_AUDIO; - mms_message = chatty_mmsd_process_mms_message_attachments (files, subject); - } else if (g_str_match_string ("text/plain", attachment->mime_type, TRUE)) { - mms_message = chatty_mmsd_process_mms_message_text (files, subject); - } else { - /* TODO: Support for inline file */ - //chatty_msg_type = CHATTY_MESSAGE_FILE; - mms_message = chatty_mmsd_process_mms_message_attachments (files, subject); - } - } else { - /* - * TODO: Support for inline multiple attachments. There may not necessarily - * be SMIL to depend on for formatting. - */ - mms_message = chatty_mmsd_process_mms_message_attachments (files, subject); + } + + if (!mms_message && !files) { + if (g_strcmp0 (status, "expired") == 0) + mms_message = g_strdup_printf (_("You received an MMS, but it expired on: %s"), + expire_time_string); + else + mms_message = g_strdup (_("You received an empty MMS.")); } date_time = g_date_time_new_from_iso8601 (date, NULL); @@ -1102,6 +1122,7 @@ chatty_mmsd_receive_message (ChattyMmsd *self, basename = g_path_get_basename (objectpath); payload->message = chatty_message_new (NULL, mms_message, basename, unix_time, chatty_msg_type, direction, mms_status); + chatty_message_set_subject (payload->message, subject); chatty_message_set_id (payload->message, basename); chatty_message_set_files (payload->message, files); } @@ -1334,6 +1355,7 @@ chatty_mmsd_get_mmsd_service_settings_cb (GObject *service, g_autoptr(GVariant) all_settings = NULL; GVariantDict dict; int max_attach_total_size, max_attachments; + gboolean autocreatesmil; g_variant_get (ret, "(@a{?*})", &all_settings); g_variant_dict_init (&dict, all_settings); @@ -1351,6 +1373,11 @@ chatty_mmsd_get_mmsd_service_settings_cb (GObject *service, self->max_num_attach = DEFAULT_MAXIMUM_ATTACHMENTS; g_debug ("MaxAttachments is set to %d", self->max_num_attach); + + if (g_variant_dict_lookup (&dict, "AutoCreateSMIL", "b", &autocreatesmil)) + self->auto_create_smil = autocreatesmil; + + g_debug ("AutoCreateSMIL is set to %d", self->auto_create_smil); } } diff --git a/src/mm/chatty-mmsd.h b/src/mm/chatty-mmsd.h index 5642fe4..3076b6f 100644 --- a/src/mm/chatty-mmsd.h +++ b/src/mm/chatty-mmsd.h @@ -45,5 +45,7 @@ void chatty_mmsd_set_settings_async (ChattyMmsd *self, gboolean chatty_mmsd_set_settings_finish (ChattyMmsd *self, GAsyncResult *result, GError **error); +void chatty_mmsd_delete_mms (ChattyMmsd *self, + const char *uid); G_END_DECLS diff --git a/src/mm/chatty-sms-uri.c b/src/mm/chatty-sms-uri.c new file mode 100644 index 0000000..6259702 --- /dev/null +++ b/src/mm/chatty-sms-uri.c @@ -0,0 +1,293 @@ +/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ +/* chatty-sms-uri.c + * + * Copyright 2021 Purism SPC + * + * Author(s): + * Mohammed Sadiq + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#define G_LOG_DOMAIN "chatty-sms-uri" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define _GNU_SOURCE +#include +#include "chatty-settings.h" +#include "chatty-utils.h" +#include "chatty-sms-uri.h" +#include "chatty-log.h" + +/** + * SECTION: chatty-sms-uri + * @title: ChattySmsUri + * @short_description: RFC 5724 SMS URI parser + * @include: "chatty-sms-uri.h" + * + * See https://www.rfc-editor.org/rfc/rfc5724 + * + * Please note that this parser implements only a minimal set of the + * RFC as required for chatty (ie, most of RFC 3966 is missing), and + * does NOT follow the RFC where it breaks the old behavior of chatty, + * eg: "phone-context" for local numbers + */ + +struct _ChattySmsUri +{ + GObject parent_instance; + + char *uri; + GPtrArray *numbers; + char *numbers_str; + char *body; + + /* If @uri_parsed is set, @uri_valid should cache the URI state */ + gboolean uri_parsed; + gboolean uri_valid; + gboolean numbers_parsed; + gboolean numbers_valid; +}; + +G_DEFINE_TYPE (ChattySmsUri, chatty_sms_uri, G_TYPE_OBJECT) + +static int +sort_strv (gconstpointer a, + gconstpointer b) +{ + char **str_a = (gpointer) a; + char **str_b = (gpointer) b; + + return g_strcmp0 (*str_a, *str_b); +} + +static void +chatty_sms_parse_numbers (ChattySmsUri *self) +{ + GPtrArray *array; + + g_assert (CHATTY_IS_SMS_URI (self)); + + array = self->numbers; + g_clear_pointer (&self->numbers_str, g_free); + + if (array->len == 1) + self->numbers_str = g_strdup (array->pdata[0]); + + if (array->len <= 1) + return; + + g_ptr_array_sort (self->numbers, sort_strv); + + /* Make the array bigger so that we can assure it's NULL terminated */ + g_ptr_array_set_size (array, array->len + 1); + + for (guint i = 0; i < array->len - 1; i++) { + if (g_strcmp0 (array->pdata[i], array->pdata[i + 1]) == 0) + g_ptr_array_remove_index (array, i); + } + + self->numbers_str = g_strjoinv (",", (char **)array->pdata); + + /* Resize back to original size */ + g_ptr_array_set_size (array, array->len - 1); +} + +/* See https://www.rfc-editor.org/rfc/rfc5724#section-2.2 */ +static void +chatty_sms_validate (ChattySmsUri *self) +{ + g_auto(GStrv) recipients = NULL; + g_autofree char *numbers = NULL; + const char *number_start; + ChattySettings *settings; + const char *end; + + g_assert (CHATTY_IS_SMS_URI (self)); + + if (self->uri_parsed) + return; + + self->uri_parsed = TRUE; + self->uri_valid = FALSE; + + if (!self->uri || !*self->uri) + return; + + self->numbers_valid = TRUE; + end = strchrnul (self->uri, '?'); + numbers = g_strndup (self->uri, end - self->uri); + number_start = numbers; + + if (g_str_has_prefix (number_start, "sms:")) + number_start += strlen ("sms:"); + + while (*number_start == '/') + number_start++; + + settings = chatty_settings_get_default (); + recipients = g_strsplit (number_start, ",", -1); + g_ptr_array_set_size (self->numbers, 0); + self->numbers->pdata[0] = NULL; + + + for (int i = 0; recipients[i]; i++) { + char *who; + + who = chatty_utils_check_phonenumber (recipients[i], + chatty_settings_get_country_iso_code (settings)); + + if (!who) { + who = g_strdup (recipients[i]); + self->numbers_valid = FALSE; + } + + g_ptr_array_add (self->numbers, who); + } + + /* + * If there are 0 or 2+ numbers, with atleast one invalid, the URI is invalid + * because this can't happen in an incoming nor outgoing message. + */ + if (!self->numbers->len || + (self->numbers->len >= 2 && !self->numbers_valid)) { + self->uri_valid = FALSE; + return; + } + + g_clear_pointer (&self->body, g_free); + + if (end) { + g_autofree char *text = NULL; + const char *body; + + body = strstr (end, "body="); + + if (!body) + goto end; + + body = body + strlen ("body="); + end = strchrnul (body, '&'); + text = g_strndup (body, end - body); + + self->body = g_uri_unescape_string (text, NULL); + } + + end: + /* A URI with exactly one non numeric sender is considered valid + * As it can happen in incoming messages, but in that case, body + * should be empty as a message can't be send to the given number + */ + if (self->numbers_valid || !self->body) + self->uri_valid = TRUE; +} + +static void +chatty_sms_uri_finalize (GObject *object) +{ + ChattySmsUri *self = (ChattySmsUri *)object; + + g_free (self->uri); + g_free (self->numbers_str); + g_free (self->body); + g_ptr_array_free (self->numbers, TRUE); + + G_OBJECT_CLASS (chatty_sms_uri_parent_class)->finalize (object); +} + +static void +chatty_sms_uri_class_init (ChattySmsUriClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = chatty_sms_uri_finalize; +} + +static void +chatty_sms_uri_init (ChattySmsUri *self) +{ + self->numbers = g_ptr_array_new_full (1, g_free); +} + +ChattySmsUri * +chatty_sms_uri_new (const char *uri) +{ + ChattySmsUri *self; + + self = g_object_new (CHATTY_TYPE_SMS_URI, NULL); + self->uri = g_strdup (uri); + + return self; +} + +void +chatty_sms_uri_set_uri (ChattySmsUri *self, + const char *uri) +{ + g_return_if_fail (CHATTY_IS_SMS_URI (self)); + + g_free (self->uri); + self->uri = g_strdup (uri); + + self->uri_parsed = FALSE; +} + +gboolean +chatty_sms_uri_is_valid (ChattySmsUri *self) +{ + g_return_val_if_fail (CHATTY_IS_SMS_URI (self), FALSE); + + chatty_sms_validate (self); + + return self->uri_valid; +} + +gboolean +chatty_sms_uri_can_send (ChattySmsUri *self) +{ + g_return_val_if_fail (CHATTY_IS_SMS_URI (self), FALSE); + + return self->numbers_valid; +} + +GPtrArray * +chatty_sms_uri_get_numbers (ChattySmsUri *self) +{ + g_return_val_if_fail (CHATTY_IS_SMS_URI (self), NULL); + + chatty_sms_validate (self); + chatty_sms_parse_numbers (self); + + return self->numbers; +} + +const char * +chatty_sms_uri_get_numbers_str (ChattySmsUri *self) +{ + g_return_val_if_fail (CHATTY_IS_SMS_URI (self), NULL); + + chatty_sms_validate (self); + chatty_sms_parse_numbers (self); + + if (self->numbers_str) + return self->numbers_str; + + return ""; +} + +const char * +chatty_sms_uri_get_body (ChattySmsUri *self) +{ + g_return_val_if_fail (CHATTY_IS_SMS_URI (self), ""); + + chatty_sms_validate (self); + + if (self->body && self->numbers_valid) + return self->body; + + return ""; +} diff --git a/src/mm/chatty-sms-uri.h b/src/mm/chatty-sms-uri.h new file mode 100644 index 0000000..8a64059 --- /dev/null +++ b/src/mm/chatty-sms-uri.h @@ -0,0 +1,31 @@ +/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ +/* chatty-sms-uri.h + * + * Copyright 2021 Purism SPC + * + * Author(s): + * Mohammed Sadiq + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CHATTY_TYPE_SMS_URI (chatty_sms_uri_get_type ()) + +G_DECLARE_FINAL_TYPE (ChattySmsUri, chatty_sms_uri, CHATTY, SMS_URI, GObject) + +ChattySmsUri *chatty_sms_uri_new (const char *uri); +void chatty_sms_uri_set_uri (ChattySmsUri *self, + const char *uri); +gboolean chatty_sms_uri_is_valid (ChattySmsUri *self); +gboolean chatty_sms_uri_can_send (ChattySmsUri *self); +GPtrArray *chatty_sms_uri_get_numbers (ChattySmsUri *self); +const char *chatty_sms_uri_get_numbers_str (ChattySmsUri *self); +const char *chatty_sms_uri_get_body (ChattySmsUri *self); + +G_END_DECLS diff --git a/src/mm/meson.build b/src/mm/meson.build index 6e5738f..48e7be8 100644 --- a/src/mm/meson.build +++ b/src/mm/meson.build @@ -6,6 +6,7 @@ libsrc += files([ 'chatty-mm-buddy.c', 'chatty-mm-chat.c', 'chatty-mmsd.c', + 'chatty-sms-uri.c', ]) chatty_deps += [ diff --git a/src/ui/chatty-contact-list.ui b/src/ui/chatty-contact-list.ui new file mode 100644 index 0000000..b15ccfd --- /dev/null +++ b/src/ui/chatty-contact-list.ui @@ -0,0 +1,79 @@ + + + + diff --git a/src/ui/chatty-dialog-new-chat.ui b/src/ui/chatty-dialog-new-chat.ui index e59970a..04893bb 100644 --- a/src/ui/chatty-dialog-new-chat.ui +++ b/src/ui/chatty-dialog-new-chat.ui @@ -1,166 +1,206 @@ - diff --git a/src/ui/chatty-settings-dialog.ui b/src/ui/chatty-settings-dialog.ui index f94a2e7..4c4d4a2 100644 --- a/src/ui/chatty-settings-dialog.ui +++ b/src/ui/chatty-settings-dialog.ui @@ -5,6 +5,7 @@ 360 dialog Preferences + diff --git a/src/users/chatty-contact.c b/src/users/chatty-contact.c index 979e67b..da178b1 100644 --- a/src/users/chatty-contact.c +++ b/src/users/chatty-contact.c @@ -262,13 +262,27 @@ chatty_contact_new (EContact *contact, ChattyContact *self; self = g_object_new (CHATTY_TYPE_CONTACT, NULL); - self->e_contact = g_object_ref (contact); + g_set_object (&self->e_contact, contact); self->attribute = attr; self->protocol = protocol; return self; } +ChattyContact * +chatty_contact_dummy_new (const char *name, + const char *value) +{ + ChattyContact *self; + + self = g_object_new (CHATTY_TYPE_CONTACT, NULL); + self->name = g_strdup (name); + self->value = g_strdup (value); + g_object_set_data (G_OBJECT (self), "dummy", GINT_TO_POINTER (TRUE)); + + return self; +} + void chatty_contact_set_name (ChattyContact *self, const char *name) diff --git a/src/users/chatty-contact.h b/src/users/chatty-contact.h index 3d3962c..99ef0ee 100644 --- a/src/users/chatty-contact.h +++ b/src/users/chatty-contact.h @@ -26,6 +26,8 @@ G_DECLARE_FINAL_TYPE (ChattyContact, chatty_contact, CHATTY, CONTACT, ChattyItem ChattyContact *chatty_contact_new (EContact *contact, EVCardAttribute *attr, ChattyProtocol protocol); +ChattyContact *chatty_contact_dummy_new (const char *name, + const char *value); void chatty_contact_set_name (ChattyContact *self, const char *name); void chatty_contact_set_value (ChattyContact *self, diff --git a/tests/history-db/empty-v4.sql b/tests/history-db/empty-v4.sql new file mode 100644 index 0000000..38c8f9e --- /dev/null +++ b/tests/history-db/empty-v4.sql @@ -0,0 +1,96 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +COMMIT; diff --git a/tests/history-db/matrix-a-v3.sql b/tests/history-db/matrix-a-v3.sql new file mode 100644 index 0000000..24e9d91 --- /dev/null +++ b/tests/history-db/matrix-a-v3.sql @@ -0,0 +1,150 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 3; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE audio ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE image ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE, + width INTEGER, + height INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE video ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'SMS',NULL,NULL,1); +INSERT INTO users VALUES(2,'MMS',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +INSERT INTO accounts VALUES(2,2,NULL,0,2); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + UNIQUE (uid, thread_id, body, time) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; + +INSERT INTO users VALUES(3,'alice',NULL,NULL,4); +INSERT INTO users VALUES(4,'@charlie:example.com',NULL,NULL,4); +INSERT INTO users VALUES(5,'@_freenode_hunter2:example.com',NULL,NULL,4); +INSERT INTO users VALUES(7,'@bob:example.com',NULL,NULL,4); +INSERT INTO users VALUES(8,'@bob:example.org',NULL,NULL,4); +INSERT INTO users VALUES(9,'@alice:example.com',NULL,NULL,4); + +INSERT INTO accounts VALUES(3,3,NULL,0,4); +INSERT INTO accounts VALUES(4,8,NULL,0,4); +INSERT INTO accounts VALUES(5,9,NULL,0,4); + +INSERT INTO threads VALUES(1,'!CDFTfyJgtVMvsXDEi:example.com','#something',NULL,4,1,0,NULL,0); +INSERT INTO threads VALUES(2,'!CDFTfyJgtVMvsXDEi:example.com',NULL,NULL,5,1,0,NULL,1); +INSERT INTO threads VALUES(3,'!VPWUCfyJyeVMxiHYGi:example.com','Some room',NULL,5,1,1,NULL,1); +INSERT INTO threads VALUES(4,'!VPWUCfyJyeVMxiHYGi:example.com',NULL,NULL,3,1,1,NULL,0); + +INSERT INTO thread_members VALUES(1,1,4); +INSERT INTO thread_members VALUES(2,1,9); +INSERT INTO thread_members VALUES(3,2,5); +INSERT INTO thread_members VALUES(4,3,7); +INSERT INTO thread_members VALUES(5,3,9); +INSERT INTO thread_members VALUES(6,4,9); + +INSERT INTO messages VALUES(NULL,'10600c18',1,4,NULL,'8',11,1,1586447320,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'1dc29876',1,4,NULL,'2',9,1,1586448432,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'c73bbcbc',1,9,NULL,'4',10,1,1586448429,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'414d35fa',2,5,NULL,'1',8,1,1586448435,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'f86768a5',2,NULL,NULL,'5',9,1,1586448438,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'12107bfc',3,7,NULL,'3',8,1,1586447316,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'2a5f6c4a',3,7,NULL,'6',8,1,1586447319,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'6b67fa36-0f91-11eb',3,9,NULL,'9',11,-1,1586447419,NULL,0,NULL); +INSERT INTO messages VALUES(NULL,'3a383ec7-7566-457b-b561-2145b328459c',4,9,NULL,'10',9,-1,1586447421,NULL,0,NULL); + +INSERT INTO mime_type VALUES(1,'audio/ogg'); +INSERT INTO mime_type VALUES(2,'application/pdf'); +INSERT INTO mime_type VALUES(3,'image/jpg'); +INSERT INTO mime_type VALUES(4,'video/ogv'); +INSERT INTO mime_type VALUES(5,'image/png'); + +INSERT INTO files VALUES(1,'document.pdf','https://example.com/document.pdf',NULL,NULL,0,0); +INSERT INTO files VALUES(2,'image.png','http://example.com/image.png','some/path/image.png',5,1,200); +INSERT INTO files VALUES(3,'another.pdf','http://example.com/another.pdf','another/path/another.pdf',2,1,400); +INSERT INTO files VALUES(4,'അ.ogv','http://example.com/അ.ogv',NULL,2,2,512); +INSERT INTO files VALUES(5,'another-image.jpg','http://example.net/another-image.jpg',NULL,3,2,512); +INSERT INTO files VALUES(6,NULL,'https://example.com/another-document.pdf',NULL,NULL,NULL,NULL); +INSERT INTO files VALUES(8,NULL,'https://example.com/song.ogg',NULL,1,NULL,NULL); +INSERT INTO files VALUES(9,'another.ogg','https://example.com/another.ogg',NULL,1,NULL,NULL); +INSERT INTO files VALUES(10,'File title','http://example.com/file.png','some/path/file.png',5,NULL,NULL); + +INSERT INTO audio VALUES(NULL,8,100); +INSERT INTO audio VALUES(NULL,9,221); + +-- One of the image file is not included here as it's okay for it to happen +INSERT INTO image VALUES(NULL,2,400,300); +INSERT INTO image VALUES(NULL,5,500,200); + +INSERT INTO video VALUES(NULL,4,400,300,100); + +COMMIT; diff --git a/tests/history-db/matrix-a-v4.sql b/tests/history-db/matrix-a-v4.sql new file mode 100644 index 0000000..568c9f6 --- /dev/null +++ b/tests/history-db/matrix-a-v4.sql @@ -0,0 +1,155 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'alice',NULL,NULL,4); +INSERT INTO users VALUES(4,'@charlie:example.com',NULL,NULL,4); +INSERT INTO users VALUES(5,'@_freenode_hunter2:example.com',NULL,NULL,4); +INSERT INTO users VALUES(7,'@bob:example.com',NULL,NULL,4); +INSERT INTO users VALUES(8,'@bob:example.org',NULL,NULL,4); +INSERT INTO users VALUES(9,'@alice:example.com',NULL,NULL,4); + +INSERT INTO accounts VALUES(3,3,NULL,0,4); +INSERT INTO accounts VALUES(4,8,NULL,0,4); +INSERT INTO accounts VALUES(5,9,NULL,0,4); + +INSERT INTO threads VALUES(1,'!CDFTfyJgtVMvsXDEi:example.com','#something',NULL,4,1,0,NULL,0,1); +INSERT INTO threads VALUES(2,'!CDFTfyJgtVMvsXDEi:example.com',NULL,NULL,5,1,0,NULL,1,1); +INSERT INTO threads VALUES(3,'!VPWUCfyJyeVMxiHYGi:example.com','Some room',NULL,5,1,1,NULL,1,1); +INSERT INTO threads VALUES(4,'!VPWUCfyJyeVMxiHYGi:example.com',NULL,NULL,3,1,1,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,4); +INSERT INTO thread_members VALUES(2,1,9); +INSERT INTO thread_members VALUES(3,2,5); +INSERT INTO thread_members VALUES(4,3,7); +INSERT INTO thread_members VALUES(5,3,9); +INSERT INTO thread_members VALUES(6,4,9); + +INSERT INTO messages VALUES(1,'10600c18',1,4,NULL,'',11,1,1586447320,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(2,'1dc29876',1,4,NULL,'',9,1,1586448432,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(3,'c73bbcbc',1,9,NULL,'',10,1,1586448429,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(5,'414d35fa',2,5,NULL,'',8,1,1586448435,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(6,'f86768a5',2,NULL,NULL,'',9,1,1586448438,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(7,'12107bfc',3,7,NULL,'',8,1,1586447316,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(9,'2a5f6c4a',3,7,NULL,'',8,1,1586447319,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(10,'6b67fa36-0f91-11eb',3,9,NULL,'',11,-1,1586447419,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(11,'3a383ec7-7566-457b-b561-2145b328459c',4,9,NULL,'',9,-1,1586447421,NULL,0,NULL,NULL); + +INSERT INTO mime_type VALUES(1,'audio/ogg'); +INSERT INTO mime_type VALUES(2,'application/pdf'); +INSERT INTO mime_type VALUES(3,'image/jpg'); +INSERT INTO mime_type VALUES(4,'video/ogv'); +INSERT INTO mime_type VALUES(5,'image/png'); + +INSERT INTO files VALUES(1,'document.pdf','https://example.com/document.pdf',NULL,NULL,0,0); +INSERT INTO files VALUES(2,'image.png','http://example.com/image.png','some/path/image.png',5,1,200); +INSERT INTO files VALUES(3,'another.pdf','http://example.com/another.pdf','another/path/another.pdf',2,1,400); +INSERT INTO files VALUES(4,'അ.ogv','http://example.com/അ.ogv',NULL,2,2,512); +INSERT INTO files VALUES(5,'another-image.jpg','http://example.net/another-image.jpg',NULL,3,2,512); +INSERT INTO files VALUES(6,NULL,'https://example.com/another-document.pdf',NULL,NULL,NULL,NULL); +INSERT INTO files VALUES(8,NULL,'https://example.com/song.ogg',NULL,1,NULL,NULL); +INSERT INTO files VALUES(9,'another.ogg','https://example.com/another.ogg',NULL,1,NULL,NULL); +INSERT INTO files VALUES(10,'File title','http://example.com/file.png','some/path/file.png',5,NULL,NULL); + +INSERT INTO message_files VALUES(NULL,1,8,NULL); +INSERT INTO message_files VALUES(NULL,2,2,NULL); +INSERT INTO message_files VALUES(NULL,3,4,NULL); +INSERT INTO message_files VALUES(NULL,5,1,NULL); +INSERT INTO message_files VALUES(NULL,6,5,NULL); +INSERT INTO message_files VALUES(NULL,7,3,NULL); +INSERT INTO message_files VALUES(NULL,9,6,NULL); +INSERT INTO message_files VALUES(NULL,11,10,NULL); +INSERT INTO message_files VALUES(NULL,10,9,NULL); + +COMMIT; diff --git a/tests/history-db/matrix-v4.sql b/tests/history-db/matrix-v4.sql new file mode 100644 index 0000000..03ed1b6 --- /dev/null +++ b/tests/history-db/matrix-v4.sql @@ -0,0 +1,129 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'alice',NULL,NULL,4); +INSERT INTO users VALUES(4,'@charlie:example.com',NULL,NULL,4); +INSERT INTO users VALUES(5,'@_freenode_hunter2:example.com',NULL,NULL,4); +INSERT INTO users VALUES(7,'@bob:example.com',NULL,NULL,4); +INSERT INTO users VALUES(8,'@bob:example.org',NULL,NULL,4); +INSERT INTO users VALUES(9,'@alice:example.com',NULL,NULL,4); + +INSERT INTO accounts VALUES(3,3,NULL,0,4); +INSERT INTO accounts VALUES(4,8,NULL,0,4); +INSERT INTO accounts VALUES(5,9,NULL,0,4); + +INSERT INTO threads VALUES(1,'!CDFTfyJgtVMvsXDEi:example.com',NULL,NULL,4,1,0,NULL,0,1); +INSERT INTO threads VALUES(2,'!CDFTfyJgtVMvsXDEi:example.com',NULL,NULL,5,1,0,NULL,0,1); +INSERT INTO threads VALUES(3,'!VPWUCfyJyeVMxiHYGi:example.com',NULL,NULL,5,1,0,NULL,0,1); +INSERT INTO threads VALUES(4,'!VPWUCfyJyeVMxiHYGi:example.com',NULL,NULL,3,1,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,4); +INSERT INTO thread_members VALUES(2,1,9); +INSERT INTO thread_members VALUES(3,2,5); +INSERT INTO thread_members VALUES(4,3,7); +INSERT INTO thread_members VALUES(5,3,9); +INSERT INTO thread_members VALUES(6,4,9); + +INSERT INTO messages VALUES(NULL,'10600c18-ecc1-4d42-8f0a-5c5e563b1b3d',1,NULL,NULL,'Another empty author message',2,1,1586447320,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1dc29876-0f92-11eb-aeb4-d7486be58053',1,4,NULL,'Failed',2,1,1586448432,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c73bbcbc-0f91-11eb-aab2-8b95affe5e24',1,9,NULL,'Test',2,1,1586448429,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'414d35fa-e50f-441f-a382-3cb8acd7a510',2,5,NULL,'Weird. All I see is *',2,1,1586448435,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'f86768a5-d0fb-423c-9430-3d3b66d74a67',2,NULL,NULL,'A message with no author',2,1,1586448438,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'12107bfc-0f91-11eb-8501-2314b53187d5',3,7,NULL,'Hi',2,1,1586447316,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'2a5f6c4a-0f91-11eb-af2c-27e3777f4483',3,7,NULL,'Are you there?',2,1,1586447319,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'6b67fa36-0f91-11eb-9714-af849160d937',3,9,NULL,'Hi',2,-1,1586447419,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'3a383ec7-7566-457b-b561-2145b328459c',4,9,NULL,'Why?',2,-1,1586447421,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/sms-DE-v4.sql b/tests/history-db/sms-DE-v4.sql new file mode 100644 index 0000000..baeac91 --- /dev/null +++ b/tests/history-db/sms-DE-v4.sql @@ -0,0 +1,132 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'+12133210011',NULL,NULL,1); +INSERT INTO users VALUES(4,'Mobile@5G',NULL,NULL,1); +INSERT INTO users VALUES(5,'5555',NULL,NULL,1); +INSERT INTO users VALUES(6,'+919876121212',NULL,NULL,1); +INSERT INTO users VALUES(7,'+919995123456',NULL,NULL,1); +INSERT INTO users VALUES(8,'+4915112345678',NULL,NULL,1); + +INSERT INTO threads VALUES(1,'+12133210011','+12133210011',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(2,'Mobile@5G','Mobile@5G',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(3,'5555','5555',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(4,'+919876121212','+919876121212',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(5,'+919995123456','+919995123456',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(6,'+4915112345678','01511 2345678',NULL,1,0,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,3); +INSERT INTO thread_members VALUES(2,2,4); +INSERT INTO thread_members VALUES(3,3,5); +INSERT INTO thread_members VALUES(4,4,6); +INSERT INTO thread_members VALUES(5,5,7); +INSERT INTO thread_members VALUES(6,6,8); + +INSERT INTO messages VALUES(NULL,'259478cf-64b3-44e1-9b1c-5d1773edc601',1,3,NULL,'Hi',1,1,1600074685,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1a1cbd44-7526-4032-9665-45aee085ab65',1,3,NULL,'I''m fine',1,1,1600074789,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'af65adc0-2d80-4de8-83bb-9bf9ea4ebd5d',1,3,NULL,'How are you?',1,-1,1600074687,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'601f2a66-e6a6-4083-9dce-e5d78fb57520',2,4,NULL,'Get Unlimitted 5G',1,1,1600074800,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'271fe95c-5d47-4ffe-ae62-7f2f6b749711',2,4,NULL,'Get Unlimmtted 5G',1,1,1600074809,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'4dafafd9-734c-4f86-b1ec-09aa327b8a88',3,5,NULL,'Free unlimitted internet 4 99$',1,1,1600074802,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1218070f-c820-40e1-bd33-5099d894683a',4,6,NULL,'Hello',1,1,1600075652,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'9abcc777-5b06-4570-9b83-48603a49add2',4,6,NULL,'Hi.',1,-1,1600075658,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c5b99952-5517-4620-8f28-fb97f5017cee',6,8,NULL,'May I call you?',1,-1,1600075789,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'fe352125-1772-4360-831e-e2d56bb73c73',6,8,NULL,'Are you there?',1,-1,1600075790,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c597bd6a-2e60-4df3-9c05-cc0c88861721',6,8,NULL,'OK. Call me later',1,-1,1600075791,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'f098e603-5ac1-4d5a-bcad-c7fe84c91252',6,8,NULL,'Sure, you may call me',1,1,1600075889,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'9d401342-3e30-4b25-859b-b56bd0ec2839',5,7,NULL,'SMS to India',1,-1,1600075909,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'776a3885-5cb1-41ed-9423-dfe3d2ac772a',5,7,NULL,'More SMS to India',1,-1,1600075913,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/sms-IN-v4.sql b/tests/history-db/sms-IN-v4.sql new file mode 100644 index 0000000..fdbaeef --- /dev/null +++ b/tests/history-db/sms-IN-v4.sql @@ -0,0 +1,132 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'+12133210011',NULL,NULL,1); +INSERT INTO users VALUES(4,'Mobile@5G',NULL,NULL,1); +INSERT INTO users VALUES(5,'5555',NULL,NULL,1); +INSERT INTO users VALUES(6,'+919876121212',NULL,NULL,1); +INSERT INTO users VALUES(7,'+919995123456',NULL,NULL,1); +INSERT INTO users VALUES(8,'+4915112345678',NULL,NULL,1); + +INSERT INTO threads VALUES(1,'+12133210011','+12133210011',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(2,'Mobile@5G','Mobile@5G',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(3,'5555','5555',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(4,'+919876121212','+919876121212',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(5,'+919995123456','9995123456',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(6,'+4915112345678','+4915112345678',NULL,1,0,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,3); +INSERT INTO thread_members VALUES(2,2,4); +INSERT INTO thread_members VALUES(3,3,5); +INSERT INTO thread_members VALUES(4,4,6); +INSERT INTO thread_members VALUES(5,5,7); +INSERT INTO thread_members VALUES(6,6,8); + +INSERT INTO messages VALUES(NULL,'259478cf-64b3-44e1-9b1c-5d1773edc601',1,3,NULL,'Hi',1,1,1600074685,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1a1cbd44-7526-4032-9665-45aee085ab65',1,3,NULL,'I''m fine',1,1,1600074789,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'af65adc0-2d80-4de8-83bb-9bf9ea4ebd5d',1,3,NULL,'How are you?',1,-1,1600074687,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'601f2a66-e6a6-4083-9dce-e5d78fb57520',2,4,NULL,'Get Unlimitted 5G',1,1,1600074800,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'271fe95c-5d47-4ffe-ae62-7f2f6b749711',2,4,NULL,'Get Unlimmtted 5G',1,1,1600074809,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'4dafafd9-734c-4f86-b1ec-09aa327b8a88',3,5,NULL,'Free unlimitted internet 4 99$',1,1,1600074802,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1218070f-c820-40e1-bd33-5099d894683a',4,6,NULL,'Hello',1,1,1600075652,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'9abcc777-5b06-4570-9b83-48603a49add2',4,6,NULL,'Hi.',1,-1,1600075658,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c5b99952-5517-4620-8f28-fb97f5017cee',5,7,NULL,'May I call you?',1,-1,1600075789,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'fe352125-1772-4360-831e-e2d56bb73c73',5,7,NULL,'Are you there?',1,-1,1600075790,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c597bd6a-2e60-4df3-9c05-cc0c88861721',5,7,NULL,'OK. Call me later',1,-1,1600075791,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'f098e603-5ac1-4d5a-bcad-c7fe84c91252',5,7,NULL,'Sure, you may call me',1,1,1600075889,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'9d401342-3e30-4b25-859b-b56bd0ec2839',6,8,NULL,'SMS to Germany',1,-1,1600075909,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'776a3885-5cb1-41ed-9423-dfe3d2ac772a',6,8,NULL,'More SMS to Germany',1,-1,1600075913,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/sms-v4.sql b/tests/history-db/sms-v4.sql new file mode 100644 index 0000000..463a5af --- /dev/null +++ b/tests/history-db/sms-v4.sql @@ -0,0 +1,126 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'+12133210011',NULL,NULL,1); +INSERT INTO users VALUES(4,'Mobile@5G',NULL,NULL,1); +INSERT INTO users VALUES(5,'5555',NULL,NULL,1); +INSERT INTO users VALUES(6,'+919876121212',NULL,NULL,1); +INSERT INTO users VALUES(7,'+12133456789',NULL,NULL,1); + +INSERT INTO threads VALUES(1,'+12133210011','+12133210011',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(2,'Mobile@5G','Mobile@5G',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(3,'5555','5555',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(4,'+919876121212','+919876121212',NULL,1,0,0,NULL,0,1); +INSERT INTO threads VALUES(5,'+12133456789','(213) 345-6789',NULL,1,0,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,3); +INSERT INTO thread_members VALUES(2,2,4); +INSERT INTO thread_members VALUES(3,3,5); +INSERT INTO thread_members VALUES(4,4,6); +INSERT INTO thread_members VALUES(5,5,7); + +INSERT INTO messages VALUES(NULL,'1a1cbd44-7526-4032-9665-45aee085ab65',1,3,NULL,'I''m fine',1,1,1600074789,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'259478cf-64b3-44e1-9b1c-5d1773edc601',1,3,NULL,'Hi',1,1,1600074685,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'22be2899-8c1e-4501-ab33-979c356a6764',1,3,NULL,'Hello',1,-1,1600074686,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'af65adc0-2d80-4de8-83bb-9bf9ea4ebd5d',1,3,NULL,'How are you?',1,-1,1600074687,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'271fe95c-5d47-4ffe-ae62-7f2f6b749711',2,4,NULL,'Get Unlimmtted 5G',1,1,1600074809,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'601f2a66-e6a6-4083-9dce-e5d78fb57520',2,4,NULL,'Get Unlimitted 5G',1,1,1600074800,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'4dafafd9-734c-4f86-b1ec-09aa327b8a88',3,5,NULL,'Free unlimitted internet 4 99$',1,1,1600074802,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1218070f-c820-40e1-bd33-5099d894683a',4,6,NULL,'Hello',1,1,1600075652,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'9abcc777-5b06-4570-9b83-48603a49add2',4,6,NULL,'Hi.',1,-1,1600075658,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c5b99952-5517-4620-8f28-fb97f5017cee',5,7,NULL,'May I call you?',1,-1,1600075789,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'f098e603-5ac1-4d5a-bcad-c7fe84c91252',5,7,NULL,'Sure, you may call me',1,1,1600075889,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/telegram-chat-v4.sql b/tests/history-db/telegram-chat-v4.sql new file mode 100644 index 0000000..0e62645 --- /dev/null +++ b/tests/history-db/telegram-chat-v4.sql @@ -0,0 +1,127 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'New Person','New Person',NULL,1); +INSERT INTO users VALUES(4,'+19876543210',NULL,NULL,1); +INSERT INTO users VALUES(5,'+19812121212',NULL,NULL,1); +INSERT INTO users VALUES(6,'Random Person','Random Person',NULL,1); +INSERT INTO users VALUES(7,'Bob','Bob',NULL,1); + +INSERT INTO accounts VALUES(3,4,NULL,0,5); +INSERT INTO accounts VALUES(4,5,NULL,0,5); + +INSERT INTO threads VALUES(1,'Random room','Random room',NULL,4,1,0,NULL,0,1); +INSERT INTO threads VALUES(2,'Random room','Random room',NULL,3,1,0,NULL,0,1); +INSERT INTO threads VALUES(3,'Another Room@example.com','Another Room@example.com',NULL,3,1,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,3); +INSERT INTO thread_members VALUES(2,2,3); +INSERT INTO thread_members VALUES(3,2,6); +INSERT INTO thread_members VALUES(4,3,6); +INSERT INTO thread_members VALUES(5,3,7); +INSERT INTO thread_members VALUES(6,1,6); + +INSERT INTO messages VALUES(NULL,'3f5f7d60-1510-4249-80f4-ad802fa9483f',1,NULL,NULL,'Hello',2,1,1502695426,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'c485ac17-513e-4e16-b049-dbc21e000ed8',1,NULL,NULL,'Hi',2,1,1502695424,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'26b5bd41-8f34-476a-bb03-9ed8f8129817',1,3,NULL,'I''m New, Hi',2,1,1502695429,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'4d3defa2-85a2-4cd5-9e1b-940b2c406351',2,3,NULL,'New here',2,1,1502695429,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'955044fb-fc34-42a1-88c7-acdd0c45acc7',2,6,NULL,'I''m random',2,1,1502695432,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1525c407-7c3d-4b02-8e26-a6e86183a8bc',3,4,NULL,'Hello all',2,-1,1502695573,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'be6ca8bf-b5d9-4983-bbd3-3767eda52f4a',3,NULL,NULL,'I''m empty',2,1,1502695572,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'53269985-89da-4e01-9914-fa053735d59f',3,6,NULL,'Another me',2,1,1502695432,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'92a4e961-b3ac-487c-9dd6-c645944e5946',3,7,NULL,'I''m bob',2,1,1502695569,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'21fb7985-c3c4-4292-ab84-1b7c637c727a',1,6,NULL,'Let me know who is here?',2,1,1502695587,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/telegram-im-v4.sql b/tests/history-db/telegram-im-v4.sql new file mode 100644 index 0000000..b4795fb --- /dev/null +++ b/tests/history-db/telegram-im-v4.sql @@ -0,0 +1,126 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'+19876543210',NULL,NULL,1); +INSERT INTO users VALUES(4,'Alice','Alice',NULL,1); +INSERT INTO users VALUES(5,'Random Person','Random Person',NULL,1); +INSERT INTO users VALUES(6,'+351123456789',NULL,NULL,1); +INSERT INTO users VALUES(7,'Another Person','Another Person',NULL,1); + +INSERT INTO accounts VALUES(3,3,NULL,0,5); +INSERT INTO accounts VALUES(4,6,NULL,0,5); + +INSERT INTO threads VALUES(1,'Alice','Alice',NULL,3,0,0,NULL,0,1); +INSERT INTO threads VALUES(2,'Random Person','Random Person',NULL,3,0,0,NULL,0,1); +INSERT INTO threads VALUES(3,'Random Person','Random Person',NULL,4,0,0,NULL,0,1); +INSERT INTO threads VALUES(4,'Another Person','Another Person',NULL,4,0,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,4); +INSERT INTO thread_members VALUES(2,2,5); +INSERT INTO thread_members VALUES(3,3,5); +INSERT INTO thread_members VALUES(4,4,7); + +INSERT INTO messages VALUES(NULL,'a88e7db7-3d41-4e3e-8e21-d1e4e6466a01',1,4,NULL,'How are you',2,1,1502685304,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'84406650-c4a6-435d-ba4f-ac193b59a975',1,4,NULL,'Hi',2,1,1502685300,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'e9d54317-9234-4de8-b345-c3a8e4d3b322',1,4,NULL,'Hello',2,-1,1502685303,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'bf5b5a8c-e9bc-4c22-b215-bdb624c0524d',2,5,NULL,'Hello Random',2,-1,1502685403,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'01241679-58e4-4e65-b88f-67e70d617594',3,5,NULL,'Hi',2,1,1502685271,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'8a7ba154-9e09-4845-973e-cc6f8aedcdc5',3,5,NULL,'Hello',2,1,1502685274,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'b23a7a25-7bdf-44ac-8685-d6881f3eaf90',3,5,NULL,'Yeah',2,-1,1502685280,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'0887db8b-11f1-4167-9dfa-c8a4a0fad6d2',3,5,NULL,'Can you call me @9:00?',2,1,1502685295,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'5a60ea9e-e6a0-4c5e-94bf-5e2330be4547',4,7,NULL,'Hi',2,-1,1502685282,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'dd12cdf6-0d8c-4010-8138-9640237ccc15',4,7,NULL,'I''m here',2,1,1502685284,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/xmpp-im-v4.sql b/tests/history-db/xmpp-im-v4.sql new file mode 100644 index 0000000..3302234 --- /dev/null +++ b/tests/history-db/xmpp-im-v4.sql @@ -0,0 +1,126 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'user@example.com',NULL,NULL,3); +INSERT INTO users VALUES(4,'buddy@example.com',NULL,NULL,3); +INSERT INTO users VALUES(5,'friend@example.com',NULL,NULL,3); +INSERT INTO users VALUES(6,'bob@example.com',NULL,NULL,3); +INSERT INTO users VALUES(7,'account@example.com',NULL,NULL,3); +INSERT INTO users VALUES(8,'alice@example.com',NULL,NULL,3); + +INSERT INTO accounts VALUES(3,7,NULL,0,3); +INSERT INTO accounts VALUES(4,8,NULL,0,3); + +INSERT INTO threads VALUES(1,'bob@example.com',NULL,NULL,3,0,0,NULL,0,1); +INSERT INTO threads VALUES(2,'friend@example.com',NULL,NULL,3,0,0,NULL,0,1); +INSERT INTO threads VALUES(3,'user@example.com',NULL,NULL,3,0,0,NULL,0,1); +INSERT INTO threads VALUES(4,'buddy@example.com',NULL,NULL,3,0,0,NULL,0,1); +INSERT INTO threads VALUES(5,'bob@example.com',NULL,NULL,4,0,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,1,6); +INSERT INTO thread_members VALUES(2,2,5); +INSERT INTO thread_members VALUES(3,3,3); +INSERT INTO thread_members VALUES(4,4,4); +INSERT INTO thread_members VALUES(5,5,6); + +INSERT INTO messages VALUES(NULL,'2ebff02a-0d1b-11eb-aa37-5fdd4a70e5d0',1,6,NULL,'Hi',2,-1,1602143867,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'NKkdrK32DFDsXDUZl',2,5,NULL,'Message with resource',2,1,1602143838,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'NKkdrKrNSDsXDUZl',3,3,NULL,'Another test message',2,-1,1602143858,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'NKkdrKrNSDsXsdxZl',3,3,NULL,'This is a system message',2,0,1602143858,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'NKkdrKrNSbYlZUZl',4,4,NULL,'Some test message',2,1,1602158858,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'4b58bb22-0d1b-11eb-b502-8b03cec4d745',5,6,NULL,'Hi',2,-1,1602145677,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'e465e9da-0d1a-11eb-93ea-e30b7b9ae820',5,6,NULL,'Hi',2,1,1602143859,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history-db/xmpp-muc-v4.sql b/tests/history-db/xmpp-muc-v4.sql new file mode 100644 index 0000000..6801da1 --- /dev/null +++ b/tests/history-db/xmpp-muc-v4.sql @@ -0,0 +1,123 @@ +BEGIN TRANSACTION; +PRAGMA user_version = 4; +PRAGMA foreign_keys = ON; +CREATE TABLE mime_type ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT, + url TEXT NOT NULL UNIQUE, + path TEXT, + mime_type_id INTEGER REFERENCES mime_type(id), + status INT, + size INTEGER +); +CREATE TABLE file_metadata ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + file_id INTEGER NOT NULL UNIQUE REFERENCES files(id) ON DELETE CASCADE, + width INTEGER, + height INTEGER, + duration INTEGER, + FOREIGN KEY(file_id) REFERENCES files(id) +); +CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + type INTEGER NOT NULL, + UNIQUE (username, type) +); +INSERT INTO users VALUES(1,'invalid-0000000000000000',NULL,NULL,1); +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id), + password TEXT, + enabled INTEGER DEFAULT 0, + protocol INTEGER NOT NULL, + UNIQUE (user_id, protocol) +); +INSERT INTO accounts VALUES(1,1,NULL,0,1); +CREATE TABLE threads ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + alias TEXT, + avatar_id INTEGER REFERENCES files(id), + account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE, + type INTEGER NOT NULL, + encrypted INTEGER DEFAULT 0, + UNIQUE (name, account_id, type) +); +CREATE TABLE thread_members ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id), + UNIQUE (thread_id, user_id) +); +CREATE TABLE messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + uid TEXT NOT NULL, + thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, + sender_id INTEGER REFERENCES users(id), + user_alias TEXT, + body TEXT NOT NULL, + body_type INTEGER NOT NULL, + direction INTEGER NOT NULL, + time INTEGER NOT NULL, + status INTEGER, + encrypted INTEGER DEFAULT 0, + preview_id INTEGER REFERENCES files(id), + subject TEXT, + UNIQUE (uid, thread_id, body, time) +); +CREATE TABLE mm_messages ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES accounts(id), + protocol INTEGER NOT NULL, + smsc TEXT, + time_sent INTEGER, + validity INTEGER, + reference_number INTEGER +); +CREATE TABLE message_files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files(id), + preview_id INTEGER REFERENCES files(id), + UNIQUE (message_id, file_id) +); +ALTER TABLE threads ADD COLUMN last_read_id INTEGER REFERENCES messages(id); +ALTER TABLE threads ADD COLUMN visibility INT NOT NULL DEFAULT 0; +ALTER TABLE threads ADD COLUMN notification INTEGER NOT NULL DEFAULT 1; + +INSERT INTO users VALUES(3,'charlie@example.org',NULL,NULL,3); +INSERT INTO users VALUES(4,'room@conference.example.com/bob',NULL,NULL,3); +INSERT INTO users VALUES(5,'bob@example.com',NULL,NULL,3); +INSERT INTO users VALUES(6,'alice@example.org',NULL,NULL,3); +INSERT INTO users VALUES(7,'jhon@example.org',NULL,NULL,3); + +INSERT INTO accounts VALUES(3,3,NULL,0,3); +INSERT INTO accounts VALUES(4,6,NULL,0,3); +INSERT INTO accounts VALUES(5,7,NULL,0,3); + +INSERT INTO threads VALUES(1,'another-room@conference.example.com',NULL,NULL,5,1,0,NULL,0,1); +INSERT INTO threads VALUES(2,'room@conference.example.com',NULL,NULL,4,1,0,NULL,0,1); +INSERT INTO threads VALUES(3,'room@conference.example.com',NULL,NULL,3,1,0,NULL,0,1); + +INSERT INTO thread_members VALUES(1,2,4); +INSERT INTO thread_members VALUES(2,2,5); +INSERT INTO thread_members VALUES(3,1,5); + +INSERT INTO messages VALUES(NULL,'43511f76-0eee-11eb-98fc-23b32f642943',1,7,NULL,'Yes this is another room',2,-1,1587854658,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'12c97d94-0eee-11eb-86e0-7fe0e99a74bb',1,5,NULL,'Is this another room?',2,1,1587854658,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'7f21eca6-0eee-11eb-bdfd-5be4cafcdd69',1,7,NULL,'Feel free to speak anything',2,-1,1587854661,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1fa48654-0eed-11eb-9110-b7542262f3bf',2,4,NULL,'Hello everyone',2,1,1587854453,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'40a341d8-0eed-11eb-91be-dbcbdfd6fab6',2,4,NULL,'Good morning',2,1,1587854455,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'96001322-0eed-11eb-b943-ffb19c0eb13a',2,5,NULL,'Hi',2,1,1587854458,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'1587644391694312',2,NULL,NULL,'Is this good?',2,1,1587854459,NULL,0,NULL,NULL); +INSERT INTO messages VALUES(NULL,'d4097d22-0efa-11eb-b349-9317bde881f6',3,3,NULL,'Hello',2,-1,1587854682,NULL,0,NULL,NULL); + +COMMIT; diff --git a/tests/history.c b/tests/history.c index f309aa6..e704fd9 100644 --- a/tests/history.c +++ b/tests/history.c @@ -120,6 +120,9 @@ compare_table (sqlite3 *db, int status; status = sqlite3_prepare_v2 (db, sql, -1, &stmt, NULL); + if (status != SQLITE_OK) + g_message ("%s", sqlite3_errmsg (db)); + if (status != SQLITE_OK) g_warning ("sql: %s", sql); @@ -140,9 +143,58 @@ compare_table (sqlite3 *db, sqlite3_finalize (stmt); } +static void +compare_db_new_columns (sqlite3 *db) +{ + g_assert (HISTORY_VERSION == 4); + + /* TO REMOVE */ + compare_table (db, + "SELECT COUNT (*) FROM (" + "SELECT threads.name,a.username,u.username,threads.encrypted,visibility FROM main.thread_members " + "INNER JOIN main.users AS u ON u.id=thread_members.user_id " + "INNER JOIN main.threads ON threads.id=thread_id " + "INNER JOIN main.accounts ON accounts.id=threads.account_id " + "INNER JOIN main.users As a ON a.id=accounts.user_id " + "UNION " + "SELECT threads.name,a.username,u.username,threads.encrypted,visibility FROM test.thread_members " + "INNER JOIN test.users AS u ON u.id=thread_members.user_id " + "INNER JOIN test.threads ON threads.id=thread_id " + "INNER JOIN test.accounts ON accounts.id=threads.account_id " + "INNER JOIN test.users As a ON a.id=accounts.user_id " + ");", + history_db_get_int (db, "SELECT COUNT(*) FROM main.thread_members;"), + history_db_get_int (db, "SELECT COUNT(*) FROM test.thread_members;")); + + compare_table (db, + "SELECT COUNT (*) FROM (" + "SELECT name FROM main.mime_type " + "UNION " + "SELECT name FROM test.mime_type " + ");", + history_db_get_int (db, "SELECT COUNT(*) FROM main.mime_type;"), + history_db_get_int (db, "SELECT COUNT(*) FROM test.mime_type;")); + + compare_table (db, + "SELECT COUNT (*) FROM (" + "SELECT f.name,f.url,f.path,f.status,f.size FROM message_files " + "INNER JOIN main.messages AS m ON m.id=message_files.message_id " + "INNER JOIN main.files AS f ON f.id=message_files.file_id " + "UNION " + "SELECT f.name,f.url,f.path,f.status,f.size FROM message_files " + "INNER JOIN main.messages AS m ON m.id=message_files.message_id " + "INNER JOIN main.files AS f ON f.id=message_files.file_id " + ");", + history_db_get_int (db, "SELECT COUNT(*) FROM main.message_files;"), + history_db_get_int (db, "SELECT COUNT(*) FROM test.message_files;")); +} + static void compare_history_db (sqlite3 *db) { + sqlite3_stmt *stmt; + int status; + /* Pragma version should match */ g_assert_cmpint (history_db_get_int (db, "PRAGMA main.user_version;"), ==, history_db_get_int (db, "PRAGMA test.user_version;")); @@ -152,6 +204,33 @@ compare_history_db (sqlite3 *db) ==, history_db_get_int (db, "SELECT COUNT(*) FROM test.sqlite_master;")); + status = sqlite3_prepare_v2 (db, "SELECT DISTINCT tbl_name,type FROM main.sqlite_master " + /* A column with 'sqlite' in name is not ours */ + "WHERE NOT instr(name,'sqlite');", -1, &stmt, NULL); + g_assert_cmpint (status, ==, SQLITE_OK); + + while ((status = sqlite3_step (stmt)) == SQLITE_ROW) { + g_autofree char *main_sql = NULL; + g_autofree char *test_sql = NULL; + g_autofree char *sql = NULL; + + sql = g_strdup_printf ("SELECT COUNT (*) FROM (" + "SELECT name,type,\"notnull\",dflt_value,pk FROM pragma_table_info('%s', 'main') " + "UNION " + "SELECT name,type,\"notnull\",dflt_value,pk FROM pragma_table_info('%s', 'test') " + ");", sqlite3_column_text (stmt, 0), sqlite3_column_text (stmt, 0)); + main_sql = g_strdup_printf ("SELECT COUNT(*) FROM pragma_table_info('%s', 'main');", + sqlite3_column_text (stmt, 0)); + test_sql = g_strdup_printf ("SELECT COUNT(*) FROM pragma_table_info('%s', 'test');", + sqlite3_column_text (stmt, 0)); + /* DEBUG */ + /* g_debug ("%d items in '%s' table", history_db_get_int (db, main_sql), sqlite3_column_text (stmt, 0)); */ + compare_table (db, sql, history_db_get_int (db, main_sql), history_db_get_int (db, test_sql)); + } + + sqlite3_finalize (stmt); + g_assert_cmpint (status, ==, SQLITE_DONE); + /* As duplicate rows are removed, SELECT count should match the size of one table. */ compare_table (db, "SELECT COUNT (*) FROM (" @@ -192,13 +271,13 @@ compare_history_db (sqlite3 *db) compare_table (db, "SELECT COUNT (*) FROM (" - "SELECT threads.name,a.username,u.username FROM main.thread_members " + "SELECT threads.name,a.username,u.username,threads.encrypted,visibility FROM main.thread_members " "INNER JOIN main.users AS u ON u.id=thread_members.user_id " "INNER JOIN main.threads ON threads.id=thread_id " "INNER JOIN main.accounts ON accounts.id=threads.account_id " "INNER JOIN main.users As a ON a.id=accounts.user_id " "UNION " - "SELECT threads.name,a.username,u.username FROM test.thread_members " + "SELECT threads.name,a.username,u.username,threads.encrypted,visibility FROM test.thread_members " "INNER JOIN test.users AS u ON u.id=thread_members.user_id " "INNER JOIN test.threads ON threads.id=thread_id " "INNER JOIN test.accounts ON accounts.id=threads.account_id " @@ -219,6 +298,16 @@ compare_history_db (sqlite3 *db) ");", history_db_get_int (db, "SELECT COUNT(*) FROM main.messages;"), history_db_get_int (db, "SELECT COUNT(*) FROM test.messages;")); + compare_table (db, + "SELECT COUNT (*) FROM (" + "SELECT f.name,f.url,f.path,mime.name,f.status,f.size FROM main.files as f " + "LEFT JOIN main.mime_type as mime ON f.mime_type_id=mime.id " + "UNION " + "SELECT f.name,f.url,f.path,mime.name,f.status,f.size FROM test.files as f " + "LEFT JOIN test.mime_type as mime ON f.mime_type_id=mime.id" + ");", + history_db_get_int (db, "SELECT COUNT(*) FROM main.files;"), + history_db_get_int (db, "SELECT COUNT(*) FROM test.files;")); } static Message * @@ -313,6 +402,28 @@ new_message (const char *account, chatty_message_set_files (message->message, g_list_append (NULL, file)); } + /* test with some random files for MMS */ + if (type == CHATTY_MESSAGE_MMS) { + GList *files = NULL; + guint i; + + i = g_random_int_range (2, 12); + g_debug ("files to add: %u", i); + + for (; i > 0; i--) { + g_autofree char *uid = NULL; + ChattyFileInfo *file; + + uid = g_uuid_string_random (); + file = g_new0 (ChattyFileInfo, 1); + file->url = g_strdup_printf ("http://example.com/some-file/%s", uid); + file->size = g_random_int_range (1000, 5000); + + files = g_list_append (files, file); + } + chatty_message_set_files (message->message, files); + } + message->account = g_strdup (account); message->who = g_strdup (buddy); message->what = g_strdup (msg_text); @@ -349,6 +460,7 @@ compare_message (Message *message, ChattyMessage *chatty_message) { ChattyMsgType type; + GList *files; if (message == NULL) g_assert_null (chatty_message); @@ -360,19 +472,22 @@ compare_message (Message *message, if (type == CHATTY_MESSAGE_HTML) type = CHATTY_MESSAGE_HTML_ESCAPED; - if (type != CHATTY_MESSAGE_FILE && - type != CHATTY_MESSAGE_IMAGE && - type != CHATTY_MESSAGE_VIDEO && - type != CHATTY_MESSAGE_AUDIO) - g_assert_cmpstr (message->what, ==, chatty_message_get_text (chatty_message)); + g_assert_cmpstr (message->what, ==, chatty_message_get_text (chatty_message)); g_assert_cmpstr (message->uuid, ==, chatty_message_get_uid (chatty_message)); g_assert_cmpint (message->when, ==, chatty_message_get_time (chatty_message)); g_assert_cmpint (message->direction, ==, chatty_message_get_msg_direction (chatty_message)); g_assert_cmpint (type, ==, chatty_message_get_msg_type (chatty_message)); - compare_file (g_list_nth_data (chatty_message_get_files (chatty_message), 0), - g_list_nth_data (chatty_message_get_files (message->message), 0)); compare_file (chatty_message_get_preview (chatty_message), chatty_message_get_preview (message->message)); + + files = chatty_message_get_files (chatty_message); + for (int i = g_list_length (files) - 1; i >= 0; i--) { + GList *expected = NULL; + + expected = chatty_message_get_files (message->message); + g_assert (expected); + compare_file (g_list_nth_data (files, i), g_list_nth_data (expected, i)); + } } static void @@ -868,7 +983,7 @@ test_history_raw_message (void) add_message (history, msg_array, account, room, who, uuid, "geo:51.5008,0.1247", when + 2, CHATTY_MESSAGE_LOCATION, CHATTY_DIRECTION_IN); add_message (history, msg_array, account, room, who, uuid, - "And one more", when + 3, CHATTY_MESSAGE_TEXT, CHATTY_DIRECTION_IN); + "And one more", when + 3, CHATTY_MESSAGE_MMS, CHATTY_DIRECTION_IN); g_ptr_array_unref (msg_array); /* Test deletion */ @@ -936,7 +1051,6 @@ test_value (ChattyHistory *history, g_assert_cmpstr (uuid, ==, (char *)sqlite3_column_text (stmt, 1)); g_assert_cmpstr (message, ==, (char *)sqlite3_column_text (stmt, 2)); g_assert_cmpint (direction, ==, sqlite3_column_int (stmt, 3)); - g_debug ("%s %s", sqlite3_column_text (stmt, 4), sqlite3_column_text (stmt, 5)); g_assert_cmpstr (account, ==, (char *)sqlite3_column_text (stmt, 4)); if (direction == -1) @@ -1049,7 +1163,7 @@ test_history_migration_db (void) sqlite3 *db = NULL; int status; - if (g_str_has_suffix (name, "v3.db")) + if (g_str_has_suffix (name, "v4.db")) continue; g_assert_true (g_str_has_suffix (name, "sql")); @@ -1067,7 +1181,7 @@ test_history_migration_db (void) sqlite3_close (db); /* Export migrated version sql file */ - expected_file = g_strdelimit (g_strdup (name), "012", '3'); + expected_file = g_strdelimit (g_strdup (name), "0123", '4'); export_sql_file (path, expected_file, &db); /* Open history with old db, which will result in db migration */ @@ -1086,6 +1200,7 @@ test_history_migration_db (void) g_assert_cmpint (status, ==, SQLITE_OK); compare_history_db (db); + compare_db_new_columns (db); sqlite3_close (db); } } diff --git a/tests/meson.build b/tests/meson.build index a5d1f80..c995528 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -25,6 +25,7 @@ test_items = [ 'matrix-utils', 'message-text-item', 'mm-account', + 'sms-uri', ] foreach item: test_items diff --git a/tests/message-text-item.c b/tests/message-text-item.c index 9603d86..54cbf78 100644 --- a/tests/message-text-item.c +++ b/tests/message-text-item.c @@ -46,6 +46,19 @@ test_message_text_markup (void) "www.gnu.org " "www.fsf.org " }, + { + "www.puri.sm\n", + "www.puri.sm\n" + }, + { + "www.puri.sm\nwww.gnu.org", + "www.puri.sm\n" + "www.gnu.org" + }, + { + "www.puri.sm, ", + "www.puri.sm, " + }, { "file:///home/user/good&bad-file.png ", "" diff --git a/tests/mm-account.c b/tests/mm-account.c index 896018b..30d19da 100644 --- a/tests/mm-account.c +++ b/tests/mm-account.c @@ -106,7 +106,7 @@ test_mm_account_new (void) account = chatty_mm_account_new (); g_assert_true (CHATTY_IS_MM_ACCOUNT (account)); - g_assert_cmpstr (chatty_item_get_username (CHATTY_ITEM (account)), ==, "SMS"); + g_assert_cmpstr (chatty_item_get_username (CHATTY_ITEM (account)), ==, "invalid-0000000000000000"); g_assert_cmpint (chatty_item_get_protocols (CHATTY_ITEM (account)), ==, CHATTY_PROTOCOL_MMS_SMS); chat_list = chatty_mm_account_get_chat_list (account); diff --git a/tests/sms-uri.c b/tests/sms-uri.c new file mode 100644 index 0000000..da02b34 --- /dev/null +++ b/tests/sms-uri.c @@ -0,0 +1,123 @@ +/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ +/* sms-uri.c + * + * Copyright 2021 Purism SPC + * + * Author(s): + * Mohammed Sadiq + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#undef NDEBUG +#undef G_DISABLE_ASSERT +#undef G_DISABLE_CHECKS +#undef G_DISABLE_CAST_CHECKS +#undef G_LOG_DOMAIN + +#include "chatty-sms-uri.c" + +typedef struct data { + char *uri; + char *body; + char *numbers; + guint n_numbers; + gboolean valid; + gboolean can_send; + char *country; +} data; +data array[] = { + { "sms:123", "", "123", 1, TRUE, TRUE}, + /* If there are 2+ numbers, with atleast one invalid, the URI is invalid + * because this can't happen in an incoming nor outgoing message + */ + { "sms:( BCD),123", "", "( BCD),123", 2, FALSE, FALSE}, + /* A URI with exactly one non numeric sender is considered valid + * As it can happen in incoming messages, but in that case, body + * should be empty as a message can't be send to the given number + */ + { "sms:( BCD)", "", "( BCD)", 1, TRUE, FALSE}, + { "sms:DL-ABC?body=some body", "", "DL-ABC", 1, FALSE, FALSE}, + { "sms://+919995112233", "", "+919995112233", 1, TRUE, TRUE}, + { "sms://+919995112233?body=I'm busy", "I'm busy", "+919995112233", 1, TRUE, TRUE}, + { "sms://123,453?body=a ചെറിയ test", "a ചെറിയ test", "123,453", 2, TRUE, TRUE}, + { "sms://453,123,145,123,453?body=HELP", "HELP", "123,145,453", 3, TRUE, TRUE}, + { "sms://453,123,145,123,453?body=HELP%20me", "HELP me", "123,145,453", 3, TRUE, TRUE}, + { "sms:9995 123 123?body=Call me later", "Call me later", "+919995123123", 1, TRUE, TRUE, "IN"}, + { "sms:+919995 123 123?body= before and after ", " before and after ", "+919995123123", 1, TRUE, TRUE, "US"}, + { "sms:00919995 123 123?body=%26%20is ampersand", "& is ampersand", "+919995123123", 1, TRUE, TRUE, "GB"}, + { "sms:(213) 321-9876,+12133219876?body=Test", "Test", "+12133219876", 1, TRUE, TRUE, "US"}, + /* '&' is used to separate arguments, so everything from '&' is not a part of body here, + * '&' can be incuded in body with '%26' */ + { "sms:123?body=is & ampersand?", "is ", "123", 1, TRUE, TRUE}, +}; + +static void +test_mm_sms_uri (void) +{ + ChattySettings *settings; + ChattySmsUri *uri; + + settings = chatty_settings_get_default (); + + uri = chatty_sms_uri_new (NULL); + + for (guint i = 0; i < G_N_ELEMENTS (array); i++) { + g_autofree char *numbers_str = NULL; + GPtrArray *numbers; + + if (array[i].country) + chatty_settings_set_country_iso_code (settings, array[i].country); + + chatty_sms_uri_set_uri (uri, array[i].uri); + g_assert_cmpint (chatty_sms_uri_is_valid (uri), ==, array[i].valid); + g_assert_cmpint (chatty_sms_uri_can_send (uri), ==, array[i].can_send); + g_assert_cmpstr (chatty_sms_uri_get_body (uri), ==, array[i].body); + + numbers = chatty_sms_uri_get_numbers (uri); + g_assert_cmpint (numbers->len, ==, array[i].n_numbers); + g_ptr_array_set_size (numbers, numbers->len + 1); + numbers_str = g_strjoinv (",", (char **)numbers->pdata); + g_ptr_array_set_size (numbers, numbers->len - 1); + + g_assert_cmpstr (chatty_sms_uri_get_numbers_str (uri), ==, array[i].numbers); + g_assert_cmpstr (numbers_str, ==, array[i].numbers); + } + + g_assert_finalize_object (uri); +} + +static void +test_mm_sms_uri_new (void) +{ + ChattySmsUri *uri; + + uri = chatty_sms_uri_new (array[0].uri); + g_assert_finalize_object (uri); + + uri = chatty_sms_uri_new (array[0].uri); + g_assert_cmpint (chatty_sms_uri_is_valid (uri), ==, array[0].valid); + g_assert_cmpstr (chatty_sms_uri_get_body (uri), ==, array[0].body); + g_assert_cmpstr (chatty_sms_uri_get_numbers_str (uri), ==, array[0].numbers); + g_assert_cmpint (chatty_sms_uri_can_send (uri), ==, array[0].can_send); + + chatty_sms_uri_set_uri (uri, array[1].uri); + g_assert_cmpint (chatty_sms_uri_is_valid (uri), ==, array[1].valid); + g_assert_cmpstr (chatty_sms_uri_get_body (uri), ==, array[1].body); + g_assert_cmpint (chatty_sms_uri_can_send (uri), ==, array[1].can_send); + g_assert_finalize_object (uri); +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_setenv ("GSETTINGS_BACKEND", "memory", TRUE); + + g_test_add_func ("/mm/sms-uri/new", test_mm_sms_uri_new); + g_test_add_func ("/mm/sms-uri", test_mm_sms_uri); + + return g_test_run (); +} -- GitLab From 3192057fa7a6d78d09140f412d2c15408896dc2e Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Wed, 26 Jan 2022 17:28:47 +0100 Subject: [PATCH 2/6] d/control: Add itstool and dbus-x11 as build dependency This is needed for the newly added messaging-text-items test --- debian/control | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/control b/debian/control index c562ac6..9b68986 100644 --- a/debian/control +++ b/debian/control @@ -7,10 +7,12 @@ Uploaders: Build-Depends: appstream, appstream-util, + dbus-x11, debhelper-compat (= 13), desktop-file-utils, gsettings-desktop-schemas-dev, help2man, + itstool, libebook-contacts1.2-dev, libebook1.2-dev, libfeedback-dev, -- GitLab From 1f911283547ae8318b0168d565a1cd1081c0824a Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Wed, 26 Jan 2022 17:49:07 +0100 Subject: [PATCH 3/6] d/rules: Set NO_AT_BRIDGE=1 for tests --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 2c8cda1..8fdb265 100755 --- a/debian/rules +++ b/debian/rules @@ -18,4 +18,4 @@ override_dh_installman: # otherwise the tests running gtk-builder-tool to validate # .ui files might fail override_dh_auto_test: - LANGUAGE=C.UTF-8 xvfb-run dh_auto_test + NO_AT_BRIDGE=1 LANGUAGE=C.UTF-8 xvfb-run dh_auto_test -- GitLab From dd4b85d49b0944d9b20739c89dae3d9e9b00375b Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Wed, 26 Jan 2022 17:51:45 +0100 Subject: [PATCH 4/6] Document and release 0.6.0-1 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index a96b5c4..b208a99 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +chatty (0.6.0-1) unstable; urgency=medium + + * New upstream version 0.6.0 (Closes: #1002241) + * d/control: Add itstool and dbus-x11 as build dependency + * d/rules: Set NO_AT_BRIDGE=1 for tests + + -- Evangelos Ribeiro Tzaras Wed, 26 Jan 2022 17:51:14 +0100 + chatty (0.5.0~beta3-1) experimental; urgency=medium * d/control: Drop purple-mm-sms from recommends -- GitLab From ae1cfef568015f54a807c6f6bb2974013b531198 Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Thu, 27 Jan 2022 19:33:27 +0100 Subject: [PATCH 5/6] d/patches: Reenable message-text-item test This should be fixed by the added build dependencies --- ...tests-Disable-message-text-item-test.patch | 28 ------------------- debian/patches/series | 1 - 2 files changed, 29 deletions(-) delete mode 100644 debian/patches/0002-tests-Disable-message-text-item-test.patch diff --git a/debian/patches/0002-tests-Disable-message-text-item-test.patch b/debian/patches/0002-tests-Disable-message-text-item-test.patch deleted file mode 100644 index f846d89..0000000 --- a/debian/patches/0002-tests-Disable-message-text-item-test.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Evangelos Ribeiro Tzaras -Date: Sat, 11 Dec 2021 16:07:25 +0100 -Subject: tests: Disable message-text-item test - -Running the test fails (sometimes?) like: - -dconf-WARNING **: 17:59:34.842: failed to commit changes to dconf: -Failed to execute child process ?dbus-launch? (No such file or directory) - -Test failure probably has to do with the build environment as local -builds run fine (both in Bookworm and Byzantium). ---- - tests/meson.build | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/meson.build b/tests/meson.build -index a5d1f80..5b4698b 100644 ---- a/tests/meson.build -+++ b/tests/meson.build -@@ -23,7 +23,7 @@ test_items = [ - 'matrix-db', - 'matrix-enc', - 'matrix-utils', -- 'message-text-item', -+# 'message-text-item', - 'mm-account', - ] - diff --git a/debian/patches/series b/debian/patches/series index 3cd3ba5..f373ea6 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ 0001-notification-Remove-glib-version-check-guard.patch -0002-tests-Disable-message-text-item-test.patch -- GitLab From a7ff5682d428a9b230a4c99f9a43a79a5d018700 Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Thu, 27 Jan 2022 19:38:11 +0100 Subject: [PATCH 6/6] Document and release 0.6.0-1pureos1 --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8dd394b..53cb77d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +chatty (0.6.0-1pureos1) byzantium; urgency=medium + + * d/patches: Reenable message-text-item test + * Upload to byzantium + + -- Evangelos Ribeiro Tzaras Thu, 27 Jan 2022 19:35:03 +0100 + chatty (0.6.0-1) unstable; urgency=medium * New upstream version 0.6.0 (Closes: #1002241) -- GitLab