mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
rename w30 to webxdc
This commit is contained in:
@@ -983,39 +983,39 @@ uint32_t dc_send_videochat_invitation (dc_context_t* context, uint32_t chat_id);
|
||||
|
||||
|
||||
/**
|
||||
* An w30 instance send a status update to its other members.
|
||||
* An webxdc instance send a status update to its other members.
|
||||
*
|
||||
* In js-land, that would be mapped to sth. as:
|
||||
* ```
|
||||
* success = window.webxdc.sendUpdate('move A3 B4', '{"action":"move","src":"A3","dest":"B4"}');
|
||||
* ```
|
||||
* `context` and `msg_id` is not needed in js as that is unique within an w30 instance.
|
||||
* See dc_get_w30_status_updates() for the receiving counterpart.
|
||||
* `context` and `msg_id` is not needed in js as that is unique within an webxdc instance.
|
||||
* See dc_get_webxdc_status_updates() for the receiving counterpart.
|
||||
*
|
||||
* If the w30 instance is a draft, the update is not send immediately.
|
||||
* If the webxdc instance is a draft, the update is not send immediately.
|
||||
* Instead, the updates are collected and sent out in batch when the instance is actually sent.
|
||||
* This allows preparing w30 instances,
|
||||
* This allows preparing webxdc instances,
|
||||
* eg. defining a poll with predefined answers.
|
||||
*
|
||||
* Other members will be informed by #DC_EVENT_W30_STATUS_UPDATE that there is a new update.
|
||||
* You will also get the #DC_EVENT_W30_STATUS_UPDATE yourself
|
||||
* and the update you're sent will also be included in dc_get_w30_status_updates().
|
||||
* Other members will be informed by #DC_EVENT_WEBXDC_STATUS_UPDATE that there is a new update.
|
||||
* You will also get the #DC_EVENT_WEBXDC_STATUS_UPDATE yourself
|
||||
* and the update you're sent will also be included in dc_get_webxdc_status_updates().
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object
|
||||
* @param msg_id id of the message with the w30 instance
|
||||
* @param msg_id id of the message with the webxdc instance
|
||||
* @param descr user-visible description of the json-data,
|
||||
* in case of a chess game, eg. the move.
|
||||
* @param json program-readable data, the actual payload
|
||||
* @return 1=success, 0=error
|
||||
*/
|
||||
int dc_send_w30_status_update (dc_context_t* context, uint32_t msg_id, const char* descr, const char* json);
|
||||
int dc_send_webxdc_status_update (dc_context_t* context, uint32_t msg_id, const char* descr, const char* json);
|
||||
|
||||
|
||||
/**
|
||||
* Get status updates.
|
||||
* The status updates may be sent by yourself or by other members using dc_send_w30_status_update().
|
||||
* In both cases, you will be informed by #DC_EVENT_W30_STATUS_UPDATE
|
||||
* The status updates may be sent by yourself or by other members using dc_send_webxdc_status_update().
|
||||
* In both cases, you will be informed by #DC_EVENT_WEBXDC_STATUS_UPDATE
|
||||
* whenever there is a new update.
|
||||
*
|
||||
* In js-land, that would be mapped to sth. as:
|
||||
@@ -1030,15 +1030,15 @@ int dc_send_w30_status_update (dc_context_t* context, uint32_t msg_id, const cha
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object
|
||||
* @param msg_id id of the message with the w30 instance
|
||||
* @param msg_id id of the message with the webxdc instance
|
||||
* @param status_update_id Can be used to filter out only a concrete status update.
|
||||
* When set to 0, all known status updates are returned.
|
||||
* @return JSON-array containing the requested updates,
|
||||
* each element was created by dc_send_w30_status_update()
|
||||
* each element was created by dc_send_webxdc_status_update()
|
||||
* on this or other devices.
|
||||
* If there are no updates, an empty JSON-array is returned.
|
||||
*/
|
||||
char* dc_get_w30_status_updates (dc_context_t* context, uint32_t msg_id, uint32_t status_update_id);
|
||||
char* dc_get_webxdc_status_updates (dc_context_t* context, uint32_t msg_id, uint32_t status_update_id);
|
||||
|
||||
/**
|
||||
* Save a draft for a chat in the database.
|
||||
@@ -3676,17 +3676,17 @@ char* dc_msg_get_filemime (const dc_msg_t* msg);
|
||||
|
||||
|
||||
/**
|
||||
* Return file from inside an archive.
|
||||
* Currently, this works for W30 messages only.
|
||||
* Return file from inside an webxdc message.
|
||||
*
|
||||
* @param msg The W30 instance.
|
||||
* @memberof dc_msg_t
|
||||
* @param msg The webxdc instance.
|
||||
* @param filename The name inside the archive,
|
||||
* must be given as a relative path (no leading `/`).
|
||||
* @param ret_bytes Pointer to a size_t. The size of the blob will be written here.
|
||||
* @return The blob must be released using dc_str_unref() after usage.
|
||||
* NULL if there is no such file in the archive or on errors.
|
||||
*/
|
||||
char* dc_msg_get_blob_from_archive (const dc_msg_t* msg, const char* filename, size_t* ret_bytes);
|
||||
char* dc_msg_get_webxdc_blob (const dc_msg_t* msg, const char* filename, size_t* ret_bytes);
|
||||
|
||||
|
||||
/**
|
||||
@@ -4848,12 +4848,12 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
|
||||
|
||||
/**
|
||||
* w30-Message.
|
||||
* webxdc-Message.
|
||||
* Message with HTML5, CSS and related content.
|
||||
*
|
||||
* To send data to a w30 instance, use dc_send_w30_status_update()
|
||||
* To send data to a webxdc instance, use dc_send_webxdc_status_update()
|
||||
*/
|
||||
#define DC_MSG_W30 80
|
||||
#define DC_MSG_WEBXDC 80
|
||||
|
||||
|
||||
/**
|
||||
@@ -5550,18 +5550,18 @@ void dc_event_unref(dc_event_t* event);
|
||||
|
||||
|
||||
/**
|
||||
* w30 status update received.
|
||||
* To get the received status update, use dc_get_w30_status_updates().
|
||||
* To send status updates, use dc_send_w30_status_update().
|
||||
* webxdc status update received.
|
||||
* To get the received status update, use dc_get_webxdc_status_updates().
|
||||
* To send status updates, use dc_send_webxdc_status_update().
|
||||
*
|
||||
* Note, that you do not get events that arrive when the app is not running;
|
||||
* instead, you can use dc_get_w30_status_updates() to get all status updates
|
||||
* instead, you can use dc_get_webxdc_status_updates() to get all status updates
|
||||
* and catch up that way.
|
||||
*
|
||||
* @param data1 (int) msg_id
|
||||
* @param data2 (int) status_update_id
|
||||
*/
|
||||
#define DC_EVENT_W30_STATUS_UPDATE 2120
|
||||
#define DC_EVENT_WEBXDC_STATUS_UPDATE 2120
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,7 @@ use deltachat::ephemeral::Timer as EphemeralTimer;
|
||||
use deltachat::key::DcKey;
|
||||
use deltachat::message::MsgId;
|
||||
use deltachat::stock_str::StockMessage;
|
||||
use deltachat::w30::StatusUpdateId;
|
||||
use deltachat::webxdc::StatusUpdateId;
|
||||
use deltachat::*;
|
||||
use deltachat::{accounts::Accounts, log::LogExt};
|
||||
|
||||
@@ -501,7 +501,7 @@ pub unsafe extern "C" fn dc_event_get_data1_int(event: *mut dc_event_t) -> libc:
|
||||
EventType::ImexFileWritten(_) => 0,
|
||||
EventType::SecurejoinInviterProgress { contact_id, .. }
|
||||
| EventType::SecurejoinJoinerProgress { contact_id, .. } => *contact_id as libc::c_int,
|
||||
EventType::W30StatusUpdate { msg_id, .. } => msg_id.to_u32() as libc::c_int,
|
||||
EventType::WebxdcStatusUpdate { msg_id, .. } => msg_id.to_u32() as libc::c_int,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ pub unsafe extern "C" fn dc_event_get_data2_int(event: *mut dc_event_t) -> libc:
|
||||
EventType::SecurejoinInviterProgress { progress, .. }
|
||||
| EventType::SecurejoinJoinerProgress { progress, .. } => *progress as libc::c_int,
|
||||
EventType::ChatEphemeralTimerModified { timer, .. } => timer.to_u32() as libc::c_int,
|
||||
EventType::W30StatusUpdate {
|
||||
EventType::WebxdcStatusUpdate {
|
||||
status_update_id, ..
|
||||
} => status_update_id.to_u32() as libc::c_int,
|
||||
}
|
||||
@@ -587,7 +587,7 @@ pub unsafe extern "C" fn dc_event_get_data2_str(event: *mut dc_event_t) -> *mut
|
||||
| EventType::SecurejoinJoinerProgress { .. }
|
||||
| EventType::ConnectivityChanged
|
||||
| EventType::SelfavatarChanged
|
||||
| EventType::W30StatusUpdate { .. }
|
||||
| EventType::WebxdcStatusUpdate { .. }
|
||||
| EventType::ChatEphemeralTimerModified { .. } => ptr::null_mut(),
|
||||
EventType::ConfigureProgress { comment, .. } => {
|
||||
if let Some(comment) = comment {
|
||||
@@ -878,40 +878,40 @@ pub unsafe extern "C" fn dc_send_videochat_invitation(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_send_w30_status_update(
|
||||
pub unsafe extern "C" fn dc_send_webxdc_status_update(
|
||||
context: *mut dc_context_t,
|
||||
msg_id: u32,
|
||||
descr: *const libc::c_char,
|
||||
json: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_send_w30_status_update()");
|
||||
eprintln!("ignoring careless call to dc_send_webxdc_status_update()");
|
||||
return 0;
|
||||
}
|
||||
let ctx = &*context;
|
||||
|
||||
block_on(ctx.send_w30_status_update(
|
||||
block_on(ctx.send_webxdc_status_update(
|
||||
MsgId::new(msg_id),
|
||||
&to_string_lossy(descr),
|
||||
&to_string_lossy(json),
|
||||
))
|
||||
.log_err(ctx, "Failed to send w30 update")
|
||||
.log_err(ctx, "Failed to send webxdc update")
|
||||
.is_ok() as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_get_w30_status_updates(
|
||||
pub unsafe extern "C" fn dc_get_webxdc_status_updates(
|
||||
context: *mut dc_context_t,
|
||||
msg_id: u32,
|
||||
status_update_id: u32,
|
||||
) -> *mut libc::c_char {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_get_w30_status_updates()");
|
||||
eprintln!("ignoring careless call to dc_get_webxdc_status_updates()");
|
||||
return "".strdup();
|
||||
}
|
||||
let ctx = &*context;
|
||||
|
||||
block_on(ctx.get_w30_status_updates(
|
||||
block_on(ctx.get_webxdc_status_updates(
|
||||
MsgId::new(msg_id),
|
||||
if status_update_id == 0 {
|
||||
None
|
||||
@@ -3071,13 +3071,13 @@ pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg_t) -> *mut libc::c
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_msg_get_blob_from_archive(
|
||||
pub unsafe extern "C" fn dc_msg_get_webxdc_blob(
|
||||
msg: *mut dc_msg_t,
|
||||
filename: *const libc::c_char,
|
||||
ret_bytes: *mut libc::size_t,
|
||||
) -> *mut libc::c_char {
|
||||
if msg.is_null() || filename.is_null() || ret_bytes.is_null() {
|
||||
eprintln!("ignoring careless call to dc_msg_get_blob_from_archive()");
|
||||
eprintln!("ignoring careless call to dc_msg_get_webxdc_blob()");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
@@ -3085,7 +3085,7 @@ pub unsafe extern "C" fn dc_msg_get_blob_from_archive(
|
||||
let blob = block_on(async move {
|
||||
ffi_msg
|
||||
.message
|
||||
.get_blob_from_archive(ctx, &to_string_lossy(filename))
|
||||
.get_webxdc_blob(ctx, &to_string_lossy(filename))
|
||||
.await
|
||||
});
|
||||
match blob {
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
# W30 User Guide
|
||||
# Webxdc User Guide
|
||||
|
||||
## W30 File Format
|
||||
## Webxdc File Format
|
||||
|
||||
- a **W30** app is a **ZIP-file** with the extension `.w30`
|
||||
- a **Webxdc app** is a **ZIP-file** with the extension `.xdc`
|
||||
- the ZIP-file must contain at least the file `index.html`
|
||||
- if the W30 app is started, `index.html` is opened in a restricted webview
|
||||
- if the Webxdc app is started, `index.html` is opened in a restricted webview
|
||||
that allow accessing resources only from the ZIP-file
|
||||
|
||||
|
||||
## W30 API
|
||||
## Webxdc API
|
||||
|
||||
W30 apps can do anything that is allowed in webviews -
|
||||
Webxdc apps can do anything that is allowed in webviews -
|
||||
html, css, images, canvas, javascript and so on.
|
||||
|
||||
There are some additional APIs available once `deltachat.js` is included
|
||||
There are some additional APIs available once `webxdc.js` is included
|
||||
(the file will be provided by the concrete implementations,
|
||||
no need to add `deltachat.js` to your ZIP-file):
|
||||
no need to add `webxdc.js` to your ZIP-file):
|
||||
|
||||
```
|
||||
<script src="deltachat.js></script>
|
||||
<script src="webxdc.js></script>
|
||||
```
|
||||
|
||||
### sendUpdate()
|
||||
|
||||
```
|
||||
window.deltachat.sendUpdate(descr, payload);
|
||||
window.webxdc.sendUpdate(descr, payload);
|
||||
```
|
||||
|
||||
W30 apps are usually shared in a chat and run independently on each peer.
|
||||
Webxdc apps are usually shared in a chat and run independently on each peer.
|
||||
To get a shared state, the peers use `sendUpdate()` to send updates to each other.
|
||||
|
||||
- `descr`: short, human-readable description what this update is about.
|
||||
@@ -40,7 +40,7 @@ will receive the update by the callback given to `setUpdateListener()`.
|
||||
### setUpdateListener()
|
||||
|
||||
```
|
||||
window.deltachat.setUpdateListener((update) => {});
|
||||
window.webxdc.setUpdateListener((update) => {});
|
||||
```
|
||||
|
||||
With `setUpdateListener()` you define a callback that receives the updates
|
||||
@@ -55,21 +55,21 @@ The callback is called for updates sent by you or other peers.
|
||||
### getAllUpdates()
|
||||
|
||||
```
|
||||
payloads = window.deltachat.getAllUpdates()
|
||||
payloads = window.webxdc.getAllUpdates()
|
||||
```
|
||||
|
||||
In case your W30 was just started,
|
||||
In case your Webxdc was just started,
|
||||
you may want to reconstruct the state from the last run -
|
||||
and also incorporate updates that may have arrived while the app was not running.
|
||||
|
||||
- `payloads`: the function returns all previous updates in an array,
|
||||
eg. `[{payload: "foo"},{payload: "bar"}]`
|
||||
if `deltachat.sendUpdate("foo"); deltachat.sendUpdate("bar");` was called on the last run.
|
||||
if `webxdc.sendUpdate("foo"); webxdc.sendUpdate("bar");` was called on the last run.
|
||||
|
||||
### selfAddr()
|
||||
|
||||
```
|
||||
addr = window.deltachat.selfAddr()
|
||||
addr = window.webxdc.selfAddr()
|
||||
```
|
||||
|
||||
Returns the peer's own address.
|
||||
@@ -78,7 +78,7 @@ just send the address along with the payload,
|
||||
and, if needed, compare the payload addresses against selfAddr() later on.
|
||||
|
||||
|
||||
## W30 Example
|
||||
## Webxdc Example
|
||||
|
||||
The following example shows an input field and every input is show on all peers.
|
||||
|
||||
@@ -87,7 +87,7 @@ The following example shows an input field and every input is show on all peers
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<script src="deltachat.js"></script>
|
||||
<script src="webxdc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<input id="input" type="text"/>
|
||||
@@ -97,21 +97,21 @@ The following example shows an input field and every input is show on all peers
|
||||
|
||||
function sendMsg() {
|
||||
msg = document.getElementById("input").value;
|
||||
window.deltachat.sendUpdate('Someone typed "'+msg+'".', msg);
|
||||
window.webxdc.sendUpdate('Someone typed "'+msg+'".', msg);
|
||||
}
|
||||
|
||||
function receiveUpdate(update) {
|
||||
document.getElementById('output').innerHTML += update.payload + "<br>";
|
||||
}
|
||||
|
||||
window.deltachat.setUpdateListener(receiveUpdate);
|
||||
window.webxdc.setUpdateListener(receiveUpdate);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
For a more advanved example, see https://github.com/r10s/w30-poll/ .
|
||||
For a more advanved example, see https://github.com/r10s/webxdc-poll/ .
|
||||
|
||||
|
||||
## Closing Remarks
|
||||
@@ -387,7 +387,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
sendfile <file> [<text>]\n\
|
||||
sendhtml <file for html-part> [<text for plain-part>]\n\
|
||||
sendsyncmsg\n\
|
||||
sendw30 <msg-id> <json status update>\n\
|
||||
sendupdate <msg-id> <json status update>\n\
|
||||
videochat\n\
|
||||
draft [<text>]\n\
|
||||
devicemsg <text>\n\
|
||||
@@ -908,14 +908,14 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
Some(msg_id) => println!("sync message sent as {}.", msg_id),
|
||||
None => println!("sync message not needed."),
|
||||
},
|
||||
"sendw30" => {
|
||||
"sendupdate" => {
|
||||
ensure!(
|
||||
!arg1.is_empty() && !arg2.is_empty(),
|
||||
"Arguments <msg-id> <json status update> expected"
|
||||
);
|
||||
let msg_id = MsgId::new(arg1.parse()?);
|
||||
context
|
||||
.send_w30_status_update(msg_id, "this is a w30 status update", arg2)
|
||||
.send_webxdc_status_update(msg_id, "this is a webxdc status update", arg2)
|
||||
.await?;
|
||||
}
|
||||
"videochat" => {
|
||||
|
||||
@@ -191,7 +191,7 @@ const CHAT_COMMANDS: [&str; 36] = [
|
||||
"sendfile",
|
||||
"sendhtml",
|
||||
"sendsyncmsg",
|
||||
"sendw30",
|
||||
"sendupdate",
|
||||
"videochat",
|
||||
"draft",
|
||||
"listmedia",
|
||||
|
||||
16
src/chat.rs
16
src/chat.rs
@@ -37,7 +37,7 @@ use crate::mimeparser::SystemMessage;
|
||||
use crate::param::{Param, Params};
|
||||
use crate::peerstate::{Peerstate, PeerstateVerifiedStatus};
|
||||
use crate::stock_str;
|
||||
use crate::w30::W30_SUFFIX;
|
||||
use crate::webxdc::WEBXDC_SUFFIX;
|
||||
|
||||
/// An chat item, such as a message or a marker.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -646,8 +646,8 @@ impl ChatId {
|
||||
.await?
|
||||
.context("no file stored in params")?;
|
||||
msg.param.set(Param::File, blob.as_name());
|
||||
if blob.suffix() == Some(W30_SUFFIX) {
|
||||
msg.viewtype = Viewtype::W30;
|
||||
if blob.suffix() == Some(WEBXDC_SUFFIX) {
|
||||
msg.viewtype = Viewtype::Webxdc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1800,7 +1800,7 @@ pub(crate) fn msgtype_has_file(msgtype: Viewtype) -> bool {
|
||||
Viewtype::Video => true,
|
||||
Viewtype::File => true,
|
||||
Viewtype::VideochatInvitation => false,
|
||||
Viewtype::W30 => true,
|
||||
Viewtype::Webxdc => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1842,8 +1842,12 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
if msg.viewtype == Viewtype::W30 && blob.suffix() != Some(W30_SUFFIX) {
|
||||
bail!("w30 message {} does not have suffix {}", blob, W30_SUFFIX);
|
||||
if msg.viewtype == Viewtype::Webxdc && blob.suffix() != Some(WEBXDC_SUFFIX) {
|
||||
bail!(
|
||||
"webxdc message {} does not have suffix {}",
|
||||
blob,
|
||||
WEBXDC_SUFFIX
|
||||
);
|
||||
}
|
||||
|
||||
info!(
|
||||
|
||||
@@ -296,8 +296,8 @@ pub enum Viewtype {
|
||||
/// Message is an invitation to a videochat.
|
||||
VideochatInvitation = 70,
|
||||
|
||||
/// Message is an w30 object.
|
||||
W30 = 80,
|
||||
/// Message is an webxdc instance.
|
||||
Webxdc = 80,
|
||||
}
|
||||
|
||||
impl Default for Viewtype {
|
||||
@@ -342,7 +342,7 @@ mod tests {
|
||||
Viewtype::VideochatInvitation,
|
||||
Viewtype::from_i32(70).unwrap()
|
||||
);
|
||||
assert_eq!(Viewtype::W30, Viewtype::from_i32(80).unwrap());
|
||||
assert_eq!(Viewtype::Webxdc, Viewtype::from_i32(80).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -258,7 +258,7 @@ pub(crate) async fn dc_receive_imf_inner(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref status_update) = mime_parser.w30_status_update {
|
||||
if let Some(ref status_update) = mime_parser.webxdc_status_update {
|
||||
if let Err(err) = context
|
||||
.receive_status_update(insert_msg_id, status_update)
|
||||
.await
|
||||
@@ -869,7 +869,7 @@ async fn add_parts(
|
||||
info!(context, "Existing non-decipherable message. (TRASH)");
|
||||
}
|
||||
|
||||
if mime_parser.w30_status_update.is_some() && mime_parser.parts.len() == 1 {
|
||||
if mime_parser.webxdc_status_update.is_some() && mime_parser.parts.len() == 1 {
|
||||
if let Some(part) = mime_parser.parts.first() {
|
||||
if part.typ == Viewtype::Text && part.msg.is_empty() {
|
||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
||||
|
||||
@@ -9,7 +9,7 @@ use strum::EnumProperty;
|
||||
use crate::chat::ChatId;
|
||||
use crate::ephemeral::Timer as EphemeralTimer;
|
||||
use crate::message::MsgId;
|
||||
use crate::w30::StatusUpdateId;
|
||||
use crate::webxdc::StatusUpdateId;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Events {
|
||||
@@ -329,7 +329,7 @@ pub enum EventType {
|
||||
SelfavatarChanged,
|
||||
|
||||
#[strum(props(id = "2120"))]
|
||||
W30StatusUpdate {
|
||||
WebxdcStatusUpdate {
|
||||
msg_id: MsgId,
|
||||
status_update_id: StatusUpdateId,
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@ pub mod stock_str;
|
||||
mod sync;
|
||||
mod token;
|
||||
mod update_helper;
|
||||
pub mod w30;
|
||||
pub mod webxdc;
|
||||
#[macro_use]
|
||||
mod dehtml;
|
||||
mod color;
|
||||
|
||||
@@ -1168,12 +1168,12 @@ pub fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> {
|
||||
"ttf" => (Viewtype::File, "font/ttf"),
|
||||
"vcard" => (Viewtype::File, "text/vcard"),
|
||||
"vcf" => (Viewtype::File, "text/vcard"),
|
||||
"w30" => (Viewtype::W30, "application/w30+zip"),
|
||||
"wav" => (Viewtype::File, "audio/wav"),
|
||||
"weba" => (Viewtype::File, "audio/webm"),
|
||||
"webm" => (Viewtype::Video, "video/webm"),
|
||||
"webp" => (Viewtype::Image, "image/webp"), // iOS via SDWebImage, Android since 4.0
|
||||
"wmv" => (Viewtype::Video, "video/x-ms-wmv"),
|
||||
"xdc" => (Viewtype::Webxdc, "application/webxdc+zip"),
|
||||
"xhtml" => (Viewtype::File, "application/xhtml+xml"),
|
||||
"xlsx" => (
|
||||
Viewtype::File,
|
||||
@@ -1704,8 +1704,8 @@ mod tests {
|
||||
Some((Viewtype::File, "text/html"))
|
||||
);
|
||||
assert_eq!(
|
||||
guess_msgtype_from_suffix(Path::new("foo/file.w30")),
|
||||
Some((Viewtype::W30, "application/w30+zip"))
|
||||
guess_msgtype_from_suffix(Path::new("foo/file.xdc")),
|
||||
Some((Viewtype::Webxdc, "application/webxdc+zip"))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -641,7 +641,7 @@ impl<'a> MimeFactory<'a> {
|
||||
"Content-Type".to_string(),
|
||||
"multipart/report; report-type=multi-device-sync".to_string(),
|
||||
))
|
||||
} else if self.msg.param.get_cmd() == SystemMessage::W30StatusUpdate {
|
||||
} else if self.msg.param.get_cmd() == SystemMessage::WebxdcStatusUpdate {
|
||||
PartBuilder::new().header((
|
||||
"Content-Type".to_string(),
|
||||
"multipart/report; report-type=status-update".to_string(),
|
||||
@@ -922,7 +922,7 @@ impl<'a> MimeFactory<'a> {
|
||||
}
|
||||
SystemMessage::LocationOnly
|
||||
| SystemMessage::MultiDeviceSync
|
||||
| SystemMessage::W30StatusUpdate => {
|
||||
| SystemMessage::WebxdcStatusUpdate => {
|
||||
// This should prevent automatic replies,
|
||||
// such as non-delivery reports.
|
||||
//
|
||||
@@ -1159,11 +1159,11 @@ impl<'a> MimeFactory<'a> {
|
||||
let ids = self.msg.param.get(Param::Arg2).unwrap_or_default();
|
||||
parts.push(context.build_sync_part(json.to_string()).await);
|
||||
self.sync_ids_to_delete = Some(ids.to_string());
|
||||
} else if command == SystemMessage::W30StatusUpdate {
|
||||
} else if command == SystemMessage::WebxdcStatusUpdate {
|
||||
let json = self.msg.param.get(Param::Arg).unwrap_or_default();
|
||||
parts.push(context.build_status_update_part(json).await);
|
||||
} else if self.msg.viewtype == Viewtype::W30 {
|
||||
let json = context.get_w30_status_updates(self.msg.id, None).await?;
|
||||
} else if self.msg.viewtype == Viewtype::Webxdc {
|
||||
let json = context.get_webxdc_status_updates(self.msg.id, None).await?;
|
||||
if json != "[]" {
|
||||
parts.push(context.build_status_update_part(&json).await);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ pub struct MimeMessage {
|
||||
pub location_kml: Option<location::Kml>,
|
||||
pub message_kml: Option<location::Kml>,
|
||||
pub(crate) sync_items: Option<SyncItems>,
|
||||
pub(crate) w30_status_update: Option<String>,
|
||||
pub(crate) webxdc_status_update: Option<String>,
|
||||
pub(crate) user_avatar: Option<AvatarAction>,
|
||||
pub(crate) group_avatar: Option<AvatarAction>,
|
||||
pub(crate) mdn_reports: Vec<Report>,
|
||||
@@ -138,8 +138,8 @@ pub enum SystemMessage {
|
||||
MultiDeviceSync = 20,
|
||||
|
||||
// Sync message that contains a json payload
|
||||
// sent to the other w30 instances
|
||||
W30StatusUpdate = 30,
|
||||
// sent to the other webxdc instances
|
||||
WebxdcStatusUpdate = 30,
|
||||
}
|
||||
|
||||
impl Default for SystemMessage {
|
||||
@@ -301,7 +301,7 @@ impl MimeMessage {
|
||||
location_kml: None,
|
||||
message_kml: None,
|
||||
sync_items: None,
|
||||
w30_status_update: None,
|
||||
webxdc_status_update: None,
|
||||
user_avatar: None,
|
||||
group_avatar: None,
|
||||
failure_report: None,
|
||||
@@ -544,7 +544,7 @@ impl MimeMessage {
|
||||
};
|
||||
|
||||
if let Some(ref subject) = self.get_subject() {
|
||||
if !self.has_chat_version() && self.w30_status_update.is_none() {
|
||||
if !self.has_chat_version() && self.webxdc_status_update.is_none() {
|
||||
part.msg = subject.to_string();
|
||||
}
|
||||
}
|
||||
@@ -1019,11 +1019,11 @@ impl MimeMessage {
|
||||
return;
|
||||
}
|
||||
let msg_type = if context
|
||||
.is_w30_file(filename, decoded_data)
|
||||
.is_webxdc_file(filename, decoded_data)
|
||||
.await
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Viewtype::W30
|
||||
Viewtype::Webxdc
|
||||
} else if filename.ends_with(".kml") {
|
||||
// XXX what if somebody sends eg an "location-highlights.kml"
|
||||
// attachment unrelated to location streaming?
|
||||
@@ -1057,7 +1057,7 @@ impl MimeMessage {
|
||||
let serialized = String::from_utf8_lossy(decoded_data)
|
||||
.parse()
|
||||
.unwrap_or_default();
|
||||
self.w30_status_update = Some(serialized);
|
||||
self.webxdc_status_update = Some(serialized);
|
||||
return;
|
||||
} else {
|
||||
msg_type
|
||||
|
||||
@@ -137,9 +137,9 @@ impl Message {
|
||||
append_text = false;
|
||||
stock_str::videochat_invitation(context).await
|
||||
}
|
||||
Viewtype::W30 => {
|
||||
Viewtype::Webxdc => {
|
||||
append_text = true;
|
||||
"W30".to_string()
|
||||
"Webxdc".to_string()
|
||||
}
|
||||
Viewtype::Text | Viewtype::Unknown => {
|
||||
if self.param.get_cmd() != SystemMessage::LocationOnly {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! # Handle W30 messages.
|
||||
//! # Handle webxdc messages.
|
||||
|
||||
use crate::constants::Viewtype;
|
||||
use crate::context::Context;
|
||||
@@ -15,7 +15,7 @@ use serde_json::Value;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::Read;
|
||||
|
||||
pub const W30_SUFFIX: &str = "w30";
|
||||
pub const WEBXDC_SUFFIX: &str = "xdc";
|
||||
|
||||
/// Status Update ID.
|
||||
#[derive(
|
||||
@@ -51,8 +51,8 @@ pub(crate) struct StatusUpdateItem {
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub(crate) async fn is_w30_file(&self, filename: &str, buf: &[u8]) -> Result<bool> {
|
||||
if filename.ends_with(W30_SUFFIX) {
|
||||
pub(crate) async fn is_webxdc_file(&self, filename: &str, buf: &[u8]) -> Result<bool> {
|
||||
if filename.ends_with(WEBXDC_SUFFIX) {
|
||||
let reader = std::io::Cursor::new(buf);
|
||||
if let Ok(mut archive) = zip::ZipArchive::new(reader) {
|
||||
if let Ok(_index_html) = archive.by_name("index.html") {
|
||||
@@ -85,22 +85,22 @@ impl Context {
|
||||
Ok(StatusUpdateId(u32::try_from(rowid)?))
|
||||
}
|
||||
|
||||
/// Sends a status update for an w30 instance.
|
||||
/// Sends a status update for an webxdc instance.
|
||||
///
|
||||
/// If the instance is a draft,
|
||||
/// the status update is sent once the instance is actually sent.
|
||||
///
|
||||
/// If an update is sent immediately, the message-id of the update-message is returned,
|
||||
/// this update-message is visible in chats, however, the id may be useful.
|
||||
pub async fn send_w30_status_update(
|
||||
pub async fn send_webxdc_status_update(
|
||||
&self,
|
||||
instance_msg_id: MsgId,
|
||||
descr: &str,
|
||||
payload: &str,
|
||||
) -> Result<Option<MsgId>> {
|
||||
let instance = Message::load_from_db(self, instance_msg_id).await?;
|
||||
if instance.viewtype != Viewtype::W30 {
|
||||
bail!("send_w30_status_update: is no w30 message");
|
||||
if instance.viewtype != Viewtype::Webxdc {
|
||||
bail!("send_webxdc_status_update: is no webxdc message");
|
||||
}
|
||||
|
||||
let status_update_id = self
|
||||
@@ -109,8 +109,7 @@ impl Context {
|
||||
|
||||
match instance.state {
|
||||
MessageState::Undefined | MessageState::OutPreparing | MessageState::OutDraft => {
|
||||
// send update once the instance is actually send;
|
||||
// on sending, the updates are retrieved using get_w30_status_updates_with_format() then.
|
||||
// send update once the instance is actually send
|
||||
Ok(None)
|
||||
}
|
||||
_ => {
|
||||
@@ -123,16 +122,18 @@ impl Context {
|
||||
hidden: true,
|
||||
..Default::default()
|
||||
};
|
||||
status_update.param.set_cmd(SystemMessage::W30StatusUpdate);
|
||||
status_update
|
||||
.param
|
||||
.set_cmd(SystemMessage::WebxdcStatusUpdate);
|
||||
status_update.param.set(
|
||||
Param::Arg,
|
||||
self.get_w30_status_updates(instance_msg_id, Some(status_update_id))
|
||||
self.get_webxdc_status_updates(instance_msg_id, Some(status_update_id))
|
||||
.await?,
|
||||
);
|
||||
status_update.set_quote(self, &instance).await?;
|
||||
let status_update_msg_id =
|
||||
chat::send_msg(self, instance.chat_id, &mut status_update).await?;
|
||||
self.emit_event(EventType::W30StatusUpdate {
|
||||
self.emit_event(EventType::WebxdcStatusUpdate {
|
||||
msg_id: instance_msg_id,
|
||||
status_update_id,
|
||||
});
|
||||
@@ -157,17 +158,17 @@ impl Context {
|
||||
/// `msg_id` may be an instance (in case there are initial status updates)
|
||||
/// or a reply to an instance (for all other updates).
|
||||
///
|
||||
/// `json` is an array containing one or more update items as created by send_w30_status_update(),
|
||||
/// `json` is an array containing one or more update items as created by send_webxdc_status_update(),
|
||||
/// the array is parsed using serde, the single payloads are used as is.
|
||||
pub(crate) async fn receive_status_update(&self, msg_id: MsgId, json: &str) -> Result<()> {
|
||||
let msg = Message::load_from_db(self, msg_id).await?;
|
||||
let instance = if msg.viewtype == Viewtype::W30 {
|
||||
let instance = if msg.viewtype == Viewtype::Webxdc {
|
||||
msg
|
||||
} else if let Some(parent) = msg.parent(self).await? {
|
||||
if parent.viewtype == Viewtype::W30 {
|
||||
if parent.viewtype == Viewtype::Webxdc {
|
||||
parent
|
||||
} else {
|
||||
bail!("receive_status_update: message is not the child of a W30 message.")
|
||||
bail!("receive_status_update: message is not the child of a webxdc message.")
|
||||
}
|
||||
} else {
|
||||
bail!("receive_status_update: status message has no parent.")
|
||||
@@ -181,7 +182,7 @@ impl Context {
|
||||
&*serde_json::to_string(&update_item.payload)?,
|
||||
)
|
||||
.await?;
|
||||
self.emit_event(EventType::W30StatusUpdate {
|
||||
self.emit_event(EventType::WebxdcStatusUpdate {
|
||||
msg_id: instance.id,
|
||||
status_update_id,
|
||||
});
|
||||
@@ -195,7 +196,7 @@ impl Context {
|
||||
/// Example: `[{"payload":"any update data"},{"payload":"another update data"}]`
|
||||
/// The updates may be filtered by a given status_update_id;
|
||||
/// if no updates are available, an empty JSON-array is returned.
|
||||
pub async fn get_w30_status_updates(
|
||||
pub async fn get_webxdc_status_updates(
|
||||
&self,
|
||||
instance_msg_id: MsgId,
|
||||
status_update_id: Option<StatusUpdateId>,
|
||||
@@ -229,13 +230,13 @@ impl Context {
|
||||
|
||||
impl Message {
|
||||
/// Return file form inside an archive.
|
||||
/// Currently, this works only if the message is an w30 instance.
|
||||
pub async fn get_blob_from_archive(&self, context: &Context, name: &str) -> Result<Vec<u8>> {
|
||||
ensure!(self.viewtype == Viewtype::W30, "No w30 instance.");
|
||||
/// Currently, this works only if the message is an webxdc instance.
|
||||
pub async fn get_webxdc_blob(&self, context: &Context, name: &str) -> Result<Vec<u8>> {
|
||||
ensure!(self.viewtype == Viewtype::Webxdc, "No webxdc instance.");
|
||||
|
||||
let archive = self
|
||||
.get_file(context)
|
||||
.ok_or_else(|| format_err!("No w30 instance file."))?;
|
||||
.ok_or_else(|| format_err!("No webxdc instance file."))?;
|
||||
let archive = dc_open_file_std(context, archive)?;
|
||||
let mut archive = zip::ZipArchive::new(archive)?;
|
||||
|
||||
@@ -265,81 +266,81 @@ mod tests {
|
||||
use async_std::io::WriteExt;
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_is_w30_file() -> Result<()> {
|
||||
async fn test_is_webxdc_file() -> Result<()> {
|
||||
let t = TestContext::new().await;
|
||||
assert!(
|
||||
!t.is_w30_file(
|
||||
!t.is_webxdc_file(
|
||||
"bad-ext-no-zip.txt",
|
||||
include_bytes!("../test-data/message/issue_523.txt")
|
||||
)
|
||||
.await?
|
||||
);
|
||||
assert!(
|
||||
!t.is_w30_file(
|
||||
!t.is_webxdc_file(
|
||||
"bad-ext-good-zip.txt",
|
||||
include_bytes!("../test-data/w30/minimal.w30")
|
||||
include_bytes!("../test-data/webxdc/minimal.xdc")
|
||||
)
|
||||
.await?
|
||||
);
|
||||
assert!(
|
||||
!t.is_w30_file(
|
||||
"good-ext-no-zip.w30",
|
||||
!t.is_webxdc_file(
|
||||
"good-ext-no-zip.xdc",
|
||||
include_bytes!("../test-data/message/issue_523.txt")
|
||||
)
|
||||
.await?
|
||||
);
|
||||
assert!(
|
||||
!t.is_w30_file(
|
||||
"good-ext-no-index-html.w30",
|
||||
include_bytes!("../test-data/w30/no-index-html.w30")
|
||||
!t.is_webxdc_file(
|
||||
"good-ext-no-index-html.xdc",
|
||||
include_bytes!("../test-data/webxdc/no-index-html.xdc")
|
||||
)
|
||||
.await?
|
||||
);
|
||||
assert!(
|
||||
t.is_w30_file(
|
||||
"good-ext-good-zip.w30",
|
||||
include_bytes!("../test-data/w30/minimal.w30")
|
||||
t.is_webxdc_file(
|
||||
"good-ext-good-zip.xdc",
|
||||
include_bytes!("../test-data/webxdc/minimal.xdc")
|
||||
)
|
||||
.await?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_w30_instance(t: &TestContext) -> Result<Message> {
|
||||
let file = t.get_blobdir().join("minimal.w30");
|
||||
async fn create_webxdc_instance(t: &TestContext) -> Result<Message> {
|
||||
let file = t.get_blobdir().join("minimal.xdc");
|
||||
File::create(&file)
|
||||
.await?
|
||||
.write_all(include_bytes!("../test-data/w30/minimal.w30"))
|
||||
.write_all(include_bytes!("../test-data/webxdc/minimal.xdc"))
|
||||
.await?;
|
||||
let mut instance = Message::new(Viewtype::File);
|
||||
instance.set_file(file.to_str().unwrap(), None);
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
async fn send_w30_instance(t: &TestContext, chat_id: ChatId) -> Result<Message> {
|
||||
let mut instance = create_w30_instance(t).await?;
|
||||
async fn send_webxdc_instance(t: &TestContext, chat_id: ChatId) -> Result<Message> {
|
||||
let mut instance = create_webxdc_instance(t).await?;
|
||||
let instance_msg_id = send_msg(t, chat_id, &mut instance).await?;
|
||||
Message::load_from_db(t, instance_msg_id).await
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_send_w30_instance() -> Result<()> {
|
||||
async fn test_send_webxdc_instance() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
|
||||
// send as .w30 file
|
||||
let instance = send_w30_instance(&t, chat_id).await?;
|
||||
assert_eq!(instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(instance.get_filename(), Some("minimal.w30".to_string()));
|
||||
// send as .xdc file
|
||||
let instance = send_webxdc_instance(&t, chat_id).await?;
|
||||
assert_eq!(instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(instance.get_filename(), Some("minimal.xdc".to_string()));
|
||||
assert_eq!(instance.chat_id, chat_id);
|
||||
|
||||
// sending using bad extension is not working, even when setting Viewtype to W30
|
||||
// sending using bad extension is not working, even when setting Viewtype to webxdc
|
||||
let file = t.get_blobdir().join("index.html");
|
||||
File::create(&file)
|
||||
.await?
|
||||
.write_all("<html>ola!</html>".as_ref())
|
||||
.await?;
|
||||
let mut instance = Message::new(Viewtype::W30);
|
||||
let mut instance = Message::new(Viewtype::Webxdc);
|
||||
instance.set_file(file.to_str().unwrap(), None);
|
||||
assert!(send_msg(&t, chat_id, &mut instance).await.is_err());
|
||||
|
||||
@@ -347,22 +348,22 @@ mod tests {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_receive_w30_instance() -> Result<()> {
|
||||
async fn test_receive_webxdc_instance() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
dc_receive_imf(
|
||||
&t,
|
||||
include_bytes!("../test-data/message/w30_good_extension.eml"),
|
||||
include_bytes!("../test-data/message/webxdc_good_extension.eml"),
|
||||
"INBOX",
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let instance = t.get_last_msg().await;
|
||||
assert_eq!(instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(instance.get_filename(), Some("minimal.w30".to_string()));
|
||||
assert_eq!(instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(instance.get_filename(), Some("minimal.xdc".to_string()));
|
||||
|
||||
dc_receive_imf(
|
||||
&t,
|
||||
include_bytes!("../test-data/message/w30_bad_extension.eml"),
|
||||
include_bytes!("../test-data/message/webxdc_bad_extension.eml"),
|
||||
"INBOX",
|
||||
false,
|
||||
)
|
||||
@@ -375,23 +376,24 @@ mod tests {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_delete_w30_instance() -> Result<()> {
|
||||
async fn test_delete_webxdc_instance() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
|
||||
let mut instance = create_w30_instance(&t).await?;
|
||||
let mut instance = create_webxdc_instance(&t).await?;
|
||||
chat_id.set_draft(&t, Some(&mut instance)).await?;
|
||||
let instance = chat_id.get_draft(&t).await?.unwrap();
|
||||
t.send_w30_status_update(instance.id, "descr", "42").await?;
|
||||
t.send_webxdc_status_update(instance.id, "descr", "42")
|
||||
.await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, None).await?,
|
||||
t.get_webxdc_status_updates(instance.id, None).await?,
|
||||
r#"[{"payload":42}]"#.to_string()
|
||||
);
|
||||
|
||||
// set_draft(None) deletes the message without the need to simulate network
|
||||
chat_id.set_draft(&t, None).await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, None).await?,
|
||||
t.get_webxdc_status_updates(instance.id, None).await?,
|
||||
"[]".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -408,15 +410,15 @@ mod tests {
|
||||
async fn test_create_status_update_record() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let instance = send_w30_instance(&t, chat_id).await?;
|
||||
let instance = send_webxdc_instance(&t, chat_id).await?;
|
||||
|
||||
assert_eq!(t.get_w30_status_updates(instance.id, None).await?, "[]");
|
||||
assert_eq!(t.get_webxdc_status_updates(instance.id, None).await?, "[]");
|
||||
|
||||
let id = t
|
||||
.create_status_update_record(instance.id, "\n\n{\"foo\":\"bar\"}\n")
|
||||
.await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, Some(id)).await?,
|
||||
t.get_webxdc_status_updates(instance.id, Some(id)).await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
|
||||
@@ -429,11 +431,11 @@ mod tests {
|
||||
.await
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, Some(id)).await?,
|
||||
t.get_webxdc_status_updates(instance.id, Some(id)).await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, None).await?,
|
||||
t.get_webxdc_status_updates(instance.id, None).await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
|
||||
@@ -441,12 +443,12 @@ mod tests {
|
||||
.create_status_update_record(instance.id, r#"{"foo2":"bar2"}"#)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, Some(id)).await?,
|
||||
t.get_webxdc_status_updates(instance.id, Some(id)).await?,
|
||||
r#"[{"payload":{"foo2":"bar2"}}]"#
|
||||
);
|
||||
t.create_status_update_record(instance.id, "true").await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, None).await?,
|
||||
t.get_webxdc_status_updates(instance.id, None).await?,
|
||||
r#"[{"payload":{"foo":"bar"}},
|
||||
{"payload":{"foo2":"bar2"}},
|
||||
{"payload":true}]"#
|
||||
@@ -459,7 +461,7 @@ mod tests {
|
||||
async fn test_receive_status_update() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let instance = send_w30_instance(&t, chat_id).await?;
|
||||
let instance = send_webxdc_instance(&t, chat_id).await?;
|
||||
|
||||
assert!(t
|
||||
.receive_status_update(instance.id, r#"foo: bar"#)
|
||||
@@ -477,14 +479,14 @@ mod tests {
|
||||
t.receive_status_update(instance.id, r#"[{"payload":{"foo":"bar"}}]"#)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, None).await?,
|
||||
t.get_webxdc_status_updates(instance.id, None).await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
|
||||
t.receive_status_update(instance.id, r#" [ {"payload" :42} , {"payload": 23} ] "#)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(instance.id, None).await?,
|
||||
t.get_webxdc_status_updates(instance.id, None).await?,
|
||||
r#"[{"payload":{"foo":"bar"}},
|
||||
{"payload":42},
|
||||
{"payload":23}]"#
|
||||
@@ -496,15 +498,15 @@ mod tests {
|
||||
async fn expect_status_update_event(t: &TestContext, instance_id: MsgId) -> Result<()> {
|
||||
let event = t
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::W30StatusUpdate { .. }))
|
||||
.get_matching(|evt| matches!(evt, EventType::WebxdcStatusUpdate { .. }))
|
||||
.await;
|
||||
match event {
|
||||
EventType::W30StatusUpdate {
|
||||
EventType::WebxdcStatusUpdate {
|
||||
msg_id,
|
||||
status_update_id,
|
||||
} => {
|
||||
assert_eq!(
|
||||
t.get_w30_status_updates(msg_id, Some(status_update_id))
|
||||
t.get_webxdc_status_updates(msg_id, Some(status_update_id))
|
||||
.await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
@@ -516,19 +518,19 @@ mod tests {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_send_w30_status_update() -> Result<()> {
|
||||
async fn test_send_webxdc_status_update() -> Result<()> {
|
||||
let alice = TestContext::new_alice().await;
|
||||
let bob = TestContext::new_bob().await;
|
||||
|
||||
// Alice sends an w30 instance and a status update
|
||||
// Alice sends an webxdc instance and a status update
|
||||
let alice_chat = alice.create_chat(&bob).await;
|
||||
let alice_instance = send_w30_instance(&alice, alice_chat.id).await?;
|
||||
let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?;
|
||||
let sent1 = &alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(alice_instance.viewtype, Viewtype::Webxdc);
|
||||
assert!(!sent1.payload().contains("report-type=status-update"));
|
||||
|
||||
let status_update_msg_id = alice
|
||||
.send_w30_status_update(alice_instance.id, "descr text", r#"{"foo":"bar"}"#)
|
||||
.send_webxdc_status_update(alice_instance.id, "descr text", r#"{"foo":"bar"}"#)
|
||||
.await?
|
||||
.unwrap();
|
||||
expect_status_update_event(&alice, alice_instance.id).await?;
|
||||
@@ -548,18 +550,18 @@ mod tests {
|
||||
assert!(sent2.payload().contains("descr text"));
|
||||
assert_eq!(
|
||||
alice
|
||||
.get_w30_status_updates(alice_instance.id, None)
|
||||
.get_webxdc_status_updates(alice_instance.id, None)
|
||||
.await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
|
||||
alice
|
||||
.send_w30_status_update(alice_instance.id, "bla text", r#"{"snipp":"snapp"}"#)
|
||||
.send_webxdc_status_update(alice_instance.id, "bla text", r#"{"snipp":"snapp"}"#)
|
||||
.await?
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
alice
|
||||
.get_w30_status_updates(alice_instance.id, None)
|
||||
.get_webxdc_status_updates(alice_instance.id, None)
|
||||
.await?,
|
||||
r#"[{"payload":{"foo":"bar"}},
|
||||
{"payload":{"snipp":"snapp"}}]"#
|
||||
@@ -570,7 +572,7 @@ mod tests {
|
||||
let bob_instance = bob.get_last_msg().await;
|
||||
let bob_chat_id = bob_instance.chat_id;
|
||||
assert_eq!(bob_instance.rfc724_mid, alice_instance.rfc724_mid);
|
||||
assert_eq!(bob_instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(bob_instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1);
|
||||
|
||||
bob.recv_msg(sent2).await;
|
||||
@@ -578,7 +580,7 @@ mod tests {
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1);
|
||||
|
||||
assert_eq!(
|
||||
bob.get_w30_status_updates(bob_instance.id, None).await?,
|
||||
bob.get_webxdc_status_updates(bob_instance.id, None).await?,
|
||||
r#"[{"payload":{"foo":"bar"}}]"#
|
||||
);
|
||||
|
||||
@@ -588,57 +590,57 @@ mod tests {
|
||||
alice2.recv_msg(sent2).await;
|
||||
let alice2_instance = alice2.get_last_msg().await;
|
||||
let alice2_chat_id = alice2_instance.chat_id;
|
||||
assert_eq!(alice2_instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(alice2_instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(alice2_chat_id.get_msg_cnt(&alice2).await?, 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_draft_and_send_w30_status_update() -> Result<()> {
|
||||
async fn test_draft_and_send_webxdc_status_update() -> Result<()> {
|
||||
let alice = TestContext::new_alice().await;
|
||||
let bob = TestContext::new_bob().await;
|
||||
let alice_chat_id = alice.create_chat(&bob).await.id;
|
||||
|
||||
// prepare w30 instance,
|
||||
// status updates are not sent for drafts, therefore send_w30_status_update() returns Ok(None)
|
||||
let mut alice_instance = create_w30_instance(&alice).await?;
|
||||
// prepare webxdc instance,
|
||||
// status updates are not sent for drafts, therefore send_webxdc_status_update() returns Ok(None)
|
||||
let mut alice_instance = create_webxdc_instance(&alice).await?;
|
||||
alice_chat_id
|
||||
.set_draft(&alice, Some(&mut alice_instance))
|
||||
.await?;
|
||||
let mut alice_instance = alice_chat_id.get_draft(&alice).await?.unwrap();
|
||||
|
||||
let status_update_msg_id = alice
|
||||
.send_w30_status_update(alice_instance.id, "descr", r#"{"foo":"bar"}"#)
|
||||
.send_webxdc_status_update(alice_instance.id, "descr", r#"{"foo":"bar"}"#)
|
||||
.await?;
|
||||
assert_eq!(status_update_msg_id, None);
|
||||
let status_update_msg_id = alice
|
||||
.send_w30_status_update(alice_instance.id, "descr", r#"42"#)
|
||||
.send_webxdc_status_update(alice_instance.id, "descr", r#"42"#)
|
||||
.await?;
|
||||
assert_eq!(status_update_msg_id, None);
|
||||
|
||||
// send w30 instance,
|
||||
// send webxdc instance,
|
||||
// the initial status updates are sent together in the same message
|
||||
let alice_instance_id = send_msg(&alice, alice_chat_id, &mut alice_instance).await?;
|
||||
let sent1 = alice.pop_sent_msg().await;
|
||||
let alice_instance = Message::load_from_db(&alice, alice_instance_id).await?;
|
||||
assert_eq!(alice_instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(alice_instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(
|
||||
alice_instance.get_filename(),
|
||||
Some("minimal.w30".to_string())
|
||||
Some("minimal.xdc".to_string())
|
||||
);
|
||||
assert_eq!(alice_instance.chat_id, alice_chat_id);
|
||||
|
||||
// bob receives the instance together with the initial updates in a single message
|
||||
bob.recv_msg(&sent1).await;
|
||||
let bob_instance = bob.get_last_msg().await;
|
||||
assert_eq!(bob_instance.viewtype, Viewtype::W30);
|
||||
assert_eq!(bob_instance.get_filename(), Some("minimal.w30".to_string()));
|
||||
assert_eq!(bob_instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(bob_instance.get_filename(), Some("minimal.xdc".to_string()));
|
||||
assert!(sent1.payload().contains("Content-Type: application/json"));
|
||||
assert!(sent1.payload().contains("status-update.json"));
|
||||
assert!(sent1.payload().contains(r#""payload":{"foo":"bar"}"#));
|
||||
assert_eq!(
|
||||
bob.get_w30_status_updates(bob_instance.id, None).await?,
|
||||
bob.get_webxdc_status_updates(bob_instance.id, None).await?,
|
||||
r#"[{"payload":{"foo":"bar"}},
|
||||
{"payload":42}]"#
|
||||
);
|
||||
@@ -647,85 +649,82 @@ mod tests {
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_send_w30_status_update_to_non_w30() -> Result<()> {
|
||||
async fn test_send_webxdc_status_update_to_non_webxdc() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let msg_id = send_text_msg(&t, chat_id, "ho!".to_string()).await?;
|
||||
assert!(t
|
||||
.send_w30_status_update(msg_id, "descr", r#"{"foo":"bar"}"#)
|
||||
.send_webxdc_status_update(msg_id, "descr", r#"{"foo":"bar"}"#)
|
||||
.await
|
||||
.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_get_blob_from_archive() -> Result<()> {
|
||||
async fn test_get_webxdc_blob() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let instance = send_w30_instance(&t, chat_id).await?;
|
||||
let instance = send_webxdc_instance(&t, chat_id).await?;
|
||||
|
||||
let buf = instance.get_blob_from_archive(&t, "index.html").await?;
|
||||
let buf = instance.get_webxdc_blob(&t, "index.html").await?;
|
||||
assert_eq!(buf.len(), 188);
|
||||
assert!(String::from_utf8_lossy(&buf).contains("document.write"));
|
||||
|
||||
assert!(instance
|
||||
.get_blob_from_archive(&t, "not-existent.html")
|
||||
.get_webxdc_blob(&t, "not-existent.html")
|
||||
.await
|
||||
.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_get_blob_from_archive_with_absolute_paths() -> Result<()> {
|
||||
async fn test_get_webxdc_blob_with_absolute_paths() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let instance = send_w30_instance(&t, chat_id).await?;
|
||||
let instance = send_webxdc_instance(&t, chat_id).await?;
|
||||
|
||||
let buf = instance.get_blob_from_archive(&t, "/index.html").await?;
|
||||
let buf = instance.get_webxdc_blob(&t, "/index.html").await?;
|
||||
assert!(String::from_utf8_lossy(&buf).contains("document.write"));
|
||||
|
||||
assert!(instance
|
||||
.get_blob_from_archive(&t, "/not-there")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(instance.get_webxdc_blob(&t, "/not-there").await.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_get_blob_from_archive_subdirs() -> Result<()> {
|
||||
async fn test_get_webxdc_blob_with_subdirs() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let file = t.get_blobdir().join("some-files.w30");
|
||||
let file = t.get_blobdir().join("some-files.xdc");
|
||||
File::create(&file)
|
||||
.await?
|
||||
.write_all(include_bytes!("../test-data/w30/some-files.w30"))
|
||||
.write_all(include_bytes!("../test-data/webxdc/some-files.xdc"))
|
||||
.await?;
|
||||
let mut instance = Message::new(Viewtype::W30);
|
||||
let mut instance = Message::new(Viewtype::Webxdc);
|
||||
instance.set_file(file.to_str().unwrap(), None);
|
||||
chat_id.set_draft(&t, Some(&mut instance)).await?;
|
||||
|
||||
let buf = instance.get_blob_from_archive(&t, "index.html").await?;
|
||||
let buf = instance.get_webxdc_blob(&t, "index.html").await?;
|
||||
assert_eq!(buf.len(), 65);
|
||||
assert!(String::from_utf8_lossy(&buf).contains("many files"));
|
||||
|
||||
let buf = instance.get_blob_from_archive(&t, "subdir/bla.txt").await?;
|
||||
let buf = instance.get_webxdc_blob(&t, "subdir/bla.txt").await?;
|
||||
assert_eq!(buf.len(), 4);
|
||||
assert!(String::from_utf8_lossy(&buf).starts_with("bla"));
|
||||
|
||||
let buf = instance
|
||||
.get_blob_from_archive(&t, "subdir/subsubdir/text.md")
|
||||
.get_webxdc_blob(&t, "subdir/subsubdir/text.md")
|
||||
.await?;
|
||||
assert_eq!(buf.len(), 24);
|
||||
assert!(String::from_utf8_lossy(&buf).starts_with("this is a markdown file"));
|
||||
|
||||
let buf = instance
|
||||
.get_blob_from_archive(&t, "subdir/subsubdir/text2.md")
|
||||
.get_webxdc_blob(&t, "subdir/subsubdir/text2.md")
|
||||
.await?;
|
||||
assert_eq!(buf.len(), 22);
|
||||
assert!(String::from_utf8_lossy(&buf).starts_with("another markdown"));
|
||||
|
||||
let buf = instance
|
||||
.get_blob_from_archive(&t, "anotherdir/anothersubsubdir/foo.txt")
|
||||
.get_webxdc_blob(&t, "anotherdir/anothersubsubdir/foo.txt")
|
||||
.await?;
|
||||
assert_eq!(buf.len(), 4);
|
||||
assert!(String::from_utf8_lossy(&buf).starts_with("foo"));
|
||||
@@ -1,4 +1,4 @@
|
||||
Subject: W30 object attached
|
||||
Subject: webxdc object attached
|
||||
Message-ID: 67890@example.org
|
||||
Date: Fri, 03 Dec 2021 10:00:27 +0000
|
||||
To: alice@example.org
|
||||
@@ -10,11 +10,10 @@ Content-Type: multipart/mixed; boundary="==BREAK=="
|
||||
--==BREAK==
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
w30 with correct extension;
|
||||
this is not that important here.
|
||||
webxdc with bad extension and bad content.
|
||||
|
||||
--==BREAK==
|
||||
Content-Type: application/html+w30
|
||||
Content-Type: application/webxdc+zip
|
||||
Content-Disposition: attachment; filename=index.html
|
||||
|
||||
<html>hey!<html>
|
||||
@@ -1,4 +1,4 @@
|
||||
Subject: W30 object attached
|
||||
Subject: webxdc object attached
|
||||
Message-ID: 12345@example.org
|
||||
Date: Fri, 03 Dec 2021 10:00:27 +0000
|
||||
To: alice@example.org
|
||||
@@ -10,13 +10,13 @@ Content-Type: multipart/mixed; boundary="==BREAK=="
|
||||
--==BREAK==
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
w30 with good extension;
|
||||
webxdc with good extension;
|
||||
the mimetype is ignored then,
|
||||
content is checked.
|
||||
|
||||
--==BREAK==
|
||||
Content-Type: text/html
|
||||
Content-Disposition: attachment; filename=minimal.w30
|
||||
Content-Disposition: attachment; filename=minimal.xdc
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
UEsDBBQAAgAIAFJqnVOItjSofAAAALwAAAAKABwAaW5kZXguaHRtbFVUCQADG1LMYV1SzGF1eAsAAQ
|
||||
Reference in New Issue
Block a user