aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala')
-rw-r--r--xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala100
1 files changed, 100 insertions, 0 deletions
diff --git a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala
new file mode 100644
index 00000000..cd249017
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala
@@ -0,0 +1,100 @@
+using Gee;
+using Xmpp;
+using Xmpp.Xep;
+
+namespace Xmpp.Xep.JingleFileTransfer {
+
+private const string NS_URI = "urn:xmpp:jingle:apps:file-transfer:5";
+
+public errordomain Error {
+ FILE_INACCESSIBLE,
+}
+
+public class Module : XmppStreamModule {
+ public static Xmpp.ModuleIdentity<Module> IDENTITY = new Xmpp.ModuleIdentity<Module>(NS_URI, "0234_jingle_file_transfer");
+
+ public override void attach(XmppStream stream) {
+ stream.add_flag(new Flag());
+ stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
+ }
+ public override void detach(XmppStream stream) { }
+
+ public bool is_available(XmppStream stream, Jid full_jid) {
+ bool? has_feature = stream.get_flag(ServiceDiscovery.Flag.IDENTITY).has_entity_feature(full_jid, NS_URI);
+ if (has_feature == null || !(!)has_feature) {
+ return false;
+ }
+ return stream.get_module(Jingle.Module.IDENTITY).is_available(stream, Jingle.TransportType.STREAMING, full_jid);
+ }
+
+ public void offer_file(XmppStream stream, Jid receiver_full_jid, string path) throws Error {
+ File file = File.new_for_path(path);
+ FileInputStream input_stream;
+ int64 size;
+ try {
+ input_stream = file.read();
+ } catch (GLib.Error e) {
+ throw new Error.FILE_INACCESSIBLE(@"could not open the file \"$path\" for reading: $(e.message)");
+ }
+ try {
+ size = input_stream.query_info(FileAttribute.STANDARD_SIZE).get_size();
+ } catch (GLib.Error e) {
+ throw new Error.FILE_INACCESSIBLE(@"could not read the size: $(e.message)");
+ }
+
+ offer_file_stream(stream, receiver_full_jid, input_stream, file.get_basename(), size);
+ }
+
+ public void offer_file_stream(XmppStream stream, Jid receiver_full_jid, InputStream input_stream, string basename, int64 size) {
+ StanzaNode description = new StanzaNode.build("description", NS_URI)
+ .add_self_xmlns()
+ .put_node(new StanzaNode.build("file", NS_URI)
+ .put_node(new StanzaNode.build("name", NS_URI).put_node(new StanzaNode.text(basename)))
+ .put_node(new StanzaNode.build("size", NS_URI).put_node(new StanzaNode.text(size.to_string()))));
+ // TODO(hrxi): Add the mandatory hash field
+
+ Jingle.Session? session = stream.get_module(Jingle.Module.IDENTITY)
+ .create_session(stream, Jingle.TransportType.STREAMING, receiver_full_jid, Jingle.Senders.INITIATOR, "a-file-offer", description); // TODO(hrxi): Why "a-file-offer"?
+
+ FileTransfer transfer = new FileTransfer(input_stream);
+ session.on_ready.connect(transfer.send_data);
+ stream.get_flag(Flag.IDENTITY).add_file_transfer(transfer);
+ }
+
+ public override string get_ns() { return NS_URI; }
+ public override string get_id() { return IDENTITY.id; }
+}
+
+public class FileTransfer : Object {
+ InputStream input_stream;
+ public FileTransfer(InputStream input_stream) {
+ this.input_stream = input_stream;
+ }
+ public void send_data(Jingle.Session session, XmppStream stream) {
+ uint8 buffer[4096];
+ ssize_t read;
+ try {
+ if((read = input_stream.read(buffer)) != 0) {
+ session.send(stream, buffer[0:read]);
+ } else {
+ session.close_connection(stream);
+ }
+ } catch (GLib.IOError e) {
+ session.set_application_error(stream);
+ }
+ // TODO(hrxi): remove file transfer
+ }
+}
+
+public class Flag : XmppStreamFlag {
+ public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "jingle_file_transfer");
+
+ private Gee.List<FileTransfer> transfers = new ArrayList<FileTransfer>();
+
+ public void add_file_transfer(FileTransfer transfer) { transfers.add(transfer); }
+
+ public override string get_ns() { return NS_URI; }
+ public override string get_id() { return IDENTITY.id; }
+}
+
+}