/// <summary> /// Selects a stream-method from the list of advertised methods. /// </summary> /// <param name="feature">The 'feature' element containing the data-form /// with advertised stream-methods.</param> /// <returns>The selected stream-method.</returns> /// <exception cref="ArgumentException">None of the advertised methods is /// supported.</exception> private string SelectStreamMethod(XmlElement feature) { // See if we support any of the advertised stream-methods. DataForm form = FeatureNegotiation.Parse(feature); ListField field = form.Fields["stream-method"] as ListField; // Order of preference: Socks5, Ibb. string[] methods = new string[] { "http://jabber.org/protocol/bytestreams", "http://jabber.org/protocol/ibb" }; for (int i = 0; i < methods.Length; i++) { if (ForceInBandBytestreams && methods[i] != "http://jabber.org/protocol/ibb") { continue; } if (field.Values.Contains(methods[i])) { return(methods[i]); } } throw new ArgumentException("No supported method advertised."); }
/// <summary> /// Creates the 'feature' XML element which is part of a 'Stream Initiation' /// request. /// </summary> /// <param name="streamOptions">An enumerable collection of accepted stream /// methods.</param> /// <returns>An XML 'feature' element.</returns> /// <exception cref="ArgumentNullException">The streamOptions parameter /// is null.</exception> private XmlElement CreateFeatureElement(IEnumerable <string> streamOptions) { streamOptions.ThrowIfNull("streamOptions"); // Create the data-form for stream-method selection. DataForm form = new RequestForm(); HashSet <Option> options = new HashSet <Option>(); foreach (string opt in streamOptions) { options.Add(new Option(opt)); } form.Fields.Add(new ListField("stream-method", true, null, null, options)); // Wrap it in a 'feature' element to create the offer. return(FeatureNegotiation.Create(form)); }
/// <summary> /// Parses the selected stream-method from the specified 'feature' XML /// element. /// </summary> /// <param name="feature">The 'feature' XML element.</param> /// <returns>The stream method contained in the 'feature' XML /// element.</returns> /// <exception cref="ArgumentNullException">The feature parameter is /// null.</exception> /// <exception cref="ArgumentException">The feature element contains /// invalid data.</exception> private string ParseStreamMethod(XmlElement feature) { feature.ThrowIfNull("feature"); DataForm form = FeatureNegotiation.Parse(feature); // The data-form must contain a field named 'stream-method'. var field = form.Fields["stream-method"]; if (field == null) { throw new ArgumentException("Missing or erroneous 'stream-method' field."); } string selected = field.Values.FirstOrDefault(); if (selected == null) { throw new ArgumentException("No stream-method selected."); } return(selected); }
/// <summary> /// Invoked whenever a 'Stream Initiation' request for file transfers /// is received. /// </summary> /// <param name="from">The JID of the XMPP entity that wishes to initiate /// the data-stream.</param> /// <param name="si">The 'si' element of the request.</param> /// <returns>The response to the SI request or an error element to include /// in the IQ response.</returns> private XmlElement OnStreamInitiationRequest(Jid from, XmlElement si) { try { string method = SelectStreamMethod(si["feature"]); // If the session-id is already in use, we cannot process the request. string sid = si.GetAttribute("id"); if (String.IsNullOrEmpty(sid) || siSessions.ContainsKey(sid)) { return(new XmppError(ErrorType.Cancel, ErrorCondition.Conflict).Data); } // Extract file information and hand to user. var file = si["file"]; string desc = file["desc"] != null ? file["desc"].InnerText : null, name = file.GetAttribute("name"); int size = int.Parse(file.GetAttribute("size")); FileTransfer transfer = new FileTransfer(from, im.Jid, name, size, sid, desc); string savePath = TransferRequest.Invoke(transfer); // User has rejected the request. if (savePath == null) { return(new XmppError(ErrorType.Cancel, ErrorCondition.NotAcceptable).Data); } // Create an SI session instance. SISession session = new SISession(sid, File.OpenWrite(savePath), size, true, from, im.Jid, im.GetExtension(method) as IDataStream); siSessions.TryAdd(sid, session); // Store the file's meta data. metaData.TryAdd(sid, new FileMetaData(name, desc)); // Construct and return the negotiation result. return(Xml.Element("si", "http://jabber.org/protocol/si").Child( FeatureNegotiation.Create(new SubmitForm( new ListField("stream-method", method))))); } catch (Exception e) { System.Diagnostics.Debug.WriteLine("Exception raised", e.ToString() + e.StackTrace); return(new XmppError(ErrorType.Cancel, ErrorCondition.BadRequest).Data); } }
/// <summary> /// Initializes the various XMPP extension modules. /// </summary> private void LoadExtensions() { version = im.LoadExtension<SoftwareVersion>(); sdisco = im.LoadExtension<ServiceDiscovery>(); ecapa = im.LoadExtension<EntityCapabilities>(); ping = im.LoadExtension<Ping>(); attention = im.LoadExtension<Attention>(); time = im.LoadExtension<EntityTime>(); block = im.LoadExtension<BlockingCommand>(); pep = im.LoadExtension<Pep>(); userTune = im.LoadExtension<UserTune>(); #if WINDOWSPLATFORM userAvatar = im.LoadExtension<UserAvatar>(); #endif userMood = im.LoadExtension<UserMood>(); dataForms = im.LoadExtension<DataForms>(); featureNegotiation = im.LoadExtension<FeatureNegotiation>(); streamInitiation = im.LoadExtension<StreamInitiation>(); siFileTransfer = im.LoadExtension<SIFileTransfer>(); inBandBytestreams = im.LoadExtension<InBandBytestreams>(); userActivity = im.LoadExtension<UserActivity>(); socks5Bytestreams = im.LoadExtension<Socks5Bytestreams>(); FileTransferSettings = new FileTransferSettings(socks5Bytestreams, siFileTransfer); serverIpCheck = im.LoadExtension<ServerIpCheck>(); messageCarbons = im.LoadExtension<MessageCarbons>(); inBandRegistration = im.LoadExtension<InBandRegistration>(); chatStateNotifications = im.LoadExtension<ChatStateNotifications>(); bitsOfBinary = im.LoadExtension<BitsOfBinary>(); vcardAvatars = im.LoadExtension<VCardAvatars>(); cusiqextension = im.LoadExtension<CustomIqExtension>(); messageArchiving = im.LoadExtension<MessageArchiving>(); messageArchiveManagement = im.LoadExtension<MessageArchiveManagement>(); multiUserChat = im.LoadExtension<MultiUserChat>(); serviceAdministration = im.LoadExtension<ServiceAdministration>(); adHocCommands = im.LoadExtension<AdHocCommands>(); directMucInvitations = im.LoadExtension<DirectMucInvitations>(); }