mirror of
https://github.com/deltachat/deltachat-android.git
synced 2025-10-02 17:29:17 +02:00
use auto-generated RPC bindings
This commit is contained in:
parent
70a05221ab
commit
b871e42b86
47 changed files with 936 additions and 655 deletions
|
@ -173,7 +173,6 @@ dependencies {
|
|||
implementation 'com.google.zxing:core:3.3.0' // fixed version to support SDK<24
|
||||
implementation ('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } // QR Code scanner
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1' // used as JSON library
|
||||
implementation 'com.google.code.gson:gson:2.12.1' // used as JSON library.
|
||||
implementation 'com.github.Baseflow:PhotoView:2.3.0' // does the zooming on photos / media
|
||||
implementation 'com.github.penfeizhou.android.animation:awebp:3.0.5' // animated webp support.
|
||||
implementation 'com.caverock:androidsvg-aar:1.4' // SVG support.
|
||||
|
|
124
src/main/java/chat/delta/rpc/BaseTransport.java
Normal file
124
src/main/java/chat/delta/rpc/BaseTransport.java
Normal file
|
@ -0,0 +1,124 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc;
|
||||
|
||||
import chat.delta.util.SettableFuture;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/* Basic RPC Transport implementation */
|
||||
public abstract class BaseTransport implements Rpc.Transport {
|
||||
private final Map<Integer, SettableFuture<JsonNode>> requestFutures = new ConcurrentHashMap<>();
|
||||
private int requestId = 0;
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
private Thread worker;
|
||||
|
||||
/* Send a Request as raw JSON String to the RPC server */
|
||||
protected abstract void sendRequest(String jsonRequest);
|
||||
|
||||
/* Get next Response as raw JSON String from the RPC server */
|
||||
protected abstract String getResponse();
|
||||
|
||||
public ObjectMapper getObjectMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
public void call(String method, JsonNode... params) throws RpcException {
|
||||
innerCall(method, params);
|
||||
}
|
||||
|
||||
public <T> T callForResult(TypeReference<T> resultType, String method, JsonNode... params) throws RpcException {
|
||||
try {
|
||||
JsonNode node = innerCall(method, params);
|
||||
if (node.isNull()) return null;
|
||||
return mapper.readValue(node.traverse(), resultType);
|
||||
} catch (IOException e) {
|
||||
throw new RpcException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private JsonNode innerCall(String method, JsonNode... params) throws RpcException {
|
||||
int id;
|
||||
synchronized (this) {
|
||||
id = ++requestId;
|
||||
ensureWorkerThread();
|
||||
}
|
||||
try {
|
||||
String jsonRequest = mapper.writeValueAsString(new Request(method, params, id));
|
||||
SettableFuture<JsonNode> future = new SettableFuture<>();
|
||||
requestFutures.put(id, future);
|
||||
sendRequest(jsonRequest);
|
||||
return future.get();
|
||||
} catch (ExecutionException e) {
|
||||
throw (RpcException)e.getCause();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RpcException(e.getMessage());
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RpcException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureWorkerThread() {
|
||||
if (worker != null) return;
|
||||
|
||||
worker = new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
processResponse();
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "jsonrpcThread");
|
||||
worker.start();
|
||||
}
|
||||
|
||||
private void processResponse() throws JsonProcessingException {
|
||||
String jsonResponse = getResponse();
|
||||
Response response = mapper.readValue(jsonResponse, Response.class);
|
||||
|
||||
if (response.id == 0) { // Got JSON-RPC notification/event, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
SettableFuture<JsonNode> future = requestFutures.remove(response.id);
|
||||
if (future == null) { // Got a response with unknown ID, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.error != null) {
|
||||
future.setException(new RpcException(response.error.toString()));
|
||||
} else if (response.result != null) {
|
||||
future.set(response.result);
|
||||
} else {
|
||||
future.setException(new RpcException("Got JSON-RPC response without result or error: " + jsonResponse));
|
||||
}
|
||||
}
|
||||
|
||||
private static class Request {
|
||||
private final String jsonrpc = "2.0";
|
||||
public final String method;
|
||||
public final JsonNode[] params;
|
||||
public final int id;
|
||||
|
||||
public Request(String method, JsonNode[] params, int id) {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Response {
|
||||
public String jsonrpc;
|
||||
public int id;
|
||||
public JsonNode result;
|
||||
public JsonNode error;
|
||||
}
|
||||
}
|
249
src/main/java/chat/delta/rpc/Rpc.java
Normal file
249
src/main/java/chat/delta/rpc/Rpc.java
Normal file
|
@ -0,0 +1,249 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import chat.delta.rpc.types.*;
|
||||
|
||||
public class Rpc {
|
||||
|
||||
public interface Transport {
|
||||
void call(String method, JsonNode... params) throws RpcException;
|
||||
<T> T callForResult(TypeReference<T> resultType, String method, JsonNode... params) throws RpcException;
|
||||
ObjectMapper getObjectMapper();
|
||||
}
|
||||
|
||||
public final Transport transport;
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
public Rpc(Transport transport) {
|
||||
this.transport = transport;
|
||||
this.mapper = transport.getObjectMapper();
|
||||
}
|
||||
|
||||
public Integer addAccount() throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "add_account");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order of accounts.
|
||||
* The provided list should contain all account IDs in the desired order.
|
||||
* If an account ID is missing from the list, it will be appended at the end.
|
||||
* If the list contains non-existent account IDs, they will be ignored.
|
||||
*/
|
||||
public void setAccountsOrder(java.util.List<Integer> order) throws RpcException {
|
||||
transport.call("set_accounts_order", mapper.valueToTree(order));
|
||||
}
|
||||
|
||||
/* Get the combined filesize of an account in bytes */
|
||||
public Integer getAccountFileSize(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "get_account_file_size", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error while the account was opened
|
||||
* and migrated to the current version,
|
||||
* then this function returns it.
|
||||
* <p>
|
||||
* This function is useful because the key-contacts migration could fail due to bugs
|
||||
* and then the account will not work properly.
|
||||
* <p>
|
||||
* After opening an account, the UI should call this function
|
||||
* and show the error string if one is returned.
|
||||
*/
|
||||
public String getMigrationError(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "get_migration_error", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
public Integer draftSelfReport(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "draft_self_report", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/* Returns configuration value for the given key. */
|
||||
public String getConfig(Integer accountId, String key) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "get_config", mapper.valueToTree(accountId), mapper.valueToTree(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a new email account using the provided parameters
|
||||
* and adds it as a transport.
|
||||
* <p>
|
||||
* If the email address is the same as an existing transport,
|
||||
* then this existing account will be reconfigured instead of a new one being added.
|
||||
* <p>
|
||||
* This function stops and starts IO as needed.
|
||||
* <p>
|
||||
* Usually it will be enough to only set `addr` and `password`,
|
||||
* and all the other settings will be autoconfigured.
|
||||
* <p>
|
||||
* During configuration, ConfigureProgress events are emitted;
|
||||
* they indicate a successful configuration as well as errors
|
||||
* and may be used to create a progress bar.
|
||||
* This function will return after configuration is finished.
|
||||
* <p>
|
||||
* If configuration is successful,
|
||||
* the working server parameters will be saved
|
||||
* and used for connecting to the server.
|
||||
* The parameters entered by the user will be saved separately
|
||||
* so that they can be prefilled when the user opens the server-configuration screen again.
|
||||
* <p>
|
||||
* See also:
|
||||
* - [Self::is_configured()] to check whether there is
|
||||
* at least one working transport.
|
||||
* - [Self::add_transport_from_qr()] to add a transport
|
||||
* from a server encoded in a QR code.
|
||||
* - [Self::list_transports()] to get a list of all configured transports.
|
||||
* - [Self::delete_transport()] to remove a transport.
|
||||
*/
|
||||
public void addOrUpdateTransport(Integer accountId, EnteredLoginParam param) throws RpcException {
|
||||
transport.call("add_or_update_transport", mapper.valueToTree(accountId), mapper.valueToTree(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new email account as a transport
|
||||
* using the server encoded in the QR code.
|
||||
* See [Self::add_or_update_transport].
|
||||
*/
|
||||
public void addTransportFromQr(Integer accountId, String qr) throws RpcException {
|
||||
transport.call("add_transport_from_qr", mapper.valueToTree(accountId), mapper.valueToTree(qr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new unencrypted group chat.
|
||||
* <p>
|
||||
* Same as [`Self::create_group_chat`], but the chat is unencrypted and can only have
|
||||
* address-contacts.
|
||||
*/
|
||||
public Integer createGroupChatUnencrypted(Integer accountId, String name) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "create_group_chat_unencrypted", mapper.valueToTree(accountId), mapper.valueToTree(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new **broadcast channel**
|
||||
* (called "Channel" in the UI).
|
||||
* <p>
|
||||
* Broadcast channels are similar to groups on the sending device,
|
||||
* however, recipients get the messages in a read-only chat
|
||||
* and will not see who the other members are.
|
||||
* <p>
|
||||
* Called `broadcast` here rather than `channel`,
|
||||
* because the word "channel" already appears a lot in the code,
|
||||
* which would make it hard to grep for it.
|
||||
* <p>
|
||||
* After creation, the chat contains no recipients and is in _unpromoted_ state;
|
||||
* see [`CommandApi::create_group_chat`] for more information on the unpromoted state.
|
||||
* <p>
|
||||
* Returns the created chat's id.
|
||||
*/
|
||||
public Integer createBroadcast(Integer accountId, String chatName) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "create_broadcast", mapper.valueToTree(accountId), mapper.valueToTree(chatName));
|
||||
}
|
||||
|
||||
/* 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<Integer>(){}, "create_chat_by_contact_id", 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));
|
||||
}
|
||||
|
||||
|
||||
/* Parses a vCard file located at the given path. Returns contacts in their original order. */
|
||||
public java.util.List<VcardContact> parseVcard(String path) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<VcardContact>>(){}, "parse_vcard", mapper.valueToTree(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports contacts from a vCard file located at the given path.
|
||||
* <p>
|
||||
* Returns the ids of created/modified contacts in the order they appear in the vCard.
|
||||
*/
|
||||
public java.util.List<Integer> importVcard(Integer accountId, String path) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<Integer>>(){}, "import_vcard", mapper.valueToTree(accountId), mapper.valueToTree(path));
|
||||
}
|
||||
|
||||
/* Returns a vCard containing contacts with the given ids. */
|
||||
public String makeVcard(Integer accountId, java.util.List<Integer> contacts) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "make_vcard", mapper.valueToTree(accountId), mapper.valueToTree(contacts));
|
||||
}
|
||||
|
||||
public void sendWebxdcRealtimeData(Integer accountId, Integer instanceMsgId, java.util.List<Integer> data) throws RpcException {
|
||||
transport.call("send_webxdc_realtime_data", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(data));
|
||||
}
|
||||
|
||||
public void sendWebxdcRealtimeAdvertisement(Integer accountId, Integer instanceMsgId) throws RpcException {
|
||||
transport.call("send_webxdc_realtime_advertisement", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the gossip of the webxdc with the given message id.
|
||||
* <p>
|
||||
* NB: When this is called before closing a webxdc app in UIs, it must be guaranteed that
|
||||
* `send_webxdc_realtime_*()` functions aren't called for the given `instance_message_id`
|
||||
* anymore until the app is open again.
|
||||
*/
|
||||
public void leaveWebxdcRealtime(Integer accountId, Integer instanceMessageId) throws RpcException {
|
||||
transport.call("leave_webxdc_realtime", mapper.valueToTree(accountId), mapper.valueToTree(instanceMessageId));
|
||||
}
|
||||
|
||||
/* Starts an outgoing call. */
|
||||
public Integer placeOutgoingCall(Integer accountId, Integer chatId, String placeCallInfo) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "place_outgoing_call", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(placeCallInfo));
|
||||
}
|
||||
|
||||
/* Accepts an incoming call. */
|
||||
public void acceptIncomingCall(Integer accountId, Integer msgId, String acceptCallInfo) throws RpcException {
|
||||
transport.call("accept_incoming_call", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(acceptCallInfo));
|
||||
}
|
||||
|
||||
/* Ends incoming or outgoing call. */
|
||||
public void endCall(Integer accountId, Integer msgId) throws RpcException {
|
||||
transport.call("end_call", mapper.valueToTree(accountId), mapper.valueToTree(msgId));
|
||||
}
|
||||
|
||||
/* Returns information about the call. */
|
||||
public CallInfo callInfo(Integer accountId, Integer msgId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<CallInfo>(){}, "call_info", mapper.valueToTree(accountId), mapper.valueToTree(msgId));
|
||||
}
|
||||
|
||||
/* Returns JSON with ICE servers, to be used for WebRTC video calls. */
|
||||
public String iceServers(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "ice_servers", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an HTTP GET request and returns a response.
|
||||
* <p>
|
||||
* `url` is the HTTP or HTTPS URL.
|
||||
*/
|
||||
public HttpResponse getHttpResponse(Integer accountId, String url) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<HttpResponse>(){}, "get_http_response", mapper.valueToTree(accountId), mapper.valueToTree(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a reaction to message.
|
||||
* <p>
|
||||
* Reaction is a string of emojis separated by spaces. Reaction to a
|
||||
* single message can be sent multiple times. The last reaction
|
||||
* received overrides all previously received reactions. It is
|
||||
* possible to remove all reactions by sending an empty string.
|
||||
*/
|
||||
public Integer sendReaction(Integer accountId, Integer messageId, java.util.List<String> reaction) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "send_reaction", mapper.valueToTree(accountId), mapper.valueToTree(messageId), mapper.valueToTree(reaction));
|
||||
}
|
||||
|
||||
/* Returns reactions to the message. */
|
||||
public Reactions getMessageReactions(Integer accountId, Integer messageId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Reactions>(){}, "get_message_reactions", mapper.valueToTree(accountId), mapper.valueToTree(messageId));
|
||||
}
|
||||
|
||||
/* Checks if messages can be sent to a given chat. */
|
||||
public Boolean canSend(Integer accountId, Integer chatId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Boolean>(){}, "can_send", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
|
||||
}
|
||||
|
||||
}
|
8
src/main/java/chat/delta/rpc/RpcException.java
Normal file
8
src/main/java/chat/delta/rpc/RpcException.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc;
|
||||
|
||||
public class RpcException extends Exception {
|
||||
|
||||
public RpcException(String message) { super(message); }
|
||||
|
||||
}
|
17
src/main/java/chat/delta/rpc/types/CallInfo.java
Normal file
17
src/main/java/chat/delta/rpc/types/CallInfo.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public class CallInfo {
|
||||
/**
|
||||
* SDP offer.
|
||||
* <p>
|
||||
* Can be used to manually answer the call even if incoming call event was missed.
|
||||
*/
|
||||
public String sdpOffer;
|
||||
/**
|
||||
* Call state.
|
||||
* <p>
|
||||
* For example, if the call is accepted, active, cancelled, declined etc.
|
||||
*/
|
||||
public CallState state;
|
||||
}
|
48
src/main/java/chat/delta/rpc/types/CallState.java
Normal file
48
src/main/java/chat/delta/rpc/types/CallState.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* 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.MINIMAL_CLASS, include=As.PROPERTY, property="kind")
|
||||
@JsonSubTypes({@Type(CallState.Alerting.class), @Type(CallState.Active.class), @Type(CallState.Completed.class), @Type(CallState.Missed.class), @Type(CallState.Declined.class), @Type(CallState.Cancelled.class)})
|
||||
public abstract class CallState {
|
||||
|
||||
/**
|
||||
* Fresh incoming or outgoing call that is still ringing.
|
||||
* <p>
|
||||
* There is no separate state for outgoing call that has been dialled but not ringing on the other side yet as we don't know whether the other side received our call.
|
||||
*/
|
||||
public static class Alerting extends CallState {
|
||||
}
|
||||
|
||||
/* Active call. */
|
||||
public static class Active extends CallState {
|
||||
}
|
||||
|
||||
/* Completed call that was once active and then was terminated for any reason. */
|
||||
public static class Completed extends CallState {
|
||||
/* Call duration in seconds. */
|
||||
public Integer duration;
|
||||
}
|
||||
|
||||
/* Incoming call that was not picked up within a timeout or was explicitly ended by the caller before we picked up. */
|
||||
public static class Missed extends CallState {
|
||||
}
|
||||
|
||||
/* Incoming call that was explicitly ended on our side before picking up or outgoing call that was declined before the timeout. */
|
||||
public static class Declined extends CallState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Outgoing call that has been cancelled on our side before receiving a response.
|
||||
* <p>
|
||||
* Incoming calls cannot be cancelled, on the receiver side cancelled calls usually result in missed calls.
|
||||
*/
|
||||
public static class Cancelled extends CallState {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public enum EnteredCertificateChecks {
|
||||
/* `Automatic` means that provider database setting should be taken. If there is no provider database setting for certificate checks, check certificates strictly. */
|
||||
automatic,
|
||||
|
||||
/* Ensure that TLS certificate is valid for the server hostname. */
|
||||
strict,
|
||||
|
||||
/* Accept certificates that are expired, self-signed or otherwise not valid for the server hostname. */
|
||||
acceptInvalidCertificates,
|
||||
}
|
51
src/main/java/chat/delta/rpc/types/EnteredLoginParam.java
Normal file
51
src/main/java/chat/delta/rpc/types/EnteredLoginParam.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
/**
|
||||
* Login parameters entered by the user.
|
||||
* <p>
|
||||
* Usually it will be enough to only set `addr` and `password`, and all the other settings will be autoconfigured.
|
||||
*/
|
||||
public class EnteredLoginParam {
|
||||
/* Email address. */
|
||||
public String addr;
|
||||
/* TLS options: whether to allow invalid certificates and/or invalid hostnames. Default: Automatic */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public EnteredCertificateChecks certificateChecks;
|
||||
/* Imap server port. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer imapPort;
|
||||
/* Imap socket security. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Socket imapSecurity;
|
||||
/* Imap server hostname or IP address. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String imapServer;
|
||||
/* Imap username. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String imapUser;
|
||||
/* If true, login via OAUTH2 (not recommended anymore). Default: false */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Boolean oauth2;
|
||||
/* Password. */
|
||||
public String password;
|
||||
/**
|
||||
* SMTP Password.
|
||||
* <p>
|
||||
* Only needs to be specified if different than IMAP password.
|
||||
*/
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String smtpPassword;
|
||||
/* SMTP server port. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer smtpPort;
|
||||
/* SMTP socket security. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Socket smtpSecurity;
|
||||
/* SMTP server hostname or IP address. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String smtpServer;
|
||||
/* SMTP username. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String smtpUser;
|
||||
}
|
13
src/main/java/chat/delta/rpc/types/HttpResponse.java
Normal file
13
src/main/java/chat/delta/rpc/types/HttpResponse.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public class HttpResponse {
|
||||
/* base64-encoded response body. */
|
||||
public String blob;
|
||||
/* Encoding, e.g. "utf-8". */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String encoding;
|
||||
/* MIME type, e.g. "text/plain" or "text/html". */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String mimetype;
|
||||
}
|
12
src/main/java/chat/delta/rpc/types/Reaction.java
Normal file
12
src/main/java/chat/delta/rpc/types/Reaction.java
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
/* A single reaction emoji. */
|
||||
public class Reaction {
|
||||
/* Emoji frequency. */
|
||||
public Integer count;
|
||||
/* Emoji. */
|
||||
public String emoji;
|
||||
/* True if we reacted with this emoji. */
|
||||
public Boolean isFromSelf;
|
||||
}
|
10
src/main/java/chat/delta/rpc/types/Reactions.java
Normal file
10
src/main/java/chat/delta/rpc/types/Reactions.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
/* Structure representing all reactions to a particular message. */
|
||||
public class Reactions {
|
||||
/* Unique reactions and their count, sorted in descending order. */
|
||||
public java.util.List<Reaction> reactions;
|
||||
/* Map from a contact to it's reaction to message. */
|
||||
public java.util.Map<String, java.util.List<String>> reactionsByContact;
|
||||
}
|
16
src/main/java/chat/delta/rpc/types/Socket.java
Normal file
16
src/main/java/chat/delta/rpc/types/Socket.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public enum Socket {
|
||||
/* Unspecified socket security, select automatically. */
|
||||
automatic,
|
||||
|
||||
/* TLS connection. */
|
||||
ssl,
|
||||
|
||||
/* STARTTLS connection. */
|
||||
starttls,
|
||||
|
||||
/* No TLS, plaintext connection. */
|
||||
plain,
|
||||
}
|
20
src/main/java/chat/delta/rpc/types/VcardContact.java
Normal file
20
src/main/java/chat/delta/rpc/types/VcardContact.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public class VcardContact {
|
||||
/* Email address. */
|
||||
public String addr;
|
||||
/* Contact color as hex string. */
|
||||
public String color;
|
||||
/* The contact's name, or the email address if no name was given. */
|
||||
public String displayName;
|
||||
/* Public PGP key in Base64. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String key;
|
||||
/* Profile image in Base64. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String profileImage;
|
||||
/* Last update timestamp. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer timestamp;
|
||||
}
|
14
src/main/java/chat/delta/util/ListenableFuture.java
Normal file
14
src/main/java/chat/delta/util/ListenableFuture.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.util;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public interface ListenableFuture<T> extends Future<T> {
|
||||
void addListener(Listener<T> listener);
|
||||
|
||||
public interface Listener<T> {
|
||||
public void onSuccess(T result);
|
||||
public void onFailure(ExecutionException e);
|
||||
}
|
||||
}
|
137
src/main/java/chat/delta/util/SettableFuture.java
Normal file
137
src/main/java/chat/delta/util/SettableFuture.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class SettableFuture<T> implements ListenableFuture<T> {
|
||||
|
||||
private final List<Listener<T>> listeners = new LinkedList<>();
|
||||
|
||||
private boolean completed;
|
||||
private boolean canceled;
|
||||
private volatile T result;
|
||||
private volatile Throwable exception;
|
||||
|
||||
public SettableFuture() { }
|
||||
|
||||
public SettableFuture(T value) {
|
||||
this.result = value;
|
||||
this.completed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if (!completed && !canceled) {
|
||||
canceled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isCancelled() {
|
||||
return canceled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isDone() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
public boolean set(T result) {
|
||||
synchronized (this) {
|
||||
if (completed || canceled) return false;
|
||||
|
||||
this.result = result;
|
||||
this.completed = true;
|
||||
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
notifyAllListeners();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setException(Throwable throwable) {
|
||||
synchronized (this) {
|
||||
if (completed || canceled) return false;
|
||||
|
||||
this.exception = throwable;
|
||||
this.completed = true;
|
||||
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
notifyAllListeners();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void deferTo(ListenableFuture<T> other) {
|
||||
other.addListener(new Listener<T>() {
|
||||
@Override
|
||||
public void onSuccess(T result) {
|
||||
SettableFuture.this.set(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(ExecutionException e) {
|
||||
SettableFuture.this.setException(e.getCause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T get() throws InterruptedException, ExecutionException {
|
||||
while (!completed) wait();
|
||||
|
||||
if (exception != null) throw new ExecutionException(exception);
|
||||
else return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
while (!completed && System.currentTimeMillis() - startTime > unit.toMillis(timeout)) {
|
||||
wait(unit.toMillis(timeout));
|
||||
}
|
||||
|
||||
if (!completed) throw new TimeoutException();
|
||||
else return get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Listener<T> listener) {
|
||||
synchronized (this) {
|
||||
listeners.add(listener);
|
||||
|
||||
if (!completed) return;
|
||||
}
|
||||
|
||||
notifyListener(listener);
|
||||
}
|
||||
|
||||
private void notifyAllListeners() {
|
||||
List<Listener<T>> localListeners;
|
||||
|
||||
synchronized (this) {
|
||||
localListeners = new LinkedList<>(listeners);
|
||||
}
|
||||
|
||||
for (Listener<T> listener : localListeners) {
|
||||
notifyListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListener(Listener<T> listener) {
|
||||
if (exception != null) listener.onFailure(new ExecutionException(exception));
|
||||
else listener.onSuccess(result);
|
||||
}
|
||||
}
|
22
src/main/java/com/b44t/messenger/FFITransport.java
Normal file
22
src/main/java/com/b44t/messenger/FFITransport.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package com.b44t.messenger;
|
||||
|
||||
import chat.delta.rpc.BaseTransport;
|
||||
|
||||
/* RPC transport over C FFI */
|
||||
public class FFITransport extends BaseTransport {
|
||||
private final DcJsonrpcInstance dcJsonrpcInstance;
|
||||
|
||||
public FFITransport(DcJsonrpcInstance dcJsonrpcInstance) {
|
||||
this.dcJsonrpcInstance = dcJsonrpcInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRequest(String jsonRequest) {
|
||||
dcJsonrpcInstance.request(jsonRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getResponse() {
|
||||
return dcJsonrpcInstance.getNextResponse();
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
public class EnteredLoginParam {
|
||||
// Email address.
|
||||
private final String addr;
|
||||
|
||||
// Password.
|
||||
private final String password;
|
||||
|
||||
// ============ IMAP settings ============
|
||||
|
||||
// Server hostname or IP address.
|
||||
private final String imapServer;
|
||||
|
||||
// Server port.
|
||||
private final int imapPort;
|
||||
|
||||
// Socket security.
|
||||
private final SocketSecurity imapSecurity;
|
||||
|
||||
// Username.
|
||||
private final String imapUser;
|
||||
|
||||
// ============ SMTP settings ============
|
||||
|
||||
// Server hostname or IP address.
|
||||
private final String smtpServer;
|
||||
|
||||
// Server port.
|
||||
private final int smtpPort;
|
||||
|
||||
// Socket security.
|
||||
private final SocketSecurity smtpSecurity;
|
||||
|
||||
// Username.
|
||||
private final String smtpUser;
|
||||
|
||||
// SMTP Password. Only needs to be specified if different than IMAP password.
|
||||
private final String smtpPassword;
|
||||
|
||||
// TLS options: whether to allow invalid certificates and/or
|
||||
// invalid hostnames
|
||||
private final EnteredCertificateChecks certificateChecks;
|
||||
|
||||
// If true, login via OAUTH2 (not recommended anymore)
|
||||
private final boolean oauth2;
|
||||
|
||||
public EnteredLoginParam(String addr,
|
||||
String password,
|
||||
String imapServer,
|
||||
int imapPort,
|
||||
SocketSecurity imapSecurity,
|
||||
String imapUser,
|
||||
String smtpServer,
|
||||
int smtpPort,
|
||||
SocketSecurity smtpSecurity,
|
||||
String smtpUser,
|
||||
String smtpPassword,
|
||||
EnteredCertificateChecks certificateChecks,
|
||||
boolean oauth2) {
|
||||
this.addr = addr;
|
||||
this.password = password;
|
||||
this.imapServer = imapServer;
|
||||
this.imapPort = imapPort;
|
||||
this.imapSecurity = imapSecurity;
|
||||
this.imapUser = imapUser;
|
||||
this.smtpServer = smtpServer;
|
||||
this.smtpPort = smtpPort;
|
||||
this.smtpSecurity = smtpSecurity;
|
||||
this.smtpUser = smtpUser;
|
||||
this.smtpPassword = smtpPassword;
|
||||
this.certificateChecks = certificateChecks;
|
||||
this.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
public String getAddr() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getImapServer() {
|
||||
return imapServer;
|
||||
}
|
||||
|
||||
public int getImapPort() {
|
||||
return imapPort;
|
||||
}
|
||||
|
||||
public SocketSecurity getImapSecurity() {
|
||||
return imapSecurity;
|
||||
}
|
||||
|
||||
public String getImapUser() {
|
||||
return imapUser;
|
||||
}
|
||||
|
||||
public String getSmtpServer() {
|
||||
return smtpServer;
|
||||
}
|
||||
|
||||
public int getSmtpPort() {
|
||||
return smtpPort;
|
||||
}
|
||||
|
||||
public SocketSecurity getSmtpSecurity() {
|
||||
return smtpSecurity;
|
||||
}
|
||||
|
||||
public String getSmtpUser() {
|
||||
return smtpUser;
|
||||
}
|
||||
|
||||
public String getSmtpPassword() {
|
||||
return smtpPassword;
|
||||
}
|
||||
|
||||
public EnteredCertificateChecks getCertificateChecks() {
|
||||
return certificateChecks;
|
||||
}
|
||||
|
||||
public boolean isOauth2() {
|
||||
return oauth2;
|
||||
}
|
||||
|
||||
public enum EnteredCertificateChecks {
|
||||
automatic, strict, acceptInvalidCertificates,
|
||||
}
|
||||
|
||||
public static EnteredCertificateChecks certificateChecksFromInt(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return EnteredCertificateChecks.automatic;
|
||||
case 1:
|
||||
return EnteredCertificateChecks.strict;
|
||||
case 2:
|
||||
return EnteredCertificateChecks.acceptInvalidCertificates;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid certificate position: " + position);
|
||||
}
|
||||
|
||||
public enum SocketSecurity {
|
||||
// Unspecified socket security, select automatically.
|
||||
automatic,
|
||||
|
||||
// TLS connection.
|
||||
ssl,
|
||||
|
||||
// STARTTLS connection.
|
||||
starttls,
|
||||
|
||||
// No TLS, plaintext connection.
|
||||
plain,
|
||||
}
|
||||
|
||||
public static SocketSecurity socketSecurityFromInt(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return SocketSecurity.automatic;
|
||||
case 1:
|
||||
return SocketSecurity.ssl;
|
||||
case 2:
|
||||
return SocketSecurity.starttls;
|
||||
case 3:
|
||||
return SocketSecurity.plain;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid socketSecurity position: " + position);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
public class HttpResponse {
|
||||
// base64-encoded response body.
|
||||
private final String blob;
|
||||
// MIME type, e.g. "text/plain" or "text/html".
|
||||
private final String mimetype;
|
||||
// Encoding, e.g. "utf-8".
|
||||
private final String encoding;
|
||||
|
||||
public HttpResponse(String blob, String mimetype, String encoding) {
|
||||
this.blob = blob;
|
||||
this.mimetype = mimetype;
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public byte[] getBlob() {
|
||||
if (blob == null) {
|
||||
return null;
|
||||
}
|
||||
return Base64.decode(blob, Base64.NO_WRAP | Base64.NO_PADDING);
|
||||
}
|
||||
|
||||
public String getMimetype() {
|
||||
return mimetype;
|
||||
}
|
||||
|
||||
public String getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class Reaction {
|
||||
// The reaction emoji string.
|
||||
private final String emoji;
|
||||
// The count of users that have reacted with this reaction.
|
||||
private final int count;
|
||||
// true if self-account reacted with this reaction, false otherwise.
|
||||
private final boolean isFromSelf;
|
||||
|
||||
public Reaction(String emoji, int count, boolean isFromSelf) {
|
||||
this.emoji = emoji;
|
||||
this.count = count;
|
||||
this.isFromSelf = isFromSelf;
|
||||
}
|
||||
|
||||
public String getEmoji() {
|
||||
return emoji;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public boolean isFromSelf() {
|
||||
return isFromSelf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof Reaction) {
|
||||
Reaction reaction = (Reaction) obj;
|
||||
return emoji.equals(reaction.getEmoji()) && count == reaction.getCount() && isFromSelf == reaction.isFromSelf();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Reactions {
|
||||
// Map from a contact to it's reaction to message.
|
||||
private final HashMap<Integer, String[]> reactionsByContact;
|
||||
// Unique reactions, sorted in descending order.
|
||||
private final ArrayList<Reaction> reactions;
|
||||
|
||||
public Reactions(HashMap<Integer, String[]> reactionsByContact, ArrayList<Reaction> reactions) {
|
||||
this.reactionsByContact = reactionsByContact;
|
||||
this.reactions = reactions;
|
||||
}
|
||||
|
||||
public Map<Integer, String[]> getReactionsByContact() {
|
||||
return reactionsByContact;
|
||||
}
|
||||
|
||||
public List<Reaction> getReactions() {
|
||||
return reactions;
|
||||
}
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.b44t.messenger.DcJsonrpcInstance;
|
||||
import com.b44t.messenger.util.concurrent.SettableFuture;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class Rpc {
|
||||
private final static String TAG = Rpc.class.getSimpleName();
|
||||
|
||||
private final Map<Integer, SettableFuture<JsonElement>> requestFutures = new ConcurrentHashMap<>();
|
||||
private final DcJsonrpcInstance dcJsonrpcInstance;
|
||||
private int requestId = 0;
|
||||
private boolean started = false;
|
||||
private final Gson gson = new GsonBuilder().serializeNulls().create();
|
||||
|
||||
public Rpc(DcJsonrpcInstance dcJsonrpcInstance) {
|
||||
this.dcJsonrpcInstance = dcJsonrpcInstance;
|
||||
}
|
||||
|
||||
private void processResponse() throws JsonSyntaxException {
|
||||
String jsonResponse = dcJsonrpcInstance.getNextResponse();
|
||||
|
||||
Response response = gson.fromJson(jsonResponse, Response.class);
|
||||
if (response == null) {
|
||||
Log.e(TAG, "Error parsing JSON: " + jsonResponse);
|
||||
return;
|
||||
} else if (response.id == 0) {
|
||||
// Got JSON-RPC notification/event, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
SettableFuture<JsonElement> future = requestFutures.remove(response.id);
|
||||
if (future == null) { // Got a response with unknown ID, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.error != null) {
|
||||
String message;
|
||||
try {
|
||||
message = response.error.getAsJsonObject().get("message").getAsString();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can't get response error message: " + e);
|
||||
message = response.error.toString();
|
||||
}
|
||||
future.setException(new RpcException(message));
|
||||
} else if (response.result != null) {
|
||||
future.set(response.result);
|
||||
} else {
|
||||
future.setException(new RpcException("Got JSON-RPC response without result or error: " + jsonResponse));
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
started = true;
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
processResponse();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "jsonrpcThread").start();
|
||||
}
|
||||
|
||||
public SettableFuture<JsonElement> call(String method, Object... params) throws RpcException {
|
||||
if (!started) throw new RpcException("RPC not started yet.");
|
||||
|
||||
int id;
|
||||
synchronized (this) {
|
||||
id = ++requestId;
|
||||
}
|
||||
String jsonRequest = gson.toJson(new Request(method, params, id));
|
||||
SettableFuture<JsonElement> future = new SettableFuture<>();
|
||||
requestFutures.put(id, future);
|
||||
dcJsonrpcInstance.request(jsonRequest);
|
||||
return future;
|
||||
}
|
||||
|
||||
public JsonElement getResult(String method, Object... params) throws RpcException {
|
||||
try {
|
||||
return call(method, params).get();
|
||||
} catch (ExecutionException e) {
|
||||
throw (RpcException)e.getCause();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RpcException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public List<VcardContact> parseVcard(String path) throws RpcException {
|
||||
TypeToken<List<VcardContact>> listType = new TypeToken<List<VcardContact>>(){};
|
||||
return gson.fromJson(getResult("parse_vcard", path), listType.getType());
|
||||
}
|
||||
|
||||
public String makeVcard(int accountId, int... contacts) throws RpcException {
|
||||
return gson.fromJson(getResult("make_vcard", accountId, contacts), String.class);
|
||||
}
|
||||
|
||||
public List<Integer> importVcard(int accountId, String path) throws RpcException {
|
||||
TypeToken<List<Integer>> listType = new TypeToken<List<Integer>>(){};
|
||||
return gson.fromJson(getResult("import_vcard", accountId, path), listType.getType());
|
||||
}
|
||||
|
||||
public HttpResponse getHttpResponse(int accountId, String url) throws RpcException {
|
||||
return gson.fromJson(getResult("get_http_response", accountId, url), HttpResponse.class);
|
||||
}
|
||||
|
||||
public Reactions getMsgReactions(int accountId, int msgId) throws RpcException {
|
||||
return gson.fromJson(getResult("get_message_reactions", accountId, msgId), Reactions.class);
|
||||
}
|
||||
|
||||
public int sendReaction(int accountId, int msgId, String... reaction) throws RpcException {
|
||||
return getResult("send_reaction", accountId, msgId, reaction).getAsInt();
|
||||
}
|
||||
|
||||
public int draftSelfReport(int accountId) throws RpcException {
|
||||
return getResult("draft_self_report", accountId).getAsInt();
|
||||
}
|
||||
|
||||
public void sendWebxdcRealtimeData(Integer accountId, Integer instanceMsgId, List<Integer> data) throws RpcException {
|
||||
getResult("send_webxdc_realtime_data", accountId, instanceMsgId, data);
|
||||
}
|
||||
|
||||
public void sendWebxdcRealtimeAdvertisement(Integer accountId, Integer instanceMsgId) throws RpcException {
|
||||
getResult("send_webxdc_realtime_advertisement", accountId, instanceMsgId);
|
||||
}
|
||||
|
||||
public void leaveWebxdcRealtime(Integer accountId, Integer instanceMessageId) throws RpcException {
|
||||
getResult("leave_webxdc_realtime", accountId, instanceMessageId);
|
||||
}
|
||||
|
||||
public int getAccountFileSize(int accountId) throws RpcException {
|
||||
return getResult("get_account_file_size", accountId).getAsInt();
|
||||
}
|
||||
|
||||
public void changeContactName(int accountId, int contactId, String name) throws RpcException {
|
||||
getResult("change_contact_name", accountId, contactId, name);
|
||||
}
|
||||
|
||||
public int addAccount() throws RpcException {
|
||||
return getResult("add_account").getAsInt();
|
||||
}
|
||||
|
||||
public void addTransportFromQr(int accountId, String qrCode) throws RpcException {
|
||||
getResult("add_transport_from_qr", accountId, qrCode);
|
||||
}
|
||||
|
||||
public void addOrUpdateTransport(int accountId, EnteredLoginParam param) throws RpcException {
|
||||
getResult("add_or_update_transport", accountId, param);
|
||||
}
|
||||
|
||||
public int createBroadcast(int accountId, String chatName) throws RpcException {
|
||||
return gson.fromJson(getResult("create_broadcast", accountId, chatName), Integer.class);
|
||||
}
|
||||
|
||||
public int createGroupChatUnencrypted(int accountId, String chatName) throws RpcException {
|
||||
return gson.fromJson(getResult("create_group_chat_unencrypted", accountId, chatName), Integer.class);
|
||||
}
|
||||
|
||||
public void setAccountsOrder(List<Integer> order) throws RpcException {
|
||||
getResult("set_accounts_order", order);
|
||||
}
|
||||
|
||||
private static class Request {
|
||||
private final String jsonrpc = "2.0";
|
||||
public final String method;
|
||||
public final Object[] params;
|
||||
public final int id;
|
||||
|
||||
public Request(String method, Object[] params, int id) {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
public String getMigrationError(int accountId) throws RpcException {
|
||||
return gson.fromJson(getResult("get_migration_error", accountId), String.class);
|
||||
}
|
||||
|
||||
private static class Response {
|
||||
public final int id;
|
||||
public final JsonElement result;
|
||||
public final JsonElement error;
|
||||
|
||||
public Response(int id, JsonElement result, JsonElement error) {
|
||||
this.id = id;
|
||||
this.result = result;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
/**
|
||||
* An exception occurred while processing a request in Delta Chat core.
|
||||
**/
|
||||
public class RpcException extends Exception {
|
||||
|
||||
public RpcException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package com.b44t.messenger.rpc;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
public class VcardContact {
|
||||
// Email address.
|
||||
private final String addr;
|
||||
|
||||
// The contact's name, or the email address if no name was given.
|
||||
private final String displayName;
|
||||
|
||||
// Public PGP key in Base64.
|
||||
private final String key;
|
||||
|
||||
// Profile image in Base64.
|
||||
private final String profileImage;
|
||||
|
||||
// Contact color in HTML color format.
|
||||
private final String color;
|
||||
|
||||
// Last update timestamp.
|
||||
private final int timestamp;
|
||||
|
||||
public VcardContact(String addr, String displayName, String key, String profileImage, String color, int timestamp) {
|
||||
this.addr = addr;
|
||||
this.displayName = displayName;
|
||||
this.key = key;
|
||||
this.profileImage = profileImage;
|
||||
this.color = color;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getAddr() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public byte[] getKey() {
|
||||
return key == null? null : Base64.decode(key, Base64.NO_WRAP | Base64.NO_PADDING);
|
||||
}
|
||||
|
||||
public boolean hasProfileImage() {
|
||||
return profileImage != null;
|
||||
}
|
||||
|
||||
public byte[] getProfileImage() {
|
||||
return profileImage == null? null : Base64.decode(profileImage, Base64.NO_WRAP | Base64.NO_PADDING);
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public int getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
|
@ -25,8 +25,7 @@ import com.b44t.messenger.DcAccounts;
|
|||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcEventEmitter;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.FFITransport;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
|
@ -51,6 +50,9 @@ import org.thoughtcrime.securesms.util.Util;
|
|||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class ApplicationContext extends MultiDexApplication {
|
||||
private static final String TAG = ApplicationContext.class.getSimpleName();
|
||||
|
||||
|
@ -87,8 +89,7 @@ public class ApplicationContext extends MultiDexApplication {
|
|||
System.loadLibrary("native-utils");
|
||||
|
||||
dcAccounts = new DcAccounts(new File(getFilesDir(), "accounts").getAbsolutePath());
|
||||
rpc = new Rpc(dcAccounts.getJsonrpcInstance());
|
||||
rpc.start();
|
||||
rpc = new Rpc(new FFITransport(dcAccounts.getJsonrpcInstance()));
|
||||
AccountManager.getInstance().migrateToDcAccounts(this);
|
||||
int[] allAccounts = dcAccounts.getAll();
|
||||
for (int accountId : allAccounts) {
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
@ -22,6 +21,8 @@ import org.thoughtcrime.securesms.util.Util;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
|
||||
public abstract class BaseConversationItem extends LinearLayout
|
||||
implements BindableConversationItem
|
||||
{
|
||||
|
|
|
@ -71,8 +71,6 @@ import com.b44t.messenger.DcContact;
|
|||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.util.concurrent.ListenableFuture;
|
||||
import com.b44t.messenger.util.concurrent.SettableFuture;
|
||||
|
||||
|
@ -123,9 +121,13 @@ import org.thoughtcrime.securesms.videochat.VideochatUtil;
|
|||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
/**
|
||||
* Activity for displaying a message thread, as well as
|
||||
* composing/sending a new message into that thread.
|
||||
|
@ -1005,7 +1007,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
try {
|
||||
byte[] vcard = rpc.makeVcard(dcContext.getAccountId(), contactId).getBytes();
|
||||
byte[] vcard = rpc.makeVcard(dcContext.getAccountId(), Collections.singletonList(contactId)).getBytes();
|
||||
String mimeType = "application/octet-stream";
|
||||
setMedia(PersistentBlobProvider.getInstance().create(this, vcard, mimeType, "vcard.vcf"), MediaType.DOCUMENT);
|
||||
} catch (RpcException e) {
|
||||
|
|
|
@ -40,9 +40,6 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Reactions;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.rpc.VcardContact;
|
||||
|
||||
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
|
||||
import org.thoughtcrime.securesms.components.AudioView;
|
||||
|
@ -76,6 +73,10 @@ import org.thoughtcrime.securesms.util.views.Stub;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.Reactions;
|
||||
import chat.delta.rpc.types.VcardContact;
|
||||
|
||||
/**
|
||||
* A view that displays an individual conversation item within a conversation
|
||||
* thread. Used by ComposeMessageActivity's ListActivity via a ConversationAdapter.
|
||||
|
@ -756,11 +757,11 @@ public class ConversationItem extends BaseConversationItem
|
|||
|
||||
private void setReactions(@NonNull DcMsg current) {
|
||||
try {
|
||||
Reactions reactions = rpc.getMsgReactions(dcContext.getAccountId(), current.getId());
|
||||
Reactions reactions = rpc.getMessageReactions(dcContext.getAccountId(), current.getId());
|
||||
if (reactions == null) {
|
||||
reactionsView.clear();
|
||||
} else {
|
||||
reactionsView.setReactions(reactions.getReactions());
|
||||
reactionsView.setReactions(reactions.reactions);
|
||||
reactionsView.setOnClickListener(view -> {
|
||||
if (eventListener != null && batchSelected.isEmpty()) {
|
||||
eventListener.onReactionClicked(current);
|
||||
|
@ -895,7 +896,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
String path = slide.asAttachment().getRealPath(context);
|
||||
VcardContact vcardContact = rpc.parseVcard(path).get(0);
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.ask_start_chat_with, vcardContact.getDisplayName()))
|
||||
.setMessage(context.getString(R.string.ask_start_chat_with, vcardContact.displayName))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
try {
|
||||
List<Integer> contactIds = rpc.importVcard(dcContext.getAccountId(), path);
|
||||
|
|
|
@ -9,17 +9,19 @@ import android.webkit.WebSettings;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.rpc.HttpResponse;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.types.HttpResponse;
|
||||
|
||||
public class FullMsgActivity extends WebViewActivity
|
||||
{
|
||||
public static final String MSG_ID_EXTRA = "msg_id";
|
||||
|
@ -187,11 +189,12 @@ public class FullMsgActivity extends WebViewActivity
|
|||
throw new Exception("no url specified");
|
||||
}
|
||||
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
|
||||
String mimeType = httpResponse.getMimetype();
|
||||
String mimeType = httpResponse.mimetype;
|
||||
if (mimeType == null) {
|
||||
mimeType = "application/octet-stream";
|
||||
}
|
||||
res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), new ByteArrayInputStream(httpResponse.getBlob()));
|
||||
byte[] blob = JsonUtils.decodeBase64(httpResponse.blob);
|
||||
res = new WebResourceResponse(mimeType, httpResponse.encoding, new ByteArrayInputStream(blob));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
res = new WebResourceResponse("text/plain", "UTF-8", new ByteArrayInputStream(("Error: " + e.getMessage()).getBytes()));
|
||||
|
|
|
@ -23,7 +23,6 @@ import androidx.loader.app.LoaderManager;
|
|||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
@ -44,6 +43,8 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ItemClickListener
|
||||
{
|
||||
|
|
|
@ -32,8 +32,6 @@ import androidx.loader.app.LoaderManager;
|
|||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcLot;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
@ -62,6 +60,9 @@ import java.io.IOException;
|
|||
import java.security.SecureRandom;
|
||||
import java.util.Objects;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class InstantOnboardingActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate {
|
||||
|
||||
private static final String TAG = InstantOnboardingActivity.class.getSimpleName();
|
||||
|
|
|
@ -23,8 +23,6 @@ import com.b44t.messenger.DcChat;
|
|||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
|
@ -36,6 +34,9 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class ProfileActivity extends PassphraseRequiredActionBarActivity
|
||||
implements DcEventCenter.DcEventDelegate
|
||||
{
|
||||
|
|
|
@ -46,9 +46,6 @@ import androidx.constraintlayout.widget.Group;
|
|||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcProvider;
|
||||
import com.b44t.messenger.rpc.EnteredLoginParam;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.util.concurrent.ListenableFuture;
|
||||
import com.b44t.messenger.util.concurrent.SettableFuture;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
@ -66,6 +63,12 @@ import org.thoughtcrime.securesms.util.views.ProgressDialog;
|
|||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
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 {
|
||||
|
||||
private enum VerificationType {
|
||||
|
@ -589,24 +592,49 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
|
|||
&& !passwordInput.getText().toString().isEmpty();
|
||||
}
|
||||
|
||||
private EnteredCertificateChecks certificateChecksFromInt(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return EnteredCertificateChecks.automatic;
|
||||
case 1:
|
||||
return EnteredCertificateChecks.strict;
|
||||
case 2:
|
||||
return EnteredCertificateChecks.acceptInvalidCertificates;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid certificate position: " + position);
|
||||
}
|
||||
|
||||
public static Socket socketSecurityFromInt(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return Socket.automatic;
|
||||
case 1:
|
||||
return Socket.ssl;
|
||||
case 2:
|
||||
return Socket.starttls;
|
||||
case 3:
|
||||
return Socket.plain;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid socketSecurity position: " + position);
|
||||
}
|
||||
|
||||
private void setupConfig() {
|
||||
DcHelper.getEventCenter(this).captureNextError();
|
||||
|
||||
EnteredLoginParam param = new EnteredLoginParam(
|
||||
getParam(R.id.email_text, true),
|
||||
getParam(R.id.password_text, false),
|
||||
getParam(R.id.imap_server_text, true),
|
||||
Util.objectToInt(getParam(R.id.imap_port_text, true)),
|
||||
EnteredLoginParam.socketSecurityFromInt(imapSecurity.getSelectedItemPosition()),
|
||||
getParam(R.id.imap_login_text, false),
|
||||
getParam(R.id.smtp_server_text, true),
|
||||
Util.objectToInt(getParam(R.id.smtp_port_text, true)),
|
||||
EnteredLoginParam.socketSecurityFromInt(smtpSecurity.getSelectedItemPosition()),
|
||||
getParam(R.id.smtp_login_text, false),
|
||||
getParam(R.id.smtp_password_text, false),
|
||||
EnteredLoginParam.certificateChecksFromInt(certCheck.getSelectedItemPosition()),
|
||||
authMethod.getSelectedItemPosition() == 1
|
||||
);
|
||||
EnteredLoginParam param = new EnteredLoginParam();
|
||||
param.addr = getParam(R.id.email_text, true);
|
||||
param.password = getParam(R.id.password_text, false);
|
||||
param.imapServer = getParam(R.id.imap_server_text, true);
|
||||
param.imapPort = Util.objectToInt(getParam(R.id.imap_port_text, true));
|
||||
param.imapSecurity = socketSecurityFromInt(imapSecurity.getSelectedItemPosition());
|
||||
param.imapUser = getParam(R.id.imap_login_text, false);
|
||||
param.smtpServer = getParam(R.id.smtp_server_text, true);
|
||||
param.smtpPort = Util.objectToInt(getParam(R.id.smtp_port_text, true));
|
||||
param.smtpSecurity = socketSecurityFromInt(smtpSecurity.getSelectedItemPosition());
|
||||
param.smtpUser = getParam(R.id.smtp_login_text, false);
|
||||
param.smtpPassword = getParam(R.id.smtp_password_text, false);
|
||||
param.certificateChecks = certificateChecksFromInt(certCheck.getSelectedItemPosition());
|
||||
param.oauth2 = authMethod.getSelectedItemPosition() == 1;
|
||||
|
||||
new Thread(() -> {
|
||||
Rpc rpc = DcHelper.getRpc(this);
|
||||
|
|
|
@ -37,8 +37,6 @@ import com.b44t.messenger.DcChat;
|
|||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
@ -62,6 +60,9 @@ import java.util.HashMap;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = WebxdcActivity.class.getSimpleName();
|
||||
private static final String EXTRA_ACCOUNT_ID = "accountId";
|
||||
|
|
|
@ -17,13 +17,11 @@ import android.widget.Toast;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.rpc.HttpResponse;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
@ -31,6 +29,10 @@ import org.thoughtcrime.securesms.util.Util;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.HttpResponse;
|
||||
|
||||
public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
|
||||
private static final String TAG = WebxdcStoreActivity.class.getSimpleName();
|
||||
|
||||
|
@ -59,7 +61,8 @@ public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
|
|||
Util.runOnAnyBackgroundThread(() -> {
|
||||
try {
|
||||
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
|
||||
Uri uri = PersistentBlobProvider.getInstance().create(WebxdcStoreActivity.this, httpResponse.getBlob(), "application/octet-stream", "app.xdc");
|
||||
byte[] blob = JsonUtils.decodeBase64(httpResponse.blob);
|
||||
Uri uri = PersistentBlobProvider.getInstance().create(WebxdcStoreActivity.this, blob, "application/octet-stream", "app.xdc");
|
||||
Intent intent = new Intent();
|
||||
intent.setData(uri);
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
|
@ -108,13 +111,14 @@ public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
|
|||
throw new Exception("no url specified");
|
||||
}
|
||||
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
|
||||
String mimeType = httpResponse.getMimetype();
|
||||
String mimeType = httpResponse.mimetype;
|
||||
if (mimeType == null) {
|
||||
mimeType = "application/octet-stream";
|
||||
}
|
||||
|
||||
ByteArrayInputStream data = new ByteArrayInputStream(httpResponse.getBlob());
|
||||
res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), data);
|
||||
byte[] blob = JsonUtils.decodeBase64(httpResponse.blob);
|
||||
ByteArrayInputStream data = new ByteArrayInputStream(blob);
|
||||
res = new WebResourceResponse(mimeType, httpResponse.encoding, data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ByteArrayInputStream data = new ByteArrayInputStream(("Could not load apps. Are you online?\n\n" + e.getMessage()).getBytes());
|
||||
|
|
|
@ -26,8 +26,6 @@ import com.b44t.messenger.DcAccounts;
|
|||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.ConnectivityActivity;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
|
@ -43,6 +41,9 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class AccountSelectionListFragment extends DialogFragment implements DcEventCenter.DcEventDelegate
|
||||
{
|
||||
private static final String TAG = AccountSelectionListFragment.class.getSimpleName();
|
||||
|
|
|
@ -18,8 +18,6 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.rpc.VcardContact;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
@ -38,6 +36,9 @@ import org.thoughtcrime.securesms.util.Util;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.VcardContact;
|
||||
|
||||
public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
|
||||
private static final String TAG = QuoteView.class.getSimpleName();
|
||||
|
|
|
@ -9,16 +9,16 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.rpc.VcardContact;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.VcardSlide;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.VcardContact;
|
||||
|
||||
public class VcardView extends FrameLayout {
|
||||
private static final String TAG = VcardView.class.getSimpleName();
|
||||
|
||||
|
@ -60,8 +60,8 @@ public class VcardView extends FrameLayout {
|
|||
public void setVcard(@NonNull GlideRequests glideRequests, final @NonNull VcardSlide slide, final @NonNull Rpc rpc) {
|
||||
try {
|
||||
VcardContact vcardContact = rpc.parseVcard(slide.asAttachment().getRealPath(getContext())).get(0);
|
||||
name.setText(vcardContact.getDisplayName());
|
||||
address.setText(vcardContact.getAddr());
|
||||
name.setText(vcardContact.displayName);
|
||||
address.setText(vcardContact.addr);
|
||||
avatar.setAvatar(glideRequests, new Recipient(getContext(), vcardContact), false);
|
||||
this.slide = slide;
|
||||
} catch (RpcException e) {
|
||||
|
|
|
@ -13,8 +13,6 @@ import androidx.preference.PreferenceManager;
|
|||
|
||||
import com.b44t.messenger.DcAccounts;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
|
@ -24,6 +22,9 @@ import org.thoughtcrime.securesms.accounts.AccountSelectionListFragment;
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class AccountManager {
|
||||
|
||||
private static final String TAG = AccountManager.class.getSimpleName();
|
||||
|
|
|
@ -22,8 +22,6 @@ import com.b44t.messenger.DcChat;
|
|||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcLot;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
|
@ -43,6 +41,9 @@ import java.io.File;
|
|||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class DcHelper {
|
||||
|
||||
private static final String TAG = DcHelper.class.getSimpleName();
|
||||
|
|
|
@ -6,7 +6,7 @@ import android.net.Uri;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.b44t.messenger.rpc.VcardContact;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -14,6 +14,8 @@ import java.io.InputStream;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import chat.delta.rpc.types.VcardContact;
|
||||
|
||||
public class VcardContactPhoto implements ContactPhoto {
|
||||
private final VcardContact vContact;
|
||||
|
||||
|
@ -23,7 +25,7 @@ public class VcardContactPhoto implements ContactPhoto {
|
|||
|
||||
@Override
|
||||
public InputStream openInputStream(Context context) throws IOException {
|
||||
byte[] blob = vContact.getProfileImage();
|
||||
byte[] blob = JsonUtils.decodeBase64(vContact.profileImage);
|
||||
return (blob == null)? null : new ByteArrayInputStream(blob);
|
||||
}
|
||||
|
||||
|
@ -39,7 +41,7 @@ public class VcardContactPhoto implements ContactPhoto {
|
|||
|
||||
@Override
|
||||
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
||||
messageDigest.update(vContact.getAddr().getBytes());
|
||||
messageDigest.update(ByteBuffer.allocate(4).putFloat(vContact.getTimestamp()).array());
|
||||
messageDigest.update(vContact.addr.getBytes());
|
||||
messageDigest.update(ByteBuffer.allocate(4).putFloat(vContact.timestamp).array());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import androidx.appcompat.app.AlertDialog;
|
|||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.b44t.messenger.util.concurrent.ListenableFuture;
|
||||
import com.b44t.messenger.util.concurrent.ListenableFuture.Listener;
|
||||
import com.b44t.messenger.util.concurrent.SettableFuture;
|
||||
|
@ -78,6 +77,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
|
||||
public class AttachmentManager {
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@ import androidx.preference.CheckBoxPreference;
|
|||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.LogViewActivity;
|
||||
|
@ -51,6 +49,8 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
|
||||
public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
|
||||
implements DcEventCenter.DcEventDelegate
|
||||
|
|
|
@ -13,16 +13,19 @@ import androidx.emoji2.emojipicker.EmojiPickerView;
|
|||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Reactions;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.Reactions;
|
||||
|
||||
public class AddReactionView extends LinearLayout {
|
||||
private AppCompatTextView[] defaultReactionViews;
|
||||
private AppCompatTextView anyReactionView;
|
||||
|
@ -123,12 +126,12 @@ public class AddReactionView extends LinearLayout {
|
|||
private String getSelfReaction() {
|
||||
String result = null;
|
||||
try {
|
||||
final Reactions reactions = rpc.getMsgReactions(dcContext.getAccountId(), msgToReactTo.getId());
|
||||
final Reactions reactions = rpc.getMessageReactions(dcContext.getAccountId(), msgToReactTo.getId());
|
||||
if (reactions != null) {
|
||||
final Map<Integer, String[]> reactionsByContact = reactions.getReactionsByContact();
|
||||
final String [] selfReactions = reactionsByContact.get(DcContact.DC_CONTACT_ID_SELF);
|
||||
if (selfReactions != null && selfReactions.length > 0) {
|
||||
result = selfReactions[0];
|
||||
final Map<String, List<String>> reactionsByContact = reactions.reactionsByContact;
|
||||
final List<String> selfReactions = reactionsByContact.get(String.valueOf(DcContact.DC_CONTACT_ID_SELF));
|
||||
if (selfReactions != null && !selfReactions.isEmpty()) {
|
||||
result = selfReactions.get(0);
|
||||
}
|
||||
}
|
||||
} catch(RpcException e) {
|
||||
|
@ -175,9 +178,9 @@ public class AddReactionView extends LinearLayout {
|
|||
private void sendReaction(final String reaction) {
|
||||
try {
|
||||
if (reaction == null || reaction.equals(getSelfReaction())) {
|
||||
rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), "");
|
||||
rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), Collections.singletonList(""));
|
||||
} else {
|
||||
rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), reaction);
|
||||
rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), Collections.singletonList(reaction));
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -14,14 +14,14 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.b44t.messenger.rpc.Reaction;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import chat.delta.rpc.types.Reaction;
|
||||
|
||||
public class ReactionsConversationView extends LinearLayout {
|
||||
|
||||
// Normally 6dp, but we have 1dp left+right margin on the pills themselves
|
||||
|
@ -80,10 +80,14 @@ public class ReactionsConversationView extends LinearLayout {
|
|||
int count = 0;
|
||||
boolean isFromSelf = false;
|
||||
for (int index = 2; index < reactions.size(); index++) {
|
||||
count += reactions.get(index).getCount();
|
||||
isFromSelf = isFromSelf || reactions.get(index).isFromSelf();
|
||||
count += reactions.get(index).count;
|
||||
isFromSelf = isFromSelf || reactions.get(index).isFromSelf;
|
||||
}
|
||||
shortened.add(new Reaction(null, count, isFromSelf));
|
||||
Reaction reaction = new Reaction();
|
||||
reaction.emoji = null;
|
||||
reaction.count = count;
|
||||
reaction.isFromSelf = isFromSelf;
|
||||
shortened.add(reaction);
|
||||
|
||||
return shortened;
|
||||
} else {
|
||||
|
@ -97,11 +101,11 @@ public class ReactionsConversationView extends LinearLayout {
|
|||
TextView countView = root.findViewById(R.id.reactions_pill_count);
|
||||
View spacer = root.findViewById(R.id.reactions_pill_spacer);
|
||||
|
||||
if (reaction.getEmoji() != null) {
|
||||
emojiView.setText(reaction.getEmoji());
|
||||
if (reaction.emoji != null) {
|
||||
emojiView.setText(reaction.emoji);
|
||||
|
||||
if (reaction.getCount() > 1) {
|
||||
countView.setText(String.valueOf(reaction.getCount()));
|
||||
if (reaction.count > 1) {
|
||||
countView.setText(String.valueOf(reaction.count));
|
||||
} else {
|
||||
countView.setVisibility(GONE);
|
||||
spacer.setVisibility(GONE);
|
||||
|
@ -109,10 +113,10 @@ public class ReactionsConversationView extends LinearLayout {
|
|||
} else {
|
||||
emojiView.setVisibility(GONE);
|
||||
spacer.setVisibility(GONE);
|
||||
countView.setText("+" + reaction.getCount());
|
||||
countView.setText("+" + reaction.count);
|
||||
}
|
||||
|
||||
if (reaction.isFromSelf()) {
|
||||
if (reaction.isFromSelf) {
|
||||
root.setBackground(ContextCompat.getDrawable(context, R.drawable.reaction_pill_background_selected));
|
||||
countView.setTextColor(ContextCompat.getColor(context, R.color.reaction_pill_text_color_selected));
|
||||
} else {
|
||||
|
|
|
@ -16,9 +16,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.rpc.Reactions;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.ProfileActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
@ -29,8 +26,14 @@ import org.thoughtcrime.securesms.util.Pair;
|
|||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.Reactions;
|
||||
|
||||
public class ReactionsDetailsFragment extends DialogFragment implements DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = ReactionsDetailsFragment.class.getSimpleName();
|
||||
|
||||
|
@ -87,14 +90,14 @@ public class ReactionsDetailsFragment extends DialogFragment implements DcEventC
|
|||
|
||||
int accId = DcHelper.getContext(requireActivity()).getAccountId();
|
||||
try {
|
||||
final Reactions reactions = DcHelper.getRpc(requireActivity()).getMsgReactions(accId, msgId);
|
||||
final Reactions reactions = DcHelper.getRpc(requireActivity()).getMessageReactions(accId, msgId);
|
||||
ArrayList<Pair<Integer, String>> contactsReactions = new ArrayList<>();
|
||||
if (reactions != null) {
|
||||
Map<Integer, String[]> reactionsByContact = reactions.getReactionsByContact();
|
||||
String[] selfReactions = reactionsByContact.remove(DcContact.DC_CONTACT_ID_SELF);
|
||||
for (Integer contact: reactionsByContact.keySet()) {
|
||||
Map<String, List<String>> reactionsByContact = reactions.reactionsByContact;
|
||||
List<String> selfReactions = reactionsByContact.remove(String.valueOf(DcContact.DC_CONTACT_ID_SELF));
|
||||
for (String contact: reactionsByContact.keySet()) {
|
||||
for (String reaction: reactionsByContact.get(contact)) {
|
||||
contactsReactions.add(new Pair<>(contact, reaction));
|
||||
contactsReactions.add(new Pair<>(Integer.parseInt(contact), reaction));
|
||||
}
|
||||
}
|
||||
if (selfReactions != null) {
|
||||
|
@ -118,12 +121,12 @@ public class ReactionsDetailsFragment extends DialogFragment implements DcEventC
|
|||
private String getSelfReaction(Rpc rpc, int accId) {
|
||||
String result = null;
|
||||
try {
|
||||
final Reactions reactions = rpc.getMsgReactions(accId, msgId);
|
||||
final Reactions reactions = rpc.getMessageReactions(accId, msgId);
|
||||
if (reactions != null) {
|
||||
final Map<Integer, String[]> reactionsByContact = reactions.getReactionsByContact();
|
||||
final String [] selfReactions = reactionsByContact.get(DcContact.DC_CONTACT_ID_SELF);
|
||||
if (selfReactions != null && selfReactions.length > 0) {
|
||||
result = selfReactions[0];
|
||||
final Map<String, List<String>> reactionsByContact = reactions.reactionsByContact;
|
||||
final List<String> selfReactions = reactionsByContact.get(String.valueOf(DcContact.DC_CONTACT_ID_SELF));
|
||||
if (selfReactions != null && !selfReactions.isEmpty()) {
|
||||
result = selfReactions.get(0);
|
||||
}
|
||||
}
|
||||
} catch(RpcException e) {
|
||||
|
@ -139,9 +142,9 @@ public class ReactionsDetailsFragment extends DialogFragment implements DcEventC
|
|||
|
||||
try {
|
||||
if (reaction == null || reaction.equals(getSelfReaction(rpc, accId))) {
|
||||
rpc.sendReaction(accId, msgId, "");
|
||||
rpc.sendReaction(accId, msgId, Collections.singletonList(""));
|
||||
} else {
|
||||
rpc.sendReaction(accId, msgId, reaction);
|
||||
rpc.sendReaction(accId, msgId, Collections.singletonList(reaction));
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -29,7 +29,6 @@ import androidx.annotation.Nullable;
|
|||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.rpc.VcardContact;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
|
@ -50,6 +49,8 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import chat.delta.rpc.types.VcardContact;
|
||||
|
||||
public class Recipient {
|
||||
|
||||
private final Set<RecipientModifiedListener> listeners = Collections.newSetFromMap(new WeakHashMap<RecipientModifiedListener, Boolean>());
|
||||
|
@ -149,7 +150,7 @@ public class Recipient {
|
|||
return dcContact.getDisplayName();
|
||||
}
|
||||
else if(vContact!=null) {
|
||||
return vContact.getDisplayName();
|
||||
return vContact.displayName;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -199,7 +200,7 @@ public class Recipient {
|
|||
rgb = dcContact.getColor();
|
||||
}
|
||||
else if(vContact!=null) {
|
||||
rgb = Color.parseColor(vContact.getColor());
|
||||
rgb = Color.parseColor(vContact.color);
|
||||
}
|
||||
return Color.argb(0xFF, Color.red(rgb), Color.green(rgb), Color.blue(rgb));
|
||||
}
|
||||
|
@ -235,7 +236,7 @@ public class Recipient {
|
|||
}
|
||||
}
|
||||
|
||||
if (vContact!=null && vContact.hasProfileImage()) {
|
||||
if (vContact!=null && vContact.profileImage != null) {
|
||||
return new VcardContactPhoto(vContact);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
@ -21,6 +23,13 @@ public class JsonUtils {
|
|||
objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
|
||||
}
|
||||
|
||||
public static byte[] decodeBase64(String base64) {
|
||||
if (base64 == null) {
|
||||
return null;
|
||||
}
|
||||
return Base64.decode(base64, Base64.NO_WRAP | Base64.NO_PADDING);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(byte[] serialized, Class<T> clazz) throws IOException {
|
||||
return fromJson(new String(serialized), clazz);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue