private async Task TryScheduleAttachmentDownload(SignalAttachment attachment) { if (Downloads.Count < 100) { if (attachment.Status != SignalAttachmentStatus.Finished && !Downloads.ContainsKey(attachment.Id)) { SignalServiceAttachmentPointer attachmentPointer = attachment.ToAttachmentPointer(); IStorageFolder localFolder = ApplicationData.Current.LocalFolder; IStorageFile tmpDownload = await Task.Run(async() => { return(await ApplicationData.Current.LocalCacheFolder.CreateFileAsync(@"Attachments\" + attachment.Id + ".cipher", CreationCollisionOption.ReplaceExisting)); }); BackgroundDownloader downloader = new BackgroundDownloader(); downloader.SetRequestHeader("Content-Type", "application/octet-stream"); // this is the recommended way to call CreateDownload // see https://docs.microsoft.com/en-us/uwp/api/windows.networking.backgroundtransfer.backgrounddownloader#Methods DownloadOperation download = downloader.CreateDownload(new Uri(await MessageReceiver.RetrieveAttachmentDownloadUrl(CancelSource.Token, attachmentPointer)), tmpDownload); attachment.Guid = download.Guid.ToString(); SignalDBContext.UpdateAttachmentGuid(attachment); Downloads.Add(attachment.Id, download); var downloadSuccessfulHandler = Task.Run(async() => { Logger.LogInformation("Waiting for download {0}({1})", attachment.SentFileName, attachment.Id); var t = await download.StartAsync(); await HandleSuccessfullDownload(attachment, tmpDownload, download); }); } } }
private async Task HandleSuccessfullDownload(SignalAttachment attachment, IStorageFile tmpDownload, DownloadOperation download) { try { SemaphoreSlim.Wait(CancelSource.Token); StorageFile plaintextFile = await ApplicationData.Current.LocalCacheFolder.CreateFileAsync(@"Attachments\" + attachment.Id + ".plain", CreationCollisionOption.ReplaceExisting); using (var tmpFileStream = (await tmpDownload.OpenAsync(FileAccessMode.ReadWrite)).AsStream()) using (var plaintextFileStream = (await plaintextFile.OpenAsync(FileAccessMode.ReadWrite)).AsStream()) { Logger.LogInformation("Decrypting to {0}\\{1}", plaintextFile.Path, plaintextFile.Name); DecryptAttachment(attachment.ToAttachmentPointer(), tmpFileStream, plaintextFileStream); } Logger.LogInformation("Deleting tmpFile {0}", tmpDownload.Name); await tmpDownload.DeleteAsync(); attachment.Status = SignalAttachmentStatus.Finished; SignalDBContext.UpdateAttachmentStatus(attachment); await DispatchAttachmentStatusChanged(download, attachment); } catch (Exception e) { Logger.LogError("HandleSuccessfullDownload failed: {0}\n{1}", e.Message, e.StackTrace); } finally { if (Downloads.ContainsKey(attachment.Id)) { Downloads.Remove(attachment.Id); } SemaphoreSlim.Release(); } }
protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); Utils.EnableBackButton(BackButton_Click); Attachments.Clear(); Attachment = e.Parameter as SignalAttachment; Attachments.Add($"{ApplicationData.Current.LocalCacheFolder.Path}/Attachments/{Attachment.Id}.plain"); }
public static void UpdateAttachmentLocked(SignalAttachment sa) { lock (DBLock) { using (var ctx = new SignalDBContext()) { ctx.Attachments.Update(sa); ctx.SaveChanges(); } } }
public static void DeleteAttachment(SignalAttachment attachment) { lock (DBLock) { using (var ctx = new SignalDBContext()) { ctx.Remove(attachment); ctx.SaveChanges(); } } }
public void UpdateAttachment(SignalAttachment sa) { if (Collection != null) { IMessageView m = Collection.GetMessageByDbId(sa.Message.Id); if (m != null) { var attachment = FindElementByName <Attachment>(m.AsFrameworkElement(), "Attachment"); attachment.HandleUpdate(sa); } } }
internal static void UpdateAttachmentStatus(SignalAttachment attachment) { lock (DBLock) { using (var ctx = new SignalDBContext()) { var savedAttachment = ctx.Attachments .Where(a => a.Id == attachment.Id) .First(); savedAttachment.Status = attachment.Status; ctx.SaveChanges(); } } }
public void UpdateAttachment(SignalAttachment sa) { if (UnfinishedAttachmentsCache.ContainsKey(sa.Id)) { var a = UnfinishedAttachmentsCache[sa.Id]; var messageItem = (ListViewItem)ConversationItemsControl.ContainerFromIndex(Collection.GetVirtualIndex(a.MessageIndex)); if (messageItem != null) { var message = FindElementByName <Message>(messageItem, "ListBoxItemContent"); var attachment = FindElementByName <Attachment>(message, "Attachment"); bool retain = attachment.HandleUpdate(sa); if (!retain) { OutgoingCache.Remove(sa.Id); } } } }
public async Task ExportAttachment(SignalAttachment sa) { try { Logger.LogTrace("ExportAttachment() locking"); await SemaphoreSlim.WaitAsync(CancelSource.Token); Logger.LogTrace("ExportAttachment() locked"); var savePicker = new Windows.Storage.Pickers.FileSavePicker { SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Downloads, SuggestedFileName = sa.SentFileName ?? "signal" }; savePicker.FileTypeChoices.Add("Any", new List <string>() { "." }); var target_file = await savePicker.PickSaveFileAsync(); if (target_file != null) { CachedFileManager.DeferUpdates(target_file); IStorageFile localCopy = await ApplicationData.Current.LocalCacheFolder.GetFileAsync($@"Attachments\{sa.Id}.plain"); await localCopy.CopyAndReplaceAsync(target_file); Windows.Storage.Provider.FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(target_file); } } catch (Exception e) { Logger.LogError("ExportAttachment failed: {0}\n{1}", e.Message, e.StackTrace); } finally { SemaphoreSlim.Release(); Logger.LogTrace("ExportAttachment() released"); } }
private async Task RecoverDownloads() { var downloads = await BackgroundDownloader.GetCurrentDownloadsAsync(); foreach (DownloadOperation download in downloads) { try { SignalAttachment attachment = SignalDBContext.GetAttachmentByGuidNameLocked(download.Guid.ToString()); if (attachment != null) { if (!Downloads.ContainsKey(attachment.Id)) { Logger.LogInformation("Creating attach task for attachment {0} ({1})", attachment.Id, download.Guid); Downloads.Add(attachment.Id, download); var t = Task.Run(async() => { await download.AttachAsync(); await HandleSuccessfullDownload(attachment, download.ResultFile, download); }); } else { Logger.LogInformation("Attachment {0} ({1}) already has a running task", attachment.Id, download.Guid); } } else { Logger.LogInformation("Aborting unrecognized download {0}", download.Guid); download.AttachAsync().Cancel(); } } catch (Exception e) { Logger.LogError("TriageDownloads encountered an error: {0}\n{1}", e.Message, e.StackTrace); } } }
public void StartAttachmentDownload(SignalAttachment sa) { //TODO lock, check if already downloading, start a new download if not exists Task.Run(async() => { try { Logger.LogTrace("StartAttachmentDownload() locking"); SemaphoreSlim.Wait(CancelSource.Token); Logger.LogTrace("StartAttachmentDownload() locked"); await TryScheduleAttachmentDownload(sa); } catch (Exception e) { Logger.LogError("StartAttachmentDownload failed: {0}\n{1}", e.Message, e.StackTrace); } finally { SemaphoreSlim.Release(); Logger.LogTrace("StartAttachmentDownload() released"); } }); }
private async Task DispatchAttachmentStatusChanged(DownloadOperation op, SignalAttachment attachment) { try { List <Task> operations = new List <Task>(); foreach (var dispatcher in Frames.Keys) { var taskCompletionSource = new TaskCompletionSource <bool>(); await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { try { Frames[dispatcher].HandleAttachmentStatusChanged(attachment); } catch (Exception e) { Logger.LogError("DispatchAttachmentStatusChanged() dispatch failed: {0}\n{1}", e.Message, e.StackTrace); } finally { taskCompletionSource.SetResult(false); } }); operations.Add(taskCompletionSource.Task); } foreach (var t in operations) { await t; } } catch (Exception e) { Logger.LogError("DispatchAttachmentStatusChanged encountered an error: {0}\n{1}", e.Message, e.StackTrace); } }
public SignalAttachmentContainer(SignalAttachment attachment, int attachmentIndex, int messageIndex) { Attachment = attachment; AttachmentIndex = attachmentIndex; MessageIndex = messageIndex; }
private void HandleSignalMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp) { SignalMessageDirection type; SignalContact author; SignalMessageStatus status; string threadId; long composedTimestamp; string body = dataMessage.Body != null ? dataMessage.Body : ""; if (dataMessage.Group != null) { var rawId = dataMessage.Group.GroupId; threadId = Base64.encodeBytes(rawId); var g = SignalDBContext.GetOrCreateGroupLocked(threadId, timestamp, this); if (!g.CanReceive) { SignalServiceGroup group = new SignalServiceGroup() { Type = SignalServiceGroup.GroupType.REQUEST_INFO, GroupId = rawId }; SignalServiceDataMessage requestInfoMessage = new SignalServiceDataMessage() { Group = group, Timestamp = Util.CurrentTimeMillis() }; MessageSender.sendMessage(envelope.getSourceAddress(), requestInfoMessage); } composedTimestamp = envelope.getTimestamp(); } else { if (isSync) { var sent = content.SynchronizeMessage.getSent().ForceGetValue(); threadId = SignalDBContext.GetOrCreateContactLocked(sent.getDestination().ForceGetValue(), timestamp, this).ThreadId; composedTimestamp = sent.getTimestamp(); } else { threadId = SignalDBContext.GetOrCreateContactLocked(envelope.getSource(), timestamp, this).ThreadId; composedTimestamp = envelope.getTimestamp(); } } if (isSync) { type = SignalMessageDirection.Synced; status = SignalMessageStatus.Confirmed; author = null; } else { status = 0; type = SignalMessageDirection.Incoming; author = SignalDBContext.GetOrCreateContactLocked(envelope.getSource(), timestamp, this); } List <SignalAttachment> attachments = new List <SignalAttachment>(); SignalMessage message = new SignalMessage() { Direction = type, Status = status, Author = author, Content = new SignalMessageContent() { Content = body }, ThreadId = threadId, DeviceId = (uint)envelope.getSourceDevice(), Receipts = 0, ComposedTimestamp = composedTimestamp, ReceivedTimestamp = timestamp, AttachmentsCount = (uint)attachments.Count, Attachments = attachments }; if (dataMessage.Attachments != null) { var receivedAttachments = dataMessage.Attachments; foreach (var receivedAttachment in receivedAttachments) { var pointer = receivedAttachment.asPointer(); SignalAttachment sa = new SignalAttachment() { Message = message, Status = (uint)SignalAttachmentStatus.Default, SentFileName = pointer.FileName, ContentType = "", Key = pointer.Key, Relay = pointer.Relay, StorageId = pointer.Id }; attachments.Add(sa); } } Debug.WriteLine("received message: " + message.Content); if (type == SignalMessageDirection.Incoming) { if (App.WindowActive) { Utils.TryVibrate(true); } else { SendTileNotification(message); SendMessageNotification(message); } } Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async() => { await UIHandleIncomingMessage(message); }).AsTask().Wait(); }
public void HandleAttachmentStatusChanged(SignalAttachment sa) { Locator.MainPageInstance.HandleAttachmentStatusChanged(sa); }
private async Task HandleSignalMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp) { SignalMessageDirection type; SignalContact author; SignalMessageStatus status; SignalConversation conversation; long composedTimestamp; string body = dataMessage.Body ?? ""; if (dataMessage.Group != null) { var rawId = dataMessage.Group.GroupId; var threadId = Base64.EncodeBytes(rawId); conversation = await SignalDBContext.GetOrCreateGroupLocked(threadId, timestamp); if (!conversation.CanReceive) { SignalServiceGroup group = new SignalServiceGroup() { Type = SignalServiceGroup.GroupType.REQUEST_INFO, GroupId = rawId }; SignalServiceDataMessage requestInfoMessage = new SignalServiceDataMessage() { Group = group, Timestamp = Util.CurrentTimeMillis() }; SignalLibHandle.Instance.OutgoingQueue.Add(new SignalServiceDataMessageSendable(requestInfoMessage, envelope.GetSourceAddress())); } composedTimestamp = envelope.GetTimestamp(); } else { if (isSync) { var sent = content.SynchronizeMessage.Sent; conversation = await SignalDBContext.GetOrCreateContactLocked(sent.Destination.ForceGetValue(), timestamp); composedTimestamp = sent.Timestamp; } else { conversation = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp); composedTimestamp = envelope.GetTimestamp(); } } if (isSync) { type = SignalMessageDirection.Synced; status = SignalMessageStatus.Confirmed; author = null; } else { status = 0; type = SignalMessageDirection.Incoming; author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp); } if (author != null && author.Blocked) { // Don't save blocked messages return; } List <SignalAttachment> attachments = new List <SignalAttachment>(); SignalMessage message = new SignalMessage() { Direction = type, Status = status, Author = author, Content = new SignalMessageContent() { Content = body.Truncate(2000) }, ThreadId = conversation.ThreadId, DeviceId = (uint)envelope.GetSourceDevice(), Receipts = 0, ComposedTimestamp = composedTimestamp, ReceivedTimestamp = timestamp, AttachmentsCount = (uint)attachments.Count, Attachments = attachments }; if (dataMessage.Attachments != null) { var receivedAttachments = dataMessage.Attachments; foreach (var receivedAttachment in receivedAttachments) { var pointer = receivedAttachment.AsPointer(); SignalAttachment sa = new SignalAttachment() { Message = message, Status = (uint)SignalAttachmentStatus.Default, SentFileName = pointer.FileName, ContentType = receivedAttachment.ContentType, Key = pointer.Key, Relay = pointer.Relay, StorageId = pointer.Id, Size = (long)pointer.Size, Digest = pointer.Digest }; attachments.Add(sa); } // Make sure to update attachments count message.AttachmentsCount = (uint)attachments.Count; } await SignalLibHandle.Instance.SaveAndDispatchSignalMessage(message, null, conversation); }
public bool HandleUpdate(SignalAttachment sa) { DataContext = sa; return(Model.Status != SignalAttachmentStatus.Finished && Model.Status != SignalAttachmentStatus.Failed_Permanently); }
private void UpdateUI() { if (Model != null) { UpdateMessageTextBlock(); if (Model.Author == null) { MessageAuthor.Visibility = Visibility.Collapsed; MessageBoxBorder.Background = Utils.BackgroundOutgoing; MessageContentTextBlock.Foreground = Utils.ForegroundOutgoing; FancyTimestampBlock.Foreground = Utils.GetSolidColorBrush(127, "#454545"); HorizontalAlignment = HorizontalAlignment.Right; FooterPanel.HorizontalAlignment = HorizontalAlignment.Right; if (Model.Status == SignalMessageStatus.Pending) { CheckImage.Visibility = Visibility.Collapsed; DoubleCheckImage.Visibility = Visibility.Collapsed; ResendTextBlock.Visibility = Visibility.Collapsed; } else if (Model.Status == SignalMessageStatus.Confirmed) { CheckImage.Visibility = Visibility.Visible; DoubleCheckImage.Visibility = Visibility.Collapsed; ResendTextBlock.Visibility = Visibility.Collapsed; } else if (Model.Status == SignalMessageStatus.Received) { CheckImage.Visibility = Visibility.Collapsed; DoubleCheckImage.Visibility = Visibility.Visible; ResendTextBlock.Visibility = Visibility.Collapsed; } else { CheckImage.Visibility = Visibility.Collapsed; DoubleCheckImage.Visibility = Visibility.Collapsed; ResendTextBlock.Visibility = Visibility.Visible; } } else { CheckImage.Visibility = Visibility.Collapsed; DoubleCheckImage.Visibility = Visibility.Collapsed; ResendTextBlock.Visibility = Visibility.Collapsed; if (Model.ThreadId.EndsWith("=")) { MessageAuthor.Visibility = Visibility.Visible; MessageAuthor.Text = Model.Author.ThreadDisplayName; } else { MessageAuthor.Visibility = Visibility.Collapsed; } MessageBoxBorder.Background = Model.Author.Color != null?Utils.GetBrushFromColor(Model.Author.Color) : Utils.GetBrushFromColor(Utils.CalculateDefaultColor(Model.Author.ThreadDisplayName)); MessageAuthor.Foreground = Utils.GetSolidColorBrush(204, "#ffffff"); MessageContentTextBlock.Foreground = Utils.ForegroundIncoming; FancyTimestampBlock.Foreground = Utils.GetSolidColorBrush(127, "#ffffff"); HorizontalAlignment = HorizontalAlignment.Left; FooterPanel.HorizontalAlignment = HorizontalAlignment.Left; } FancyTimestampBlock.Text = Utils.GetTimestamp(Model.ComposedTimestamp); HasAttachment = false; if (Model.Attachments?.Count > 0) { HasAttachment = true; Attachment = Model.Attachments[0]; } } }
private void HandleSignalMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp) { SignalMessageDirection type; SignalContact author; SignalMessageStatus status; SignalConversation conversation; long composedTimestamp; string body = dataMessage.Body ?? ""; if (dataMessage.Group != null) { var rawId = dataMessage.Group.GroupId; var threadId = Base64.encodeBytes(rawId); conversation = SignalDBContext.GetOrCreateGroupLocked(threadId, timestamp); if (!conversation.CanReceive) { SignalServiceGroup group = new SignalServiceGroup() { Type = SignalServiceGroup.GroupType.REQUEST_INFO, GroupId = rawId }; SignalServiceDataMessage requestInfoMessage = new SignalServiceDataMessage() { Group = group, Timestamp = Util.CurrentTimeMillis() }; //MessageSender.sendMessage(envelope.getSourceAddress(), requestInfoMessage); TODO } composedTimestamp = envelope.getTimestamp(); } else { if (isSync) { var sent = content.SynchronizeMessage.getSent().ForceGetValue(); conversation = SignalDBContext.GetOrCreateContactLocked(sent.getDestination().ForceGetValue(), timestamp); composedTimestamp = sent.getTimestamp(); } else { conversation = SignalDBContext.GetOrCreateContactLocked(envelope.getSource(), timestamp); composedTimestamp = envelope.getTimestamp(); } } if (isSync) { type = SignalMessageDirection.Synced; status = SignalMessageStatus.Confirmed; author = null; } else { status = 0; type = SignalMessageDirection.Incoming; author = SignalDBContext.GetOrCreateContactLocked(envelope.getSource(), timestamp); } List <SignalAttachment> attachments = new List <SignalAttachment>(); SignalMessage message = new SignalMessage() { Direction = type, Status = status, Author = author, Content = new SignalMessageContent() { Content = body }, ThreadId = conversation.ThreadId, DeviceId = (uint)envelope.getSourceDevice(), Receipts = 0, ComposedTimestamp = composedTimestamp, ReceivedTimestamp = timestamp, AttachmentsCount = (uint)attachments.Count, Attachments = attachments }; if (dataMessage.Attachments != null) { var receivedAttachments = dataMessage.Attachments; foreach (var receivedAttachment in receivedAttachments) { var pointer = receivedAttachment.asPointer(); SignalAttachment sa = new SignalAttachment() { Message = message, Status = (uint)SignalAttachmentStatus.Default, SentFileName = pointer.FileName, ContentType = "", Key = pointer.Key, Relay = pointer.Relay, StorageId = pointer.Id }; attachments.Add(sa); } } SignalLibHandle.Instance.SaveAndDispatchSignalMessage(message, conversation); }