mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
api!: remove APIs for video chat invitations
This commit is contained in:
@@ -458,12 +458,6 @@ char* dc_get_blobdir (const dc_context_t* context);
|
|||||||
* The library uses the `media_quality` setting to use different defaults
|
* The library uses the `media_quality` setting to use different defaults
|
||||||
* for recoding images sent with type #DC_MSG_IMAGE.
|
* for recoding images sent with type #DC_MSG_IMAGE.
|
||||||
* If needed, recoding other file types is up to the UI.
|
* If needed, recoding other file types is up to the UI.
|
||||||
* - `webrtc_instance` = webrtc instance to use for videochats in the form
|
|
||||||
* `[basicwebrtc:|jitsi:]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.
|
|
||||||
* The type `jitsi:` may be handled by external apps.
|
|
||||||
* If no type is prefixed, the videochat is handled completely in a browser.
|
|
||||||
* - `bot` = Set to "1" if this is a bot.
|
* - `bot` = Set to "1" if this is a bot.
|
||||||
* Prevents adding the "Device messages" and "Saved messages" chats,
|
* Prevents adding the "Device messages" and "Saved messages" chats,
|
||||||
* adds Auto-Submitted header to outgoing messages,
|
* adds Auto-Submitted header to outgoing messages,
|
||||||
@@ -575,11 +569,10 @@ int dc_set_stock_translation(dc_context_t* context, uint32_t stock_i
|
|||||||
/**
|
/**
|
||||||
* Set configuration values from a QR code.
|
* Set configuration values from a QR code.
|
||||||
* Before this function is called, dc_check_qr() should confirm the type of the
|
* Before this function is called, dc_check_qr() should confirm the type of the
|
||||||
* QR code is DC_QR_ACCOUNT, DC_QR_LOGIN or DC_QR_WEBRTC_INSTANCE.
|
* QR code is DC_QR_ACCOUNT or DC_QR_LOGIN.
|
||||||
*
|
*
|
||||||
* Internally, the function will call dc_set_config() with the appropriate keys,
|
* Internally, the function will call dc_set_config() with the appropriate keys,
|
||||||
* e.g. `addr` and `mail_pw` for DC_QR_ACCOUNT and DC_QR_LOGIN
|
* e.g. `addr` and `mail_pw` for DC_QR_ACCOUNT and DC_QR_LOGIN.
|
||||||
* or `webrtc_instance` for DC_QR_WEBRTC_INSTANCE.
|
|
||||||
*
|
*
|
||||||
* @memberof dc_context_t
|
* @memberof dc_context_t
|
||||||
* @param context The context object.
|
* @param context The context object.
|
||||||
@@ -1052,42 +1045,6 @@ void dc_send_edit_request (dc_context_t* context, uint32_t ms
|
|||||||
void dc_send_delete_request (dc_context_t* context, const uint32_t* msg_ids, int msg_cnt);
|
void dc_send_delete_request (dc_context_t* context, const uint32_t* msg_ids, int msg_cnt);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send invitation to a videochat.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 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 e.g.
|
|
||||||
* 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.
|
|
||||||
* 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 success, 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,
|
|
||||||
* However, UIs might some things differently, e.g. play a different sound.
|
|
||||||
*
|
|
||||||
* @memberof dc_context_t
|
|
||||||
* @param context The context object.
|
|
||||||
* @param chat_id The chat to start a videochat for.
|
|
||||||
* @return The ID of the message sent out
|
|
||||||
* or 0 for errors.
|
|
||||||
*/
|
|
||||||
uint32_t dc_send_videochat_invitation (dc_context_t* context, uint32_t chat_id);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A webxdc instance sends a status update to its other members.
|
* A webxdc instance sends a status update to its other members.
|
||||||
*
|
*
|
||||||
@@ -2615,7 +2572,6 @@ void dc_stop_ongoing_process (dc_context_t* context);
|
|||||||
#define DC_QR_BACKUP 251 // deprecated
|
#define DC_QR_BACKUP 251 // deprecated
|
||||||
#define DC_QR_BACKUP2 252
|
#define DC_QR_BACKUP2 252
|
||||||
#define DC_QR_BACKUP_TOO_NEW 255
|
#define DC_QR_BACKUP_TOO_NEW 255
|
||||||
#define DC_QR_WEBRTC_INSTANCE 260 // text1=domain, text2=instance pattern
|
|
||||||
#define DC_QR_PROXY 271 // text1=address (e.g. "127.0.0.1:9050")
|
#define DC_QR_PROXY 271 // text1=address (e.g. "127.0.0.1:9050")
|
||||||
#define DC_QR_ADDR 320 // id=contact
|
#define DC_QR_ADDR 320 // id=contact
|
||||||
#define DC_QR_TEXT 330 // text1=text
|
#define DC_QR_TEXT 330 // text1=text
|
||||||
@@ -2669,10 +2625,6 @@ void dc_stop_ongoing_process (dc_context_t* context);
|
|||||||
* show a hint to the user that this backup comes from a newer Delta Chat version
|
* show a hint to the user that this backup comes from a newer Delta Chat version
|
||||||
* and this device needs an update
|
* and this device needs an update
|
||||||
*
|
*
|
||||||
* - DC_QR_WEBRTC_INSTANCE with dc_lot_t::text1=domain:
|
|
||||||
* ask the user if they want to use the given service for video chats;
|
|
||||||
* if so, call dc_set_config_from_qr().
|
|
||||||
*
|
|
||||||
* - DC_QR_PROXY with dc_lot_t::text1=address:
|
* - DC_QR_PROXY with dc_lot_t::text1=address:
|
||||||
* ask the user if they want to use the given proxy.
|
* ask the user if they want to use the given proxy.
|
||||||
* if so, call dc_set_config_from_qr() and restart I/O.
|
* if so, call dc_set_config_from_qr() and restart I/O.
|
||||||
@@ -4744,22 +4696,6 @@ int dc_msg_is_setupmessage (const dc_msg_t* msg);
|
|||||||
char* dc_msg_get_setupcodebegin (const dc_msg_t* msg);
|
char* dc_msg_get_setupcodebegin (const dc_msg_t* msg);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get URL of a 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.
|
|
||||||
*
|
|
||||||
* @memberof dc_msg_t
|
|
||||||
* @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);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the error status of the message.
|
* Gets the error status of the message.
|
||||||
* If there is no error associated with the message, NULL is returned.
|
* If there is no error associated with the message, NULL is returned.
|
||||||
@@ -4782,41 +4718,6 @@ char* dc_msg_get_videochat_url (const dc_msg_t* msg);
|
|||||||
char* dc_msg_get_error (const dc_msg_t* msg);
|
char* dc_msg_get_error (const dc_msg_t* msg);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get type of videochat.
|
|
||||||
*
|
|
||||||
* Calling this functions only makes sense for messages of type #DC_MSG_VIDEOCHAT_INVITATION,
|
|
||||||
* in this case, if `basicwebrtc:` as of https://github.com/cracker0dks/basicwebrtc or `jitsi`
|
|
||||||
* were used to initiate the videochat,
|
|
||||||
* dc_msg_get_videochat_type() returns the corresponding type.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @memberof dc_msg_t
|
|
||||||
* @param msg The message object.
|
|
||||||
* @return Type of the videochat as of DC_VIDEOCHATTYPE_BASICWEBRTC, DC_VIDEOCHATTYPE_JITSI or DC_VIDEOCHATTYPE_UNKNOWN.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* ~~~
|
|
||||||
* if (dc_msg_get_viewtype(msg) == DC_MSG_VIDEOCHAT_INVITATION) {
|
|
||||||
* if (dc_msg_get_videochat_type(msg) == DC_VIDEOCHATTYPE_BASICWEBRTC) {
|
|
||||||
* // videochat invitation that we ship a client for
|
|
||||||
* } else {
|
|
||||||
* // use browser for videochat - or add an additional check for DC_VIDEOCHATTYPE_JITSI
|
|
||||||
* }
|
|
||||||
* } else {
|
|
||||||
* // not a videochat invitation
|
|
||||||
* }
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
int dc_msg_get_videochat_type (const dc_msg_t* msg);
|
|
||||||
|
|
||||||
#define DC_VIDEOCHATTYPE_UNKNOWN 0
|
|
||||||
#define DC_VIDEOCHATTYPE_BASICWEBRTC 1
|
|
||||||
#define DC_VIDEOCHATTYPE_JITSI 2
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the message has a full HTML version.
|
* Checks if the message has a full HTML version.
|
||||||
*
|
*
|
||||||
@@ -5715,17 +5616,6 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
|||||||
#define DC_MSG_FILE 60
|
#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,
|
|
||||||
* e.g. 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
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message indicating an incoming or outgoing call.
|
* Message indicating an incoming or outgoing call.
|
||||||
*
|
*
|
||||||
@@ -7276,17 +7166,6 @@ void dc_event_unref(dc_event_t* event);
|
|||||||
/// @deprecated Deprecated 2021-01-30, DC_STR_EPHEMERAL_WEEKS is used instead.
|
/// @deprecated Deprecated 2021-01-30, DC_STR_EPHEMERAL_WEEKS is used instead.
|
||||||
#define DC_STR_EPHEMERAL_FOUR_WEEKS 81
|
#define DC_STR_EPHEMERAL_FOUR_WEEKS 81
|
||||||
|
|
||||||
/// "Video chat invitation"
|
|
||||||
///
|
|
||||||
/// Used in summaries.
|
|
||||||
#define DC_STR_VIDEOCHAT_INVITATION 82
|
|
||||||
|
|
||||||
/// "You are invited to a video chat, click %1$s to join."
|
|
||||||
///
|
|
||||||
/// Used as message text of outgoing video chat invitations.
|
|
||||||
/// - %1$s will be replaced by the URL of the video chat
|
|
||||||
#define DC_STR_VIDEOCHAT_INVITE_MSG_BODY 83
|
|
||||||
|
|
||||||
/// "Error: %1$s"
|
/// "Error: %1$s"
|
||||||
///
|
///
|
||||||
/// Used in error strings.
|
/// Used in error strings.
|
||||||
|
|||||||
@@ -1098,25 +1098,6 @@ pub unsafe extern "C" fn dc_send_delete_request(
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 video chat invitation")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_send_webxdc_status_update(
|
pub unsafe extern "C" fn dc_send_webxdc_status_update(
|
||||||
context: *mut dc_context_t,
|
context: *mut dc_context_t,
|
||||||
@@ -3854,31 +3835,6 @@ pub unsafe extern "C" fn dc_msg_has_html(msg: *mut dc_msg_t) -> libc::c_int {
|
|||||||
ffi_msg.message.has_html().into()
|
ffi_msg.message.has_html().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;
|
|
||||||
|
|
||||||
ffi_msg
|
|
||||||
.message
|
|
||||||
.get_videochat_url()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.strdup()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
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_get_videochat_type()");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let ffi_msg = &*msg;
|
|
||||||
ffi_msg.message.get_videochat_type().unwrap_or_default() as i32
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut libc::c_char {
|
pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut libc::c_char {
|
||||||
if msg.is_null() {
|
if msg.is_null() {
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ impl Lot {
|
|||||||
Qr::Account { domain } => Some(Cow::Borrowed(domain)),
|
Qr::Account { domain } => Some(Cow::Borrowed(domain)),
|
||||||
Qr::Backup2 { .. } => None,
|
Qr::Backup2 { .. } => None,
|
||||||
Qr::BackupTooNew { .. } => None,
|
Qr::BackupTooNew { .. } => None,
|
||||||
Qr::WebrtcInstance { domain, .. } => Some(Cow::Borrowed(domain)),
|
|
||||||
Qr::Proxy { host, port, .. } => Some(Cow::Owned(format!("{host}:{port}"))),
|
Qr::Proxy { host, port, .. } => Some(Cow::Owned(format!("{host}:{port}"))),
|
||||||
Qr::Addr { draft, .. } => draft.as_deref().map(Cow::Borrowed),
|
Qr::Addr { draft, .. } => draft.as_deref().map(Cow::Borrowed),
|
||||||
Qr::Url { url } => Some(Cow::Borrowed(url)),
|
Qr::Url { url } => Some(Cow::Borrowed(url)),
|
||||||
@@ -105,7 +104,6 @@ impl Lot {
|
|||||||
Qr::Account { .. } => LotState::QrAccount,
|
Qr::Account { .. } => LotState::QrAccount,
|
||||||
Qr::Backup2 { .. } => LotState::QrBackup2,
|
Qr::Backup2 { .. } => LotState::QrBackup2,
|
||||||
Qr::BackupTooNew { .. } => LotState::QrBackupTooNew,
|
Qr::BackupTooNew { .. } => LotState::QrBackupTooNew,
|
||||||
Qr::WebrtcInstance { .. } => LotState::QrWebrtcInstance,
|
|
||||||
Qr::Proxy { .. } => LotState::QrProxy,
|
Qr::Proxy { .. } => LotState::QrProxy,
|
||||||
Qr::Addr { .. } => LotState::QrAddr,
|
Qr::Addr { .. } => LotState::QrAddr,
|
||||||
Qr::Url { .. } => LotState::QrUrl,
|
Qr::Url { .. } => LotState::QrUrl,
|
||||||
@@ -132,7 +130,6 @@ impl Lot {
|
|||||||
Qr::Account { .. } => Default::default(),
|
Qr::Account { .. } => Default::default(),
|
||||||
Qr::Backup2 { .. } => Default::default(),
|
Qr::Backup2 { .. } => Default::default(),
|
||||||
Qr::BackupTooNew { .. } => Default::default(),
|
Qr::BackupTooNew { .. } => Default::default(),
|
||||||
Qr::WebrtcInstance { .. } => Default::default(),
|
|
||||||
Qr::Proxy { .. } => Default::default(),
|
Qr::Proxy { .. } => Default::default(),
|
||||||
Qr::Addr { contact_id, .. } => contact_id.to_u32(),
|
Qr::Addr { contact_id, .. } => contact_id.to_u32(),
|
||||||
Qr::Url { .. } => Default::default(),
|
Qr::Url { .. } => Default::default(),
|
||||||
@@ -185,9 +182,6 @@ pub enum LotState {
|
|||||||
|
|
||||||
QrBackupTooNew = 255,
|
QrBackupTooNew = 255,
|
||||||
|
|
||||||
/// text1=domain, text2=instance pattern
|
|
||||||
QrWebrtcInstance = 260,
|
|
||||||
|
|
||||||
/// text1=address, text2=protocol
|
/// text1=address, text2=protocol
|
||||||
QrProxy = 271,
|
QrProxy = 271,
|
||||||
|
|
||||||
|
|||||||
@@ -2282,13 +2282,6 @@ impl CommandApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_videochat_invitation(&self, account_id: u32, chat_id: u32) -> Result<u32> {
|
|
||||||
let ctx = self.get_context(account_id).await?;
|
|
||||||
chat::send_videochat_invitation(&ctx, ChatId::new(chat_id))
|
|
||||||
.await
|
|
||||||
.map(|msg_id| msg_id.to_u32())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------
|
// ---------------------------------------------
|
||||||
// misc prototyping functions
|
// misc prototyping functions
|
||||||
// that might get removed later again
|
// that might get removed later again
|
||||||
|
|||||||
@@ -84,9 +84,6 @@ pub struct MessageObject {
|
|||||||
dimensions_height: i32,
|
dimensions_height: i32,
|
||||||
dimensions_width: i32,
|
dimensions_width: i32,
|
||||||
|
|
||||||
videochat_type: Option<u32>,
|
|
||||||
videochat_url: Option<String>,
|
|
||||||
|
|
||||||
override_sender_name: Option<String>,
|
override_sender_name: Option<String>,
|
||||||
sender: ContactObject,
|
sender: ContactObject,
|
||||||
|
|
||||||
@@ -239,15 +236,6 @@ impl MessageObject {
|
|||||||
dimensions_height: message.get_height(),
|
dimensions_height: message.get_height(),
|
||||||
dimensions_width: message.get_width(),
|
dimensions_width: message.get_width(),
|
||||||
|
|
||||||
videochat_type: match message.get_videochat_type() {
|
|
||||||
Some(vct) => Some(
|
|
||||||
vct.to_u32()
|
|
||||||
.context("videochat type conversion to number failed")?,
|
|
||||||
),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
videochat_url: message.get_videochat_url(),
|
|
||||||
|
|
||||||
override_sender_name,
|
override_sender_name,
|
||||||
sender,
|
sender,
|
||||||
|
|
||||||
@@ -321,9 +309,6 @@ pub enum MessageViewtype {
|
|||||||
/// Message containing any file, eg. a PDF.
|
/// Message containing any file, eg. a PDF.
|
||||||
File,
|
File,
|
||||||
|
|
||||||
/// Message is an invitation to a videochat.
|
|
||||||
VideochatInvitation,
|
|
||||||
|
|
||||||
/// Message is a call.
|
/// Message is a call.
|
||||||
Call,
|
Call,
|
||||||
|
|
||||||
@@ -348,7 +333,6 @@ impl From<Viewtype> for MessageViewtype {
|
|||||||
Viewtype::Voice => MessageViewtype::Voice,
|
Viewtype::Voice => MessageViewtype::Voice,
|
||||||
Viewtype::Video => MessageViewtype::Video,
|
Viewtype::Video => MessageViewtype::Video,
|
||||||
Viewtype::File => MessageViewtype::File,
|
Viewtype::File => MessageViewtype::File,
|
||||||
Viewtype::VideochatInvitation => MessageViewtype::VideochatInvitation,
|
|
||||||
Viewtype::Call => MessageViewtype::Call,
|
Viewtype::Call => MessageViewtype::Call,
|
||||||
Viewtype::Webxdc => MessageViewtype::Webxdc,
|
Viewtype::Webxdc => MessageViewtype::Webxdc,
|
||||||
Viewtype::Vcard => MessageViewtype::Vcard,
|
Viewtype::Vcard => MessageViewtype::Vcard,
|
||||||
@@ -368,7 +352,6 @@ impl From<MessageViewtype> for Viewtype {
|
|||||||
MessageViewtype::Voice => Viewtype::Voice,
|
MessageViewtype::Voice => Viewtype::Voice,
|
||||||
MessageViewtype::Video => Viewtype::Video,
|
MessageViewtype::Video => Viewtype::Video,
|
||||||
MessageViewtype::File => Viewtype::File,
|
MessageViewtype::File => Viewtype::File,
|
||||||
MessageViewtype::VideochatInvitation => Viewtype::VideochatInvitation,
|
|
||||||
MessageViewtype::Call => Viewtype::Call,
|
MessageViewtype::Call => Viewtype::Call,
|
||||||
MessageViewtype::Webxdc => Viewtype::Webxdc,
|
MessageViewtype::Webxdc => Viewtype::Webxdc,
|
||||||
MessageViewtype::Vcard => Viewtype::Vcard,
|
MessageViewtype::Vcard => Viewtype::Vcard,
|
||||||
|
|||||||
@@ -225,13 +225,6 @@ impl From<Qr> for QrObject {
|
|||||||
auth_token,
|
auth_token,
|
||||||
},
|
},
|
||||||
Qr::BackupTooNew {} => QrObject::BackupTooNew {},
|
Qr::BackupTooNew {} => QrObject::BackupTooNew {},
|
||||||
Qr::WebrtcInstance {
|
|
||||||
domain,
|
|
||||||
instance_pattern,
|
|
||||||
} => QrObject::WebrtcInstance {
|
|
||||||
domain,
|
|
||||||
instance_pattern,
|
|
||||||
},
|
|
||||||
Qr::Proxy { url, host, port } => QrObject::Proxy { url, host, port },
|
Qr::Proxy { url, host, port } => QrObject::Proxy { url, host, port },
|
||||||
Qr::Addr { contact_id, draft } => {
|
Qr::Addr { contact_id, draft } => {
|
||||||
let contact_id = contact_id.to_u32();
|
let contact_id = contact_id.to_u32();
|
||||||
|
|||||||
@@ -210,13 +210,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
if msg.get_viewtype() == Viewtype::VideochatInvitation {
|
if msg.get_viewtype() == Viewtype::Webxdc {
|
||||||
format!(
|
|
||||||
"[VIDEOCHAT-INVITATION: {}, type={}]",
|
|
||||||
msg.get_videochat_url().unwrap_or_default(),
|
|
||||||
msg.get_videochat_type().unwrap_or_default()
|
|
||||||
)
|
|
||||||
} else if msg.get_viewtype() == Viewtype::Webxdc {
|
|
||||||
match msg.get_webxdc_info(context).await {
|
match msg.get_webxdc_info(context).await {
|
||||||
Ok(info) => format!(
|
Ok(info) => format!(
|
||||||
"[WEBXDC: {}, icon={}, document={}, summary={}, source_code_url={}]",
|
"[WEBXDC: {}, icon={}, document={}, summary={}, source_code_url={}]",
|
||||||
@@ -371,7 +365,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
sendhtml <file for html-part> [<text for plain-part>]\n\
|
sendhtml <file for html-part> [<text for plain-part>]\n\
|
||||||
sendsyncmsg\n\
|
sendsyncmsg\n\
|
||||||
sendupdate <msg-id> <json status update>\n\
|
sendupdate <msg-id> <json status update>\n\
|
||||||
videochat\n\
|
|
||||||
draft [<text>]\n\
|
draft [<text>]\n\
|
||||||
devicemsg <text>\n\
|
devicemsg <text>\n\
|
||||||
listmedia\n\
|
listmedia\n\
|
||||||
@@ -962,10 +955,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
let msg_id = MsgId::new(arg1.parse()?);
|
let msg_id = MsgId::new(arg1.parse()?);
|
||||||
context.send_webxdc_status_update(msg_id, arg2).await?;
|
context.send_webxdc_status_update(msg_id, arg2).await?;
|
||||||
}
|
}
|
||||||
"videochat" => {
|
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
|
||||||
chat::send_videochat_invitation(&context, sel_chat.as_ref().unwrap().get_id()).await?;
|
|
||||||
}
|
|
||||||
"listmsgs" => {
|
"listmsgs" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <query> missing.");
|
ensure!(!arg1.is_empty(), "Argument <query> missing.");
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ const DB_COMMANDS: [&str; 11] = [
|
|||||||
"housekeeping",
|
"housekeeping",
|
||||||
];
|
];
|
||||||
|
|
||||||
const CHAT_COMMANDS: [&str; 39] = [
|
const CHAT_COMMANDS: [&str; 38] = [
|
||||||
"listchats",
|
"listchats",
|
||||||
"listarchived",
|
"listarchived",
|
||||||
"start-realtime",
|
"start-realtime",
|
||||||
@@ -206,7 +206,6 @@ const CHAT_COMMANDS: [&str; 39] = [
|
|||||||
"sendhtml",
|
"sendhtml",
|
||||||
"sendsyncmsg",
|
"sendsyncmsg",
|
||||||
"sendupdate",
|
"sendupdate",
|
||||||
"videochat",
|
|
||||||
"draft",
|
"draft",
|
||||||
"devicemsg",
|
"devicemsg",
|
||||||
"listmedia",
|
"listmedia",
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ class ViewType(str, Enum):
|
|||||||
VOICE = "Voice"
|
VOICE = "Voice"
|
||||||
VIDEO = "Video"
|
VIDEO = "Video"
|
||||||
FILE = "File"
|
FILE = "File"
|
||||||
VIDEOCHAT_INVITATION = "VideochatInvitation"
|
|
||||||
WEBXDC = "Webxdc"
|
WEBXDC = "Webxdc"
|
||||||
VCARD = "Vcard"
|
VCARD = "Vcard"
|
||||||
|
|
||||||
@@ -279,11 +278,3 @@ class SocketSecurity(IntEnum):
|
|||||||
SSL = 1
|
SSL = 1
|
||||||
STARTTLS = 2
|
STARTTLS = 2
|
||||||
PLAIN = 3
|
PLAIN = 3
|
||||||
|
|
||||||
|
|
||||||
class VideochatType(IntEnum):
|
|
||||||
"""Video chat URL type."""
|
|
||||||
|
|
||||||
UNKNOWN = 0
|
|
||||||
BASICWEBRTC = 1
|
|
||||||
JITSI = 2
|
|
||||||
|
|||||||
@@ -435,10 +435,6 @@ class Message:
|
|||||||
"""return True if it's a video message."""
|
"""return True if it's a video message."""
|
||||||
return self._view_type == const.DC_MSG_VIDEO
|
return self._view_type == const.DC_MSG_VIDEO
|
||||||
|
|
||||||
def is_videochat_invitation(self):
|
|
||||||
"""return True if it's a videochat invitation message."""
|
|
||||||
return self._view_type == const.DC_MSG_VIDEOCHAT_INVITATION
|
|
||||||
|
|
||||||
def is_webxdc(self):
|
def is_webxdc(self):
|
||||||
"""return True if it's a Webxdc message."""
|
"""return True if it's a Webxdc message."""
|
||||||
return self._view_type == const.DC_MSG_WEBXDC
|
return self._view_type == const.DC_MSG_WEBXDC
|
||||||
@@ -479,7 +475,6 @@ _view_type_mapping = {
|
|||||||
"video": const.DC_MSG_VIDEO,
|
"video": const.DC_MSG_VIDEO,
|
||||||
"file": const.DC_MSG_FILE,
|
"file": const.DC_MSG_FILE,
|
||||||
"sticker": const.DC_MSG_STICKER,
|
"sticker": const.DC_MSG_STICKER,
|
||||||
"videochat": const.DC_MSG_VIDEOCHAT_INVITATION,
|
|
||||||
"webxdc": const.DC_MSG_WEBXDC,
|
"webxdc": const.DC_MSG_WEBXDC,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
src/chat.rs
37
src/chat.rs
@@ -2691,10 +2691,7 @@ impl ChatIdBlocked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|
async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|
||||||
if msg.viewtype == Viewtype::Text
|
if msg.viewtype == Viewtype::Text || msg.viewtype == Viewtype::Call {
|
||||||
|| msg.viewtype == Viewtype::VideochatInvitation
|
|
||||||
|| msg.viewtype == Viewtype::Call
|
|
||||||
{
|
|
||||||
// the caller should check if the message text is empty
|
// the caller should check if the message text is empty
|
||||||
} else if msg.viewtype.has_file() {
|
} else if msg.viewtype.has_file() {
|
||||||
let viewtype_orig = msg.viewtype;
|
let viewtype_orig = msg.viewtype;
|
||||||
@@ -3165,10 +3162,6 @@ pub async fn send_edit_request(context: &Context, msg_id: MsgId, new_text: Strin
|
|||||||
);
|
);
|
||||||
ensure!(!original_msg.is_info(), "Cannot edit info messages");
|
ensure!(!original_msg.is_info(), "Cannot edit info messages");
|
||||||
ensure!(!original_msg.has_html(), "Cannot edit HTML messages");
|
ensure!(!original_msg.has_html(), "Cannot edit HTML messages");
|
||||||
ensure!(
|
|
||||||
original_msg.viewtype != Viewtype::VideochatInvitation,
|
|
||||||
"Cannot edit videochat invitations"
|
|
||||||
);
|
|
||||||
ensure!(original_msg.viewtype != Viewtype::Call, "Cannot edit calls");
|
ensure!(original_msg.viewtype != Viewtype::Call, "Cannot edit calls");
|
||||||
ensure!(
|
ensure!(
|
||||||
!original_msg.text.is_empty(), // avoid complexity in UI element changes. focus is typos and rewordings
|
!original_msg.text.is_empty(), // avoid complexity in UI element changes. focus is typos and rewordings
|
||||||
@@ -3217,34 +3210,6 @@ pub(crate) async fn save_text_edit_to_db(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends invitation to a videochat.
|
|
||||||
pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Result<MsgId> {
|
|
||||||
ensure!(
|
|
||||||
!chat_id.is_special(),
|
|
||||||
"video chat invitation cannot be sent to special chat: {}",
|
|
||||||
chat_id
|
|
||||||
);
|
|
||||||
|
|
||||||
let instance = if let Some(instance) = context.get_config(Config::WebrtcInstance).await? {
|
|
||||||
if !instance.is_empty() {
|
|
||||||
instance
|
|
||||||
} else {
|
|
||||||
bail!("webrtc_instance is empty");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bail!("webrtc_instance not set");
|
|
||||||
};
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance(&instance, &create_id());
|
|
||||||
|
|
||||||
let mut msg = Message::new(Viewtype::VideochatInvitation);
|
|
||||||
msg.param.set(Param::WebrtcRoom, &instance);
|
|
||||||
msg.text =
|
|
||||||
stock_str::videochat_invite_msg_body(context, &Message::parse_webrtc_instance(&instance).1)
|
|
||||||
.await;
|
|
||||||
send_msg(context, chat_id, &mut msg).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn donation_request_maybe(context: &Context) -> Result<()> {
|
async fn donation_request_maybe(context: &Context) -> Result<()> {
|
||||||
let secs_between_checks = 30 * 24 * 60 * 60;
|
let secs_between_checks = 30 * 24 * 60 * 60;
|
||||||
let now = time();
|
let now = time();
|
||||||
|
|||||||
@@ -4568,17 +4568,6 @@ async fn test_cannot_send_edit_request() -> Result<()> {
|
|||||||
.is_err()
|
.is_err()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Videochat invitations cannot be edited
|
|
||||||
alice
|
|
||||||
.set_config(Config::WebrtcInstance, Some("https://foo.bar"))
|
|
||||||
.await?;
|
|
||||||
let msg_id = send_videochat_invitation(alice, chat_id).await?;
|
|
||||||
assert!(
|
|
||||||
send_edit_request(alice, msg_id, "bar".to_string())
|
|
||||||
.await
|
|
||||||
.is_err()
|
|
||||||
);
|
|
||||||
|
|
||||||
// If not text was given initally, there is nothing to edit
|
// If not text was given initally, there is nothing to edit
|
||||||
// (this also avoids complexity in UI element changes; focus is typos and rewordings)
|
// (this also avoids complexity in UI element changes; focus is typos and rewordings)
|
||||||
let mut msg = Message::new(Viewtype::File);
|
let mut msg = Message::new(Viewtype::File);
|
||||||
|
|||||||
@@ -346,9 +346,6 @@ pub enum Config {
|
|||||||
/// Unset, when quota falls below minimal warning threshold again.
|
/// Unset, when quota falls below minimal warning threshold again.
|
||||||
QuotaExceeding,
|
QuotaExceeding,
|
||||||
|
|
||||||
/// address to webrtc instance to use for videochats
|
|
||||||
WebrtcInstance,
|
|
||||||
|
|
||||||
/// Timestamp of the last time housekeeping was run
|
/// Timestamp of the last time housekeeping was run
|
||||||
LastHousekeeping,
|
LastHousekeeping,
|
||||||
|
|
||||||
|
|||||||
@@ -60,23 +60,6 @@ pub enum MediaQuality {
|
|||||||
Worse = 1,
|
Worse = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Video chat URL type.
|
|
||||||
#[derive(
|
|
||||||
Debug, Default, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql,
|
|
||||||
)]
|
|
||||||
#[repr(i8)]
|
|
||||||
pub enum VideochatType {
|
|
||||||
/// Unknown type.
|
|
||||||
#[default]
|
|
||||||
Unknown = 0,
|
|
||||||
|
|
||||||
/// [basicWebRTC](https://github.com/cracker0dks/basicwebrtc) instance.
|
|
||||||
BasicWebrtc = 1,
|
|
||||||
|
|
||||||
/// [Jitsi Meet](https://jitsi.org/jitsi-meet/) instance.
|
|
||||||
Jitsi = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
|
pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
|
||||||
pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02;
|
pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02;
|
||||||
pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04;
|
pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04;
|
||||||
@@ -308,16 +291,4 @@ mod tests {
|
|||||||
assert_eq!(MediaQuality::Balanced, MediaQuality::from_i32(0).unwrap());
|
assert_eq!(MediaQuality::Balanced, MediaQuality::from_i32(0).unwrap());
|
||||||
assert_eq!(MediaQuality::Worse, MediaQuality::from_i32(1).unwrap());
|
assert_eq!(MediaQuality::Worse, MediaQuality::from_i32(1).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_videochattype_values() {
|
|
||||||
// values may be written to disk and must not change
|
|
||||||
assert_eq!(VideochatType::Unknown, VideochatType::default());
|
|
||||||
assert_eq!(VideochatType::Unknown, VideochatType::from_i32(0).unwrap());
|
|
||||||
assert_eq!(
|
|
||||||
VideochatType::BasicWebrtc,
|
|
||||||
VideochatType::from_i32(1).unwrap()
|
|
||||||
);
|
|
||||||
assert_eq!(VideochatType::Jitsi, VideochatType::from_i32(2).unwrap());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -972,12 +972,6 @@ impl Context {
|
|||||||
res.insert("private_key_count", prv_key_cnt.to_string());
|
res.insert("private_key_count", prv_key_cnt.to_string());
|
||||||
res.insert("public_key_count", pub_key_cnt.to_string());
|
res.insert("public_key_count", pub_key_cnt.to_string());
|
||||||
res.insert("fingerprint", fingerprint_str);
|
res.insert("fingerprint", fingerprint_str);
|
||||||
res.insert(
|
|
||||||
"webrtc_instance",
|
|
||||||
self.get_config(Config::WebrtcInstance)
|
|
||||||
.await?
|
|
||||||
.unwrap_or_else(|| "<unset>".to_string()),
|
|
||||||
);
|
|
||||||
res.insert(
|
res.insert(
|
||||||
"media_quality",
|
"media_quality",
|
||||||
self.get_config_int(Config::MediaQuality).await?.to_string(),
|
self.get_config_int(Config::MediaQuality).await?.to_string(),
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ use crate::blob::BlobObject;
|
|||||||
use crate::chat::{Chat, ChatId, ChatIdBlocked, ChatVisibility, send_msg};
|
use crate::chat::{Chat, ChatId, ChatIdBlocked, ChatVisibility, send_msg};
|
||||||
use crate::chatlist_events;
|
use crate::chatlist_events;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::constants::{
|
use crate::constants::{Blocked, Chattype, DC_CHAT_ID_TRASH, DC_MSG_ID_LAST_SPECIAL};
|
||||||
Blocked, Chattype, DC_CHAT_ID_TRASH, DC_MSG_ID_LAST_SPECIAL, VideochatType,
|
|
||||||
};
|
|
||||||
use crate::contact::{self, Contact, ContactId};
|
use crate::contact::{self, Contact, ContactId};
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::debug_logging::set_debug_logging_xdc;
|
use crate::debug_logging::set_debug_logging_xdc;
|
||||||
@@ -1017,85 +1015,6 @@ impl Message {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// add room to a webrtc_instance as defined by the corresponding config-value;
|
|
||||||
// the result may still be prefixed by the type
|
|
||||||
pub(crate) fn create_webrtc_instance(instance: &str, room: &str) -> String {
|
|
||||||
let (videochat_type, mut url) = Message::parse_webrtc_instance(instance);
|
|
||||||
|
|
||||||
// make sure, there is a scheme in the url
|
|
||||||
if !url.contains(':') {
|
|
||||||
url = format!("https://{url}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// add/replace room
|
|
||||||
let url = if url.contains("$ROOM") {
|
|
||||||
url.replace("$ROOM", room)
|
|
||||||
} else if url.contains("$NOROOM") {
|
|
||||||
// there are some usecases where a separate room is not needed to use a service
|
|
||||||
// eg. if you let in people manually anyway, see discussion at
|
|
||||||
// <https://support.delta.chat/t/videochat-with-webex/1412/4>.
|
|
||||||
// hacks as hiding the room behind `#` are not reliable, therefore,
|
|
||||||
// these services are supported by adding the string `$NOROOM` to the url.
|
|
||||||
url.replace("$NOROOM", "")
|
|
||||||
} else {
|
|
||||||
// if there nothing that would separate the room, add a slash as a separator;
|
|
||||||
// this way, urls can be given as "https://meet.jit.si" as well as "https://meet.jit.si/"
|
|
||||||
let maybe_slash = if url.ends_with('/')
|
|
||||||
|| url.ends_with('?')
|
|
||||||
|| url.ends_with('#')
|
|
||||||
|| url.ends_with('=')
|
|
||||||
{
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
"/"
|
|
||||||
};
|
|
||||||
format!("{url}{maybe_slash}{room}")
|
|
||||||
};
|
|
||||||
|
|
||||||
// re-add and normalize type
|
|
||||||
match videochat_type {
|
|
||||||
VideochatType::BasicWebrtc => format!("basicwebrtc:{url}"),
|
|
||||||
VideochatType::Jitsi => format!("jitsi:{url}"),
|
|
||||||
VideochatType::Unknown => url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 instance: String = instance.split_whitespace().collect();
|
|
||||||
let mut split = instance.splitn(2, ':');
|
|
||||||
let type_str = split.next().unwrap_or_default().to_lowercase();
|
|
||||||
let url = split.next();
|
|
||||||
match type_str.as_str() {
|
|
||||||
"basicwebrtc" => (
|
|
||||||
VideochatType::BasicWebrtc,
|
|
||||||
url.unwrap_or_default().to_string(),
|
|
||||||
),
|
|
||||||
"jitsi" => (VideochatType::Jitsi, url.unwrap_or_default().to_string()),
|
|
||||||
_ => (VideochatType::Unknown, instance.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns videochat URL if the message is a videochat invitation.
|
|
||||||
pub fn get_videochat_url(&self) -> Option<String> {
|
|
||||||
if self.viewtype == Viewtype::VideochatInvitation {
|
|
||||||
if let Some(instance) = self.param.get(Param::WebrtcRoom) {
|
|
||||||
return Some(Message::parse_webrtc_instance(instance).1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns videochat type if the message is a videochat invitation.
|
|
||||||
pub fn get_videochat_type(&self) -> Option<VideochatType> {
|
|
||||||
if self.viewtype == Viewtype::VideochatInvitation {
|
|
||||||
if let Some(instance) = self.param.get(Param::WebrtcRoom) {
|
|
||||||
return Some(Message::parse_webrtc_instance(instance).0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets or unsets message text.
|
/// Sets or unsets message text.
|
||||||
pub fn set_text(&mut self, text: String) {
|
pub fn set_text(&mut self, text: String) {
|
||||||
self.text = text;
|
self.text = text;
|
||||||
@@ -2277,9 +2196,6 @@ pub enum Viewtype {
|
|||||||
/// and retrieved via dc_msg_get_file().
|
/// and retrieved via dc_msg_get_file().
|
||||||
File = 60,
|
File = 60,
|
||||||
|
|
||||||
/// Message is an invitation to a videochat.
|
|
||||||
VideochatInvitation = 70,
|
|
||||||
|
|
||||||
/// Message is an incoming or outgoing call.
|
/// Message is an incoming or outgoing call.
|
||||||
Call = 71,
|
Call = 71,
|
||||||
|
|
||||||
@@ -2305,7 +2221,6 @@ impl Viewtype {
|
|||||||
Viewtype::Voice => true,
|
Viewtype::Voice => true,
|
||||||
Viewtype::Video => true,
|
Viewtype::Video => true,
|
||||||
Viewtype::File => true,
|
Viewtype::File => true,
|
||||||
Viewtype::VideochatInvitation => false,
|
|
||||||
Viewtype::Call => false,
|
Viewtype::Call => false,
|
||||||
Viewtype::Webxdc => true,
|
Viewtype::Webxdc => true,
|
||||||
Viewtype::Vcard => true,
|
Viewtype::Vcard => true,
|
||||||
|
|||||||
@@ -25,82 +25,6 @@ fn test_guess_msgtype_from_suffix() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
||||||
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");
|
|
||||||
|
|
||||||
let (webrtc_type, url) = Message::parse_webrtc_instance("jitsi:https://j.si/foo");
|
|
||||||
assert_eq!(webrtc_type, VideochatType::Jitsi);
|
|
||||||
assert_eq!(url, "https://j.si/foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
||||||
async fn test_create_webrtc_instance() {
|
|
||||||
// webrtc_instance may come from an input field of the ui, be pretty tolerant on input
|
|
||||||
let instance = Message::create_webrtc_instance("https://meet.jit.si/", "123");
|
|
||||||
assert_eq!(instance, "https://meet.jit.si/123");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("https://meet.jit.si", "456");
|
|
||||||
assert_eq!(instance, "https://meet.jit.si/456");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("meet.jit.si", "789");
|
|
||||||
assert_eq!(instance, "https://meet.jit.si/789");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("bla.foo?", "123");
|
|
||||||
assert_eq!(instance, "https://bla.foo?123");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("jitsi:bla.foo#", "456");
|
|
||||||
assert_eq!(instance, "jitsi:https://bla.foo#456");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("bla.foo#room=", "789");
|
|
||||||
assert_eq!(instance, "https://bla.foo#room=789");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("https://bla.foo#room", "123");
|
|
||||||
assert_eq!(instance, "https://bla.foo#room/123");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("bla.foo#room$ROOM", "123");
|
|
||||||
assert_eq!(instance, "https://bla.foo#room123");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance("bla.foo#room=$ROOM&after=cont", "234");
|
|
||||||
assert_eq!(instance, "https://bla.foo#room=234&after=cont");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance(" meet.jit .si ", "789");
|
|
||||||
assert_eq!(instance, "https://meet.jit.si/789");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance(" basicwebrtc: basic . stuff\n ", "12345ab");
|
|
||||||
assert_eq!(instance, "basicwebrtc:https://basic.stuff/12345ab");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
||||||
async fn test_create_webrtc_instance_noroom() {
|
|
||||||
// webrtc_instance may come from an input field of the ui, be pretty tolerant on input
|
|
||||||
let instance = Message::create_webrtc_instance("bla.foo$NOROOM", "123");
|
|
||||||
assert_eq!(instance, "https://bla.foo");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance(" bla . foo $NOROOM ", "456");
|
|
||||||
assert_eq!(instance, "https://bla.foo");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance(" $NOROOM bla . foo ", "789");
|
|
||||||
assert_eq!(instance, "https://bla.foo");
|
|
||||||
|
|
||||||
let instance = Message::create_webrtc_instance(" bla.foo / $NOROOM ? a = b ", "123");
|
|
||||||
assert_eq!(instance, "https://bla.foo/?a=b");
|
|
||||||
|
|
||||||
// $ROOM has a higher precedence
|
|
||||||
let instance = Message::create_webrtc_instance("bla.foo/?$NOROOM=$ROOM", "123");
|
|
||||||
assert_eq!(instance, "https://bla.foo/?$NOROOM=123");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_get_width_height() {
|
async fn test_get_width_height() {
|
||||||
let t = TestContext::new_alice().await;
|
let t = TestContext::new_alice().await;
|
||||||
@@ -648,10 +572,6 @@ fn test_viewtype_values() {
|
|||||||
assert_eq!(Viewtype::Voice, Viewtype::from_i32(41).unwrap());
|
assert_eq!(Viewtype::Voice, Viewtype::from_i32(41).unwrap());
|
||||||
assert_eq!(Viewtype::Video, Viewtype::from_i32(50).unwrap());
|
assert_eq!(Viewtype::Video, Viewtype::from_i32(50).unwrap());
|
||||||
assert_eq!(Viewtype::File, Viewtype::from_i32(60).unwrap());
|
assert_eq!(Viewtype::File, Viewtype::from_i32(60).unwrap());
|
||||||
assert_eq!(
|
|
||||||
Viewtype::VideochatInvitation,
|
|
||||||
Viewtype::from_i32(70).unwrap()
|
|
||||||
);
|
|
||||||
assert_eq!(Viewtype::Webxdc, Viewtype::from_i32(80).unwrap());
|
assert_eq!(Viewtype::Webxdc, Viewtype::from_i32(80).unwrap());
|
||||||
assert_eq!(Viewtype::Vcard, Viewtype::from_i32(90).unwrap());
|
assert_eq!(Viewtype::Vcard, Viewtype::from_i32(90).unwrap());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1565,11 +1565,6 @@ impl MimeFactory {
|
|||||||
"Chat-Content",
|
"Chat-Content",
|
||||||
mail_builder::headers::raw::Raw::new("sticker").into(),
|
mail_builder::headers::raw::Raw::new("sticker").into(),
|
||||||
));
|
));
|
||||||
} else if msg.viewtype == Viewtype::VideochatInvitation {
|
|
||||||
headers.push((
|
|
||||||
"Chat-Content",
|
|
||||||
mail_builder::headers::raw::Raw::new("videochat-invitation").into(),
|
|
||||||
));
|
|
||||||
} else if msg.viewtype == Viewtype::Call {
|
} else if msg.viewtype == Viewtype::Call {
|
||||||
headers.push((
|
headers.push((
|
||||||
"Chat-Content",
|
"Chat-Content",
|
||||||
|
|||||||
@@ -732,12 +732,10 @@ impl MimeMessage {
|
|||||||
.map(|s| s.to_string());
|
.map(|s| s.to_string());
|
||||||
if let Some(part) = self.parts.first_mut() {
|
if let Some(part) = self.parts.first_mut() {
|
||||||
if let Some(room) = room {
|
if let Some(room) = room {
|
||||||
if content == "videochat-invitation" {
|
if content == "call" {
|
||||||
part.typ = Viewtype::VideochatInvitation;
|
part.typ = Viewtype::Call;
|
||||||
} else if content == "call" {
|
part.param.set(Param::WebrtcRoom, room);
|
||||||
part.typ = Viewtype::Call
|
|
||||||
}
|
}
|
||||||
part.param.set(Param::WebrtcRoom, room);
|
|
||||||
} else if let Some(accepted) = accepted {
|
} else if let Some(accepted) = accepted {
|
||||||
part.param.set(Param::WebrtcAccepted, accepted);
|
part.param.set(Param::WebrtcAccepted, accepted);
|
||||||
}
|
}
|
||||||
@@ -765,10 +763,7 @@ impl MimeMessage {
|
|||||||
| Viewtype::Vcard
|
| Viewtype::Vcard
|
||||||
| Viewtype::File
|
| Viewtype::File
|
||||||
| Viewtype::Webxdc => true,
|
| Viewtype::Webxdc => true,
|
||||||
Viewtype::Unknown
|
Viewtype::Unknown | Viewtype::Text | Viewtype::Call => false,
|
||||||
| Viewtype::Text
|
|
||||||
| Viewtype::VideochatInvitation
|
|
||||||
| Viewtype::Call => false,
|
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
let mut parts = std::mem::take(&mut self.parts);
|
let mut parts = std::mem::take(&mut self.parts);
|
||||||
|
|||||||
@@ -476,6 +476,10 @@ async fn test_mimeparser_with_avatars() {
|
|||||||
assert!(mimeparser.group_avatar.unwrap().is_change());
|
assert!(mimeparser.group_avatar.unwrap().is_change());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tests that video chat invitations that are not supported anymore
|
||||||
|
/// are displayed as text messages.
|
||||||
|
///
|
||||||
|
/// User can still click on the link manually.
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_mimeparser_with_videochat() {
|
async fn test_mimeparser_with_videochat() {
|
||||||
let t = TestContext::new_alice().await;
|
let t = TestContext::new_alice().await;
|
||||||
@@ -483,14 +487,8 @@ async fn test_mimeparser_with_videochat() {
|
|||||||
let raw = include_bytes!("../../test-data/message/videochat_invitation.eml");
|
let raw = include_bytes!("../../test-data/message/videochat_invitation.eml");
|
||||||
let mimeparser = MimeMessage::from_bytes(&t, &raw[..], None).await.unwrap();
|
let mimeparser = MimeMessage::from_bytes(&t, &raw[..], None).await.unwrap();
|
||||||
assert_eq!(mimeparser.parts.len(), 1);
|
assert_eq!(mimeparser.parts.len(), 1);
|
||||||
assert_eq!(mimeparser.parts[0].typ, Viewtype::VideochatInvitation);
|
assert_eq!(mimeparser.parts[0].typ, Viewtype::Text);
|
||||||
assert_eq!(
|
assert_eq!(mimeparser.parts[0].param.get(Param::WebrtcRoom), None);
|
||||||
mimeparser.parts[0]
|
|
||||||
.param
|
|
||||||
.get(Param::WebrtcRoom)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
"https://example.org/p2p/?roomname=6HiduoAn4xN"
|
|
||||||
);
|
|
||||||
assert!(
|
assert!(
|
||||||
mimeparser.parts[0]
|
mimeparser.parts[0]
|
||||||
.msg
|
.msg
|
||||||
|
|||||||
43
src/qr.rs
43
src/qr.rs
@@ -16,7 +16,6 @@ use crate::contact::{Contact, ContactId, Origin};
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::events::EventType;
|
use crate::events::EventType;
|
||||||
use crate::key::Fingerprint;
|
use crate::key::Fingerprint;
|
||||||
use crate::message::Message;
|
|
||||||
use crate::net::http::post_empty;
|
use crate::net::http::post_empty;
|
||||||
use crate::net::proxy::{DEFAULT_SOCKS_PORT, ProxyConfig};
|
use crate::net::proxy::{DEFAULT_SOCKS_PORT, ProxyConfig};
|
||||||
use crate::token;
|
use crate::token;
|
||||||
@@ -27,7 +26,6 @@ const IDELTACHAT_SCHEME: &str = "https://i.delta.chat/#";
|
|||||||
const IDELTACHAT_NOSLASH_SCHEME: &str = "https://i.delta.chat#";
|
const IDELTACHAT_NOSLASH_SCHEME: &str = "https://i.delta.chat#";
|
||||||
const DCACCOUNT_SCHEME: &str = "DCACCOUNT:";
|
const DCACCOUNT_SCHEME: &str = "DCACCOUNT:";
|
||||||
pub(super) const DCLOGIN_SCHEME: &str = "DCLOGIN:";
|
pub(super) const DCLOGIN_SCHEME: &str = "DCLOGIN:";
|
||||||
const DCWEBRTC_SCHEME: &str = "DCWEBRTC:";
|
|
||||||
const TG_SOCKS_SCHEME: &str = "https://t.me/socks";
|
const TG_SOCKS_SCHEME: &str = "https://t.me/socks";
|
||||||
const MAILTO_SCHEME: &str = "mailto:";
|
const MAILTO_SCHEME: &str = "mailto:";
|
||||||
const MATMSG_SCHEME: &str = "MATMSG:";
|
const MATMSG_SCHEME: &str = "MATMSG:";
|
||||||
@@ -122,15 +120,6 @@ pub enum Qr {
|
|||||||
/// The QR code is a backup, but it is too new. The user has to update its Delta Chat.
|
/// The QR code is a backup, but it is too new. The user has to update its Delta Chat.
|
||||||
BackupTooNew {},
|
BackupTooNew {},
|
||||||
|
|
||||||
/// Ask the user if they want to use the given service for video chats.
|
|
||||||
WebrtcInstance {
|
|
||||||
/// Server domain name.
|
|
||||||
domain: String,
|
|
||||||
|
|
||||||
/// URL pattern for video chat rooms.
|
|
||||||
instance_pattern: String,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Ask the user if they want to use the given proxy.
|
/// Ask the user if they want to use the given proxy.
|
||||||
///
|
///
|
||||||
/// Note that HTTP(S) URLs without a path
|
/// Note that HTTP(S) URLs without a path
|
||||||
@@ -294,8 +283,6 @@ pub async fn check_qr(context: &Context, qr: &str) -> Result<Qr> {
|
|||||||
decode_account(qr)?
|
decode_account(qr)?
|
||||||
} else if starts_with_ignore_case(qr, DCLOGIN_SCHEME) {
|
} else if starts_with_ignore_case(qr, DCLOGIN_SCHEME) {
|
||||||
dclogin_scheme::decode_login(qr)?
|
dclogin_scheme::decode_login(qr)?
|
||||||
} else if starts_with_ignore_case(qr, DCWEBRTC_SCHEME) {
|
|
||||||
decode_webrtc_instance(context, qr)?
|
|
||||||
} else if starts_with_ignore_case(qr, TG_SOCKS_SCHEME) {
|
} else if starts_with_ignore_case(qr, TG_SOCKS_SCHEME) {
|
||||||
decode_tg_socks_proxy(context, qr)?
|
decode_tg_socks_proxy(context, qr)?
|
||||||
} else if qr.starts_with(SHADOWSOCKS_SCHEME) {
|
} else if qr.starts_with(SHADOWSOCKS_SCHEME) {
|
||||||
@@ -573,28 +560,6 @@ fn decode_account(qr: &str) -> Result<Qr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// scheme: `DCWEBRTC:https://meet.jit.si/$ROOM`
|
|
||||||
fn decode_webrtc_instance(_context: &Context, qr: &str) -> Result<Qr> {
|
|
||||||
let payload = qr
|
|
||||||
.get(DCWEBRTC_SCHEME.len()..)
|
|
||||||
.context("Invalid DCWEBRTC payload")?;
|
|
||||||
|
|
||||||
let (_type, url) = Message::parse_webrtc_instance(payload);
|
|
||||||
let url = url::Url::parse(&url).context("Invalid WebRTC instance")?;
|
|
||||||
|
|
||||||
if url.scheme() == "http" || url.scheme() == "https" {
|
|
||||||
Ok(Qr::WebrtcInstance {
|
|
||||||
domain: url
|
|
||||||
.host_str()
|
|
||||||
.context("can't extract WebRTC instance domain")?
|
|
||||||
.to_string(),
|
|
||||||
instance_pattern: payload.to_string(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
bail!("Bad URL scheme for WebRTC instance: {:?}", url.scheme());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// scheme: `https://t.me/socks?server=foo&port=123` or `https://t.me/socks?server=1.2.3.4&port=123`
|
/// scheme: `https://t.me/socks?server=foo&port=123` or `https://t.me/socks?server=1.2.3.4&port=123`
|
||||||
fn decode_tg_socks_proxy(_context: &Context, qr: &str) -> Result<Qr> {
|
fn decode_tg_socks_proxy(_context: &Context, qr: &str) -> Result<Qr> {
|
||||||
let url = url::Url::parse(qr).context("Invalid t.me/socks url")?;
|
let url = url::Url::parse(qr).context("Invalid t.me/socks url")?;
|
||||||
@@ -732,14 +697,6 @@ pub(crate) async fn set_account_from_qr(context: &Context, qr: &str) -> Result<(
|
|||||||
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> {
|
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> {
|
||||||
match check_qr(context, qr).await? {
|
match check_qr(context, qr).await? {
|
||||||
Qr::Account { .. } => set_account_from_qr(context, qr).await?,
|
Qr::Account { .. } => set_account_from_qr(context, qr).await?,
|
||||||
Qr::WebrtcInstance {
|
|
||||||
domain: _,
|
|
||||||
instance_pattern,
|
|
||||||
} => {
|
|
||||||
context
|
|
||||||
.set_config_internal(Config::WebrtcInstance, Some(&instance_pattern))
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Qr::Proxy { url, .. } => {
|
Qr::Proxy { url, .. } => {
|
||||||
let old_proxy_url_value = context
|
let old_proxy_url_value = context
|
||||||
.get_config(Config::ProxyUrl)
|
.get_config(Config::ProxyUrl)
|
||||||
|
|||||||
@@ -712,32 +712,6 @@ async fn test_decode_account() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
||||||
async fn test_decode_webrtc_instance() -> Result<()> {
|
|
||||||
let ctx = TestContext::new().await;
|
|
||||||
|
|
||||||
let qr = check_qr(&ctx.ctx, "DCWEBRTC:basicwebrtc:https://basicurl.com/$ROOM").await?;
|
|
||||||
assert_eq!(
|
|
||||||
qr,
|
|
||||||
Qr::WebrtcInstance {
|
|
||||||
domain: "basicurl.com".to_string(),
|
|
||||||
instance_pattern: "basicwebrtc:https://basicurl.com/$ROOM".to_string()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test it again with mixcased "dcWebRTC:" uri scheme
|
|
||||||
let qr = check_qr(&ctx.ctx, "dcWebRTC:https://example.org/").await?;
|
|
||||||
assert_eq!(
|
|
||||||
qr,
|
|
||||||
Qr::WebrtcInstance {
|
|
||||||
domain: "example.org".to_string(),
|
|
||||||
instance_pattern: "https://example.org/".to_string()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_decode_tg_socks_proxy() -> Result<()> {
|
async fn test_decode_tg_socks_proxy() -> Result<()> {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
@@ -820,34 +794,6 @@ async fn test_decode_account_bad_scheme() {
|
|||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
||||||
async fn test_set_webrtc_instance_config_from_qr() -> Result<()> {
|
|
||||||
let ctx = TestContext::new().await;
|
|
||||||
|
|
||||||
assert!(ctx.ctx.get_config(Config::WebrtcInstance).await?.is_none());
|
|
||||||
|
|
||||||
let res = set_config_from_qr(&ctx.ctx, "badqr:https://example.org/").await;
|
|
||||||
assert!(res.is_err());
|
|
||||||
assert!(ctx.ctx.get_config(Config::WebrtcInstance).await?.is_none());
|
|
||||||
|
|
||||||
let res = set_config_from_qr(&ctx.ctx, "dcwebrtc:https://example.org/").await;
|
|
||||||
assert!(res.is_ok());
|
|
||||||
assert_eq!(
|
|
||||||
ctx.ctx.get_config(Config::WebrtcInstance).await?.unwrap(),
|
|
||||||
"https://example.org/"
|
|
||||||
);
|
|
||||||
|
|
||||||
let res =
|
|
||||||
set_config_from_qr(&ctx.ctx, "DCWEBRTC:basicwebrtc:https://foo.bar/?$ROOM&test").await;
|
|
||||||
assert!(res.is_ok());
|
|
||||||
assert_eq!(
|
|
||||||
ctx.ctx.get_config(Config::WebrtcInstance).await?.unwrap(),
|
|
||||||
"basicwebrtc:https://foo.bar/?$ROOM&test"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_set_proxy_config_from_qr() -> Result<()> {
|
async fn test_set_proxy_config_from_qr() -> Result<()> {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
|
|||||||
@@ -130,12 +130,6 @@ pub enum StockMessage {
|
|||||||
#[strum(props(fallback = "Failed to send message to %1$s."))]
|
#[strum(props(fallback = "Failed to send message to %1$s."))]
|
||||||
FailedSendingTo = 74,
|
FailedSendingTo = 74,
|
||||||
|
|
||||||
#[strum(props(fallback = "Video chat invitation"))]
|
|
||||||
VideochatInvitation = 82,
|
|
||||||
|
|
||||||
#[strum(props(fallback = "You are invited to a video chat, click %1$s to join."))]
|
|
||||||
VideochatInviteMsgBody = 83,
|
|
||||||
|
|
||||||
#[strum(props(fallback = "Error:\n\n“%1$s”"))]
|
#[strum(props(fallback = "Error:\n\n“%1$s”"))]
|
||||||
ConfigurationFailed = 84,
|
ConfigurationFailed = 84,
|
||||||
|
|
||||||
@@ -1059,18 +1053,6 @@ pub(crate) async fn msg_ephemeral_timer_year(context: &Context, by_contact: Cont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stock string: `Video chat invitation`.
|
|
||||||
pub(crate) async fn videochat_invitation(context: &Context) -> String {
|
|
||||||
translated(context, StockMessage::VideochatInvitation).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stock string: `You are invited to a video chat, click %1$s to join.`.
|
|
||||||
pub(crate) async fn videochat_invite_msg_body(context: &Context, url: &str) -> String {
|
|
||||||
translated(context, StockMessage::VideochatInviteMsgBody)
|
|
||||||
.await
|
|
||||||
.replace1(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stock string: `Error:\n\n“%1$s”`.
|
/// Stock string: `Error:\n\n“%1$s”`.
|
||||||
pub(crate) async fn configuration_failed(context: &Context, details: &str) -> String {
|
pub(crate) async fn configuration_failed(context: &Context, details: &str) -> String {
|
||||||
translated(context, StockMessage::ConfigurationFailed)
|
translated(context, StockMessage::ConfigurationFailed)
|
||||||
|
|||||||
@@ -211,12 +211,6 @@ impl Message {
|
|||||||
type_file = self.get_filename();
|
type_file = self.get_filename();
|
||||||
append_text = true
|
append_text = true
|
||||||
}
|
}
|
||||||
Viewtype::VideochatInvitation => {
|
|
||||||
emoji = None;
|
|
||||||
type_name = Some(stock_str::videochat_invitation(context).await);
|
|
||||||
type_file = None;
|
|
||||||
append_text = false;
|
|
||||||
}
|
|
||||||
Viewtype::Webxdc => {
|
Viewtype::Webxdc => {
|
||||||
emoji = None;
|
emoji = None;
|
||||||
type_name = None;
|
type_name = None;
|
||||||
@@ -428,13 +422,6 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_summary_texts(&msg, ctx, "📎 foo.bar \u{2013} bla bla").await; // file name is added for files
|
assert_summary_texts(&msg, ctx, "📎 foo.bar \u{2013} bla bla").await; // file name is added for files
|
||||||
|
|
||||||
let file = write_file_to_blobdir(&d).await;
|
|
||||||
let mut msg = Message::new(Viewtype::VideochatInvitation);
|
|
||||||
msg.set_text(some_text.clone());
|
|
||||||
msg.set_file_and_deduplicate(&d, &file, Some("foo.bar"), None)
|
|
||||||
.unwrap();
|
|
||||||
assert_summary_texts(&msg, ctx, "Video chat invitation").await; // text is not added for videochat invitations
|
|
||||||
|
|
||||||
let mut msg = Message::new(Viewtype::Vcard);
|
let mut msg = Message::new(Viewtype::Vcard);
|
||||||
msg.set_file_from_bytes(ctx, "foo.vcf", b"", None).unwrap();
|
msg.set_file_from_bytes(ctx, "foo.vcf", b"", None).unwrap();
|
||||||
chat_id.set_draft(ctx, Some(&mut msg)).await.unwrap();
|
chat_id.set_draft(ctx, Some(&mut msg)).await.unwrap();
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ use crate::context::Context;
|
|||||||
use crate::events::{Event, EventEmitter, EventType, Events};
|
use crate::events::{Event, EventEmitter, EventType, Events};
|
||||||
use crate::key::{self, DcKey, DcSecretKey, self_fingerprint};
|
use crate::key::{self, DcKey, DcSecretKey, self_fingerprint};
|
||||||
use crate::log::warn;
|
use crate::log::warn;
|
||||||
use crate::message::{Message, MessageState, MsgId, Viewtype, update_msg_state};
|
use crate::message::{Message, MessageState, MsgId, update_msg_state};
|
||||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||||
use crate::pgp::KeyPair;
|
use crate::pgp::KeyPair;
|
||||||
use crate::receive_imf::receive_imf;
|
use crate::receive_imf::receive_imf;
|
||||||
@@ -1535,7 +1535,7 @@ async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut Str
|
|||||||
let msgtext = msg.get_text();
|
let msgtext = msg.get_text();
|
||||||
writeln!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
"{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{}",
|
"{}{}{}{}: {} (Contact#{}): {} {}{}{}{}",
|
||||||
prefix,
|
prefix,
|
||||||
msg.get_id(),
|
msg.get_id(),
|
||||||
if msg.get_showpadlock() { "🔒" } else { "" },
|
if msg.get_showpadlock() { "🔒" } else { "" },
|
||||||
@@ -1563,15 +1563,6 @@ async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut Str
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
if msg.get_viewtype() == Viewtype::VideochatInvitation {
|
|
||||||
format!(
|
|
||||||
"[VIDEOCHAT-INVITATION: {}, type={}]",
|
|
||||||
msg.get_videochat_url().unwrap_or_default(),
|
|
||||||
msg.get_videochat_type().unwrap_or_default()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
},
|
|
||||||
if msg.is_forwarded() {
|
if msg.is_forwarded() {
|
||||||
"[FORWARDED]"
|
"[FORWARDED]"
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user