/// <summary> /// Sends a request for a new chat room connection -- SNAC(01,04) /// </summary> /// <param name="chatRoom">A <see cref="ChatRoom"/> object</param> internal void RequestChatRoomConnection(ChatRoom chatRoom) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = 0x0001; sh.FamilySubtypeID = 0x0004; ByteStream chatStream = new ByteStream(); chatStream.WriteUshort(chatRoom.Exchange); chatStream.WriteByte((byte)Encoding.ASCII.GetByteCount(chatRoom.FullName)); chatStream.WriteString(chatRoom.FullName, Encoding.ASCII); chatStream.WriteUshort(chatRoom.Instance); TlvBlock tlv = new TlvBlock(); tlv.WriteByteArray(0x0001, chatStream.GetBytes()); ByteStream mainStream = new ByteStream(); mainStream.WriteUshort(0x000E); mainStream.WriteTlvBlock(tlv); parent.StoreRequestID(sh.RequestID, chatRoom); DataPacket dp = Marshal.BuildDataPacket(parent, sh, mainStream); // This one is always sent on BOS 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); }
/// <summary> /// Sets the away message and/or profile of the client /// </summary> /// <param name="awayMessage">The away message to set</param> /// <param name="profile">The profile to set</param> private void SetAwayMessageProfileInternal(string awayMessage, string profile) { // Build the SNAC header SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_LOCATION_FAMILY; sh.FamilySubtypeID = LOCATION_PARAMETER_USERINFO; ByteStream stream = new ByteStream(); using (TlvBlock tlvs = new TlvBlock()) { if (profile != null) { Encoding profileEncoding = UtilityMethods.FindBestOscarEncoding(profile); tlvs.WriteString(LOCATION_PROFILE_ENCODING, Marshal.EncodingToAolMime(profileEncoding), Encoding.ASCII); tlvs.WriteString(LOCATION_PROFILE, profile, profileEncoding); } if (awayMessage != null) { Encoding awayMessageEncoding = UtilityMethods.FindBestOscarEncoding(awayMessage); tlvs.WriteString(LOCATION_AWAYMESSAGE_ENCODING, Marshal.EncodingToAolMime(awayMessageEncoding), Encoding.ASCII); tlvs.WriteString(LOCATION_AWAYMESSAGE, awayMessage, awayMessageEncoding); } stream.WriteByteArray(tlvs.GetBytes()); } SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, 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> /// 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> /// Sends a request for parameter information -- SNAC(09,02) /// </summary> /// <param name="sess">A <see cref="Session"/> object</param> public static void RequestParametersList(Session sess) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = (ushort)SNACFamily.PrivacyManagementService; sh.FamilySubtypeID = (ushort)PrivacyManagementService.ServiceParametersRequest; SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(sess, sh, new ByteStream())); }
/// <summary> /// Requests parameter settings for the ChatNav SNAC family /// </summary> internal void RequestParameters() { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_CHATNAV_FAMILY; sh.FamilySubtypeID = CHATNAV_PARAMETER_LIMITREQUEST; chatParameterRequests[sh.RequestID] = "parameters"; SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, new ByteStream())); }
/// <summary> /// Requests parameter settings for the Location and Buddy Management SNAC families /// </summary> /// <remarks>This method sends both SNAC(0x02,0x02) and SNAC(0x03,0x02)</remarks> internal void RequestParameters() { SNACHeader header1 = new SNACHeader(); header1.FamilyServiceID = SNAC_LOCATION_FAMILY; header1.FamilySubtypeID = LOCATION_PARAMETER_REQUEST; SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, header1, new ByteStream())); SNACHeader header2 = new SNACHeader(); header2.FamilyServiceID = SNAC_BUDDY_FAMILY; header2.FamilySubtypeID = BUDDY_PARAMETER_REQUEST; SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, header2, new ByteStream())); }
/// <summary> /// Requests the client's own online information /// </summary> public void RequestOnlineInformation() { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_REQUEST_OWN_INFORMATION; DataPacket dp = Marshal.BuildDataPacket(parent, sh, new ByteStream()); // Always gets sent on BOS dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <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 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); }
public void SendNewPassword(string password) { ByteStream stream = new ByteStream(); stream.WriteUshortLE((ushort)password.Length); stream.WriteString(password, Encoding.ASCII); /* * * * * Header * * * * */ SNACHeader sh = CreateIcqMetaHeader(); stream = CreateMetaInfoHeader(parent, sh, MetaInfoRequestType.SetPassword, stream); //parent.StoreRequestID(sh.RequestID, screenname); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Sets the client's ICQ status -- SNAC(01,1E) /// </summary> /// <param name="flags">The ICQ flags to set</param> /// <param name="status">The ICQ status flags to set</param> internal void SetExtendedICQStatus(ICQFlags flags, ICQStatus status) { SNACHeader sh = new SNACHeader(SNAC_BOS_FAMILY, BOS_SET_EXTENDED_STATUS); ByteStream stream = new ByteStream(); uint stat = (uint)((ushort)flags << 16); stat |= (ushort)status; stream.WriteUint(0x00060004); stream.WriteUint(stat); DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <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> /// Send a message to this chatroom using a specific character set and language /// </summary> /// <param name="message">The message to send</param> /// <param name="charset">The character set in which to encode the message</param> /// <param name="language">The two-letter code of the language of the message</param> private void SendMessage(string message, Encoding charset, string language) { if (!Connection.Connected) { // TODO: The semantics here aren't right throw new NotLoggedInException(); } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = 0x000E; sh.FamilySubtypeID = (ushort)ChatService.MessageFromClient; byte[] cookie = new byte[8]; Random r = new Random(); r.NextBytes(cookie); ByteStream stream = new ByteStream(); stream.WriteByteArray(cookie); stream.WriteUshort(0x0003); TlvBlock tlvs = new TlvBlock(); using (TlvBlock messageBlock = new TlvBlock()) { Encoding messageEncoding = UtilityMethods.FindBestOscarEncoding(message); messageBlock.WriteString(CHATMESSAGE_MESSAGE, message, messageEncoding); messageBlock.WriteString(CHATMESSAGE_CHARSET, UtilityMethods.OscarEncodingToString(messageEncoding), Encoding.ASCII); messageBlock.WriteString(CHATMESSAGE_LANGUAGE, language, Encoding.ASCII); messageBlock.WriteString(CHATMESSAGE_CONTENTTYPE, "text/x-aolrtf", Encoding.ASCII); messageBlock.WriteString(CHATMESSAGE_ENCODING, "binary", Encoding.ASCII); tlvs.WriteByteArray(0x0005, messageBlock.GetBytes()); } tlvs.WriteEmpty(0x0001); stream.WriteTlvBlock(tlvs); DataPacket dp = Marshal.BuildDataPacket(Connection.ParentSession, sh, stream); dp.ParentConnection = Connection; SNACFunctions.BuildFLAP(dp); }
/// <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> /// <para>Request full user informations from Server. Strings are ASCII and UTF8.</para> /// <para>Works only with ICQ-Contacts not e.g. AOL-Contacts.</para> /// </summary> /// <param name="screenname">The screenname to get information about, see <see cref="Utility.ScreennameVerifier.IsValidICQ"/></param> /// <remarks>Results are returned by the <see cref="FullUserInfoReceived"/> event.</remarks> public void RequestFullUserInfo(string screenname) { if (!ScreennameVerifier.IsValidICQ(screenname)) { return; } ByteStream stream = new ByteStream(); // Metatoken SSIBuddy buddy = parent.SSI.GetBuddyByName(screenname); byte[] metatoken = (buddy != null ? buddy.MetaInfoToken : null); // Length ushort len_token = (ushort)(metatoken != null ? metatoken.Length + 4 : 0); ushort len_name = (ushort)(Encoding.ASCII.GetByteCount(screenname) + 4); /* * * * * User * * * * */ stream.WriteUshort(0x0003); stream.WriteUint((uint)1); stream.WriteUshort((ushort)(len_name + len_token)); // size to end // MetaToken for extendet userinfo if (metatoken != null) { stream.WriteUshort(0x003c); stream.WriteUshort((ushort)metatoken.Length); stream.WriteByteArray(metatoken); } // TLV Block stream.WriteUshort(0x0032); stream.WriteUshort((ushort)Encoding.ASCII.GetByteCount(screenname)); stream.WriteString(screenname, Encoding.ASCII); /* * * * * Header * * * * */ SNACHeader sh = CreateIcqMetaHeader(); stream = CreateDirectoryHeader(DirectoryRequestType.QueryInfoRequest, stream); stream = CreateMetaInfoHeader(parent, sh, MetaInfoRequestType.DirectoryQueryRequest, stream); parent.StoreRequestID(sh.RequestID, DirecotyQueryType.InfoUser); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Creates a new AIM chat room /// </summary> /// <param name="chatRoom">A <see cref="ChatRoom"/> object describing the room to create</param> /// <remarks>TODO: I think this doesn't work, the fullname should be "create" maybe?</remarks> private void CreateChatRoom(ChatRoom chatRoom) { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_CHATNAV_FAMILY; sh.FamilySubtypeID = CHATNAV_CREATE_ROOM; ByteStream stream = new ByteStream(); chatRoom.WriteToByteStream(stream); chatRoomCreationRequests[sh.RequestID] = chatRoom; chatParameterRequests[sh.RequestID] = "create"; SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// <para>Request short user informations from Server. Strings are ASCII.</para> /// <para>Works only with ICQ-Contacts not e.g. AOL-Contacts.</para> /// </summary> /// <param name="screenname">The screenname to get information about, see <see cref="Utility.ScreennameVerifier.IsValidICQ"/></param> /// <remarks>Results are returned by the <see cref="ShortUserInfoReceived"/> event</remarks> public void RequestShortUserInfo(string screenname) { if (!ScreennameVerifier.IsValidICQ(screenname)) { return; } ByteStream stream = new ByteStream(); stream.WriteUintLE(uint.Parse(screenname)); /* * * * * Header * * * * */ SNACHeader sh = CreateIcqMetaHeader(); stream = CreateMetaInfoHeader(parent, sh, MetaInfoRequestType.ShortUserInfoRequest, stream); parent.StoreRequestID(sh.RequestID, screenname); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Downloads a buddy icon from the AIM servers /// </summary> /// <param name="screenName">The screenname to which the icon belongs</param> /// <param name="iconId">The ID of the icon stored on the server</param> public void DownloadBuddyIcon(string screenName, BartID iconId) { // Check to make sure the icon ID is valid and actually a buddy icon if (iconId == null || iconId.Data == null || !(iconId.Type == BartTypeId.BuddyIcon || iconId.Type == BartTypeId.BigBuddyIcon)) { return; } // Check to see if the icon's cached, if the cache location is set if (!String.IsNullOrEmpty(AutoSaveLocation)) { string saveLocation = Path.Combine(AutoSaveLocation, iconId.ToString()); if (File.Exists(saveLocation)) { OnBuddyIconDownloaded(screenName, iconId, saveLocation); return; } } // Check to see if there's already a request in progress for this icon ID if (currentlyDownloading.Contains(iconId)) { return; } currentlyDownloading.Add(iconId); SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BART_FAMILY; sh.FamilySubtypeID = BART_DOWNLOAD; sh.Flags = 0; ByteStream stream = new ByteStream(); stream.WriteByte((byte)Encoding.ASCII.GetByteCount(screenName)); stream.WriteString(screenName, Encoding.ASCII); stream.WriteByte(0x01); stream.WriteBartID(iconId); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Requests a list of accounts associated with an email address /// </summary> /// <param name="email">The email address to search for</param> /// <remarks>Results are returned by the <see cref="FindByEmailResults"/> event</remarks> /// <exception cref="NotLoggedInException">Thrown when the <see cref="Session"/> is not logged in</exception> public void FindUsersByEmail(string email) { if (!parent.LoggedIn) { throw new NotLoggedInException(); } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_USERLOOKUP_FAMILY; sh.FamilySubtypeID = USERLOOKUP_EMAIL_SEARCH; ByteStream stream = new ByteStream(); stream.WriteString(email, Encoding.ASCII); parent.StoreRequestID(sh.RequestID, email); 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 response to a client verification request -- SNAC(01,20) /// </summary> /// <remarks> /// SNAC(01,1F) and SNAC(01,20) are used to verify that the client connecting /// to the network was the official AOL Instant Messenger. The server sends /// two integers, an offset and a length, in SNAC(01,1F). These parameters are then used to /// get 16 bytes of data in the offical client's static memory region. However, after /// AOL begain using this authentication method, the servers never changed the requested /// offset and length. The expected response was the same 16 bytes every time, which made /// it a fairly ineffective deterrent to "unauthorized" clients. /// </remarks> public void SendVerificationResponse() { SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_BOS_FAMILY; sh.FamilySubtypeID = BOS_CLIENT_VERIFICATION_RESPONSE; ByteStream stream = new ByteStream(); stream.WriteUint(0x44a95d26); stream.WriteUint(0xd2490423); stream.WriteUint(0x93b8821f); stream.WriteUint(0x51c54b01); DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <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> /// 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> /// Requests all user information from the server /// </summary> /// <param name="screenname">The screenname to get information about</param> /// <remarks>Results are returned by the <see cref="UserInfoReceived"/> event</remarks> public void RequestAllUserInfo(string screenname) { //KSD-SYSTEMS - commented at 24.02.2010 -> I want AllUserInfo, no Redirect // If the requested information is an ICQ name, redirect this //if (ScreennameVerifier.IsValidICQ(screenname)) //{ // RequestBasicUserInfo(screenname, BasicUserInfoRequest.AwayMessage); // return; //} // Build SNAC(02,15) SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_LOCATION_FAMILY; sh.FamilySubtypeID = LOCATION_REQUEST_ALL_INFO; ByteStream stream = new ByteStream(); stream.WriteUint((uint)(UserInfoRequest.AwayMessage | UserInfoRequest.Capabilities | UserInfoRequest.UserProfile)); stream.WriteByte((byte)Encoding.ASCII.GetByteCount(screenname)); stream.WriteString(screenname, Encoding.ASCII); SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); }
/// <summary> /// Sets the client's idle time. /// </summary> /// <param name="seconds">The client's idle time, in seconds</param> /// <remarks> /// <para> /// To remove idle status, set <paramref name="seconds"/> to zero. /// </para> /// <para> /// This method should be used only once to set the client as idle, /// or to remove idle status. The server updates the client's idle time /// automatically. So, for example, if the client application wants the /// user to appear idle after ten minutes, the application should call /// this method after 10 minutes of being idle: /// <code>Session s; /// ... /// s.SetIdleTime(600);</code> /// The next time this method is called, it should be to remove idle status: /// <code>s.SetIdleTime(0);</code> /// </para> /// </remarks> /// <exception cref="NotLoggedInException">Thrown when the <see cref="Session"/> is not logged in</exception> public void SetIdleTime(uint seconds) { if (!parent.LoggedIn) { throw new NotLoggedInException(); } SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = 0x0001; sh.FamilySubtypeID = 0x0011; ByteStream stream = new ByteStream(); stream.WriteUint(seconds); // Always gets sent on BOS DataPacket dp = Marshal.BuildDataPacket(parent, sh, stream); dp.ParentConnection = parent.Connections.BOSConnection; SNACFunctions.BuildFLAP(dp); }
/// <summary> /// Kicks off the authorization hash request when the initial connection is complete /// </summary> void loginConnection_ServerConnectionCompleted(Connection conn) { conn.ReadyForData = true; /*** Send SNAC(17,06) to get the auth key ***/ SNACHeader sh = new SNACHeader(); sh.FamilyServiceID = SNAC_AUTH_FAMILY; sh.FamilySubtypeID = AUTH_KEY_REQUEST; ByteStream stream = new ByteStream(); using (TlvBlock tlvs = new TlvBlock()) { tlvs.WriteString(0x0001, parent.ScreenName, Encoding.ASCII); tlvs.WriteEmpty(0x004B); tlvs.WriteEmpty(0x005A); stream.WriteTlvBlock(tlvs); } SNACFunctions.BuildFLAP(Marshal.BuildDataPacket(parent, sh, stream)); conn.ReadHeader(); }
/// <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> /// 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); } } }