/// <summary> /// Processes a "You Were Added" notification sent by the server -- SNAC(13,1C) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(13,1C)</param> /// <remarks> /// The server only sends this SNAC to ICQ clients, so the packet is passed to to the /// <see cref="IcqManager"/> for dealing-with /// </remarks> public static void ProcessAddedMessage(DataPacket dp) { int length = dp.Data.ReadByte(); String uin = dp.Data.ReadString(length, Encoding.ASCII); dp.ParentSession.OnAddedToRemoteList(uin); }
/// <summary> /// Processes a popup message sent by the server -- SNAC(08,02) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(08,02)</param> public static void ProcessPopupMessage(DataPacket dp) { TlvBlock tlvs = new TlvBlock(dp.Data.ReadByteArrayToEnd()); string message = tlvs.ReadString(0x0001, Encoding.ASCII); string url = tlvs.ReadString(0x0002, Encoding.ASCII); ushort width = tlvs.ReadUshort(0x0003); ushort height = tlvs.ReadUshort(0x0004); ushort delay = tlvs.ReadUshort(0x0005); dp.ParentSession.OnPopupMessage(width, height, delay, url, message); }
/// <summary> /// Enqueues a SNAC for transmission with the appropriate RateClass /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> /// <remarks> /// <para> /// This needs commenting /// </para> /// </remarks> public static void BuildFLAP(DataPacket dp) { // Build the FLAP header dp.FLAP.DatagramSequenceNumber = 0; // Gets bound in Connection.cs dp.FLAP.Channel = (byte) FLAPChannels.SNACData; // Build the size of the data to be sent, not counting the FLAP header dp.FLAP.DataSize = (ushort) (10 + dp.Data.GetByteCount()); dp.Data.PrependOscarHeaders(dp.FLAP, dp.SNAC); SNACFunctions.DispatchToRateClass(dp); }
/// <summary> /// Enqueues a data packet to be processed by SNAC handling functions /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> public void Enqueue(DataPacket dp) { lock (this) { processQueue.Enqueue(dp); if (!hasTimerBeenSet) { SetDispatchTimer(); } } }
/// <summary> /// Processes a list of known interests from the server -- SNAC(0F,05) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(0F,05)</param> /// <remarks> /// libfaim doesn't implement the interest list fetching, so this one's thanks to Mark Doliner's /// ([email protected]) documentation. /// </remarks> public static void ProcessInterestList(DataPacket dp) { dp.Data.ReadUshort(); // First two bytes: 0x0001 ushort num_items = dp.Data.ReadUshort(); InterestItem[] interests = new InterestItem[num_items]; for (int i = 0; i < num_items; i++) { interests[i] = dp.Data.ReadInterestItem(); } dp.ParentSession.OnInterestsReceived(interests); }
/// <summary> /// Process an incoming <see cref="DataPacket"/> from SNAC family 0x0017 /// </summary> /// <param name="dp">A <see cref="DataPacket"/> received by the server</param> public void ProcessIncomingPacket(csammisrun.OscarLib.Utility.DataPacket dp) { switch (dp.SNAC.FamilySubtypeID) { case AUTH_KEY_RESPONSE: SendAuthorizationRequest(dp); break; case AUTH_LOGIN_RESPONSE: ProcessLoginResponse(dp); break; } }
/// <summary> /// Processes the results of a search-by-email request -- SNAC(0A,03) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(0A,03)</param> public static void ProcessSearchResults(DataPacket dp) { string email = (string) dp.ParentSession.RetrieveRequestID(dp.SNAC.RequestID); List<string> accts = new List<string>(); while (dp.Data.HasMoreData) { ushort key = dp.Data.ReadUshort(); accts.Add(dp.Data.ReadString(dp.Data.ReadUshort(), Encoding.ASCII)); } dp.ParentSession.OnSearchByEmailResults(email, accts.ToArray()); }
/// <summary> /// Dispatches a newly received <see cref="DataPacket"/> according to its SNAC family /// </summary> /// <param name="dp">The packet to dispatch</param> /// <returns><c>true</c> if the packet was handled, <c>false</c> if no handlers were registered for its SNAC family</returns> public bool DispatchPacket(DataPacket dp) { bool handled = false; if (handlers.ContainsKey(dp.SNAC.FamilyServiceID)) { if (handlers[dp.SNAC.FamilyServiceID] != null) { handlers[dp.SNAC.FamilyServiceID].ProcessIncomingPacket(dp); handled = true; } } return handled; }
/// <summary> /// Reads the error code and subcode from a SNAC(XX,01) packet /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(XX,01)</param> /// <param name="errorCode">The main error code contained in the SNAC</param> /// <param name="subCode">The subcode contained in the SNAC, or 0 if there is no subcode present</param> public static void GetSNACErrorCodes(DataPacket dp, out ushort errorCode, out ushort subCode) { errorCode = dp.Data.ReadUshort(); subCode = 0; if (dp.Data.HasMoreData) { using (TlvBlock tlvs = dp.Data.ReadTlvBlockByLength(dp.Data.GetRemainingByteCount())) { if (tlvs.HasTlv(0x0008)) { subCode = tlvs.ReadUshort(0x0008); } } } }
/// <summary> /// Sends an acknowledgement of the server's rate limitations -- SNAC(01,08) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> /// <param name="classes">The known rate classes to acknowledge</param> public static void AcknowledgeRateLimitations(DataPacket dp, ushort[] classes) { Session sess = dp.ParentSession; SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.AcknowledgeRateLimits; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); for (int i = 0; i < classes.Length; i++) { stream.WriteUshort(classes[i]); } DataPacket dp2 = Marshal.BuildDataPacket(sess, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); sess.OnLoginStatusUpdate("Protocol negotiation complete", 0.66); /* * If this is the initial services connection, we call the remaining SNACs * in the login sequence. * Otherwise, this is the last step in setting up a new service connection, * and we send SNAC(01,02) here. */ if (!sess.LoggedIn) { // Start stage 3, services setup RequestOwnInformation(sess); SNAC13.RequestParametersList(sess); SNAC13.RequestInitialContactList(sess); sess.Statuses.RequestParameters(); sess.Messages.RequestParametersList(); SNAC09.RequestParametersList(sess); sess.Statuses.ReportClientCapabilities(); sess.Statuses.SetProfile(sess.Statuses.Profile); } else { SendReadyNotification(dp); } }
/// <summary> /// Process an incoming <see cref="DataPacket"/> from SNAC family 0x000A or 0x000F /// </summary> /// <param name="dp">A <see cref="DataPacket"/> received by the server</param> public void ProcessIncomingPacket(csammisrun.OscarLib.Utility.DataPacket dp) { if (dp.SNAC.FamilyServiceID == SNAC_USERLOOKUP_FAMILY) { switch (dp.SNAC.FamilySubtypeID) { case USERLOOKUP_EMAIL_RESULTS: ProcessEmailSearchResults(dp); break; } } else if (dp.SNAC.FamilyServiceID == SNAC_DIRECTORY_FAMILY) { switch (dp.SNAC.FamilySubtypeID) { } } }
public void ProcessIncomingPacket(Utility.DataPacket dp) { switch ((UsageStatsService)dp.SNAC.FamilySubtypeID) { case UsageStatsService.ClientServerError: SNACFunctions.ProcessErrorNotification(dp); break; case UsageStatsService.SetMinimumInterval: ProcessReportInterval(dp); break; case UsageStatsService.UsageReportAck: ProcessReportAck(dp); break; default: break; } }
/// <summary> /// Processes a login response -- SNAC(17,03) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(17,03)</param> public static void ProcessLoginResponse(DataPacket dp) { // Pull apart SNAC(17,03) Cookie cookie; string BOSaddress; using (TlvBlock tlvs = new TlvBlock(dp.Data.ReadByteArrayToEnd())) { if (tlvs.HasTlv(0x0008)) { ushort errorcode = tlvs.ReadUshort(0x0008); dp.ParentSession.OnLoginFailed((LoginErrorCode)errorcode); return; } BOSaddress = tlvs.ReadString(0x0005, Encoding.ASCII); cookie = Cookie.GetReceivedCookie(tlvs.ReadByteArray(0x0006)); } // Shut down the authorization connection // Socket shutdown is initiated by the server dp.ParentSession.OnLoginStatusUpdate("Authorized", 0.33); dp.ParentConnection.DisconnectFromServer(false); // Create a new connection to the BOS server Connection newconn = dp.ParentSession.Connections.CreateNewConnection(0x0001); string[] bosinfo = BOSaddress.Split(':'); newconn.ServerConnectionCompleted += new ServerConnectionCompletedHandler(newconn_ServerConnnectionCompleted); newconn.Server = bosinfo[0]; newconn.Port = Int32.Parse(bosinfo[1]); newconn.Cookie = cookie; newconn.ConnectToServer(); // The connection process continues when the server sends SNAC(01,03) }
/// <summary> /// Sends authorization request -- SNAC(17,02) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(17,07)</param> public static void SendAuthorizationRequest(DataPacket dp) { // Pull apart SNAC(17,07) byte[] key = dp.Data.ReadByteArray(dp.Data.ReadUshort()); // Construct SNAC(17,02) SNACHeader header = new SNACHeader(); header.FamilyServiceID = (ushort) SNACFamily.AuthorizationRegistrationService; header.FamilySubtypeID = (ushort) AuthorizationRegistrationService.LoginRequest; header.Flags = 0; header.RequestID = Session.GetNextRequestID(); OSCARIdentification id = dp.ParentSession.ClientIdentification; ByteStream stream = new ByteStream(); using (TlvBlock tlvs = new TlvBlock()) { tlvs.WriteString(0x0001, dp.ParentSession.ScreenName, Encoding.ASCII); tlvs.WriteString(0x0003, id.ClientName, Encoding.ASCII); tlvs.WriteString(0x000F, "en", Encoding.ASCII); tlvs.WriteString(0x000E, "us", Encoding.ASCII); tlvs.WriteUint(0x0014, id.ClientDistribution); tlvs.WriteUshort(0x0016, id.ClientId); tlvs.WriteUshort(0x0017, id.ClientMajor); tlvs.WriteUshort(0x0018, id.ClientMinor); tlvs.WriteUshort(0x0019, id.ClientLesser); tlvs.WriteUshort(0x001A, id.ClientBuild); tlvs.WriteByteArray(0x0025, dp.ParentSession.HashPassword(key)); tlvs.WriteByte(0x004A, 0x01); tlvs.WriteEmpty(0x004C); stream.WriteTlvBlock(tlvs); } DataPacket newPacket = Marshal.BuildDataPacket(dp.ParentSession, header, stream); newPacket.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(newPacket); }
/// <summary> /// Send a data packet to the rate class that will send it /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> public static void DispatchToRateClass(DataPacket dp) { if (dp.ParentConnection == null) { dp.ParentConnection = dp.ParentSession.Connections.GetByFamily( dp.SNAC.FamilyServiceID); if (dp.ParentConnection == null || dp.ParentConnection.ReadyForData == false) { dp.ParentSession.Connections.AddDelayedPacket(dp.SNAC.FamilyServiceID, dp); return; } } int key = (int) (dp.SNAC.FamilyServiceID << 16) | dp.SNAC.FamilySubtypeID; RateClass rc = dp.ParentSession.RateClasses[key]; if (rc != null) { rc.Enqueue(dp); } else { dp.ParentConnection.SendFLAP(dp.Data.GetBytes()); } }
/// <summary> /// Sends SNAC(01,06) in response to SNAC(01,18) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,18)</param> /// <remarks>OscarLib doesn't store the version list, so this method just sends SNAC(01,06) for rate limit info</remarks> private void ProcessVersionsListAndGetRateLimits(DataPacket dp) { // Construct SNAC (01,06) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_RATE_LIMIT_REQUST; DataPacket dp2 = Marshal.BuildDataPacket(parent, sh, new ByteStream()); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); }
/// <summary> /// Processes a request for client verification -- SNAC(01,1F) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,1F)</param> /// <remarks>See the entry for <see cref="SendVerificationResponse"/> for a description of /// how this SNAC is used.</remarks> private void ProcessVerificationRequest(DataPacket dp) { SendVerificationResponse(); }
/// <summary> /// Processes the server-supported family list -- SNAC(01,03) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(01,03)</param> private void ProcessServicesList(DataPacket dp) { // Get the list of supported families and populate the session list while (dp.Data.HasMoreData) { ushort family = dp.Data.ReadUshort(); // Add family to connection list, unless it is 0x0001, because all // connections (except authorization) handle this family if (family != SNAC_BOS_FAMILY) { parent.Connections.AssignFamily(family, dp.ParentConnection); } } // Request the server versions of these services RequestServiceVersions(dp.ParentConnection); }
/// <summary> /// Processes a resume request from the server -- SNAC(01,0D) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,0D)</param> private void ProcessResumeRequest(DataPacket dp) { // TODO: Tell the connection it can start sending again }
/// <summary> /// Processes the list of rate limitations -- SNAC(01,07) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(01,07)</param> /// <remarks>This is the last step in setting up a secondary service connection, /// and the trigger to initialize basic services for the primary connection.</remarks> private void ProcessRateLimitations(DataPacket dp) { ushort num_classes = dp.Data.ReadUshort(); ushort[] classes = new ushort[num_classes]; RateClassManager rcm = parent.RateClasses; // Get the rate class attributes out of the SNAC for (int i = 0; i < num_classes; i++) { ushort id = dp.Data.ReadUshort(); RateClass rc = rcm.GetByID(id); rc.WindowSize = dp.Data.ReadUint(); rc.ClearLevel = dp.Data.ReadUint(); rc.AlertLevel = dp.Data.ReadUint(); rc.LimitLevel = dp.Data.ReadUint(); rc.DisconnectLevel = dp.Data.ReadUint(); rc.CurrentLevel = dp.Data.ReadUint(); rc.MaxLevel = dp.Data.ReadUint(); if (parent.Families.GetFamilyVersion(0x0001) >= 3) { rc.LastTime = dp.Data.ReadUint(); rc.IsDroppingSNACs = dp.Data.ReadByte() != 0; } rcm.SetByID(id, rc); rc.StartLimitedTransmission(); classes[i] = id; } // Register rates with the session's ConnectionList for (int i = 0; i < num_classes; i++) { ushort id = dp.Data.ReadUshort(); ushort num_pairs = dp.Data.ReadUshort(); for (int j = 0; j < num_pairs; j++) { ushort family = dp.Data.ReadUshort(); ushort subtype = dp.Data.ReadUshort(); if (family == 0x04) { if (id == 1) { Console.WriteLine("** SNAC 4 handled by RC " + id); } else { Console.WriteLine("SNAC 4-{0} handled by RC " + id, subtype); } } else if (family == 0x02 && subtype == 0x05) { Console.WriteLine("** 02,05 handled by RC " + id); } rcm.SetRateClassKey(family, subtype, id); } } // Construct SNAC(01,08) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_ACKNOWLEDGE_RATE_LIMITS; ByteStream stream = new ByteStream(); for (int i = 0; i < classes.Length; i++) { stream.WriteUshort(classes[i]); } DataPacket dp2 = Marshal.BuildDataPacket(parent, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); parent.OnLoginStatusUpdate("Protocol negotiation complete", 0.66); /* * If this is the initial services connection, we call the remaining SNACs * in the login sequence. * Otherwise, this is the last step in setting up a new service connection, * and we send SNAC(01,02) here. */ if (!parent.LoggedIn) { // Start stage 3, services setup RequestOnlineInformation(); SNAC13.RequestParametersList(parent); SNAC13.RequestInitialContactList(parent); parent.Statuses.RequestParameters(); parent.Messages.RequestParametersList(); SNAC09.RequestParametersList(parent); parent.Statuses.ReportClientCapabilities(); parent.Statuses.SetProfile(parent.Statuses.Profile); } else { SendReadyNotification(dp.ParentConnection); } }
/// <summary> /// Process a rate change message from the server -- SNAC(01,0A) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,0A)</param> private void ProcessRateChange(DataPacket dp) { ushort rateCode = dp.Data.ReadUshort(); while (dp.Data.HasMoreData) { ushort classID = dp.Data.ReadUshort(); RateClass targetClass = parent.RateClasses.GetByID(classID); switch (rateCode) { case 1: break; case 2: targetClass.State = RateClassState.Warning; break; case 3: targetClass.State = RateClassState.Limited; break; case 4: targetClass.State = RateClassState.Normal; break; } targetClass.WindowSize = dp.Data.ReadUint(); targetClass.ClearLevel = dp.Data.ReadUint(); targetClass.AlertLevel = dp.Data.ReadUint(); targetClass.LimitLevel = dp.Data.ReadUint(); targetClass.DisconnectLevel = dp.Data.ReadUint(); targetClass.CurrentLevel = dp.Data.ReadUint(); targetClass.MaxLevel = dp.Data.ReadUint(); targetClass.LastTime = dp.Data.ReadUint(); targetClass.IsDroppingSNACs = dp.Data.ReadByte() != 0; parent.RateClasses.SetByID(classID, targetClass); } }
/// <summary> /// Set minimum report interval -- SNAC(0b,02) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(0b,02)</param> private void ProcessReportInterval(DataPacket dp) { // read report interval in hours ushort n = dp.Data.ReadUshort(); if (n > 0) statsIntervalMins = (ulong)(n * 60); }
/// <summary> /// Processes the client's own online information -- SNAC(01,0F) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,0F)</param> private void ProcessOwnInformation(DataPacket dp) { UserInfo ui = dp.Data.ReadUserInfo(); if (ui.Icon != null) { parent.Graphics.OwnBuddyIcon = ui.Icon; } IPAddress ipAddress = null; if (parent.Connections.LocalExternalIP == null) if (IPAddress.TryParse(ui.ExternalIPAddress.ToString(), out ipAddress)) parent.Connections.LocalExternalIP = ipAddress; }
/// <summary> /// Processes the server response to a new family request -- SNAC(01,05) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(01,05)</param> private void ProcessNewServiceResponse(DataPacket dp) { int startIndex = 0; byte[] SNACData = dp.Data.ReadByteArrayToEnd(); if (SNACData[0] == 0x00 && SNACData[1] == 0x06) { startIndex += 2; // What the heck is this...0x0006, some families, some of the time? } using (TlvBlock tlvs = new TlvBlock(SNACData, startIndex)) { ushort family = tlvs.ReadUshort(NEW_SERVICE_FAMILY); string BOSaddress = tlvs.ReadString(NEW_SERVICE_ADDRESS, Encoding.ASCII); byte[] cookie = tlvs.ReadByteArray(NEW_SERVICE_COOKIE); Connection newconn = null; object store = dp.ParentSession.RetrieveRequestID(dp.SNAC.RequestID); if (family != 0x000E) { newconn = dp.ParentSession.Connections.CreateNewConnection(family); } else { ChatRoom roominfo = (ChatRoom)store; newconn = dp.ParentSession.Connections.CreateNewChatConnection(roominfo); } string[] bosinfo = BOSaddress.Split(':'); int port = 0; if (bosinfo.Length == 2) { port = Int32.Parse(bosinfo[1]); } else { port = dp.ParentSession.ServerSettings.LoginPort; } newconn.ServerConnectionCompleted += delegate { newconn.ReadHeader(); }; newconn.Server = bosinfo[0]; newconn.Port = port; newconn.Cookie = new Cookie(cookie); newconn.ConnectToServer(); } // The connection process continues when the server sends SNAC(01,03) }
/// <summary> /// Processes a server migration notification -- SNAC(01,12) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,12)</param> private void ProcessMigrationNotice(DataPacket dp) { //KSD-SYSTEMS - changed at 26.05.2011 // Process migration //dp.ParentSession.OnError(ServerErrorCode.OscarLibUnsupportedFunction); dp.ParentSession.OnStatusUpdate("Server-Address changed"); dp.ParentSession.OnLoginStatusUpdate("Connecting to server", 0.00); parent.Authorization.ProcessLoginResponse(dp); }
/// <summary> /// Sends authorization request -- SNAC(17,02) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(17,07)</param> void SendAuthorizationRequest(DataPacket dp) { // Pull apart SNAC(17,07) byte[] key = dp.Data.ReadByteArray(dp.Data.ReadUshort()); // Construct SNAC(17,02) SNACHeader header = new SNACHeader(); header.FamilyServiceID = SNAC_AUTH_FAMILY; header.FamilySubtypeID = AUTH_LOGIN_REQUEST; OSCARIdentification id = parent.ClientIdentification; ByteStream stream = new ByteStream(); using (TlvBlock tlvs = new TlvBlock()) { tlvs.WriteString(0x0001, parent.ScreenName, Encoding.ASCII); tlvs.WriteString(0x0003, id.ClientName, Encoding.ASCII); tlvs.WriteString(0x000F, "en", Encoding.ASCII); tlvs.WriteString(0x000E, "us", Encoding.ASCII); tlvs.WriteUint(0x0014, id.ClientDistribution); tlvs.WriteUshort(0x0016, id.ClientId); tlvs.WriteUshort(0x0017, id.ClientMajor); tlvs.WriteUshort(0x0018, id.ClientMinor); tlvs.WriteUshort(0x0019, id.ClientLesser); tlvs.WriteUshort(0x001A, id.ClientBuild); tlvs.WriteByteArray(0x0025, parent.HashPassword(key)); tlvs.WriteByte(0x004A, 0x01); tlvs.WriteEmpty(0x004C); stream.WriteTlvBlock(tlvs); } DataPacket newPacket = Marshal.BuildDataPacket(parent, header, stream); newPacket.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(newPacket); }
/// <summary> /// Enqueues a DataPacket to be sent asynchronously /// </summary> public void Enqueue(DataPacket dp) { lock (this) { _sendqueue.Enqueue(dp); } }
/// <summary> /// Creates a <see cref="DataPacket"/> from the beginning of the stream /// </summary> /// <returns>A new <see cref="DataPacket"/></returns> public DataPacket CreateDataPacket() { if (dataIndex != 0) { throw new Exception("A DataPacket can only be created from an unused ByteStream"); } SNACHeader header = new SNACHeader(this); if ((header.Flags & 0x8000) != 0) { dataIndex += 2 + ReadUshort(); // Read past family version information } DataPacket retval = new DataPacket(this); retval.SNAC = header; return retval; }
/// <summary> /// Processes a pause request from the server -- SNAC(01,0B) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,0B)</param> private void ProcessPauseRequest(DataPacket dp) { // TODO: Actually tell the connection to stop sending in preparation for the migration SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_PAUSE_CONNECTION_RESPONSE; DataPacket dp2 = Marshal.BuildDataPacket(parent, sh, new ByteStream()); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); }
/// <summary> /// Processes a login response -- SNAC(17,03) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(17,03)</param> internal void ProcessLoginResponse(DataPacket dp) { // Pull apart SNAC(17,03) Cookie cookie; string BOSaddress; using (TlvBlock tlvs = new TlvBlock(dp.Data.ReadByteArrayToEnd())) { if (tlvs.HasTlv(0x0008)) { ushort errorcode = tlvs.ReadUshort(0x0008); parent.OnLoginFailed((LoginErrorCode)errorcode); return; } BOSaddress = tlvs.ReadString(0x0005, Encoding.ASCII); cookie = Cookie.GetReceivedCookie(tlvs.ReadByteArray(0x0006)); } // Shut down the authorization connection // Socket shutdown is initiated by the server parent.OnLoginStatusUpdate("Authorized", 0.33); dp.ParentConnection.DisconnectFromServer(false); // Create a new connection to the BOS server Connection newconn = parent.Connections.CreateNewConnection(0x0001); string[] bosinfo = BOSaddress.Split(':'); newconn.ServerConnectionCompleted += delegate(Connection conn) { conn.ReadyForData = true; conn.ReadHeader(); }; newconn.Server = bosinfo[0]; if (bosinfo.Length == 2) newconn.Port = Int32.Parse(bosinfo[1]); else newconn.Port = dp.ParentConnection.Port; Logging.WriteString("Connect to Server after auth. Address from dp: {0} - Address to connect: {1}:{2}", BOSaddress, newconn.Server, newconn.Port); newconn.Cookie = cookie; newconn.ConnectToServer(); // The login process continues when the server sends SNAC(01,03) on the new connection }
/// <summary> /// Notifies the OSCAR server that the new connection is ready to receive service-specific data /// </summary> /// <remarks> /// This SNAC must be sent within 30ish seconds of connection, or the connection will drop. /// This should not ever be a problem, barring a lost connection well below the level of this library. /// </remarks> public void SendReadyNotification(Connection conn) { // Build SNAC(01,02) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_CONNECTION_READY; ushort[] families = parent.Connections.GetFamilies(conn); FamilyManager fm = parent.Families; Array.Sort(families); Array.Reverse(families); bool isChatRoomConnection = false; bool isChatNavService = false; ByteStream stream = new ByteStream(); DataPacket[][] delayedframes = new DataPacket[families.Length][]; for (int i = 0; i < families.Length; i++) { ushort family = families[i]; delayedframes[i] = parent.Connections.GetDelayedPackets(family); stream.WriteUshort(family); stream.WriteUshort(fm.GetFamilyVersion(family)); stream.WriteUshort(fm.GetFamilyToolID(family)); stream.WriteUshort(fm.GetFamilyToolVersion(family)); if (family == 0x000D) { isChatNavService = true; } else if (family == 0x000E) { isChatRoomConnection = true; } } /* * The initial service connection has to send SNAC(01,1E) before it actually * sends SNAC(01,02), thus the check for the initial connection here * and after it gets sent. */ if (!parent.LoggedIn) { SetAvailableMessage(parent.Statuses.AvailableMessage); SetDCInfo(); SetExtendedICQStatus(parent.Statuses.ICQFlags, parent.Statuses.ICQStatus); } // The connection is done, so start sending keepalives conn.Connecting = false; conn.ReadyForData = true; DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = conn; SNACFunctions.BuildFLAP(dp); /* * If this is a new service connection, there is probably at least one * delayed packet. Process those packets. Additionally, if the new connection is * a chatroom connection, query the Rendezvous manager to see if it is the result * of an explict room creation (or implict, as in accepting a chat invitation). * If it was explict, notify the user that it's done */ if (parent.LoggedIn) { foreach (DataPacket[] list in delayedframes) { if (list == null) continue; foreach (DataPacket dp_delay in list) { dp_delay.ParentConnection = conn; SNACFunctions.DispatchToRateClass(dp_delay); } } if (isChatNavService) { parent.ChatRooms.OnChatNavServiceAvailable(); } else if (isChatRoomConnection) { ChatRoom chatRoom = parent.Connections.GetChatByConnection((ChatConnection)conn); parent.ChatRooms.OnChatRoomConnectionAvailable(chatRoom); } } }
public static void ProcessInfoResponse(DataPacket dp) { // The first four bytes of this are the TLV 0x0001 // header which encapsulates the rest of the data int index = 4; ushort cmdlength = dp.Data.ReadUshortLE(); uint my_uin = dp.Data.ReadUintLE(); ushort command = dp.Data.ReadUshortLE(); ushort requestID = dp.Data.ReadUshortLE(); Encoding enc = Encoding.ASCII; switch (command) { case 0x0041: break; case 0x0042: // Gaim does a callback here break; case 0x07DA: ICQInfo info = new ICQInfo(); // RecallICQInfo(requestid) ushort subtype = dp.Data.ReadUshortLE(); index++; // 0x0A switch (subtype) { case 0x00A0: break; case 0x00AA: break; case 0x00C8: info.Nickname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Firstname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Lastname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Email = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomeCity = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomeState = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomePhone = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomeFax = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomeAddress = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.MobilePhone = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomeZip = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.HomeCountry = dp.Data.ReadUshortLE(); break; case 0x00DC: info.Age = dp.Data.ReadByte(); index++; // unknown info.Gender = dp.Data.ReadByte(); info.PersonalURL = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.BirthYear = dp.Data.ReadUshortLE(); info.BirthMonth = dp.Data.ReadByte(); info.BirthDay = dp.Data.ReadByte(); info.Language1 = dp.Data.ReadByte(); info.Language2 = dp.Data.ReadByte(); info.Language3 = dp.Data.ReadByte(); break; case 0x00D2: info.WorkCity = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkState = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkPhone = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkFax = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkAddress = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkZip = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkCountry = dp.Data.ReadUshortLE(); info.WorkCompany = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkDivision = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.WorkPosition = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); index += 2; info.WorkWebsite = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); break; case 0x00E6: info.Information = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); break; case 0x00EB: ushort numaddresses = dp.Data.ReadUshortLE(); info.EmailAddresses = new string[numaddresses]; for (int i = 0; i < numaddresses; i++) { info.EmailAddresses[i] = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); if (i + 1 != numaddresses) index++; } break; case 0x00F0: break; case 0x00FA: break; case 0x0104: info.Nickname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Firstname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Lastname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); break; case 0x010E: break; case 0x019A: index += 2; info.Screenname = dp.Data.ReadUintLE().ToString(); info.Nickname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Firstname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Lastname = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); info.Email = dp.Data.ReadString(dp.Data.ReadUshortLE(), Encoding.ASCII); break; } // End the subtype switch statement break; // Do some crazy multipart snac stuff default: index += cmdlength; break; } }
/// <summary> /// Processes the client's own extended status update sent by the server -- SNAC(01,21) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(01,21)</param> private void ProcessExtendedStatus(DataPacket dp) { // Messages are starting with a 0x0004...what the heck? dp.Data.ReadUshort(); ushort type = dp.Data.ReadUshort(); byte flags = dp.Data.ReadByte(); byte length = dp.Data.ReadByte(); if (type == EXTSTATUS_ICON1 || type == EXTSTATUS_ICON2) { // TODO: Some icon bullcrap, I don't know } else // Available message { } }