/// <summary> /// Sends an instant message /// </summary> /// <param name="screenName">The screenname to receive the IM</param> /// <param name="message">The message to send</param> /// <param name="flags">A <see cref="OutgoingMessageFlags"/> enumeration specifying what /// additional information should be sent with the message</param> /// <remarks>Delivery confirmation results or sending errors will be returned in the <see cref="MessageDeliveryUpdate"/> event.</remarks> /// <exception cref="NotLoggedInException">Thrown when the <see cref="Session"/> is not logged in</exception> public Cookie SendMessage(String screenName, String message, OutgoingMessageFlags flags) { return SendMessage(screenName, message, flags, null); }
/// <summary> /// Sends an instant message /// </summary> /// <param name="screenName">The screenname to receive the IM</param> /// <param name="message">The message to send</param> /// <param name="flags">A <see cref="OutgoingMessageFlags"/> enumeration specifying what /// additional information should be sent with the message</param> /// <param name="attachments">A list of <see cref="Attachment"/>s to send with the message</param> /// <remarks> /// <para>Delivery confirmation results or sending errors will be returned in the <see cref="MessageDeliveryUpdate"/> event.</para> /// <para>If any attachments are specified in the <paramref name="attachments"/> list, this method will /// attempt to open a Direct Connection, a peer-to-peer connection that could expose the local /// IP address to the other participant in the conversation. If a Direct Connection cannot be established, /// this method will not attempt to send the message without the attachments. The <see cref="Session.DirectIMSessionCancelled"/> /// event will be raised, and the client should attempt to send the message without attachments manually.</para></remarks> /// <exception cref="NotLoggedInException">Thrown when the <see cref="Session"/> is not logged in</exception> public Cookie SendMessage(String screenName, String message, OutgoingMessageFlags flags, List<Attachment> attachments) { if (!parent.LoggedIn) { throw new NotLoggedInException(); } // See if there is an existing Direct Connection for this screen name. // If there is, send the message by it. If there isn't and there are // attachments to send along, create a new DC DirectIMConnection conn = parent.Connections.GetDirectIMByScreenname(screenName); if (conn != null || (attachments != null && attachments.Count > 0)) { // Make sure the connection hasn't been disconnected on the other side if (conn != null && conn.Connected == false) { // If there are no attachments, it can be sent through the server, // otherwise the DC will attempt reconnection if (attachments == null || attachments.Count == 0) { // No attachments, just send it through the server return SendMessageThroughServer(screenName, message, flags); } } if (conn == null) { conn = parent.Connections.CreateNewDirectIMConnection(DirectConnectionMethod.Direct, DirectConnectRole.Initiator); RequestDirectConnectionInvite(conn); } DirectIM dim = new DirectIM(screenName, conn); dim.Cookie = Cookie.CreateCookieForSending(); dim.Attachments = attachments; dim.Message = message; dim.IsAutoResponse = (flags & OutgoingMessageFlags.AutoResponse) != 0; conn.SendMessage(dim); return dim.Cookie; } else { return SendMessageThroughServer(screenName, message, flags); } }
/// <summary> /// Sends an ICBM on channel 1 -- SNAC(04,06) /// </summary> /// <param name="destination">The screenname to receive the IM</param> /// <param name="message">The message to send</param> /// <param name="flags">A <see cref="OutgoingMessageFlags"/> enumeration specifying what /// additional information should be sent with the message</param> private Cookie SendMessageThroughServer(string destination, string message, OutgoingMessageFlags flags) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_OUTGOING_MESSAGE; byte[] default_features = new byte[] { 0x01, 0x01, 0x01, 0x02 }; Cookie cookie = Cookie.CreateCookieForSending(); Encoding encoding = UtilityMethods.FindBestOscarEncoding(message); ByteStream stream = new ByteStream(); InsertIcbmHeader(stream, cookie, 0x0001, destination); using (TlvBlock tlvs = new TlvBlock()) { // Write in TLV 0x0002: a text message using (TlvBlock tlv02 = new TlvBlock()) { tlv02.WriteByteArray(0x0501, default_features); ByteStream feature0101 = new ByteStream(); feature0101.WriteUshort(Marshal.EncodingToCharset(encoding)); feature0101.WriteUshort(0x0000); feature0101.WriteString(message, encoding); tlv02.WriteByteArray(0x0101, feature0101.GetBytes()); tlvs.WriteByteArray(0x0002, tlv02.GetBytes()); } // Pack in optional TLVs if ((flags & OutgoingMessageFlags.AutoResponse) != 0) { tlvs.WriteEmpty(0x0004); } else { // Request a notification of delivery - note that this can't happen // with an AutoResponse flag set, otherwise the message is bounced tlvs.WriteEmpty(0x0003); } if ((flags & OutgoingMessageFlags.DeliverOffline) != 0 && (flags & OutgoingMessageFlags.AutoResponse) == 0) { // Try to store if the user is offline tlvs.WriteEmpty(0x0006); } // Add the TLVs to the byte stream stream.WriteByteArray(tlvs.GetBytes()); } // Cache the message for delivery updates messageStatuses.Add(sh.RequestID, new MessageStatusEventArgs(cookie, destination)); // Send that sucker off SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); return cookie; }