From b6a48ad39b36a0983c86f777e09ac0a2367584b3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sun, 19 Jul 2020 14:40:59 +0200 Subject: [PATCH 01/17] design APIs for videochats --- deltachat-ffi/deltachat.h | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 4b0e526df..9a9d16e7e 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -839,6 +839,42 @@ uint32_t dc_send_msg_sync (dc_context_t* context, uint32 uint32_t dc_send_text_msg (dc_context_t* context, uint32_t chat_id, const char* text_to_send); +/** + * Send invitation to a videochat. + * + * This function reads the `basic_web_rtc_instance` config value, + * may check that the server is working in some way + * and creates a unique room for this chat, if needed doing a TOKEN roundtrip for that. + * + * After that, the function sends out a message that contains information to join the room: + * + * - To allow non-delta-clients to join the chat, + * the message contains a text-area with some descriptive text + * and a url that can be opened in a supported browser to join the videochat + * + * - delta-clients can get all information needed from + * the message object, using eg. + * dc_msg_is_videochat_invitation(), dc_msg_get_videochat_url() + * + * dc_send_videochat_invitation() is blocking and may take a while, + * so the UIs will typically call the function from within a thread. + * Moreover, UIs will typically enter the room directly without an additional click on the message, + * for this purpose, the function returns the message-id directly. + * + * As for other messages sent, this function + * sends the event #DC_EVENT_MSGS_CHANGED on succcess, the message has a delivery state, and so on. + * The recipient will get noticed by the call as usual by DC_EVENT_INCOMING_MSG or DC_EVENT_MSGS_CHANGED, + * depending on dc_msg_is_videochat_invitation(), however, UIs might some things differently, + * eg. play a different sound. + * + * @param context The context object. + * @param chat_id The chat to start a videochat for. + * @return The id if the message sent out + * or 0 for errors. + */ +uint32_t dc_send_videochat_invitation (dc_context_t* context, uint32_t chat_id); + + /** * Save a draft for a chat in the database. * @@ -3240,6 +3276,36 @@ int dc_msg_is_setupmessage (const dc_msg_t* msg); char* dc_msg_get_setupcodebegin (const dc_msg_t* msg); +/** + * Check if the message is a videochat invitation. + * + * Typically, such messages are rendered differently by the UIs, + * if so, they should contain a button to join the videochat. + * The url for joining can be retrieved using dc_msg_get_videochat_url(). + * + * @param msg The message object. + * @return Tristate, 0=message is no videochat invitation, + * 1=message is a videochat invitation that should be handled by a supported browser, + * 2=message is a videochat invitation that can be handled internally or by a supported browser. + */ +int dc_msg_is_videochat_invitation (const dc_msg_t* msg); + + +/** + * Get url of a videochat invitation. + * + * Videochat invitations are send out using dc_send_videochat_invitation() + * and you can check the state of a message using dc_msg_is_videochat_invitation(). + * + * @param msg The message object. + * @return If the message contains a videochat invitation, + * the url of the invitation is returned. + * If the message is no videochat invitation, NULL is returned. + * Must be released using dc_str_unref() when done. + */ +char* dc_msg_get_videochat_url (const dc_msg_t* msg); + + /** * Set the text of a message object. * This does not alter any information in the database; this may be done by dc_send_msg() later. From 0b2bce8334e420d02825ad84770602d1a2ed465a Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sun, 19 Jul 2020 23:19:21 +0200 Subject: [PATCH 02/17] use message-type instead of a special flag to mark videochat-invitations --- deltachat-ffi/deltachat.h | 53 ++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 9a9d16e7e..b66234c1f 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -854,7 +854,7 @@ uint32_t dc_send_text_msg (dc_context_t* context, uint32_t ch * * - delta-clients can get all information needed from * the message object, using eg. - * dc_msg_is_videochat_invitation(), dc_msg_get_videochat_url() + * dc_msg_get_videochat_url() and check dc_msg_get_viewtype() for DC_MSG_VIDEOCHAT_INVITATION * * dc_send_videochat_invitation() is blocking and may take a while, * so the UIs will typically call the function from within a thread. @@ -864,8 +864,7 @@ uint32_t dc_send_text_msg (dc_context_t* context, uint32_t ch * As for other messages sent, this function * sends the event #DC_EVENT_MSGS_CHANGED on succcess, the message has a delivery state, and so on. * The recipient will get noticed by the call as usual by DC_EVENT_INCOMING_MSG or DC_EVENT_MSGS_CHANGED, - * depending on dc_msg_is_videochat_invitation(), however, UIs might some things differently, - * eg. play a different sound. + * However, UIs might some things differently, eg. play a different sound. * * @param context The context object. * @param chat_id The chat to start a videochat for. @@ -3276,26 +3275,11 @@ int dc_msg_is_setupmessage (const dc_msg_t* msg); char* dc_msg_get_setupcodebegin (const dc_msg_t* msg); -/** - * Check if the message is a videochat invitation. - * - * Typically, such messages are rendered differently by the UIs, - * if so, they should contain a button to join the videochat. - * The url for joining can be retrieved using dc_msg_get_videochat_url(). - * - * @param msg The message object. - * @return Tristate, 0=message is no videochat invitation, - * 1=message is a videochat invitation that should be handled by a supported browser, - * 2=message is a videochat invitation that can be handled internally or by a supported browser. - */ -int dc_msg_is_videochat_invitation (const dc_msg_t* msg); - - /** * Get url of a videochat invitation. * - * Videochat invitations are send out using dc_send_videochat_invitation() - * and you can check the state of a message using dc_msg_is_videochat_invitation(). + * Videochat invitations are sent out using dc_send_videochat_invitation() + * and dc_msg_get_viewtype() returns #DC_MSG_VIDEOCHAT_INVITATION for such invitations. * * @param msg The message object. * @return If the message contains a videochat invitation, @@ -3306,6 +3290,23 @@ int dc_msg_is_videochat_invitation (const dc_msg_t* msg); char* dc_msg_get_videochat_url (const dc_msg_t* msg); +/** + * Check if the videochat can be handled internally. + * If "basic webrtc" as of https://github.com/cracker0dks/basicwebrtc is used to initiate the videochat, + * this is returned by dc_msg_is_basic_videochat(). + * "basic webrtc" videochat may be processed natively by the app + * whereas for other urls just the browser is opened. + * + * The videochat-url can be retrieved using dc_msg_get_videochat_url(). + * To check if a message is a videochat invitation at all, check the message type for #DC_MSG_VIDEOCHAT_INVITATION. + * + * @param msg The message object. + * @return 0=message is no videochat invitation or cannot be handled internally + * 1=message is a videochat invitation that can be handled internally or by a supported browser. + */ +int dc_msg_is_basic_videochat (const dc_msg_t* msg); + + /** * Set the text of a message object. * This does not alter any information in the database; this may be done by dc_send_msg() later. @@ -3841,6 +3842,18 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); */ #define DC_MSG_FILE 60 + +/** + * Message indicating an incoming or outgoing videochat. + * The message was created via dc_send_videochat_invitation() on this or a remote device. + * + * Typically, such messages are rendered differently by the UIs, + * eg. contain a button to join the videochat. + * The url for joining can be retrieved using dc_msg_get_videochat_url(). + */ +#define DC_MSG_VIDEOCHAT_INVITATION 70 + + /** * @} */ From 11b369db0fcbf31ae6514ea20989221e73b39151 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 00:13:21 +0200 Subject: [PATCH 03/17] rename basic_web_rtc_instance to basic_webrtc_instance --- deltachat-ffi/deltachat.h | 4 ++-- src/config.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index b66234c1f..4a1e4dfd7 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -318,7 +318,7 @@ char* dc_get_blobdir (const dc_context_t* context); * The library uses the `media_quality` setting to use different defaults * for recoding images sent with type DC_MSG_IMAGE. * If needed, recoding other file types is up to the UI. - * - `basic_web_rtc_instance` = address to webrtc signaling server (https://github.com/cracker0dks/basicwebrtc) + * - `basic_webrtc_instance` = address to webrtc signaling server (https://github.com/cracker0dks/basicwebrtc) * that should be used for opening video hangouts. * This property is only used in the UIs not by the core itself. * Format: https://example.com/subdir @@ -842,7 +842,7 @@ uint32_t dc_send_text_msg (dc_context_t* context, uint32_t ch /** * Send invitation to a videochat. * - * This function reads the `basic_web_rtc_instance` config value, + * This function reads the `basic_webrtc_instance` config value, * may check that the server is working in some way * and creates a unique room for this chat, if needed doing a TOKEN roundtrip for that. * diff --git a/src/config.rs b/src/config.rs index 31067a27f..850fa424d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -128,7 +128,7 @@ pub enum Config { /// This property is only used in the UIs not by the core itself. /// Format: https://example.com/subdir /// The other properties that are needed for a call such as the roomname will be set by the client in the anchor part of the url. - BasicWebRTCInstance, + BasicWebrtcInstance, } impl Context { From 29d4197340fb5875394b36b339baff73aa80df1c Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 12:45:53 +0200 Subject: [PATCH 04/17] send out videochat-invitation message, set up fallback text --- deltachat-ffi/deltachat.h | 4 +++- deltachat-ffi/src/lib.rs | 42 +++++++++++++++++++++++++++++++++++++++ src/chat.rs | 32 +++++++++++++++++++++++++++++ src/message.rs | 8 ++++++++ src/stock.rs | 6 ++++++ 5 files changed, 91 insertions(+), 1 deletion(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 4a1e4dfd7..0a2245316 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -4596,8 +4596,10 @@ void dc_event_unref(dc_event_t* event); #define DC_STR_EPHEMERAL_DAY 79 #define DC_STR_EPHEMERAL_WEEK 80 #define DC_STR_EPHEMERAL_FOUR_WEEKS 81 +#define DC_STR_VIDEOCHAT_INVITATION 82 +#define DC_STR_VIDEOCHAT_INVITE_MSG_BODY 83 -#define DC_STR_COUNT 81 +#define DC_STR_COUNT 83 /* * @} diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 8578548f9..eb42050d6 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -710,6 +710,25 @@ pub unsafe extern "C" fn dc_send_text_msg( }) } +#[no_mangle] +pub unsafe extern "C" fn dc_send_videochat_invitation( + context: *mut dc_context_t, + chat_id: u32, +) -> u32 { + if context.is_null() { + eprintln!("ignoring careless call to dc_send_videochat_invitation()"); + return 0; + } + let ctx = &*context; + + block_on(async move { + chat::send_videochat_invitation(&ctx, ChatId::new(chat_id)) + .await + .map(|msg_id| msg_id.to_u32()) + .unwrap_or_log_default(&ctx, "Failed to send videochat invitation") + }) +} + #[no_mangle] pub unsafe extern "C" fn dc_set_draft( context: *mut dc_context_t, @@ -2820,6 +2839,29 @@ pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg_t) -> libc::c_i ffi_msg.message.is_setupmessage().into() } +#[no_mangle] +pub unsafe extern "C" fn dc_msg_get_videochat_url(msg: *mut dc_msg_t) -> *mut libc::c_char { + if msg.is_null() { + eprintln!("ignoring careless call to dc_msg_get_videochat_url()"); + return "".strdup(); + } + let ffi_msg = &*msg; + + block_on(ffi_msg.message.get_videochat_url()) + .unwrap_or_default() + .strdup() +} + +#[no_mangle] +pub unsafe extern "C" fn dc_msg_is_basic_videochat(msg: *mut dc_msg_t) -> libc::c_int { + if msg.is_null() { + eprintln!("ignoring careless call to dc_msg_is_basic_videochat()"); + return 0; + } + let ffi_msg = &*msg; + ffi_msg.message.is_basic_videochat().into() +} + #[no_mangle] pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut libc::c_char { if msg.is_null() { diff --git a/src/chat.rs b/src/chat.rs index f21ce144a..f75468952 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1611,6 +1611,38 @@ pub async fn send_text_msg( send_msg(context, chat_id, &mut msg).await } +pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Result { + ensure!( + !chat_id.is_special(), + "videochat invitation cannot be sent to special chat: {}", + chat_id + ); + + let url = if let Some(basic_webrtc_instance) = + context.get_config(Config::BasicWebrtcInstance).await + { + basic_webrtc_instance + } else { + bail!("basic_webrtc_instance not set"); + }; + + let room = dc_create_id(); + + let url = if url.contains("$ROOM") { + url.replace("$ROOM", &room) + } else { + format!("{}{}", url, room) + }; + + let mut msg = Message::new(Viewtype::Text); + msg.text = Some( + context + .stock_string_repl_str(StockMessage::VideochatInviteMsgBody, url) + .await, + ); + send_msg(context, chat_id, &mut msg).await +} + pub async fn get_chat_msgs( context: &Context, chat_id: ChatId, diff --git a/src/message.rs b/src/message.rs index fa87fdca3..6c36ddeb2 100644 --- a/src/message.rs +++ b/src/message.rs @@ -638,6 +638,14 @@ impl Message { None } + pub async fn get_videochat_url(&self) -> Option { + None + } + + pub fn is_basic_videochat(&self) -> bool { + false + } + pub fn set_text(&mut self, text: Option) { self.text = text; } diff --git a/src/stock.rs b/src/stock.rs index 84ef72f09..7c6d788c3 100644 --- a/src/stock.rs +++ b/src/stock.rs @@ -210,6 +210,12 @@ pub enum StockMessage { #[strum(props(fallback = "Message deletion timer is set to 4 weeks."))] MsgEphemeralTimerFourWeeks = 81, + + #[strum(props(fallback = "Videochat invitation"))] + VideochatInvitation = 82, + + #[strum(props(fallback = "You are invited to an videochat, click %1$s to join."))] + VideochatInviteMsgBody = 83, } /* From 4227dec127215b5c6e38ae02efcb63eb9a8e2ae9 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 14:36:06 +0200 Subject: [PATCH 05/17] adapt repl to new videochat api --- examples/repl/cmdline.rs | 5 +++++ examples/repl/main.rs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 4890ada73..03b17ca4b 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -359,6 +359,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu send-garbage\n\ sendimage []\n\ sendfile []\n\ + videochat\n\ draft []\n\ devicemsg \n\ listmedia\n\ @@ -808,6 +809,10 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu } chat::send_msg(&context, sel_chat.as_ref().unwrap().get_id(), &mut msg).await?; } + "videochat" => { + ensure!(sel_chat.is_some(), "No chat selected."); + chat::send_videochat_invitation(&context, sel_chat.as_ref().unwrap().get_id()).await?; + } "listmsgs" => { ensure!(!arg1.is_empty(), "Argument missing."); diff --git a/examples/repl/main.rs b/examples/repl/main.rs index e53bed1c2..7be1c9bea 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -158,7 +158,7 @@ const DB_COMMANDS: [&str; 9] = [ "housekeeping", ]; -const CHAT_COMMANDS: [&str; 26] = [ +const CHAT_COMMANDS: [&str; 27] = [ "listchats", "listarchived", "chat", @@ -178,6 +178,7 @@ const CHAT_COMMANDS: [&str; 26] = [ "send", "sendimage", "sendfile", + "videochat", "draft", "listmedia", "archive", From f39abd6d51dc7b58fd8988c64dd8627784cb5a79 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 15:01:25 +0200 Subject: [PATCH 06/17] correct summary for videochat-invites --- src/chat.rs | 5 +++-- src/constants.rs | 3 +++ src/message.rs | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index f75468952..45d516e9a 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1374,11 +1374,12 @@ pub(crate) fn msgtype_has_file(msgtype: Viewtype) -> bool { Viewtype::Voice => true, Viewtype::Video => true, Viewtype::File => true, + Viewtype::VideochatInvitation => false, } } async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<(), Error> { - if msg.viewtype == Viewtype::Text { + if msg.viewtype == Viewtype::Text || msg.viewtype == Viewtype::VideochatInvitation { // the caller should check if the message text is empty } else if msgtype_has_file(msg.viewtype) { let blob = msg @@ -1634,7 +1635,7 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re format!("{}{}", url, room) }; - let mut msg = Message::new(Viewtype::Text); + let mut msg = Message::new(Viewtype::VideochatInvitation); msg.text = Some( context .stock_string_repl_str(StockMessage::VideochatInviteMsgBody, url) diff --git a/src/constants.rs b/src/constants.rs index e6489547c..2e93f508e 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -296,6 +296,9 @@ pub enum Viewtype { /// The file is set via dc_msg_set_file() /// and retrieved via dc_msg_get_file(). File = 60, + + /// Message is an invitation to a videochat. + VideochatInvitation = 70, } impl Default for Viewtype { diff --git a/src/message.rs b/src/message.rs index 6c36ddeb2..050e6cd17 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1249,6 +1249,13 @@ pub async fn get_summarytext_by_raw( format!("{} – {}", label, file_name) } } + Viewtype::VideochatInvitation => { + append_text = false; + context + .stock_str(StockMessage::VideochatInvitation) + .await + .into_owned() + } _ => { if param.get_cmd() != SystemMessage::LocationOnly { "".to_string() From b9d3e6b3423028c62954a12fb9124e1be05a2d9e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 16:27:04 +0200 Subject: [PATCH 07/17] send videochat-url and -invitation also through header --- src/chat.rs | 1 + src/mimefactory.rs | 13 +++++++++++++ src/param.rs | 3 +++ 3 files changed, 17 insertions(+) diff --git a/src/chat.rs b/src/chat.rs index 45d516e9a..bc695c647 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1636,6 +1636,7 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re }; let mut msg = Message::new(Viewtype::VideochatInvitation); + msg.param.set(Param::VideochatUrl, &url); msg.text = Some( context .stock_string_repl_str(StockMessage::VideochatInviteMsgBody, url) diff --git a/src/mimefactory.rs b/src/mimefactory.rs index bac979fc4..822f3ab97 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -875,6 +875,19 @@ impl<'a, 'b> MimeFactory<'a, 'b> { if self.msg.viewtype == Viewtype::Sticker { protected_headers.push(Header::new("Chat-Content".into(), "sticker".into())); + } else if self.msg.viewtype == Viewtype::VideochatInvitation { + protected_headers.push(Header::new( + "Chat-Content".into(), + "videochat-invitation".into(), + )); + protected_headers.push(Header::new( + "Chat-Videochat-Url".into(), + self.msg + .param + .get(Param::VideochatUrl) + .unwrap_or_default() + .into(), + )); } if self.msg.viewtype == Viewtype::Voice diff --git a/src/param.rs b/src/param.rs index 77169f42c..8ccfd8bfc 100644 --- a/src/param.rs +++ b/src/param.rs @@ -68,6 +68,9 @@ pub enum Param { /// For Messages AttachGroupImage = b'A', + /// For Messages + VideochatUrl = b'V', + /// For Messages: space-separated list of messaged IDs of forwarded copies. /// /// This is used when a [crate::message::Message] is in the From 0520ec8ab76cd1a6b018b4cfae10362731b932c0 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 17:37:37 +0200 Subject: [PATCH 08/17] implement videochat-getters --- examples/repl/cmdline.rs | 11 ++++++++++- src/message.rs | 10 ++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 03b17ca4b..da3216574 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -183,7 +183,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { let temp2 = dc_timestamp_to_str(msg.get_timestamp()); let msgtext = msg.get_text(); println!( - "{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{} [{}]", + "{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{}{} [{}]", prefix.as_ref(), msg.get_id(), if msg.get_showpadlock() { "🔒" } else { "" }, @@ -202,6 +202,15 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { "[FRESH]" }, if msg.is_info() { "[INFO]" } else { "" }, + if msg.get_viewtype() == Viewtype::VideochatInvitation { + format!( + "[VIDEOCHAT-INVITATION: {}, basic={}]", + msg.get_videochat_url().await.unwrap_or_default(), + msg.is_basic_videochat() + ) + } else { + "".to_string() + }, if msg.is_forwarded() { "[FORWARDED]" } else { diff --git a/src/message.rs b/src/message.rs index 050e6cd17..e8b3f6148 100644 --- a/src/message.rs +++ b/src/message.rs @@ -639,11 +639,17 @@ impl Message { } pub async fn get_videochat_url(&self) -> Option { - None + if self.viewtype == Viewtype::VideochatInvitation { + self.param.get(Param::VideochatUrl).map(|s| s.to_string()) + } else { + None + } } pub fn is_basic_videochat(&self) -> bool { - false + // currently, all videochat-urls are of type basic-webrtc + self.viewtype == Viewtype::VideochatInvitation + && self.param.get(Param::VideochatUrl).is_some() } pub fn set_text(&mut self, text: Option) { From e66ca5b018923f06dc7c82bdc83c3aca57486c9c Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Jul 2020 18:15:18 +0200 Subject: [PATCH 09/17] parse incoming videochat-invitations and mark messages as such --- src/headerdef.rs | 1 + src/mimeparser.rs | 35 ++++++++++++++++++++++ test-data/message/videochat_invitation.eml | 15 ++++++++++ 3 files changed, 51 insertions(+) create mode 100644 test-data/message/videochat_invitation.eml diff --git a/src/headerdef.rs b/src/headerdef.rs index d87929435..a3b079fe0 100644 --- a/src/headerdef.rs +++ b/src/headerdef.rs @@ -35,6 +35,7 @@ pub enum HeaderDef { ChatContent, ChatDuration, ChatDispositionNotificationTo, + ChatVideochatUrl, Autocrypt, AutocryptSetupMessage, SecureJoin, diff --git a/src/mimeparser.rs b/src/mimeparser.rs index f467538ac..5f3338804 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -242,6 +242,18 @@ impl MimeMessage { } } + fn parse_videochat_headers(&mut self) { + if let Some(value) = self.get(HeaderDef::ChatContent).cloned() { + if value == "videochat-invitation" { + let url = self.get(HeaderDef::ChatVideochatUrl).cloned(); + if let Some(part) = self.parts.first_mut() { + part.typ = Viewtype::VideochatInvitation; + part.param.set(Param::VideochatUrl, url.unwrap_or_default()); + } + } + } + } + /// Squashes mutlipart chat messages with attachment into single-part messages. /// /// Delta Chat sends attachments, such as images, in two-part messages, with the first message @@ -314,6 +326,7 @@ impl MimeMessage { fn parse_headers(&mut self, context: &Context) -> Result<()> { self.parse_system_message_headers(context)?; self.parse_avatar_headers(); + self.parse_videochat_headers(); self.squash_attachment_parts(); if let Some(ref subject) = self.get_subject() { @@ -1449,6 +1462,28 @@ mod tests { assert!(mimeparser.group_avatar.unwrap().is_change()); } + #[async_std::test] + async fn test_mimeparser_with_videochat() { + let t = TestContext::new().await; + + let raw = include_bytes!("../test-data/message/videochat_invitation.eml"); + let mimeparser = MimeMessage::from_bytes(&t.ctx, &raw[..]).await.unwrap(); + assert_eq!(mimeparser.parts.len(), 1); + assert_eq!(mimeparser.parts[0].typ, Viewtype::VideochatInvitation); + assert_eq!( + mimeparser.parts[0] + .param + .get(Param::VideochatUrl) + .unwrap_or_default(), + "https://example.org/p2p/?roomname=6HiduoAn4xN" + ); + assert!(mimeparser.parts[0] + .msg + .contains("https://example.org/p2p/?roomname=6HiduoAn4xN")); + assert_eq!(mimeparser.user_avatar, None); + assert_eq!(mimeparser.group_avatar, None); + } + #[async_std::test] async fn test_mimeparser_message_kml() { let context = TestContext::new().await; diff --git a/test-data/message/videochat_invitation.eml b/test-data/message/videochat_invitation.eml new file mode 100644 index 000000000..96f1df16b --- /dev/null +++ b/test-data/message/videochat_invitation.eml @@ -0,0 +1,15 @@ +Content-Type: text/plain; charset=utf-8 +Subject: Message from user +Message-ID: +Date: Mon, 20 Jul 2020 14:28:30 +0000 +X-Mailer: Delta Chat Core 1.40.0/CLI +Chat-Version: 1.0 +Chat-Content: videochat-invitation +Chat-Videochat-Url: https://example.org/p2p/?roomname=6HiduoAn4xN +To: +From: "=?utf-8?q??=" + +You are invited to an videochat, click https://example.org/p2p/?roomname=6HiduoAn4xN to join. + +-- +Sent with my Delta Chat Messenger: https://delta.chat From e054a49198877b895b51698a87e926f7d9c98549 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Jul 2020 12:49:15 +0200 Subject: [PATCH 10/17] tweak examples --- deltachat-ffi/deltachat.h | 25 +++++++++++++++++----- test-data/message/videochat_invitation.eml | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 0a2245316..13716e53b 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -3291,9 +3291,11 @@ char* dc_msg_get_videochat_url (const dc_msg_t* msg); /** - * Check if the videochat can be handled internally. - * If "basic webrtc" as of https://github.com/cracker0dks/basicwebrtc is used to initiate the videochat, - * this is returned by dc_msg_is_basic_videochat(). + * Check if the videochat is a "basic webrtc" videochat. + * + * Calling this functions only makes sense for messages of type #DC_MSG_VIDEOCHAT_INVITATION, + * in this case, if "basic webrtc" as of https://github.com/cracker0dks/basicwebrtc was used to initiate the videochat, + * dc_msg_is_basic_videochat() returns true. * "basic webrtc" videochat may be processed natively by the app * whereas for other urls just the browser is opened. * @@ -3301,8 +3303,21 @@ char* dc_msg_get_videochat_url (const dc_msg_t* msg); * To check if a message is a videochat invitation at all, check the message type for #DC_MSG_VIDEOCHAT_INVITATION. * * @param msg The message object. - * @return 0=message is no videochat invitation or cannot be handled internally - * 1=message is a videochat invitation that can be handled internally or by a supported browser. + * @return 0=message is no "basic webrtc" videochat invitation + * 1=message is a "basic webrtc" videochat invitation. + * + * Example: + * ~~~ + * if (dc_msg_get_viewtype(msg) == DC_MSG_VIDEOCHAT_INVITATION) { + * if (dc_msg_is_basic_videochat(msg)) { + * // videochat invitation that we ship a client for + * } else { + * // use browser for videochat, just open the url + * } + * } else { + * // not a videochat invitation + * } + * ~~~ */ int dc_msg_is_basic_videochat (const dc_msg_t* msg); diff --git a/test-data/message/videochat_invitation.eml b/test-data/message/videochat_invitation.eml index 96f1df16b..2851dc319 100644 --- a/test-data/message/videochat_invitation.eml +++ b/test-data/message/videochat_invitation.eml @@ -6,7 +6,7 @@ X-Mailer: Delta Chat Core 1.40.0/CLI Chat-Version: 1.0 Chat-Content: videochat-invitation Chat-Videochat-Url: https://example.org/p2p/?roomname=6HiduoAn4xN -To: +To: From: "=?utf-8?q??=" You are invited to an videochat, click https://example.org/p2p/?roomname=6HiduoAn4xN to join. From f3b9f671ba2a05682f8d1867ab1fa394d2bab857 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Jul 2020 15:14:29 +0200 Subject: [PATCH 11/17] webrtc-config-setting is just 'webrtc_instance' --- deltachat-ffi/deltachat.h | 10 ++++------ src/chat.rs | 8 +++----- src/config.rs | 8 ++------ 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 13716e53b..53896014f 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -318,11 +318,9 @@ char* dc_get_blobdir (const dc_context_t* context); * The library uses the `media_quality` setting to use different defaults * for recoding images sent with type DC_MSG_IMAGE. * If needed, recoding other file types is up to the UI. - * - `basic_webrtc_instance` = address to webrtc signaling server (https://github.com/cracker0dks/basicwebrtc) - * that should be used for opening video hangouts. - * This property is only used in the UIs not by the core itself. - * Format: https://example.com/subdir - * The other properties that are needed for a call such as the roomname will be set by the client in the anchor part of the url. + * - `webrtc_instance` = address to webrtc instance to use for videochats, + * eg. a server as of https://github.com/cracker0dks/basicwebrtc. + * Format: https://example.com/subdir#roomname=$ROOM * * If you want to retrieve a value, use dc_get_config(). * @@ -842,7 +840,7 @@ uint32_t dc_send_text_msg (dc_context_t* context, uint32_t ch /** * Send invitation to a videochat. * - * This function reads the `basic_webrtc_instance` config value, + * This function reads the `webrtc_instance` config value, * may check that the server is working in some way * and creates a unique room for this chat, if needed doing a TOKEN roundtrip for that. * diff --git a/src/chat.rs b/src/chat.rs index bc695c647..09b9764e8 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1619,12 +1619,10 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re chat_id ); - let url = if let Some(basic_webrtc_instance) = - context.get_config(Config::BasicWebrtcInstance).await - { - basic_webrtc_instance + let url = if let Some(webrtc_instance) = context.get_config(Config::WebrtcInstance).await { + webrtc_instance } else { - bail!("basic_webrtc_instance not set"); + bail!("webrtc_instance not set"); }; let room = dc_create_id(); diff --git a/src/config.rs b/src/config.rs index 850fa424d..6434f560b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -123,12 +123,8 @@ pub enum Config { /// because we do not want to send a second warning) NotifyAboutWrongPw, - /// address to webrtc signaling server (https://github.com/cracker0dks/basicwebrtc) - /// that should be used for opening video hangouts. - /// This property is only used in the UIs not by the core itself. - /// Format: https://example.com/subdir - /// The other properties that are needed for a call such as the roomname will be set by the client in the anchor part of the url. - BasicWebrtcInstance, + /// address to webrtc instance to use for videochats + WebrtcInstance, } impl Context { From 39364d1f6cd28f8a3188d992a9cbd23cfe5d5ed3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Jul 2020 17:24:40 +0200 Subject: [PATCH 12/17] prefix webrtc_instance by type, unify naming --- deltachat-ffi/deltachat.h | 8 +++++--- src/chat.rs | 14 ++++++++------ src/headerdef.rs | 2 +- src/message.rs | 16 ++++++++++------ src/mimefactory.rs | 4 ++-- src/mimeparser.rs | 7 ++++--- src/param.rs | 2 +- test-data/message/videochat_invitation.eml | 2 +- 8 files changed, 32 insertions(+), 23 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 53896014f..992e0d4e1 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -318,9 +318,11 @@ char* dc_get_blobdir (const dc_context_t* context); * The library uses the `media_quality` setting to use different defaults * for recoding images sent with type DC_MSG_IMAGE. * If needed, recoding other file types is up to the UI. - * - `webrtc_instance` = address to webrtc instance to use for videochats, - * eg. a server as of https://github.com/cracker0dks/basicwebrtc. - * Format: https://example.com/subdir#roomname=$ROOM + * - `webrtc_instance` = webrtc instance to use for videochats in the form + * `[basicwebrtc:]https://example.com/subdir#roomname=$ROOM` + * if the url is prefixed by `basicwebrtc`, the server is assumed to be of the type + * https://github.com/cracker0dks/basicwebrtc which some UIs have native support for. + * If no type is prefixed, the videochat is handled completely in a browser. * * If you want to retrieve a value, use dc_get_config(). * diff --git a/src/chat.rs b/src/chat.rs index 09b9764e8..e1483128b 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1619,22 +1619,24 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re chat_id ); - let url = if let Some(webrtc_instance) = context.get_config(Config::WebrtcInstance).await { - webrtc_instance + let instance = if let Some(instance) = context.get_config(Config::WebrtcInstance).await { + instance } else { bail!("webrtc_instance not set"); }; let room = dc_create_id(); - let url = if url.contains("$ROOM") { - url.replace("$ROOM", &room) + let instance = if instance.contains("$ROOM") { + instance.replace("$ROOM", &room) } else { - format!("{}{}", url, room) + format!("{}{}", instance, room) }; + let url = instance.replace("basicwebrtc:", ""); + let mut msg = Message::new(Viewtype::VideochatInvitation); - msg.param.set(Param::VideochatUrl, &url); + msg.param.set(Param::WebrtcInstance, &instance); msg.text = Some( context .stock_string_repl_str(StockMessage::VideochatInviteMsgBody, url) diff --git a/src/headerdef.rs b/src/headerdef.rs index a3b079fe0..482a47ada 100644 --- a/src/headerdef.rs +++ b/src/headerdef.rs @@ -35,7 +35,7 @@ pub enum HeaderDef { ChatContent, ChatDuration, ChatDispositionNotificationTo, - ChatVideochatUrl, + ChatWebrtcInstance, Autocrypt, AutocryptSetupMessage, SecureJoin, diff --git a/src/message.rs b/src/message.rs index e8b3f6148..affdfa2c1 100644 --- a/src/message.rs +++ b/src/message.rs @@ -640,16 +640,20 @@ impl Message { pub async fn get_videochat_url(&self) -> Option { if self.viewtype == Viewtype::VideochatInvitation { - self.param.get(Param::VideochatUrl).map(|s| s.to_string()) - } else { - None + if let Some(instance) = self.param.get(Param::WebrtcInstance) { + return Some(instance.replace("basicwebrtc:", "")); + } } + None } pub fn is_basic_videochat(&self) -> bool { - // currently, all videochat-urls are of type basic-webrtc - self.viewtype == Viewtype::VideochatInvitation - && self.param.get(Param::VideochatUrl).is_some() + if self.viewtype == Viewtype::VideochatInvitation { + if let Some(instance) = self.param.get(Param::WebrtcInstance) { + return instance.starts_with("basicwebrtc:"); + } + } + false } pub fn set_text(&mut self, text: Option) { diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 822f3ab97..7558ef523 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -881,10 +881,10 @@ impl<'a, 'b> MimeFactory<'a, 'b> { "videochat-invitation".into(), )); protected_headers.push(Header::new( - "Chat-Videochat-Url".into(), + "Chat-Webrtc-Instance".into(), self.msg .param - .get(Param::VideochatUrl) + .get(Param::WebrtcInstance) .unwrap_or_default() .into(), )); diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 5f3338804..7dc3e5766 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -245,10 +245,11 @@ impl MimeMessage { fn parse_videochat_headers(&mut self) { if let Some(value) = self.get(HeaderDef::ChatContent).cloned() { if value == "videochat-invitation" { - let url = self.get(HeaderDef::ChatVideochatUrl).cloned(); + let instance = self.get(HeaderDef::ChatWebrtcInstance).cloned(); if let Some(part) = self.parts.first_mut() { part.typ = Viewtype::VideochatInvitation; - part.param.set(Param::VideochatUrl, url.unwrap_or_default()); + part.param + .set(Param::WebrtcInstance, instance.unwrap_or_default()); } } } @@ -1473,7 +1474,7 @@ mod tests { assert_eq!( mimeparser.parts[0] .param - .get(Param::VideochatUrl) + .get(Param::WebrtcInstance) .unwrap_or_default(), "https://example.org/p2p/?roomname=6HiduoAn4xN" ); diff --git a/src/param.rs b/src/param.rs index 8ccfd8bfc..f3681ebc3 100644 --- a/src/param.rs +++ b/src/param.rs @@ -69,7 +69,7 @@ pub enum Param { AttachGroupImage = b'A', /// For Messages - VideochatUrl = b'V', + WebrtcInstance = b'V', /// For Messages: space-separated list of messaged IDs of forwarded copies. /// diff --git a/test-data/message/videochat_invitation.eml b/test-data/message/videochat_invitation.eml index 2851dc319..9b4e35031 100644 --- a/test-data/message/videochat_invitation.eml +++ b/test-data/message/videochat_invitation.eml @@ -5,7 +5,7 @@ Date: Mon, 20 Jul 2020 14:28:30 +0000 X-Mailer: Delta Chat Core 1.40.0/CLI Chat-Version: 1.0 Chat-Content: videochat-invitation -Chat-Videochat-Url: https://example.org/p2p/?roomname=6HiduoAn4xN +Chat-Webrtc-Instance: https://example.org/p2p/?roomname=6HiduoAn4xN To: From: "=?utf-8?q??=" From 72d95075a05b331a6852feb0f68eba1e49fa4c19 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Jul 2020 18:31:34 +0200 Subject: [PATCH 13/17] return correct videochat-type --- deltachat-ffi/deltachat.h | 14 ++++++++------ deltachat-ffi/src/lib.rs | 10 ++++++---- examples/repl/cmdline.rs | 6 +++--- src/chat.rs | 7 ++++--- src/constants.rs | 13 +++++++++++++ src/message.rs | 40 ++++++++++++++++++++++++++++++++++----- 6 files changed, 69 insertions(+), 21 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 992e0d4e1..15fba4ab3 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -3291,11 +3291,11 @@ char* dc_msg_get_videochat_url (const dc_msg_t* msg); /** - * Check if the videochat is a "basic webrtc" videochat. + * Get type of videochat. * * Calling this functions only makes sense for messages of type #DC_MSG_VIDEOCHAT_INVITATION, * in this case, if "basic webrtc" as of https://github.com/cracker0dks/basicwebrtc was used to initiate the videochat, - * dc_msg_is_basic_videochat() returns true. + * dc_msg_get_videochat_type() returns DC_VIDEOCHATTYPE_BASICWEBRTC. * "basic webrtc" videochat may be processed natively by the app * whereas for other urls just the browser is opened. * @@ -3303,13 +3303,12 @@ char* dc_msg_get_videochat_url (const dc_msg_t* msg); * To check if a message is a videochat invitation at all, check the message type for #DC_MSG_VIDEOCHAT_INVITATION. * * @param msg The message object. - * @return 0=message is no "basic webrtc" videochat invitation - * 1=message is a "basic webrtc" videochat invitation. + * @return Type of the videochat as of DC_VIDEOCHATTYPE_BASICWEBRTC or DC_VIDEOCHATTYPE_UNKNOWN. * * Example: * ~~~ * if (dc_msg_get_viewtype(msg) == DC_MSG_VIDEOCHAT_INVITATION) { - * if (dc_msg_is_basic_videochat(msg)) { + * if (dc_msg_get_videochat_type(msg) == DC_VIDEOCHATTYPE_BASICWEBRTC) { * // videochat invitation that we ship a client for * } else { * // use browser for videochat, just open the url @@ -3319,7 +3318,10 @@ char* dc_msg_get_videochat_url (const dc_msg_t* msg); * } * ~~~ */ -int dc_msg_is_basic_videochat (const dc_msg_t* msg); +int dc_msg_get_videochat_type (const dc_msg_t* msg); + +#define DC_VIDEOCHATTYPE_UNKNOWN 0 +#define DC_VIDEOCHATTYPE_BASICWEBRTC 1 /** diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index eb42050d6..643017977 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -2847,19 +2847,21 @@ pub unsafe extern "C" fn dc_msg_get_videochat_url(msg: *mut dc_msg_t) -> *mut li } let ffi_msg = &*msg; - block_on(ffi_msg.message.get_videochat_url()) + ffi_msg + .message + .get_videochat_url() .unwrap_or_default() .strdup() } #[no_mangle] -pub unsafe extern "C" fn dc_msg_is_basic_videochat(msg: *mut dc_msg_t) -> libc::c_int { +pub unsafe extern "C" fn dc_msg_get_videochat_type(msg: *mut dc_msg_t) -> libc::c_int { if msg.is_null() { - eprintln!("ignoring careless call to dc_msg_is_basic_videochat()"); + eprintln!("ignoring careless call to dc_msg_get_videochat_type()"); return 0; } let ffi_msg = &*msg; - ffi_msg.message.is_basic_videochat().into() + ffi_msg.message.get_videochat_type().unwrap_or_default() as i32 } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index da3216574..b6fd67a3d 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -204,9 +204,9 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { if msg.is_info() { "[INFO]" } else { "" }, if msg.get_viewtype() == Viewtype::VideochatInvitation { format!( - "[VIDEOCHAT-INVITATION: {}, basic={}]", - msg.get_videochat_url().await.unwrap_or_default(), - msg.is_basic_videochat() + "[VIDEOCHAT-INVITATION: {}, type={}]", + msg.get_videochat_url().unwrap_or_default(), + msg.get_videochat_type().unwrap_or_default() ) } else { "".to_string() diff --git a/src/chat.rs b/src/chat.rs index e1483128b..8d9c58d8a 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1633,13 +1633,14 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re format!("{}{}", instance, room) }; - let url = instance.replace("basicwebrtc:", ""); - let mut msg = Message::new(Viewtype::VideochatInvitation); msg.param.set(Param::WebrtcInstance, &instance); msg.text = Some( context - .stock_string_repl_str(StockMessage::VideochatInviteMsgBody, url) + .stock_string_repl_str( + StockMessage::VideochatInviteMsgBody, + Message::parse_webrtc_instance(&instance).1, + ) .await, ); send_msg(context, chat_id, &mut msg).await diff --git a/src/constants.rs b/src/constants.rs index 2e93f508e..eb9e2a6f8 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -84,6 +84,19 @@ impl Default for KeyGenType { } } +#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)] +#[repr(i8)] +pub enum VideochatType { + Unknown = 0, + BasicWebrtc = 1, +} + +impl Default for VideochatType { + fn default() -> Self { + VideochatType::Unknown + } +} + pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01; pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02; pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04; diff --git a/src/message.rs b/src/message.rs index affdfa2c1..b4859c6ef 100644 --- a/src/message.rs +++ b/src/message.rs @@ -638,22 +638,37 @@ impl Message { None } - pub async fn get_videochat_url(&self) -> Option { + /// split a webrtc_instance as defined by the corresponding config-value into a type and a url + pub fn parse_webrtc_instance(instance: &str) -> (VideochatType, String) { + let mut split = instance.splitn(2, ':'); + let type_str = split.next().unwrap_or_default().to_lowercase(); + let url = split.next(); + if type_str == "basicwebrtc" { + ( + VideochatType::BasicWebrtc, + url.unwrap_or_default().to_string(), + ) + } else { + (VideochatType::Unknown, instance.to_string()) + } + } + + pub fn get_videochat_url(&self) -> Option { if self.viewtype == Viewtype::VideochatInvitation { if let Some(instance) = self.param.get(Param::WebrtcInstance) { - return Some(instance.replace("basicwebrtc:", "")); + return Some(Message::parse_webrtc_instance(instance).1); } } None } - pub fn is_basic_videochat(&self) -> bool { + pub fn get_videochat_type(&self) -> Option { if self.viewtype == Viewtype::VideochatInvitation { if let Some(instance) = self.param.get(Param::WebrtcInstance) { - return instance.starts_with("basicwebrtc:"); + return Some(Message::parse_webrtc_instance(instance).0); } } - false + None } pub fn set_text(&mut self, text: Option) { @@ -1824,4 +1839,19 @@ mod tests { "Autocrypt Setup Message" // file name is not added for autocrypt setup messages ); } + + #[async_std::test] + async fn test_parse_webrtc_instance() { + let (webrtc_type, url) = Message::parse_webrtc_instance("basicwebrtc:https://foo/bar"); + assert_eq!(webrtc_type, VideochatType::BasicWebrtc); + assert_eq!(url, "https://foo/bar"); + + let (webrtc_type, url) = Message::parse_webrtc_instance("bAsIcwEbrTc:url"); + assert_eq!(webrtc_type, VideochatType::BasicWebrtc); + assert_eq!(url, "url"); + + let (webrtc_type, url) = Message::parse_webrtc_instance("https://foo/bar?key=val#key=val"); + assert_eq!(webrtc_type, VideochatType::Unknown); + assert_eq!(url, "https://foo/bar?key=val#key=val"); + } } From 74fbd4fd162bba62400a4132f6d91cea0372a061 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 23 Jul 2020 01:13:48 +0200 Subject: [PATCH 14/17] show error if webrtc_instance is empty --- src/chat.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/chat.rs b/src/chat.rs index 8d9c58d8a..59afd2918 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1620,7 +1620,11 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re ); let instance = if let Some(instance) = context.get_config(Config::WebrtcInstance).await { - instance + if !instance.is_empty() { + instance + } else { + bail!("webrtc_instance is empty"); + } } else { bail!("webrtc_instance not set"); }; From 04c90e2d873b3d5b805f1f9e070954d48808cb19 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 23 Jul 2020 11:52:02 +0200 Subject: [PATCH 15/17] differ between webrtc-instance-pattern and webrtc-rooms generated from that --- src/chat.rs | 2 +- src/headerdef.rs | 2 +- src/message.rs | 4 ++-- src/mimefactory.rs | 4 ++-- src/mimeparser.rs | 6 +++--- src/param.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index 59afd2918..4e49cb885 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1638,7 +1638,7 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re }; let mut msg = Message::new(Viewtype::VideochatInvitation); - msg.param.set(Param::WebrtcInstance, &instance); + msg.param.set(Param::WebrtcRoom, &instance); msg.text = Some( context .stock_string_repl_str( diff --git a/src/headerdef.rs b/src/headerdef.rs index 482a47ada..5743351e6 100644 --- a/src/headerdef.rs +++ b/src/headerdef.rs @@ -35,7 +35,7 @@ pub enum HeaderDef { ChatContent, ChatDuration, ChatDispositionNotificationTo, - ChatWebrtcInstance, + ChatWebrtcRoom, Autocrypt, AutocryptSetupMessage, SecureJoin, diff --git a/src/message.rs b/src/message.rs index b4859c6ef..38e90b3dc 100644 --- a/src/message.rs +++ b/src/message.rs @@ -655,7 +655,7 @@ impl Message { pub fn get_videochat_url(&self) -> Option { if self.viewtype == Viewtype::VideochatInvitation { - if let Some(instance) = self.param.get(Param::WebrtcInstance) { + if let Some(instance) = self.param.get(Param::WebrtcRoom) { return Some(Message::parse_webrtc_instance(instance).1); } } @@ -664,7 +664,7 @@ impl Message { pub fn get_videochat_type(&self) -> Option { if self.viewtype == Viewtype::VideochatInvitation { - if let Some(instance) = self.param.get(Param::WebrtcInstance) { + if let Some(instance) = self.param.get(Param::WebrtcRoom) { return Some(Message::parse_webrtc_instance(instance).0); } } diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 7558ef523..f17659e5d 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -881,10 +881,10 @@ impl<'a, 'b> MimeFactory<'a, 'b> { "videochat-invitation".into(), )); protected_headers.push(Header::new( - "Chat-Webrtc-Instance".into(), + "Chat-Webrtc-Room".into(), self.msg .param - .get(Param::WebrtcInstance) + .get(Param::WebrtcRoom) .unwrap_or_default() .into(), )); diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 7dc3e5766..1cfd71a38 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -245,11 +245,11 @@ impl MimeMessage { fn parse_videochat_headers(&mut self) { if let Some(value) = self.get(HeaderDef::ChatContent).cloned() { if value == "videochat-invitation" { - let instance = self.get(HeaderDef::ChatWebrtcInstance).cloned(); + let instance = self.get(HeaderDef::ChatWebrtcRoom).cloned(); if let Some(part) = self.parts.first_mut() { part.typ = Viewtype::VideochatInvitation; part.param - .set(Param::WebrtcInstance, instance.unwrap_or_default()); + .set(Param::WebrtcRoom, instance.unwrap_or_default()); } } } @@ -1474,7 +1474,7 @@ mod tests { assert_eq!( mimeparser.parts[0] .param - .get(Param::WebrtcInstance) + .get(Param::WebrtcRoom) .unwrap_or_default(), "https://example.org/p2p/?roomname=6HiduoAn4xN" ); diff --git a/src/param.rs b/src/param.rs index f3681ebc3..4d87202eb 100644 --- a/src/param.rs +++ b/src/param.rs @@ -69,7 +69,7 @@ pub enum Param { AttachGroupImage = b'A', /// For Messages - WebrtcInstance = b'V', + WebrtcRoom = b'V', /// For Messages: space-separated list of messaged IDs of forwarded copies. /// From c43f6964c5f2ab14066d219ca34b7ba6473c4c11 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 23 Jul 2020 23:49:05 +0200 Subject: [PATCH 16/17] wording --- deltachat-ffi/src/lib.rs | 2 +- src/chat.rs | 2 +- src/stock.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 643017977..aa0442318 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -725,7 +725,7 @@ pub unsafe extern "C" fn dc_send_videochat_invitation( chat::send_videochat_invitation(&ctx, ChatId::new(chat_id)) .await .map(|msg_id| msg_id.to_u32()) - .unwrap_or_log_default(&ctx, "Failed to send videochat invitation") + .unwrap_or_log_default(&ctx, "Failed to send video chat invitation") }) } diff --git a/src/chat.rs b/src/chat.rs index 4e49cb885..74af3f678 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1615,7 +1615,7 @@ pub async fn send_text_msg( pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Result { ensure!( !chat_id.is_special(), - "videochat invitation cannot be sent to special chat: {}", + "video chat invitation cannot be sent to special chat: {}", chat_id ); diff --git a/src/stock.rs b/src/stock.rs index 7c6d788c3..09e0ecd9c 100644 --- a/src/stock.rs +++ b/src/stock.rs @@ -211,10 +211,10 @@ pub enum StockMessage { #[strum(props(fallback = "Message deletion timer is set to 4 weeks."))] MsgEphemeralTimerFourWeeks = 81, - #[strum(props(fallback = "Videochat invitation"))] + #[strum(props(fallback = "Video chat invitation"))] VideochatInvitation = 82, - #[strum(props(fallback = "You are invited to an videochat, click %1$s to join."))] + #[strum(props(fallback = "You are invited to a video chat, click %1$s to join."))] VideochatInviteMsgBody = 83, } From 62f424452a080c9642650e54be583f0938aaf883 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 24 Jul 2020 02:31:39 +0200 Subject: [PATCH 17/17] fix tests --- test-data/message/videochat_invitation.eml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/message/videochat_invitation.eml b/test-data/message/videochat_invitation.eml index 9b4e35031..4c9e9c7e5 100644 --- a/test-data/message/videochat_invitation.eml +++ b/test-data/message/videochat_invitation.eml @@ -5,7 +5,7 @@ Date: Mon, 20 Jul 2020 14:28:30 +0000 X-Mailer: Delta Chat Core 1.40.0/CLI Chat-Version: 1.0 Chat-Content: videochat-invitation -Chat-Webrtc-Instance: https://example.org/p2p/?roomname=6HiduoAn4xN +Chat-Webrtc-Room: https://example.org/p2p/?roomname=6HiduoAn4xN To: From: "=?utf-8?q??="