private SignalServiceDataMessage createSignalServiceMessage(SignalServiceEnvelope envelope, DataMessage content)
        {
            SignalServiceGroup             groupInfo   = createGroupInfo(envelope, content);
            List <SignalServiceAttachment> attachments = new List <SignalServiceAttachment>();
            bool endSession       = ((content.Flags & (uint)DataMessage.Types.Flags.EndSession) != 0);
            bool expirationUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ExpirationTimerUpdate) != 0);

            foreach (AttachmentPointer pointer in content.Attachments)
            {
                attachments.Add(new SignalServiceAttachmentPointer(pointer.Id,
                                                                   pointer.ContentType,
                                                                   pointer.Key.ToByteArray(),
                                                                   envelope.getRelay(),
                                                                   pointer.SizeOneofCase == AttachmentPointer.SizeOneofOneofCase.Size ? pointer.Size : 0,
                                                                   pointer.ThumbnailOneofCase == AttachmentPointer.ThumbnailOneofOneofCase.Thumbnail ? pointer.Thumbnail.ToByteArray() : null,
                                                                   pointer.DigestOneofCase == AttachmentPointer.DigestOneofOneofCase.Digest ? pointer.Digest.ToByteArray() : null,
                                                                   pointer.FileNameOneofCase == AttachmentPointer.FileNameOneofOneofCase.FileName ? pointer.FileName : null,
                                                                   pointer.FlagsOneofCase == AttachmentPointer.FlagsOneofOneofCase.Flags && (pointer.Flags & (uint)AttachmentPointer.Types.Flags.VoiceMessage) != 0));
            }

            return(new SignalServiceDataMessage()
            {
                Timestamp = envelope.getTimestamp(),
                Group = groupInfo,
                Attachments = attachments,
                Body = content.Body,
                EndSession = endSession,
                ExpiresInSeconds = (int)content.ExpireTimer,
                ExpirationUpdate = expirationUpdate
            });
        }
Example #2
0
        private SignalServiceDataMessage CreateSignalServiceMessage(SignalServiceEnvelope envelope, DataMessage content)
        {
            SignalServiceGroup             groupInfo   = CreateGroupInfo(envelope, content);
            List <SignalServiceAttachment> attachments = new List <SignalServiceAttachment>();
            bool endSession       = ((content.Flags & (uint)DataMessage.Types.Flags.EndSession) != 0);
            bool expirationUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ExpirationTimerUpdate) != 0);
            bool profileKeyUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ProfileKeyUpdate) != 0);

            SignalServiceDataMessage.SignalServiceQuote quote = CreateQuote(envelope, content);

            foreach (AttachmentPointer pointer in content.Attachments)
            {
                attachments.Add(CreateAttachmentPointer(envelope.GetRelay(), pointer));
            }

            if (content.TimestampOneofCase == DataMessage.TimestampOneofOneofCase.Timestamp && (long)content.Timestamp != envelope.GetTimestamp())
            {
                throw new InvalidMessageException("Timestamps don't match: " + content.Timestamp + " vs " + envelope.GetTimestamp());
            }

            return(new SignalServiceDataMessage()
            {
                Timestamp = envelope.GetTimestamp(),
                Group = groupInfo,
                Attachments = attachments,
                Body = content.Body,
                EndSession = endSession,
                ExpiresInSeconds = (int)content.ExpireTimer,
                ExpirationUpdate = expirationUpdate,
                ProfileKey = content.ProfileKeyOneofCase == DataMessage.ProfileKeyOneofOneofCase.ProfileKey ? content.ProfileKey.ToByteArray() : null,
                ProfileKeyUpdate = profileKeyUpdate,
                Quote = quote
            });
        }
Example #3
0
        private GroupContext createGroupContent(SignalServiceGroup group)
        {
            GroupContext groupContext = new GroupContext {
            };

            groupContext.Id = ByteString.CopyFrom(group.GroupId);

            if (group.Type != SignalServiceGroup.GroupType.DELIVER)
            {
                if (group.Type == SignalServiceGroup.GroupType.UPDATE)
                {
                    groupContext.Type = GroupContext.Types.Type.Update;
                }
                else if (group.Type == SignalServiceGroup.GroupType.QUIT)
                {
                    groupContext.Type = GroupContext.Types.Type.Quit;
                }
                else if (group.Type == SignalServiceGroup.GroupType.REQUEST_INFO)
                {
                    groupContext.Type = GroupContext.Types.Type.RequestInfo;
                }
                else
                {
                    throw new Exception("Unknown type: " + group.Type);
                }

                if (group.Name != null)
                {
                    groupContext.Name = group.Name;
                }
                if (group.Members != null)
                {
                    groupContext.Members.AddRange(group.Members);
                }

                if (group.Avatar != null && group.Avatar.isStream())
                {
                    AttachmentPointer pointer = createAttachmentPointer(group.Avatar.asStream());
                    groupContext.Avatar = pointer;
                }
            }
            else
            {
                groupContext.Type = GroupContext.Types.Type.Deliver;
            }

            return(groupContext);
        }
