Compare commits

...

8 Commits

Author SHA1 Message Date
Xavier Del Campo Romero f5e471b3c2
Remove USE_SOUP3
CMake had already replaced it with SOUP_VERSION, so it made no sense for
configure to insist on USE_SOUP3.
2023-10-05 13:56:06 +02:00
Xavier Del Campo Romero 4da3856f07
SoupVersion.cmake: Force version required by Nice
Otherwise, Dino would crash due to conflicting Soup 2 and 3 symbols.
2023-10-05 13:56:05 +02:00
Xavier Del Campo Romero 5a907a6105
file_widget.vala: Only show image when sent 2023-10-05 13:56:05 +02:00
Xavier Del Campo Romero 496cf39f67
connection_manager.vala: Use yield on disconnect() 2023-10-05 13:56:05 +02:00
Xavier Del Campo Romero 5387929470
file_sender.vala: Split very long line 2023-10-05 13:56:05 +02:00
Xavier Del Campo Romero 291474c751
Check XmppStream against null
Most of the calls to stream_interactor.get_stream(account) were already
doing null checks, but there were still some missing.
2023-10-05 13:56:05 +02:00
Xavier Del Campo Romero 316770a31e
file_manager.vala: Disable automatic download 2023-10-05 13:56:05 +02:00
Xavier Del Campo Romero af0da9eee3
Show file upload/download progress
Fixes upstream issue #1350.

Notes:

Image uploads were incorrectly handled by Dino, as they were always
reported as completed even if they were not, maybe so as to show the
image preview from the start. Now, Dino shows the upload progress for
all file types, and the image is only shown when completed.
2023-10-05 13:56:05 +02:00
15 changed files with 114 additions and 35 deletions

View File

@ -1,5 +1,5 @@
find_package(Nice QUIET)
if (Nice_FOUND AND NOT SOUP_VERSION AND NOT USE_SOUP3)
if (Nice_FOUND)
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR Nice_DEPENDENCIES
UNRESOLVED_DEPENDENCIES_VAR Nice_UNRESOLVED_DEPENDENCIES
@ -9,11 +9,21 @@ if (Nice_FOUND AND NOT SOUP_VERSION AND NOT USE_SOUP3)
)
foreach (lib ${Nice_DEPENDENCIES})
if (lib MATCHES ".*/libsoup-3.*")
if(SOUP_VERSION AND NOT SOUP_VERSION EQUAL 3)
message(FATAL_ERROR "libnice-${Nice_VERSION} depends on "
"libsoup-3, but SOUP_VERSION=${SOUP_VERSION} was given.")
endif()
set(SOUP_VERSION 3)
endif ()
endforeach ()
foreach (lib ${Nice_DEPENDENCIES})
if (lib MATCHES ".*/libsoup-2.*")
if(SOUP_VERSION AND NOT SOUP_VERSION EQUAL 2)
message(FATAL_ERROR "libnice-${Nice_VERSION} depends on "
"libsoup-2, but SOUP_VERSION=${SOUP_VERSION} was given.")
endif()
set(SOUP_VERSION 2)
endif ()
endforeach ()
@ -24,7 +34,7 @@ elseif (NOT SOUP_VERSION)
find_package(Soup2 QUIET)
find_package(Soup3 QUIET)
# Only use libsoup 3 if specifically requested or when libsoup 2 is not available
if (Soup3_FOUND AND NOT Soup2_FOUND OR USE_SOUP3)
if (Soup3_FOUND AND NOT Soup2_FOUND)
set(SOUP_VERSION 3)
else ()
set(SOUP_VERSION 2)

6
configure vendored
View File

@ -22,7 +22,7 @@ DISABLE_FAST_VAPI=
LIB_SUFFIX=
NO_DEBUG=
FETCH_ONLY=
USE_SOUP3=
SOUP_VERSION=2
EXEC_PREFIX=
BINDIR=
@ -113,7 +113,7 @@ while true; do
--valac-flags ) VALAC_FLAGS="$2"; shift; shift ;;
--lib-suffix ) LIB_SUFFIX="$2"; shift; shift ;;
--with-libsignal-in-tree ) BUILD_LIBSIGNAL_IN_TREE=yes; shift ;;
--with-libsoup3 ) USE_SOUP3=yes; shift ;;
--with-libsoup3 ) SOUP_VERSION=3; shift ;;
--disable-fast-vapi ) DISABLE_FAST_VAPI=yes; shift ;;
--no-debug ) NO_DEBUG=yes; shift ;;
--fetch-only ) FETCH_ONLY=yes; shift ;;
@ -259,7 +259,7 @@ cmake -G "$cmake_type" \
-DDISABLED_PLUGINS="$DISABLED_PLUGINS" \
-DBUILD_TESTS="$BUILD_TESTS" \
-DBUILD_LIBSIGNAL_IN_TREE="$BUILD_LIBSIGNAL_IN_TREE" \
-DUSE_SOUP3="$USE_SOUP3" \
-DSOUP_VERSION="$SOUP_VERSION" \
-DVALA_EXECUTABLE="$VALAC" \
-DCMAKE_VALA_FLAGS="$VALACFLAGS" \
-DDISABLE_FAST_VAPI="$DISABLE_FAST_VAPI" \

