Skip to content

Commit 5433e74

Browse files
committed
Mock support for sharing contacts
1 parent db48599 commit 5433e74

File tree

8 files changed

+2957
-749
lines changed

8 files changed

+2957
-749
lines changed

.editorconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,8 @@ csharp_indent_case_contents = true
3535
csharp_indent_switch_labels = true
3636
csharp_indent_labels = flush_left
3737
csharp_space_around_binary_operators = ignore
38+
39+
[*.cs]
40+
41+
# CS1591: Fehledes XML-Kommentar für öffentlich sichtbaren Typ oder Element
42+
dotnet_diagnostic.CS1591.severity = silent

libsignal-service-dotnet/SignalServiceMessageSender.cs

Lines changed: 121 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using libsignalservice.crypto;
77
using libsignalservice.messages;
88
using libsignalservice.messages.multidevice;
9+
using libsignalservice.messages.shared;
910
using libsignalservice.push;
1011
using libsignalservice.push.exceptions;
1112
using libsignalservice.push.http;
@@ -19,6 +20,7 @@
1920
using System.Threading;
2021
using System.Threading.Tasks;
2122
using static libsignalservice.messages.SignalServiceDataMessage;
23+
using static libsignalservice.push.DataMessage.Types;
2224
using static libsignalservice.push.DataMessage.Types.Quote.Types;
2325
using static libsignalservice.push.SyncMessage.Types;
2426