Example #4
0
        private async Task <GroupContext> createGroupContent(SignalServiceGroup group)
        {
            GroupContext.Builder builder = GroupContext.CreateBuilder();
            builder.SetId(ByteString.CopyFrom(group.getGroupId()));

            if (group.getType() != SignalServiceGroup.Type.DELIVER)
            {
                if (group.getType() == SignalServiceGroup.Type.UPDATE)
                {
                    builder.SetType(GroupContext.Types.Type.UPDATE);
                }
                else if (group.getType() == SignalServiceGroup.Type.QUIT)
                {
                    builder.SetType(GroupContext.Types.Type.QUIT);
                }
                else if (group.getType() == SignalServiceGroup.Type.REQUEST_INFO)
                {
                    builder.SetType(GroupContext.Types.Type.REQUEST_INFO);
                }
                else
                {
                    throw new Exception("Unknown type: " + group.getType());
                }

                if (group.getName().HasValue)
                {
                    builder.SetName(group.getName().ForceGetValue());
                }
                if (group.getMembers().HasValue)
                {
                    builder.AddRangeMembers(group.getMembers().ForceGetValue());
                }

                if (group.getAvatar().HasValue&& group.getAvatar().ForceGetValue().isStream())
                {
                    AttachmentPointer pointer = await createAttachmentPointer(group.getAvatar().ForceGetValue().asStream());

                    builder.SetAvatar(pointer);
                }
            }
            else
            {
                builder.SetType(GroupContext.Types.Type.DELIVER);
            }

            return(builder.Build());
        }
Example #5
0
        private SignalServiceDataMessage createSignalServiceMessage(SignalServiceEnvelope envelope, DataMessage content)
        {
            SignalServiceGroup             groupInfo   = createGroupInfo(envelope, content);
            List <SignalServiceAttachment> attachments = new List <SignalServiceAttachment>();
            bool endSession       = ((content.Flags & (uint)DataMessage.Types.Flags.END_SESSION) != 0);
            bool expirationUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.EXPIRATION_TIMER_UPDATE) != 0);

            foreach (AttachmentPointer pointer in content.AttachmentsList)
            {
                attachments.Add(new SignalServiceAttachmentPointer(pointer.Id,
                                                                   pointer.ContentType,
                                                                   pointer.Key.ToByteArray(),
                                                                   envelope.getRelay(),
                                                                   pointer.HasSize ? new May <uint>(pointer.Size) : May <uint> .NoValue,
                                                                   pointer.HasThumbnail ? new May <byte[]>(pointer.Thumbnail.ToByteArray()) : May <byte[]> .NoValue));
            }

            return(new SignalServiceDataMessage(envelope.getTimestamp(), groupInfo, attachments,
                                                content.Body, endSession, (int)content.ExpireTimer, expirationUpdate));
        }
Example #6
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();
        }
Example #7
0
        private void HandleGroupUpdateMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            if (dataMessage.Group != null) //TODO check signal droid: group messages have different types!
            {
                SignalServiceGroup group       = dataMessage.Group;
                string             groupid     = Base64.encodeBytes(group.GroupId);
                SignalGroup        g           = new SignalGroup();
                string             displayname = "Unknown group";
                string             avatarfile  = null;
                if (group.Name != null)
                {
                    displayname = group.Name;
                }
                var dbgroup = SignalDBContext.InsertOrUpdateGroupLocked(groupid, displayname, avatarfile, true, timestamp, this);
                if (group.Members != null)
                {
                    foreach (var member in group.Members)
                    {
                        SignalDBContext.InsertOrUpdateGroupMembershipLocked(dbgroup.Id, SignalDBContext.GetOrCreateContactLocked(member, 0, this).Id);
                    }
                }

                /* insert message into conversation */
                SignalMessageDirection type;
                SignalContact          author;
                SignalMessageStatus    status;
                string prefix;
                long   composedTimestamp;

                if (isSync)
                {
                    var sent = content.SynchronizeMessage.getSent().ForceGetValue();
                    type              = SignalMessageDirection.Synced;
                    status            = SignalMessageStatus.Confirmed;
                    composedTimestamp = sent.getTimestamp();
                    author            = null;
                    prefix            = "You have";
                }
                else
                {
                    status            = 0;
                    type              = SignalMessageDirection.Incoming;
                    author            = SignalDBContext.GetOrCreateContactLocked(envelope.getSource(), timestamp, this);
                    prefix            = $"{author.ThreadDisplayName} has";
                    composedTimestamp = envelope.getTimestamp();
                }

                SignalMessage sm = new SignalMessage()
                {
                    Direction = type,
                    Type      = SignalMessageType.GroupUpdate,
                    Status    = status,
                    Author    = author,
                    Content   = new SignalMessageContent()
                    {
                        Content = $"{prefix} updated the group."
                    },
                    ThreadId          = groupid,
                    DeviceId          = (uint)envelope.getSourceDevice(),
                    Receipts          = 0,
                    ComposedTimestamp = composedTimestamp,
                    ReceivedTimestamp = timestamp,
                };
                Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async() =>
                {
                    await UIHandleIncomingMessage(sm);
                }).AsTask().Wait();
            }
            else
            {
                Debug.WriteLine("received group update without group info!");
            }
        }