View File

@ -3,7 +3,7 @@ using Xmpp;
namespace Dino.Entities {
public class FileTransfer : Object {
public signal void progress_updated(int progress);
public const bool DIRECTION_SENT = true;
public const bool DIRECTION_RECEIVED = false;
@ -70,6 +70,14 @@ public class FileTransfer : Object {
public State state { get; set; default=State.NOT_STARTED; }
public int provider { get; set; }
public string info { get; set; }
private int progress_ { get; set; }
public int progress {
get {return progress_;}
set {
progress_ = value;
progress_updated(progress_);
}
}
public Cancellable cancellable { get; default=new Cancellable(); }
private Database? db;

View File

@ -144,7 +144,7 @@ public class AvatarManager : StreamInteractionModule, Object {
}
uint8[] buffer;
pixbuf.save_to_buffer(out buffer, "png");
XmppStream stream = stream_interactor.get_stream(account);
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) {
Xmpp.Xep.UserAvatars.publish_png(stream, buffer, pixbuf.width, pixbuf.height);
}

View File

@ -21,22 +21,26 @@ public class BlockingManager : StreamInteractionModule, Object {
}
public bool is_blocked(Account account, Jid jid) {
XmppStream stream = stream_interactor.get_stream(account);
XmppStream? stream = stream_interactor.get_stream(account);
return stream != null && stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).is_blocked(stream, jid.to_string());
}
public void block(Account account, Jid jid) {
XmppStream stream = stream_interactor.get_stream(account);
stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).block(stream, { jid.to_string() });
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) {
stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).block(stream, { jid.to_string() });
}
}
public void unblock(Account account, Jid jid) {
XmppStream stream = stream_interactor.get_stream(account);
stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).unblock(stream, { jid.to_string() });
XmppStream? stream = stream_interactor.get_stream(account);
if (stream != null) {
stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).unblock(stream, { jid.to_string() });
}
}
public bool is_supported(Account account) {
XmppStream stream = stream_interactor.get_stream(account);
XmppStream? stream = stream_interactor.get_stream(account);
return stream != null && stream.get_module(Xmpp.Xep.BlockingCommand.Module.IDENTITY).is_supported(stream);
}
}

View File

