/// <summary> /// Attempts to initiate a data stream with the XMPP entity with the specified /// JID. /// </summary> /// <param name="to">The JID of the XMPP entity to initiate a data-stream /// with.</param> /// <param name="mimeType">The MIME type of the data to be transferred across /// the stream.</param> /// <param name="profile">The 'Stream Initiation' profile to use.</param> /// <param name="streamOptions">An enumerable collection of supported /// stream methods which are advertised to the receiving XMPP /// entity.</param> /// <param name="data">An XML element containing any additional data the /// specified 'Stream Initiation' profile may require.</param> /// <param name="cb">A callback method to invoke once the result of the /// stream-initation operation has been received.</param> /// <returns>An initialized instance of the InitiationResult class containing /// the negotiated stream-method and session identifier.</returns> /// <exception cref="ArgumentNullException">The to parameter or the mimeType /// parameter or the profile parameter or the streamOptions parameter /// is null.</exception> /// <exception cref="ArgumentException">The streamOptions enumerable contains /// no elements, or the stream-initiation response received contained no /// selection for the stream-method.</exception> /// <exception cref="NotSupportedException">The XMPP entity with /// the specified JID does not support the 'Stream Initiation' XMPP /// extension.</exception> public void InitiateStreamAsync(Jid to, string mimeType, string profile, IEnumerable <string> streamOptions, XmlElement data = null, Action <InitiationResult, Iq> cb = null) { to.ThrowIfNull("to"); mimeType.ThrowIfNull("mimeType"); profile.ThrowIfNull("profile"); streamOptions.ThrowIfNull("streamOptions"); if (streamOptions.Count() == 0) { throw new ArgumentException("The streamOptions enumerable must " + "include one or more stream-options."); } if (!ecapa.Supports(to, Extension.StreamInitiation)) { throw new NotSupportedException("The XMPP entity does not support " + "the 'Stream Initiation' extension."); } string sid = GenerateSessionId(); var si = CreateSiElement(sid, mimeType, profile, streamOptions, data); // Perform the actual request. im.IqRequestAsync(IqType.Set, to, im.Jid, si, null, (id, iq) => { if (cb == null) { return; } InitiationResult result = null; if (iq.Type != IqType.Error) { // Result must contain a 'feature' element. var feat = iq.Data["si"]["feature"]; string selected = ParseStreamMethod(feat); // Construct the initiation result and call the provided callback. result = new InitiationResult(sid, selected, iq.Data["si"]); } cb(result, iq); }); }
/// <summary> /// Invoked once the result of a pending stream-initiation operation has been /// received. /// </summary> /// <param name="result">The result of the stream-initiation operation. If /// this parameter is null, stream-initiation failed.</param> /// <param name="to">The JID of the XMPP user to offer the file to.</param> /// <param name="stream">The stream to read the file-data from.</param> /// <param name="name">The name of the file, as offered to the XMPP user /// with the specified JID.</param> /// <param name="size">The number of bytes to transfer.</param> /// <param name="cb">A callback method invoked once the other site has /// accepted or rejected the file-transfer request.</param> /// <param name="description">A description of the file so the receiver can /// better understand what is being sent.</param> /// <remarks>This is called in the context of an arbitrary thread.</remarks> void OnInitiationResult(InitiationResult result, Jid to, string name, Stream stream, long size, string description, Action <bool, FileTransfer> cb) { FileTransfer transfer = new FileTransfer(im.Jid, to, name, size, null, description); try { // Get the instance of the data-stream extension that the other site has // selected. IDataStream ext = im.GetExtension(result.Method) as IDataStream; // Register the session. SISession session = new SISession(result.SessionId, stream, size, false, im.Jid, to, ext); siSessions.TryAdd(result.SessionId, session); // Store the file's meta data. metaData.TryAdd(result.SessionId, new FileMetaData(name, description)); // Invoke user-provided callback. if (cb != null) { cb.Invoke(true, transfer); } // Perform the actual data-transfer. try { ext.Transfer(session); } catch (Exception e) { // Nothing to do here. } } catch { // Something went wrong. Invoke user-provided callback to let them know // the file-transfer can't be performed. if (cb != null) { cb.Invoke(false, transfer); } } }