Example #8
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);
        }
Example #9
0
        private async Task HandleGroupUpdateMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            if (dataMessage.Group != null) //TODO check signal droid: group messages have different types!
            {
                SignalServiceGroup group       = dataMessage.Group;
                string             groupid     = Base64.EncodeBytes(group.GroupId);
                SignalGroup        g           = new SignalGroup();
                string             displayname = "Unknown group";
                string             avatarfile  = null;
                if (group.Name != null)
                {
                    displayname = group.Name;
                }
                var dbgroup = SignalDBContext.InsertOrUpdateGroupLocked(groupid, displayname, avatarfile, true, timestamp);
                if (group.Members != null)
                {
                    foreach (var member in group.Members)
                    {
                        SignalDBContext.InsertOrUpdateGroupMembershipLocked(dbgroup.Id, (await SignalDBContext.GetOrCreateContactLocked(member, 0)).Id);
                    }
                }

                /* insert message into conversation */
                SignalMessageDirection type;
                SignalContact          author;
                SignalMessageStatus    status;
                string prefix;
                long   composedTimestamp;

                if (isSync)
                {
                    var sent = content.SynchronizeMessage.Sent;
                    type              = SignalMessageDirection.Synced;
                    status            = SignalMessageStatus.Confirmed;
                    composedTimestamp = sent.Timestamp;
                    author            = null;
                    prefix            = "You have";
                }
                else
                {
                    status = 0;
                    type   = SignalMessageDirection.Incoming;
                    author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp);

                    prefix            = $"{author.ThreadDisplayName} has";
                    composedTimestamp = envelope.GetTimestamp();
                }

                SignalMessage sm = new SignalMessage()
                {
                    Direction = type,
                    Type      = SignalMessageType.GroupUpdate,
                    Status    = status,
                    Author    = author,
                    Content   = new SignalMessageContent()
                    {
                        Content = $"{prefix} updated the group."
                    },
                    ThreadId          = groupid,
                    DeviceId          = (uint)envelope.GetSourceDevice(),
                    Receipts          = 0,
                    ComposedTimestamp = composedTimestamp,
                    ReceivedTimestamp = timestamp,
                };
                SignalDBContext.SaveMessageLocked(sm);
                dbgroup.MessagesCount += 1;
                if (sm.Direction == SignalMessageDirection.Incoming)
                {
                    dbgroup.UnreadCount += 1;
                }
                else
                {
                    dbgroup.UnreadCount          = 0;
                    dbgroup.LastSeenMessageIndex = dbgroup.MessagesCount;
                }
                dbgroup.LastMessage = sm;
                await SignalLibHandle.Instance.DispatchAddOrUpdateConversation(dbgroup, sm);
            }
            else
            {
                Logger.LogError("HandleGroupUpdateMessage() received group update without group info");
            }
        }
Example #10
0
        private async Task HandleGroupLeaveMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            SignalServiceGroup sentGroup = dataMessage.Group;

            if (sentGroup != null)
            {
                string      groupid = Base64.EncodeBytes(sentGroup.GroupId);
                SignalGroup group   = await SignalDBContext.GetOrCreateGroupLocked(groupid, 0);

                if (isSync)
                {
                    SignalContact author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), 0);

                    SignalMessage sm = new SignalMessage()
                    {
                        Direction = SignalMessageDirection.Incoming,
                        Type      = SignalMessageType.GroupLeave,
                        Status    = SignalMessageStatus.Received,
                        Author    = author,
                        Content   = new SignalMessageContent()
                        {
                            Content = $"You have left the group."
                        },
                        ThreadId          = groupid,
                        DeviceId          = (uint)envelope.GetSourceDevice(),
                        Receipts          = 0,
                        ComposedTimestamp = envelope.GetTimestamp(),
                        ReceivedTimestamp = timestamp,
                    };
                    SignalConversation updatedConversation = SignalDBContext.RemoveMemberFromGroup(groupid, author, sm);
                    await SignalLibHandle.Instance.DispatchAddOrUpdateConversation(updatedConversation, sm);
                }
                else
                {
                    SignalContact author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), 0);

                    SignalMessage sm = new SignalMessage()
                    {
                        Direction = SignalMessageDirection.Incoming,
                        Type      = SignalMessageType.GroupLeave,
                        Status    = SignalMessageStatus.Received,
                        Author    = author,
                        Content   = new SignalMessageContent()
                        {
                            Content = $"{author.ThreadDisplayName} has left the group."
                        },
                        ThreadId          = groupid,
                        DeviceId          = (uint)envelope.GetSourceDevice(),
                        Receipts          = 0,
                        ComposedTimestamp = envelope.GetTimestamp(),
                        ReceivedTimestamp = timestamp,
                    };
                    SignalConversation updatedConversation = SignalDBContext.RemoveMemberFromGroup(groupid, author, sm);
                    await SignalLibHandle.Instance.DispatchAddOrUpdateConversation(updatedConversation, sm);
                }
            }
            else
            {
                Logger.LogError("HandleGroupLeaveMessage() received group update without group info");
            }
        }
Example #11
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);
        }