@@ -305,7 +307,7 @@ private async Task<byte[]> CreateMessageContent(CancellationToken token, SignalS
305307
{
306308
var quote = new DataMessage.Types.Quote()
307309
{
308-
Id = (ulong) message.Quote.Id,
310+
Id = (ulong)message.Quote.Id,
309311
Author = message.Quote.Author.E164number,
310312
Text = message.Quote.Text
311313
};
@@ -329,7 +331,10 @@ private async Task<byte[]> CreateMessageContent(CancellationToken token, SignalS
329331
dataMessage.Quote = quote;
330332
}
331333

332-
dataMessage.Timestamp = (ulong) message.Timestamp;
334+
if (message.SharedContacts != null)
335+
dataMessage.Contact.AddRange(CreateSharedContactContent(message.SharedContacts));
336+
337+
dataMessage.Timestamp = (ulong)message.Timestamp;
333338

334339
content.DataMessage = dataMessage;
335340
return content.ToByteArray();
@@ -550,7 +555,7 @@ private async Task<GroupContext> CreateGroupContent(CancellationToken token, Sig
550555
else throw new Exception("Unknown type: " + group.Type);
551556

552557
if (group.Name != null) groupContext.Name = group.Name;
553-
if (group.Members != null ) groupContext.Members.AddRange(group.Members);
558+
if (group.Members != null) groupContext.Members.AddRange(group.Members);
554559

555560
if (group.Avatar != null && group.Avatar.IsStream())
556561
{
@@ -595,6 +600,115 @@ private async Task<SendMessageResponseList> SendMessage(CancellationToken token,
595600
return responseList;
596601
}
597602

603+
private List<Contact> CreateSharedContactContent(List<SharedContact> contacts)
604+
{
605+
List<Contact> results = new List<Contact>();
606+
607+
foreach (var contact in contacts)
608+
{
609+
//TODO
610+
/*
611+
DataMessage.Contact.Name.Builder nameBuilder = DataMessage.Contact.Name.newBuilder();
612+
613+
if (contact.getName().getFamily().isPresent()) nameBuilder.setFamilyName(contact.getName().getFamily().get());
614+
if (contact.getName().getGiven().isPresent()) nameBuilder.setGivenName(contact.getName().getGiven().get());
615+
if (contact.getName().getMiddle().isPresent()) nameBuilder.setMiddleName(contact.getName().getMiddle().get());
616+
if (contact.getName().getPrefix().isPresent()) nameBuilder.setPrefix(contact.getName().getPrefix().get());
617+
if (contact.getName().getSuffix().isPresent()) nameBuilder.setSuffix(contact.getName().getSuffix().get());
618+
if (contact.getName().getDisplay().isPresent()) nameBuilder.setDisplayName(contact.getName().getDisplay().get());
619+
620+
DataMessage.Contact.Builder contactBuilder = DataMessage.Contact.newBuilder()
621+
.setName(nameBuilder);
622+
623+
if (contact.getAddress().isPresent())
624+
{
625+
for (SharedContact.PostalAddress address : contact.getAddress().get())
626+
{
627+
DataMessage.Contact.PostalAddress.Builder addressBuilder = DataMessage.Contact.PostalAddress.newBuilder();
628+
629+
switch (address.getType())
630+
{
631+
case HOME: addressBuilder.setType(DataMessage.Contact.PostalAddress.Type.HOME); break;
632+
case WORK: addressBuilder.setType(DataMessage.Contact.PostalAddress.Type.WORK); break;
633+
case CUSTOM: addressBuilder.setType(DataMessage.Contact.PostalAddress.Type.CUSTOM); break;
634+
default: throw new AssertionError("Unknown type: " + address.getType());
635+
}
636+
637+
if (address.getCity().isPresent()) addressBuilder.setCity(address.getCity().get());
638+
if (address.getCountry().isPresent()) addressBuilder.setCountry(address.getCountry().get());
639+
if (address.getLabel().isPresent()) addressBuilder.setLabel(address.getLabel().get());
640+
if (address.getNeighborhood().isPresent()) addressBuilder.setNeighborhood(address.getNeighborhood().get());
641+
if (address.getPobox().isPresent()) addressBuilder.setPobox(address.getPobox().get());
642+
if (address.getPostcode().isPresent()) addressBuilder.setPostcode(address.getPostcode().get());
643+
if (address.getRegion().isPresent()) addressBuilder.setRegion(address.getRegion().get());
644+
if (address.getStreet().isPresent()) addressBuilder.setStreet(address.getStreet().get());
645+
646+
contactBuilder.addAddress(addressBuilder);
647+
}
648+
}
649+
650+
if (contact.getEmail().isPresent())
651+
{
652+
for (SharedContact.Email email : contact.getEmail().get())
653+
{
654+
DataMessage.Contact.Email.Builder emailBuilder = DataMessage.Contact.Email.newBuilder()
655+
.setValue(email.getValue());
656+
657+
switch (email.getType())
658+
{
659+
case HOME: emailBuilder.setType(DataMessage.Contact.Email.Type.HOME); break;
660+
case WORK: emailBuilder.setType(DataMessage.Contact.Email.Type.WORK); break;
661+
case MOBILE: emailBuilder.setType(DataMessage.Contact.Email.Type.MOBILE); break;
662+
case CUSTOM: emailBuilder.setType(DataMessage.Contact.Email.Type.CUSTOM); break;
663+
default: throw new AssertionError("Unknown type: " + email.getType());
664+
}
665+
666+
if (email.getLabel().isPresent()) emailBuilder.setLabel(email.getLabel().get());
667+
668+
contactBuilder.addEmail(emailBuilder);
669+
}
670+
}
671+
672+
if (contact.getPhone().isPresent())
673+
{
674+
for (SharedContact.Phone phone : contact.getPhone().get())
675+
{
676+
DataMessage.Contact.Phone.Builder phoneBuilder = DataMessage.Contact.Phone.newBuilder()
677+
.setValue(phone.getValue());
678+
679+
switch (phone.getType())
680+
{
681+
case HOME: phoneBuilder.setType(DataMessage.Contact.Phone.Type.HOME); break;
682+
case WORK: phoneBuilder.setType(DataMessage.Contact.Phone.Type.WORK); break;
683+
case MOBILE: phoneBuilder.setType(DataMessage.Contact.Phone.Type.MOBILE); break;
684+
case CUSTOM: phoneBuilder.setType(DataMessage.Contact.Phone.Type.CUSTOM); break;
685+
default: throw new AssertionError("Unknown type: " + phone.getType());
686+
}
687+
688+
if (phone.getLabel().isPresent()) phoneBuilder.setLabel(phone.getLabel().get());
689+
690+
contactBuilder.addNumber(phoneBuilder);
691+
}
692+
}
693+
694+
if (contact.getAvatar().isPresent())
695+
{
696+
contactBuilder.setAvatar(DataMessage.Contact.Avatar.newBuilder()
697+
.setAvatar(createAttachmentPointer(contact.getAvatar().get().getAttachment().asStream()))
698+
.setIsProfile(contact.getAvatar().get().isProfile()));
699+
}
700+
701+
if (contact.getOrganization().isPresent())
702+
{
703+
contactBuilder.setOrganization(contact.getOrganization().get());
704+
}
705+
706+
results.add(contactBuilder.build());
707+
*/
708+
}
709+
return results;
710+
}
711+
598712
private async Task<SendMessageResponse> SendMessage(CancellationToken token, SignalServiceAddress recipient, long timestamp, byte[] content, bool silent)
599713
{
600714
for (int i = 0; i < 3; i++)
@@ -631,7 +745,7 @@ private async Task<SendMessageResponse> SendMessage(CancellationToken token, Sig
631745
throw new Exception("Failed to resolve conflicts after 3 attempts!");
632746
}
633747

634-
private async Task<IList<AttachmentPointer>> CreateAttachmentPointers(CancellationToken token, List<SignalServiceAttachment> attachments)
748+
private async Task<IList<AttachmentPointer>> CreateAttachmentPointers(CancellationToken token, List<SignalServiceAttachment>? attachments)
635749
{
636750
IList<AttachmentPointer> pointers = new List<AttachmentPointer>();
637751

@@ -691,7 +805,7 @@ private async Task<AttachmentPointer> CreateAttachmentPointer(CancellationToken
691805

692806
if (attachment.Width > 0)
693807
{
694-
attachmentPointer.Width = (uint) attachment.Width;
808+
attachmentPointer.Width = (uint)attachment.Width;
695809
}
696810

697811
if (attachment.Height > 0)
@@ -701,7 +815,7 @@ private async Task<AttachmentPointer> CreateAttachmentPointer(CancellationToken
701815

702816
if (attachment.VoiceNote)
703817
{
704-
attachmentPointer.Flags = (uint) AttachmentPointer.Types.Flags.VoiceMessage;
818+
attachmentPointer.Flags = (uint)AttachmentPointer.Types.Flags.VoiceMessage;
705819
}
706820

707821
return attachmentPointer;
@@ -824,7 +938,7 @@ private async Task<OutgoingPushMessage> GetEncryptedMessage(CancellationToken to
824938
{
825939
return cipher.Encrypt(signalProtocolAddress, plaintext, silent);
826940
}
827-
catch(libsignal.exceptions.UntrustedIdentityException e)
941+
catch (libsignal.exceptions.UntrustedIdentityException e)
828942
{
829943
throw new UntrustedIdentityException("Untrusted on send", e.getName(), e.getUntrustedIdentity());
830944
}

libsignal-service-dotnet/crypto/SignalServiceCipher.cs

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using libsignal_service_dotnet.messages.calls;
77
using libsignalservice.messages;
88
using libsignalservice.messages.multidevice;
9+
using libsignalservice.messages.shared;
910
using libsignalservice.push;
1011
using libsignalservice.util;
1112

@@ -146,6 +147,7 @@ private SignalServiceDataMessage CreateSignalServiceMessage(SignalServiceEnvelop
146147
bool expirationUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ExpirationTimerUpdate) != 0);
147148
bool profileKeyUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ProfileKeyUpdate) != 0);
148149
SignalServiceDataMessage.SignalServiceQuote quote = CreateQuote(envelope, content);
150+
List<SharedContact> sharedContacts = CreateSharedContacts(envelope, content);
149151

150152
foreach (AttachmentPointer pointer in content.Attachments)
151153
{
@@ -168,7 +170,8 @@ private SignalServiceDataMessage CreateSignalServiceMessage(SignalServiceEnvelop
168170
ExpirationUpdate = expirationUpdate,
169171
ProfileKey = content.ProfileKeyOneofCase == DataMessage.ProfileKeyOneofOneofCase.ProfileKey ? content.ProfileKey.ToByteArray() : null,
170172
ProfileKeyUpdate = profileKeyUpdate,
171-
Quote = quote
173+
Quote = quote,
174+
SharedContacts = sharedContacts
172175
};
173176
}
174177

@@ -380,6 +383,118 @@ private SignalServiceDataMessage.SignalServiceQuote CreateQuote(SignalServiceEnv
380383
attachments);
381384
}
382385

386+
private List<SharedContact>? CreateSharedContacts(SignalServiceEnvelope envelope, DataMessage content)
387+
{
388+
if (content.Contact.Count <= 0) return null;
389+
390+
var results = new List<SharedContact>();
391+
392+
foreach (var contact in content.Contact)
393+
{
394+
var name = new Name(contact.Name.DisplayNameOneofCase == Types.Contact.Types.Name.DisplayNameOneofOneofCase.DisplayName ? contact.Name.DisplayName : null,
395+
contact.Name.GivenNameOneofCase == Types.Contact.Types.Name.GivenNameOneofOneofCase.GivenName ? contact.Name.GivenName : null,
396+
contact.Name.FamilyNameOneofCase == Types.Contact.Types.Name.FamilyNameOneofOneofCase.FamilyName ? contact.Name.FamilyName : null,
397+
contact.Name.PrefixOneofCase == Types.Contact.Types.Name.PrefixOneofOneofCase.Prefix ? contact.Name.Prefix : null,
398+
contact.Name.SuffixOneofCase == Types.Contact.Types.Name.SuffixOneofOneofCase.Suffix ? contact.Name.DisplayName : null,
399+
contact.Name.MiddleNameOneofCase == Types.Contact.Types.Name.MiddleNameOneofOneofCase.MiddleName ? contact.Name.MiddleName : null);
400+
401+
Avatar? avatar = null;
402+
string? organization = null;
403+
if (contact.Address.Count > 0)
404+
{
405+
foreach (var address in contact.Address)
406+
{
407+
//TODO
408+
/*
409+
SharedContact.PostalAddress.Type type = SharedContact.PostalAddress.Type.HOME;
410+
411+
switch (address.getType())
412+
{
413+
case WORK: type = SharedContact.PostalAddress.Type.WORK; break;
414+
case HOME: type = SharedContact.PostalAddress.Type.HOME; break;
415+
case CUSTOM: type = SharedContact.PostalAddress.Type.CUSTOM; break;
416+
}
417+
418+
builder.withAddress(SharedContact.PostalAddress.newBuilder()
419+
.setCity(address.getCity())
420+
.setCountry(address.getCountry())
421+
.setLabel(address.getLabel())
422+
.setNeighborhood(address.getNeighborhood())
423+
.setPobox(address.getPobox())
424+
.setPostcode(address.getPostcode())
425+
.setRegion(address.getRegion())
426+
.setStreet(address.getStreet())
427+
.setType(type)
428+
.build());
429+
*/
430+
}
431+
}
432+
433+
if (contact.Number.Count > 0)
434+
{
435+
foreach (var phone in contact.Number)
436+
{
437+
//TODO
438+
/*
439+
SharedContact.Phone.Type type = SharedContact.Phone.Type.HOME;
440+
441+
switch (phone.getType())
442+
{
443+
case HOME: type = SharedContact.Phone.Type.HOME; break;
444+
case WORK: type = SharedContact.Phone.Type.WORK; break;
445+
case MOBILE: type = SharedContact.Phone.Type.MOBILE; break;
446+
case CUSTOM: type = SharedContact.Phone.Type.CUSTOM; break;
447+
}
448+
449+
builder.withPhone(SharedContact.Phone.newBuilder()
450+
.setLabel(phone.getLabel())
451+
.setType(type)
452+
.setValue(phone.getValue())
453+
.build());
454+
*/
455+
}
456+
}
457+
458+
if (contact.Email.Count > 0)
459+
{
460+
foreach (var email in contact.Email)
461+
{
462+
//TODO
463+
/*
464+
SharedContact.Email.Type type = SharedContact.Email.Type.HOME;
465+
466+
switch (email.getType())
467+
{
468+
case HOME: type = SharedContact.Email.Type.HOME; break;
469+
case WORK: type = SharedContact.Email.Type.WORK; break;
470+
case MOBILE: type = SharedContact.Email.Type.MOBILE; break;
471+
case CUSTOM: type = SharedContact.Email.Type.CUSTOM; break;
472+
}
473+
474+
builder.withEmail(SharedContact.Email.newBuilder()
475+
.setLabel(email.getLabel())
476+
.setType(type)
477+
.setValue(email.getValue())
478+
.build());
479+
*/
480+
}
481+
}
482+
483+
if (contact.AvatarOneofCase == Types.Contact.AvatarOneofOneofCase.Avatar)
484+
{
485+
avatar = new Avatar(CreateAttachmentPointer(envelope.GetRelay(), contact.Avatar.Avatar_), contact.Avatar.IsProfile);
486+
}
487+
488+
if (contact.OrganizationOneofCase == Types.Contact.OrganizationOneofOneofCase.Organization)
489+
{
490+
organization = contact.Organization;
491+
}
492+
493+
results.Add(new SharedContact(name, avatar, null, null, null, organization)); //TODO
494+
}
495+
return results;
496+
}
497+
383498
private SignalServiceAttachmentPointer CreateAttachmentPointer(string relay, AttachmentPointer pointer)
384499
{
385500
uint? size = null;

libsignal-service-dotnet/libsignal-service-dotnet.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
<RepositoryUrl>https://github.com/signal-csharp/libsignal-service-dotnet</RepositoryUrl>
1515
<PackageTags>libsignal libsignal-service libsignal-service-dotnet signal messenger</PackageTags>
1616
<IncludeSymbols>true</IncludeSymbols>
17-
<IncludeSource>true</IncludeSource>
17+
<IncludeSource>true</IncludeSource>
18+
<LangVersion>8.0</LangVersion>
19+
<Nullable>enable</Nullable>
1820
</PropertyGroup>
1921

2022
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

0 commit comments

Comments
 (0)