diff --git a/BUILDING.md b/BUILDING.md
index ea58e1d15..ebd1ea464 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -27,12 +27,10 @@ install the [dcrpcgen tool](https://github.com/chatmail/dcrpcgen)
then generate the `schema.json` file:
```
-# install deltachat-rpc-server program:
-cargo install --path ./jni/deltachat-core-rust/deltachat-rpc-server
-# check the version of core matches:
-deltachat-rpc-server --version
-# generate the schema:
-deltachat-rpc-server --openrpc > schema.json
+# in the root of the project:
+cd ./jni/deltachat-core-rust/deltachat-rpc-server
+cargo run -- --openrpc > ../../../schema.json
+cd ../../../
```
then pass the schema file to the `dcrpcgen` tool to generate the
diff --git a/CHANGELOG-upstream.md b/CHANGELOG-upstream.md
index 610d56e83..91ea6cd92 100644
--- a/CHANGELOG-upstream.md
+++ b/CHANGELOG-upstream.md
@@ -3,7 +3,16 @@
## Unreleased
* Change color of links in text messages
+* Allow to withdraw channel invite links and QR codes
+* Do not show "1 member" when the process of joining the group is not finished
+* Improve handling of video recoding
+* Send .webm videos as file, they are not supported by all platforms
* Tweak advanced section and wording of some advanced options
+* Fix: avoid crash in push notifications handling
+* Expose new "Multi-device mode" option instead of "Delete from server" for chatmail profiles
+* Opened in-chat apps got a 'About Apps' menu item
+* Avoid gray avatar on profile creation
+* Update to core 2.27.0
## v2.25.0
2025-11
diff --git a/flake.lock b/flake.lock
index 290045b63..457cd5257 100644
--- a/flake.lock
+++ b/flake.lock
@@ -138,11 +138,11 @@
"nixpkgs": "nixpkgs_3"
},
"locked": {
- "lastModified": 1756197489,
- "narHash": "sha256-S16rPaBH1TnMbDyL5NlGSJcYd7wPlOEWTStdBDL7BHw=",
+ "lastModified": 1763347184,
+ "narHash": "sha256-6QH8hpCYJxifvyHEYg+Da0BotUn03BwLIvYo3JAxuqQ=",
"owner": "oxalica",
"repo": "rust-overlay",
- "rev": "8ec04f46f1edeeed3f870da62191745b93975da7",
+ "rev": "08895cce80433978d5bfd668efa41c5e24578cbd",
"type": "github"
},
"original": {
diff --git a/jni/dc_wrapper.c b/jni/dc_wrapper.c
index f2fa8f0c2..9a8bc7273 100644
--- a/jni/dc_wrapper.c
+++ b/jni/dc_wrapper.c
@@ -231,6 +231,12 @@ JNIEXPORT jboolean Java_com_b44t_messenger_DcAccounts_backgroundFetch(JNIEnv *en
}
+JNIEXPORT void Java_com_b44t_messenger_DcAccounts_stopBackgroundFetch(JNIEnv *env, jobject obj)
+{
+ dc_accounts_stop_background_fetch(get_dc_accounts(env, obj));
+}
+
+
JNIEXPORT jint Java_com_b44t_messenger_DcAccounts_migrateAccount(JNIEnv *env, jobject obj, jstring dbfile)
{
CHAR_REF(dbfile);
diff --git a/jni/deltachat-core-rust b/jni/deltachat-core-rust
index 21dec8e4b..810c40435 160000
--- a/jni/deltachat-core-rust
+++ b/jni/deltachat-core-rust
@@ -1 +1 @@
-Subproject commit 21dec8e4b64a43f4087b93b44a54d4131f0784cc
+Subproject commit 810c40435f49a1dba0e8afd08f0b4caf967268d0
diff --git a/scripts/rust-toolchain b/scripts/rust-toolchain
index b7844a6ff..8d3947429 100644
--- a/scripts/rust-toolchain
+++ b/scripts/rust-toolchain
@@ -1 +1 @@
-1.86.0
+1.91.1
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 684131cd8..c6a3ba9ba 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -233,7 +233,7 @@
android:theme="@style/TextSecure.LightNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
-
-
+
diff --git a/src/main/assets/help/de/help.html b/src/main/assets/help/de/help.html
index 5aadc975a..8173cc86d 100644
--- a/src/main/assets/help/de/help.html
+++ b/src/main/assets/help/de/help.html
@@ -122,7 +122,7 @@ Sie können sich anonym bei einer Vielzahl von
Delta Chat is a reliable, decentralized and secure messaging app,
+
Delta Chat is a reliable, decentralized and secure instant messaging app,
available for mobile and desktop platforms.
-
Delta Chat feels like Whatsapp or Telegram but you can also use and regard it as an e-mail app.
-You can signup anonymously to a variety of interoperable chatmail servers
-which are minimal e-mail servers optimized for fast and secure operations.
-Or you may use classic e-mail servers and an existing e-mail account
-in which case Delta Chat acts as an e-mail app.
-
-
-
-
-
-
- How can I find people to chat with?
-
-
-
-
-
To securely setup contact with others scan an invite QR code
-or share an invite link.
-This is required when using a (default) chatmail-based chat profile
-because chatmail servers reject un-encrypted outgoing messages.
-
-
If you create a chat profile with a classic e-mail address
-you may manually create a contact if you know their e-mail address
-and then write a message to them
-even if the recipient is not using Delta Chat.
-
-
-
-
- What are the advantages of Delta Chat compared to other messengers?
-
-
-
-
-
Anonymous chat profiles with fast, secure and interoperable chatmail servers
-which offer instant Push Notifications for iOS and Android devices.
+
Instant creation of private chat profiles
+with secure and interoperable chatmail relays
+that offer instant message delivery, and Push Notifications for iOS and Android devices.
-
Pervasive multi-profile and multi-device support on all platforms.
Free and Open Source software, both app and server side,
+built on Internet Standards.
-
+
- What if I expect a message from someone I didn’t write to in the past?
+ How can I find people to chat with?
-
If a message comes from an unknown contact, it appears as a request.
+
First, note that Delta Chat is a private messenger.
+There is no public discovery, you decide about your contacts.
+
+
+
+
If you are face to face with your friend or family,
+tap the QR Code icon
+on the main screen.
+Ask your chat partner to scan the QR image
+with their Delta Chat app.
+
+
+
For a remote contact setup,
+from the same screen,
+click “Copy” or “Share” and send the invite link
+through another private chat.
+
+
+
+
Now wait while connection gets established.
+
+
+
+
If both sides are online, they will soon see a chat
+and can start messaging securely.
+
+
+
If one side is offline or in bad network,
+the ability to chat is delayed until connectivity is restored.
+
+
+
+
Congratulations!
+You now will automatically use end-to-end encryption with this contact.
+If you add each other to groups, end-to-end encryption will be established among all members.
Your friends may share your contact with other friends, this appears as a request.
@@ -201,6 +200,20 @@ receive messages from this person, consider blocking them.
+
+
+
+ How can I put two of my friends in contact with each other?
+
+
+
+
+
Attach the first contact to the chat of the second using Attachment Button → Contact.
+You can also add a little introduction message.
+
+
The second contact will receive a card then
+and can tap it to start chatting with the first contact.
+
@@ -211,7 +224,8 @@ receive messages from this person, consider blocking them.
-
Yes. Images, videos, files, voice messages etc. are handled as usual.
+
Yes. Images, videos, files, voice messages etc. can be sent using the Attachment-
+or Voice Message buttons
For performance, images are optimized and sent at a smaller size by default, but you can send it as a “file” to preserve the original.
@@ -228,16 +242,14 @@ receive messages from this person, consider blocking them.
A profile is a name, a picture and some additional information for encrypting messages.
A profile lives on your device(s) only
-and uses a chatmail or a classic e-mail server to transport messages.
+and uses the server only to relay messages.
On first installation of Delta Chat a first profile is created.
Later, you can tap your profile image in the upper left corner to Add Profiles
or to Switch Profiles.
-
You may want to use separate profiles for political, family or work related activities,
-or e. g. for a dedicated “spam-profile” with which you register at websites and platforms
-that tend to cause unsolicited messages (“spam”) sooner or later.
+
You may want to use separate profiles for political, family or work related activities.
@@ -253,35 +265,25 @@ that tend to cause unsolicited messages (“spam”) sooner or later.
You can add a profile picture in your settings. If you write to your contacts
or add them via QR code, they automatically see it as your profile picture.
-
-
-
Contacts who don’t use Delta Chat do not see the profile picture
-(however, of course, they can install Delta Chat :)
For privacy reasons, no one sees your profile picture until you write a
message to them.
-
-
Your profile picture isn’t sent with every message, but regularly enough that
-your contacts will re-receive your profile picture, even if they add a new
-device.
-
- Can I set a Bio/Signature/Status/Motto with Delta Chat?
+ Can I set a Bio/Status with Delta Chat?
Yes,
you can do so under Settings → Profile → Bio.
-Your contacts who use Delta Chat will see it
-when they view your contact details.
-Moreover, it will appear as a classic e-mail signature.
+Once you sent a message to a contact,
+they will see it when they view your contact details.
You can sometimes see a green dot
next to the avatar of a contact.
-It means they were recently seen in the last 10 minutes:
+It means they were recently seen by you in the last 10 minutes,
+e.g. because they messaged you or sent a read receipt.
-
-
either because they messaged you directly,
-
because they wrote something to a group you are both a member of,
-
because they sent you a read receipt for a message you wrote,
-
because they edit or delete a message in a chat shared with you,
-
or because they use an app in a chat shared with you.
-
-
-
So this is not a real time online status -
-and if someone doesn’t answer right away even though they seem to be online,
-don’t worry and give them some space :)
-
-
On the other hand, others will not always “see that you are online”.
-If you have turned off read receipts,
-they will not see the green dot
-until one of the above conditions are met.
+
So this is not a real time online status
+and others will as well not always see that you are “online”.
@@ -385,13 +374,23 @@ until one of the above conditions are met.
-
One tick means that the message was sent successfully to your provider.
-
Two ticks mean that at least one recipient’s device
-reported back to having received the message.
-
Recipients may have disabled read-receipts,
-so even if you see only one tick, the message may have been read.
-
The other way round, two ticks do not automatically mean
-that a human has read or understood the message ;)
+
+
One tick
+means that the message was sent successfully to your provider.
+
+
+
Two ticks
+mean that at least one recipient’s device
+reported back to having received the message.
+
+
+
Recipients may have disabled read-receipts,
+so even if you see only one tick, the message may have been read.
+
+
+
The other way round, two ticks do not automatically mean
+that a human has read or understood the message ;)
+
@@ -441,9 +440,9 @@ of deleting the messages
after the selected time span.
The time span begins
when the receiver first sees the message in Delta Chat.
-The messages are deleted
-both in each email account on the server,
-and in the app itself.
+The messages are deleted both,
+on the servers,
+and in the apps itself.
Note that you can rely on disappearing messages
only as long as you trust your chat partners;
@@ -452,36 +451,29 @@ or otherwise save, copy or forward messages before deletion.
Apart from that,
if one chat partner uninstalls Delta Chat,
-the messages will not get deleted from their email account.
-They will most likely also not be decryptable anymore
-(as long as they were encrypted in the first place).
+the (anyway encrypted) messages may take longer to get deleted from their server.
-
+
- What happens if I turn on “Delete old messages from server”?
+ How does “Delete messages from server” work?
-
By default, Delta Chat stores all messages locally on your device.
-If you e.g. want to save storage space at your mail provider,
-you can configure Delta Chat
-to delete old already-received messages on the server automatically.
-They still remain on your device until you delete them there, too.
+
If you are using only one device,
+messages are deleted At once from the server.
-
To turn it on, go to Delete Old Messages → Delete Messages from Server
-in the “Chats and Media” settings.
-You can set a timeframe between “At once” and “After 1 year”.
-All e-mails received by Delta Chat will be deleted from the server after this timeframe.
+
If you are using Multiple devices,
+this option is switched to Automatic,
+meaning the server will keep the messages for a while so that all devices have a chance to receive them.
-
Note that if you use Delta Chat on more than one device,
-you need to leave the message on the server with a sufficient timeframe
-so that the other device(s) can download them, too.
+
If you are no longer using additional devices,
+you can switch the option manually at Delete Old Messages → Delete Messages from Server.
@@ -502,6 +494,25 @@ this way, all messages will be deleted from your device as soon as they
older than that.
+
+
+
+ How can I delete my chat profile?
+
+
+
+
+
If you are using more than one chat profile,
+you can remove single ones in the top profile switcher menu (on Android and iOS),
+or in the sidebar with a right click (in the Desktop app).
+Chat profiles are only removed on the device where deletion was triggered.
+Chat profiles on other devices will continue to fully function.
+
+
If you use a single default chat profile you can simply uninstall the app.
+This will still automatically trigger deletion of all associated address data on the chatmail server.
+For more info, please refer to nine.testrun.org address-deletion
+or the respective page from your chosen 3rd party chatmail server.
+
@@ -509,6 +520,16 @@ older than that.
+
+
Groups let several people chat together privately with equal rights.
Because all members have the same rights, groups work best among trusted friends and family.
@@ -524,18 +545,37 @@ older than that.
As soon as you write the first message in the group, all members are informed about the new group and can answer in the group (as long as you do not write a message in the group the group is invisible to the members).
-
+
- Add members to a group
+ Add and remove members
-
Every group member has the same rights as any other. For this reason every one can delete every member or add new ones.
-
To add or delete members, click on the group name in the chat.
+
+
All group members have the same rights.
+For this reason, everyone can delete any member or add new ones.
+
+
+
To add or delete members, tap the group name in the chat and select the member to add or remove.
+
+
+
If the member is not yet in your contact list, but face to face with you,
+from the same screen, show a QR code.
+Ask your chat partner to scan the QR image with their Delta Chat app by tapping
+ on the main screen.
+
+
+
For a remote member addition,
+click “Copy” or “Share” and send the invite link
+through another private chat to the new member.
+
+
+
QR code and invite link can be reused to add several members.
+However, since groups are meant for trusted people, avoid sharing them publicly.
@@ -569,6 +609,30 @@ can still write, but are no longer notified of any new messages.
+
+
+
+ Cloning a group
+
+
+
+
+
You can duplicate a group to start a separate discussion
+or to exclude members without them noticing.
+
+
+
+
Open the group profile and tap Clone Chat (Android/iOS),
+or right-click the group in the chat list (Desktop).
+
+
+
Set a new name, choose an avatar, and adjust the member list if needed.
+
+
+
+
The new group is fully independent from the original,
+which continues to work as before.
+
@@ -601,9 +665,6 @@ including on devices that use microG
instead of proprietary Google code on the phone.
-
-
As of May 2024, classic e-mail servers do not support Push Notifications
-for Delta Chat users.
@@ -629,9 +690,7 @@ does not expose data to Apple that it doesn’t already have.
If a “Push Service” is available, Delta Chat enables Push Notifications
-to achieve instant message delivery for all chatmail users.
-If you are using a classic e-mail provider instead of chatmail servers,
-Push Notifications are not available.
+to achieve instant message delivery for all chatmail users.
In the Delta Chat “Notifications” settings for “Instant delivery”
you can change the following settings effecting all chat profiles:
@@ -667,7 +726,7 @@ safe to try if you experience messages arrive only with long delays.
Delta Chat Push Notification support avoids leakage of private information.
-It does not leak e-mail, IP address or message content (not even encrypted)
+It does not leak profile data, IP address or message content (not even encrypted)
to any system involved in the delivery of Push Notifications.
Here is how Delta Chat apps perform Push Notification delivery:
@@ -678,20 +737,20 @@ to any system involved in the delivery of Push Notifications.
on the chatmail server.
-
When a chatmail server receives an e-mail for a Delta Chat user
+
When a chatmail server receives a message for a Delta Chat user
it forwards the encrypted device token to the central Delta Chat notification proxy.
The central Delta Chat notification proxy decrypts the device token
and forwards it to the respective Push service (Apple, Google, etc.),
-without ever knowing the IP or e-mail address of Delta Chat users.
+without ever knowing the IP or profile data of Delta Chat users.
The central Push Service (Apple, Google, etc.)
wakes up the Delta Chat app on your device
to check for new messages in the background.
-It does not know about the chatmail or e-mail address of the device it wakes up.
-The central Apple/Google Push services never see an e-mail address (sender or receiver)
+It does not know about the profile data of the device it wakes up.
+The central Apple/Google Push services never see any profile data (sender or receiver)
and also never see any message content (also not in encrypted forms).
@@ -702,7 +761,7 @@ usually in a matter of milliseconds.
Note that the device token is encrypted between apps and notification proxy
but it is not signed.
-The notification proxy thus never sees e-mail addresses, IP-addresses or
+The notification proxy thus never sees profile data, IP-addresses or
any cryptographic identity information associated with a user’s device (token).
Resulting from this overall privacy design, even the seizure of a chatmail server,
@@ -725,7 +784,331 @@ without asking questions up-front that are more suited to expert users or develo
On the second device, start Delta Chat, select Add as Second Device, and scan the QR code from the old device
+
+
+
Transfer should start after a few seconds and during transfer both devices will show the progress.
+Wait until it is finished on both devices.
+
+
+
+
In contrast to many other messengers, after successful transfer,
+both devices are completely independent.
+One device is not needed for the other to work.
+
+
+
+
+ Troubleshooting
+
+
+
+
+
+
+
Double-check both devices are in the same Wi-Fi or network
+
+
+
On Windows, go to Control Panel / Network and Internet
+and make sure, Private Network is selected as “Network profile type”
+(after transfer, you can change back to the original value)
+
+
+
On iOS, make sure “System Settings / Apps / Delta Chat / Local Network” access is granted
+
+
+
On macOS, enable “System Settings / Privacy & Security / Local Network / Delta Chat”
+
+
+
Your system might have a “personal firewall”,
+which is known to cause problems (especially on Windows).
+Disable the personal firewall for Delta Chat on both ends and try again
+
+
+
Guest Networks may not allow devices to communicate with each other.
+If possible, use a non-guest network.
+
+
+
If you still have troubles using the same network,
+try to open Mobile Hotspot on one device and join that Wi-Fi from the other one
+
+
+
Ensure there is enough storage on the destination device
+
+
+
If transfer started, make sure, the devices stay active and do not fall asleep.
+Do not exit Delta Chat.
+(we try hard to make the app work in background, but systems tend to kill apps, unfortunately)
+
+
+
Delta Chat is already logged in on the destination device?
+You can use multiple profiles per device, just add another profile
+
+
+
If you still have problems or if you cannot scan a QR code
+try the manual transfer described below
+
+
+
+
+
+
+ Manual Transfer
+
+
+
+
+
This method is only recommended if “Add Second Device” as described above does not work.
+
+
+
On the old device, go to “Settings -> Chats and media -> Export Backup”. Enter your
+screen unlock PIN, pattern, or password. Then you can click on “Start
+Backup”. This saves the backup file to your device. Now you have to transfer
+it to the other device somehow.
+
On the new device, in the “I already have a profile” menu,
+choose “restore from backup”. After import, your conversations, encryption
+keys, and media should be copied to the new device.
+
+
If you use iOS: and you encounter difficulties, maybe
+this guide will
+help you.
+
+
+
You are now synchronized, and can use both devices for sending and receiving
+end-to-end encrypted messages with your communication partners.
+
+
+
+
+
+ Are there any plans for introducing a Delta Chat Web Client?
+
+
+
+
+
+
There are no immediate plans but some preliminary thoughts.
+
There are 2-3 avenues for introducing a Delta Chat Web Client, but all are
+significant work. For now, we focus on getting stable releases into all
+app stores (Google Play/iOS/Windows/macOS/Linux repositories) as native apps.
+
If you need a Web Client, because you are not allowed to install software on
+the computer you work with, you can use the portable Windows Desktop Client,
+or the AppImage for Linux. You can find them on
+get.delta.chat.
+
+
+
+
+
+ In-chat apps
+
+
+
+
+
You can send apps to a chat - games, editors, polls and other tools.
+This makes Delta Chat a truly extensible messenger.
+
+
+
+
+ Where can I get in-chat apps?
+
+
+
+
+
+
+
In a chat, using Attachment Button → Apps
+
+
+
You can also create your own app and attach it using Attachment Button → File
+
+
+
+
+
+
+ How private are in-chat apps?
+
+
+
+
+
+
+
In-chat apps can not send data to the Internet, or download anything.
+
+
+
An in-chat app can only exchange data within a Delta Chat chat, with its
+copies on the devices of your chat partners. Other than that, it’s completely
+isolated from the Internet.
+
+
+
The privacy an in-chat app offers is the privacy of your chat - as long as you
+trust the people you chat with, you can trust the in-chat app as well.
+
+
+
This also means: Just like for web links, do not open apps from untrusted contacts.
+
+
+
+
+
+
+ How can I create my own in-chat apps?
+
+
+
+
+
+
+
In-chat apps are zip files with .xdc extension containing html, css, and javascript code.
If you have question, you can ask others with experience
+in the Delta Chat Forum.
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+ Experimental Features
+
+
+
+
+
At Settings → Advanced → Experimental Features
+you can try out features we are working on.
+
+
The features may be unstable and may be changed or removed.
+
+
You can find more information
+and give feedback in the Forum.
+
+
+
+
+ Can I use a classic email address with Delta Chat?
+
+
+
+
+
Yes, but only if the email address is used exclusively by chatmail clients.
+
+
It is not supported to share usage of an email address with non-chatmail apps or web-based mailers,
+for the following reasons:
+
+
+
+
Non-chatmail apps are largely not accomplishing automatic end-to-end email encryption for their users,
+while chatmail apps and relays pervasively enforce end-to-end encryption and security standards.
+
+
+
Non-chatmail apps use email servers as a long-term message archive
+while chatmail clients use email servers for ephemeral instant message transport.
+
+
+
Supporting the full variety of classic email setups
+would require considerable development and maintenance efforts,
+and complicate making chatmail-based messaging more resilient, reliable and fast.
+
+
+
+
+
+
+ How can I configure a chat profile with a classic email address as transport?
+
+
+
+
+
First off, please do not use the same classic email address also from non-chatmail classic email apps
+unless you are prepared to deal with encrypted messages in the inbox,
+double notifications, accidentally deleted emails or similar annoyances.
+
+
You can configure a email address for chatting at New Profile → Use Other Server → Use Classic Mail as Transport.
+Note that classic email providers will generally not support Push Notifications
+and have other limitations, see Provider Overview.
+Chatmail uses the default INBOX for relay; ensure the provider setup does too.
+A chat profile using a classic email address allows to to send and receive unencrypted messages.
+These messages, and the chats they appear in, are marked with an email icon
+.
+
+
+
+
+ I want to manage my own server for Delta Chat. What do you recommend?
+
+
+
+
+
Any well behaving email server setup will do fine
+except if your users’ devices require Google/Apple Push Notifications to work properly.
@@ -767,7 +1150,7 @@ enables receivers to use end-to-end encryption with the contact.
- How can i know if messages are end-to-end encrypted?
+ How can I know if messages are end-to-end encrypted?
@@ -776,10 +1159,10 @@ enables receivers to use end-to-end encryption with the contact.
Since the Delta Chat Version 2 release series (July 2025)
there are no lock or similar markers on end-to-end encrypted messages, anymore.
-
+
- Can i still receive or send mails without end-to-end encryption?
+ Can I still receive or send messages without end-to-end encryption?
@@ -787,60 +1170,11 @@ there are no lock or similar markers on end-to-end encrypted messages, anymore.<
If you use default chatmail relays,
it is impossible to receive or send messages without end-to-end encryption.
-
If you instead create a profile using a classic e-mail server,
+
If you instead use a classic email server,
you can send and receive messages with or without end-to-end encryption.
-Messages lacking end-to-end encryption are marked with an e-mail icon
+Messages lacking end-to-end encryption are marked with an email icon
.
-
-
-
- How can I establish a chat with a new contact?
-
-
-
-
-
You can send an invite link through another private chat,
-show an invitation QR code when next to each other or in a video call,
-or click on a “contact” that was shared in a chat.
-
-
-
-
For Group invitations,
-tap the chat group title to see its member list,
-and select “QR Invite code”.
-
-
-
For direct 1:1 chat invitations,
-tap the QR Code icon
-on the Delta Chat app main screen.
-
-
-
-
Ask your chat partner to scan the QR image
-with their Delta Chat app,
-or click “Copy” or “Share” to create an invite link
-and share it with your chat partner.
If both sides are online, they will soon see a (group or direct) chat
-and can start messaging securely.
-
-
-
If one side is offline or in bad network,
-the ability to chat is delayed until connectivity is restored.
-
-
-
-
Congratulations!
-You now will automatically use end-to-end encryption
-with this contact.
-If you add each other to chat groups,
-end-to-end encryption will be established among all members.
-
@@ -916,9 +1250,7 @@ which was thankfully adopted in summer 2023.
Yes, we are following efforts like MLS
-or Saltpack
-but adopting them would mean breaking end-to-end encryption interoperability
-with all other e-mail apps that typically support OpenPGP encryption.
+but adopting them would mean breaking end-to-end encryption interoperability.
So it would not be a light decision to take
and there must be tangible improvements for users.
@@ -958,19 +1290,19 @@ as defined by the Autocrypt Level 1 specification.
-
If you are sending or receiving e-mail messages without end-to-end encryption (using a classic e-mail server),
-they are still protected from cell or cable companies who can not read or modify your e-mail messages.
-But both your and your recipient’s e-mail providers
+
If you are sending or receiving email messages without end-to-end encryption (using a classic email server),
+they are still protected from cell or cable companies who can not read or modify your email messages.
+But both your and your recipient’s email providers
may read, analyze or modify your messages, including any attachments.
Delta Chat by default uses strict
TLS encryption
-which secures connections between your device and your e-mail provider.
+which secures connections between your device and your email provider.
All of Delta Chat’s TLS-handling has been independently security audited.
-Moreover, the connection between your and the recipient’s e-mail provider
+Moreover, the connection between your and the recipient’s email provider
will typically be transport-encrypted as well.
-If the involved e-mail servers support MTA-STS
-then transport encryption will be enforced between e-mail providers
+If the involved email servers support MTA-STS
+then transport encryption will be enforced between email providers
in which case Delta Chat communications will never be exposed in cleartext to the Internet
even if the message was not end-to-end encrypted.
@@ -986,20 +1318,15 @@ even if the message was not end-to-end encrypted.
Delta Chat apps do not store any metadata about contacts or groups on servers, also not in encrypted form.
Instead, all group metadata is end-to-end encrypted and stored on end-user devices, only.
-
E-mail Servers can therefore only see
+
Servers can therefore only see:
-
-
the message date,
-
-
-
sender and receiver addresses
-
-
-
and message size.
-
+
the sender and receiver addresses
+
and the message size.
+
By default, the addresses are randomly generated.
+
All other message, contact and group metadata resides in the end-to-end encrypted part of messages.
@@ -1010,10 +1337,10 @@ Instead, all group metadata is end-to-end encrypted and stored on end-user devic
-
Both for protecting against metadata-collecting e-mail servers
+
Both for protecting against metadata-collecting servers
as well as against the threat of device seizure
we recommend to use a chatmail relay
-to create chat profiles using random e-mail addresses for transport.
+to create chat profiles using random addresses for transport.
Note that Delta Chat apps on all platforms support multiple profiles
so you can easily use situation-specific profiles next to your “main” profile
with the knowledge that all their data, along with all metadata, will be deleted.
@@ -1038,7 +1365,7 @@ which is usually associated with a passport identity.
Even if chatmail relays
do not ask for any private data (including no phone numbers),
it might still be worthwhile to protect relational metadata between addresses.
-We don’t foresee bigger problems in using random throw-away e-mail addresses for sealed sending
+We don’t foresee bigger problems in using random throw-away addresses for sealed sending
but an implementation has not been agreed as a priority yet.
On the second device, start Delta Chat, select Add as Second Device, and scan the QR code from the old device
-
-
-
Transfer should start after a few seconds and during transfer both devices will show the progress.
-Wait until it is finished on both devices.
-
-
-
-
In contrast to many other messengers, after successful transfer,
-both devices are completely independent.
-One device is not needed for the other to work.
-
-
-
-
- Troubleshooting
-
-
-
-
-
-
-
Double-check both devices are in the same Wi-Fi or network
-
-
-
On Windows, go to Control Panel / Network and Internet
-and make sure, Private Network is selected as “Network profile type”
-(after transfer, you can change back to the original value)
-
-
-
On iOS, make sure “System Settings / Apps / Delta Chat / Local Network” access is granted
-
-
-
On macOS, enable “System Settings / Privacy & Security / Local Network / Delta Chat”
-
-
-
Your system might have a “personal firewall”,
-which is known to cause problems (especially on Windows).
-Disable the personal firewall for Delta Chat on both ends and try again
-
-
-
Guest Networks may not allow devices to communicate with each other.
-If possible, use a non-guest network.
-
-
-
If you still have troubles using the same network,
-try to open Mobile Hotspot on one device and join that Wi-Fi from the other one
-
-
-
Ensure there is enough storage on the destination device
-
-
-
If transfer started, make sure, the devices stay active and do not fall asleep.
-Do not exit Delta Chat.
-(we try hard to make the app work in background, but systems tend to kill apps, unfortunately)
-
-
-
Delta Chat is already logged in on the destination device?
-You can use multiple profiles per device, just add another profile
-
-
-
If you still have problems or if you cannot scan a QR code
-try the manual transfer described below
-
-
-
-
-
-
- Manual Transfer
-
-
-
-
-
This method is only recommended if “Add Second Device” as described above does not work.
-
-
-
On the old device, go to “Settings -> Chats and media -> Export Backup”. Enter your
-screen unlock PIN, pattern, or password. Then you can click on “Start
-Backup”. This saves the backup file to your device. Now you have to transfer
-it to the other device somehow.
-
On the new device, in the “I already have a profile” menu,
-choose “restore from backup”. After import, your conversations, encryption
-keys, and media should be copied to the new device.
-
-
If you use iOS: and you encounter difficulties, maybe
-this guide will
-help you.
-
-
-
You are now synchronized, and can use both devices for sending and receiving
-end-to-end encrypted messages with your communication partners.
-
-
-
-
-
- Is Deletion, Pinning, Archiving, Saving, Muting etc. synced to all devices?
-
-
-
-
-
Yes.
-
-
If you e.g. delete a chat or a message from your phone,
-it will be deleted on your desktop as soon as it comes online again.
-
-
Notable exceptions are Delete old messages from Device,
-as different devices may have different storage capacities,
-and system specific settings as notification sounds.
-
-
-
-
- Are there any plans for introducing a Delta Chat Web Client?
-
-
-
-
-
-
There are no immediate plans but some preliminary thoughts.
-
There are 2-3 avenues for introducing a Delta Chat Web Client, but all are
-significant work. For now, we focus on getting stable releases into all
-app stores (Google Play/iOS/Windows/macOS/Linux repositories) as native apps.
-
If you need a Web Client, because you are not allowed to install software on
-the computer you work with, you can use the portable Windows Desktop Client,
-or the AppImage for Linux. You can find them on
-get.delta.chat.
-
-
-
-
-
- webxdc apps
-
-
-
-
-
In Delta Chat, you can share webxdc apps, attachments with an .xdc file
-extension. They can do very different things, and make Delta Chat a truly
-extendable messenger.
-
-
-
-
- How private are webxdc apps?
-
-
-
-
-
-
webxdc apps can not send data to the Internet, or download anything.
-
A webxdc app can only exchange data within a Delta Chat chat, with its
-copies on the devices of your chat partners. Other than that, it’s completely
-isolated from the Internet.
-
The privacy a webxdc app offers is the privacy of your chat - as long as you
-trust the people you chat with, you can trust the webxdc app as well.
-
This also means: it can be a privacy risk to open apps in chats with untrusted members.
-Just like with e-mail attachments, video calls or plain links:
-open them only from senders you trust, and not from spammers.
-Spammers can get to know any data you send to them, as well as your IP address.
-
-
-
-
-
- Where can I get webxdc apps?
-
-
-
-
-
-
In general, anyone can share webxdc apps with each
-other without restrictions.
All else you need to know is written in the
-documentation.
-
If you have question, you can ask others with experience in the Delta Chat
-Forum.
-
-
-
-
-
- Advanced
-
-
-
-
-
-
-
- Does Delta Chat work with my e-mail-provider?
-
-
-
-
-
-
With a rather good chance: Yes :)
-However, some providers need special options to work properly,
-see Provider Overview
-
-
-
-
-
- Can I use Delta Chat in parallel with other E-Mail apps?
-
-
-
-
-
Yes, but it is not recommended.
-
-
Parallel usage with the same E-Mail address might lead to the following inconveniences:
-
-
-
Next to your Delta Chat notifications,
-you might also get notifications for (encrypted, so unreadable) chat mail messages
-in your other email app
-
If Delta Chat is not running
-or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
-encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.
-
-
- Why do I have to enter my E-Mail password into Delta Chat? Is this secure?
-
-
-
-
-
As with other E-Mail programs like Thunderbird, K9-Mail, or Outlook, the
-program needs the password so you can use it to send and receive mails. Of course, the
-password is stored only on your device. The password is only transmitted to
-your E-Mail provider (when you login), which has access to your mails anyway.
-
-
As Delta Chat is Open Source, you can check the Source
-Code
-if you want to verify that your credentials are handled securely. We are happy
-about feedback which makes the app more secure for all of our users.
-
-
-
-
- Which messages do appear in Delta Chat?
-
-
-
-
-
By default, Delta Chat shows all e-mails.
-
-
At “Settings → Advanced → Show Classic E-Mails”,
-you can change this. You have these options:
-
-
-
“No, chats only”: Only messages sent by other Delta Chat users and replies to
-your Delta Chat messages are shown. This makes most sense if you use the same
-e-mail account for normal e-mails as well.
-
“All”: Delta Chat shows all e-mails that are sent to your email address. This
-makes sense if you want to use Delta Chat for all your e-mails, so no message
-gets lost. This is the default setting.
-
“For accepted contacts”: Delta Chat shows all e-mails from contacts with whom
-you already have a chat, but new chats only pop up for Delta Chat messages.
-This helps to decide on a case-by-case basis whether you want to have a
-conversation in Delta Chat or in a “normal” e-mail app.
-
-
-
-
-
- Does Delta Chat support HTML e-mails?
-
-
-
-
-
Yes, incoming HTML messages come with a “Show full message” button.
-Outgoing messages always use plain text.
-
-
-
-
- Can I set the E-Mail Subject with Delta Chat?
-
-
-
-
-
Delta Chat sets (and encrypts!) the classic e-mail subject
-automatically to the group name or to the sender name.
-
-
So if you want to set the subject yourself,
-for example for a formal e-mail to a business contact,
-you can create a group
-with only yourself and the recipient(s).
-Set the Chat Title to the Subject you want,
-and then send your e-mail as the first message.
-If the recipients don’t use Delta Chat,
-it will look like a normal,
-formal e-mail to them.
-You will get bonus professionalism points
-if you set a signature text.
-
-
-
-
- What is the “Send Copy to Self” setting good for?
-
-
-
-
-
Sending a copy of your messages to yourself ensures that you receive your own
-messages on all devices. If you have multiple devices and don’t turn it on, you
-see only the messages from other people, and the messages you send from the
-current device.
-
-
The copy is sent to the Inbox, and then moved to the DeltaChat folder; it’s not
-put into the “Sent” folder. Delta Chat never uploads anything to the Sent
-folder because this would mean uploading a message twice (once through SMTP,
-and once through IMAP to Sent folder).
-
-
The default setting for “Send Copy to Self” is “on”.
-
-
-
-
- Why can I choose to watch the “Sent” folder?
-
-
-
-
-
The only reason one wants to watch the Sent folder is if you are using another
-mail program (like Thunderbird) next to your Delta Chat app, and want your MUA
-to participate in chat conversations.
-
-
However, we recommend using the Delta Chat Desktop Client; you can download it
-on get.delta.chat. The option to watch the “Sent”
-folder might go away in the future. It was introduced at a time where there was
-no Delta Chat Desktop client available on all platforms.
-
-
-
-
- Why can I choose to only watch the DeltaChat folder?
-
-
-
-
-
This is an experimental setting for some people who are experimenting with
-server-side rules. Not all providers support this, but with some you can move
-all mails with a “Chat-Version” header to the DeltaChat folder. Normally, this
-would be done by the Delta Chat app.
-
-
Enabling “Only Fetch from DeltaChat folder” makes sense if you have both:
-
-
-
enabled a server-side rule to move all messages with Chat-Version header to the DeltaChat folder, and
-
have set the “Show classic emails” setting to “no, chats only”.
-
-
-
In this case, Delta Chat doesn’t need to watch the Inbox, and it’s enough to only watch the DeltaChat folder.
-
-
-
-
- Is Delta Chat compatible with Proton Mail / Tutanota / Criptext?
-
-
-
-
-
-
Yes and No.
-
No, you can not use your Proton Mail, Tutanota, or Criptext account with Delta
-Chat; they do not offer receiving mails via IMAP.
-
In any case you can use Delta Chat to send Messages to people who use
-Protonmail, Tutanota, or Criptext. Those messages will not be end-to-end
-encrypted, though. The end-to-end encryption those providers offer is not
-compatible with Autocrypt, the standard Delta Chat
-uses.
We are very grateful for feedback on these features - do you want to share
-your ideas? Join the Forum to contribute.
-You may conveniently login via Delta Chat and a QR code scan,
-another rather stable experiment we run on the side (sic!).
-
-
-
-
- How can I use audio/video calls with Delta Chat?
-
-
-
-
-
-
To turn on audio/video calls, go to the “experimental features” section in
-the advanced settings and choose a “Video Chat Instance”.
-
When you invite others to a video chat, it is opened in your browser/app at
-once. The others receive an e-mail with a link to the video chat.
-This way, it is also compatible if your chat partners don’t use Delta Chat.
-
Note that there is no ring tone on the other side, and your chat partners
-will not get interrupted by a video chat invite.
-
You can use any video chat service which allows joining by link. Just add the
-link in the settings.
-
For example, to use the flagship Jitsi Meet instance, you could enter
-https://meet.jit.si/$ROOM. The $ROOM variable will be a random value;
-this way, you will have a new random Jitsi room every time you call someone.
-
-
-
-
-
- What are Broadcast Lists and how can I use them?
-
-
-
-
-
With a Broadcast List you can send a message to many recipients at once;
-the recipients cannot reply in that list.
-Broadcast lists are still highly experimental
-and will very probably be replaced by something else, stay tuned :)
-
-
-
-
- How can I share my location with my chat partners?
-
-
-
-
-
-
You can turn on location streaming in the “experimental features” section of
-the advanced settings.
-
Now, if you want to share your location in a chat, go to “attach” and select
-“location”. You can now set a time frame in which your location will be
-streamed to your chat partners, between 5 minutes and 6 hours.
-
When your location changes, the others in the chat can view it on a map in
-the chat.
-
To see the map and view locations of others, you need to turn on the feature
-in the advanced settings.
-
This feature will not share your location with anyone except your chat partners.
-Map tiles are downloaded from OpenStreetMap.
-
On desktop, the OS typically can’t determine your location. Instead you can
-right click on the map and describe a location, which is sent to the chat as
-a message, but also appears on the map.
-
-
-
-
-
- How can I use a different e-mail address with my profile?
-
-
-
-
-
Note:
-Changing email addresses is temporarily disabled
-because of ongoing changes to the DeltaChat core.
-It should be available again in a few months.
-
-
-
-
Change your address in “Settings → Advanced → Password and Account” and
-enter the password of your new e-mail account (and if necessary, server settings).
-You will get an information notice about the fact that you are moving to a new address.
-An additional notice will also show up in your “Device messages” chat.
-
-
-
If possible, let your old e-mail provider forward all messages to your new address.
-
-
-
Tell your contacts that you changed your address.
-Writing to guaranteed end-to-end encrypted chats and groups,
-will make them notice your move automatically
-and they will continue chatting with you using your new address.
-
-
-
-
Note that Delta Chat will not retrieve messages anymore from your old e-mail provider.
-If you didn’t configure your e-mail provider to forward messages (step 2.)
-only those contacts to whom you sent a message in a guaranteed end-to-end encrypted chat
-will send messages to your new address.
Depending on the operating system in use,
-you may be asked to grant permissions to the app.
-This is what Delta Chat does with these permissions:
+
Some features require certain permissions,
+e.g. you need to grant camera permission if you want to scan an invite QR code.
-
-
Camera (can be disallowed)
-
-
take pictures and videos: for sending Photos
-
-
-
Contacts (can be disallowed)
-
-
read your contacts: to discover contacts to chat with
-
-
-
Location (can be disallowed)
-
-
access approximate location (network location sources): for the location streaming feature
-
access precise location (GPS and network location sources): for the location streaming feature
-
-
-
Microphone (can be disallowed)
-
-
record audio: for audio messages
-
-
-
Storage (can be disallowed)
-
-
modify or delete the contents of your SD card: to download message attachments
-
read the contents of your SD card: to share files with your contacts
-
-
-
Other app capabilities
-
-
change your audio settings: so you can choose ring tones and volume for notifications and audio messages
-
run at startup: so you don’t have to start Delta Chat manually
-
control vibration: for notifications
-
view network connections: to connect to your E-Mail provider
-
prevent phone from sleeping: so you can easier copy the security code during the Autocrypt Setup Message
-
have full network access: to connect to your E-Mail provider
-
view Wi-Fi connections: to connect to your E-Mail provider
-
ask to ignore battery optimisations: for achieving “instant message delivery”
-
-
-
-
-
-
-
- How can I delete my account?
-
-
-
-
-
If you use a default chat profile
-you can simply uninstall the app.
-This will automatically trigger deletion of all associated account data on the chatmail server.
-For more info, please refer to nine.testrun.org account-deletion for the default onboarding server,
-or the respective page from your chosen 3rd party chatmail server.
-
-
If you have set up your chat profile on multiple devices
-you need to remove it from all devices.
-
-
If you are using more than one account,
-but don’t want to get rid of all of them,
-you can remove it in the account switcher menu (on android and iOS),
-or in the sidebar with a right click (in the desktop client).
-
-
Accounts on classic e-mail providers
-will not be deleted automatically;
-how you can delete your account depends on your e-mail provider.
-We don’t have any control over e-mail accounts at those providers,
-so unfortunately we can’t help you with that.
-
-
If you want to continue using a classic e-mail account with other apps,
-but uninstall Delta Chat,
-it is recommended to leave any group chat before uninstalling Delta Chat.
-Otherwise you might receive undecryptable messages from those group chats.
@@ -1876,7 +1556,7 @@ Otherwise you might receive undecryptable messages from those group chats.
Open one of the following app stores and search for “Delta Chat”:
-Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store
+Google Play Store, F-Droid, Huawei App Gallery, iOS and macOS App Store, Microsoft Store
Check the package manager of your Linux distributions
@@ -1927,13 +1607,13 @@ completing Rust/Python bindings and instigating a Chat-bot eco-system.
In 2021 we received further EU funding for two Next-Generation-Internet
-proposals, namely for EPPD - e-mail provider portability directory (~97K EUR) and AEAP - email address porting (~90K EUR) which resulted in better multi-profile support, improved QR-code contact and group setups and many networking improvements on all platforms.
From End 2021 till March 2023 we received Internet Freedom funding (500K USD) from the
U.S. Bureau of Democracy, Human Rights and Labor (DRL).
This funding supported our long-running goals to make Delta Chat more usable
-and compatible with a wide range of e-mail servers world-wide, and more resilient and secure
+and compatible with a wide range of email servers world-wide, and more resilient and secure
in places often affected by internet censorship and shutdowns.
diff --git a/src/main/assets/help/es/help.html b/src/main/assets/help/es/help.html
index a35f58a35..add82b4cf 100644
--- a/src/main/assets/help/es/help.html
+++ b/src/main/assets/help/es/help.html
@@ -123,7 +123,7 @@ que son servidores de correo electrónico mínimos y optimizados para operacione
O puedes utilizar servidores de correo electrónico clásicos y una cuenta de correo electrónico existente
en cuyo caso, Delta Chat actúa como una aplicación de correo electrónico.
-
+
diff --git a/src/main/assets/help/fr/help.html b/src/main/assets/help/fr/help.html
index 6f7d277d7..6559418ef 100644
--- a/src/main/assets/help/fr/help.html
+++ b/src/main/assets/help/fr/help.html
@@ -124,7 +124,7 @@ Qui sont des serveurs e-mails minimalistes optimisés pour des opérations rapid
Ou vous pouvez utiliser des serveurs e-mail classiques et utiliser votre compte e-mail
dans ce cas Delta Chat agit comme une application de courriel.
-
+
diff --git a/src/main/assets/help/id/help.html b/src/main/assets/help/id/help.html
index 93a775338..fd596c623 100644
--- a/src/main/assets/help/id/help.html
+++ b/src/main/assets/help/id/help.html
@@ -124,7 +124,7 @@ which are minimal e-mail servers optimized for fast and secure operations.
Or you may use classic e-mail servers and an existing e-mail account
in which case Delta Chat acts as an e-mail app.
-
+
diff --git a/src/main/assets/help/it/help.html b/src/main/assets/help/it/help.html
index 965268f89..99000e5bd 100644
--- a/src/main/assets/help/it/help.html
+++ b/src/main/assets/help/it/help.html
@@ -124,7 +124,7 @@ che sono server e-mail minimi ottimizzati per operazioni veloci e sicure.
Oppure puoi utilizzare i classici server e-mail e un profilo e-mail esistente
nel qual caso Delta Chat funge da app e-mail.
-
+
diff --git a/src/main/assets/help/mic.png b/src/main/assets/help/mic.png
new file mode 100644
index 000000000..ed5d44845
Binary files /dev/null and b/src/main/assets/help/mic.png differ
diff --git a/src/main/assets/help/nl/help.html b/src/main/assets/help/nl/help.html
index 16729d3b7..a8ccaf3f4 100644
--- a/src/main/assets/help/nl/help.html
+++ b/src/main/assets/help/nl/help.html
@@ -124,7 +124,7 @@ which are minimal e-mail servers optimized for fast and secure operations.
Or you may use classic e-mail servers and an existing e-mail account
in which case Delta Chat acts as an e-mail app.
-
+
diff --git a/src/main/assets/help/paperclip.png b/src/main/assets/help/paperclip.png
new file mode 100644
index 000000000..01d4e15f0
Binary files /dev/null and b/src/main/assets/help/paperclip.png differ
diff --git a/src/main/assets/help/pl/help.html b/src/main/assets/help/pl/help.html
index 28c3ab450..d3968c14c 100644
--- a/src/main/assets/help/pl/help.html
+++ b/src/main/assets/help/pl/help.html
@@ -119,7 +119,7 @@
Delta Chat przypomina Whatsapp lub Telegram, ale możesz go również używać i traktować jako aplikację e-mail. Możesz zarejestrować się anonimowo na różnych interoperacyjnych serwerach chatmail, które są minimalnymi serwerami poczty e-mail zoptymalizowanymi pod kątem szybkich i bezpiecznych operacji. Możesz też skorzystać z klasycznych serwerów pocztowych i istniejącego konta e-mail, w którym to przypadku Delta Chat będzie pełnić funkcję aplikacji pocztowej.
-
+
diff --git a/src/main/assets/help/pt/help.html b/src/main/assets/help/pt/help.html
index 9ee9694a9..581319093 100644
--- a/src/main/assets/help/pt/help.html
+++ b/src/main/assets/help/pt/help.html
@@ -124,7 +124,7 @@ which are minimal e-mail servers optimized for fast and secure operations.
Or you may use classic e-mail servers and an existing e-mail account
in which case Delta Chat acts as an e-mail app.
-
+
diff --git a/src/main/assets/help/qr-icon.png b/src/main/assets/help/qr-icon.png
index dec4cb70b..b01218466 100644
Binary files a/src/main/assets/help/qr-icon.png and b/src/main/assets/help/qr-icon.png differ
diff --git a/src/main/assets/help/ru/help.html b/src/main/assets/help/ru/help.html
index 4b8c73979..250abbb24 100644
--- a/src/main/assets/help/ru/help.html
+++ b/src/main/assets/help/ru/help.html
@@ -124,7 +124,7 @@
Или вы можете использовать обычные почтовые серверы и существующий почтовый аккаунт,
в этом случае Delta Chat работает как приложение электронной почты.
-
+
diff --git a/src/main/assets/help/saved-icon.png b/src/main/assets/help/saved-icon.png
index b3443d5a3..27c2812ef 100644
Binary files a/src/main/assets/help/saved-icon.png and b/src/main/assets/help/saved-icon.png differ
diff --git a/src/main/assets/help/sk/help.html b/src/main/assets/help/sk/help.html
index e012a0955..097d20e94 100644
--- a/src/main/assets/help/sk/help.html
+++ b/src/main/assets/help/sk/help.html
@@ -124,7 +124,7 @@ which are minimal e-mail servers optimized for fast and secure operations.
Or you may use classic e-mail servers and an existing e-mail account
in which case Delta Chat acts as an e-mail app.
-
+
diff --git a/src/main/assets/help/sq/help.html b/src/main/assets/help/sq/help.html
index 9a3e561be..db1ffb6db 100644
--- a/src/main/assets/help/sq/help.html
+++ b/src/main/assets/help/sq/help.html
@@ -124,7 +124,7 @@ which are minimal e-mail servers optimized for fast and secure operations.
Or you may use classic e-mail servers and an existing e-mail account
in which case Delta Chat acts as an e-mail app.
-
+
diff --git a/src/main/assets/help/tick1.png b/src/main/assets/help/tick1.png
new file mode 100644
index 000000000..986201dfb
Binary files /dev/null and b/src/main/assets/help/tick1.png differ
diff --git a/src/main/assets/help/tick2.png b/src/main/assets/help/tick2.png
new file mode 100644
index 000000000..ea6f08f0b
Binary files /dev/null and b/src/main/assets/help/tick2.png differ
diff --git a/src/main/assets/help/uk/help.html b/src/main/assets/help/uk/help.html
index c1bc96863..3870e2270 100644
--- a/src/main/assets/help/uk/help.html
+++ b/src/main/assets/help/uk/help.html
@@ -119,7 +119,7 @@
Delta Chat схожий на Whatsapp або Telegram, але ви також можете використовувати його як додаток електронної пошти. Ви можете анонімно зареєструватися на різних сумісних chatmail-серверах які є мінімальними поштовими серверами, оптимізованими для швидкої та безпечної роботи. Або ви можете використовувати класичні поштові сервери та існуючий профіль електронної пошти в цьому випадку Delta Chat буде працювати як поштовий додаток.
diff --git a/src/main/java/chat/delta/rpc/Rpc.java b/src/main/java/chat/delta/rpc/Rpc.java
index 7d57530f4..205a07b8f 100644
--- a/src/main/java/chat/delta/rpc/Rpc.java
+++ b/src/main/java/chat/delta/rpc/Rpc.java
@@ -23,10 +23,66 @@ public class Rpc {
this.mapper = transport.getObjectMapper();
}
+ /* Test function. */
+ public void sleep(Float delay) throws RpcException {
+ transport.call("sleep", mapper.valueToTree(delay));
+ }
+
+ /* Checks if an email address is valid. */
+ public Boolean checkEmailValidity(String email) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "check_email_validity", mapper.valueToTree(email));
+ }
+
+ /* Returns general system info. */
+ public java.util.Map getSystemInfo() throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_system_info");
+ }
+
+ /**
+ * Get the next event, and remove it from the event queue.
+ *
+ * If no events have happened since the last `get_next_event`
+ * (i.e. if the event queue is empty), the response will be returned
+ * only when a new event fires.
+ *
+ * Note that if you are using the `BaseDeltaChat` JavaScript class
+ * or the `Rpc` Python class, this function will be invoked
+ * by those classes internally and should not be used manually.
+ */
+ public Event getNextEvent() throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_next_event");
+ }
+
public Integer addAccount() throws RpcException {
return transport.callForResult(new TypeReference(){}, "add_account");
}
+ /**
+ * Imports/migrated an existing account from a database path into this account manager.
+ * Returns the ID of new account.
+ */
+ public Integer migrateAccount(String pathToDb) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "migrate_account", mapper.valueToTree(pathToDb));
+ }
+
+ public void removeAccount(Integer accountId) throws RpcException {
+ transport.call("remove_account", mapper.valueToTree(accountId));
+ }
+
+ public java.util.List getAllAccountIds() throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_all_account_ids");
+ }
+
+ /* Select account in account manager, this saves the last used account to accounts.toml */
+ public void selectAccount(Integer id) throws RpcException {
+ transport.call("select_account", mapper.valueToTree(id));
+ }
+
+ /* Get the selected account from the account manager (on startup it is read from accounts.toml) */
+ public Integer getSelectedAccountId() throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_selected_account_id");
+ }
+
/**
* Set the order of accounts.
* The provided list should contain all account IDs in the desired order.
@@ -37,11 +93,88 @@ public class Rpc {
transport.call("set_accounts_order", mapper.valueToTree(order));
}
+ /* Get a list of all configured accounts. */
+ public java.util.List getAllAccounts() throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_all_accounts");
+ }
+
+ /* Starts background tasks for all accounts. */
+ public void startIoForAllAccounts() throws RpcException {
+ transport.call("start_io_for_all_accounts");
+ }
+
+ /* Stops background tasks for all accounts. */
+ public void stopIoForAllAccounts() throws RpcException {
+ transport.call("stop_io_for_all_accounts");
+ }
+
+ /**
+ * Performs a background fetch for all accounts in parallel with a timeout.
+ *
+ * The `AccountsBackgroundFetchDone` event is emitted at the end even in case of timeout.
+ * Process all events until you get this one and you can safely return to the background
+ * without forgetting to create notifications caused by timing race conditions.
+ */
+ public void backgroundFetch(Float timeoutInSeconds) throws RpcException {
+ transport.call("background_fetch", mapper.valueToTree(timeoutInSeconds));
+ }
+
+ public void stopBackgroundFetch() throws RpcException {
+ transport.call("stop_background_fetch");
+ }
+
+ /* Starts background tasks for a single account. */
+ public void startIo(Integer accountId) throws RpcException {
+ transport.call("start_io", mapper.valueToTree(accountId));
+ }
+
+ /* Stops background tasks for a single account. */
+ public void stopIo(Integer accountId) throws RpcException {
+ transport.call("stop_io", mapper.valueToTree(accountId));
+ }
+
+ /* Get top-level info for an account. */
+ public Account getAccountInfo(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_account_info", mapper.valueToTree(accountId));
+ }
+
+ /* Get the current push notification state. */
+ public NotifyState getPushState(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_push_state", mapper.valueToTree(accountId));
+ }
+
/* Get the combined filesize of an account in bytes */
public Integer getAccountFileSize(Integer accountId) throws RpcException {
return transport.callForResult(new TypeReference(){}, "get_account_file_size", mapper.valueToTree(accountId));
}
+ /**
+ * Returns provider for the given domain.
+ *
+ * This function looks up domain in offline database.
+ *
+ * For compatibility, email address can be passed to this function
+ * instead of the domain.
+ */
+ public ProviderInfo getProviderInfo(Integer accountId, String email) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_provider_info", mapper.valueToTree(accountId), mapper.valueToTree(email));
+ }
+
+ /* Checks if the context is already configured. */
+ public Boolean isConfigured(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "is_configured", mapper.valueToTree(accountId));
+ }
+
+ /* Get system info for an account. */
+ public java.util.Map getInfo(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_info", mapper.valueToTree(accountId));
+ }
+
+ /* Get the blob dir. */
+ public String getBlobDir(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_blob_dir", mapper.valueToTree(accountId));
+ }
+
/**
* If there was an error while the account was opened
* and migrated to the current version,
@@ -57,11 +190,60 @@ public class Rpc {
return transport.callForResult(new TypeReference(){}, "get_migration_error", mapper.valueToTree(accountId));
}
+ /* Copy file to blob dir. */
+ public String copyToBlobDir(Integer accountId, String path) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "copy_to_blob_dir", mapper.valueToTree(accountId), mapper.valueToTree(path));
+ }
+
+ /* Sets the given configuration key. */
+ public void setConfig(Integer accountId, String key, String value) throws RpcException {
+ transport.call("set_config", mapper.valueToTree(accountId), mapper.valueToTree(key), mapper.valueToTree(value));
+ }
+
+ /* Updates a batch of configuration values. */
+ public void batchSetConfig(Integer accountId, java.util.Map config) throws RpcException {
+ transport.call("batch_set_config", mapper.valueToTree(accountId), mapper.valueToTree(config));
+ }
+
+ /**
+ * Set configuration values from a QR code. (technically from the URI that is stored in the qrcode)
+ * Before this function is called, `checkQr()` should confirm the type of the
+ * QR code is `account` or `webrtcInstance`.
+ *
+ * Internally, the function will call dc_set_config() with the appropriate keys,
+ */
+ public void setConfigFromQr(Integer accountId, String qrContent) throws RpcException {
+ transport.call("set_config_from_qr", mapper.valueToTree(accountId), mapper.valueToTree(qrContent));
+ }
+
+ public Qr checkQr(Integer accountId, String qrContent) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "check_qr", mapper.valueToTree(accountId), mapper.valueToTree(qrContent));
+ }
+
/* Returns configuration value for the given key. */
public String getConfig(Integer accountId, String key) throws RpcException {
return transport.callForResult(new TypeReference(){}, "get_config", mapper.valueToTree(accountId), mapper.valueToTree(key));
}
+ public java.util.Map batchGetConfig(Integer accountId, java.util.List keys) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "batch_get_config", mapper.valueToTree(accountId), mapper.valueToTree(keys));
+ }
+
+ public void setStockStrings(java.util.Map strings) throws RpcException {
+ transport.call("set_stock_strings", mapper.valueToTree(strings));
+ }
+
+ /**
+ * Configures this account with the currently set parameters.
+ * Setup the credential config before calling this.
+ *
+ * Deprecated as of 2025-02; use `add_transport_from_qr()`
+ * or `add_or_update_transport()` instead.
+ */
+ public void configure(Integer accountId) throws RpcException {
+ transport.call("configure", mapper.valueToTree(accountId));
+ }
+
/**
* Configures a new email account using the provided parameters
* and adds it as a transport.
@@ -97,6 +279,11 @@ public class Rpc {
transport.call("add_or_update_transport", mapper.valueToTree(accountId), mapper.valueToTree(param));
}
+ /* Deprecated 2025-04. Alias for [Self::add_or_update_transport()]. */
+ public void addTransport(Integer accountId, EnteredLoginParam param) throws RpcException {
+ transport.call("add_transport", mapper.valueToTree(accountId), mapper.valueToTree(param));
+ }
+
/**
* Adds a new email account as a transport
* using the server encoded in the QR code.
@@ -106,6 +293,345 @@ public class Rpc {
transport.call("add_transport_from_qr", mapper.valueToTree(accountId), mapper.valueToTree(qr));
}
+ /**
+ * Returns the list of all email accounts that are used as a transport in the current profile.
+ * Use [Self::add_or_update_transport()] to add or change a transport
+ * and [Self::delete_transport()] to delete a transport.
+ */
+ public java.util.List listTransports(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "list_transports", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Removes the transport with the specified email address
+ * (i.e. [EnteredLoginParam::addr]).
+ */
+ public void deleteTransport(Integer accountId, String addr) throws RpcException {
+ transport.call("delete_transport", mapper.valueToTree(accountId), mapper.valueToTree(addr));
+ }
+
+ /* Signal an ongoing process to stop. */
+ public void stopOngoingProcess(Integer accountId) throws RpcException {
+ transport.call("stop_ongoing_process", mapper.valueToTree(accountId));
+ }
+
+ public void exportSelfKeys(Integer accountId, String path, String passphrase) throws RpcException {
+ transport.call("export_self_keys", mapper.valueToTree(accountId), mapper.valueToTree(path), mapper.valueToTree(passphrase));
+ }
+
+ public void importSelfKeys(Integer accountId, String path, String passphrase) throws RpcException {
+ transport.call("import_self_keys", mapper.valueToTree(accountId), mapper.valueToTree(path), mapper.valueToTree(passphrase));
+ }
+
+ /**
+ * Returns the message IDs of all _fresh_ messages of any chat.
+ * Typically used for implementing notification summaries
+ * or badge counters e.g. on the app icon.
+ * The list is already sorted and starts with the most recent fresh message.
+ *
+ * Messages belonging to muted chats or to the contact requests are not returned;
+ * these messages should not be notified
+ * and also badge counters should not include these messages.
+ *
+ * To get the number of fresh messages for a single chat, muted or not,
+ * use `get_fresh_msg_cnt()`.
+ */
+ public java.util.List getFreshMsgs(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_fresh_msgs", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Get the number of _fresh_ messages in a chat.
+ * Typically used to implement a badge with a number in the chatlist.
+ *
+ * If the specified chat is muted,
+ * the UI should show the badge counter "less obtrusive",
+ * e.g. using "gray" instead of "red" color.
+ */
+ public Integer getFreshMsgCnt(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_fresh_msg_cnt", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Gets messages to be processed by the bot and returns their IDs.
+ *
+ * Only messages with database ID higher than `last_msg_id` config value
+ * are returned. After processing the messages, the bot should
+ * update `last_msg_id` by calling [`markseen_msgs`]
+ * or manually updating the value to avoid getting already
+ * processed messages.
+ *
+ * [`markseen_msgs`]: Self::markseen_msgs
+ */
+ public java.util.List getNextMsgs(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_next_msgs", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Waits for messages to be processed by the bot and returns their IDs.
+ *
+ * This function is similar to [`get_next_msgs`],
+ * but waits for internal new message notification before returning.
+ * New message notification is sent when new message is added to the database,
+ * on initialization, when I/O is started and when I/O is stopped.
+ * This allows bots to use `wait_next_msgs` in a loop to process
+ * old messages after initialization and during the bot runtime.
+ * To shutdown the bot, stopping I/O can be used to interrupt
+ * pending or next `wait_next_msgs` call.
+ *
+ * [`get_next_msgs`]: Self::get_next_msgs
+ */
+ public java.util.List waitNextMsgs(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "wait_next_msgs", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Estimate the number of messages that will be deleted
+ * by the set_config()-options `delete_device_after` or `delete_server_after`.
+ * This is typically used to show the estimated impact to the user
+ * before actually enabling deletion of old messages.
+ */
+ public Integer estimateAutoDeletionCount(Integer accountId, Boolean fromServer, Integer seconds) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "estimate_auto_deletion_count", mapper.valueToTree(accountId), mapper.valueToTree(fromServer), mapper.valueToTree(seconds));
+ }
+
+ public String initiateAutocryptKeyTransfer(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "initiate_autocrypt_key_transfer", mapper.valueToTree(accountId));
+ }
+
+ public void continueAutocryptKeyTransfer(Integer accountId, Integer messageId, String setupCode) throws RpcException {
+ transport.call("continue_autocrypt_key_transfer", mapper.valueToTree(accountId), mapper.valueToTree(messageId), mapper.valueToTree(setupCode));
+ }
+
+ public java.util.List getChatlistEntries(Integer accountId, Integer listFlags, String queryString, Integer queryContactId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_chatlist_entries", mapper.valueToTree(accountId), mapper.valueToTree(listFlags), mapper.valueToTree(queryString), mapper.valueToTree(queryContactId));
+ }
+
+ /**
+ * Returns chats similar to the given one.
+ *
+ * Experimental API, subject to change without notice.
+ */
+ public java.util.List getSimilarChatIds(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_similar_chat_ids", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ public java.util.Map getChatlistItemsByEntries(Integer accountId, java.util.List entries) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_chatlist_items_by_entries", mapper.valueToTree(accountId), mapper.valueToTree(entries));
+ }
+
+ public FullChat getFullChatById(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_full_chat_by_id", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * get basic info about a chat,
+ * use chatlist_get_full_chat_by_id() instead if you need more information
+ */
+ public BasicChat getBasicChatInfo(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_basic_chat_info", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ public void acceptChat(Integer accountId, Integer chatId) throws RpcException {
+ transport.call("accept_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ public void blockChat(Integer accountId, Integer chatId) throws RpcException {
+ transport.call("block_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Delete a chat.
+ *
+ * Messages are deleted from the device and the chat database entry is deleted.
+ * After that, the event #DC_EVENT_MSGS_CHANGED is posted.
+ *
+ * Things that are _not done_ implicitly:
+ *
+ * - Messages are **not deleted from the server**.
+ * - The chat or the contact is **not blocked**, so new messages from the user/the group may appear as a contact request
+ * and the user may create the chat again.
+ * - **Groups are not left** - this would
+ * be unexpected as (1) deleting a normal chat also does not prevent new mails
+ * from arriving, (2) leaving a group requires sending a message to
+ * all group members - especially for groups not used for a longer time, this is
+ * really unexpected when deletion results in contacting all members again,
+ * (3) only leaving groups is also a valid usecase.
+ *
+ * To leave a chat explicitly, use leave_group()
+ */
+ public void deleteChat(Integer accountId, Integer chatId) throws RpcException {
+ transport.call("delete_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Get encryption info for a chat.
+ * Get a multi-line encryption info, containing encryption preferences of all members.
+ * Can be used to find out why messages sent to group are not encrypted.
+ *
+ * returns Multi-line text
+ */
+ public String getChatEncryptionInfo(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_chat_encryption_info", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Get QR code text that will offer a [SecureJoin](https://securejoin.delta.chat/) invitation.
+ *
+ * If `chat_id` is a group chat ID, SecureJoin QR code for the group is returned.
+ * If `chat_id` is unset, setup contact QR code is returned.
+ */
+ public String getChatSecurejoinQrCode(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_chat_securejoin_qr_code", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Get QR code (text and SVG) that will offer a Setup-Contact or Verified-Group invitation.
+ * The QR code is compatible to the OPENPGP4FPR format
+ * so that a basic fingerprint comparison also works e.g. with OpenKeychain.
+ *
+ * The scanning device will pass the scanned content to `checkQr()` then;
+ * if `checkQr()` returns `askVerifyContact` or `askVerifyGroup`
+ * an out-of-band-verification can be joined using `secure_join()`
+ *
+ * chat_id: If set to a group-chat-id,
+ * the Verified-Group-Invite protocol is offered in the QR code;
+ * works for protected groups as well as for normal groups.
+ * If not set, the Setup-Contact protocol is offered in the QR code.
+ * See https://securejoin.delta.chat/ for details about both protocols.
+ *
+ * return format: `[code, svg]`
+ */
+ public Pair getChatSecurejoinQrCodeSvg(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_chat_securejoin_qr_code_svg", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Continue a Setup-Contact or Verified-Group-Invite protocol
+ * started on another device with `get_chat_securejoin_qr_code_svg()`.
+ * This function is typically called when `check_qr()` returns
+ * type=AskVerifyContact or type=AskVerifyGroup.
+ *
+ * The function returns immediately and the handshake runs in background,
+ * sending and receiving several messages.
+ * During the handshake, info messages are added to the chat,
+ * showing progress, success or errors.
+ *
+ * Subsequent calls of `secure_join()` will abort previous, unfinished handshakes.
+ *
+ * See https://securejoin.delta.chat/ for details about both protocols.
+ *
+ * **qr**: The text of the scanned QR code. Typically, the same string as given
+ * to `check_qr()`.
+ *
+ * **returns**: The chat ID of the joined chat, the UI may redirect to the this chat.
+ * A returned chat ID does not guarantee that the chat is protected or the belonging contact is verified.
+ *
+ */
+ public Integer secureJoin(Integer accountId, String qr) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "secure_join", mapper.valueToTree(accountId), mapper.valueToTree(qr));
+ }
+
+ /**
+ * Like `secure_join()`, but allows to pass a source and a UI-path.
+ * You only need this if your UI has an option to send statistics
+ * to Delta Chat's developers.
+ *
+ * **source**: The source where the QR code came from.
+ * E.g. a link that was clicked inside or outside Delta Chat,
+ * the "Paste from Clipboard" action,
+ * the "Load QR code as image" action,
+ * or a QR code scan.
+ *
+ * **uipath**: Which UI path did the user use to arrive at the QR code screen.
+ * If the SecurejoinSource was ExternalLink or InternalLink,
+ * pass `None` here, because the QR code screen wasn't even opened.
+ * ```
+ */
+ public Integer secureJoinWithUxInfo(Integer accountId, String qr, SecurejoinSource source, SecurejoinUiPath uipath) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "secure_join_with_ux_info", mapper.valueToTree(accountId), mapper.valueToTree(qr), mapper.valueToTree(source), mapper.valueToTree(uipath));
+ }
+
+ public void leaveGroup(Integer accountId, Integer chatId) throws RpcException {
+ transport.call("leave_group", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Remove a member from a group.
+ *
+ * If the group is already _promoted_ (any message was sent to the group),
+ * all group members are informed by a special status message that is sent automatically by this function.
+ *
+ * Sends out #DC_EVENT_CHAT_MODIFIED and #DC_EVENT_MSGS_CHANGED if a status message was sent.
+ */
+ public void removeContactFromChat(Integer accountId, Integer chatId, Integer contactId) throws RpcException {
+ transport.call("remove_contact_from_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(contactId));
+ }
+
+ /**
+ * Add a member to a group.
+ *
+ * If the group is already _promoted_ (any message was sent to the group),
+ * all group members are informed by a special status message that is sent automatically by this function.
+ *
+ * If the group has group protection enabled, only verified contacts can be added to the group.
+ *
+ * Sends out #DC_EVENT_CHAT_MODIFIED and #DC_EVENT_MSGS_CHANGED if a status message was sent.
+ */
+ public void addContactToChat(Integer accountId, Integer chatId, Integer contactId) throws RpcException {
+ transport.call("add_contact_to_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(contactId));
+ }
+
+ /**
+ * Get the contact IDs belonging to a chat.
+ *
+ * - for normal chats, the function always returns exactly one contact,
+ * DC_CONTACT_ID_SELF is returned only for SELF-chats.
+ *
+ * - for group chats all members are returned, DC_CONTACT_ID_SELF is returned
+ * explicitly as it may happen that oneself gets removed from a still existing
+ * group
+ *
+ * - for broadcast channels, all recipients are returned, DC_CONTACT_ID_SELF is not included
+ *
+ * - for mailing lists, the behavior is not documented currently, we will decide on that later.
+ * for now, the UI should not show the list for mailing lists.
+ * (we do not know all members and there is not always a global mailing list address,
+ * so we could return only SELF or the known members; this is not decided yet)
+ */
+ public java.util.List getChatContacts(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_chat_contacts", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /* Returns contact IDs of the past chat members. */
+ public java.util.List getPastChatContacts(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_past_chat_contacts", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Create a new encrypted group chat (with key-contacts).
+ *
+ * After creation,
+ * the group has one member with the ID DC_CONTACT_ID_SELF
+ * and is in _unpromoted_ state.
+ * This means, you can add or remove members, change the name,
+ * the group image and so on without messages being sent to all group members.
+ *
+ * This changes as soon as the first message is sent to the group members
+ * and the group becomes _promoted_.
+ * After that, all changes are synced with all group members
+ * by sending status message.
+ *
+ * To check, if a chat is still unpromoted, you can look at the `is_unpromoted` property of `BasicChat` or `FullChat`.
+ * This may be useful if you want to show some help for just created groups.
+ *
+ * `protect` argument is deprecated as of 2025-10-22 and is left for compatibility.
+ * Pass `false` here.
+ */
+ public Integer createGroupChat(Integer accountId, String name, Boolean protect) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "create_group_chat", mapper.valueToTree(accountId), mapper.valueToTree(name), mapper.valueToTree(protect));
+ }
+
/**
* Create a new unencrypted group chat.
*
@@ -116,8 +642,13 @@ public class Rpc {
return transport.callForResult(new TypeReference(){}, "create_group_chat_unencrypted", mapper.valueToTree(accountId), mapper.valueToTree(name));
}
+ /* Deprecated 2025-07 in favor of create_broadcast(). */
+ public Integer createBroadcastList(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "create_broadcast_list", mapper.valueToTree(accountId));
+ }
+
/**
- * Create a new **broadcast channel**
+ * Create a new, outgoing **broadcast channel**
* (called "Channel" in the UI).
*
* Broadcast channels are similar to groups on the sending device,
@@ -137,16 +668,369 @@ public class Rpc {
return transport.callForResult(new TypeReference(){}, "create_broadcast", mapper.valueToTree(accountId), mapper.valueToTree(chatName));
}
+ /**
+ * Set group name.
+ *
+ * If the group is already _promoted_ (any message was sent to the group),
+ * all group members are informed by a special status message that is sent automatically by this function.
+ *
+ * Sends out #DC_EVENT_CHAT_MODIFIED and #DC_EVENT_MSGS_CHANGED if a status message was sent.
+ */
+ public void setChatName(Integer accountId, Integer chatId, String newName) throws RpcException {
+ transport.call("set_chat_name", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(newName));
+ }
+
+ /**
+ * Set group profile image.
+ *
+ * If the group is already _promoted_ (any message was sent to the group),
+ * all group members are informed by a special status message that is sent automatically by this function.
+ *
+ * Sends out #DC_EVENT_CHAT_MODIFIED and #DC_EVENT_MSGS_CHANGED if a status message was sent.
+ *
+ * To find out the profile image of a chat, use dc_chat_get_profile_image()
+ *
+ * @param image_path Full path of the image to use as the group image. The image will immediately be copied to the
+ * `blobdir`; the original image will not be needed anymore.
+ * If you pass null here, the group image is deleted (for promoted groups, all members are informed about
+ * this change anyway).
+ */
+ public void setChatProfileImage(Integer accountId, Integer chatId, String imagePath) throws RpcException {
+ transport.call("set_chat_profile_image", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(imagePath));
+ }
+
+ public void setChatVisibility(Integer accountId, Integer chatId, ChatVisibility visibility) throws RpcException {
+ transport.call("set_chat_visibility", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(visibility));
+ }
+
+ public void setChatEphemeralTimer(Integer accountId, Integer chatId, Integer timer) throws RpcException {
+ transport.call("set_chat_ephemeral_timer", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(timer));
+ }
+
+ public Integer getChatEphemeralTimer(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_chat_ephemeral_timer", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Add a message to the device-chat.
+ * Device-messages usually contain update information
+ * and some hints that are added during the program runs, multi-device etc.
+ * The device-message may be defined by a label;
+ * if a message with the same label was added or skipped before,
+ * the message is not added again, even if the message was deleted in between.
+ * If needed, the device-chat is created before.
+ *
+ * Sends the `MsgsChanged` event on success.
+ *
+ * Setting msg to None will prevent the device message with this label from being added in the future.
+ */
+ public Integer addDeviceMessage(Integer accountId, String label, MessageData msg) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "add_device_message", mapper.valueToTree(accountId), mapper.valueToTree(label), mapper.valueToTree(msg));
+ }
+
+ /**
+ * Mark all messages in a chat as _noticed_.
+ * _Noticed_ messages are no longer _fresh_ and do not count as being unseen
+ * but are still waiting for being marked as "seen" using markseen_msgs()
+ * (IMAP/MDNs is not done for noticed messages).
+ *
+ * Calling this function usually results in the event #DC_EVENT_MSGS_NOTICED.
+ * See also markseen_msgs().
+ */
+ public void marknoticedChat(Integer accountId, Integer chatId) throws RpcException {
+ transport.call("marknoticed_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Returns the message that is immediately followed by the last seen
+ * message.
+ * From the point of view of the user this is effectively
+ * "first unread", but in reality in the database a seen message
+ * _can_ be followed by a fresh (unseen) message
+ * if that message has not been individually marked as seen.
+ */
+ public Integer getFirstUnreadMessageOfChat(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_first_unread_message_of_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Set mute duration of a chat.
+ *
+ * The UI can then call is_chat_muted() when receiving a new message
+ * to decide whether it should trigger an notification.
+ *
+ * Muted chats should not sound or vibrate
+ * and should not show a visual notification in the system area.
+ * Moreover, muted chats should be excluded from global badge counter
+ * (get_fresh_msgs() skips muted chats therefore)
+ * and the in-app, per-chat badge counter should use a less obtrusive color.
+ *
+ * Sends out #DC_EVENT_CHAT_MODIFIED.
+ */
+ public void setChatMuteDuration(Integer accountId, Integer chatId, MuteDuration duration) throws RpcException {
+ transport.call("set_chat_mute_duration", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(duration));
+ }
+
+ /**
+ * Check whether the chat is currently muted (can be changed by set_chat_mute_duration()).
+ *
+ * This is available as a standalone function outside of fullchat, because it might be only needed for notification
+ */
+ public Boolean isChatMuted(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "is_chat_muted", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Mark messages as presented to the user.
+ * Typically, UIs call this function on scrolling through the message list,
+ * when the messages are presented at least for a little moment.
+ * The concrete action depends on the type of the chat and on the users settings
+ * (dc_msgs_presented() may be a better name therefore, but well. :)
+ *
+ * - For normal chats, the IMAP state is updated, MDN is sent
+ * (if set_config()-options `mdns_enabled` is set)
+ * and the internal state is changed to @ref DC_STATE_IN_SEEN to reflect these actions.
+ *
+ * - For contact requests, no IMAP or MDNs is done
+ * and the internal state is not changed therefore.
+ * See also marknoticed_chat().
+ *
+ * Moreover, timer is started for incoming ephemeral messages.
+ * This also happens for contact requests chats.
+ *
+ * This function updates `last_msg_id` configuration value
+ * to the maximum of the current value and IDs passed to this function.
+ * Bots which mark messages as seen can rely on this side effect
+ * to avoid updating `last_msg_id` value manually.
+ *
+ * One #DC_EVENT_MSGS_NOTICED event is emitted per modified chat.
+ */
+ public void markseenMsgs(Integer accountId, java.util.List msgIds) throws RpcException {
+ transport.call("markseen_msgs", mapper.valueToTree(accountId), mapper.valueToTree(msgIds));
+ }
+
+ /**
+ * Returns all messages of a particular chat.
+ *
+ * * `add_daymarker` - If `true`, add day markers as `DC_MSG_ID_DAYMARKER` to the result,
+ * e.g. [1234, 1237, 9, 1239]. The day marker timestamp is the midnight one for the
+ * corresponding (following) day in the local timezone.
+ */
+ public java.util.List getMessageIds(Integer accountId, Integer chatId, Boolean infoOnly, Boolean addDaymarker) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_message_ids", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(infoOnly), mapper.valueToTree(addDaymarker));
+ }
+
+ public java.util.List getMessageListItems(Integer accountId, Integer chatId, Boolean infoOnly, Boolean addDaymarker) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_message_list_items", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(infoOnly), mapper.valueToTree(addDaymarker));
+ }
+
+ public Message getMessage(Integer accountId, Integer msgId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_message", mapper.valueToTree(accountId), mapper.valueToTree(msgId));
+ }
+
+ public String getMessageHtml(Integer accountId, Integer messageId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_message_html", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
+ }
+
+ /**
+ * get multiple messages in one call,
+ * if loading one message fails the error is stored in the result object in it's place.
+ *
+ * this is the batch variant of [get_message]
+ */
+ public java.util.Map getMessages(Integer accountId, java.util.List messageIds) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_messages", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
+ }
+
+ /* Fetch info desktop needs for creating a notification for a message */
+ public MessageNotificationInfo getMessageNotificationInfo(Integer accountId, Integer messageId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_message_notification_info", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
+ }
+
+ /**
+ * Delete messages. The messages are deleted on the current device and
+ * on the IMAP server.
+ */
+ public void deleteMessages(Integer accountId, java.util.List messageIds) throws RpcException {
+ transport.call("delete_messages", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
+ }
+
+ /**
+ * Delete messages. The messages are deleted on the current device,
+ * on the IMAP server and also for all chat members
+ */
+ public void deleteMessagesForAll(Integer accountId, java.util.List messageIds) throws RpcException {
+ transport.call("delete_messages_for_all", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
+ }
+
+ /**
+ * Get an informational text for a single message. The text is multiline and may
+ * contain e.g. the raw text of the message.
+ *
+ * The max. text returned is typically longer (about 100000 characters) than the
+ * max. text returned by dc_msg_get_text() (about 30000 characters).
+ */
+ public String getMessageInfo(Integer accountId, Integer messageId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_message_info", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
+ }
+
+ /* Returns additional information for single message. */
+ public MessageInfo getMessageInfoObject(Integer accountId, Integer messageId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_message_info_object", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
+ }
+
+ /* Returns contacts that sent read receipts and the time of reading. */
+ public java.util.List getMessageReadReceipts(Integer accountId, Integer messageId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_message_read_receipts", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
+ }
+
+ /**
+ * Asks the core to start downloading a message fully.
+ * This function is typically called when the user hits the "Download" button
+ * that is shown by the UI in case `download_state` is `'Available'` or `'Failure'`
+ *
+ * On success, the @ref DC_MSG "view type of the message" may change
+ * or the message may be replaced completely by one or more messages with other message IDs.
+ * That may happen e.g. in cases where the message was encrypted
+ * and the type could not be determined without fully downloading.
+ * Downloaded content can be accessed as usual after download.
+ *
+ * To reflect these changes a @ref DC_EVENT_MSGS_CHANGED event will be emitted.
+ */
+ public void downloadFullMessage(Integer accountId, Integer messageId) throws RpcException {
+ transport.call("download_full_message", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
+ }
+
+ /**
+ * Search messages containing the given query string.
+ * Searching can be done globally (chat_id=None) or in a specified chat only (chat_id set).
+ *
+ * Global search results are typically displayed using dc_msg_get_summary(), chat
+ * search results may just highlight the corresponding messages and present a
+ * prev/next button.
+ *
+ * For the global search, the result is limited to 1000 messages,
+ * this allows an incremental search done fast.
+ * So, when getting exactly 1000 messages, the result actually may be truncated;
+ * the UIs may display sth. like "1000+ messages found" in this case.
+ * The chat search (if chat_id is set) is not limited.
+ */
+ public java.util.List searchMessages(Integer accountId, String query, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "search_messages", mapper.valueToTree(accountId), mapper.valueToTree(query), mapper.valueToTree(chatId));
+ }
+
+ public java.util.Map messageIdsToSearchResults(Integer accountId, java.util.List messageIds) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "message_ids_to_search_results", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
+ }
+
+ public void saveMsgs(Integer accountId, java.util.List messageIds) throws RpcException {
+ transport.call("save_msgs", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
+ }
+
+ /* Get a single contact options by ID. */
+ public Contact getContact(Integer accountId, Integer contactId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_contact", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
+ }
+
+ /**
+ * Add a single contact as a result of an explicit user action.
+ *
+ * This will always create or look up an address-contact,
+ * i.e. a contact identified by an email address,
+ * with all messages sent to and from this contact being unencrypted.
+ * If the user just clicked on an email address,
+ * you should first check [`Self::lookup_contact_id_by_addr`]/`lookupContactIdByAddr.`,
+ * and only if there is no contact yet, call this function here.
+ *
+ * Returns contact id of the created or existing contact.
+ */
+ public Integer createContact(Integer accountId, String email, String name) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "create_contact", mapper.valueToTree(accountId), mapper.valueToTree(email), mapper.valueToTree(name));
+ }
+
/* Returns contact id of the created or existing DM chat with that contact */
public Integer createChatByContactId(Integer accountId, Integer contactId) throws RpcException {
return transport.callForResult(new TypeReference(){}, "create_chat_by_contact_id", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
}
+ public void blockContact(Integer accountId, Integer contactId) throws RpcException {
+ transport.call("block_contact", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
+ }
+
+ public void unblockContact(Integer accountId, Integer contactId) throws RpcException {
+ transport.call("unblock_contact", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
+ }
+
+ public java.util.List getBlockedContacts(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_blocked_contacts", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Returns ids of known and unblocked contacts.
+ *
+ * By default, key-contacts are listed.
+ *
+ * * `list_flags` - A combination of flags:
+ * - `DC_GCL_ADD_SELF` - Add SELF unless filtered by other parameters.
+ * - `DC_GCL_ADDRESS` - List address-contacts instead of key-contacts.
+ * * `query` - A string to filter the list.
+ */
+ public java.util.List getContactIds(Integer accountId, Integer listFlags, String query) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_contact_ids", mapper.valueToTree(accountId), mapper.valueToTree(listFlags), mapper.valueToTree(query));
+ }
+
+ /**
+ * Returns known and unblocked contacts.
+ *
+ * Formerly called `getContacts2` in Desktop.
+ * See [`Self::get_contact_ids`] for parameters and more info.
+ */
+ public java.util.List getContacts(Integer accountId, Integer listFlags, String query) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_contacts", mapper.valueToTree(accountId), mapper.valueToTree(listFlags), mapper.valueToTree(query));
+ }
+
+ public java.util.Map getContactsByIds(Integer accountId, java.util.List ids) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_contacts_by_ids", mapper.valueToTree(accountId), mapper.valueToTree(ids));
+ }
+
+ public void deleteContact(Integer accountId, Integer contactId) throws RpcException {
+ transport.call("delete_contact", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
+ }
+
/* Sets display name for existing contact. */
public void changeContactName(Integer accountId, Integer contactId, String name) throws RpcException {
transport.call("change_contact_name", mapper.valueToTree(accountId), mapper.valueToTree(contactId), mapper.valueToTree(name));
}
+ /**
+ * Get encryption info for a contact.
+ * Get a multi-line encryption info, containing your fingerprint and the
+ * fingerprint of the contact, used e.g. to compare the fingerprints for a simple out-of-band verification.
+ */
+ public String getContactEncryptionInfo(Integer accountId, Integer contactId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_contact_encryption_info", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
+ }
+
+ /**
+ * Looks up a known and unblocked contact with a given e-mail address.
+ * To get a list of all known and unblocked contacts, use contacts_get_contacts().
+ *
+ * **POTENTIAL SECURITY ISSUE**: If there are multiple contacts with this address
+ * (e.g. an address-contact and a key-contact),
+ * this looks up the most recently seen contact,
+ * i.e. which contact is returned depends on which contact last sent a message.
+ * If the user just clicked on a mailto: link, then this is the best thing you can do.
+ * But **DO NOT** internally represent contacts by their email address
+ * and do not use this function to look them up;
+ * otherwise this function will sometimes look up the wrong contact.
+ * Instead, you should internally represent contacts by their ids.
+ *
+ * To validate an e-mail address independently of the contact database
+ * use check_email_validity().
+ */
+ public Integer lookupContactIdByAddr(Integer accountId, String addr) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "lookup_contact_id_by_addr", mapper.valueToTree(accountId), mapper.valueToTree(addr));
+ }
/* Parses a vCard file located at the given path. Returns contacts in their original order. */
public java.util.List parseVcard(String path) throws RpcException {
@@ -162,11 +1046,168 @@ public class Rpc {
return transport.callForResult(new TypeReference>(){}, "import_vcard", mapper.valueToTree(accountId), mapper.valueToTree(path));
}
+ /**
+ * Imports contacts from a vCard.
+ *
+ * Returns the ids of created/modified contacts in the order they appear in the vCard.
+ */
+ public java.util.List importVcardContents(Integer accountId, String vcard) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "import_vcard_contents", mapper.valueToTree(accountId), mapper.valueToTree(vcard));
+ }
+
/* Returns a vCard containing contacts with the given ids. */
public String makeVcard(Integer accountId, java.util.List contacts) throws RpcException {
return transport.callForResult(new TypeReference(){}, "make_vcard", mapper.valueToTree(accountId), mapper.valueToTree(contacts));
}
+ /* Sets vCard containing the given contacts to the message draft. */
+ public void setDraftVcard(Integer accountId, Integer msgId, java.util.List contacts) throws RpcException {
+ transport.call("set_draft_vcard", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(contacts));
+ }
+
+ /**
+ * Returns the [`ChatId`] for the 1:1 chat with `contact_id` if it exists.
+ *
+ * If it does not exist, `None` is returned.
+ */
+ public Integer getChatIdByContactId(Integer accountId, Integer contactId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_chat_id_by_contact_id", mapper.valueToTree(accountId), mapper.valueToTree(contactId));
+ }
+
+ /**
+ * Returns all message IDs of the given types in a chat.
+ * Typically used to show a gallery.
+ *
+ * The list is already sorted and starts with the oldest message.
+ * Clients should not try to re-sort the list as this would be an expensive action
+ * and would result in inconsistencies between clients.
+ *
+ * Setting `chat_id` to `None` (`null` in typescript) means get messages with media
+ * from any chat of the currently used account.
+ */
+ public java.util.List getChatMedia(Integer accountId, Integer chatId, Viewtype messageType, Viewtype orMessageType2, Viewtype orMessageType3) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_chat_media", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(messageType), mapper.valueToTree(orMessageType2), mapper.valueToTree(orMessageType3));
+ }
+
+ public void exportBackup(Integer accountId, String destination, String passphrase) throws RpcException {
+ transport.call("export_backup", mapper.valueToTree(accountId), mapper.valueToTree(destination), mapper.valueToTree(passphrase));
+ }
+
+ public void importBackup(Integer accountId, String path, String passphrase) throws RpcException {
+ transport.call("import_backup", mapper.valueToTree(accountId), mapper.valueToTree(path), mapper.valueToTree(passphrase));
+ }
+
+ /**
+ * Offers a backup for remote devices to retrieve.
+ *
+ * Can be canceled by stopping the ongoing process. Success or failure can be tracked
+ * via the `ImexProgress` event which should either reach `1000` for success or `0` for
+ * failure.
+ *
+ * This **stops IO** while it is running.
+ *
+ * Returns once a remote device has retrieved the backup, or is canceled.
+ */
+ public void provideBackup(Integer accountId) throws RpcException {
+ transport.call("provide_backup", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Returns the text of the QR code for the running [`CommandApi::provide_backup`].
+ *
+ * This QR code text can be used in [`CommandApi::get_backup`] on a second device to
+ * retrieve the backup and setup this second device.
+ *
+ * This call will block until the QR code is ready,
+ * even if there is no concurrent call to [`CommandApi::provide_backup`],
+ * but will fail after 60 seconds to avoid deadlocks.
+ */
+ public String getBackupQr(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_backup_qr", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Returns the rendered QR code for the running [`CommandApi::provide_backup`].
+ *
+ * This QR code can be used in [`CommandApi::get_backup`] on a second device to
+ * retrieve the backup and setup this second device.
+ *
+ * This call will block until the QR code is ready,
+ * even if there is no concurrent call to [`CommandApi::provide_backup`],
+ * but will fail after 60 seconds to avoid deadlocks.
+ *
+ * Returns the QR code rendered as an SVG image.
+ */
+ public String getBackupQrSvg(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_backup_qr_svg", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Gets a backup from a remote provider.
+ *
+ * This retrieves the backup from a remote device over the network and imports it into
+ * the current device.
+ *
+ * Can be canceled by stopping the ongoing process.
+ *
+ * Do not forget to call start_io on the account after a successful import,
+ * otherwise it will not connect to the email server.
+ */
+ public void getBackup(Integer accountId, String qrText) throws RpcException {
+ transport.call("get_backup", mapper.valueToTree(accountId), mapper.valueToTree(qrText));
+ }
+
+ /**
+ * Indicate that the network likely has come back.
+ * or just that the network conditions might have changed
+ */
+ public void maybeNetwork() throws RpcException {
+ transport.call("maybe_network");
+ }
+
+ /**
+ * Get the current connectivity, i.e. whether the device is connected to the IMAP server.
+ * One of:
+ * - DC_CONNECTIVITY_NOT_CONNECTED (1000-1999): Show e.g. the string "Not connected" or a red dot
+ * - DC_CONNECTIVITY_CONNECTING (2000-2999): Show e.g. the string "Connecting…" or a yellow dot
+ * - DC_CONNECTIVITY_WORKING (3000-3999): Show e.g. the string "Getting new messages" or a spinning wheel
+ * - DC_CONNECTIVITY_CONNECTED (>=4000): Show e.g. the string "Connected" or a green dot
+ *
+ * We don't use exact values but ranges here so that we can split up
+ * states into multiple states in the future.
+ *
+ * Meant as a rough overview that can be shown
+ * e.g. in the title of the main screen.
+ *
+ * If the connectivity changes, a #DC_EVENT_CONNECTIVITY_CHANGED will be emitted.
+ */
+ public Integer getConnectivity(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_connectivity", mapper.valueToTree(accountId));
+ }
+
+ /**
+ * Get an overview of the current connectivity, and possibly more statistics.
+ * Meant to give the user more insight about the current status than
+ * the basic connectivity info returned by get_connectivity(); show this
+ * e.g., if the user taps on said basic connectivity info.
+ *
+ * If this page changes, a #DC_EVENT_CONNECTIVITY_CHANGED will be emitted.
+ *
+ * This comes as an HTML from the core so that we can easily improve it
+ * and the improvement instantly reaches all UIs.
+ */
+ public String getConnectivityHtml(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_connectivity_html", mapper.valueToTree(accountId));
+ }
+
+ public java.util.List getLocations(Integer accountId, Integer chatId, Integer contactId, Integer timestampBegin, Integer timestampEnd) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "get_locations", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(contactId), mapper.valueToTree(timestampBegin), mapper.valueToTree(timestampEnd));
+ }
+
+ public void sendWebxdcStatusUpdate(Integer accountId, Integer instanceMsgId, String updateStr, String descr) throws RpcException {
+ transport.call("send_webxdc_status_update", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(updateStr), mapper.valueToTree(descr));
+ }
+
public void sendWebxdcRealtimeData(Integer accountId, Integer instanceMsgId, java.util.List data) throws RpcException {
transport.call("send_webxdc_realtime_data", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(data));
}
@@ -186,6 +1227,50 @@ public class Rpc {
transport.call("leave_webxdc_realtime", mapper.valueToTree(accountId), mapper.valueToTree(instanceMessageId));
}
+ public String getWebxdcStatusUpdates(Integer accountId, Integer instanceMsgId, Integer lastKnownSerial) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_webxdc_status_updates", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(lastKnownSerial));
+ }
+
+ /* Get info from a webxdc message */
+ public WebxdcMessageInfo getWebxdcInfo(Integer accountId, Integer instanceMsgId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_webxdc_info", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId));
+ }
+
+ /**
+ * Get href from a WebxdcInfoMessage which might include a hash holding
+ * information about a specific position or state in a webxdc app (optional)
+ */
+ public String getWebxdcHref(Integer accountId, Integer infoMsgId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_webxdc_href", mapper.valueToTree(accountId), mapper.valueToTree(infoMsgId));
+ }
+
+ /**
+ * Get blob encoded as base64 from a webxdc message
+ *
+ * path is the path of the file within webxdc archive
+ */
+ public String getWebxdcBlob(Integer accountId, Integer instanceMsgId, String path) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_webxdc_blob", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(path));
+ }
+
+ /**
+ * Sets Webxdc file as integration.
+ * `file` is the .xdc to use as Webxdc integration.
+ */
+ public void setWebxdcIntegration(Integer accountId, String filePath) throws RpcException {
+ transport.call("set_webxdc_integration", mapper.valueToTree(accountId), mapper.valueToTree(filePath));
+ }
+
+ /**
+ * Returns Webxdc instance used for optional integrations.
+ * UI can open the Webxdc as usual.
+ * Returns `None` if there is no integration; the caller can add one using `set_webxdc_integration` then.
+ * `integrate_for` is the chat to get the integration for.
+ */
+ public Integer initWebxdcIntegration(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "init_webxdc_integration", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
/* Starts an outgoing call. */
public Integer placeOutgoingCall(Integer accountId, Integer chatId, String placeCallInfo) throws RpcException {
return transport.callForResult(new TypeReference(){}, "place_outgoing_call", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(placeCallInfo));
@@ -220,6 +1305,36 @@ public class Rpc {
return transport.callForResult(new TypeReference(){}, "get_http_response", mapper.valueToTree(accountId), mapper.valueToTree(url));
}
+ /**
+ * Forward messages to another chat.
+ *
+ * All types of messages can be forwarded,
+ * however, they will be flagged as such (dc_msg_is_forwarded() is set).
+ *
+ * Original sender, info-state and webxdc updates are not forwarded on purpose.
+ */
+ public void forwardMessages(Integer accountId, java.util.List messageIds, Integer chatId) throws RpcException {
+ transport.call("forward_messages", mapper.valueToTree(accountId), mapper.valueToTree(messageIds), mapper.valueToTree(chatId));
+ }
+
+ /**
+ * Resend messages and make information available for newly added chat members.
+ * Resending sends out the original message, however, recipients and webxdc-status may differ.
+ * Clients that already have the original message can still ignore the resent message as
+ * they have tracked the state by dedicated updates.
+ *
+ * Some messages cannot be resent, eg. info-messages, drafts, already pending messages or messages that are not sent by SELF.
+ *
+ * message_ids all message IDs that should be resend. All messages must belong to the same chat.
+ */
+ public void resendMessages(Integer accountId, java.util.List messageIds) throws RpcException {
+ transport.call("resend_messages", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
+ }
+
+ public Integer sendSticker(Integer accountId, Integer chatId, String stickerPath) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "send_sticker", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(stickerPath));
+ }
+
/**
* Send a reaction to message.
*
@@ -237,9 +1352,102 @@ public class Rpc {
return transport.callForResult(new TypeReference(){}, "get_message_reactions", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
}
+ public Integer sendMsg(Integer accountId, Integer chatId, MessageData data) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "send_msg", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(data));
+ }
+
+ public void sendEditRequest(Integer accountId, Integer msgId, String newText) throws RpcException {
+ transport.call("send_edit_request", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(newText));
+ }
+
/* Checks if messages can be sent to a given chat. */
public Boolean canSend(Integer accountId, Integer chatId) throws RpcException {
return transport.callForResult(new TypeReference(){}, "can_send", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
}
-}
+ /**
+ * Saves a file copy at the user-provided path.
+ *
+ * Fails if file already exists at the provided path.
+ */
+ public void saveMsgFile(Integer accountId, Integer msgId, String path) throws RpcException {
+ transport.call("save_msg_file", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(path));
+ }
+
+ public void removeDraft(Integer accountId, Integer chatId) throws RpcException {
+ transport.call("remove_draft", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ /* Get draft for a chat, if any. */
+ public Message getDraft(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "get_draft", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+ public String miscGetStickerFolder(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "misc_get_sticker_folder", mapper.valueToTree(accountId));
+ }
+
+ /* Saves a sticker to a collection/folder in the account's sticker folder. */
+ public void miscSaveSticker(Integer accountId, Integer msgId, String collection) throws RpcException {
+ transport.call("misc_save_sticker", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(collection));
+ }
+
+ /**
+ * for desktop, get stickers from stickers folder,
+ * grouped by the collection/folder they are in.
+ */
+ public java.util.Map> miscGetStickers(Integer accountId) throws RpcException {
+ return transport.callForResult(new TypeReference>>(){}, "misc_get_stickers", mapper.valueToTree(accountId));
+ }
+
+ /* Returns the messageid of the sent message */
+ public Integer miscSendTextMessage(Integer accountId, Integer chatId, String text) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "misc_send_text_message", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(text));
+ }
+
+ /**
+ * Send a message to a chat.
+ *
+ * This function returns after the message has been placed in the sending queue.
+ * This does not imply that the message was really sent out yet.
+ * However, from your view, you're done with the message.
+ * Sooner or later it will find its way.
+ *
+ * **Attaching files:**
+ *
+ * Pass the file path in the `file` parameter.
+ * If `file` is not in the blob directory yet,
+ * it will be copied into the blob directory.
+ * If you want, you can delete the file immediately after this function returns.
+ *
+ * You can also write the attachment directly into the blob directory
+ * and then pass the path as the `file` parameter;
+ * this will prevent an unnecessary copying of the file.
+ *
+ * In `filename`, you can pass the original name of the file,
+ * which will then be shown in the UI.
+ * in this case the current name of `file` on the filesystem will be ignored.
+ *
+ * In order to deduplicate files that contain the same data,
+ * the file will be named `.`, e.g. `ce940175885d7b78f7b7e9f1396611f.jpg`.
+ *
+ * NOTE:
+ * - This function will rename the file. To get the new file path, call `get_file()`.
+ * - The file must not be modified after this function was called.
+ * - Images etc. will NOT be recoded.
+ * In order to recode images,
+ * use `misc_set_draft` and pass `Image` as the viewtype.
+ */
+ public Pair miscSendMsg(Integer accountId, Integer chatId, String text, String file, String filename, Pair location, Integer quotedMessageId) throws RpcException {
+ return transport.callForResult(new TypeReference>(){}, "misc_send_msg", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(text), mapper.valueToTree(file), mapper.valueToTree(filename), mapper.valueToTree(location), mapper.valueToTree(quotedMessageId));
+ }
+
+ public void miscSetDraft(Integer accountId, Integer chatId, String text, String file, String filename, Integer quotedMessageId, Viewtype viewType) throws RpcException {
+ transport.call("misc_set_draft", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(text), mapper.valueToTree(file), mapper.valueToTree(filename), mapper.valueToTree(quotedMessageId), mapper.valueToTree(viewType));
+ }
+
+ public Integer miscSendDraft(Integer accountId, Integer chatId) throws RpcException {
+ return transport.callForResult(new TypeReference(){}, "misc_send_draft", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Account.java b/src/main/java/chat/delta/rpc/types/Account.java
new file mode 100644
index 000000000..ab3a9778f
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Account.java
@@ -0,0 +1,32 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = Account.Configured.class, name="Configured"), @Type(value = Account.Unconfigured.class, name="Unconfigured")})
+public abstract class Account {
+
+ public static class Configured extends Account {
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String addr;
+ public String color;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String displayName;
+ public Integer id;
+ /* Optional tag as "Work", "Family". Meant to help profile owner to differ between profiles with similar names. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String privateTag;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String profileImage;
+ }
+
+ public static class Unconfigured extends Account {
+ public Integer id;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/BasicChat.java b/src/main/java/chat/delta/rpc/types/BasicChat.java
new file mode 100644
index 000000000..5ca3526fe
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/BasicChat.java
@@ -0,0 +1,35 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+/**
+ * cheaper version of fullchat, omits: - contacts - contact_ids - fresh_message_counter - ephemeral_timer - self_in_group - was_seen_recently - can_send
+ *
+ * used when you only need the basic metadata of a chat like type, name, profile picture
+ */
+public class BasicChat {
+ public Boolean archived;
+ public ChatType chatType;
+ public String color;
+ public Integer id;
+ public Boolean isContactRequest;
+ public Boolean isDeviceChat;
+ /**
+ * True if the chat is encrypted. This means that all messages in the chat are encrypted, and all contacts in the chat are "key-contacts", i.e. identified by the PGP key fingerprint.
+ *
+ * False if the chat is unencrypted. This means that all messages in the chat are unencrypted, and all contacts in the chat are "address-contacts", i.e. identified by the email address. The UI should mark this chat e.g. with a mail-letter icon.
+ *
+ * Unencrypted groups are called "ad-hoc groups" and the user can't add/remove members, create a QR invite code, or set an avatar. These options should therefore be disabled in the UI.
+ *
+ * Note that it can happen that an encrypted chat contains unencrypted messages that were received in core <= v1.159.* and vice versa.
+ *
+ * See also `is_key_contact` on `Contact`.
+ */
+ public Boolean isEncrypted;
+ public Boolean isMuted;
+ public Boolean isSelfTalk;
+ public Boolean isUnpromoted;
+ public String name;
+ public Boolean pinned;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String profileImage;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/ChatListItemFetchResult.java b/src/main/java/chat/delta/rpc/types/ChatListItemFetchResult.java
new file mode 100644
index 000000000..687aa35be
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/ChatListItemFetchResult.java
@@ -0,0 +1,71 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = ChatListItemFetchResult.ChatListItem.class, name="ChatListItem"), @Type(value = ChatListItemFetchResult.ArchiveLink.class, name="ArchiveLink"), @Type(value = ChatListItemFetchResult.Error.class, name="Error")})
+public abstract class ChatListItemFetchResult {
+
+ public static class ChatListItem extends ChatListItemFetchResult {
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String avatarPath;
+ public ChatType chatType;
+ public String color;
+ /* contact id if this is a dm chat (for view profile entry in context menu) */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer dmChatContact;
+ public Integer freshMessageCounter;
+ public Integer id;
+ public Boolean isArchived;
+ public Boolean isContactRequest;
+ public Boolean isDeviceTalk;
+ /**
+ * True if the chat is encrypted. This means that all messages in the chat are encrypted, and all contacts in the chat are "key-contacts", i.e. identified by the PGP key fingerprint.
+ *
+ * False if the chat is unencrypted. This means that all messages in the chat are unencrypted, and all contacts in the chat are "address-contacts", i.e. identified by the email address. The UI should mark this chat e.g. with a mail-letter icon.
+ *
+ * Unencrypted groups are called "ad-hoc groups" and the user can't add/remove members, create a QR invite code, or set an avatar. These options should therefore be disabled in the UI.
+ *
+ * Note that it can happen that an encrypted chat contains unencrypted messages that were received in core <= v1.159.* and vice versa.
+ *
+ * See also `is_key_contact` on `Contact`.
+ */
+ public Boolean isEncrypted;
+ /* deprecated 2025-07, use chat_type instead */
+ public Boolean isGroup;
+ public Boolean isMuted;
+ public Boolean isPinned;
+ public Boolean isSelfInGroup;
+ public Boolean isSelfTalk;
+ public Boolean isSendingLocation;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer lastMessageId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Viewtype lastMessageType;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer lastUpdated;
+ public String name;
+ /* showing preview if last chat message is image */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String summaryPreviewImage;
+ public Integer summaryStatus;
+ public String summaryText1;
+ public String summaryText2;
+ public Boolean wasSeenRecently;
+ }
+
+ public static class ArchiveLink extends ChatListItemFetchResult {
+ public Integer freshMessageCounter;
+ }
+
+ public static class Error extends ChatListItemFetchResult {
+ public String error;
+ public Integer id;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/ChatType.java b/src/main/java/chat/delta/rpc/types/ChatType.java
new file mode 100644
index 000000000..ef7d360e9
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/ChatType.java
@@ -0,0 +1,10 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum ChatType {
+ Single,
+ Group,
+ Mailinglist,
+ OutBroadcast,
+ InBroadcast,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/ChatVisibility.java b/src/main/java/chat/delta/rpc/types/ChatVisibility.java
new file mode 100644
index 000000000..340595a61
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/ChatVisibility.java
@@ -0,0 +1,8 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum ChatVisibility {
+ Normal,
+ Archived,
+ Pinned,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Contact.java b/src/main/java/chat/delta/rpc/types/Contact.java
new file mode 100644
index 000000000..91ed6d273
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Contact.java
@@ -0,0 +1,52 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class Contact {
+ public String address;
+ public String authName;
+ public String color;
+ public String displayName;
+ /**
+ * Is encryption available for this contact.
+ *
+ * This can only be true for key-contacts. However, it is possible to have a key-contact for which encryption is not available because we don't have a key yet, e.g. if we just scanned the fingerprint from a QR code.
+ */
+ public Boolean e2eeAvail;
+ public Integer id;
+ public Boolean isBlocked;
+ /* If the contact is a bot. */
+ public Boolean isBot;
+ /* Is the contact a key contact. */
+ public Boolean isKeyContact;
+ /**
+ * True if the contact can be added to protected chats because SELF and contact have verified their fingerprints in both directions.
+ *
+ * See [`Self::verifier_id`]/`Contact.verifierId` for a guidance how to display these information.
+ */
+ public Boolean isVerified;
+ /* the contact's last seen timestamp */
+ public Integer lastSeen;
+ public String name;
+ public String nameAndAddr;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String profileImage;
+ public String status;
+ /**
+ * The contact ID that verified a contact.
+ *
+ * As verifier may be unknown, use [`Self::is_verified`]/`Contact.isVerified` to check if a contact can be added to a protected chat.
+ *
+ * UI should display the information in the contact's profile as follows:
+ *
+ * - If `verifierId` != 0, display text "Introduced by ..." with the name and address of the contact formatted by `name_and_addr`/`nameAndAddr`. Prefix the text by a green checkmark.
+ *
+ * - If `verifierId` == 0 and `isVerified` != 0, display "Introduced" prefixed by a green checkmark.
+ *
+ * - if `verifierId` == 0 and `isVerified` == 0, display nothing
+ *
+ * This contains the contact ID of the verifier. If it is `DC_CONTACT_ID_SELF`, we verified the contact ourself. If it is None/Null, we don't have verifier information or the contact is not verified.
+ */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer verifierId;
+ public Boolean wasSeenRecently;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/DownloadState.java b/src/main/java/chat/delta/rpc/types/DownloadState.java
new file mode 100644
index 000000000..4a8cbad3c
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/DownloadState.java
@@ -0,0 +1,10 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum DownloadState {
+ Done,
+ Available,
+ Failure,
+ Undecipherable,
+ InProgress,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/EphemeralTimer.java b/src/main/java/chat/delta/rpc/types/EphemeralTimer.java
new file mode 100644
index 000000000..fb4e34f72
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/EphemeralTimer.java
@@ -0,0 +1,28 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = EphemeralTimer.Disabled.class, name="Disabled"), @Type(value = EphemeralTimer.Enabled.class, name="Enabled")})
+public abstract class EphemeralTimer {
+
+/* Timer is disabled. */
+ public static class Disabled extends EphemeralTimer {
+ }
+
+/* Timer is enabled. */
+ public static class Enabled extends EphemeralTimer {
+ /**
+ * Timer duration in seconds.
+ *
+ * This event should *not* be reported to the end-user using a popup or something like that.
+ */
+ public static class Info extends EventType {
+ public String msg;
+ }
+
+/* Emitted when SMTP connection is established and login was successful. */
+ public static class SmtpConnected extends EventType {
+ public String msg;
+ }
+
+/* Emitted when IMAP connection is established and login was successful. */
+ public static class ImapConnected extends EventType {
+ public String msg;
+ }
+
+/* Emitted when a message was successfully sent to the SMTP server. */
+ public static class SmtpMessageSent extends EventType {
+ public String msg;
+ }
+
+/* Emitted when an IMAP message has been marked as deleted */
+ public static class ImapMessageDeleted extends EventType {
+ public String msg;
+ }
+
+/* Emitted when an IMAP message has been moved */
+ public static class ImapMessageMoved extends EventType {
+ public String msg;
+ }
+
+/* Emitted before going into IDLE on the Inbox folder. */
+ public static class ImapInboxIdle extends EventType {
+ }
+
+/* Emitted when an new file in the $BLOBDIR was created */
+ public static class NewBlobFile extends EventType {
+ public String file;
+ }
+
+/* Emitted when an file in the $BLOBDIR was deleted */
+ public static class DeletedBlobFile extends EventType {
+ public String file;
+ }
+
+/**
+ * The library-user should write a warning string to the log.
+ *
+ * This event should *not* be reported to the end-user using a popup or something like that.
+ */
+ public static class Warning extends EventType {
+ public String msg;
+ }
+
+/**
+ * The library-user should report an error to the end-user.
+ *
+ * As most things are asynchronous, things may go wrong at any time and the user should not be disturbed by a dialog or so. Instead, use a bubble or so.
+ *
+ * However, for ongoing processes (eg. configure()) or for functions that are expected to fail (eg. autocryptContinueKeyTransfer()) it might be better to delay showing these events until the function has really failed (returned false). It should be sufficient to report only the *last* error in a message box then.
+ */
+ public static class Error extends EventType {
+ public String msg;
+ }
+
+/* An action cannot be performed because the user is not in the group. Reported eg. after a call to setChatName(), setChatProfileImage(), addContactToChat(), removeContactFromChat(), and messages sending functions. */
+ public static class ErrorSelfNotInGroup extends EventType {
+ public String msg;
+ }
+
+/* Messages or chats changed. One or more messages or chats changed for various reasons in the database: - Messages sent, received or removed - Chats created, deleted or archived - A draft has been set */
+ public static class MsgsChanged extends EventType {
+ /* Set if only a single chat is affected by the changes, otherwise 0. */
+ public Integer chatId;
+ /* Set if only a single message is affected by the changes, otherwise 0. */
+ public Integer msgId;
+ }
+
+/* Reactions for the message changed. */
+ public static class ReactionsChanged extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chatId;
+ /* ID of the contact whose reaction set is changed. */
+ public Integer contactId;
+ /* ID of the message for which reactions were changed. */
+ public Integer msgId;
+ }
+
+/**
+ * A reaction to one's own sent message received. Typically, the UI will show a notification for that.
+ *
+ * In addition to this event, ReactionsChanged is emitted.
+ */
+ public static class IncomingReaction extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chatId;
+ /* ID of the contact whose reaction set is changed. */
+ public Integer contactId;
+ /* ID of the message for which reactions were changed. */
+ public Integer msgId;
+ /* The reaction. */
+ public String reaction;
+ }
+
+/* Incoming webxdc info or summary update, should be notified. */
+ public static class IncomingWebxdcNotify extends EventType {
+ /* ID of the chat. */
+ public Integer chatId;
+ /* ID of the contact sending. */
+ public Integer contactId;
+ /* Link assigned to this notification, if any. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String href;
+ /* ID of the added info message or webxdc instance in case of summary change. */
+ public Integer msgId;
+ /* Text to notify. */
+ public String text;
+ }
+
+/**
+ * There is a fresh message. Typically, the user will show a notification when receiving this message.
+ *
+ * There is no extra #DC_EVENT_MSGS_CHANGED event sent together with this event.
+ */
+ public static class IncomingMsg extends EventType {
+ /* ID of the chat where the message is assigned. */
+ public Integer chatId;
+ /* ID of the message. */
+ public Integer msgId;
+ }
+
+/* Downloading a bunch of messages just finished. This is an event to allow the UI to only show one notification per message bunch, instead of cluttering the user with many notifications. */
+ public static class IncomingMsgBunch extends EventType {
+ }
+
+/* Messages were seen or noticed. chat id is always set. */
+ public static class MsgsNoticed extends EventType {
+ public Integer chatId;
+ }
+
+/* A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to DC_STATE_OUT_DELIVERED, see `Message.state`. */
+ public static class MsgDelivered extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chatId;
+ /* ID of the message that was successfully sent. */
+ public Integer msgId;
+ }
+
+/* A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to DC_STATE_OUT_FAILED, see `Message.state`. */
+ public static class MsgFailed extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chatId;
+ /* ID of the message that could not be sent. */
+ public Integer msgId;
+ }
+
+/* A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to DC_STATE_OUT_MDN_RCVD, see `Message.state`. */
+ public static class MsgRead extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chatId;
+ /* ID of the message that was read. */
+ public Integer msgId;
+ }
+
+/**
+ * A single message was deleted.
+ *
+ * This event means that the message will no longer appear in the messagelist. UI should remove the message from the messagelist in response to this event if the message is currently displayed.
+ *
+ * The message may have been explicitly deleted by the user or expired. Internally the message may have been removed from the database, moved to the trash chat or hidden.
+ *
+ * This event does not indicate the message deletion from the server.
+ */
+ public static class MsgDeleted extends EventType {
+ /* ID of the chat where the message was prior to deletion. Never 0. */
+ public Integer chatId;
+ /* ID of the deleted message. Never 0. */
+ public Integer msgId;
+ }
+
+/**
+ * Chat changed. The name or the image of a chat group was changed or members were added or removed. See setChatName(), setChatProfileImage(), addContactToChat() and removeContactFromChat().
+ *
+ * This event does not include ephemeral timer modification, which is a separate event.
+ */
+ public static class ChatModified extends EventType {
+ public Integer chatId;
+ }
+
+/* Chat ephemeral timer changed. */
+ public static class ChatEphemeralTimerModified extends EventType {
+ /* Chat ID. */
+ public Integer chatId;
+ /* New ephemeral timer value. */
+ public Integer timer;
+ }
+
+/* Chat deleted. */
+ public static class ChatDeleted extends EventType {
+ /* Chat ID. */
+ public Integer chat_id;
+ }
+
+/* Contact(s) created, renamed, blocked or deleted. */
+ public static class ContactsChanged extends EventType {
+ /* If set, this is the contact_id of an added contact that should be selected. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer contactId;
+ }
+
+/* Location of one or more contact has changed. */
+ public static class LocationChanged extends EventType {
+ /* contact_id of the contact for which the location has changed. If the locations of several contacts have been changed, this parameter is set to `None`. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer contactId;
+ }
+
+/* Inform about the configuration progress started by configure(). */
+ public static class ConfigureProgress extends EventType {
+ /* Progress comment or error, something to display to the user. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String comment;
+ /**
+ * Progress.
+ *
+ * 0=error, 1-999=progress in permille, 1000=success and done
+ */
+ public Integer progress;
+ }
+
+/* Inform about the import/export progress started by imex(). */
+ public static class ImexProgress extends EventType {
+ /* 0=error, 1-999=progress in permille, 1000=success and done */
+ public Integer progress;
+ }
+
+/**
+ * A file has been exported. A file has been written by imex(). This event may be sent multiple times by a single call to imex().
+ *
+ * A typical purpose for a handler of this event may be to make the file public to some system services.
+ *
+ * @param data2 0
+ */
+ public static class ImexFileWritten extends EventType {
+ public String path;
+ }
+
+/**
+ * Progress event sent when SecureJoin protocol has finished from the view of the inviter (Alice, the person who shows the QR code).
+ *
+ * These events are typically sent after a joiner has scanned the QR code generated by getChatSecurejoinQrCodeSvg().
+ */
+ public static class SecurejoinInviterProgress extends EventType {
+ /* ID of the chat in case of success. */
+ public Integer chatId;
+ /* The type of the joined chat. This can take the same values as `BasicChat.chatType` ([`crate::api::types::chat::BasicChat::chat_type`]). */
+ public ChatType chatType;
+ /* ID of the contact that wants to join. */
+ public Integer contactId;
+ /* Progress, always 1000. */
+ public Integer progress;
+ }
+
+/* Progress information of a secure-join handshake from the view of the joiner (Bob, the person who scans the QR code). The events are typically sent while secureJoin(), which may take some time, is executed. */
+ public static class SecurejoinJoinerProgress extends EventType {
+ /* ID of the inviting contact. */
+ public Integer contactId;
+ /* Progress as: 400=vg-/vc-request-with-auth sent, typically shown as "alice@addr verified, introducing myself." (Bob has verified alice and waits until Alice does the same for him) 1000=vg-member-added/vc-contact-confirm received */
+ public Integer progress;
+ }
+
+/* The connectivity to the server changed. This means that you should refresh the connectivity view and possibly the connectivtiy HTML; see getConnectivity() and getConnectivityHtml() for details. */
+ public static class ConnectivityChanged extends EventType {
+ }
+
+/* Deprecated by `ConfigSynced`. */
+ public static class SelfavatarChanged extends EventType {
+ }
+
+/* A multi-device synced config value changed. Maybe the app needs to refresh smth. For uniformity this is emitted on the source device too. The value isn't here, otherwise it would be logged which might not be good for privacy. */
+ public static class ConfigSynced extends EventType {
+ /* Configuration key. */
+ public String key;
+ }
+
+ public static class WebxdcStatusUpdate extends EventType {
+ /* Message ID. */
+ public Integer msgId;
+ /* Status update ID. */
+ public Integer statusUpdateSerial;
+ }
+
+/* Data received over an ephemeral peer channel. */
+ public static class WebxdcRealtimeData extends EventType {
+ /* Realtime data. */
+ public java.util.List data;
+ /* Message ID. */
+ public Integer msgId;
+ }
+
+/* Advertisement received over an ephemeral peer channel. This can be used by bots to initiate peer-to-peer communication from their side. */
+ public static class WebxdcRealtimeAdvertisementReceived extends EventType {
+ /* Message ID of the webxdc instance. */
+ public Integer msgId;
+ }
+
+/* Inform that a message containing a webxdc instance has been deleted */
+ public static class WebxdcInstanceDeleted extends EventType {
+ /* ID of the deleted message. */
+ public Integer msgId;
+ }
+
+/**
+ * Tells that the Background fetch was completed (or timed out). This event acts as a marker, when you reach this event you can be sure that all events emitted during the background fetch were processed.
+ *
+ * This event is only emitted by the account manager
+ */
+ public static class AccountsBackgroundFetchDone extends EventType {
+ }
+
+/**
+ * Inform that set of chats or the order of the chats in the chatlist has changed.
+ *
+ * Sometimes this is emitted together with `UIChatlistItemChanged`.
+ */
+ public static class ChatlistChanged extends EventType {
+ }
+
+/* Inform that a single chat list item changed and needs to be rerendered. If `chat_id` is set to None, then all currently visible chats need to be rerendered, and all not-visible items need to be cleared from cache if the UI has a cache. */
+ public static class ChatlistItemChanged extends EventType {
+ /* ID of the changed chat */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer chatId;
+ }
+
+/**
+ * Inform that the list of accounts has changed (an account removed or added or (not yet implemented) the account order changes)
+ *
+ * This event is only emitted by the account manager
+ */
+ public static class AccountsChanged extends EventType {
+ }
+
+/**
+ * Inform that an account property that might be shown in the account list changed, namely: - is_configured (see is_configured()) - displayname - selfavatar - private_tag
+ *
+ * This event is emitted from the account whose property changed.
+ */
+ public static class AccountsItemChanged extends EventType {
+ }
+
+/* Inform than some events have been skipped due to event channel overflow. */
+ public static class EventChannelOverflow extends EventType {
+ /* Number of events skipped. */
+ public Integer n;
+ }
+
+/* Incoming call. */
+ public static class IncomingCall extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chat_id;
+ /* True if incoming call is a video call. */
+ public Boolean has_video;
+ /* ID of the info message referring to the call. */
+ public Integer msg_id;
+ /* User-defined info as passed to place_outgoing_call() */
+ public String place_call_info;
+ }
+
+/* Incoming call accepted. This is esp. interesting to stop ringing on other devices. */
+ public static class IncomingCallAccepted extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chat_id;
+ /* ID of the info message referring to the call. */
+ public Integer msg_id;
+ }
+
+/* Outgoing call accepted. */
+ public static class OutgoingCallAccepted extends EventType {
+ /* User-defined info passed to dc_accept_incoming_call( */
+ public String accept_call_info;
+ /* ID of the chat which the message belongs to. */
+ public Integer chat_id;
+ /* ID of the info message referring to the call. */
+ public Integer msg_id;
+ }
+
+/* Call ended. */
+ public static class CallEnded extends EventType {
+ /* ID of the chat which the message belongs to. */
+ public Integer chat_id;
+ /* ID of the info message referring to the call. */
+ public Integer msg_id;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/FullChat.java b/src/main/java/chat/delta/rpc/types/FullChat.java
new file mode 100644
index 000000000..141a57b02
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/FullChat.java
@@ -0,0 +1,42 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class FullChat {
+ public Boolean archived;
+ public Boolean canSend;
+ public ChatType chatType;
+ public String color;
+ public java.util.List contactIds;
+ public java.util.List contacts;
+ public Integer ephemeralTimer;
+ public Integer freshMessageCounter;
+ public Integer id;
+ public Boolean isContactRequest;
+ public Boolean isDeviceChat;
+ /**
+ * True if the chat is encrypted. This means that all messages in the chat are encrypted, and all contacts in the chat are "key-contacts", i.e. identified by the PGP key fingerprint.
+ *
+ * False if the chat is unencrypted. This means that all messages in the chat are unencrypted, and all contacts in the chat are "address-contacts", i.e. identified by the email address. The UI should mark this chat e.g. with a mail-letter icon.
+ *
+ * Unencrypted groups are called "ad-hoc groups" and the user can't add/remove members, create a QR invite code, or set an avatar. These options should therefore be disabled in the UI.
+ *
+ * Note that it can happen that an encrypted chat contains unencrypted messages that were received in core <= v1.159.* and vice versa.
+ *
+ * See also `is_key_contact` on `Contact`.
+ */
+ public Boolean isEncrypted;
+ public Boolean isMuted;
+ public Boolean isSelfTalk;
+ public Boolean isUnpromoted;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String mailingListAddress;
+ public String name;
+ /* Contact IDs of the past chat members. */
+ public java.util.List pastContactIds;
+ public Boolean pinned;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String profileImage;
+ /* Note that this is different from [`ChatListItem::is_self_in_group`](`crate::api::types::chat_list::ChatListItemFetchResult::ChatListItem::is_self_in_group`). This property should only be accessed when [`FullChat::chat_type`] is [`Chattype::Group`]. */
+ public Boolean selfInGroup;
+ public Boolean wasSeenRecently;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Location.java b/src/main/java/chat/delta/rpc/types/Location.java
new file mode 100644
index 000000000..f7c4b4554
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Location.java
@@ -0,0 +1,16 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class Location {
+ public Float accuracy;
+ public Integer chatId;
+ public Integer contactId;
+ public Boolean isIndependent;
+ public Float latitude;
+ public Integer locationId;
+ public Float longitude;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String marker;
+ public Integer msgId;
+ public Integer timestamp;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Message.java b/src/main/java/chat/delta/rpc/types/Message.java
new file mode 100644
index 000000000..498767896
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Message.java
@@ -0,0 +1,69 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class Message {
+ public Integer chatId;
+ public Integer dimensionsHeight;
+ public Integer dimensionsWidth;
+ public DownloadState downloadState;
+ public Integer duration;
+ /* An error text, if there is one. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String error;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String file;
+ public Integer fileBytes;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String fileMime;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String fileName;
+ public Integer fromId;
+ public Boolean hasDeviatingTimestamp;
+ public Boolean hasHtml;
+ /* Check if a message has a POI location bound to it. These locations are also returned by `get_locations` method. The UI may decide to display a special icon beside such messages. */
+ public Boolean hasLocation;
+ public Integer id;
+ /* if is_info is set, this refers to the contact profile that should be opened when the info message is tapped. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer infoContactId;
+ /* True if the message was sent by a bot. */
+ public Boolean isBot;
+ public Boolean isEdited;
+ public Boolean isForwarded;
+ public Boolean isInfo;
+ public Boolean isSetupmessage;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer originalMsgId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String overrideSenderName;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer parentId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public MessageQuote quote;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Reactions reactions;
+ public Integer receivedTimestamp;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer savedMessageId;
+ public Contact sender;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String setupCodeBegin;
+ /**
+ * True if the message was correctly encrypted&signed, false otherwise. Historically, UIs showed a small padlock on the message then.
+ *
+ * Today, the UIs should instead show a small email-icon on the message if `show_padlock` is `false`, and nothing if it is `true`.
+ */
+ public Boolean showPadlock;
+ public Integer sortTimestamp;
+ public Integer state;
+ public String subject;
+ /* when is_info is true this describes what type of system message it is */
+ public SystemMessageType systemMessageType;
+ public String text;
+ public Integer timestamp;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public VcardContact vcardContact;
+ public Viewtype viewType;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String webxdcHref;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageData.java b/src/main/java/chat/delta/rpc/types/MessageData.java
new file mode 100644
index 000000000..647b586e0
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageData.java
@@ -0,0 +1,24 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class MessageData {
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String file;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String filename;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String html;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Pair location;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String overrideSenderName;
+ /* Quoted message id. Takes preference over `quoted_text` (see below). */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer quotedMessageId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String quotedText;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String text;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Viewtype viewtype;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageInfo.java b/src/main/java/chat/delta/rpc/types/MessageInfo.java
new file mode 100644
index 000000000..c01228d5c
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageInfo.java
@@ -0,0 +1,14 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class MessageInfo {
+ public EphemeralTimer ephemeralTimer;
+ /* When message is ephemeral this contains the timestamp of the message expiry */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer ephemeralTimestamp;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String error;
+ public String hopInfo;
+ public String rfc724Mid;
+ public java.util.List serverUrls;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageListItem.java b/src/main/java/chat/delta/rpc/types/MessageListItem.java
new file mode 100644
index 000000000..666152e0f
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageListItem.java
@@ -0,0 +1,24 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = MessageListItem.Message.class, name="Message"), @Type(value = MessageListItem.DayMarker.class, name="DayMarker")})
+public abstract class MessageListItem {
+
+ public static class Message extends MessageListItem {
+ public Integer msg_id;
+ }
+
+/* Day marker, separating messages that correspond to different days according to local time. */
+ public static class DayMarker extends MessageListItem {
+ /* Marker timestamp, for day markers, in unix milliseconds */
+ public Integer timestamp;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageLoadResult.java b/src/main/java/chat/delta/rpc/types/MessageLoadResult.java
new file mode 100644
index 000000000..5ad339751
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageLoadResult.java
@@ -0,0 +1,85 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = MessageLoadResult.Message.class, name="Message"), @Type(value = MessageLoadResult.LoadingError.class, name="LoadingError")})
+public abstract class MessageLoadResult {
+
+ public static class Message extends MessageLoadResult {
+ public Integer chatId;
+ public Integer dimensionsHeight;
+ public Integer dimensionsWidth;
+ public DownloadState downloadState;
+ public Integer duration;
+ /* An error text, if there is one. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String error;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String file;
+ public Integer fileBytes;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String fileMime;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String fileName;
+ public Integer fromId;
+ public Boolean hasDeviatingTimestamp;
+ public Boolean hasHtml;
+ /* Check if a message has a POI location bound to it. These locations are also returned by `get_locations` method. The UI may decide to display a special icon beside such messages. */
+ public Boolean hasLocation;
+ public Integer id;
+ /* if is_info is set, this refers to the contact profile that should be opened when the info message is tapped. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer infoContactId;
+ /* True if the message was sent by a bot. */
+ public Boolean isBot;
+ public Boolean isEdited;
+ public Boolean isForwarded;
+ public Boolean isInfo;
+ public Boolean isSetupmessage;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer originalMsgId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String overrideSenderName;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer parentId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public MessageQuote quote;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Reactions reactions;
+ public Integer receivedTimestamp;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer savedMessageId;
+ public Contact sender;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String setupCodeBegin;
+ /**
+ * True if the message was correctly encrypted&signed, false otherwise. Historically, UIs showed a small padlock on the message then.
+ *
+ * Today, the UIs should instead show a small email-icon on the message if `show_padlock` is `false`, and nothing if it is `true`.
+ */
+ public Boolean showPadlock;
+ public Integer sortTimestamp;
+ public Integer state;
+ public String subject;
+ /* when is_info is true this describes what type of system message it is */
+ public SystemMessageType systemMessageType;
+ public String text;
+ public Integer timestamp;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public VcardContact vcardContact;
+ public Viewtype viewType;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String webxdcHref;
+ }
+
+ public static class LoadingError extends MessageLoadResult {
+ public String error;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageNotificationInfo.java b/src/main/java/chat/delta/rpc/types/MessageNotificationInfo.java
new file mode 100644
index 000000000..c8b6669b3
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageNotificationInfo.java
@@ -0,0 +1,20 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class MessageNotificationInfo {
+ public Integer accountId;
+ public Integer chatId;
+ public String chatName;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String chatProfileImage;
+ public Integer id;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String image;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String imageMimeType;
+ /* also known as summary_text1 */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String summaryPrefix;
+ /* also known as summary_text2 */
+ public String summaryText;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageQuote.java b/src/main/java/chat/delta/rpc/types/MessageQuote.java
new file mode 100644
index 000000000..3a11ee806
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageQuote.java
@@ -0,0 +1,33 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = MessageQuote.JustText.class, name="JustText"), @Type(value = MessageQuote.WithMessage.class, name="WithMessage")})
+public abstract class MessageQuote {
+
+ public static class JustText extends MessageQuote {
+ public String text;
+ }
+
+ public static class WithMessage extends MessageQuote {
+ public String authorDisplayColor;
+ public String authorDisplayName;
+ /* The quoted message does not always belong to the same chat, e.g. when "Reply Privately" is used. */
+ public Integer chatId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String image;
+ public Boolean isForwarded;
+ public Integer messageId;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String overrideSenderName;
+ public String text;
+ public Viewtype viewType;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageReadReceipt.java b/src/main/java/chat/delta/rpc/types/MessageReadReceipt.java
new file mode 100644
index 000000000..88c4e1908
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageReadReceipt.java
@@ -0,0 +1,7 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class MessageReadReceipt {
+ public Integer contactId;
+ public Integer timestamp;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MessageSearchResult.java b/src/main/java/chat/delta/rpc/types/MessageSearchResult.java
new file mode 100644
index 000000000..d5caadc74
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MessageSearchResult.java
@@ -0,0 +1,22 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class MessageSearchResult {
+ public String authorColor;
+ public Integer authorId;
+ /* if sender name if overridden it will show it as ~alias */
+ public String authorName;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String authorProfileImage;
+ public String chatColor;
+ public Integer chatId;
+ public String chatName;
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String chatProfileImage;
+ public ChatType chatType;
+ public Integer id;
+ public Boolean isChatArchived;
+ public Boolean isChatContactRequest;
+ public String message;
+ public Integer timestamp;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/MuteDuration.java b/src/main/java/chat/delta/rpc/types/MuteDuration.java
new file mode 100644
index 000000000..88363bfbb
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/MuteDuration.java
@@ -0,0 +1,24 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = MuteDuration.NotMuted.class, name="NotMuted"), @Type(value = MuteDuration.Forever.class, name="Forever"), @Type(value = MuteDuration.Until.class, name="Until")})
+public abstract class MuteDuration {
+
+ public static class NotMuted extends MuteDuration {
+ }
+
+ public static class Forever extends MuteDuration {
+ }
+
+ public static class Until extends MuteDuration {
+ public Integer duration;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/NotifyState.java b/src/main/java/chat/delta/rpc/types/NotifyState.java
new file mode 100644
index 000000000..41f2ea388
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/NotifyState.java
@@ -0,0 +1,13 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum NotifyState {
+ /* Not subscribed to push notifications. */
+ NotConnected,
+
+ /* Subscribed to heartbeat push notifications. */
+ Heartbeat,
+
+ /* Subscribed to push notifications for new messages. */
+ Connected,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Pair.java b/src/main/java/chat/delta/rpc/types/Pair.java
new file mode 100644
index 000000000..141be5c22
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Pair.java
@@ -0,0 +1,36 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class Pair {
+ private final T1 v1;
+ private final T2 v2;
+
+ public Pair(T1 v1, T2 v2) {
+ this.v1 = v1;
+ this.v2 = v2;
+ }
+
+ public T1 first(){
+ return v1;
+ }
+
+ public T2 second(){
+ return v2;
+ }
+
+ public boolean equals(Object o) {
+ return o instanceof Pair &&
+ equal(((Pair) o).first(), first()) &&
+ equal(((Pair) o).second(), second());
+ }
+
+ public int hashCode() {
+ return first().hashCode() ^ second().hashCode();
+ }
+
+ private boolean equal(Object first, Object second) {
+ if (first == null && second == null) return true;
+ if (first == null || second == null) return false;
+ return first.equals(second);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/ProviderInfo.java b/src/main/java/chat/delta/rpc/types/ProviderInfo.java
new file mode 100644
index 000000000..d950cc0d2
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/ProviderInfo.java
@@ -0,0 +1,10 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class ProviderInfo {
+ public String beforeLoginHint;
+ /* Unique ID, corresponding to provider database filename. */
+ public String id;
+ public String overviewPage;
+ public Integer status;
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Qr.java b/src/main/java/chat/delta/rpc/types/Qr.java
new file mode 100644
index 000000000..902b93431
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Qr.java
@@ -0,0 +1,254 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
+@JsonSubTypes({@Type(value = Qr.AskVerifyContact.class, name="AskVerifyContact"), @Type(value = Qr.AskVerifyGroup.class, name="AskVerifyGroup"), @Type(value = Qr.AskJoinBroadcast.class, name="AskJoinBroadcast"), @Type(value = Qr.FprOk.class, name="FprOk"), @Type(value = Qr.FprMismatch.class, name="FprMismatch"), @Type(value = Qr.FprWithoutAddr.class, name="FprWithoutAddr"), @Type(value = Qr.Account.class, name="Account"), @Type(value = Qr.Backup2.class, name="Backup2"), @Type(value = Qr.BackupTooNew.class, name="BackupTooNew"), @Type(value = Qr.WebrtcInstance.class, name="WebrtcInstance"), @Type(value = Qr.Proxy.class, name="Proxy"), @Type(value = Qr.Addr.class, name="Addr"), @Type(value = Qr.Url.class, name="Url"), @Type(value = Qr.Text.class, name="Text"), @Type(value = Qr.WithdrawVerifyContact.class, name="WithdrawVerifyContact"), @Type(value = Qr.WithdrawVerifyGroup.class, name="WithdrawVerifyGroup"), @Type(value = Qr.WithdrawJoinBroadcast.class, name="WithdrawJoinBroadcast"), @Type(value = Qr.ReviveVerifyContact.class, name="ReviveVerifyContact"), @Type(value = Qr.ReviveVerifyGroup.class, name="ReviveVerifyGroup"), @Type(value = Qr.ReviveJoinBroadcast.class, name="ReviveJoinBroadcast"), @Type(value = Qr.Login.class, name="Login")})
+public abstract class Qr {
+
+/**
+ * Ask the user whether to verify the contact.
+ *
+ * If the user agrees, pass this QR code to [`crate::securejoin::join_securejoin`].
+ */
+ public static class AskVerifyContact extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* ID of the contact. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Invite number. */
+ public String invitenumber;
+ }
+
+/* Ask the user whether to join the group. */
+ public static class AskVerifyGroup extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* ID of the contact. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Group ID. */
+ public String grpid;
+ /* Group name. */
+ public String grpname;
+ /* Invite number. */
+ public String invitenumber;
+ }
+
+/* Ask the user whether to join the broadcast channel. */
+ public static class AskJoinBroadcast extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* ID of the contact who owns the broadcast channel and created the QR code. */
+ public Integer contact_id;
+ /* Fingerprint of the broadcast channel owner's key as scanned from the QR code. */
+ public String fingerprint;
+ /* A string of random characters, uniquely identifying this broadcast channel across all databases/clients. Called `grpid` for historic reasons: The id of multi-user chats is always called `grpid` in the database because groups were once the only multi-user chats. */
+ public String grpid;
+ /* Invite number. */
+ public String invitenumber;
+ /* The user-visible name of this broadcast channel */
+ public String name;
+ }
+
+/**
+ * Contact fingerprint is verified.
+ *
+ * Ask the user if they want to start chatting.
+ */
+ public static class FprOk extends Qr {
+ /* Contact ID. */
+ public Integer contact_id;
+ }
+
+/* Scanned fingerprint does not match the last seen fingerprint. */
+ public static class FprMismatch extends Qr {
+ /* Contact ID. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public Integer contact_id;
+ }
+
+/* The scanned QR code contains a fingerprint but no e-mail address. */
+ public static class FprWithoutAddr extends Qr {
+ /* Key fingerprint. */
+ public String fingerprint;
+ }
+
+/* Ask the user if they want to create an account on the given domain. */
+ public static class Account extends Qr {
+ /* Server domain name. */
+ public String domain;
+ }
+
+/* Provides a backup that can be retrieved using iroh-net based backup transfer protocol. */
+ public static class Backup2 extends Qr {
+ /* Authentication token. */
+ public String auth_token;
+ /* Iroh node address. */
+ public String node_addr;
+ }
+
+ public static class BackupTooNew extends Qr {
+ }
+
+/* Ask the user if they want to use the given service for video chats. */
+ public static class WebrtcInstance extends Qr {
+ public String domain;
+ public String instance_pattern;
+ }
+
+/**
+ * Ask the user if they want to use the given proxy.
+ *
+ * Note that HTTP(S) URLs without a path and query parameters are treated as HTTP(S) proxy URL. UI may want to still offer to open the URL in the browser if QR code contents starts with `http://` or `https://` and the QR code was not scanned from the proxy configuration screen.
+ */
+ public static class Proxy extends Qr {
+ /* Host extracted from the URL to display in the UI. */
+ public String host;
+ /* Port extracted from the URL to display in the UI. */
+ public Integer port;
+ /**
+ * Proxy URL.
+ *
+ * This is the URL that is going to be added.
+ */
+ public String url;
+ }
+
+/**
+ * Contact address is scanned.
+ *
+ * Optionally, a draft message could be provided. Ask the user if they want to start chatting.
+ */
+ public static class Addr extends Qr {
+ /* Contact ID. */
+ public Integer contact_id;
+ /* Draft message. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String draft;
+ }
+
+/**
+ * URL scanned.
+ *
+ * Ask the user if they want to open a browser or copy the URL to clipboard.
+ */
+ public static class Url extends Qr {
+ public String url;
+ }
+
+/**
+ * Text scanned.
+ *
+ * Ask the user if they want to copy the text to clipboard.
+ */
+ public static class Text extends Qr {
+ public String text;
+ }
+
+/* Ask the user if they want to withdraw their own QR code. */
+ public static class WithdrawVerifyContact extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* Contact ID. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Invite number. */
+ public String invitenumber;
+ }
+
+/* Ask the user if they want to withdraw their own group invite QR code. */
+ public static class WithdrawVerifyGroup extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* Contact ID. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Group ID. */
+ public String grpid;
+ /* Group name. */
+ public String grpname;
+ /* Invite number. */
+ public String invitenumber;
+ }
+
+/* Ask the user if they want to withdraw their own broadcast channel invite QR code. */
+ public static class WithdrawJoinBroadcast extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* Contact ID. Always `ContactId::SELF`. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* ID, uniquely identifying this chat. Called grpid for historic reasons. */
+ public String grpid;
+ /* Invite number. */
+ public String invitenumber;
+ /* Broadcast name. */
+ public String name;
+ }
+
+/* Ask the user if they want to revive their own QR code. */
+ public static class ReviveVerifyContact extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* Contact ID. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Invite number. */
+ public String invitenumber;
+ }
+
+/* Ask the user if they want to revive their own group invite QR code. */
+ public static class ReviveVerifyGroup extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* Contact ID. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Group ID. */
+ public String grpid;
+ /* Contact ID. */
+ public String grpname;
+ /* Invite number. */
+ public String invitenumber;
+ }
+
+/* Ask the user if they want to revive their own broadcast channel invite QR code. */
+ public static class ReviveJoinBroadcast extends Qr {
+ /* Authentication code. */
+ public String authcode;
+ /* Contact ID. Always `ContactId::SELF`. */
+ public Integer contact_id;
+ /* Fingerprint of the contact key as scanned from the QR code. */
+ public String fingerprint;
+ /* Globally unique chat ID. Called grpid for historic reasons. */
+ public String grpid;
+ /* Invite number. */
+ public String invitenumber;
+ /* Broadcast name. */
+ public String name;
+ }
+
+/**
+ * `dclogin:` scheme parameters.
+ *
+ * Ask the user if they want to login with the email address.
+ */
+ public static class Login extends Qr {
+ public String address;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/SecurejoinSource.java b/src/main/java/chat/delta/rpc/types/SecurejoinSource.java
new file mode 100644
index 000000000..e9688b9e6
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/SecurejoinSource.java
@@ -0,0 +1,22 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum SecurejoinSource {
+ /* Because of some problem, it is unknown where the QR code came from. */
+ Unknown,
+
+ /* The user opened a link somewhere outside Delta Chat */
+ ExternalLink,
+
+ /* The user clicked on a link in a message inside Delta Chat */
+ InternalLink,
+
+ /* The user clicked "Paste from Clipboard" in the QR scan activity */
+ Clipboard,
+
+ /* The user clicked "Load QR code as image" in the QR scan activity */
+ ImageLoaded,
+
+ /* The user scanned a QR code */
+ Scan,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/SecurejoinUiPath.java b/src/main/java/chat/delta/rpc/types/SecurejoinUiPath.java
new file mode 100644
index 000000000..9cbe52e90
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/SecurejoinUiPath.java
@@ -0,0 +1,13 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum SecurejoinUiPath {
+ /* The UI path is unknown, or the user didn't open the QR code screen at all. */
+ Unknown,
+
+ /* The user directly clicked on the QR icon in the main screen */
+ QrIcon,
+
+ /* The user first clicked on the `+` button in the main screen, and then on "New Contact" */
+ NewContact,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/SystemMessageType.java b/src/main/java/chat/delta/rpc/types/SystemMessageType.java
new file mode 100644
index 000000000..f10b2c1a9
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/SystemMessageType.java
@@ -0,0 +1,39 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum SystemMessageType {
+ Unknown,
+ GroupNameChanged,
+ GroupImageChanged,
+ MemberAddedToGroup,
+ MemberRemovedFromGroup,
+ AutocryptSetupMessage,
+ SecurejoinMessage,
+ LocationStreamingEnabled,
+ LocationOnly,
+ InvalidUnencryptedMail,
+ ChatE2ee,
+ ChatProtectionEnabled,
+ ChatProtectionDisabled,
+ WebxdcStatusUpdate,
+ CallAccepted,
+ CallEnded,
+
+ /* 1:1 chats info message telling that SecureJoin has started and the user should wait for it to complete. */
+ SecurejoinWait,
+
+ /* 1:1 chats info message telling that SecureJoin is still running, but the user may already send messages. */
+ SecurejoinWaitTimeout,
+
+ /* Chat ephemeral message timer is changed. */
+ EphemeralTimerChanged,
+
+ /* Self-sent-message that contains only json used for multi-device-sync; if possible, we attach that to other messages as for locations. */
+ MultiDeviceSync,
+
+ /* Webxdc info added with `info` set in `send_webxdc_status_update()`. */
+ WebxdcInfoMessage,
+
+ /* This message contains a users iroh node address. */
+ IrohNodeAddr,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/Viewtype.java b/src/main/java/chat/delta/rpc/types/Viewtype.java
new file mode 100644
index 000000000..f7cf9f9a0
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/Viewtype.java
@@ -0,0 +1,43 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public enum Viewtype {
+ Unknown,
+
+ /* Text message. */
+ Text,
+
+ /* Image message. If the image is an animated GIF, the type `Viewtype.Gif` should be used. */
+ Image,
+
+ /* Animated GIF message. */
+ Gif,
+
+ /**
+ * Message containing a sticker, similar to image. NB: When sending, the message viewtype may be changed to `Image` by some heuristics like checking for transparent pixels. Use `Message::force_sticker()` to disable them.
+ *
+ * If possible, the ui should display the image without borders in a transparent way. A click on a sticker will offer to install the sticker set in some future.
+ */
+ Sticker,
+
+ /* Message containing an Audio file. */
+ Audio,
+
+ /* A voice message that was directly recorded by the user. For all other audio messages, the type `Viewtype.Audio` should be used. */
+ Voice,
+
+ /* Video messages. */
+ Video,
+
+ /* Message containing any file, eg. a PDF. */
+ File,
+
+ /* Message is a call. */
+ Call,
+
+ /* Message is an webxdc instance. */
+ Webxdc,
+
+ /* Message containing shared contacts represented as a vCard (virtual contact file) with email addresses and possibly other fields. Use `parse_vcard()` to retrieve them. */
+ Vcard,
+}
\ No newline at end of file
diff --git a/src/main/java/chat/delta/rpc/types/WebxdcMessageInfo.java b/src/main/java/chat/delta/rpc/types/WebxdcMessageInfo.java
new file mode 100644
index 000000000..8b869d7ed
--- /dev/null
+++ b/src/main/java/chat/delta/rpc/types/WebxdcMessageInfo.java
@@ -0,0 +1,36 @@
+/* Autogenerated file, do not edit manually */
+package chat.delta.rpc.types;
+
+public class WebxdcMessageInfo {
+ /* if the Webxdc represents a document, then this is the name of the document */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String document;
+ /**
+ * App icon file name. Defaults to an standard icon if nothing is set in the manifest.
+ *
+ * To get the file, use dc_msg_get_webxdc_blob(). (not yet in jsonrpc, use rust api or cffi for it)
+ *
+ * App icons should should be square, the implementations will add round corners etc. as needed.
+ */
+ public String icon;
+ /* True if full internet access should be granted to the app. */
+ public Boolean internetAccess;
+ /**
+ * The name of the app.
+ *
+ * Defaults to the filename if not set in the manifest.
+ */
+ public String name;
+ /* Address to be used for `window.webxdc.selfAddr` in JS land. */
+ public String selfAddr;
+ /* Milliseconds to wait before calling `sendUpdate()` again since the last call. Should be exposed to `window.sendUpdateInterval` in JS land. */
+ public Integer sendUpdateInterval;
+ /* Maximum number of bytes accepted for a serialized update object. Should be exposed to `window.sendUpdateMaxSize` in JS land. */
+ public Integer sendUpdateMaxSize;
+ /* URL where the source code of the Webxdc and other information can be found; defaults to an empty string. Implementations may offer an menu or a button to open this URL. */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String sourceCodeUrl;
+ /* short string describing the state of the app, sth. as "2 votes", "Highscore: 123", can be changed by the apps */
+ @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
+ public String summary;
+}
\ No newline at end of file
diff --git a/src/main/java/com/b44t/messenger/DcAccounts.java b/src/main/java/com/b44t/messenger/DcAccounts.java
index 2dec50068..43e986e45 100644
--- a/src/main/java/com/b44t/messenger/DcAccounts.java
+++ b/src/main/java/com/b44t/messenger/DcAccounts.java
@@ -34,6 +34,7 @@ public class DcAccounts {
public native void maybeNetwork ();
public native void setPushDeviceToken (String token);
public native boolean backgroundFetch (int timeoutSeconds);
+ public native void stopBackgroundFetch ();
public native int migrateAccount (String dbfile);
public native boolean removeAccount (int accountId);
diff --git a/src/main/java/com/b44t/messenger/DcContext.java b/src/main/java/com/b44t/messenger/DcContext.java
index f830e450a..4032bff73 100644
--- a/src/main/java/com/b44t/messenger/DcContext.java
+++ b/src/main/java/com/b44t/messenger/DcContext.java
@@ -68,8 +68,10 @@ public class DcContext {
public final static int DC_QR_ERROR = 400;
public final static int DC_QR_WITHDRAW_VERIFYCONTACT = 500;
public final static int DC_QR_WITHDRAW_VERIFYGROUP = 502;
+ public final static int DC_QR_WITHDRAW_JOINBROADCAST = 504;
public final static int DC_QR_REVIVE_VERIFYCONTACT = 510;
public final static int DC_QR_REVIVE_VERIFYGROUP = 512;
+ public final static int DC_QR_REVIVE_JOINBROADCAST = 514;
public final static int DC_QR_LOGIN = 520;
public final static int DC_SOCKET_AUTO = 0;
diff --git a/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
index bea089662..560ce04e6 100644
--- a/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
+++ b/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
@@ -132,6 +132,11 @@ public class ApplicationContext extends MultiDexApplication {
e.printStackTrace();
}
}
+
+ // 2025.11.12: this is needed until core starts ignoring "delete_server_after" for chatmail
+ if (ac.isChatmail()) {
+ ac.setConfig("delete_server_after", null); // reset
+ }
}
if (allAccounts.length == 0) {
try {
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java
index 99fd541b7..d64a8d07f 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java
@@ -785,7 +785,7 @@ public class ConversationFragment extends MessageSelectorFragment
&& messageRecord.getText().contains(self_mail)
&& getListAdapter().getChat().isDeviceTalk()) {
// This is a device message informing the user that the password is wrong
- startActivity(new Intent(getActivity(), RegistrationActivity.class));
+ startActivity(new Intent(getActivity(), EditTransportActivity.class));
}
}
}
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationTitleView.java b/src/main/java/org/thoughtcrime/securesms/ConversationTitleView.java
index 98802ea36..b1c3a7203 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationTitleView.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationTitleView.java
@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DateUtils;
+import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Locale;
@@ -59,10 +60,6 @@ public class ConversationTitleView extends RelativeLayout {
}
public void setTitle(@NonNull GlideRequests glideRequests, @NonNull DcChat dcChat) {
- setTitle(glideRequests, dcChat, false);
- }
-
- public void setTitle(@NonNull GlideRequests glideRequests, @NonNull DcChat dcChat, boolean profileView) {
final int chatId = dcChat.getId();
final Context context = getContext();
final DcContext dcContext = DcHelper.getContext(context);
@@ -74,23 +71,16 @@ public class ConversationTitleView extends RelativeLayout {
boolean isOnline = false;
int[] chatContacts = dcContext.getChatContacts(chatId);
if (dcChat.isMailingList()) {
- subtitleStr = dcChat.getMailinglistAddr();
- if (!profileView) {
- if (TextUtils.isEmpty(subtitleStr)) {
- subtitleStr = context.getString(R.string.channel);
- } else {
- subtitleStr = context.getString(R.string.super_group);
- }
- }
+ subtitleStr = context.getString(R.string.mailing_list);
} else if (dcChat.isInBroadcast()) {
subtitleStr = context.getString(R.string.channel);
} else if (dcChat.isOutBroadcast()) {
- if (!profileView) {
- subtitleStr = context.getResources().getQuantityString(R.plurals.n_recipients, chatContacts.length, chatContacts.length);
- }
+ subtitleStr = context.getResources().getQuantityString(R.plurals.n_recipients, chatContacts.length, chatContacts.length);
} else if( dcChat.isMultiUser() ) {
- if (!profileView) {
+ if (chatContacts.length > 1 || Util.contains(chatContacts, DcContact.DC_CONTACT_ID_SELF)) {
subtitleStr = context.getResources().getQuantityString(R.plurals.n_members, chatContacts.length, chatContacts.length);
+ } else {
+ subtitleStr = "…";
}
} else if( chatContacts.length>=1 ) {
if( dcChat.isSelfTalk() ) {
@@ -102,7 +92,7 @@ public class ConversationTitleView extends RelativeLayout {
else {
DcContact dcContact = dcContext.getContact(chatContacts[0]);
isOnline = dcContact.wasSeenRecently();
- if (profileView || !dcChat.isEncrypted()) {
+ if (!dcChat.isEncrypted()) {
subtitleStr = dcContact.getAddr();
} else if (dcContact.isBot()) {
subtitleStr = context.getString(R.string.bot);
diff --git a/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java b/src/main/java/org/thoughtcrime/securesms/EditTransportActivity.java
similarity index 84%
rename from src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java
rename to src/main/java/org/thoughtcrime/securesms/EditTransportActivity.java
index adc744835..b4758d806 100644
--- a/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/EditTransportActivity.java
@@ -1,17 +1,6 @@
package org.thoughtcrime.securesms;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_ADDRESS;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_PASSWORD;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_PORT;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_SECURITY;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_SERVER;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_USER;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_PASSWORD;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_PORT;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SECURITY;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SERVER;
-import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_USER;
import static org.thoughtcrime.securesms.connect.DcHelper.getContext;
import android.content.DialogInterface;
@@ -53,13 +42,15 @@ import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.ProgressDialog;
+import java.util.List;
+
import chat.delta.rpc.Rpc;
import chat.delta.rpc.RpcException;
import chat.delta.rpc.types.EnteredCertificateChecks;
import chat.delta.rpc.types.EnteredLoginParam;
import chat.delta.rpc.types.Socket;
-public class RegistrationActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate {
+public class EditTransportActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate {
private enum VerificationType {
EMAIL,
@@ -88,12 +79,17 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
private SwitchCompat proxySwitch;
+ Rpc rpc;
+ int accId;
+
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
dynamicTheme.onCreate(this);
+ rpc = DcHelper.getRpc(this);
+ accId = DcHelper.getContext(this).getAccountId();
- setContentView(R.layout.registration_activity);
+ setContentView(R.layout.activity_edittransport);
emailInput = findViewById(R.id.email_text);
passwordInput = findViewById(R.id.password_text);
@@ -122,19 +118,23 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
startActivity(new Intent(this, ProxySettingsActivity.class));
});
- boolean isConfigured = DcHelper.isConfigured(getApplicationContext());
+ EnteredLoginParam config = null;
+ try {
+ List relays = rpc.listTransports(accId);
+ if (!relays.isEmpty()) config = relays.get(0);
+ } catch (RpcException ignored) {}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(
- isConfigured? R.string.pref_password_and_account_settings : R.string.manual_account_setup_option
+ config != null? R.string.edit_transport : R.string.manual_account_setup_option
);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
- if (isConfigured) emailInput.setEnabled(false);
+ if (config != null) emailInput.setEnabled(false);
emailInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
@@ -154,66 +154,54 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
viewLogText.setOnClickListener((view) -> showLog());
boolean expandAdvanced = false;
- String strVal;
int intVal;
intVal = DcHelper.getInt(this, CONFIG_PROXY_ENABLED);
proxySwitch.setChecked(intVal == 1);
expandAdvanced = expandAdvanced || intVal == 1;
- if (isConfigured) {
- String email = DcHelper.get(this, CONFIG_ADDRESS);
- emailInput.setText(email);
- if(!TextUtils.isEmpty(email)) {
- emailInput.setSelection(email.length(), email.length());
+ if (config != null) { // configured
+ emailInput.setText(config.addr);
+ if(!TextUtils.isEmpty(config.addr)) {
+ emailInput.setSelection(config.addr.length(), config.addr.length());
}
- passwordInput.setText(DcHelper.get(this, CONFIG_MAIL_PASSWORD));
+ passwordInput.setText(config.password);
TextInputEditText imapLoginInput = findViewById(R.id.imap_login_text);
- strVal = DcHelper.get(this, CONFIG_MAIL_USER);
- imapLoginInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ imapLoginInput.setText(config.imapUser);
+ expandAdvanced = expandAdvanced || !TextUtils.isEmpty(config.imapUser);
- strVal = DcHelper.get(this, CONFIG_MAIL_SERVER);
- imapServerInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ imapServerInput.setText(config.imapServer);
+ expandAdvanced = expandAdvanced || !TextUtils.isEmpty(config.imapServer);
- strVal = DcHelper.get(this, CONFIG_MAIL_PORT);
- imapPortInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ if (config.imapPort != null) imapPortInput.setText(config.imapPort.toString());
+ expandAdvanced = expandAdvanced || config.imapPort != null;
- intVal = DcHelper.getInt(this, CONFIG_MAIL_SECURITY);
+ intVal = socketSecurityToInt(config.imapSecurity);
imapSecurity.setSelection(ViewUtil.checkBounds(intVal, imapSecurity));
expandAdvanced = expandAdvanced || intVal != 0;
TextInputEditText smtpLoginInput = findViewById(R.id.smtp_login_text);
- strVal = DcHelper.get(this, CONFIG_SEND_USER);
- smtpLoginInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ smtpLoginInput.setText(config.smtpUser);
+ expandAdvanced = expandAdvanced || !TextUtils.isEmpty(config.smtpUser);
TextInputEditText smtpPasswordInput = findViewById(R.id.smtp_password_text);
- strVal = DcHelper.get(this, CONFIG_SEND_PASSWORD);
- smtpPasswordInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ smtpPasswordInput.setText(config.smtpPassword);
+ expandAdvanced = expandAdvanced || !TextUtils.isEmpty(config.smtpPassword);
- strVal = DcHelper.get(this, CONFIG_SEND_SERVER);
- smtpServerInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ smtpServerInput.setText(config.smtpServer);
+ expandAdvanced = expandAdvanced || !TextUtils.isEmpty(config.smtpServer);
- strVal = DcHelper.get(this, CONFIG_SEND_PORT);
- smtpPortInput.setText(strVal);
- expandAdvanced = expandAdvanced || !TextUtils.isEmpty(strVal);
+ if (config.smtpPort != null) smtpPortInput.setText(config.smtpPort.toString());
+ expandAdvanced = expandAdvanced || config.smtpPort != null;
- intVal = DcHelper.getInt(this, CONFIG_SEND_SECURITY);
+ intVal = socketSecurityToInt(config.smtpSecurity);
smtpSecurity.setSelection(ViewUtil.checkBounds(intVal, smtpSecurity));
expandAdvanced = expandAdvanced || intVal != 0;
- int imapCertificateChecks = DcHelper.getInt(this, "imap_certificate_checks");
- if (imapCertificateChecks == 3) {
- imapCertificateChecks = 2; // 3 is a deprecated alias for 2
- }
- certCheck.setSelection(ViewUtil.checkBounds(imapCertificateChecks, certCheck));
- expandAdvanced = expandAdvanced || imapCertificateChecks != 0;
+ intVal = certificateChecksToInt(config.certificateChecks);
+ certCheck.setSelection(ViewUtil.checkBounds(intVal, certCheck));
+ expandAdvanced = expandAdvanced || intVal != 0;
}
if (expandAdvanced) { onAdvancedSettings(); }
@@ -430,6 +418,20 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
throw new IllegalArgumentException("Invalid certificate position: " + position);
}
+ private int certificateChecksToInt(EnteredCertificateChecks check) {
+ if (check == null) return 0;
+
+ switch (check) {
+ case strict:
+ return 1;
+ case acceptInvalidCertificates:
+ return 2;
+ case automatic:
+ default:
+ return 0;
+ }
+ }
+
public static Socket socketSecurityFromInt(int position) {
switch (position) {
case 0:
@@ -444,6 +446,22 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
throw new IllegalArgumentException("Invalid socketSecurity position: " + position);
}
+ public static int socketSecurityToInt(Socket security) {
+ if (security == null) return 0;
+
+ switch (security) {
+ case ssl:
+ return 1;
+ case starttls:
+ return 2;
+ case plain:
+ return 3;
+ case automatic:
+ default:
+ return 0;
+ }
+ }
+
private void setupConfig() {
DcHelper.getEventCenter(this).captureNextError();
@@ -462,9 +480,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
param.certificateChecks = certificateChecksFromInt(certCheck.getSelectedItemPosition());
new Thread(() -> {
- Rpc rpc = DcHelper.getRpc(this);
try {
- rpc.addOrUpdateTransport(DcHelper.getContext(this).getAccountId(), param);
+ rpc.addOrUpdateTransport(accId, param);
DcHelper.getEventCenter(this).endCaptureNextError();
progressDialog.dismiss();
Intent conversationList = new Intent(getApplicationContext(), ConversationListActivity.class);
diff --git a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
index ea9d956b1..36935c0c9 100644
--- a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java
@@ -350,7 +350,7 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
}
private void startRegistrationActivity() {
- Intent intent = new Intent(this, RegistrationActivity.class);
+ Intent intent = new Intent(this, EditTransportActivity.class);
startActivity(intent);
}
diff --git a/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java b/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java
index cfb055740..a08e0c4a9 100644
--- a/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java
+++ b/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java
@@ -54,7 +54,7 @@ public class ProfileAdapter extends RecyclerView.Adapter
private DcChatlist itemDataSharedChats;
private String itemDataStatusText;
private boolean isOutBroadcast;
- private int memberCount;
+ private int[] memberList;
private final Set selectedMembers;
private final LayoutInflater layoutInflater;
@@ -205,7 +205,7 @@ public class ProfileAdapter extends RecyclerView.Adapter
else if(holder.itemView instanceof ProfileAvatarItem) {
ProfileAvatarItem item = (ProfileAvatarItem) holder.itemView;
item.setAvatarClickListener(view -> clickListener.onAvatarClicked());
- item.set(glideRequests, dcChat, dcContact, memberCount);
+ item.set(glideRequests, dcChat, dcContact, memberList);
}
else if(holder.itemView instanceof ProfileTextItem) {
ProfileTextItem item = (ProfileTextItem) holder.itemView;
@@ -281,7 +281,7 @@ public class ProfileAdapter extends RecyclerView.Adapter
boolean isInBroadcast = dcChat != null && dcChat.isInBroadcast();
boolean isSelfTalk = dcChat != null && dcChat.isSelfTalk();
boolean isDeviceTalk = dcChat != null && dcChat.isDeviceTalk();
- memberCount = memberList!=null ? memberList.length : 0;
+ this.memberList = memberList;
itemData.add(new ItemData(ITEM_AVATAR, null, 0));
diff --git a/src/main/java/org/thoughtcrime/securesms/ProfileAvatarItem.java b/src/main/java/org/thoughtcrime/securesms/ProfileAvatarItem.java
index eb9887dda..3e319ba3b 100644
--- a/src/main/java/org/thoughtcrime/securesms/ProfileAvatarItem.java
+++ b/src/main/java/org/thoughtcrime/securesms/ProfileAvatarItem.java
@@ -47,8 +47,9 @@ public class ProfileAvatarItem extends LinearLayout implements RecipientModified
ViewUtil.setTextViewGravityStart(nameView, getContext());
}
- public void set(@NonNull GlideRequests glideRequests, @Nullable DcChat dcChat, @Nullable DcContact dcContact, int memberCount) {
+ public void set(@NonNull GlideRequests glideRequests, @Nullable DcChat dcChat, @Nullable DcContact dcContact, @Nullable int[] members) {
this.glideRequests = glideRequests;
+ int memberCount = members != null ? members.length : 0;
String name = "";
String subtitle = null;
@@ -61,7 +62,9 @@ public class ProfileAvatarItem extends LinearLayout implements RecipientModified
} else if (dcChat.isOutBroadcast()) {
subtitle = getContext().getResources().getQuantityString(R.plurals.n_recipients, memberCount, memberCount);
} else if (dcChat.getType() == DcChat.DC_CHAT_TYPE_GROUP) {
- subtitle = getContext().getResources().getQuantityString(R.plurals.n_members, memberCount, memberCount);
+ if (memberCount > 1 || Util.contains(members, DcContact.DC_CONTACT_ID_SELF)) {
+ subtitle = getContext().getResources().getQuantityString(R.plurals.n_members, memberCount, memberCount);
+ }
} else if (dcContact != null && !dcChat.isSelfTalk() && !dcChat.isDeviceTalk()) {
long timestamp = dcContact.getLastSeen();
if (timestamp == 0) {
diff --git a/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java b/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java
index 4bf6b536b..94405ef11 100644
--- a/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java
@@ -300,6 +300,8 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
if (itemId == R.id.menu_add_to_home_screen) {
addToHomeScreen(this, dcAppMsg.getId());
return true;
+ } else if (itemId == R.id.webxdc_help) {
+ DcHelper.openHelp(this, "#webxdc");
} else if (itemId == R.id.source_code) {
IntentUtils.showInBrowser(this, sourceCodeUrl);
return true;
diff --git a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
index 4d4ee64e6..469659b8a 100644
--- a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
+++ b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java
@@ -49,19 +49,7 @@ public class DcHelper {
private static final String TAG = DcHelper.class.getSimpleName();
- public static final String CONFIG_ADDRESS = "addr";
public static final String CONFIG_CONFIGURED_ADDRESS = "configured_addr";
- public static final String CONFIG_MAIL_SERVER = "mail_server";
- public static final String CONFIG_MAIL_USER = "mail_user";
- public static final String CONFIG_MAIL_PASSWORD = "mail_pw";
- public static final String CONFIG_MAIL_PORT = "mail_port";
- public static final String CONFIG_MAIL_SECURITY = "mail_security";
- public static final String CONFIG_SEND_SERVER = "send_server";
- public static final String CONFIG_SEND_USER = "send_user";
- public static final String CONFIG_SEND_PASSWORD = "send_pw";
- public static final String CONFIG_SEND_PORT = "send_port";
- public static final String CONFIG_SEND_SECURITY = "send_security";
- public static final String CONFIG_SERVER_FLAGS = "server_flags";
public static final String CONFIG_DISPLAY_NAME = "displayname";
public static final String CONFIG_SELF_STATUS = "selfstatus";
public static final String CONFIG_SELF_AVATAR = "selfavatar";
@@ -171,6 +159,11 @@ public class DcHelper {
dcContext.setStockTranslation(118, context.getString(R.string.secure_join_replies));
dcContext.setStockTranslation(119, context.getString(R.string.qrshow_join_contact_hint));
+ // HACK: svg does not handle entities correctly and shows `"` as the text `quot;`.
+ // until that is fixed, we fix the most obvious errors (core uses encode_minimal, so this does not affect so many characters)
+ // cmp. https://github.com/deltachat/deltachat-android/issues/2187
+ dcContext.setStockTranslation(120, context.getString(R.string.qrshow_join_group_hint).replace("\"", ""));
+ dcContext.setStockTranslation(121, context.getString(R.string.connectivity_not_connected));
dcContext.setStockTranslation(124, context.getString(R.string.group_name_changed_by_you));
dcContext.setStockTranslation(125, context.getString(R.string.group_name_changed_by_other));
dcContext.setStockTranslation(126, context.getString(R.string.group_image_changed_by_you));
@@ -189,8 +182,6 @@ public class DcHelper {
dcContext.setStockTranslation(139, context.getString(R.string.ephemeral_timer_disabled_by_other));
dcContext.setStockTranslation(140, context.getString(R.string.ephemeral_timer_seconds_by_you));
dcContext.setStockTranslation(141, context.getString(R.string.ephemeral_timer_seconds_by_other));
- dcContext.setStockTranslation(142, context.getString(R.string.ephemeral_timer_1_minute_by_you));
- dcContext.setStockTranslation(143, context.getString(R.string.ephemeral_timer_1_minute_by_other));
dcContext.setStockTranslation(144, context.getString(R.string.ephemeral_timer_1_hour_by_you));
dcContext.setStockTranslation(145, context.getString(R.string.ephemeral_timer_1_hour_by_other));
dcContext.setStockTranslation(146, context.getString(R.string.ephemeral_timer_1_day_by_you));
@@ -207,12 +198,6 @@ public class DcHelper {
dcContext.setStockTranslation(157, context.getString(R.string.ephemeral_timer_weeks_by_other));
dcContext.setStockTranslation(158, context.getString(R.string.ephemeral_timer_1_year_by_you));
dcContext.setStockTranslation(159, context.getString(R.string.ephemeral_timer_1_year_by_other));
-
- // HACK: svg does not handle entities correctly and shows `"` as the text `quot;`.
- // until that is fixed, we fix the most obvious errors (core uses encode_minimal, so this does not affect so many characters)
- // cmp. https://github.com/deltachat/deltachat-android/issues/2187
- dcContext.setStockTranslation(120, context.getString(R.string.qrshow_join_group_hint).replace("\"", ""));
- dcContext.setStockTranslation(121, context.getString(R.string.connectivity_not_connected));
dcContext.setStockTranslation(162, context.getString(R.string.multidevice_qr_subtitle));
dcContext.setStockTranslation(163, context.getString(R.string.multidevice_transfer_done_devicemsg));
dcContext.setStockTranslation(170, context.getString(R.string.chat_protection_enabled_tap_to_learn_more));
@@ -221,6 +206,7 @@ public class DcHelper {
dcContext.setStockTranslation(174, context.getString(R.string.invalid_unencrypted_tap_to_learn_more));
dcContext.setStockTranslation(176, context.getString(R.string.reaction_by_you));
dcContext.setStockTranslation(177, context.getString(R.string.reaction_by_other));
+ dcContext.setStockTranslation(178, context.getString(R.string.member_x_removed));
dcContext.setStockTranslation(190, context.getString(R.string.secure_join_wait));
dcContext.setStockTranslation(193, context.getString(R.string.donate_device_msg));
dcContext.setStockTranslation(194, context.getString(R.string.outgoing_call));
@@ -228,6 +214,14 @@ public class DcHelper {
dcContext.setStockTranslation(196, context.getString(R.string.declined_call));
dcContext.setStockTranslation(197, context.getString(R.string.canceled_call));
dcContext.setStockTranslation(198, context.getString(R.string.missed_call));
+ dcContext.setStockTranslation(200, context.getString(R.string.channel_left_by_you));
+ dcContext.setStockTranslation(201, context.getString(R.string.qrshow_join_channel_hint));
+ dcContext.setStockTranslation(202, context.getString(R.string.you_joined_the_channel));
+ dcContext.setStockTranslation(203, context.getString(R.string.secure_join_channel_started));
+ dcContext.setStockTranslation(210, context.getString(R.string.stats_msg_body));
+ dcContext.setStockTranslation(220, context.getString(R.string.proxy_enabled));
+ dcContext.setStockTranslation(221, context.getString(R.string.proxy_enabled_hint));
+ dcContext.setStockTranslation(230, context.getString(R.string.chat_unencrypted_explanation));
}
public static File getImexDir() {
diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index 97d9f7c2b..2dba9d074 100644
--- a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.LogViewActivity;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.RegistrationActivity;
+import org.thoughtcrime.securesms.EditTransportActivity;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
@@ -56,7 +56,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName();
private ListPreference showEmails;
- CheckBoxPreference bccSelfCheckbox;
+ CheckBoxPreference multiDeviceCheckbox;
CheckBoxPreference mvboxMoveCheckbox;
CheckBoxPreference onlyFetchMvboxCheckbox;
CheckBoxPreference webxdcRealtimeCheckbox;
@@ -74,12 +74,24 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
});
}
- bccSelfCheckbox = (CheckBoxPreference) this.findPreference("pref_bcc_self");
- if (bccSelfCheckbox != null) {
- bccSelfCheckbox.setOnPreferenceChangeListener((preference, newValue) -> {
+ multiDeviceCheckbox = (CheckBoxPreference) this.findPreference("pref_bcc_self");
+ if (multiDeviceCheckbox != null) {
+ multiDeviceCheckbox.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
- dcContext.setConfigInt(CONFIG_BCC_SELF, enabled? 1 : 0);
- return true;
+ if (enabled) {
+ dcContext.setConfigInt(CONFIG_BCC_SELF, 1);
+ return true;
+ } else {
+ new AlertDialog.Builder(requireContext())
+ .setMessage(R.string.pref_multidevice_change_warn)
+ .setPositiveButton(R.string.ok, (dialogInterface, i) -> {
+ dcContext.setConfigInt(CONFIG_BCC_SELF, 0);
+ ((CheckBoxPreference)preference).setChecked(false);
+ })
+ .setNegativeButton(R.string.cancel, null)
+ .show();
+ return false;
+ }
});
}
@@ -152,7 +164,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
Preference passwordAndAccount = this.findPreference("password_account_settings_button");
if (passwordAndAccount != null) {
passwordAndAccount.setOnPreferenceClickListener(((preference) -> {
- boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.pref_password_and_account_settings), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
+ boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.edit_transport), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
if (!result) {
openRegistrationActivity();
}
@@ -162,7 +174,6 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
if (dcContext.isChatmail()) {
showEmails.setVisible(false);
- bccSelfCheckbox.setVisible(false);
mvboxMoveCheckbox.setVisible(false);
onlyFetchMvboxCheckbox.setVisible(false);
}
@@ -182,7 +193,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
showEmails.setValue(value);
updateListSummary(showEmails, value);
- bccSelfCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_BCC_SELF));
+ multiDeviceCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_BCC_SELF));
mvboxMoveCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_MVBOX_MOVE));
onlyFetchMvboxCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_ONLY_FETCH_MVBOX));
webxdcRealtimeCheckbox.setChecked(0!=dcContext.getConfigInt(CONFIG_WEBXDC_REALTIME_ENABLED));
@@ -260,7 +271,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
private void openRegistrationActivity() {
- Intent intent = new Intent(requireActivity(), RegistrationActivity.class);
+ Intent intent = new Intent(requireActivity(), EditTransportActivity.class);
startActivity(intent);
}
diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java
index 2d6a1bfb3..35fa083c7 100644
--- a/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java
@@ -153,12 +153,11 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> {
- final String addr = DcHelper.get(getActivity(), DcHelper.CONFIG_CONFIGURED_ADDRESS);
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity())
.setTitle(R.string.pref_backup)
.setMessage(R.string.pref_backup_export_explain)
.setNeutralButton(android.R.string.cancel, null)
- .setPositiveButton(requireActivity().getString(R.string.pref_backup_export_this, addr), (dialogInterface, i) -> startImexOne(DcContext.DC_IMEX_EXPORT_BACKUP));
+ .setPositiveButton(R.string.pref_backup_export_this, (dialogInterface, i) -> startImexOne(DcContext.DC_IMEX_EXPORT_BACKUP));
int[] allAccounts = DcHelper.getAccounts(requireActivity()).getAll();
if (allAccounts.length > 1) {
String exportAllString = requireActivity().getString(R.string.pref_backup_export_all, allAccounts.length);
diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/PrivacyPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/PrivacyPreferenceFragment.java
index 00528f0a7..2607ae1ca 100644
--- a/src/main/java/org/thoughtcrime/securesms/preferences/PrivacyPreferenceFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/preferences/PrivacyPreferenceFragment.java
@@ -57,11 +57,7 @@ public class PrivacyPreferenceFragment extends ListSummaryPreferenceFragment {
autoDelServer = findPreference("autodel_server");
autoDelServer.setOnPreferenceChangeListener(new AutodelChangeListener("delete_server_after"));
if (dcContext.isChatmail()) {
- autoDelServer.setEntries(new CharSequence[]{getString(R.string.automatic), getString(R.string.autodel_at_once)});
- autoDelServer.setEntryValues(new CharSequence[]{"0", "1"});
- if (dcContext.getConfigInt("delete_server_after") > 1) {
- dcContext.setConfigInt("delete_server_after", 0 /*never/automatic*/);
- }
+ autoDelServer.setVisible(false);
}
Preference screenSecurity = this.findPreference(Prefs.SCREEN_SECURITY_PREF);
diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
index cc5424cf5..e2cf69561 100644
--- a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
+++ b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
@@ -112,8 +112,10 @@ public class QrCodeHandler {
case DcContext.DC_QR_WITHDRAW_VERIFYCONTACT:
case DcContext.DC_QR_WITHDRAW_VERIFYGROUP:
+ case DcContext.DC_QR_WITHDRAW_JOINBROADCAST:
String message = qrParsed.getState() == DcContext.DC_QR_WITHDRAW_VERIFYCONTACT ? activity.getString(R.string.withdraw_verifycontact_explain)
- : activity.getString(R.string.withdraw_verifygroup_explain, qrParsed.getText1());
+ : qrParsed.getState() == DcContext.DC_QR_WITHDRAW_VERIFYCONTACT ? activity.getString(R.string.withdraw_verifygroup_explain, qrParsed.getText1())
+ : activity.getString(R.string.withdraw_joinbroadcast_explain, qrParsed.getText1());
builder.setTitle(R.string.qrshow_title);
builder.setMessage(message);
builder.setNeutralButton(R.string.reset, (dialog, which) -> {
@@ -126,6 +128,7 @@ public class QrCodeHandler {
case DcContext.DC_QR_REVIVE_VERIFYCONTACT:
case DcContext.DC_QR_REVIVE_VERIFYGROUP:
+ case DcContext.DC_QR_REVIVE_JOINBROADCAST:
builder.setTitle(R.string.qrshow_title);
builder.setMessage(activity.getString(R.string.revive_verifycontact_explain));
builder.setNeutralButton(R.string.revive_qr_code, (dialog, which) -> {
diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrShowFragment.java b/src/main/java/org/thoughtcrime/securesms/qr/QrShowFragment.java
index 79941c728..8b1704d64 100644
--- a/src/main/java/org/thoughtcrime/securesms/qr/QrShowFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/qr/QrShowFragment.java
@@ -20,6 +20,7 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
+import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEvent;
import com.caverock.androidsvg.SVG;
@@ -144,8 +145,17 @@ public class QrShowFragment extends Fragment implements DcEventCenter.DcEventDel
public void withdrawQr() {
Activity activity = getActivity();
- String message = chatId == 0 ? activity.getString(R.string.withdraw_verifycontact_explain)
- : activity.getString(R.string.withdraw_verifygroup_explain, dcContext.getChat(chatId).getName());
+ String message;
+ if (chatId == 0) {
+ message = activity.getString(R.string.withdraw_verifycontact_explain);
+ } else {
+ DcChat chat = dcContext.getChat(chatId);
+ if (chat.getType() == DcChat.DC_CHAT_TYPE_GROUP) {
+ message = activity.getString(R.string.withdraw_verifygroup_explain, chat.getName());
+ } else {
+ message = activity.getString(R.string.withdraw_joinbroadcast_explain, chat.getName());
+ }
+ }
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.withdraw_qr_code);
builder.setMessage(message);
diff --git a/src/main/java/org/thoughtcrime/securesms/service/FetchForegroundService.java b/src/main/java/org/thoughtcrime/securesms/service/FetchForegroundService.java
index 341559663..29b71c2c7 100644
--- a/src/main/java/org/thoughtcrime/securesms/service/FetchForegroundService.java
+++ b/src/main/java/org/thoughtcrime/securesms/service/FetchForegroundService.java
@@ -108,4 +108,11 @@ public final class FetchForegroundService extends Service {
public IBinder onBind(Intent intent) {
return null;
}
+
+ @Override
+ public void onTimeout(int startId, int fgsType) {
+ ApplicationContext.dcAccounts.stopBackgroundFetch();
+ stopSelf();
+ }
+
}
diff --git a/src/main/java/org/thoughtcrime/securesms/util/Util.java b/src/main/java/org/thoughtcrime/securesms/util/Util.java
index 3aced4758..75c2797f2 100644
--- a/src/main/java/org/thoughtcrime/securesms/util/Util.java
+++ b/src/main/java/org/thoughtcrime/securesms/util/Util.java
@@ -126,6 +126,18 @@ public class Util {
return ret;
}
+ public static boolean contains(@Nullable int[] array, int val) {
+ if (array == null) {
+ return false;
+ }
+ for (int element : array) {
+ if (element == val) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static void wait(Object lock, long timeout) {
try {
lock.wait(timeout);
diff --git a/src/main/java/org/thoughtcrime/securesms/video/recode/VideoRecoder.java b/src/main/java/org/thoughtcrime/securesms/video/recode/VideoRecoder.java
index 79ce14377..a8b1cbd65 100644
--- a/src/main/java/org/thoughtcrime/securesms/video/recode/VideoRecoder.java
+++ b/src/main/java/org/thoughtcrime/securesms/video/recode/VideoRecoder.java
@@ -554,6 +554,8 @@ public class VideoRecoder {
// the function fills out missing information and also recodes the video as needed.
// return: true=video might be prepared, can be sent, false=error
public static boolean prepareVideo(Context context, int chatId, DcMsg msg) {
+ final long MAX_BYTES = DcHelper.getInt(context, "sys.msgsize_max_recommended");
+ final String TOO_BIG_FILE = "Video cannot be compressed to a reasonable size. Try a shorter video or a lower quality.";
try {
String inPath = msg.getFile();
Log.i(TAG, "Preparing video: " + inPath);
@@ -561,9 +563,14 @@ public class VideoRecoder {
// try to get information from video file
VideoEditedInfo vei = getVideoEditInfoFromFile(inPath);
if (vei == null) {
- alert(context, String.format("Recoding failed for %s: cannot get info", inPath));
- return false;
+ Log.w(TAG, String.format("Recoding failed for %s: cannot get info", inPath));
+ if (msg.getFilebytes() > MAX_BYTES+MAX_BYTES/4) {
+ alert(context, TOO_BIG_FILE);
+ return false;
+ }
+ return true; // if the file is small, send it without recoding
}
+
vei.rotationValue = vei.originalRotationValue;
vei.startTime = 0;
vei.endTime = -1;
@@ -579,7 +586,6 @@ public class VideoRecoder {
// check if video bitrate is already reasonable
final int MAX_KBPS = 1500000;
- final long MAX_BYTES = DcHelper.getInt(context, "sys.msgsize_max_recommended");
long inBytes = new File(inPath).length();
if (inBytes > 0 && inBytes <= MAX_BYTES && vei.originalVideoBitrate <= MAX_KBPS*2 /*be tolerant as long the file size matches*/) {
Log.i(TAG, String.format("recoding for %s is not needed, %d bytes and %d kbps are ok", inPath, inBytes, vei.originalVideoBitrate));
@@ -627,7 +633,7 @@ public class VideoRecoder {
vei.resultVideoBitrate, vei.originalDurationMs, vei.originalAudioBytes);
if (vei.estimatedBytes > MAX_BYTES+MAX_BYTES/4) {
- alert(context, "Video cannot be compressed to a reasonable size. Try a shorter video or a lower quality.");
+ alert(context, TOO_BIG_FILE);
return false;
}
diff --git a/src/main/res/layout/registration_activity.xml b/src/main/res/layout/activity_edittransport.xml
similarity index 99%
rename from src/main/res/layout/registration_activity.xml
rename to src/main/res/layout/activity_edittransport.xml
index 1ad7ff7d0..028631705 100644
--- a/src/main/res/layout/registration_activity.xml
+++ b/src/main/res/layout/activity_edittransport.xml
@@ -13,7 +13,7 @@
android:layout_height="match_parent"
android:fillViewport="true"
android:background="?android:attr/windowBackground"
- tools:context=".RegistrationActivity">
+ tools:context=".EditTransportActivity">
-
-
+
+
diff --git a/src/main/res/menu/webxdc.xml b/src/main/res/menu/webxdc.xml
index 69aebb7c7..b71b85d7d 100644
--- a/src/main/res/menu/webxdc.xml
+++ b/src/main/res/menu/webxdc.xml
@@ -2,10 +2,12 @@