/// <summary> /// Completes the initial connection to the AOL proxy server /// </summary> /// <remarks>This method is used to complete the proxy server transaction for both /// Stage 1 sending and Stage 2 receiver-redirect proxy scenarios</remarks> private void InitAolProxyConnectFinished() { try { ProxyInitializeSend(); RendezvousProxyPacket rpp = ReadProxyPacket(); if (rpp.Command == RendezvousProxyCommand.Acknowledge) { using (ByteStream bstream = new ByteStream(rpp.Data)) { Port = bstream.ReadUshort(); aolProxyIP = (new IPAddress(bstream.ReadByteArray(4))).ToString(); } // Send the "send file" request on SNAC(04,06):02 parent.Messages.RequestDirectConnectionInvite(this); // Wait for the proxy to send its 12 byte READY sequence lock (socket) { socket.BeginRead(new byte[12], 0, 12, new AsyncCallback(ProxyReceivedReady), null); //socket.BeginReceive(new byte[12], 0, 12, SocketFlags.None, new AsyncCallback(ProxyReceivedReady), null); } } else { ushort error = (ushort)((rpp.Data[0] << 8) | rpp.Data[1]); if (error == 0x0004) { throw new Exception("Recipient not logged in"); } else if (error == 0x000D) { throw new Exception("Client sent bad request"); } throw new Exception("AOL proxy sent unknown error"); } } catch (Exception ex) { if (DirectConnectionFailed != null) { DirectConnectionFailed(ex.Message); } } }
/// <summary> /// Parses a byte buffer into an <see cref="BartID"/> object /// </summary> private void ReadIconInfo(byte[] buffer, UserInfo userinfo) { using (ByteStream iconStream = new ByteStream(buffer)) { int iconStreamSize = iconStream.GetByteCount(); while (iconStream.CurrentPosition + 4 <= iconStreamSize) { BartID item = new BartID(iconStream); // Find the end of the current data item in the stream int endDataPosition = iconStream.CurrentPosition + item.Data.Length; switch (item.Type) { case BartTypeId.BuddyIcon: if (!GraphicsManager.IsBlankIcon(item.Data)) { userinfo.Icon = item; } break; case BartTypeId.StatusString: // Available message using (ByteStream messageStream = new ByteStream(item.Data)) { Encoding encoding = Encoding.UTF8; byte[] amessage = new byte[0]; if (messageStream.HasMoreData) { // Pull the message to a byte array, assume at first that the encoding // is UTF-8. If existing encoding information exists, use that instead amessage = messageStream.ReadByteArray(messageStream.ReadByte()); // Check if there's encoding information available if (messageStream.HasMoreData) { // Check to see if the encoding's been specified if (messageStream.ReadUshort() == 0x0001) { messageStream.AdvanceOffset(2); string encodingStr = messageStream.ReadString(messageStream.ReadUshort(), Encoding.ASCII); // Try to use the encoding from the byte stream try { encoding = Encoding.GetEncoding(encodingStr); } catch (ArgumentException) { Logging.WriteString( "ReadIconInfo: Got unknown encoding for available message (" + encodingStr + "), falling back to UTF-8"); encoding = Encoding.UTF8; } } } } userinfo.AvailableMessage = Encoding.Unicode.GetString( Encoding.Convert(encoding, Encoding.Unicode, amessage)); } break; default: break; } } } }
/// <summary> /// Initializes a new BartID from a byte stream /// </summary> internal BartID(ByteStream stream) { type = (BartTypeId)stream.ReadUshort(); flags = (BartFlags)stream.ReadByte(); byte dataLength = stream.ReadByte(); data = stream.ReadByteArray(dataLength); }
/// <summary> /// Processes the received message /// </summary> private void EndReadHeader(IAsyncResult res) { byte[] odcheader = null; try { odcheader = (byte[])res.AsyncState; socket.EndRead(res); } catch (Exception ex) { Logging.WriteString(String.Format("Exception in DirectIMConnection.EndReadHeader: {0}", ex)); DisconnectFromServer(true); } // Verify that this is an ODC header if (Encoding.ASCII.GetString(odcheader, 0, 4) != "ODC2") { // Huh... return; } ushort datalen = (ushort)((odcheader[4] << 8) | odcheader[5]); if (datalen < 6) { // Oh return; } ByteStream messageheader = ReadPacket(datalen - 6); if (messageheader == null) { // Tum ta tiddily tumpa turr return; } // Extract various members from the message header messageheader.AdvanceToPosition(6); byte[] cookie = messageheader.ReadByteArray(8); messageheader.AdvanceToPosition(22); uint datalength = messageheader.ReadUint(); ushort charset = messageheader.ReadUshort(); ushort subcharset = messageheader.ReadUshort(); DirectIMFlags flags = (DirectIMFlags)messageheader.ReadUint(); messageheader.AdvanceToPosition(38); string screenname = messageheader.ReadString(16, Encoding.ASCII); if ((flags & DirectIMFlags.TypingPacket) != 0) { // Determine the type of typing packet this is if ((flags & DirectIMFlags.UserTyping) != 0) { //_parent.OnTypingNotification(screenname, TypingNotification.TypingStarted); } else if ((flags & DirectIMFlags.UserTyped) != 0) { //_parent.OnTypingNotification(screenname, TypingNotification.TextTyped); } else { // TODO: restore these // _parent.OnTypingNotification(screenname, TypingNotification.TypingFinished); } // Probably no data, but read it in anyway to make sure we're not missing anything ReadPacket((int)datalength); } else if ((flags & DirectIMFlags.ConfirmationPacket) != 0 && datalength == 0) { // Do we really do anything here? I don't think so. } else { // Create a new instant message DirectIM dim = new DirectIM(Other.ScreenName, this); dim.Cookie = csammisrun.OscarLib.Cookie.GetReceivedCookie(cookie); dim.IsAutoResponse = ((flags & DirectIMFlags.AutoResponse) != 0); dim.Encoding = IM.GetEncodingFromCharset(charset, subcharset); // Create a spooler to incrementally read in a DirectIM packet, // then restart the read sequence when it's done DirectIMDataReader reader = new DirectIMDataReader(this, dim); reader.DataReaderComplete += new DataReaderCompleteHandler(delegate { parent.OnDirectIMReceived( reader.Message); reader.Dispose(); ReadHeader(); }); reader.Read(datalength); return; } // Restart the read sequence ReadHeader(); }
/// <summary> /// Processes a newly received offline message for the specified UIN /// </summary> /// <remarks>This is called from the ICQ manager, which receives the incoming /// offline message packet and sends it here for processing</remarks> internal void ReadIcqOfflineMessage(String uin, ByteStream stream) { String sender = stream.ReadUintLE().ToString(); // Read in the date information (GMT) ushort year = stream.ReadUshortLE(); byte month = stream.ReadByte(); byte day = stream.ReadByte(); byte hourGmt = stream.ReadByte(); byte minute = stream.ReadByte(); DateTime received = new DateTime(year, month, day, hourGmt, minute, 0, DateTimeKind.Utc); // Read in message type information byte messageType = stream.ReadByte(); byte messageFlags = stream.ReadByte(); Encoding messageEncoding = GetOfflineMessageEncoding(messageType); OfflineIM im = new OfflineIM(sender); im.ReceivedOn = received; im.Message = Encoding.Unicode.GetString( Encoding.Convert(messageEncoding, Encoding.Unicode, stream.ReadByteArray(stream.ReadUshortLE() - 1))); im.IsAutoResponse = (messageFlags == 0x03) || (messageType == 0xE8); // Store it for delivery to the client AcceptIcbmOIM(im); }
/// <summary> /// Processes the inner TLV list in TLV 0x0005 and returns a new DirectConnection /// </summary> private DirectConnection ProcessChannel2Tlv05(ByteStream stream, UserInfo ui, DataPacket dp) { byte[] invitemessage; Encoding encoding = Encoding.ASCII; string language = "en"; DirectConnection directconn = null; // Pull the type, cookie, and capability array RendezvousType rtype = RendezvousData.TypeFromUshort(stream.ReadUshort()); Cookie cookie = Cookie.GetReceivedCookie(stream.ReadByteArray(8)); byte[] capabilitiesArray = stream.ReadByteArray(16); Capabilities capabilities = CapabilityProcessor.ProcessCLSIDList(capabilitiesArray); // Create the correct type of connection based on the capability if (capabilities == Capabilities.SendFiles) { if ((directconn = parent.Connections.GetDirectConnectionByCookie(cookie)) == null) { directconn = parent.Connections.CreateNewFileTransferConnection( DirectConnectionMethod.Direct, DirectConnectRole.Receiver); } } else if (capabilities == Capabilities.DirectIM) { if ((directconn = parent.Connections.GetDirectConnectionByCookie(cookie)) == null) { directconn = parent.Connections.CreateNewDirectIMConnection( DirectConnectionMethod.Direct, DirectConnectRole.Receiver); } } else if (capabilities == Capabilities.Chat) { directconn = parent.Connections.CreateNewChatInvitationConnection(DirectConnectRole.Receiver); } else { // Currently unsupported parent.OnWarning(ServerErrorCode.UnknownRendezvousChannel, dp); return null; } directconn.Other = ui; directconn.Cookie = cookie; directconn.Type = rtype; ByteStream serviceData = null; Encoding serviceDataEncoding = Encoding.ASCII; // Process the inner TLV list using (TlvBlock tlvs = new TlvBlock(stream.ReadByteArrayToEnd())) { directconn.AOLProxyIP = tlvs.ReadIPAddress(DC_PROXY_IP_ADDRESS); // proxy ip directconn.ClientIP = tlvs.ReadIPAddress(DC_CLIENT_IP_ADDRESS); // internal ip directconn.VerifiedIP = tlvs.ReadIPAddress(0x0004); // external ip directconn.Port = tlvs.ReadUshort(DC_PORT); directconn.Sequence = RendezvousData.SequenceFromUshort(tlvs.ReadUshort(DC_SEQUENCE_NUMBER)); invitemessage = tlvs.ReadByteArray(DC_MESSAGE); if (tlvs.HasTlv(0x000D)) { encoding = Encoding.GetEncoding(tlvs.ReadString(0x000D, Encoding.ASCII)); } language = tlvs.ReadString(0x000E, Encoding.ASCII); directconn.Method = (tlvs.HasTlv(DC_USE_PROXY_FLAG)) ? DirectConnectionMethod.Proxied : DirectConnectionMethod.Direct; serviceData = new ByteStream(tlvs.ReadByteArray(0x2711)); if (tlvs.HasTlv(0x2712)) { serviceDataEncoding = Encoding.GetEncoding(tlvs.ReadString(0x2712, Encoding.ASCII)); } } if (invitemessage != null) { directconn.Message = encoding.GetString(invitemessage, 0, invitemessage.Length); } // Process the extra data, if necessary if (directconn is FileTransferConnection || directconn is DirectIMConnection) { ProcessDirectConnectionRequest(directconn, serviceData); } else if (directconn is ChatInvitationConnection) { ChatInvitationConnection cic = directconn as ChatInvitationConnection; cic.ChatInvite = new ChatInvitation(); cic.ChatInvite.Message = directconn.Message; cic.ChatInvite.Encoding = encoding; cic.ChatInvite.Language = language; ProcessChatInvitationRequest(cic, serviceData); } return directconn; }
/// <summary> /// Retrieves the message text from SNAC(04,07) TLV 02 /// </summary> /// <param name="stream">A received <see cref="ByteStream"/></param> /// <param name="message">An <see cref="IM"/> object to be populated</param> private void GetChannelOneMessage(ByteStream stream, ref IM message) { while (stream.HasMoreData) { byte identifier = stream.ReadByte(); byte version = stream.ReadByte(); ushort length = stream.ReadUshort(); switch (identifier) { case 0x01: // Message text ushort charset = stream.ReadUshort(); ushort language = stream.ReadUshort(); Encoding incoming = IM.GetEncodingFromCharset(charset, language); message.Message = Encoding.Unicode.GetString( Encoding.Convert(incoming, Encoding.Unicode, stream.ReadByteArray(length - 4))); break; default: // Unhandled case stream.AdvanceOffset(length); break; } } }
/// <summary> /// Retrieves the message text from SNAC(04,07) TLV 05 /// </summary> /// <param name="stream">A received <see cref="ByteStream"/></param> /// <param name="message">An <see cref="IM"/> object to be populated</param> private void GetChannelfourMessage(ByteStream stream, ref IM message) { stream.ReadByteArray(46); //fixed unknon part ushort length = stream.ReadUshort(); ushort charset = stream.ReadUshort(); stream.ReadByte(); ushort charsubset = (ushort)0;//stream.ReadUshort(); Encoding incoming = IM.GetEncodingFromCharset(charset, charsubset); string xml = Encoding.Unicode.GetString( Encoding.Convert(incoming, Encoding.Unicode, stream.ReadByteArray(length))); // parse xml System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); doc.LoadXml(xml); System.Xml.XmlNode node = doc.SelectSingleNode("/sms_message/text"); if (node != null) { message.Message = node.InnerText; } node = doc.SelectSingleNode("/sms_message/sender"); if (node != null) { message.ScreenName = node.InnerText; } }