diff options
Diffstat (limited to 'libdino/src/service/stateless_file_sharing.vala')
| -rw-r--r-- | libdino/src/service/stateless_file_sharing.vala | 177 |
1 files changed, 99 insertions, 78 deletions
diff --git a/libdino/src/service/stateless_file_sharing.vala b/libdino/src/service/stateless_file_sharing.vala index 15e1ddfe..6e97a5ce 100644 --- a/libdino/src/service/stateless_file_sharing.vala +++ b/libdino/src/service/stateless_file_sharing.vala @@ -16,11 +16,16 @@ public class Dino.StatelessFileSharing : StreamInteractionModule, Object { private set { } } - public FileManager file_manager { + public FileManager fm { owned get { return stream_interactor.get_module(FileManager.IDENTITY); } private set { } } + public FileManager2 fm2 { + owned get { return stream_interactor.get_module(FileManager2.IDENTITY); } + private set { } + } + public Database db { owned get { return Application.get_default().db; } private set { } @@ -30,7 +35,7 @@ public class Dino.StatelessFileSharing : StreamInteractionModule, Object { this.stream_interactor = stream_interactor; this.db = db; - stream_interactor.get_module(MessageProcessor.IDENTITY).received_pipeline.connect(new ReceivedMessageListener(this)); + stream_interactor.get_module(MessageProcessor.IDENTITY).build_message_stanza.connect(check_add_sfs_element); } public static void start(StreamInteractor stream_interactor, Database db) { @@ -38,7 +43,81 @@ public class Dino.StatelessFileSharing : StreamInteractionModule, Object { stream_interactor.add_module(m); } - public async void create_file_transfer(Conversation conversation, Message message, string? file_sharing_id, Xep.FileMetadataElement.FileMetadata metadata, Gee.List<Xep.StatelessFileSharing.Source>? sources) { + public async Entities.Message announce_files(FileTransferGroup file_group, Conversation conversation) { + Entities.Message file_share_message = stream_interactor.get_module(MessageProcessor.IDENTITY).create_out_message(null, conversation); + stream_interactor.get_module(MessageStorage.IDENTITY).add_message(file_share_message, conversation); + file_group.message_id = file_share_message.id; + + foreach (var file_transfer in file_group.file_transfers) { + file_transfer.provider = SFS_PROVIDER_ID; + file_transfer.info = file_share_message.id.to_string(); + file_transfer.file_sharing_id = Xmpp.random_uuid(); + } + + stream_interactor.get_module(MessageProcessor.IDENTITY).send_xmpp_message(file_share_message, conversation); + + return file_share_message; + } + + public async void attach_source(FileTransfer file_transfer, Conversation conversation, string http_url, string to_sfs_id) { + MessageStanza stanza = new MessageStanza() { to = conversation.counterpart, type_ = conversation.type_ == GROUPCHAT ? MessageStanza.TYPE_GROUPCHAT : MessageStanza.TYPE_CHAT }; + stanza.body = http_url; + Xep.OutOfBandData.add_url_to_message(stanza, http_url); + var sources = new ArrayList<Xep.StatelessFileSharing.Source>(); + sources.add(new Xep.StatelessFileSharing.HttpSource() { url = http_url }); + Xep.StatelessFileSharing.set_sfs_attachment(stanza, to_sfs_id, file_transfer.file_sharing_id, sources); + + var stream = stream_interactor.get_stream(conversation.account); + if (stream == null) throw new FileSendError.UPLOAD_FAILED("No stream"); + + stream.get_module(MessageModule.IDENTITY).send_message.begin(stream, stanza); + } + + public async bool try_process_sfs(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) { + Gee.List<Xep.StatelessFileSharing.FileShare> file_shares = Xep.StatelessFileSharing.get_file_shares(stanza); + if (file_shares != null) { + // For now, only accept file shares that have at least one supported hash + foreach (Xep.StatelessFileSharing.FileShare file_share in file_shares) { + if (!Xep.CryptographicHashes.has_supported_hashes(file_share.metadata.hashes)) { + return false; + } + } + + if (file_shares.size > 0) { + var file_transfers = new ArrayList<FileTransfer>(); + foreach (Xep.StatelessFileSharing.FileShare file_share in file_shares) { + var file_transfer = yield create_incoming_file_transfer(conversation, message, file_share.id, file_share.metadata, file_share.sources); + file_transfers.add(file_transfer); + stream_interactor.get_module(FileTransferStorage.IDENTITY).add_file(file_transfer); + } + var file_group = new FileTransferGroup() { + message_id = message.id, + file_transfers = file_transfers + }; + stream_interactor.get_module(FileTransferStorage.IDENTITY).add_file_group(file_group); + + fm2.received_file_group(file_group, conversation); + } + return true; + } + + var source_attachments = Xep.StatelessFileSharing.get_source_attachments(stanza); + if (source_attachments != null) { + foreach (var source_attachment in source_attachments) { + on_received_sources(stanza.from, conversation, source_attachment.to_message_id, source_attachment.to_file_transfer_id, source_attachment.sources); + return true; + } + } + + // Don't process messages that are fallback for legacy clients + if (Xep.StatelessFileSharing.is_sfs_fallback_message(stanza)) { + return true; + } + + return false; + } + + public async FileTransfer create_incoming_file_transfer(Conversation conversation, Message message, string? file_sharing_id, Xep.FileMetadataElement.FileMetadata metadata, Gee.List<Xep.StatelessFileSharing.Source>? sources) { FileTransfer file_transfer = new FileTransfer(); file_transfer.file_sharing_id = file_sharing_id; file_transfer.account = message.account; @@ -57,7 +136,8 @@ public class Dino.StatelessFileSharing : StreamInteractionModule, Object { stream_interactor.get_module(FileTransferStorage.IDENTITY).add_file(file_transfer); conversation.last_active = file_transfer.time; - file_manager.received_file(file_transfer, conversation); + + return file_transfer; } public void on_received_sources(Jid from, Conversation conversation, string attach_to_message_id, string? attach_to_file_id, Gee.List<Xep.StatelessFileSharing.Source> sources) { @@ -74,9 +154,9 @@ public class Dino.StatelessFileSharing : StreamInteractionModule, Object { // "If no <hash/> is provided or the <hash/> elements provided use unsupported algorithms, receiving clients MUST ignore // any attached sources from other senders and only obtain the file from the sources announced by the original sender." - // For now we only allow the original sender - if (from.equals(file_transfer.from) && Xep.CryptographicHashes.get_supported_hashes(file_transfer.hashes).is_empty) { - warning("Ignoring sfs source: Not from original sender or no known file hashes"); + // For now we don't allow source attachments for file shares without hashes. TODO extend this + if (Xep.CryptographicHashes.get_supported_hashes(file_transfer.hashes).is_empty) { + warning("Ignoring sfs source: No known file hashes"); return; } @@ -84,85 +164,26 @@ public class Dino.StatelessFileSharing : StreamInteractionModule, Object { file_transfer.add_sfs_source(source); } - if (file_manager.is_sender_trustworthy(file_transfer, conversation) && file_transfer.state == FileTransfer.State.NOT_STARTED && file_transfer.size >= 0 && file_transfer.size < 5000000) { - file_manager.download_file(file_transfer); + if (fm2.is_sender_trustworthy(file_transfer, conversation) && file_transfer.state == FileTransfer.State.NOT_STARTED && file_transfer.size >= 0 && file_transfer.size < 5000000) { + fm.download_file(file_transfer); } } - /* - public async void create_sfs_for_legacy_transfer(FileProvider file_provider, string info, Jid from, DateTime time, DateTime local_time, Conversation conversation, FileReceiveData receive_data, FileMeta file_meta) { - FileTransfer file_transfer = file_manager.create_file_transfer_from_provider_incoming(file_provider, info, from, time, local_time, conversation, receive_data, file_meta); - - HttpFileReceiveData? http_receive_data = receive_data as HttpFileReceiveData; - if (http_receive_data == null) return; + private void check_add_sfs_element(Entities.Message message, Xmpp.MessageStanza message_stanza, Conversation conversation) { + if (message.encryption != Encryption.NONE) return; - var sources = new ArrayList<Xep.StatelessFileSharing.Source>(); - Xep.StatelessFileSharing.HttpSource source = new Xep.StatelessFileSharing.HttpSource(); - source.url = http_receive_data.url; - sources.add(source); - - if (file_manager.is_jid_trustworthy(from, conversation)) { - try { - file_meta = yield file_provider.get_meta_info(file_transfer, http_receive_data, file_meta); - } catch (Error e) { - warning("Http meta request failed: %s", e.message); + // Check if it's a FileTransferGroup + FileTransferGroup? file_group = stream_interactor.get_module(FileTransferStorage.IDENTITY).get_file_group_by_message_id(message.id, conversation); + if (file_group != null) { + print("check added file group\n"); + foreach (FileTransfer file_transfer in file_group.file_transfers) { + Xep.StatelessFileSharing.set_sfs_element(message_stanza, file_transfer.file_sharing_id, file_transfer.file_metadata, file_transfer.sfs_sources); } - } - var metadata = new Xep.FileMetadataElement.FileMetadata(); - metadata.size = file_meta.size; - metadata.name = file_meta.file_name; - metadata.mime_type = file_meta.mime_type; + Xep.MessageProcessingHints.set_message_hint(message_stanza, Xep.MessageProcessingHints.HINT_STORE); - file_transfer.provider = SFS_PROVIDER_ID; - file_transfer.file_metadata = metadata; - file_transfer.sfs_sources = sources; - } - */ - - private class ReceivedMessageListener : MessageListener { - - public string[] after_actions_const = new string[]{ "STORE" }; - public override string action_group { get { return "MESSAGE_REINTERPRETING"; } } - public override string[] after_actions { get { return after_actions_const; } } - - private StatelessFileSharing outer; - private StreamInteractor stream_interactor; - - public ReceivedMessageListener(StatelessFileSharing outer) { - this.outer = outer; - this.stream_interactor = outer.stream_interactor; + return; } - public override async bool run(Entities.Message message, Xmpp.MessageStanza stanza, Conversation conversation) { - Gee.List<Xep.StatelessFileSharing.FileShare> file_shares = Xep.StatelessFileSharing.get_file_shares(stanza); - if (file_shares != null) { - // For now, only accept file shares that have at least one supported hash - foreach (Xep.StatelessFileSharing.FileShare file_share in file_shares) { - if (!Xep.CryptographicHashes.has_supported_hashes(file_share.metadata.hashes)) { - return false; - } - } - foreach (Xep.StatelessFileSharing.FileShare file_share in file_shares) { - outer.create_file_transfer(conversation, message, file_share.id, file_share.metadata, file_share.sources); - } - return true; - } - - var source_attachments = Xep.StatelessFileSharing.get_source_attachments(stanza); - if (source_attachments != null) { - foreach (var source_attachment in source_attachments) { - outer.on_received_sources(stanza.from, conversation, source_attachment.to_message_id, source_attachment.to_file_transfer_id, source_attachment.sources); - return true; - } - } - - // Don't process messages that are fallback for legacy clients - if (Xep.StatelessFileSharing.is_sfs_fallback_message(stanza)) { - return true; - } - - return false; - } } }
\ No newline at end of file |
