diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000000000000000000000000000000000..18dd2b3f8cc45034a0d9a0e9ac715e084c659a07 --- /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 ed6630e799707b11fc4ca24a475ee7ab8454d7b8..53cb77d5e9cc2c399c27c2b49c91fa3ce094b983 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +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) + * 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-1pureos1) byzantium; urgency=high * d/patches: Refresh patches diff --git a/debian/control b/debian/control index ff525435b2fbb0fbbbffed73b101d6994a5bb074..3320ded78ef6e8b2789b566bedc34e168eb8e3eb 100644 --- a/debian/control +++ b/debian/control @@ -8,10 +8,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, 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 f846d898fc6bbd2b66b5ae6f9da8d90429a345b8..0000000000000000000000000000000000000000 --- 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 3cd3ba5abd509ebbe86fc2ab6d5af12707e6d22c..f373ea6e745a3ca27236c019af7836530c5c685a 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 diff --git a/debian/rules b/debian/rules index 2c8cda1721b47c22ca5961a9355c6597e48f1da2..8fdb26583747ae12341fa93884afafeaa0248ec9 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 diff --git a/meson.build b/meson.build index deae3e041215b77aeb71bf178509bab87c43bc2f..9733f39c921048872533e0eda89b5cd17a8dce7a 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 33f802ae50f3d15de0af8a121c9ab6db5cd85e71..746b003ad6c184536acf18d3cec1461001654cec 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 5529de450c318151fd73f54d8cf59b76ff38df17..6cbabebf3f24c9170c34b99fb539da26c4825720 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 7d3beae1a1f8a15c9914c69309babc27a829ec4c..918b01e740a6fad5f6f56f3cf91c6d9e182ae379 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 34238dd771ab9eb5ab6adfd183e1796f18af6a95..228ce822dbd23d66387aa893ff61192242eba4d3 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 521ddb2c1d57e9e258292f217f333879026fc76b..6da2f7374f3c7177126e7a13a935b119119e381b 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 556d6f89d11d80b7ea47524698cee4afa13f94db..d3d48fa66846bed674ccde40c7228d69e6ea8cd9 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 ba6b33ca466795a10fccf092da99e52a27743bba..37ce1451da34c7755eb44f1b440f83f8ad900dcc 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 4e97115bd29f2a806aafb6f4fac0772ffd9c627a..ef3ea0f3d94b8834519d6cb1afe0145a38b361d8 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 9c729932fcdb017e2f40ec3b070296a2d1309b8b..11a56ccc7f289b6f7c6c7d2a9528ccc4c830916c 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 1ffdfb300bbcfae62c9af4efb26707a8040f29fb..ce2afaa6dbeaa5a9eb504e349c8ab4631351744e 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 657d7d03bc55019ce7ad6f421f9707733c96a02d..2ac607e5d8b906805eb07e45dad9cc0a0be4ae19 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 0000000000000000000000000000000000000000..a8681435d27d42fe942e6bc5ea0eaaac5dbe325d --- /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 0000000000000000000000000000000000000000..0b25a2e6c501f0afac25eaebf5f98dd2bdb9fd9a --- /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 2126217a1222f241d71fd96d7b321550858090e2..93cffb4884d57fcb56b83e02226602c9dc0e0054 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 393189cf3d846367df34db6807b79a103406b152..27efab804bb60de6900e1fbc0264ca39209e3d97 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 a3cf108ffe937c6fdf77960919147df51ffe7f6a..2a7fb0e49998d34f011b9fc9df11bd85096efdd6 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 bb7e3637446bf66c4a9880abd6b3d8dfb1780cfd..b826549ed8813d7660dd72e43181439001de2df7 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 8ed362cfbc4b9e734781d907362389515e189738..3868ecb064df89cea54be15d00af314e95618ebc 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 3f8b777b349eeaa364cdf4da1ed413cc203eac1c..47e690ae941df948209a30705b25c18e04b7e8fd 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 9ee9db3d9f159a65d6acccf3b8546aff0bcbab6b..3097d75ffd19ebbe72aa0ccb2b6bd50161ec6a1d 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 f40141a7df09cd23fa42aaca973b2558e1957515..f7ce57539ea6541928e2db196d2e3089a8c38153 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 b096cd954373d89564fd39d875f0f06de4c3be69..db1e192d16cbe94d3e1a7c502ad8fa1ebb8ae89f 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 065e6920651bbd45bf4a0598b0908380035338b7..1fddffb1541d89ca9e39a135973afe795e1ede60 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 ab07b08378b82de41fe16e0e9cc312b0a6b495ee..b409a00c8604ce3a8499ae9c4e610bbc0b707ca9 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 a34e08517dbc7db7ee2f12150a4146246b5b10a6..583e4ed7cc649b1bef5069787266538fe7749547 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 7420292b6ece3063eda0d71d3ac7c98a5b4be7a7..25122d72387cb0856fe8d3d80c92e99a95f50026 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 1bf8b36b1cb82858d045dd26e708dc9ef1dccada..b9f8a8db2cb9a35ecac1de54bc269ef83b652c21 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 7668747f1f505a8d96c1f4e4d174b1bbf63ef0ff..2fb6a343af85d76b503a7ef143457154c08b0c20 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 e9b47b2fc5ac215b04f0a5a40be2b79cf68621d0..806ae61ab79bef59dd175d0348ae440f07d93a59 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 c0dd950e096e35719b53c3fc4dd8a1ff85c9b322..2a5f3e92681771b155bf51588a4fe250e6adddd9 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 3499a55eec85c750010185ba737707ed772309a4..5fe5cedf39db559c9ae65adf3b42b7aee8472f64 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 23bb92553c94cba254eb4041a06fa71b67ecef60..54cc9a611bc05901f22e1bebf88bbe282404ec7b 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 0c3e44af33a5ec357ec29e540c6a378882f2cebf..e6bd91a77e8d13a43f9e3d2ee98f05db71b674f9 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 203cb6f96b8a48b2a74f5473da8fe4db37988c05..62b184180fb481d3c0c02e893ac9fb6b6ae450a6 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 3ffbc3d39153e39ba65427b8406320afb92d9d41..d0e57319929fa6484fbde49f445c5c6fa6e567f8 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 4a91ccea90dd2279108258f278121305986320eb..05e8c9f9afadac21516b5a37340c2ab581496554 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 d76cd1f7fe5000bac796e2cbd740a236d0dc6397..be62794c9342975cf13ac3bfa045581100d4cf9e 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 1402c46dbf4a9889b96809cd8531c4739f45e2a3..fc71c32fc3ddee841e4bed0d2aee10c800f50854 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 cc5fd4357b9c06d5e33c630560b10fd6a57c3b89..9da694e81b49053f70fcc4dd86f3ff0b92edc311 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 0050f742408e324d796645550d546481eb7ef38d..9bd70a323ba0d5694b520fc26acf9e65db725e98 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 f9ee14f6fff906329c1496b3878e89b43981cd2e..2ca5a1b0217089b2306501df1350ee5fe33338d0 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 5642fe459258885843c657276523bd55a82f1e07..3076b6fa7ec50bef4771aa03c7b2941645c68189 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 0000000000000000000000000000000000000000..6259702d11aa22274de643106e0ca146d7c14668 --- /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 0000000000000000000000000000000000000000..8a64059c983f73627b5eb59a941452f10b817024 --- /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 6e5738fb3f9e0c9a3667ff1a25c4685034b49cdd..48e7be85d3abf7e2aa50fb57545afed9802fc7a7 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 0000000000000000000000000000000000000000..b15ccfd310f37e79c1bf25142c15f9eae928aaab --- /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 e59970a523ffa35efc1ab56e9ea8bc0986216a59..04893bb452d67cd003062d44ddec60e88f65ccd6 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 f94a2e715d7cc6579bb17e3f6bff939c419e03ca..4c4d4a20f737eaa063bb7d5b44c05e5f9244d744 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 979e67b11dbeeacd1af9cc6861388b727acdcad9..da178b16c87dfc186d96f3f2d6ef07d1b8c2f9d4 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 3d3962c6745dac138cf3153a6c978084dbb2f40e..99ef0ee89435a1f7516bb911c409ec8e456a20ab 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 0000000000000000000000000000000000000000..38c8f9e2fd0e0460f51fea8f3798044111c871d4 --- /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 0000000000000000000000000000000000000000..24e9d91003b76e1e88abaff6f6c7f3f9790149f7 --- /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 0000000000000000000000000000000000000000..568c9f656bc5f009636dba939b1fa650108db04a --- /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 0000000000000000000000000000000000000000..03ed1b6bea8f7d43772f9520b85ebe8b65cca5cf --- /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 0000000000000000000000000000000000000000..baeac9100b7d01d8dd6a79fad370b232ef25cd3a --- /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 0000000000000000000000000000000000000000..fdbaeef4e6b6c011dde2d22a8a92173ca2b22992 --- /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 0000000000000000000000000000000000000000..463a5af7c86cc2708e241f14b31e168c8c7e9b0f --- /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 0000000000000000000000000000000000000000..0e6264578dc6ef1302534b7de378cfaaa8455c88 --- /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 0000000000000000000000000000000000000000..b4795fbd37008d3a05e7fe3f29da0e2f632f03f3 --- /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 0000000000000000000000000000000000000000..3302234345687a25e552c1af2ef0dd161c25464e --- /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 0000000000000000000000000000000000000000..6801da15ab28d54828145b2ea9818a07c165d923 --- /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 f309aa63eed4a6d31b178bc7385cfd083f93f6a0..e704fd9130cb6e7b2176ec150a7fb94b51314fd8 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 a5d1f806d031bf75ed42cf287509ddd2682a0b3a..c995528d76d4755a33140e0de1391e708e449ae7 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 9603d86f611e9a8f7981d80dde945a360a68dd74..54cbf789947a7b3d3e19c208d642cce5d81264ce 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 896018b6dc7568183b9186fa985ab7c4be466ba7..30d19da0e271e9cd5bf280c60728cb693c85e2dc 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 0000000000000000000000000000000000000000..da02b34acdb5a46e49bcbaf3586b71ff3cacfc95 --- /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 (); +}