예제 #1
0
        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);
                    });
                }
            }
        }
예제 #2
0
        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");
 }
예제 #4
0
 public static void UpdateAttachmentLocked(SignalAttachment sa)
 {
     lock (DBLock)
     {
         using (var ctx = new SignalDBContext())
         {
             ctx.Attachments.Update(sa);
             ctx.SaveChanges();
         }
     }
 }
예제 #5
0
 public static void DeleteAttachment(SignalAttachment attachment)
 {
     lock (DBLock)
     {
         using (var ctx = new SignalDBContext())
         {
             ctx.Remove(attachment);
             ctx.SaveChanges();
         }
     }
 }
예제 #6
0
 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);
         }
     }
 }
예제 #7
0
 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);
             }
         }
     }
 }
예제 #9
0
        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");
            }
        }
예제 #10
0
        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);
                }
            }
        }
예제 #11
0
 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");
         }
     });
 }
예제 #12
0
        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;
 }
예제 #14
0
        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);
 }
예제 #16
0
        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);
        }
예제 #17
0
 public bool HandleUpdate(SignalAttachment sa)
 {
     DataContext = sa;
     return(Model.Status != SignalAttachmentStatus.Finished && Model.Status != SignalAttachmentStatus.Failed_Permanently);
 }
예제 #18
0
        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];
                }
            }
        }
예제 #19
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);
        }