@ -126,7 +126,7 @@ public class Dino.CallState : Object {
call.state = Call.State.DECLINED;
if (use_cim) {
XmppStream stream = stream_interactor.get_stream(call.account);
XmppStream? stream = stream_interactor.get_stream(call.account);
if (stream == null) return;
stream.get_module(Xep.CallInvites.Module.IDENTITY).send_reject(stream, cim_counterpart, cim_call_id, cim_message_type);
}
@ -143,7 +143,7 @@ public class Dino.CallState : Object {
peers_cpy.add_all(peers.values);
if (group_call != null) {
XmppStream stream = stream_interactor.get_stream(call.account);
XmppStream? stream = stream_interactor.get_stream(call.account);
if (stream != null) {
stream.get_module(Xep.Muc.Module.IDENTITY).exit(stream, group_call.muc_jid);
}

View File

@ -59,12 +59,12 @@ public class ConnectionManager : Object {
reset();
}
public void reset() {
public async void reset() {
acked = false;
if (stream != null) {
stream.detach_modules();
stream.disconnect.begin();
yield stream.disconnect();
}
stream = null;
uuid = Xmpp.random_uuid();

View File

@ -120,6 +120,7 @@ public class FileManager : StreamInteractionModule, Object {
}
yield file_sender.send_file(conversation, file_transfer, file_send_data, file_meta);
file_transfer.state = FileTransfer.State.COMPLETE;
} catch (Error e) {
warning("Send file error: %s", e.message);
@ -252,8 +253,13 @@ public class FileManager : StreamInteractionModule, Object {
uint8[] buffer = new uint8[1024];
ssize_t read;
uint64 received_bytes = 0;
while ((read = yield input_stream.read_async(buffer, Priority.LOW, file_transfer.cancellable)) > 0) {
buffer.length = (int) read;
received_bytes += (size_t)read;
file_transfer.progress =
(int)((received_bytes * (uint64)100)
/ (uint64)file_transfer.size);
yield os.write_async(buffer, Priority.LOW, file_transfer.cancellable);
buffer.length = 1024;
}
@ -290,6 +296,7 @@ public class FileManager : StreamInteractionModule, Object {
file_transfer.file_name = file_meta.file_name;
file_transfer.size = (int)file_meta.size;
file_transfer.info = info;
file_transfer.progress = 0;
var encryption = file_provider.get_encryption(file_transfer, receive_data, file_meta);
if (encryption != Encryption.NONE) file_transfer.encryption = encryption;
@ -309,11 +316,6 @@ public class FileManager : StreamInteractionModule, Object {
warning("Error downloading file: %s", e.message);
file_transfer.state = FileTransfer.State.FAILED;
}
if (file_transfer.size >= 0 && file_transfer.size < 5000000) {
download_file_internal.begin(file_provider, file_transfer, conversation, (_, res) => {
download_file_internal.end(res);
});
}
}
conversation.last_active = file_transfer.time;
@ -326,7 +328,7 @@ public class FileManager : StreamInteractionModule, Object {
File file = File.new_for_path(Path.build_filename(get_storage_dir(), filename));
OutputStream os = file.create(FileCreateFlags.REPLACE_DESTINATION);
yield os.splice_async(file_transfer.input_stream, OutputStreamSpliceFlags.CLOSE_SOURCE|OutputStreamSpliceFlags.CLOSE_TARGET);
file_transfer.state = FileTransfer.State.COMPLETE;
file_transfer.state = FileTransfer.State.IN_PROGRESS;
file_transfer.path = filename;
file_transfer.input_stream = yield file.read_async();
} catch (Error e) {

View File

@ -366,7 +366,10 @@ public class Dino.HistorySync {
* prev_page_result: null if this is the first page request
**/
private async PageRequestResult get_mam_page(Account account, Xmpp.MessageArchiveManagement.V2.MamQueryParams query_params, PageRequestResult? prev_page_result, Cancellable? cancellable = null) {
XmppStream stream = stream_interactor.get_stream(account);
XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) {
return new PageRequestResult.with_result(PageResult.Error);
}
Xmpp.MessageArchiveManagement.QueryResult query_result = null;
if (prev_page_result == null) {
query_result = yield Xmpp.MessageArchiveManagement.V2.query_archive(stream, query_params, cancellable);
@ -592,5 +595,9 @@ public class Dino.HistorySync {
this.query_result = query_result;
this.stanzas = stanzas;
}
public PageRequestResult.with_result(PageResult page_result) {
this.page_result = page_result;
}
}
}

View File

@ -31,7 +31,8 @@ public class FileDefaultWidget : EventBox {
cancel_button = new ModelButton() { text=_("Cancel"), visible=true };
}
public void update_file_info(string? mime_type, FileTransfer.State state, long size) {
public void update_file_info(string? mime_type, int progress,
bool direction, FileTransfer.State state, long size) {
this.state = state;
spinner.active = false; // A hidden spinning spinner still uses CPU. Deactivate asap
@ -58,7 +59,12 @@ public class FileDefaultWidget : EventBox {
popover_menu.closed.connect(on_pointer_left);
break;
case FileTransfer.State.IN_PROGRESS:
mime_label.label = _("Downloading %s…").printf(get_size_string(size));
if (direction == FileTransfer.DIRECTION_SENT) {
mime_label.label = _("Uploading %s (%d%%)…").printf(get_size_string(size), progress);
}
else {
mime_label.label = _("Downloading %s (%d%%)…").printf(get_size_string(size), progress);
}
spinner.active = true;
image_stack.set_visible_child_name("spinner");

View File

@ -65,7 +65,8 @@ public class FileWidget : SizeRequestBox {
}
private async void update_widget() {
if (show_image() && state != State.IMAGE) {
if (show_image() && state != State.IMAGE
&& file_transfer.state == FileTransfer.State.COMPLETE) {
var content_bak = content;
FileImageWidget file_image_widget = null;
@ -148,6 +149,7 @@ public class FileDefaultWidgetController : Object {
this.notify["file-transfer-state"].connect(update_file_info);
this.notify["file-transfer-mime-type"].connect(update_file_info);
file_transfer.progress_updated.connect(update_file_info);
update_file_info();
}
@ -155,13 +157,15 @@ public class FileDefaultWidgetController : Object {
file_uri = file.get_uri();
state = FileTransfer.State.COMPLETE;
widget.name_label.label = this.file_name = file_name;
widget.update_file_info(mime_type, state, -1);
widget.update_file_info(mime_type, 0, false, state, -1);
}
private void update_file_info() {
file_uri = file_transfer.get_file().get_uri();
state = file_transfer.state;
widget.update_file_info(file_transfer.mime_type, file_transfer.state, file_transfer.size);
widget.update_file_info(file_transfer.mime_type,
file_transfer.progress,
file_transfer.direction, file_transfer.state, file_transfer.size);
}
private void open_file() {

View File

@ -74,7 +74,8 @@ public class FileSendOverlay : Gtk.EventBox {
if (widget == null) {
FileDefaultWidget default_widget = new FileDefaultWidget() { visible=true };
default_widget.name_label.label = file_name;
default_widget.update_file_info(mime_type, FileTransfer.State.COMPLETE, (long)file_info.get_size());
default_widget.update_file_info(mime_type, 100, FileTransfer.DIRECTION_SENT,
FileTransfer.State.COMPLETE, (long)file_info.get_size());
widget = default_widget;
}

View File

@ -25,7 +25,11 @@ public class HttpFileSender : FileSender, Object {
if (stream == null) return null;
try {
var slot_result = yield stream_interactor.module_manager.get_module(file_transfer.account, Xmpp.Xep.HttpFileUpload.Module.IDENTITY).request_slot(stream, file_transfer.server_file_name, file_meta.size, file_meta.mime_type);
var slot_result = yield stream_interactor.module_manager
.get_module(file_transfer.account,
Xmpp.Xep.HttpFileUpload.Module.IDENTITY)
.request_slot(stream, file_transfer.server_file_name,
file_meta.size, file_meta.mime_type);
send_data.url_down = slot_result.url_get;
send_data.url_up = slot_result.url_put;
send_data.headers = slot_result.headers;
@ -106,6 +110,22 @@ public class HttpFileSender : FileSender, Object {
put_message.wrote_headers.connect(() => transfer_more_bytes(file_transfer.input_stream, put_message.request_body));
put_message.wrote_chunk.connect(() => transfer_more_bytes(file_transfer.input_stream, put_message.request_body));
#endif
uint64 sent_bytes = 0;
put_message.wrote_body_data.connect((chunk) => {
if (file_transfer.size != 0) {
#if SOUP_3_0
sent_bytes += chunk;
#else
sent_bytes += chunk.length;
#endif
file_transfer.progress =
(int)((sent_bytes * (uint64)100)
/ (uint64)file_transfer.size);
}
});
foreach (var entry in file_send_data.headers.entries) {
put_message.request_headers.append(entry.key, entry.value);
}

View File

@ -39,7 +39,11 @@ namespace Xmpp.MessageArchiveManagement.V2 {
}
}
private StanzaNode create_base_query(XmppStream stream, MamQueryParams mam_params) {
private StanzaNode create_base_query(XmppStream? stream, MamQueryParams mam_params) {
if (stream == null) {
return new StanzaNode();
}
var fields = new ArrayList<DataForms.DataForm.Field>();
if (mam_params.with != null) {
@ -61,7 +65,12 @@ namespace Xmpp.MessageArchiveManagement.V2 {
return MessageArchiveManagement.create_base_query(stream, MessageArchiveManagement.NS_URI_2, mam_params.query_id, fields);
}
public async QueryResult query_archive(XmppStream stream, MamQueryParams mam_params, Cancellable? cancellable = null) {
public async QueryResult query_archive(XmppStream? stream, MamQueryParams mam_params, Cancellable? cancellable = null) {
if (stream == null) {
var result = new QueryResult();
result.error = true;
return result;
}
var query_node = create_base_query(stream, mam_params);
if (!mam_params.use_ns2_extended) {
query_node.put_node(ResultSetManagement.create_set_rsm_node_before(mam_params.end_id));

View File

@ -53,7 +53,11 @@ public class Module : XmppStreamModule {
}
}
internal StanzaNode create_base_query(XmppStream stream, string ns, string? queryid, Gee.List<DataForms.DataForm.Field> fields) {
internal StanzaNode create_base_query(XmppStream? stream, string ns, string? queryid, Gee.List<DataForms.DataForm.Field> fields) {
if (stream == null) {
return new StanzaNode();
}
DataForms.DataForm data_form = new DataForms.DataForm();
DataForms.DataForm.HiddenField form_type_field = new DataForms.DataForm.HiddenField() { var="FORM_TYPE" };
@ -156,7 +160,11 @@ public class MessageFlag : Xmpp.MessageFlag {
}
private static string NS_VER(XmppStream stream) {
return stream.get_flag(Flag.IDENTITY).ns_ver;
var? flag = stream.get_flag(Flag.IDENTITY);
if (flag == null) {
return "";
}
return flag.ns_ver;
}
}