public void TestByteStreamNumberWriting() { ByteStream stream = new ByteStream(); stream.WriteByte(0x08); stream.WriteUshort(0x4164); stream.WriteUint(0x7269656e); stream.WriteByteArray(new byte[] {0x6e, 0x65}); Assert.AreEqual(testData.Length, stream.GetByteCount()); ByteStream testStream = new ByteStream(stream.GetBytes()); Assert.AreEqual("Adrienne", testStream.ReadString(testStream.ReadByte(), Encoding.ASCII)); }
public void TestByteStreamStringWriting() { ByteStream stream = new ByteStream(); stream.WriteByte((byte) Encoding.ASCII.GetByteCount("Adrienne")); stream.WriteString("Adrienne", Encoding.ASCII); Assert.AreEqual(testData.Length, stream.GetByteCount()); byte[] data = stream.GetBytes(); for (int i = 0; i < testData.Length; i++) { Assert.AreEqual(testData[i], data[i]); } }
/// <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> /// Processes the asynchronous receipt of a FLAP /// </summary> /// <param name="res">The <see cref="IAsyncResult"/> of a BeginReceive call</param> private void ProcessFLAP(IAsyncResult res) { int bytesreceived = 0; int receiveindex = 0; byte[] flapbuffer = null; try { lock (socket) { bytesreceived = socket.EndRead(res); if (bytesreceived == 0) { throw new Exception("Socket receive returned 0 bytes read"); } flapbuffer = (byte[])res.AsyncState; receiveindex = bytesreceived; while (receiveindex < flapbuffer.Length) { bytesreceived = socket.Read(flapbuffer, receiveindex, flapbuffer.Length - receiveindex); if (bytesreceived == 0) { throw new Exception("Socket receive returned 0 bytes read"); } receiveindex += bytesreceived; } } } catch (Exception ex) { if (!isDisconnecting) { Logging.WriteString("Receive error in ProcessFLAP: {0}, connection {1}", ex.Message, ID); DisconnectFromServer(true); } return; } if (flapbuffer[0] == 0xFF) { int badcount = 0; for (badcount = 0; badcount < flapbuffer.Length && flapbuffer[badcount] == 0xFF; badcount++) { ; } // SOMEHOW there are two bytes of 0xFF occuring when requesting // SNAC family 0x10 and receiving SNAC(01,03). So that has to stop for (int i = badcount; i < flapbuffer.Length; i++) { flapbuffer[i - badcount] = flapbuffer[i]; } socket.Read(flapbuffer, flapbuffer.Length - badcount, badcount); } // Get the FLAP header out of the async result FLAPHeader flap = GetFLAPHeader(flapbuffer); ByteStream stream = ReadPacket(flap.DataSize); if (stream == null) { return; } // The full packet is here, so we can chuck it out for processing DataPacket dp; switch (flap.Channel) { case 0x01: // New connection negotiation // This will not occur, FLAP 0x01 is handled in ConnectToServer break; case 0x02: // SNAC data if (stream.GetByteCount() < 10) { break; // Don't return, don't disconnect, just keep on keeping on } dp = stream.CreateDataPacket(); dp.FLAP = flap; dp.ParentConnection = this; dp.ParentSession = parent; Processor.Enqueue(dp); break; case 0x03: // FLAP error // Session error: FLAP error, bailing out Logging.WriteString("Received error FLAP"); DisconnectFromServer(true); return; case 0x04: // Close connection negotiation //KSD-SYSTEMS - added at 27.11.2009 if (stream.GetByteCount() > 10) { dp = stream.CreateDataPacket(); if (((SNACFamily)dp.SNAC.FamilyServiceID) == SNACFamily.PrivacyManagementService) { PrivacyManagementService sub = (PrivacyManagementService)dp.SNAC.FamilySubtypeID; if (sub == PrivacyManagementService.ServiceParametersRequest) { parent.OnError(ServerErrorCode.ExternalClientRequest, dp); } } } Logging.WriteString("Received close connection FLAP"); DisconnectFromServer(false); return; case 0x05: // Keepalive packet Logging.WriteString("Received keepalive FLAP"); SendKeepalive(null); break; default: break; } // Shine on, you crazy connection keepAliveTimer.Change(60000, Timeout.Infinite); ReadHeader(); }
/// <summary> /// Cancel a direct connection attempt /// </summary> public void SendDirectConnectionCancellation(DirectConnection conn, string reason) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_OUTGOING_MESSAGE; ByteStream stream = new ByteStream(); InsertIcbmHeader(stream, conn.Cookie, 0x0002, conn.Other.ScreenName); using (ByteStream tlv05 = new ByteStream()) { tlv05.WriteUshort(RendezvousData.UshortFromType(RendezvousType.Cancel)); tlv05.WriteByteArray(conn.Cookie.ToByteArray()); tlv05.WriteByteArray(CapabilityProcessor.GetCapabilityArray(conn.Capability)); using (TlvBlock tlvs = new TlvBlock()) { tlvs.WriteUshort(0x000B, 0x0001); tlvs.WriteString(0x000C, reason, Encoding.ASCII); tlvs.WriteEmpty(0x0003); //KSD-SYSTEMS - commented at 02.12.2009 -> Canceling = Send Message only with Cookie //tlv05.WriteByteArray(tlvs.GetBytes()); } stream.WriteUshort(0x0005); stream.WriteUshort((ushort)tlv05.GetByteCount()); stream.WriteByteArray(tlv05.GetBytes()); } SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Accept a direct connection attempt /// </summary> public void SendDirectConnectionAccept(DirectConnection conn) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_OUTGOING_MESSAGE; ByteStream stream = new ByteStream(); InsertIcbmHeader(stream, conn.Cookie, 0x0002, conn.Other.ScreenName); using (ByteStream tlv05 = new ByteStream()) { tlv05.WriteUshort(RendezvousData.UshortFromType(RendezvousType.Accept)); tlv05.WriteByteArray(conn.Cookie.ToByteArray()); tlv05.WriteByteArray(CapabilityProcessor.GetCapabilityArray(conn.Capability)); tlv05.WriteUint(0x00030000); stream.WriteUshort(0x0005); stream.WriteUshort((ushort)tlv05.GetByteCount()); stream.WriteByteArray(tlv05.GetBytes()); } SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Sends a direct connection request /// </summary> /// <param name="conn">A <see cref="DirectConnection"/> object that will handle the request</param> public void RequestDirectConnectionInvite(DirectConnection conn) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_OUTGOING_MESSAGE; ByteStream stream = new ByteStream(); InsertIcbmHeader(stream, conn.Cookie, 0x0002, conn.Other.ScreenName); using (ByteStream tlv05 = new ByteStream()) { tlv05.WriteUshort(RendezvousData.UshortFromType(RendezvousType.Invite)); tlv05.WriteByteArray(conn.Cookie.ToByteArray()); tlv05.WriteByteArray(CapabilityProcessor.GetCapabilityArray(conn.Capability)); using (TlvBlock tlvs = new TlvBlock()) { tlvs.WriteUshort(DC_SEQUENCE_NUMBER, RendezvousData.UshortFromSequence(conn.Sequence)); if (conn.Sequence == RendezvousSequence.DirectOrStage1) { tlvs.WriteEmpty(0x000F); } if (!String.IsNullOrEmpty(conn.Message)) { tlvs.WriteString(DC_MESSAGE, conn.Message, Encoding.ASCII); } uint ipaddress = 0; if (conn.Method == DirectConnectionMethod.Proxied) { ipaddress = ConvertIPAddress(conn.AOLProxyIP); } else { ipaddress = ConvertIPAddress(conn.ClientIP); } tlvs.WriteUint(DC_PROXY_IP_ADDRESS, ipaddress); tlvs.WriteUint(DC_PROXY_IP_ADDRESS_COMPLIMENT, ~ipaddress); if (conn.Sequence == RendezvousSequence.DirectOrStage1) { tlvs.WriteUint(DC_CLIENT_IP_ADDRESS, ConvertIPAddress(conn.ClientIP)); } if (conn.Sequence != RendezvousSequence.Stage3) { tlvs.WriteUshort(DC_PORT, (ushort)conn.Port); tlvs.WriteUshort(DC_PORT_COMPLIMENT, (ushort)(~conn.Port)); } if (conn.Method == DirectConnectionMethod.Proxied) { tlvs.WriteEmpty(DC_USE_PROXY_FLAG); } if (conn is FileTransferConnection && conn.Sequence == RendezvousSequence.DirectOrStage1) { FileTransferConnection ftc = conn as FileTransferConnection; using (ByteStream tlv2711 = new ByteStream()) { tlv2711.WriteUshort((ushort)((ftc.TotalFiles > 1) ? 0x0002 : 0x0001)); tlv2711.WriteUshort((ushort)ftc.TotalFiles); tlv2711.WriteUint(ftc.TotalFileSize); tlv2711.WriteString(ftc.FileHeader.Name, Encoding.ASCII); tlv2711.WriteByte(0x00); tlvs.WriteByteArray(0x2711, tlv2711.GetBytes()); } tlvs.WriteString(0x2712, ftc.LocalFileNameEncoding.WebName, Encoding.ASCII); } tlv05.WriteByteArray(tlvs.GetBytes()); } stream.WriteUshort(0x0005); stream.WriteUshort((ushort)tlv05.GetByteCount()); stream.WriteByteArray(tlv05.GetBytes()); } // Acknowledgement request stream.WriteUint(0x00030000); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Invites an AIM user to an AOL chatroom /// </summary> /// <param name="chatroom">The <see cref="ChatRoom"/> describing the chatroom</param> /// <param name="screenName">The screenname of the user to invite</param> /// <param name="message">A message to send along with the invitation</param> public Cookie InviteToChatRoom(ChatRoom chatroom, string screenName, string message) { if (!parent.LoggedIn) { throw new NotLoggedInException(); } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_OUTGOING_MESSAGE; Cookie cookie = Cookie.CreateCookieForSending(); Encoding enc = Encoding.ASCII; byte destlength = (byte) enc.GetByteCount(screenName); ushort messagelength = (ushort) enc.GetByteCount(message); byte roomnamelength = (byte) enc.GetByteCount(chatroom.FullName); ByteStream stream = new ByteStream(); InsertIcbmHeader(stream, cookie, 0x0002, screenName); ByteStream header = new ByteStream(); header.WriteUshort(0x0000); header.WriteByteArray(cookie.ToByteArray()); header.WriteUint(0x748F2420); header.WriteUint(0x628711D1); header.WriteUint(0x82224445); header.WriteUint(0x53540000); using (TlvBlock tlv05 = new TlvBlock()) { tlv05.WriteUshort(0x000A, 0x0001); tlv05.WriteEmpty(0x000F); tlv05.WriteString(0x000C, message, enc); ByteStream tlv2711 = new ByteStream(); tlv2711.WriteUshort(chatroom.Exchange); tlv2711.WriteByte(roomnamelength); tlv2711.WriteString(chatroom.FullName, enc); tlv2711.WriteUshort(chatroom.Instance); tlv05.WriteByteArray(0x2711, tlv2711.GetBytes()); header.WriteByteArray(tlv05.GetBytes()); } stream.WriteUshort(0x0005); stream.WriteUshort((ushort) header.GetByteCount()); stream.WriteByteArray(header.GetBytes()); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); return cookie; }
/// <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; } } } }