/// <summary> /// Sends service versions request -- SNAC(01,17) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> public static void RequestServiceVersions(DataPacket dp) { Session sess = dp.ParentSession; // Construct SNAC (01,17) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.ServerServicesVersionRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); // Pack the family IDs and version numbers into a stream ushort[] families = sess.Connections.GetFamilies(dp.ParentConnection); Array.Sort(families); Array.Reverse(families); ByteStream stream = new ByteStream(); foreach (ushort id in families) { ushort version = sess.Families.GetFamilyVersion(id); stream.WriteUshort(id); stream.WriteUshort(version); } DataPacket dp2 = Marshal.BuildDataPacket(sess, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); }
/// <summary> /// Requests a full set of information about an ICQ account /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="screenname">The account for which to retrieve information</param> public static void GetAllICQInfo(ISession sess, string screenname) { if (!ScreennameVerifier.IsValidICQ(screenname)) { throw new ArgumentException(screenname + " is not a valid ICQ screenname", "screenname"); } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort)ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort)sh.RequestID); stream.WriteUshort(0x04B2); stream.WriteUint(uint.Parse(screenname)); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sets the client's extended status -- SNAC(01,1E) /// </summary> /// <param name="sess">A <see cref="Session"/> object</param> /// <param name="availablemessage">The available message to set</param> /// <param name="flags">The ICQ flags to set</param> /// <param name="status">The ICQ status to set</param> /// <remarks>Either the available message or the flags/status can be set in one call to SetExtendedStatus</remarks> private static void SetExtendedStatus(Session sess, string availablemessage, ICQFlags flags, ICQStatus status) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.SetExtendedStatus; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); if (availablemessage != null) { stream.WriteUshort(0x001D); stream.WriteUshort((ushort)(availablemessage.Length + 8)); stream.WriteUshort(0x0002); stream.WriteByte(0x04); stream.WriteByte((byte)(Encoding.ASCII.GetByteCount(availablemessage) + 4)); stream.WriteUshort((ushort)Encoding.ASCII.GetByteCount(availablemessage)); stream.WriteString(availablemessage, Encoding.ASCII); stream.WriteUshort(0x0000); } else { uint stat = (uint)((ushort)flags << 16); stat |= (ushort)status; stream.WriteUint(0x00060004); stream.WriteUint(stat); } DataPacket dp = Marshal.BuildDataPacket(sess, sh, stream); dp.ParentConnection = sess.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Requests the alias assigned to an ICQ account /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="screenname">The account for which to retrieve information</param> public static void GetAlias(ISession sess, string screenname) { if (!ScreennameVerifier.IsValidICQ(screenname)) { throw new ArgumentException(screenname + " is not a valid ICQ screenname", "screenname"); } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort) ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort) sh.RequestID); stream.WriteUshort(0x04BA); stream.WriteUint(uint.Parse(screenname)); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
byte[] ISegment.GetBytes() { using (ByteStream buffer = new ByteStream()) { buffer.WriteUshort((ushort)item.Type); buffer.WriteByte((byte)item.Flags); buffer.WriteByte((byte)item.Data.Length); buffer.WriteByteArray(item.Data); return(buffer.GetBytes()); } }
/// <summary> /// Allows the authorization to another client in the future /// </summary> /// <param name="sess">the session object</param> /// <param name="screenname">the destination screenname</param> /// <param name="reason">the reason for the future authorization</param> public static void SendFutureAuthorizationGrant(Session sess, string screenname, string reason) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.SSIService; sh.FamilySubtypeID = (ushort)SSIService.SendFutureAuthorizationGrant; ByteStream stream = new ByteStream(); stream.WriteByte((byte)Encoding.ASCII.GetByteCount(screenname)); stream.WriteString(screenname, Encoding.ASCII); stream.WriteUshort((ushort)sess.Encoding.GetByteCount(reason)); stream.WriteString(reason, sess.Encoding); stream.WriteUshort(0x0000); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
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)); }
/// <summary> /// Changes the password on an ICQ account /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="newpassword">The new password</param> /// <remarks>If the new password is longer than 8 characters, it is automatically /// truncated to 8 characters by the server.</remarks> public static void ChangeICQPassword(ISession sess, string newpassword) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort) ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort) sh.RequestID); stream.WriteUshort(0x042E); stream.WriteUshort((ushort) (newpassword.Length + 1)); stream.WriteString(newpassword, Encoding.ASCII); stream.WriteByte(0x00); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sends an out-of-the-country text message /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="number">The number to which to send the message</param> /// <param name="message">The message to send</param> /// <param name="alias">The sender's alias</param> /// <remarks><paramref name="message"/> must be in codepage 1252. A delivery receipt /// is automatically requested by this method.</remarks> public static void SendSMSMessage(ISession sess, string number, string message, string alias) { string xmlformat = "<icq_sms_message>\n" + "\t<destination>{0}</destination>\n" + "\t<text>{1}</text>\n" + "\t<codepage>1252</codepage>\n" + "\t<senders_UIN>{2}</senders_UIN>\n" + "\t<senders_name>{3}</senders_name>\n" + "\t<delivery_receipt>Yes</delivery_receipt>\n" + "\t<time>{4}</time>\n" + "</icq_sms_message>\n"; string xml = String.Format(xmlformat, number, message, sess.ScreenName, alias, DateTime.Now.ToString("r")); SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort)ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort)sh.RequestID); stream.WriteUshort(0x8214); stream.WriteUshort(0x0001); stream.WriteUshort(0x0016); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUshort(0x0000); stream.WriteUshort((ushort)Encoding.ASCII.GetByteCount(xml)); stream.WriteString(xml, Encoding.ASCII); stream.WriteByte(0x00); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sends an XML string /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="xml">The contents of an XML document</param> /// <remarks>I have no idea how to use this.</remarks> public static void SendXmlRequest(ISession sess, string xml) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort)ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort)sh.RequestID); stream.WriteUshort(0x0998); stream.WriteUshort((ushort)Encoding.ASCII.GetByteCount(xml)); stream.WriteString(xml, Encoding.ASCII); stream.WriteByte(0x00); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Changes the password on an ICQ account /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="newpassword">The new password</param> /// <remarks>If the new password is longer than 8 characters, it is automatically /// truncated to 8 characters by the server.</remarks> public static void ChangeICQPassword(ISession sess, string newpassword) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort)ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort)sh.RequestID); stream.WriteUshort(0x042E); stream.WriteUshort((ushort)(newpassword.Length + 1)); stream.WriteString(newpassword, Encoding.ASCII); stream.WriteByte(0x00); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <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> /// 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> /// Requests for the server side contact list. /// </summary> /// <param name="sess">the session object</param> /// <param name="modificationDate">the last client side modification date</param> /// <param name="isLocalTime">Determines if the given modification time is in the local or universal time format</param> /// <param name="itemCount">the total item count at the client side</param> public static void SendContactListCheckout(Session sess, DateTime modificationDate, bool isLocalTime, ushort itemCount) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.SSIService; sh.FamilySubtypeID = (ushort)SSIService.ContactListCheckout; ByteStream stream = new ByteStream(); uint modDateValue = ByteStream.ConvertDateTimeToUint(modificationDate, isLocalTime); stream.WriteUint(modDateValue); stream.WriteUshort(itemCount); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sends a request for a new service family -- SNAC(01,04) /// </summary> /// <param name="sess">A <see cref="Session"/> object</param> /// <param name="newfamily">The new family to request</param> public static void RequestNewService(Session sess, ushort newfamily) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.NewServiceRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(newfamily); // This SNAC expects a response in SNAC(01,05) sess.StoreRequestID(sh.RequestID, null); DataPacket dp = Marshal.BuildDataPacket(sess, sh, stream); // This one is always sent on BOS dp.ParentConnection = sess.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Sends an acknowledgement to the pause command -- SNAC(01,0C) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object to be paused</param> public static void SendPauseAcknowledgement(DataPacket dp) { Session sess = dp.ParentSession; SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.PauseResponse; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); ushort[] families = sess.Connections.GetFamilies(dp.ParentConnection); for (int i = 0; i < families.Length; i++) { stream.WriteUshort(families[i]); } DataPacket dp2 = Marshal.BuildDataPacket(sess, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); }
public byte[] GetBytes() { ByteStream buffer = new ByteStream(); buffer.WriteUshort((ushort)Encoding.UTF8.GetByteCount(item.Name)); buffer.WriteString(item.Name, Encoding.UTF8); buffer.WriteUshort(item.GroupID); buffer.WriteUshort(item.ItemID); buffer.WriteUshort(item.ItemType); if (item.Tlvs == null) { buffer.WriteUshort(0x000); } else { buffer.WriteUshort((ushort)item.Tlvs.GetByteCount()); buffer.WriteTlvBlock(item.Tlvs); } return(buffer.GetBytes()); }
/// <summary> /// Hides the client's IP address from view /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> public static void HidePublicIP(ISession sess) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort)ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort)sh.RequestID); stream.WriteUshort(0x0424); stream.WriteUshort(0x0001); stream.WriteUshort(0x0001); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Notifies the BOS server that the client is ready to go online -- SNAC(01,02) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> /// <remarks> /// The client sends this SNAC to notify the server that it is ready to receive messages /// and online notifications. /// <para> /// This SNAC must be sent within 30 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. /// </para> /// </remarks> public static void SendReadyNotification(DataPacket dp) { // Build SNAC(01,02) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.ClientOnline; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ConnectionManager cm = dp.ParentSession.Connections; ushort[] families = cm.GetFamilies(dp.ParentConnection); FamilyManager fm = dp.ParentSession.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] = dp.ParentSession.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. */ Session sess = dp.ParentSession; if (!sess.LoggedIn) { SetExtendedStatus(sess, sess.AvailableMessage, ICQFlags.Normal, ICQStatus.Online); SetExtendedStatus(sess, null, ICQFlags.Normal, ICQStatus.Online); } // The connection is done, so start sending keepalives dp.ParentConnection.Connecting = false; dp.ParentConnection.ReadyForData = true; // Build and send a new DataPacket instead of re-using the originator; // SNAC(01,02) was getting sent twice on child connections with the reuse DataPacket dp2 = Marshal.BuildDataPacket(dp.ParentSession, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); /* * 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 (sess.LoggedIn) { foreach (DataPacket[] list in delayedframes) { if (list == null) { continue; } foreach (DataPacket dp_delay in list) { dp_delay.ParentConnection = dp.ParentConnection; SNACFunctions.DispatchToRateClass(dp_delay); } } if (isChatNavService) { sess.ChatRooms.OnChatNavServiceAvailable(); } else if (isChatRoomConnection) { ChatRoom chatRoom = sess.Connections.GetChatByConnection((ChatConnection)dp.ParentConnection); sess.ChatRooms.OnChatRoomConnectionAvailable(chatRoom); } } }
/// <summary> /// Sends an XML string /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="xml">The contents of an XML document</param> /// <remarks>I have no idea how to use this.</remarks> public static void SendXmlRequest(ISession sess, string xml) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort) ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort) sh.RequestID); stream.WriteUshort(0x0998); stream.WriteUshort((ushort) Encoding.ASCII.GetByteCount(xml)); stream.WriteString(xml, Encoding.ASCII); stream.WriteByte(0x00); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, 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> /// 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> /// Sets the client's available message -- SNAC(01,1E) /// </summary> /// <param name="availablemessage">The available message to set</param> internal void SetAvailableMessage(string availablemessage) { SNACHeader sh = new SNACHeader(SNAC_BOS_FAMILY, BOS_SET_EXTENDED_STATUS); ByteStream stream = new ByteStream(); if (String.IsNullOrEmpty(availablemessage)) { availablemessage = String.Empty; } stream.WriteUshort(0x001D); stream.WriteUshort((ushort)(availablemessage.Length + 8)); stream.WriteUshort(0x0002); stream.WriteByte(0x04); stream.WriteByte((byte)(Encoding.ASCII.GetByteCount(availablemessage) + 4)); stream.WriteUshort((ushort)Encoding.ASCII.GetByteCount(availablemessage)); stream.WriteString(availablemessage, Encoding.ASCII); stream.WriteUshort(0x0000); DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Requests the version of SNAC services provided to this connection /// </summary> /// <param name="connection">The <see cref="Connection"/> for which to retrieve service information</param> public void RequestServiceVersions(Connection connection) { // Pack the family IDs and version numbers into a stream ushort[] families = parent.Connections.GetFamilies(connection); Array.Sort(families); Array.Reverse(families); ByteStream stream = new ByteStream(); foreach (ushort id in families) { ushort version = parent.Families.GetFamilyVersion(id); stream.WriteUshort(id); stream.WriteUshort(version); } // Construct SNAC (01,17) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_FAMILY_VERSION_REQUEST; DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = connection; // Always send this on the same connection it was received SNACFunctions.BuildFLAP(dp); }
byte[] ISegment.GetBytes() { using (ByteStream buffer = new ByteStream()) { buffer.WriteUshort((ushort)item.Type); buffer.WriteByte((byte)item.Flags); buffer.WriteByte((byte)item.Data.Length); buffer.WriteByteArray(item.Data); return buffer.GetBytes(); } }
/// <summary> /// Uploads a buddy icon to the AIM servers /// </summary> /// <param name="filename">The filename of the icon to upload</param> public void UploadBuddyIcon(string filename) { // Check to make sure the local file exists if (!File.Exists(filename)) { OnBuddyIconUploadFailed(BartReplyCode.NotFound); return; } byte[] data = null; using (StreamReader reader = new StreamReader(filename)) { if (reader.BaseStream.Length > 7168) // 7KB { OnBuddyIconUploadFailed(BartReplyCode.TooBig); return; } if (!VerifyIcon(filename)) { OnBuddyIconUploadFailed(BartReplyCode.DimensionsTooBig); return; } data = new byte[reader.BaseStream.Length]; int index = 0; while (index < data.Length) { index += reader.BaseStream.Read(data, index, data.Length - index); } } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BART_FAMILY; sh.FamilySubtypeID = BART_UPLOAD; sh.Flags = 0; ByteStream stream = new ByteStream(); stream.WriteUshort((ushort)BartTypeId.BuddyIcon); stream.WriteUshort((ushort)data.Length); stream.WriteByteArray(data); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Requests a single type of user information from the server /// </summary> /// <param name="screenname">The screenname to get information about</param> /// <param name="requesttype">The type of information to retrieve</param> /// <remarks>Results are returned by the <see cref="UserInfoReceived"/> event</remarks> public void RequestBasicUserInfo(string screenname, BasicUserInfoRequest requesttype) { // Build SNAC(02,05) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_LOCATION_FAMILY; sh.FamilySubtypeID = LOCATION_REQUEST_BASIC_INFO; ByteStream stream = new ByteStream(); stream.WriteUshort((ushort)requesttype); stream.WriteByte((byte)Encoding.ASCII.GetByteCount(screenname)); stream.WriteString(screenname, Encoding.ASCII); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// This method is invoked when the connection is complete /// </summary> protected virtual void OnConnectionFinished() { Connecting = true; // Read in the first ten bytes (6 byte FLAP channel 0x01 + 0x00000001) // of the connection handshake byte[] serverhandshake = new byte[10]; try { int bytesreceived = 0; int receiveindex = 0; lock (socket) { while (bytesreceived < 10) { bytesreceived = socket.Read(serverhandshake, receiveindex, 10 - receiveindex); receiveindex += bytesreceived; } } } catch (Exception ex) { Logging.WriteString("Can't read handshake from server: {0}, connection {1}", ex.Message, ID); DisconnectFromServer(true); return; } finally { serverhandshake = null; } // Construct our reply to the connection handshake using (ByteStream clientHandshake = new ByteStream()) { FLAPHeader fh; fh.Channel = 0x01; fh.DatagramSequenceNumber = FLAPSequence; fh.DataSize = (ushort)(4 + ((cookie == null) ? 0 : 4 + cookie.GetByteCount())); clientHandshake.PrependOscarHeaders(fh, null); clientHandshake.WriteUint(Constants.PROTOCOL_VERSION); if (cookie != null) { clientHandshake.WriteUshort(0x0006); clientHandshake.WriteUshort((ushort)cookie.GetByteCount()); clientHandshake.WriteByteArray(cookie.ToByteArray()); } try { lock (socket) { socket.Write(clientHandshake.GetBytes()); } } catch (Exception ex) { Logging.WriteString("Couldn't send handshake to server: {0}, connection {1}", ex.Message, ID); DisconnectFromServer(true); return; } } StopTimeoutPeriod(); Connecting = true; // And the handshaking is done. Auth connection will send // SNAC(17,06) and any other connection will receive SNAC(01,03) OnServerConnectionCompleted(); }
/// <summary> /// Sets the client's extended status -- SNAC(01,1E) /// </summary> /// <param name="sess">A <see cref="Session"/> object</param> /// <param name="availablemessage">The available message to set</param> /// <param name="flags">The ICQ flags to set</param> /// <param name="status">The ICQ status to set</param> /// <remarks>Either the available message or the flags/status can be set in one call to SetExtendedStatus</remarks> private static void SetExtendedStatus(Session sess, string availablemessage, ICQFlags flags, ICQStatus status) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.SetExtendedStatus; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); if (availablemessage != null) { stream.WriteUshort(0x001D); stream.WriteUshort((ushort)(availablemessage.Length + 8)); stream.WriteUshort(0x0002); stream.WriteByte(0x04); stream.WriteByte((byte)(Encoding.ASCII.GetByteCount(availablemessage) + 4)); stream.WriteUshort((ushort)Encoding.ASCII.GetByteCount(availablemessage)); stream.WriteString(availablemessage, Encoding.ASCII); stream.WriteUshort(0x0000); } else { uint stat = (uint)((ushort)flags << 16); stat |= (ushort)status; stream.WriteUint(0x00060004); stream.WriteUint(stat); } DataPacket dp = Marshal.BuildDataPacket(sess, sh, stream); dp.ParentConnection = sess.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Notifies the BOS server that the client is ready to go online -- SNAC(01,02) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> /// <remarks> /// The client sends this SNAC to notify the server that it is ready to receive messages /// and online notifications. /// <para> /// This SNAC must be sent within 30 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. /// </para> /// </remarks> public static void SendReadyNotification(DataPacket dp) { // Build SNAC(01,02) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.ClientOnline; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ConnectionManager cm = dp.ParentSession.Connections; ushort[] families = cm.GetFamilies(dp.ParentConnection); FamilyManager fm = dp.ParentSession.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] = dp.ParentSession.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. */ Session sess = dp.ParentSession; if (!sess.LoggedIn) { SetExtendedStatus(sess, sess.AvailableMessage, ICQFlags.Normal, ICQStatus.Online); SetExtendedStatus(sess, null, ICQFlags.Normal, ICQStatus.Online); } // The connection is done, so start sending keepalives dp.ParentConnection.Connecting = false; dp.ParentConnection.ReadyForData = true; // Build and send a new DataPacket instead of re-using the originator; // SNAC(01,02) was getting sent twice on child connections with the reuse DataPacket dp2 = Marshal.BuildDataPacket(dp.ParentSession, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); /* * 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 (sess.LoggedIn) { foreach (DataPacket[] list in delayedframes) { if (list == null) continue; foreach (DataPacket dp_delay in list) { dp_delay.ParentConnection = dp.ParentConnection; SNACFunctions.DispatchToRateClass(dp_delay); } } if (isChatNavService) { sess.ChatRooms.OnChatNavServiceAvailable(); } else if (isChatRoomConnection) { ChatRoom chatRoom = sess.Connections.GetChatByConnection((ChatConnection)dp.ParentConnection); sess.ChatRooms.OnChatRoomConnectionAvailable(chatRoom); } } }
/// <summary> /// Sends an acknowledgement to the pause command -- SNAC(01,0C) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object to be paused</param> public static void SendPauseAcknowledgement(DataPacket dp) { Session sess = dp.ParentSession; SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.PauseResponse; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); ushort[] families = sess.Connections.GetFamilies(dp.ParentConnection); for (int i = 0; i < families.Length; i++) { stream.WriteUshort(families[i]); } DataPacket dp2 = Marshal.BuildDataPacket(sess, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); }
/// <summary> /// Sends service versions request -- SNAC(01,17) /// </summary> /// <param name="dp">A <see cref="DataPacket"/> object</param> public static void RequestServiceVersions(DataPacket dp) { Session sess = dp.ParentSession; // Construct SNAC (01,17) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.ServerServicesVersionRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); // Pack the family IDs and version numbers into a stream ushort[] families = sess.Connections.GetFamilies(dp.ParentConnection); Array.Sort(families); Array.Reverse(families); ByteStream stream = new ByteStream(); foreach (ushort id in families) { ushort version = sess.Families.GetFamilyVersion(id); stream.WriteUshort(id); stream.WriteUshort(version); } DataPacket dp2 = Marshal.BuildDataPacket(sess, sh, stream); dp2.ParentConnection = dp.ParentConnection; SNACFunctions.BuildFLAP(dp2); }
/// <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)); }
public byte[] GetBytes() { ByteStream buffer = new ByteStream(); buffer.WriteUshort((ushort)Encoding.UTF8.GetByteCount(item.Name)); buffer.WriteString(item.Name, Encoding.UTF8); buffer.WriteUshort(item.GroupID); buffer.WriteUshort(item.ItemID); buffer.WriteUshort(item.ItemType); if (item.Tlvs == null) buffer.WriteUshort(0x000); else { buffer.WriteUshort((ushort)item.Tlvs.GetByteCount()); buffer.WriteTlvBlock(item.Tlvs); } return buffer.GetBytes(); }
/// <summary> /// Sends a status report to the OSCAR server -- SNAC(0B,03) /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <remarks>libfaim does not send this report</remarks> public static void SendStatusReport(ISession sess) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.UsageStatsService; sh.FamilySubtypeID = (ushort)UsageStatsService.UsageReport; sh.Flags = 0; sh.RequestID = Session.GetNextRequestID(); // Get the necessary strings together string sn = sess.ScreenName; // Here we start lying until I can figure out how to get *all* the values in .NET string osversion = Environment.OSVersion.ToString(); string osname = "Windows 98"; //osversion.Substring(0, osversion.LastIndexOf(" ") - 1); string osver = "4.10.67766446"; //osversion.Substring(osversion.LastIndexOf(" ") + 1); string procname = "Intel Pentium"; string winsockname = "Microsoft Corporation BSD Socket API for Windows"; string winsockver = "4.1.1998"; Encoding enc = Encoding.ASCII; byte snlength = (byte)enc.GetByteCount(sn); ushort osversionlength = (ushort)enc.GetByteCount(osversion); ushort osnamelength = (ushort)enc.GetByteCount(osname); ushort osverlength = (ushort)enc.GetByteCount(osver); ushort procnamelength = (ushort)enc.GetByteCount(procname); ushort winsocknamelength = (ushort)enc.GetByteCount(winsockname); ushort winsockverlength = (ushort)enc.GetByteCount(winsockver); ByteStream mainStream = new ByteStream(); using (ByteStream stream = new ByteStream()) { TimeSpan t = (DateTime.Now - new DateTime(1970, 1, 1)); stream.WriteUint((uint)t.Seconds); t = (DateTime.UtcNow - new DateTime(1970, 1, 1).ToUniversalTime()); stream.WriteUint((uint)t.Seconds); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteByte(snlength); stream.WriteString(sn, Encoding.ASCII); stream.WriteUshort(osnamelength); stream.WriteString(osname, Encoding.ASCII); stream.WriteUshort(osverlength); stream.WriteString(osver, Encoding.ASCII); stream.WriteUshort(procnamelength); stream.WriteString(procname, Encoding.ASCII); stream.WriteUshort(winsocknamelength); stream.WriteString(winsockname, Encoding.ASCII); stream.WriteUshort(winsockverlength); stream.WriteString(winsockver, Encoding.ASCII); stream.WriteUint(0x00000002); stream.WriteUint(0x00010001); stream.WriteUint(0x00020002); using (TlvBlock tlv = new TlvBlock()) { tlv.WriteByteArray(0x0009, stream.GetBytes()); mainStream.WriteTlvBlock(tlv); } } SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, mainStream)); }
/// <summary> /// Sends a request for a new service family /// </summary> /// <param name="newfamily">The new family to request</param> public void RequestNewService(ushort newfamily) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_REQUEST_NEW_SERVICE; ByteStream stream = new ByteStream(); stream.WriteUshort(newfamily); // This SNAC expects a response in SNAC(01,05) parent.StoreRequestID(sh.RequestID, null); DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); // This one is always sent on BOS dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Allows the authorization to another client in the future /// </summary> /// <param name="sess">the session object</param> /// <param name="screenname">the destination screenname</param> /// <param name="reason">the reason for the future authorization</param> public static void SendFutureAuthorizationGrant(Session sess, string screenname, string reason) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.SSIService; sh.FamilySubtypeID = (ushort) SSIService.SendFutureAuthorizationGrant; ByteStream stream = new ByteStream(); stream.WriteByte((byte) Encoding.ASCII.GetByteCount(screenname)); stream.WriteString(screenname, Encoding.ASCII); stream.WriteUshort((ushort) sess.Encoding.GetByteCount(reason)); stream.WriteString(reason, sess.Encoding); stream.WriteUshort(0x0000); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <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); } } }
/// <summary> /// Requests for the server side contact list. /// </summary> /// <param name="sess">the session object</param> /// <param name="modificationDate">the last client side modification date</param> /// <param name="isLocalTime">Determines if the given modification time is in the local or universal time format</param> /// <param name="itemCount">the total item count at the client side</param> public static void SendContactListCheckout(Session sess, DateTime modificationDate, bool isLocalTime, ushort itemCount) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.SSIService; sh.FamilySubtypeID = (ushort) SSIService.ContactListCheckout; ByteStream stream = new ByteStream(); uint modDateValue = ByteStream.ConvertDateTimeToUint(modificationDate, isLocalTime); stream.WriteUint(modDateValue); stream.WriteUshort(itemCount); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sets the client's DC info -- SNAC(01,1E) /// </summary> /// <remarks>see <see cref="UserDCInfo"/> for contact info</remarks> internal void SetDCInfo() { SNACHeader sh = new SNACHeader(SNAC_BOS_FAMILY, BOS_SET_EXTENDED_STATUS); ByteStream stream = new ByteStream(); // Header stream.WriteUshort(0x000c); stream.WriteUshort(0x0025); // Values from Icq 6.5 & 7 dumping // Miranda use other Values (see CIcqProto::handleServUINSettings) stream.WriteUint(0); // IP stream.WriteUint(0); // Port stream.WriteByte((byte)DCType.Disabled); // DC type stream.WriteUshort((ushort)DCProtocol.IcqLite); // DC protocol version stream.WriteInt(AuthCookie); // DC auth cookie stream.WriteUint(0); // Web front port stream.WriteUint(0); // Client futures stream.WriteUint(0); // last info update time stream.WriteUint(0); // last ext info update time (i.e. icqphone status) stream.WriteUint(0); // last ext status update time (i.e. phonebook) stream.WriteUshort(0); // unknown DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Inserts an ICBM header /// </summary> private static void InsertIcbmHeader(ByteStream stream, Cookie cookie, ushort channel, string screenName) { stream.WriteByteArray(cookie.ToByteArray()); stream.WriteUshort(channel); stream.WriteByte((byte)Encoding.ASCII.GetByteCount(screenName)); stream.WriteString(screenName, Encoding.ASCII); }
/// <summary> /// Hides the client's IP address from view /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> public static void HidePublicIP(ISession sess) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort) ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort) sh.RequestID); stream.WriteUshort(0x0424); stream.WriteUshort(0x0001); stream.WriteUshort(0x0001); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sends a warning to a remote client -- SNAC(04,08) /// </summary> /// <param name="screenname">The screenname of the client to warn</param> /// <param name="anonymous">Send the warning as anonymous or as yourself</param> public void SendWarning(string screenname, bool anonymous) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_SEND_WARNING; ByteStream stream = new ByteStream(); stream.WriteUshort((ushort)((anonymous) ? 1 : 0)); stream.WriteByte((byte)Encoding.ASCII.GetByteCount(screenname)); stream.WriteString(screenname, Encoding.ASCII); // Save the screenname so the handler for the reply SNAC can retrieve it parent.StoreRequestID(sh.RequestID, screenname); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Sends an out-of-the-country text message /// </summary> /// <param name="sess">A <see cref="ISession"/> object</param> /// <param name="number">The number to which to send the message</param> /// <param name="message">The message to send</param> /// <param name="alias">The sender's alias</param> /// <remarks><paramref name="message"/> must be in codepage 1252. A delivery receipt /// is automatically requested by this method.</remarks> public static void SendSMSMessage(ISession sess, string number, string message, string alias) { string xmlformat = "<icq_sms_message>\n" + "\t<destination>{0}</destination>\n" + "\t<text>{1}</text>\n" + "\t<codepage>1252</codepage>\n" + "\t<senders_UIN>{2}</senders_UIN>\n" + "\t<senders_name>{3}</senders_name>\n" + "\t<delivery_receipt>Yes</delivery_receipt>\n" + "\t<time>{4}</time>\n" + "</icq_sms_message>\n"; string xml = String.Format(xmlformat, number, message, sess.ScreenName, alias, DateTime.Now.ToString("r")); SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort) SNACFamily.ICQExtensionsService; sh.FamilySubtypeID = (ushort) ICQExtensionsService.MetaInformationRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(0x0001); stream.WriteUshort(0x000A); stream.WriteUshort(0x0008); stream.WriteUint(uint.Parse(sess.ScreenName)); stream.WriteUshortLE(0x07D0); stream.WriteUshortLE((ushort) sh.RequestID); stream.WriteUshort(0x8214); stream.WriteUshort(0x0001); stream.WriteUshort(0x0016); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUint(0x00000000); stream.WriteUshort(0x0000); stream.WriteUshort((ushort) Encoding.ASCII.GetByteCount(xml)); stream.WriteString(xml, Encoding.ASCII); stream.WriteByte(0x00); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, stream)); }
/// <summary> /// Sends a typing notification /// </summary> /// <param name="screenName">The screenname to receive the typing notification</param> /// <param name="tn">A <see cref="TypingNotification"/> enumeration specifying what /// notification to send</param> /// <exception cref="NotLoggedInException">Thrown when the <see cref="Session"/> is not logged in</exception> public void SendTypingNotification(string screenName, TypingNotification tn) { if (!parent.LoggedIn) { throw new NotLoggedInException(); } DirectIMConnection conn = parent.Connections.GetDirectIMByScreenname(screenName); if (conn != null) { if (conn.Connected) { // TODO: send DIM typing notifications } } // Construct SNAC(04,14) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_ICBM_FAMILY; sh.FamilySubtypeID = ICBM_TYPING_NOTIFICATION; ByteStream stream = new ByteStream(); stream.WriteByteArray(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}); stream.WriteUshort(0x0001); stream.WriteByte((byte) Encoding.ASCII.GetByteCount(screenName)); stream.WriteString(screenName, Encoding.ASCII); stream.WriteUshort((ushort) tn); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Sends a list of the client's capabilities to the server /// </summary> /// <remarks>This method sends SNAC(0x02,0x04)</remarks> public void ReportClientCapabilities() { if (parent.ClientCapabilities != Capabilities.None) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_LOCATION_FAMILY; sh.FamilySubtypeID = LOCATION_PARAMETER_USERINFO; // Build the capabilities list, TLV type 0x0005 byte[] caps = CapabilityProcessor.GetCapabilityArray(parent.ClientCapabilities); ByteStream stream = new ByteStream(); stream.WriteUshort(LOCATION_CAPABILITIES); stream.WriteUshort((ushort)caps.Length); stream.WriteByteArray(caps); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); } }
/// <summary> /// Sends a request for a new service family -- SNAC(01,04) /// </summary> /// <param name="sess">A <see cref="Session"/> object</param> /// <param name="newfamily">The new family to request</param> public static void RequestNewService(Session sess, ushort newfamily) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.BasicOscarService; sh.FamilySubtypeID = (ushort)GenericServiceControls.NewServiceRequest; sh.Flags = 0x0000; sh.RequestID = Session.GetNextRequestID(); ByteStream stream = new ByteStream(); stream.WriteUshort(newfamily); // This SNAC expects a response in SNAC(01,05) sess.StoreRequestID(sh.RequestID, null); DataPacket dp = Marshal.BuildDataPacket(sess, sh, stream); // This one is always sent on BOS dp.ParentConnection = sess.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }