private void OnContactUpdated(object sender, ContactStatusEventArgs args) { this.Name = String.Format("{0} ({1})", ContactName, ContactStatus); }
private void connectInThread(string UserName, string UserDomain, string Password, string IP = null) { IsConnected = false; username = UserName; #if WINDOWS var srvRec = DnsSRV.GetSRVRecords("_impp._tcp." + UserDomain).First(); TcpClient tcpClient; if (IP == null) { tcpClient = new TcpClient(srvRec.NameTarget, srvRec.Port); } else { tcpClient = new TcpClient(); tcpClient.Connect(new IPEndPoint(IPAddress.Parse(IP), srvRec.Port)); } WriteDebugLine("Connected to " + srvRec); tcpClient.GetStream().ReadTimeout = Timeout.Infinite; stream = new BigEndianStream(tcpClient.GetStream()); #elif NETFX_CORE //TODO: Fix this var srvRec = new DnsSRV.SRVRecord("impp.trillian.im", 0, 0, 3158); var sock = new StreamSocket(); HostName host; if (IP == null) { host = new HostName(srvRec.NameTarget); } else { host = new HostName(IP); } sock.ConnectAsync(host, srvRec.Port.ToString()).AsTask().Wait(); stream = new BigEndianStream(sock); #endif var vp = new VersionPacket(); vp.Write(stream); vp.Read(stream); WriteDebugLine("Got version " + vp.ReadProtocolVersion); stream.Flush(); TLVPacket tp = new TLVPacket(); tp.MessageType = (ushort)StreamTypes.TType.FEATURES_SET; tp.MessageFamily = (ushort)StreamTypes.TFamily.STREAM; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Block = new TLV[] { new TLV() { TLVType = (ushort)StreamTypes.TTupleType.FEATURES, Value = new byte[] { 0x00, 0x01 } } }; tp.Write(stream); stream.Flush(); tp.Read(stream); stream.Flush(); WriteDebugLine("Features set: " + tp); bool UseSSL = false; foreach (byte b in tp.Block.First().Value) { if (b == (byte)0x01) { UseSSL = true; } } if (!UseSSL) { WriteDebugLine("Warning! Expected SSL to be used!"); } else { stream.Flush(); //stream.Close(); #if WINDOWS SslStream ss = new SslStream(stream); ss.AuthenticateAsClient(srvRec.NameTarget); stream = new BigEndianStream(ss); #elif NETFX_CORE sock.UpgradeToSslAsync(SocketProtectionLevel.Ssl, new HostName(srvRec.NameTarget)).AsTask().Wait(); #endif } tp = new TLVPacket(); tp.MessageType = (ushort)StreamTypes.TType.AUTHENTICATE; tp.MessageFamily = (ushort)StreamTypes.TFamily.STREAM; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Block = new TLV[] { new TLV() { TLVType = 0x0002, Value = new byte[] { 0x00, 0x01 } }, new StringTLV() { TLVType = 0x0003, Value = UserName }, new StringTLV() { TLVType = 0x4001, Value = Password }, }; tp.Write(stream); stream.Flush(); tp.Read(stream); WriteDebugLine("Authenticate: " + tp); tp = new TLVPacket(); tp.MessageType = (ushort)DeviceTypes.TType.BIND; tp.MessageFamily = (ushort)DeviceTypes.TFamily.DEVICE; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; string os = "Windows"; string arch = "Unknown"; string machine = "Unknown"; #if WINDOWS switch (Environment.OSVersion.Platform) { case PlatformID.MacOSX: os = "Mac OS X"; break; case PlatformID.Unix: os = "Unix"; break; } arch = Environment.Is64BitOperatingSystem ? "amd64" : "i386"; machine = Environment.MachineName; #elif WINRT os = "WinRT"; switch (System.CPU.NativeInfo.ProcessorArchitecture) { case ProcessorArchitecture.INTEL: arch = "i386"; break; case ProcessorArchitecture.IA32_ON_WIN64: arch = "amd64"; break; default: arch = System.CPU.NativeInfo.ProcessorArchitecture.ToString().ToLower(); break; } var hostnames = Windows.Networking.Connectivity.NetworkInformation.GetHostNames(); foreach (var hostname in hostnames) { WriteDebugLine("Machine: " + hostname.RawName); if (!hostname.RawName.Contains(".") && !hostname.RawName.Contains(":")) { machine = hostname.RawName; } } #elif WINDOWS_PHONE os = "Windows Phone"; arch = "arm"; machine = DeviceStatus.DeviceName; #endif tp.Block = new TLV[] { new StringTLV() { TLVType = 0x0001, Value = "SharpIMPP" }, //Client name new StringTLV() { TLVType = 0x0002, Value = os }, //OS Name new StringTLV() { TLVType = 0x0004, Value = arch }, //Processor architecture new TLV() { TLVType = 0x0005, Value = new byte[] { 0x00, 0x01 } }, //Client version new TLV() { TLVType = 0x0006, Value = new byte[] { 0x00, 0x01 } }, //Build Number new StringTLV() { TLVType = 0x0008, Value = machine }, //Machine name new TLV() { TLVType = 0x000b, Value = new byte[] { 0x00, 0x01 } }, //Status new TLV() { TLVType = 0x0010, Value = new byte[] { 0x01 } }, //IS_STATUS_AUTOMATIC new TLV() { TLVType = 0x000d, Value = new byte[] { 0x00, 0x01, 0x00, 0x02 } }, //Capabilities new StringTLV() { TLVType = 0x0007, Value = "SharpIMPP/" + os + "-" + arch + " 1.0.0.1" }, //Description }; tp.Write(stream); stream.Flush(); tp.Read(stream); WriteDebugLine("Device bind: " + tp); bool reconnect = false; foreach (TLV t in tp.Block) { if (t.TLVType == 0) { if (t.Value.Length == 2 && t.Value[0] == 128 && t.Value[1] == 4) { reconnect = true; } else { throw new Exception("Error"); } } else if (t.TLVType == (ushort)DeviceTypes.TTupleType.DEVICE_NAME) { this.DeviceName = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); } else if (t.TLVType == (ushort)DeviceTypes.TTupleType.SERVER) { IP = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); } } if (reconnect && IP != null) { WriteDebugLine("Reconnecting to " + IP); #if WINDOWS tcpClient.GetStream().Dispose(); #elif NETFX_CORE sock.Dispose(); #endif connectInThread(UserName, UserDomain, Password, IP); return; } Password = null; //We don't need this anymore! tp = new TLVPacket(); tp.MessageType = (ushort)ListTypes.TType.GET; tp.MessageFamily = (ushort)ListTypes.TFamily.LISTS; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Block = new TLV[] { }; tp.Write(stream); stream.Flush(); tp.Read(stream); WriteDebugLine("Lists get: " + tp); if (ListReceived != null) { List <ContactListItem> contacts = new List <ContactListItem>(); foreach (TLV t in tp.Block) { contacts.Add(new ContactListItem() { ContactType = (ListTypes.TTupleType)t.TLVType, ContactName = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length) }); } RaiseEventOnUIThread(this.ListReceived, new object[] { this, new ListEventArgs() { ContactList = contacts } }); } tp = new TLVPacket(); tp.MessageType = (ushort)GroupChatTypes.TType.GET; tp.MessageFamily = (ushort)GroupChatTypes.TFamily.GROUP_CHATS; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Block = new TLV[] { }; tp.Write(stream); stream.Flush(); tp.Read(stream); WriteDebugLine("Group chats: " + tp); tp = new TLVPacket(); tp.MessageType = (ushort)IMTypes.TType.OFFLINE_MESSAGES_GET; tp.MessageFamily = (ushort)IMTypes.TFamily.IM; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Write(stream); stream.Flush(); tp.Read(stream); WriteDebugLine("Offline IMs: " + tp); byte[] timestamp = new byte[0]; foreach (TLV t in tp.Block) { if (t.TLVType == (ushort)IMTypes.TTupleType.TIMESTAMP) { timestamp = t.Value; } else if (t.TLVType == (ushort)IMTypes.TTupleType.OFFLINE_MESSAGE) { WriteDebugLine("Offline message: " + Encoding.UTF8.GetString(t.Value, 0, t.Value.Length)); } } tp = new TLVPacket(); tp.MessageType = (ushort)IMTypes.TType.OFFLINE_MESSAGES_DELETE; tp.MessageFamily = (ushort)IMTypes.TFamily.IM; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Block = new TLV[] { new TLV() { TLVType = (ushort)IMTypes.TTupleType.TIMESTAMP, Value = timestamp } }; tp.Write(stream); stream.Flush(); tp.Read(stream); WriteDebugLine("Deleted offline IMs: " + tp); tp = new TLVPacket(); tp.MessageType = (ushort)PresenceTypes.TType.GET; tp.MessageFamily = (ushort)PresenceTypes.TFamily.PRESENCE; tp.Flags = Globals.MF_REQUEST; tp.SequenceNumber = SeqNum; tp.Block = new TLV[0]; tp.Write(stream); stream.Flush(); //tp.Read(stream); //WriteDebugLine("Presence set: " + tp); #if WINDOWS Thread pingThread = new Thread(new ThreadStart(doPing)); pingThread.Start(); #elif NETFX_CORE //Task.Run(() => { doPing(); }); #endif IsConnected = true; if (Connected != null) { RaiseEventOnUIThread(this.Connected, new object[] { this, new EventArgs() }); } while (stream.CanRead) { tp = new TLVPacket(); WriteDebugLine("Start byte: " + stream.ReadByte()); WriteDebugLine("Channel byte: " + stream.ReadByte()); tp.Read(stream, false); bool error = false; foreach (TLV t in tp.Block) { if (t.TLVType == 0) { error = true; } } if (error) { WriteDebugLine("Error: " + tp); } else if (tp.MessageType == (ushort)PresenceTypes.TType.UPDATE && tp.MessageFamily == (ushort)PresenceTypes.TFamily.PRESENCE) { String str = "User:"******" Nick: " + csea.Nick; } else if (t.TLVType == (ushort)PresenceTypes.TTupleType.FROM) { csea.Username = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); str += " Username: "******" Email: " + Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); } else if (t.TLVType == (ushort)PresenceTypes.TTupleType.STATUS) { csea.Status = t.Value.Last(); str += " Status: " + csea.Status; } else if (t.TLVType == (ushort)PresenceTypes.TTupleType.STATUS_MESSAGE) { csea.StatusMessage = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); str += " Message: " + csea.StatusMessage; } else if (t.TLVType == (ushort)PresenceTypes.TTupleType.AVATAR_SHA1) { csea.AvatarSHA = t.Value; } } if (ContactStatusChanged != null) { RaiseEventOnUIThread(this.ContactStatusChanged, new object[] { this, csea }); } WriteDebugLine(str); } else if (tp.MessageFamily == (ushort)StreamTypes.TFamily.STREAM && tp.MessageType == (ushort)StreamTypes.TType.PING) { WriteDebugLine("Pong"); } else if (tp.MessageFamily == (ushort)IMTypes.TFamily.IM && tp.MessageType == (ushort)IMTypes.TType.MESSAGE_SEND) { string from = ""; string to = ""; string msg = ""; bool typingevent = false; foreach (TLV t in tp.Block) { if (t.TLVType == (ushort)IMTypes.TTupleType.FROM) { from = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); } else if (t.TLVType == (ushort)IMTypes.TTupleType.TO) { to = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); } else if (t.TLVType == (ushort)IMTypes.TTupleType.MESSAGE_CHUNK) { msg = Encoding.UTF8.GetString(t.Value, 0, t.Value.Length); } else if (t.TLVType == (ushort)IMTypes.TTupleType.CAPABILITY && t.Value[1] == 2) { typingevent = true; } } if (typingevent) { bool isTyping = true; if (contactsTyping.Contains(from)) { isTyping = false; contactsTyping.Remove(from); } else { contactsTyping.Add(from); } WriteDebugLine(from + (isTyping ? " started" : " ended") + " typing"); if (ContactTyping != null) { RaiseEventOnUIThread(this.ContactTyping, new object[] { this, new TypingEventArgs() { From = from, Packet = tp, IsTyping = isTyping } }); } } else if (msg != null && msg.Length > 0) { WriteDebugLine("Chat message from " + from + " to " + to + ": " + msg); if (contactsTyping.Contains(from)) { contactsTyping.Remove(from); if (ContactTyping != null) { RaiseEventOnUIThread(this.ContactTyping, new object[] { this, new TypingEventArgs() { From = from, Packet = tp, IsTyping = false } }); } } if (ChatReceived != null) { RaiseEventOnUIThread(this.ChatReceived, new object[] { this, new ChatEventArgs() { From = from, To = to, OfflineMessage = false, Message = msg, Packet = tp } }); } } } else if (tp.MessageFamily == (ushort)AvatarTypes.TFamily.AVATAR && tp.MessageType == (ushort)AvatarTypes.TType.GET) { WriteDebugLine("Got avatar"); if (AvatarReceived != null) { byte[] data = new byte[0]; string sha = ""; string user = ""; foreach (TLV t in tp.Block) { if (t.TLVType == (ushort)AvatarTypes.TTupleType.DATA) { data = t.Value; } } user = avatarQueue.First(); avatarQueue.Remove(user); RaiseEventOnUIThread(this.AvatarReceived, new object[] { this, new AvatarEventArgs() { Packet = tp, Data = data, AvatarSHA = sha, User = user } }); } } else if (!error) { WriteDebugLine(tp); } } //Just some debug reads to check if we missed something //WriteDebugLine(stream.ReadByte()); //WriteDebugLine(stream.ReadByte()); //WriteDebugLine(stream.ReadByte()); //WriteDebugLine(stream.ReadByte()); //WriteDebugLine(stream.ReadByte()); }