diff --git a/CHANGELOG.md b/CHANGELOG.md index edf83e118..f4fb9ad31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index db4c9c519..1978b7aac 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -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 { 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 { + 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 { + 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, + ) -> 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, + ) -> 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 { + 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 diff --git a/deltachat-jsonrpc/src/api/types/message.rs b/deltachat-jsonrpc/src/api/types/message.rs index c7fdc17b5..739d00576 100644 --- a/deltachat-jsonrpc/src/api/types/message.rs +++ b/deltachat-jsonrpc/src/api/types/message.rs @@ -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, }, } diff --git a/deltachat-jsonrpc/typescript/generated/client.ts b/deltachat-jsonrpc/typescript/generated/client.ts index d4b5e095d..4c7e79be0 100644 --- a/deltachat-jsonrpc/typescript/generated/client.ts +++ b/deltachat-jsonrpc/typescript/generated/client.ts @@ -66,6 +66,26 @@ export class RawClient { return (this._transport.request('get_all_accounts', [] as RPC.Params)) as Promise<(T.Account)[]>; } + + public startIoForAllAccounts(): Promise { + return (this._transport.request('start_io_for_all_accounts', [] as RPC.Params)) as Promise; + } + + + public stopIoForAllAccounts(): Promise { + return (this._transport.request('stop_io_for_all_accounts', [] as RPC.Params)) as Promise; + } + + + public startIo(id: T.U32): Promise { + return (this._transport.request('start_io', [id] as RPC.Params)) as Promise; + } + + + public stopIo(id: T.U32): Promise { + return (this._transport.request('stop_io', [id] as RPC.Params)) as Promise; + } + /** * 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 { + return (this._transport.request('secure_join', [accountId, qr] as RPC.Params)) as Promise; + } + public leaveGroup(accountId: T.U32, chatId: T.U32): Promise { return (this._transport.request('leave_group', [accountId, chatId] as RPC.Params)) as Promise; @@ -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>; } + + public deleteContact(accountId: T.U32, contactId: T.U32): Promise { + return (this._transport.request('delete_contact', [accountId, contactId] as RPC.Params)) as Promise; + } + + + public changeContactName(accountId: T.U32, contactId: T.U32, name: string): Promise { + return (this._transport.request('change_contact_name', [accountId, contactId, name] as RPC.Params)) as Promise; + } + /** * 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 { + return (this._transport.request('export_backup', [accountId, destination, passphrase] as RPC.Params)) as Promise; + } + + + public importBackup(accountId: T.U32, path: string, passphrase: (string|null)): Promise { + return (this._transport.request('import_backup', [accountId, path, passphrase] as RPC.Params)) as Promise; + } + /** * 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 { + return (this._transport.request('send_sticker', [accountId, chatId, stickerPath] as RPC.Params)) as Promise; + } + + public removeDraft(accountId: T.U32, chatId: T.U32): Promise { return (this._transport.request('remove_draft', [accountId, chatId] as RPC.Params)) as Promise; } diff --git a/deltachat-jsonrpc/typescript/generated/types.ts b/deltachat-jsonrpc/typescript/generated/types.ts index e368cea0f..d8937045c 100644 --- a/deltachat-jsonrpc/typescript/generated/types.ts +++ b/deltachat-jsonrpc/typescript/generated/types.ts @@ -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,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,U64,U32,string,(ProviderInfo|null),U32,boolean,U32,Record,U32,string,(string|null),null,U32,Record,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record,Record,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,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,U32,MessageNotificationInfo,U32,(U32)[],null,U32,U32,string,U32,U32,null,U32,string,(U32|null),(U32)[],U32,(U32)[],Record,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,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,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,U32,string,(string|null),null,U32,Record,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record,Record,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,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,U32,MessageNotificationInfo,U32,(U32)[],null,U32,U32,string,U32,U32,null,U32,string,(U32|null),(U32)[],U32,(U32)[],Record,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,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];