using ChatController.ChatKlassen; using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Security; using System.Runtime.CompilerServices; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Forms; using System.Windows.Media; using System.Windows.Media.Imaging; using ChatController.Annotations; using ChatController.Core; using ChatController.Extensions; using ChatController.LoginKlassen; using ChatController.Utilities; using ChatController.Utilities.Extensions; using RestSharp; using RestSharp.Extensions; using Clipboard = System.Windows.Forms.Clipboard; using ContextMenu = System.Windows.Controls.ContextMenu; using DataFormats = System.Windows.Forms.DataFormats; using Image = System.Drawing.Image; using MessageBox = System.Windows.MessageBox; namespace ChatController.HauptKlassen { // Ist quasi das ViewModel public class Chat : INotifyPropertyChanged { private static DateTime _DefaultTime = new DateTime(1970, 1, 1); public Action ExceptionCallback { get; set; } public Action ThreadExceptionCallback { get; set; } private readonly List _Contacts = new List(); public static ChatDatenUebergabe ChatDaten { get; set; } private UserMessages _UserMessages; private UserMessages _AdditionalUserMessages; private string _NextPage; private bool _HasNextPage; public long LastTimeStamp { get; set; } public Chat(ChatDatenUebergabe chatDaten, Action exceptionCallback, Action threadExceptionCallback) { ChatDaten = chatDaten; ExceptionCallback = exceptionCallback; ThreadExceptionCallback = threadExceptionCallback; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; PinCertificate(); } private static void PinCertificate() { ServicePointManager.ServerCertificateValidationCallback = PinPublicKey; } //!!!!Wenn hier neue Keys hinzugefügt werden, muss das auch in der Klasse BeWo.LoginControl und im DatabaseTerminator gemacht werden!! private const string PinningFailMessage = "Es konnte keine sichere Verbindung zum Server hergestellt werden."; private const String PUB_KEY_X3 = "9CD30CF05AE52E47B7725D3783B3686330EAD735261925E1BDBE35F170922FB7B84B4105ABA99E350858ECB12AC468870BA3E375E4E6F3A76271BA7981601FD7919A9FF3D0786771C8690E9591CFFEE699E9603C48CC7ECA4D7712249D471B5AEBB9EC1E37001C9CAC7BA705EACE4AEBBD41E53698B9CBFD6D3C9668DF232A42900C867467C87FA59AB8526114133F65E98287CBDBFA0E56F68689F3853F9786AFB0DC1AEF6B0D95167DC42BA065B299043675806BAC4AF31B9049782FA2964F2A20252904C674C0D031CD8F31389516BAA833B843F1B11FC3307FA27931133D2D36F8E3FCF2336AB93931C5AFC48D0D1D641633AAFA8429B6D40BC0D87DC3930203010001"; private const String PUB_KEY_R3 = "BB021528CCF6A094D30F12EC8D5592C3F882F199A67A4288A75D26AAB52BB9C54CB1AF8E6BF975C8A3D70F4794145535578C9EA8A23919F5823C42A94E6EF53BC32EDB8DC0B05CF35938E7EDCF69F05A0B1BBEC094242587FA3771B313E71CACE19BEFDBE43B45524596A9C153CE34C852EEB5AEED8FDE6070E2A554ABB66D0E97A540346B2BD3BC66EB66347CFA6B8B8F572999F830175DBA726FFB81C5ADD286583D17C7E709BBF12BF786DCC1DA715DD446E3CCAD25C188BC60677566B3F118F7A25CE653FF3A88B647A5FF1318EA9809773F9D53F9CF01E5F5A6701714AF63A4FF99B3939DDC53A706FE48851DA169AE2575BB13CC5203F5ED51A18BDB150203010001"; private const String PUB_KEY_E1 = "245c2da22afd1c4ba65d97732731acb2a06962ef65e8a6b0f0ac4b9fff1c0b700fd3982f4dfc0f009b37f074055732972e05ef2a4325a3fb6e342713f64f7e69d302995eeb244792c1249be6b1218fc12481fc68cc1f69ba58f51922f774c616"; private const String PUB_KEY_E5 = "0d0b3a8a6b618eb6efdc5f58e7c6424554ab63f66661480a2e5975b481023750b73f1679dc98eca1289772201c2ccfd57c52204e54785b84146bc090ae85ecc051413c5a877f064dd4fe60d1fa6c2de17d951088a208540f991a4ce6ea0aacd8"; private const String PUB_KEY_E6 = "d9f19e4687f8217160a826eba3fab9eada1db912a7d426d95114b1617c7596bf220b391fd5bed10a46aa2d3c4a09842ebe409555e91940376675ed324e770449f8707bc318e7cef77110feac74d800d4ed6d1c731633109c3ab2ea6c62f4bdb8"; private const String PUB_KEY_R10 = "CF57E5E6C45412EDB447FEC92758764650288C1D3E88DF059DD5B51829BDDDB55ABFFAF6CEA3BEAF00214B625A5A3C012FC55803F689FF8E1143EBC1B5E01407968F6F1FD7E7BA8139097565B7C2AF185B372628E7A3F4072B6D1AFFAB58BC95AE40FFE9CB57C4B55B7F780D1861BC17E754C6BB4991CD6E18D18085EEA66536BC74EABC504CEAFC21F338169394BAB0D36B3806CD16127ACA5275C8AD76B2C29C5D98455C6F617BC62DEE3C13528601D957E6381CDF8DB51F92919AE74A1CCC45A87255F0B0E6A307ECFDA71B669E3F488B71847158C93AFAEF5EF25B442B3C74E78FB247C1076ACD9AB70D96F712812651540AEC61F6F7F5E2F28AC8950D8D0203010001"; private const String PUB_KEY_R11 = "BA87BC5C1B0039CBCA0ACDD46710F9013CA54EA561CB26CA52FB1501B7B928F5281EED27B324183967090C08ECE03AB03B770EBDF3E53954410C4EAE41D69974DE51DBEF7BFF58BDA8B713F6DE31D5F272C9726A0B8374959C4600641499F3B1D922D9CDA892AA1C267A3FFEEF58057B089581DB710F8EFBE33109BB09BE504D5F8F91763D5A9D9E83F2E9C466B3E106664348188065A037189A9B843297B1B2BDC4F815009D2788FBE26317966C9B27674BC4DB285E69C279F0495CE02450E1C4BCA105AC7B406D00B4C2413FA758B82FC55C9BA5BB099EF1FEEBB08539FDA80AEF45C478EB652AC2CF5F3CDEE35C4D1BF70B272BAA0B4277534F796A1D87D90203010001"; private static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors) { try { if (certificate == null || chain == null) return false; bool chainContainsPk = false; foreach (var element in chain.ChainElements) { String pk = element.Certificate.GetPublicKeyString().ToLower(); if (pk.Contains(PUB_KEY_X3.ToLower()) || pk.Contains(PUB_KEY_R3.ToLower()) || pk.Contains(PUB_KEY_E1.ToLower()) || pk.Contains(PUB_KEY_E5.ToLower()) || pk.Contains(PUB_KEY_E6.ToLower()) || pk.Contains(PUB_KEY_R10.ToLower()) || pk.Contains(PUB_KEY_R11.ToLower())) { chainContainsPk = true; } } bool subjectAccepted = certificate.Subject.Trim().ToLower().EndsWith(".bewoplaner.de") || certificate.Subject.Trim().ToLower().EndsWith(".ownchat.de"); return chainContainsPk && subjectAccepted; } catch (Exception e) { return false; } } public List AddContacts() { var groupInputs = ChatDaten?.AlleGruppen?.Response?.Groups?.ToArray() ?? new GroupInput[0]; _Contacts.AddRange(GenerateContactsFromServerResponse(groupInputs, true)); return _Contacts; } // Klick auf Kontakt. Die Collection muss davor geleert werden. // Führt zu doppelter neuester Nachricht, wenn man vorher eine verschickt hat! public void LoadChatMessagesForContactAsync(Contact contact, ChatMessage previousMessage, Action> callback) { if(!(contact is null)) { LoadMessagesFromServerAsync(contact.GroupId, delegate { callback?.Invoke(AddMessagesFromServerResponse(_UserMessages?.Response?.Messages ?? new OwnChatMessage[0], previousMessage)); }); return; } callback?.Invoke(new List()); } private void LoadMessagesFromServerAsync(long groupId, Action callback) { var url = $"{ChatDaten.ServerUrl}{Constants.LoadMessagesForGroupUrl}{groupId}"; var client = new RestClient(url); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { _UserMessages = JsonConvert.DeserializeObject(response.Content); if(_UserMessages?.Response?.HasMorePages ?? false) { _NextPage = _UserMessages.Response.NextPage; _HasNextPage = true; } else { _HasNextPage = false; } callback?.Invoke(); }); } public void LoadMoreMessagesAsync(Contact contact, ChatMessage previousMessage, Action> callback) { LoadMoreMessagesFromServerAsync(contact.GroupId, _NextPage, () => { callback?.Invoke(AddMessagesFromServerResponse(_AdditionalUserMessages?.Response?.Messages ?? new OwnChatMessage[0], previousMessage)); }); } private void LoadMoreMessagesFromServerAsync(long groupId, string page, Action callback) { if(page is null || !page.Contains("=")) { callback?.Invoke(); return; } var pageParam = page.Split('=')[1]; var url = $"{ChatDaten.ServerUrl}/api/chat/messages?groupid={groupId}&page={pageParam}"; var client = new RestClient(url); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { _AdditionalUserMessages = null; _AdditionalUserMessages = JsonConvert.DeserializeObject(response.Content); if(_AdditionalUserMessages?.Response?.HasMorePages ?? false) { _NextPage = _AdditionalUserMessages.Response.NextPage; } _HasNextPage = _AdditionalUserMessages?.Response?.HasMorePages ?? false; callback?.Invoke(); }); } private double _FormerMessagesCount; public void CheckIfNewMessagesExistAsync(long groupId, Action callback) { #if DEBUG if(_UserMessages?.Response is null) { throw new Exception("Too many requests."); } #endif var span = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); var timespan = Convert.ToInt64(span.TotalSeconds); if(!(_UserMessages is null) && _UserMessages.Response.Messages.Length > 0) { timespan = _UserMessages.Response.Messages.First().CreatedAt; } GetNumberOfNewMessagesAsync(groupId, timespan, numberOfNewMessages => { var hasNewMessages = numberOfNewMessages != _FormerMessagesCount; _FormerMessagesCount = numberOfNewMessages; callback?.Invoke(hasNewMessages); }); } private void GetNumberOfNewMessagesAsync(long groupId, long lastTimeStamp, Action callback) { try { var url = $"{ChatDaten.ServerUrl}{Constants.LoadOwnChatNewsUrl}{groupId}/{lastTimeStamp}"; var client = new RestClient(url); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { var messageCounter = JsonConvert.DeserializeObject(response.Content); callback?.Invoke(messageCounter?.MessageCount ?? 0); }); } catch(Exception exception) { callback?.Invoke(0d); throw exception; } } public void GetNumberOfAllNewMessagesAsync(Action callback) { LoadNumberOfNewMessagesFromServerAsync(0, numberOfNewMessages => { if(numberOfNewMessages > 0) { LastTimeStamp = DateTime.UtcNow.GetUnixTimeStamp(); } callback?.Invoke(numberOfNewMessages); }); } private void LoadNumberOfNewMessagesFromServerAsync(long groupId, Action callback) { var url = $"{ChatDaten.ServerUrl}{Constants.LoadOwnChatNewsUrl}{groupId}/{LastTimeStamp}"; var client = new RestClient(url); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { var messageCounter = JsonConvert.DeserializeObject(response.Content); callback?.Invoke(messageCounter?.MessageCount ?? 0); }); } private void LoadGroupsAsync(Action callback) { var url = $"{ChatDaten.ServerUrl}{Constants.GetChatGroupsUrl}"; var client = new RestClient(url); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { var contacts = JsonConvert.DeserializeObject(response.Content); callback?.Invoke(contacts); }); } public void UpdateContactList(Action> callback) { LoadGroupsAsync(rawData => { if(rawData.Response is null) { return; } var contacts = GenerateContactsFromServerResponse(rawData.Response.Groups.ToArray(), true); callback?.Invoke(contacts.OrderByDescending(c => c.TimeStamp)); }); } public List AddNewMessage(string pMessage, long pGroupId, ChatMessage previousMessage) { var time = DateTime.Now; var chatMessage = new ChatMessage(pGroupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, pMessage, time, true, 0, null, null, null, null, null, ChatMessageType.Message, ChatDaten.LoggedInUser.Response.User.Oid); var messages = new List(); if(!(previousMessage is null)) { messages.Add(previousMessage); } messages.Add(chatMessage); var result = AddSeparators(messages); result.Remove(previousMessage); return result; } public async Task SendMessage(string message, long groupId) { var endurl = ChatDaten.ServerUrl + Constants.SendMessageUrl; using(var multiPartContent = new MultipartFormDataContent()) { multiPartContent.Add(new StringContent(groupId.ToString()), "groupid"); multiPartContent.Add(new StringContent(message), "text"); var requestUri = new Uri(endurl); var httpRequest = new HttpRequestMessage {Method = HttpMethod.Post, RequestUri = requestUri, Content = multiPartContent}; httpRequest.Headers.Add("Token", ChatDaten.AuthToken); httpRequest.Headers.Add("CustomerID", ChatDaten.Kundennummer); var httpClient = new HttpClient(); await httpClient.SendAsync(httpRequest, CancellationToken.None); } } public string OpenFile() { var openFileDialog = new OpenFileDialog { Filter = Resource.OpenFileDialogFilter_Test }; var result = openFileDialog.ShowDialog(); return result == DialogResult.OK ? openFileDialog.FileName : null; } public List AddNewFile(string pathToScaledFile, string originalFilePath, long groupId, ChatMessage previousMessage, string chatBoxText) { var result = new List(); if(string.IsNullOrEmpty(pathToScaledFile) || string.IsNullOrEmpty(originalFilePath)) { return result; } var messageId = 0; var userName = ChatDaten.LoggedInUser.Response.User.UserName; var sendTime = DateTime.Now; var fileName = Path.GetFileName(pathToScaledFile); var imageFile = GetImageFile(pathToScaledFile, out var fileSize); var isImage = Constants.ImageFileExtensions.Contains(Path.GetExtension(pathToScaledFile).ToUpperInvariant()); var messageText = string.IsNullOrWhiteSpace(chatBoxText) ? fileName : chatBoxText; var filePath = isImage ? null : pathToScaledFile; var originalImage = isImage ? pathToScaledFile : null; var imageName = isImage ? fileName : null; var linkToThumbnail = isImage ? null : $"{ChatDaten.ServerUrl}/document.png"; var logo = isImage ? imageFile : null; var chatMessageType = isImage ? ChatMessageType.Image : ChatMessageType.Document; var senderId = ChatDaten.LoggedInUser.Response.User.Oid; var chatMessage = new ChatMessage(groupId, messageId, userName, messageText, sendTime, true, fileSize, filePath, originalImage, imageName, linkToThumbnail, logo, chatMessageType, senderId); result = AddSeparators(new List { previousMessage, chatMessage }); result.Remove(previousMessage); return result; } private static BitmapImage GetImageFile(string pathToScaledFile, out long fileSize) { if(!File.Exists(pathToScaledFile) || !Constants.ImageFileExtensions.Contains(Path.GetExtension(pathToScaledFile).ToUpperInvariant())) { fileSize = 0L; return null; } byte[] file; using(Stream reader = File.Open(pathToScaledFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { file = Utils.ReadFully(reader); } using(var memoryStream = new MemoryStream(file)) { var image = Image.FromStream(memoryStream); using(var bitmap = new Bitmap(image)) { using(var stream = new MemoryStream()) { short orient = 0; const int orientationId = 0x0112; if (image.PropertyIdList.Contains(orientationId)) { var item = image.GetPropertyItem(orientationId); orient = BitConverter.ToInt16(item.Value, 0); bitmap.SetPropertyItem(item); } var flipType = Utils.OrientationToFlipType(orient.ToString()); bitmap.RotateFlip(flipType); bitmap.Save(stream, ImageFormat.Jpeg); var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = new MemoryStream(stream.ToArray()); bitmapImage.EndInit(); bitmapImage.Freeze(); fileSize = memoryStream.Length; return bitmapImage; } } } } public List AddFileToMessage(byte[] file, string fileName, long groupId, ChatMessage previousMessage) { var result = new List(); if (string.IsNullOrEmpty(fileName)) { return result; } if(!(previousMessage is null)) { result.Add(previousMessage); } var message = _UserMessages.Response.Messages.Last(); var sendtime = DateTime.Now; if(Constants.ImageFileExtensions.Contains(Path.GetExtension(fileName).ToUpperInvariant())) { var bitmapImage = new BitmapImage(); var memoryStream = new MemoryStream(file); bitmapImage.BeginInit(); bitmapImage.StreamSource = memoryStream; bitmapImage.EndInit(); bitmapImage.Freeze(); memoryStream.Close(); ImageSource logo = bitmapImage; // Mit Logo var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(fileName), sendtime, true, memoryStream.Length, null, fileName, Path.GetFileName(fileName), null, logo, ChatMessageType.Image, ChatDaten.LoggedInUser.Response.User.Oid); result.Add(chatMessage); } else { // Dokument var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(fileName), sendtime, true, 0, fileName, null, null, message.SmallerImage, null, ChatMessageType.Document, ChatDaten.LoggedInUser.Response.User.Oid); result.Add(chatMessage); } return AddSeparators(result); } public async Task SendFileToContact(Contact currentContact, string scaledImagePath, string originalFilePath, string message) { await SendFile(scaledImagePath, currentContact, originalFilePath, message); } private async Task SendFile(string pFile, Contact currentContact, string pOriginalFilePath, string message) { if(string.IsNullOrEmpty(pOriginalFilePath)) { return; } byte[] mediaFile; using(Stream reader = File.OpenRead(pFile)) { mediaFile = Utils.ReadFully(reader); } var fileName = Path.GetFileName(pOriginalFilePath).ToLower(); if(Constants.ImageFileExtensions.Contains(Path.GetExtension(fileName).ToUpperInvariant())) { fileName = fileName.Replace(".bmp", ".jpg"); } await SendMediaMessage(fileName, currentContact.GroupId, mediaFile, message); } private HttpRequestMessage _HttpRequest; private async Task SendMediaMessage(string fileName, long groupId, byte[] mediaFile, string message) { try { using (var multiPartContent = new MultipartFormDataContent()) { var requestUri = new Uri(ChatDaten.ServerUrl + Constants.SendMessageUrl); multiPartContent.Add(new ByteArrayContent(mediaFile, 0, mediaFile.Length), "file", fileName); multiPartContent.Add(new StringContent(groupId.ToString()), "groupid"); if(!string.IsNullOrWhiteSpace(message)) { multiPartContent.Add(new StringContent(message), "text"); } _HttpRequest = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = requestUri, Content = multiPartContent }; _HttpRequest.Headers.Add(Constants.Token, ChatDaten.AuthToken); _HttpRequest.Headers.Add(Constants.CustomerId, ChatDaten.Kundennummer); var httpClient = new HttpClient(); await httpClient.SendAsync(_HttpRequest, HttpCompletionOption.ResponseContentRead); } } catch(Exception) { } } public ContextMenu ErstelleKontextMenue() { var contextMenu = new ContextMenu(); var item1 = new System.Windows.Controls.MenuItem(); var item2 = new System.Windows.Controls.MenuItem(); var item3 = new System.Windows.Controls.MenuItem(); contextMenu.Items.Add(item1); contextMenu.Items.Add(item2); contextMenu.Items.Add(item3); item1.Header = "Speichern unter"; item1.Visibility = Visibility.Visible; item2.Header = "Einfügen"; item2.Visibility = Visibility.Visible; item3.Header = "Kopieren"; item3.Visibility = Visibility.Visible; return contextMenu; } public void SaveFileAs(ChatMessage pChatMessage) { var originalImage = pChatMessage.OriginalImage; var fileUri = originalImage; if(originalImage is null) { fileUri = pChatMessage.FilePath; } if(fileUri is null) { return; } SaveAs(Path.GetFileName(fileUri), DownloadMediaFile(fileUri)); } private static byte[] DownloadMediaFile(string uriToFile) { byte[] mediaFile; using(var webClient = new WebClient()) { webClient.Credentials = CredentialCache.DefaultCredentials; webClient.Headers[Constants.Token] = ChatDaten.AuthToken; webClient.Headers[Constants.CustomerId] = ChatDaten.Kundennummer; mediaFile = webClient.DownloadData(uriToFile); } return mediaFile; } private static void SaveAs(string pFileName, byte[] pMediaFile) { var saveFileDialog = new SaveFileDialog {FileName = pFileName}; saveFileDialog.Title = "ownChat"; saveFileDialog.Filter = "All files (*.*)|*.*"; saveFileDialog.DefaultExt = Path.GetExtension(pFileName); if(saveFileDialog.DefaultExt.Length > 0) { saveFileDialog.AddExtension = true; saveFileDialog.Filter = $"{saveFileDialog.DefaultExt} files (*.{saveFileDialog.DefaultExt})|*.{saveFileDialog.DefaultExt}|{saveFileDialog.Filter}"; saveFileDialog.FilterIndex = 0; } saveFileDialog.ShowDialog(); if (string.IsNullOrEmpty(saveFileDialog.FileName)) { return; } using (var fileStream = (FileStream)saveFileDialog.OpenFile()) { fileStream.Write(pMediaFile, 0, pMediaFile.Length); } } public async Task Paste(long pGroupOid, ChatMainControl pChatMainControl) { var dataObject = Clipboard.GetDataObject(); if(dataObject is null) { return; } if(dataObject.GetDataPresent(DataFormats.FileDrop)) { if(dataObject.GetData(DataFormats.FileDrop) is string[] fileList) { var pathToFile = fileList[0]; if(File.Exists(pathToFile)) { var fileName = Path.GetFileName(pathToFile); var mediaFile = File.ReadAllBytes(pathToFile); pChatMainControl.AddMessages(AddFileToMessage(mediaFile, fileName, pGroupOid, pChatMainControl.GetFirstMessage())); CollectionViewSource.GetDefaultView(pChatMainControl.ChatListBox.ItemsSource).Refresh(); pChatMainControl.ChatListBox.Items.MoveCurrentToLast(); pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem); await SendMediaMessage(fileName, pGroupOid, mediaFile, null); } } } else { if(dataObject.GetDataPresent(DataFormats.Text)) { var text = (string) dataObject.GetData(DataFormats.StringFormat); pChatMainControl.AddMessages(AddNewMessage(text, pGroupOid, pChatMainControl.GetFirstMessage())); CollectionViewSource.GetDefaultView(pChatMainControl.ChatListBox.ItemsSource).Refresh(); pChatMainControl.ChatListBox.Items.MoveCurrentToLast(); pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem); await SendMessage(text, pGroupOid); } else if(dataObject.GetDataPresent(DataFormats.Bitmap)) { var bitmap = (Bitmap) dataObject.GetData(DataFormats.Bitmap); var imageName = Utils.GenerateTempName() + ".jpg"; Image image = bitmap; pChatMainControl.AddMessages(AddFileToMessage(Utils.ImageToByteArray(image), imageName, pGroupOid, pChatMainControl.GetFirstMessage())); CollectionViewSource.GetDefaultView(pChatMainControl.ChatListBox.ItemsSource).Refresh(); pChatMainControl.ChatListBox.Items.MoveCurrentToLast(); pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem); await SendMediaMessage(imageName, pGroupOid, Utils.ImageToByteArray(image), null); } else { MessageBox.Show("Der Zwischen-Speicher kann nicht verarbeitet werden.", "Fehler", MessageBoxButton.OK); } } } public void Copy(object pData, int pDataType) { switch(pDataType) { case 1: Clipboard.SetData(DataFormats.Text, pData); break; case 2: Clipboard.SetData(DataFormats.Bitmap, pData); break; case 3: Clipboard.SetData(DataFormats.FileDrop, pData); break; } } public void ShowProfilePicture(Contact currentContact) { ShowPictureWindow(currentContact.Image, currentContact.Name); } public void ShowPictureWindow(ImageSource imageSource, string title) { var imageWidth = Convert.ToInt32(imageSource.Width); var imageHeight = Convert.ToInt32(imageSource.Height); var imageAspectRatio = imageWidth / (double)imageHeight; var primaryScreenWidth2 = SystemParameters.PrimaryScreenWidth; var primaryScreenHeight2 = SystemParameters.PrimaryScreenHeight; var windowMaxWidth = imageWidth; var windowMaxHeight = imageHeight; if(windowMaxWidth > .8 * primaryScreenWidth2 || windowMaxHeight > .8 * primaryScreenHeight2) { if(primaryScreenWidth2 > primaryScreenHeight2) { windowMaxHeight = (int)(.8 * primaryScreenHeight2); windowMaxWidth = (int)(windowMaxHeight * imageAspectRatio); } else { windowMaxWidth = (int)(.8 * primaryScreenWidth2); windowMaxHeight = (int)(windowMaxWidth * imageAspectRatio); } } var maximumWindowSize = new System.Windows.Size(windowMaxWidth, windowMaxHeight); var minHeight = 232 / imageAspectRatio; var minWidth = 232d; var window = new Window { Title = title, MinHeight = minHeight, MinWidth = minWidth }; var grid = new Grid { Width = maximumWindowSize.Width, Height = maximumWindowSize.Height, MinHeight = minHeight, MinWidth = minWidth }; var image = new System.Windows.Controls.Image { Source = imageSource, Margin = new Thickness(0) }; grid.Children.Clear(); grid.Children.Add(image); window.SizeToContent = SizeToContent.WidthAndHeight; window.Content = grid; window.Margin = new Thickness(0); window.WindowStartupLocation = WindowStartupLocation.CenterScreen; window.ShowDialog(); } public void ShowPicture(string originalImage, long groupId, Action downloadCompletedCallback) { if(originalImage is null) { return; } Utils.DownloadImageAsync(originalImage, $"group-{groupId}", CacheCategory.MessageAttachment, imageSource => { var splitName = originalImage.Split('/'); var last = splitName.LastOrDefault(); downloadCompletedCallback?.Invoke(imageSource, last ?? "Bild"); }); } public async Task ReloadGroupsAsync(Action callback) { var url = ChatDaten.ServerUrl + Constants.GetChatGroupsUrl; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // ToDo: Durch HttpClient ersetzen using(var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add(Constants.Token, ChatDaten.AuthToken); httpClient.DefaultRequestHeaders.Add(Constants.CustomerId, ChatDaten.Kundennummer); var test = await httpClient.GetStringAsync(url); var gruppen = JsonConvert.DeserializeObject(test); } var client = new RestClient(url); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { var groups = JsonConvert.DeserializeObject(response.Content); callback?.Invoke(groups); }); } public List UpdateContacts(ChatGruppenDaten chatDaten) { _Contacts.Clear(); if(!(chatDaten?.Response is null)) { _Contacts.AddRange(GenerateContactsFromServerResponse(chatDaten.Response.Groups.ToArray())); } return _Contacts; } public List GenerateContactsFromServerResponse(GroupInput[] pGroupInputs, bool pShouldUpdateLastTimeStamp = false) { var contacts = new List(); foreach(var groupInput in pGroupInputs) { var formattedTime = new DateTime(); var latestMessage = groupInput.LastMessage; if(latestMessage?.Text != null)// && latestMessage?.Timestamp != null) { var timeStamp = DateTime.Parse(latestMessage.Timestamp.Date); var clientZone = TimeZoneInfo.Local; formattedTime = TimeZoneInfo.ConvertTimeFromUtc(timeStamp, clientZone); } string userIdManage = null; foreach(var user in groupInput.Users) { if(user.Oid != ChatDaten.Userid) { if(!user.Is_Employee && !string.IsNullOrEmpty(user.Userid_Manage)) { userIdManage = user.Userid_Manage; } } } var key = $"group-{groupInput.Oid}"; contacts.Add(new Contact( groupInput.Name, groupInput.LastMessage, formattedTime, groupInput.Oid, userIdManage, groupInput.OnlyEmployees, groupInput.Users.Length, groupInput.CanWrite, groupInput.AccentColor, groupInput.Avatar, key, groupInput.Users.ToDictionary(user => user.Oid, user => user.Picture))); if(!pShouldUpdateLastTimeStamp || latestMessage?.Timestamp?.Date is null) { continue; } var time = DateTime.Parse(latestMessage.Timestamp.Date); //var unixTimeStamp = latestMessage.Timestamp.Value.GetUnixTimeStamp(); var unixTimeStamp = time.GetUnixTimeStamp(); if(LastTimeStamp < unixTimeStamp) { LastTimeStamp = unixTimeStamp; } } Task.Run(() => { var userId2Uris = new Dictionary(); foreach(var contact in contacts) { foreach(var test in contact.UserId2Uri) { userId2Uris.AddAndIgnoreDuplicates(test.Key, test.Value); } } Utils.DownloadUserProfilePicturesSync(userId2Uris); foreach(var contact in contacts) { contact.Image = Utils.DownloadImageSync(contact.ProfilePicturePath, null, contact.GroupId); } }); return contacts; } public List AddMessagesFromServerResponse(OwnChatMessage[] pMessages, ChatMessage previousMessage) { var result = new List(); foreach(var message in pMessages ?? new OwnChatMessage[0]) { var time = DateTime.Parse(message.Timestamp.Date); var clientZone = TimeZoneInfo.Local; var formattedTime = TimeZoneInfo.ConvertTimeFromUtc(time, clientZone); var isLoggedInUsersMessage = !(ChatDaten.Userid is null) && message.UserId == ChatDaten.Userid.Value; var messageText = message.Text ?? (string.IsNullOrEmpty(message.File) ? string.Empty : message.OriginalFilename); if(!string.IsNullOrEmpty(message.File)) { var message2Add = Constants.ImageFileExtensions.Contains(Path.GetExtension(message.File).ToUpperInvariant()) ? //SmallerImage ist null new ChatMessage(message.GroupId, message.Id, message.UserName, messageText, formattedTime, isLoggedInUsersMessage, message.FileSize, message.SmallerImage, message.File, message.OriginalFilename, null, null, ChatMessageType.Image, message.UserId) : new ChatMessage(message.GroupId, message.Id, message.UserName, messageText, formattedTime, isLoggedInUsersMessage, 0, message.File, null, null, message.SmallerImage, null, ChatMessageType.Document, message.UserId); result.AddIfNotIn(message2Add); } else { var chatMessage = new ChatMessage(message.GroupId, message.Id, message.UserName, message.Text, formattedTime, isLoggedInUsersMessage, message.FileSize, null, null, null, null, null, ChatMessageType.Message, message.UserId); result.AddIfNotIn(chatMessage); } } return AddSeparators(result); } private static List AddSeparators(List chatMessages) { if(chatMessages is null) { chatMessages = new List(); } var test = chatMessages.Any(a => a is null); var messagesWithoutSeparators = chatMessages.Where(message => !message.IsSeparator).OrderBy(message => message.SendTime).ToList(); var separators = new List(); var previousMessage = messagesWithoutSeparators.OrderBy(message => message.SendTime).FirstOrDefault(); foreach(var message in messagesWithoutSeparators.OrderBy(message => message.SendTime)) { if(!message.Equals(previousMessage) && !(previousMessage is null)) { if(message.SendTime.Date != previousMessage.SendTime.Date) { var separatorMessage = new ChatMessage(0, -1, null, null, message.SendTime.Date, false, 0, null, null, null, null, null, ChatMessageType.Separator, 0); separators.Add(separatorMessage); previousMessage = message; } } } chatMessages.AddRange(separators); return chatMessages; } public void DownloadFileAsync(string uri, string path, Action callback) { var client = new RestClient(uri); var request = new RestRequest(); request.AddHeader(Constants.Token, ChatDaten.AuthToken); request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer); client.ExecuteAsync(request, response => { if(response.StatusCode == HttpStatusCode.OK) { response.RawBytes.SaveAs(path); } else { throw new Exception("Die Datei konnte nicht heruntergeladen werden."); } callback?.Invoke(); }); } private bool _IsInBroadcastMode; public bool IsInBroadcastMode { get => _IsInBroadcastMode; set { _IsInBroadcastMode = value; OnPropertyChanged(nameof(IsInBroadcastMode)); } } public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class ChatMessageComparer : IComparer { public int Compare(object x, object y) { return x is ChatMessage message1 && y is ChatMessage message2 ? message1.SendTime.CompareTo(message2.SendTime) : 0; } } }