internal static SignalConversation UpdateMessageRead(long timestamp) { SignalConversation conversation; lock (DBLock) { using (var ctx = new SignalDBContext()) { var message = ctx.Messages .Where(m => m.ComposedTimestamp == timestamp) .First(); //TODO care about early reads or messages with the same timestamp sometime conversation = GetSignalConversationByThreadId(ctx, message.ThreadId); var currentLastSeenMessage = ctx.Messages .Where(m => m.ThreadId == conversation.ThreadId) .Skip((int)conversation.LastSeenMessageIndex - 1) .Take(1) .Single(); if (message.Id > currentLastSeenMessage.Id) { var diff = (uint)ctx.Messages .Where(m => m.ThreadId == conversation.ThreadId && m.Id <= message.Id && m.Id > currentLastSeenMessage.Id) .Count(); conversation.LastSeenMessageIndex += diff; if (diff > conversation.UnreadCount) { throw new InvalidOperationException($"UpdateMessageRead encountered an inconsistent state: {diff} > {conversation.UnreadCount}"); } conversation.UnreadCount -= diff; ctx.SaveChanges(); } } } return(conversation); }
public static void UpdateExpiresInLocked(SignalConversation thread, uint exp) { lock (DBLock) { using (var ctx = new SignalDBContext()) { if (!thread.ThreadId.EndsWith("=")) { var contact = ctx.Contacts .Where(c => c.ThreadId == thread.ThreadId) .SingleOrDefault(); if (contact != null) { contact.ExpiresInSeconds = exp; } } else { var group = ctx.Groups .Where(c => c.ThreadId == thread.ThreadId) .SingleOrDefault(); if (group != null) { group.ExpiresInSeconds = exp; } } ctx.SaveChanges(); } } }
public static SignalGroup GetOrCreateGroupLocked(string groupId, long timestamp) { SignalGroup dbgroup; lock (DBLock) { using (var ctx = new SignalDBContext()) { dbgroup = ctx.Groups .Where(g => g.ThreadId == groupId) .Include(g => g.GroupMemberships) .ThenInclude(gm => gm.Contact) .SingleOrDefault(); if (dbgroup == null) { dbgroup = new SignalGroup() { ThreadId = groupId, ThreadDisplayName = "Unknown group", LastActiveTimestamp = timestamp, AvatarFile = null, UnreadCount = 0, CanReceive = false, GroupMemberships = new List <GroupMembership>() }; ctx.Add(dbgroup); ctx.SaveChanges(); } } } return(dbgroup); }
public static void UpdateMessageStatus(SignalMessage outgoingSignalMessage, MainPageViewModel mpvm) { SignalMessage m; lock (DBLock) { using (var ctx = new SignalDBContext()) { m = ctx.Messages.Single(t => t.ComposedTimestamp == outgoingSignalMessage.ComposedTimestamp && t.Author == null); if (m != null) { if (outgoingSignalMessage.Status == SignalMessageStatus.Confirmed) { if (m.Receipts > 0) { m.Status = SignalMessageStatus.Received; } else { m.Status = SignalMessageStatus.Confirmed; } } else { m.Status = outgoingSignalMessage.Status; } ctx.SaveChanges(); } } } Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.UIUpdateMessageBox(m); }).AsTask().Wait(); }
public static SignalMessage IncreaseReceiptCountLocked(SignalServiceEnvelope envelope) { SignalMessage m; bool set_mark = false; lock (DBLock) { using (var ctx = new SignalDBContext()) { m = ctx.Messages.SingleOrDefault(t => t.ComposedTimestamp == envelope.GetTimestamp()); if (m != null) { m.Receipts++; if (m.Status == SignalMessageStatus.Confirmed) { m.Status = SignalMessageStatus.Received; set_mark = true; } } else { ctx.EarlyReceipts.Add(new SignalEarlyReceipt() { DeviceId = (uint)envelope.GetSourceDevice(), Timestamp = envelope.GetTimestamp(), Username = envelope.GetSourceE164() }); } ctx.SaveChanges(); } } return(set_mark ? m : null); }
public static SignalContact GetOrCreateContactLocked(string username, long timestamp) { SignalContact contact; lock (DBLock) { using (var ctx = new SignalDBContext()) { contact = ctx.Contacts .Where(c => c.ThreadId == username) .SingleOrDefault(); if (contact == null) { contact = new SignalContact() { ThreadId = username, ThreadDisplayName = username, CanReceive = true, LastActiveTimestamp = timestamp, Color = null //Utils.CalculateDefaultColor(username) }; ctx.Contacts.Add(contact); ctx.SaveChanges(); } } } return(contact); }
public static void DeleteMessage(SignalMessage message) { lock (DBLock) { using (var ctx = new SignalDBContext()) { ctx.Remove(message); SignalConversation conversation = ctx.Contacts .Where(c => c.ThreadId == message.ThreadId) .Single(); conversation.MessagesCount -= 1; conversation.LastMessage = null; conversation.LastMessageId = null; conversation.LastSeenMessage = null; conversation.LastSeenMessageIndex = ctx.Messages .Where(m => m.ThreadId == conversation.ThreadId) .Count() - 1; // also delete fts message SignalMessageContent ftsMessage = ctx.Messages_fts.Where(m => m == message.Content) .Single(); ctx.Remove(ftsMessage); ctx.SaveChanges(); } } }
public static SignalMessage UpdateMessageStatus(SignalMessage outgoingSignalMessage) { SignalMessage m; lock (DBLock) { using (var ctx = new SignalDBContext()) { m = ctx.Messages.Single(t => t.ComposedTimestamp == outgoingSignalMessage.ComposedTimestamp && t.Author == null); if (m != null) { if (outgoingSignalMessage.Status == SignalMessageStatus.Confirmed) { if (m.Receipts > 0) { m.Status = SignalMessageStatus.Received; } else { m.Status = SignalMessageStatus.Confirmed; } } else { m.Status = outgoingSignalMessage.Status; } ctx.SaveChanges(); } return(m); } } }
private static LinkedList <SignalMessage> InsertIdentityChangedMessages(string number) { long now = Util.CurrentTimeMillis(); LinkedList <SignalMessage> messages = new LinkedList <SignalMessage>(); using (var ctx = new SignalDBContext()) { SignalContact contact = SignalDBContext.GetSignalContactByThreadId(ctx, number); if (contact != null) { string str = $"Your safety numbers with {contact.ThreadDisplayName} have changed."; SignalMessage msg = new SignalMessage() { Author = contact, ComposedTimestamp = now, ReceivedTimestamp = now, Direction = SignalMessageDirection.Incoming, Type = SignalMessageType.IdentityKeyChange, ThreadId = contact.ThreadId, ThreadGuid = contact.ThreadGuid, Content = new SignalMessageContent() { Content = str } }; contact.LastMessage = msg; contact.MessagesCount += 1; contact.UnreadCount += 1; ctx.Messages.Add(msg); messages.AddLast(msg); var groups = ctx.GroupMemberships .Where(gm => gm.ContactId == contact.Id) .Include(gm => gm.Group); foreach (var gm in groups) { msg = new SignalMessage() { Author = contact, ComposedTimestamp = now, ReceivedTimestamp = now, Direction = SignalMessageDirection.Incoming, Type = SignalMessageType.IdentityKeyChange, ThreadId = gm.Group.ThreadId, ThreadGuid = gm.Group.ThreadGuid, Content = new SignalMessageContent() { Content = str } }; gm.Group.LastMessage = msg; gm.Group.MessagesCount += 1; gm.Group.UnreadCount += 1; ctx.Messages.Add(msg); messages.AddLast(msg); } } ctx.SaveChanges(); } return(messages); }
public static SignalGroup InsertOrUpdateGroupLocked(string groupId, string displayname, string avatarfile, bool canReceive, long timestamp, MainPageViewModel mpvm) { SignalGroup dbgroup; bool is_new = false; lock (DBLock) { using (var ctx = new SignalDBContext()) { dbgroup = ctx.Groups .Where(g => g.ThreadId == groupId) .Include(g => g.GroupMemberships) .ThenInclude(gm => gm.Contact) .SingleOrDefault(); if (dbgroup == null) { is_new = true; dbgroup = new SignalGroup() { ThreadId = groupId, ThreadDisplayName = displayname, LastActiveTimestamp = timestamp, AvatarFile = avatarfile, UnreadCount = 0, CanReceive = canReceive, GroupMemberships = new List <GroupMembership>() }; ctx.Add(dbgroup); } else { dbgroup.ThreadDisplayName = displayname; dbgroup.LastActiveTimestamp = timestamp; dbgroup.AvatarFile = avatarfile; dbgroup.CanReceive = true; } ctx.SaveChanges(); } if (is_new) { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.AddThread(dbgroup); }).AsTask().Wait(); } else { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.UIUpdateThread(dbgroup); }).AsTask().Wait(); } } return(dbgroup); }
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 static void SaveMessageLocked(SignalMessage message) { lock (DBLock) { using (var ctx = new SignalDBContext()) { SaveMessage(ctx, message); ctx.SaveChanges(); } } }
public static void UpdateMessageExpiresAt(SignalMessage message) { lock (DBLock) { using (var ctx = new SignalDBContext()) { var m = ctx.Messages.Single(t => t.Id == message.Id); m.ExpiresAt = message.ExpiresAt; ctx.SaveChanges(); } } }
public static void FailAllPendingMessages() { lock (DBLock) { using (var ctx = new SignalDBContext()) { var messages = ctx.Messages .Where(m => m.Direction == SignalMessageDirection.Outgoing && m.Status == SignalMessageStatus.Pending).ToList(); messages.ForEach(m => m.Status = SignalMessageStatus.Failed_Unknown); ctx.SaveChanges(); } } }
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 static void UpdateExpiresInLocked(SignalConversation thread) { lock (DBLock) { using (var ctx = new SignalDBContext()) { var dbConversation = GetSignalConversationByThreadId(ctx, thread.ThreadId); if (dbConversation != null) { dbConversation.ExpiresInSeconds = thread.ExpiresInSeconds; ctx.SaveChanges(); } } } }
public static void InsertOrUpdateConversationLocked(SignalConversation conversation) { lock (DBLock) { using (var ctx = new SignalDBContext()) { if (conversation is SignalContact contact) { var c = ctx.Contacts.SingleOrDefault(b => b.ThreadId == conversation.ThreadId); if (c == null) { ctx.Contacts.Add(contact); } else { c.Color = contact.Color; c.ThreadId = conversation.ThreadId; c.ThreadDisplayName = conversation.ThreadDisplayName; c.CanReceive = conversation.CanReceive; c.AvatarFile = conversation.AvatarFile; c.Draft = conversation.Draft; c.UnreadCount = conversation.UnreadCount; } } else if (conversation is SignalGroup group) { var c = ctx.Groups.SingleOrDefault(b => b.ThreadId == conversation.ThreadId); if (c == null) { ctx.Groups.Add(group); } else { c.ThreadId = conversation.ThreadId; c.ThreadDisplayName = conversation.ThreadDisplayName; c.CanReceive = conversation.CanReceive; c.AvatarFile = conversation.AvatarFile; c.Draft = conversation.Draft; c.UnreadCount = conversation.UnreadCount; } } ctx.SaveChanges(); } } }
public static void InsertOrUpdateGroupMembershipLocked(long groupid, long memberid) { lock (DBLock) { using (var ctx = new SignalDBContext()) { var old = ctx.GroupMemberships.Where(g => g.GroupId == groupid && g.ContactId == memberid).SingleOrDefault(); if (old == null) { ctx.GroupMemberships.Add(new GroupMembership() { ContactId = memberid, GroupId = groupid }); ctx.SaveChanges(); } } } }
public static void InsertOrUpdateContactLocked(SignalContact contact, MainPageViewModel mpvm) { bool is_new = false; lock (DBLock) { using (var ctx = new SignalDBContext()) { var c = ctx.Contacts.SingleOrDefault(b => b.ThreadId == contact.ThreadId); if (c == null) { is_new = true; ctx.Contacts.Add(contact); } else { c.Color = contact.Color; c.ThreadId = contact.ThreadId; c.ThreadDisplayName = contact.ThreadDisplayName; c.CanReceive = contact.CanReceive; c.AvatarFile = contact.AvatarFile; c.Draft = contact.Draft; c.UnreadCount = contact.UnreadCount; } ctx.SaveChanges(); } if (is_new) { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.AddThread(contact); }).AsTask().Wait(); } else { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.UIUpdateThread(contact); }).AsTask().Wait(); } } }
public static SignalGroup InsertOrUpdateGroupLocked(string groupId, string displayname, string avatarfile, bool canReceive, long timestamp) { SignalGroup dbgroup; lock (DBLock) { using (var ctx = new SignalDBContext()) { dbgroup = ctx.Groups .Where(g => g.ThreadId == groupId) .Include(g => g.GroupMemberships) .ThenInclude(gm => gm.Contact) .SingleOrDefault(); if (dbgroup == null) { dbgroup = new SignalGroup() { ThreadId = groupId, ThreadDisplayName = displayname, LastActiveTimestamp = timestamp, AvatarFile = avatarfile, UnreadCount = 0, CanReceive = canReceive, GroupMemberships = new List <GroupMembership>() }; ctx.Add(dbgroup); } else { dbgroup.ThreadDisplayName = displayname; dbgroup.LastActiveTimestamp = timestamp; dbgroup.AvatarFile = avatarfile; dbgroup.CanReceive = true; } ctx.SaveChanges(); } } return(dbgroup); }
public static void IncreaseReceiptCountLocked(SignalServiceEnvelope envelope, MainPageViewModel mpvm) { SignalMessage m; bool set_mark = false; lock (DBLock) { using (var ctx = new SignalDBContext()) { m = ctx.Messages.SingleOrDefault(t => t.ComposedTimestamp == envelope.getTimestamp()); if (m != null) { m.Receipts++; if (m.Status == SignalMessageStatus.Confirmed) { m.Status = SignalMessageStatus.Received; set_mark = true; } } else { ctx.EarlyReceipts.Add(new SignalEarlyReceipt() { DeviceId = (uint)envelope.getSourceDevice(), Timestamp = envelope.getTimestamp(), Username = envelope.getSource() }); } ctx.SaveChanges(); } } if (set_mark) { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.UIUpdateMessageBox(m); }).AsTask().Wait(); } }
public static SignalContact GetOrCreateContactLocked(string username, long timestamp, MainPageViewModel mpvm) { SignalContact contact; bool is_new = false; lock (DBLock) { using (var ctx = new SignalDBContext()) { contact = ctx.Contacts .Where(c => c.ThreadId == username) .SingleOrDefault(); if (contact == null) { is_new = true; contact = new SignalContact() { ThreadId = username, ThreadDisplayName = username, CanReceive = true, LastActiveTimestamp = timestamp, Color = Utils.Colors[Utils.CalculateDefaultColorIndex(username)] }; ctx.Contacts.Add(contact); ctx.SaveChanges(); } } if (is_new) { Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { mpvm.AddThread(contact); }).AsTask().Wait(); } } return(contact); }
public static void SaveMessageLocked(SignalMessage message) { lock (DBLock) { using (var ctx = new SignalDBContext()) { long timestamp; if (message.Direction == SignalMessageDirection.Synced) { var receipts = ctx.EarlyReceipts .Where(er => er.Timestamp == message.ComposedTimestamp) .ToList(); message.Receipts = (uint)receipts.Count; ctx.EarlyReceipts.RemoveRange(receipts); if (message.Receipts > 0) { message.Status = SignalMessageStatus.Received; } } if (message.Author != null) { timestamp = message.ReceivedTimestamp; message.Author = ctx.Contacts.Where(a => a.Id == message.Author.Id).Single(); } else { timestamp = message.ComposedTimestamp; } if (!message.ThreadId.EndsWith("=")) { var contact = ctx.Contacts .Where(c => c.ThreadId == message.ThreadId) .Single(); contact.LastActiveTimestamp = timestamp; contact.LastMessage = message; contact.MessagesCount += 1; if (message.Author == null) { contact.UnreadCount = 0; contact.LastSeenMessageIndex = contact.MessagesCount; } else { contact.UnreadCount += 1; } } else { var group = ctx.Groups .Where(c => c.ThreadId == message.ThreadId) .Single(); message.ExpiresAt = group.ExpiresInSeconds; group.LastActiveTimestamp = timestamp; group.LastMessage = message; group.MessagesCount += 1; if (message.Author == null) { group.UnreadCount = 0; group.LastSeenMessageIndex = group.MessagesCount; } else { group.UnreadCount += 1; } } ctx.Messages.Add(message); ctx.SaveChanges(); } } }
public static LinkedList <SignalMessage> InsertIdentityChangedMessages(string number) { long now = Util.CurrentTimeMillis(); LinkedList <SignalMessage> messages = new LinkedList <SignalMessage>(); lock (DBLock) { using (var ctx = new SignalDBContext()) { SignalContact contact = ctx.Contacts .Where(c => c.ThreadId == number) .SingleOrDefault(); if (contact != null) { string str = $"Your safety numbers with {contact.ThreadDisplayName} have changed."; SignalMessage msg = new SignalMessage() { Author = contact, ComposedTimestamp = now, ReceivedTimestamp = now, Direction = SignalMessageDirection.Incoming, Type = SignalMessageType.IdentityKeyChange, ThreadId = contact.ThreadId, Content = new SignalMessageContent() { Content = str } }; contact.LastMessage = msg; contact.MessagesCount += 1; ctx.Messages.Add(msg); messages.AddLast(msg); var groups = ctx.GroupMemberships .Where(gm => gm.ContactId == contact.Id) .Include(gm => gm.Group); foreach (var gm in groups) { msg = new SignalMessage() { Author = contact, ComposedTimestamp = now, ReceivedTimestamp = now, Direction = SignalMessageDirection.Incoming, Type = SignalMessageType.IdentityKeyChange, ThreadId = gm.Group.ThreadId, Content = new SignalMessageContent() { Content = str } }; gm.Group.LastMessage = msg; gm.Group.MessagesCount += 1; ctx.Messages.Add(msg); messages.AddLast(msg); } } else { Debug.WriteLine("InsertIdentityChangedMessages for non-existing contact!"); } ctx.SaveChanges(); } } return(messages); }