jsonrpc: more methods and some fixes (#3653)

* jsonrpc: Implement join_securejoin(), contacts_delete(),
contacts_change_name(), send_sticker()

* Add missing fn

* cargo fmt

* add missing &self

* Make it compile

* fixup return type, clippy and doc comment

* generate types and add 2 functions

* change naming

* changelog entry

* jsonrpc add start and stop io functions

* fix getMessageListItems

* normalize daymarker timestamps for MessageListItem

* jsonrpc: exportBackup and importBackup

* don't multiply timestamp anymore

* update types.ts

Co-authored-by: Simon Laux <mobile.info@simonlaux.de>
This commit is contained in:
Jikstra
2022-10-13 12:56:10 +02:00
committed by GitHub
parent 6f329c9e96
commit 81d0ecd8f6
5 changed files with 221 additions and 15 deletions

View File

@@ -3,7 +3,7 @@
## Unreleased
### API-Changes
- jsonrpc: add function: #3641, #3645
- jsonrpc: add function: #3641, #3645, #3653
- `getChatContacts()`
- `createGroupChat()`
- `createBroadcastList()`
@@ -23,7 +23,17 @@
- `setStockStrings()`
- `exportSelfKeys()`
- `importSelfKeys()`
- breaking: jsonrpc: remove function `messageListGetMessageIds()`, it is replaced by `getMessageIds()` and `getMessageListEntries()` the latter returns a new `MessageListItem` type, which is the now prefered way of using the message list.
- `sendSticker()`
- `changeContactName()`
- `deleteContact()`
- `joinSecurejoin()`
- `stopIoForAllAccounts()`
- `startIoForAllAccounts()`
- `startIo()`
- `stopIo()`
- `exportBackup()`
- `importBackup()`
- breaking: jsonrpc: remove function `messageListGetMessageIds()`, it is replaced by `getMessageIds()` and `getMessageListItems()` the latter returns a new `MessageListItem` type, which is the now prefered way of using the message list.
- jsonrpc: add type: #3641, #3645
- `MessageSearchResult`
- `Location`

View File

@@ -140,10 +140,32 @@ impl CommandApi {
Ok(accounts)
}
async fn start_io_for_all_accounts(&self) -> Result<()> {
self.accounts.read().await.start_io().await;
Ok(())
}
async fn stop_io_for_all_accounts(&self) -> Result<()> {
self.accounts.read().await.stop_io().await;
Ok(())
}
// ---------------------------------------------
// Methods that work on individual accounts
// ---------------------------------------------
async fn start_io(&self, id: u32) -> Result<()> {
let ctx = self.get_context(id).await?;
ctx.start_io().await;
Ok(())
}
async fn stop_io(&self, id: u32) -> Result<()> {
let ctx = self.get_context(id).await?;
ctx.stop_io().await;
Ok(())
}
/// Get top-level info for an account.
async fn get_account_info(&self, account_id: u32) -> Result<Account> {
let context_option = self.accounts.read().await.get_account(account_id);
@@ -514,7 +536,7 @@ impl CommandApi {
///
/// 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 dc_join_securejoin()
/// 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;
@@ -524,7 +546,6 @@ impl CommandApi {
/// for details about both protocols.
///
/// return format: `[code, svg]`
// TODO fix doc comment after adding dc_join_securejoin
async fn get_chat_securejoin_qr_code_svg(
&self,
account_id: u32,
@@ -538,6 +559,33 @@ impl CommandApi {
))
}
/// 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://countermitm.readthedocs.io/en/latest/new.html
/// 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.
///
async fn secure_join(&self, account_id: u32, qr: String) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
let chat_id = securejoin::join_securejoin(&ctx, &qr).await?;
Ok(chat_id.to_u32())
}
async fn leave_group(&self, account_id: u32, chat_id: u32) -> Result<()> {
let ctx = self.get_context(account_id).await?;
remove_contact_from_chat(&ctx, ChatId::new(chat_id), ContactId::SELF).await
@@ -848,7 +896,7 @@ impl CommandApi {
.collect())
}
async fn get_message_list_entries(
async fn get_message_list_items(
&self,
account_id: u32,
chat_id: u32,
@@ -1103,6 +1151,28 @@ impl CommandApi {
Ok(contacts)
}
async fn delete_contact(&self, account_id: u32, contact_id: u32) -> Result<bool> {
let ctx = self.get_context(account_id).await?;
let contact_id = ContactId::new(contact_id);
Contact::delete(&ctx, contact_id).await?;
Ok(true)
}
async fn change_contact_name(
&self,
account_id: u32,
contact_id: u32,
name: String,
) -> Result<()> {
let ctx = self.get_context(account_id).await?;
let contact_id = ContactId::new(contact_id);
let contact = Contact::load_from_db(&ctx, contact_id).await?;
let addr = contact.get_addr();
Contact::create(&ctx, &name, addr).await?;
Ok(())
}
/// 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.
@@ -1210,6 +1280,45 @@ impl CommandApi {
Ok((prev, next))
}
// ---------------------------------------------
// backup
// ---------------------------------------------
async fn export_backup(
&self,
account_id: u32,
destination: String,
passphrase: Option<String>,
) -> Result<()> {
let ctx = self.get_context(account_id).await?;
ctx.stop_io().await;
let result = imex::imex(
&ctx,
imex::ImexMode::ExportBackup,
destination.as_ref(),
passphrase,
)
.await;
ctx.start_io().await;
result
}
async fn import_backup(
&self,
account_id: u32,
path: String,
passphrase: Option<String>,
) -> Result<()> {
let ctx = self.get_context(account_id).await?;
imex::imex(
&ctx,
imex::ImexMode::ImportBackup,
path.as_ref(),
passphrase,
)
.await
}
// ---------------------------------------------
// connectivity
// ---------------------------------------------
@@ -1337,6 +1446,21 @@ impl CommandApi {
forward_msgs(&ctx, &message_ids, ChatId::new(chat_id)).await
}
async fn send_sticker(
&self,
account_id: u32,
chat_id: u32,
sticker_path: String,
) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(&sticker_path, None);
let message_id = deltachat::chat::send_msg(&ctx, ChatId::new(chat_id), &mut msg).await?;
Ok(message_id.to_u32())
}
// ---------------------------------------------
// functions for the composer
// the composer is the message input field

View File

@@ -388,7 +388,7 @@ impl MessageSearchResult {
}
#[derive(Serialize, TypeDef)]
#[serde(rename_all = "camelCase", rename = "MessageListItem")]
#[serde(rename_all = "camelCase", rename = "MessageListItem", tag = "kind")]
pub enum JSONRPCMessageListItem {
Message {
msg_id: u32,
@@ -397,7 +397,7 @@ pub enum JSONRPCMessageListItem {
/// Day marker, separating messages that correspond to different
/// days according to local time.
DayMarker {
/// Marker timestamp, for day markers
/// Marker timestamp, for day markers, in unix milliseconds
timestamp: i64,
},
}

View File

@@ -66,6 +66,26 @@ export class RawClient {
return (this._transport.request('get_all_accounts', [] as RPC.Params)) as Promise<(T.Account)[]>;
}
public startIoForAllAccounts(): Promise<null> {
return (this._transport.request('start_io_for_all_accounts', [] as RPC.Params)) as Promise<null>;
}
public stopIoForAllAccounts(): Promise<null> {
return (this._transport.request('stop_io_for_all_accounts', [] as RPC.Params)) as Promise<null>;
}
public startIo(id: T.U32): Promise<null> {
return (this._transport.request('start_io', [id] as RPC.Params)) as Promise<null>;
}
public stopIo(id: T.U32): Promise<null> {
return (this._transport.request('stop_io', [id] as RPC.Params)) as Promise<null>;
}
/**
* Get top-level info for an account.
*/
@@ -296,7 +316,7 @@ export class RawClient {
*
* 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 dc_join_securejoin()
* 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;
@@ -311,6 +331,33 @@ export class RawClient {
return (this._transport.request('get_chat_securejoin_qr_code_svg', [accountId, chatId] as RPC.Params)) as Promise<[string,string]>;
}
/**
* 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://countermitm.readthedocs.io/en/latest/new.html
* 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 secureJoin(accountId: T.U32, qr: string): Promise<T.U32> {
return (this._transport.request('secure_join', [accountId, qr] as RPC.Params)) as Promise<T.U32>;
}
public leaveGroup(accountId: T.U32, chatId: T.U32): Promise<null> {
return (this._transport.request('leave_group', [accountId, chatId] as RPC.Params)) as Promise<null>;
@@ -541,8 +588,8 @@ export class RawClient {
}
public getMessageListEntries(accountId: T.U32, chatId: T.U32, flags: T.U32): Promise<(T.MessageListItem)[]> {
return (this._transport.request('get_message_list_entries', [accountId, chatId, flags] as RPC.Params)) as Promise<(T.MessageListItem)[]>;
public getMessageListItems(accountId: T.U32, chatId: T.U32, flags: T.U32): Promise<(T.MessageListItem)[]> {
return (this._transport.request('get_message_list_items', [accountId, chatId, flags] as RPC.Params)) as Promise<(T.MessageListItem)[]>;
}
@@ -677,6 +724,16 @@ export class RawClient {
return (this._transport.request('contacts_get_contacts_by_ids', [accountId, ids] as RPC.Params)) as Promise<Record<T.U32,T.Contact>>;
}
public deleteContact(accountId: T.U32, contactId: T.U32): Promise<boolean> {
return (this._transport.request('delete_contact', [accountId, contactId] as RPC.Params)) as Promise<boolean>;
}
public changeContactName(accountId: T.U32, contactId: T.U32, name: string): Promise<null> {
return (this._transport.request('change_contact_name', [accountId, contactId, name] as RPC.Params)) as Promise<null>;
}
/**
* Get encryption info for a contact.
* Get a multi-line encryption info, containing your fingerprint and the
@@ -724,6 +781,16 @@ export class RawClient {
return (this._transport.request('chat_get_neighboring_media', [accountId, msgId, messageType, orMessageType2, orMessageType3] as RPC.Params)) as Promise<[(T.U32|null),(T.U32|null)]>;
}
public exportBackup(accountId: T.U32, destination: string, passphrase: (string|null)): Promise<null> {
return (this._transport.request('export_backup', [accountId, destination, passphrase] as RPC.Params)) as Promise<null>;
}
public importBackup(accountId: T.U32, path: string, passphrase: (string|null)): Promise<null> {
return (this._transport.request('import_backup', [accountId, path, passphrase] as RPC.Params)) as Promise<null>;
}
/**
* Indicate that the network likely has come back.
* or just that the network conditions might have changed
@@ -802,6 +869,11 @@ export class RawClient {
}
public sendSticker(accountId: T.U32, chatId: T.U32, stickerPath: string): Promise<T.U32> {
return (this._transport.request('send_sticker', [accountId, chatId, stickerPath] as RPC.Params)) as Promise<T.U32>;
}
public removeDraft(accountId: T.U32, chatId: T.U32): Promise<null> {
return (this._transport.request('remove_draft', [accountId, chatId] as RPC.Params)) as Promise<null>;
}

View File

@@ -52,16 +52,16 @@ export type BasicChat=
{"id":U32;"name":string;"isProtected":boolean;"profileImage":(string|null);"archived":boolean;"chatType":U32;"isUnpromoted":boolean;"isSelfTalk":boolean;"color":string;"isContactRequest":boolean;"isDeviceChat":boolean;"isMuted":boolean;};
export type ChatVisibility=("Normal"|"Archived"|"Pinned");
export type MuteDuration=("NotMuted"|"Forever"|{"Until":I64;});
export type MessageListItem=({"message":{"msg_id":U32;};}|{
export type MessageListItem=(({"kind":"message";}&{"msg_id":U32;})|({
/**
* Day marker, separating messages that correspond to different
* days according to local time.
*/
"dayMarker":{
"kind":"dayMarker";}&{
/**
* Marker timestamp, for day markers
* Marker timestamp, for day markers, in unix milliseconds
*/
"timestamp":I64;};});
"timestamp":I64;}));
export type MessageQuote=(({"kind":"JustText";}&{"text":string;})|({"kind":"WithMessage";}&{"text":string;"messageId":U32;"authorDisplayName":string;"authorDisplayColor":string;"overrideSenderName":(string|null);"image":(string|null);"isForwarded":boolean;}));
export type Viewtype=("Unknown"|
/**
@@ -160,4 +160,4 @@ export type MessageNotificationInfo={"id":U32;"chatId":U32;"accountId":U32;"imag
export type MessageSearchResult={"id":U32;"authorProfileImage":(string|null);"authorName":string;"authorColor":string;"chatName":(string|null);"message":string;"timestamp":I64;};
export type F64=number;
export type Location={"locationId":U32;"isIndependent":boolean;"latitude":F64;"longitude":F64;"accuracy":F64;"timestamp":I64;"contactId":U32;"msgId":U32;"chatId":U32;"marker":(string|null);};
export type __AllTyps=[string,boolean,Record<string,string>,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,U64,U32,string,(ProviderInfo|null),U32,boolean,U32,Record<string,string>,U32,string,(string|null),null,U32,Record<string,(string|null)>,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record<string,(string|null)>,Record<U32,string>,null,U32,null,U32,null,U32,string,(string|null),null,U32,string,(string|null),null,U32,(U32)[],U32,U32,Usize,U32,boolean,I64,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record<U32,ChatListItemFetchResult>,U32,U32,FullChat,U32,U32,BasicChat,U32,U32,null,U32,U32,null,U32,U32,null,U32,U32,string,U32,(U32|null),[string,string],U32,U32,null,U32,U32,U32,null,U32,U32,U32,null,U32,U32,(U32)[],U32,string,boolean,U32,U32,U32,U32,U32,string,null,U32,U32,(string|null),null,U32,U32,ChatVisibility,null,U32,U32,U32,null,U32,U32,U32,U32,string,string,U32,U32,U32,null,U32,U32,(U32|null),U32,U32,MuteDuration,null,U32,U32,boolean,U32,(U32)[],null,U32,U32,U32,(U32)[],U32,U32,U32,(MessageListItem)[],U32,U32,Message,U32,(U32)[],Record<U32,Message>,U32,U32,MessageNotificationInfo,U32,(U32)[],null,U32,U32,string,U32,U32,null,U32,string,(U32|null),(U32)[],U32,(U32)[],Record<U32,MessageSearchResult>,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record<U32,Contact>,U32,U32,string,U32,string,(U32|null),U32,(U32|null),Viewtype,(Viewtype|null),(Viewtype|null),(U32)[],U32,U32,Viewtype,(Viewtype|null),(Viewtype|null),[(U32|null),(U32|null)],null,U32,U32,U32,string,U32,(U32|null),(U32|null),I64,I64,(Location)[],U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,(U32)[],U32,null,U32,U32,null,U32,U32,(Message|null),U32,U32,U32,U32,string,U32,U32,U32,U32,(string|null),(string|null),([F64,F64]|null),(U32|null),[U32,Message],U32,U32,(string|null),(string|null),(U32|null),null];
export type __AllTyps=[string,boolean,Record<string,string>,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],null,null,U32,null,U32,null,U32,Account,U32,U64,U32,string,(ProviderInfo|null),U32,boolean,U32,Record<string,string>,U32,string,(string|null),null,U32,Record<string,(string|null)>,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record<string,(string|null)>,Record<U32,string>,null,U32,null,U32,null,U32,string,(string|null),null,U32,string,(string|null),null,U32,(U32)[],U32,U32,Usize,U32,boolean,I64,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record<U32,ChatListItemFetchResult>,U32,U32,FullChat,U32,U32,BasicChat,U32,U32,null,U32,U32,null,U32,U32,null,U32,U32,string,U32,(U32|null),[string,string],U32,string,U32,U32,U32,null,U32,U32,U32,null,U32,U32,U32,null,U32,U32,(U32)[],U32,string,boolean,U32,U32,U32,U32,U32,string,null,U32,U32,(string|null),null,U32,U32,ChatVisibility,null,U32,U32,U32,null,U32,U32,U32,U32,string,string,U32,U32,U32,null,U32,U32,(U32|null),U32,U32,MuteDuration,null,U32,U32,boolean,U32,(U32)[],null,U32,U32,U32,(U32)[],U32,U32,U32,(MessageListItem)[],U32,U32,Message,U32,(U32)[],Record<U32,Message>,U32,U32,MessageNotificationInfo,U32,(U32)[],null,U32,U32,string,U32,U32,null,U32,string,(U32|null),(U32)[],U32,(U32)[],Record<U32,MessageSearchResult>,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record<U32,Contact>,U32,U32,boolean,U32,U32,string,null,U32,U32,string,U32,string,(U32|null),U32,(U32|null),Viewtype,(Viewtype|null),(Viewtype|null),(U32)[],U32,U32,Viewtype,(Viewtype|null),(Viewtype|null),[(U32|null),(U32|null)],U32,string,(string|null),null,U32,string,(string|null),null,null,U32,U32,U32,string,U32,(U32|null),(U32|null),I64,I64,(Location)[],U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,(U32)[],U32,null,U32,U32,string,U32,U32,U32,null,U32,U32,(Message|null),U32,U32,U32,U32,string,U32,U32,U32,U32,(string|null),(string|null),([F64,F64]|null),(U32|null),[U32,Message],U32,U32,(string|null),(string|null),(U32|null),null];