From c0c7ad7d0f800c5eaed2488c1de2dd272d02794a Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Thu, 20 Jun 2024 15:52:39 -0600 Subject: [PATCH] media: handle contact shares Signed-off-by: Sumner Evans --- pkg/connector/client.go | 17 +++++++----- pkg/connector/directdownload.go | 1 - pkg/connector/login.go | 3 ++- pkg/connector/msgconv/converter.go | 12 ++++++--- pkg/connector/msgconv/tomatrix.go | 43 ++++++++++++++++++++++++++---- pkg/connector/util/util.go | 10 +++++++ 6 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 pkg/connector/util/util.go diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 4b97bb44..18f3c1b5 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -19,6 +19,7 @@ import ( "go.mau.fi/mautrix-telegram/pkg/connector/ids" "go.mau.fi/mautrix-telegram/pkg/connector/msgconv" + "go.mau.fi/mautrix-telegram/pkg/connector/util" ) type TelegramClient struct { @@ -72,7 +73,7 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge Logger: zaplog, UpdateHandler: updatesManager, }) - client.msgConv = msgconv.NewMessageConverter(client.client, tc.useDirectMedia) + client.msgConv = msgconv.NewMessageConverter(client.client, tc.Bridge.Matrix, tc.useDirectMedia) client.clientCancel, err = connectTelegramClient(ctx, client.client) go func() { err = updatesManager.Run(ctx, client.client.API(), loginID, updates.AuthOptions{}) @@ -147,6 +148,12 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, e tg.Entities, panic("not from anyone") } + if media, ok := msg.GetMedia(); ok && media.TypeID() == tg.MessageMediaContactTypeID { + contact := media.(*tg.MessageMediaContact) + // TODO update the corresponding puppet + log.Info().Int64("user_id", contact.UserID).Msg("received contact") + } + t.main.Bridge.QueueRemoteEvent(t.userLogin, &bridgev2.SimpleRemoteEvent[*tg.Message]{ Type: bridgev2.RemoteEventMessage, LogContext: func(c zerolog.Context) zerolog.Context { @@ -181,10 +188,6 @@ func (t *TelegramClient) Disconnect() { t.clientCancel() } -func getFullName(user *tg.User) string { - return strings.TrimSpace(fmt.Sprintf("%s %s", user.FirstName, user.LastName)) -} - func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { fmt.Printf("%+v\n", portal) peerType, id, err := ids.ParsePortalID(portal.ID) @@ -207,7 +210,7 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta if user, ok := users[0].(*tg.User); !ok { return nil, fmt.Errorf("returned user is not *tg.User") } else { - name = getFullName(user) // TODO gate this behind a config? + name = util.FormatFullName(user.FirstName, user.LastName) // TODO gate this behind a config? members = []networkid.UserID{ids.MakeUserID(id), ids.MakeUserID(t.loginID)} isDM = true } @@ -264,7 +267,7 @@ func (t *TelegramClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) identifiers = append(identifiers, fmt.Sprintf("tel:+%s", strings.TrimPrefix(phone, "+"))) } - name := getFullName(user) + name := util.FormatFullName(user.FirstName, user.LastName) return &bridgev2.UserInfo{ IsBot: &user.Bot, Name: &name, diff --git a/pkg/connector/directdownload.go b/pkg/connector/directdownload.go index d2b15859..f118225f 100644 --- a/pkg/connector/directdownload.go +++ b/pkg/connector/directdownload.go @@ -95,7 +95,6 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med // TODO all of these // case *tg.MessageMediaGeo: // messageMediaGeo#56e0d474 - // case *tg.MessageMediaContact: // messageMediaContact#70322949 // case *tg.MessageMediaUnsupported: // messageMediaUnsupported#9f84f49e // case *tg.MessageMediaDocument: // messageMediaDocument#4cf4d72d // case *tg.MessageMediaVenue: // messageMediaVenue#2ec0533f diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 57171ff2..e2900526 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -32,6 +32,7 @@ import ( "maunium.net/go/mautrix/bridgev2/database" "go.mau.fi/mautrix-telegram/pkg/connector/ids" + "go.mau.fi/mautrix-telegram/pkg/connector/util" ) const LoginFlowIDPhone = "phone" @@ -217,7 +218,7 @@ func (p *PhoneLogin) handleAuthSuccess(ctx context.Context, authorization *tg.Au return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, StepID: completeStep, - Instructions: fmt.Sprintf("Successfully logged in as %d / +%s (%s)", user.ID, user.Phone, getFullName(user)), + Instructions: fmt.Sprintf("Successfully logged in as %d / +%s (%s)", user.ID, user.Phone, util.FormatFullName(user.FirstName, user.LastName)), CompleteParams: &bridgev2.LoginCompleteParams{ UserLoginID: ul.ID, }, diff --git a/pkg/connector/msgconv/converter.go b/pkg/connector/msgconv/converter.go index c9317cb4..b9b1313c 100644 --- a/pkg/connector/msgconv/converter.go +++ b/pkg/connector/msgconv/converter.go @@ -1,13 +1,17 @@ package msgconv -import "github.com/gotd/td/telegram" +import ( + "github.com/gotd/td/telegram" + "maunium.net/go/mautrix/bridgev2" +) type MessageConverter struct { - client *telegram.Client + client *telegram.Client + connector bridgev2.MatrixConnector useDirectMedia bool } -func NewMessageConverter(client *telegram.Client, useDirectMedia bool) *MessageConverter { - return &MessageConverter{client: client, useDirectMedia: useDirectMedia} +func NewMessageConverter(client *telegram.Client, connector bridgev2.MatrixConnector, useDirectMedia bool) *MessageConverter { + return &MessageConverter{client: client, connector: connector, useDirectMedia: useDirectMedia} } diff --git a/pkg/connector/msgconv/tomatrix.go b/pkg/connector/msgconv/tomatrix.go index 8b599867..d0680766 100644 --- a/pkg/connector/msgconv/tomatrix.go +++ b/pkg/connector/msgconv/tomatrix.go @@ -3,7 +3,9 @@ package msgconv import ( "context" "fmt" + "html" "slices" + "strings" "time" "github.com/gotd/td/tg" @@ -17,6 +19,7 @@ import ( "go.mau.fi/mautrix-telegram/pkg/connector/download" "go.mau.fi/mautrix-telegram/pkg/connector/ids" + "go.mau.fi/mautrix-telegram/pkg/connector/util" ) type spoilable interface { @@ -30,10 +33,7 @@ type ttlable interface { func mediaRequiringUpload(media tg.MessageMediaClass) bool { allowed := []uint32{ tg.MessageMediaPhotoTypeID, - tg.MessageMediaGeoTypeID, - tg.MessageMediaContactTypeID, tg.MessageMediaDocumentTypeID, - tg.MessageMediaStoryTypeID, } return slices.Contains(allowed, media.TypeID()) } @@ -77,6 +77,41 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, portal *bridgev2.Porta cm.Disappear = *disappearingSetting } cm.Parts = append(cm.Parts, mediaParts) + case media.TypeID() == tg.MessageMediaContactTypeID: + contact := media.(*tg.MessageMediaContact) + name := util.FormatFullName(contact.FirstName, contact.LastName) + formattedPhone := fmt.Sprintf("+%s", strings.TrimPrefix(contact.PhoneNumber, "+")) + + content := event.MessageEventContent{ + MsgType: event.MsgText, + Body: fmt.Sprintf("Shared contact info for %s: %s", name, formattedPhone), + } + if contact.UserID > 0 { + content.Format = event.FormatHTML + content.FormattedBody = fmt.Sprintf( + `Shared contact info for %s: %s`, + mc.connector.FormatGhostMXID(ids.MakeUserID(contact.UserID)), + html.EscapeString(name), + html.EscapeString(formattedPhone), + ) + } + + cm.Parts = append(cm.Parts, &bridgev2.ConvertedMessagePart{ + ID: networkid.PartID("contact"), + Type: event.EventMessage, + Content: &content, + Extra: map[string]any{ + "fi.mau.telegram.contact": map[string]any{ + "user_id": contact.UserID, + "first_name": contact.FirstName, + "last_name": contact.LastName, + "phone_number": contact.PhoneNumber, + "vcard": contact.Vcard, + }, + }, + }) + default: + return nil, fmt.Errorf("unsupported media type %T", media) } } return cm, nil @@ -168,7 +203,6 @@ func (mc *MessageConverter) convertMediaRequiringUpload(ctx context.Context, por // TODO all of these // case *tg.MessageMediaGeo: // messageMediaGeo#56e0d474 - // case *tg.MessageMediaContact: // messageMediaContact#70322949 // case *tg.MessageMediaUnsupported: // messageMediaUnsupported#9f84f49e // case *tg.MessageMediaVenue: // messageMediaVenue#2ec0533f // case *tg.MessageMediaGame: // messageMediaGame#fdb19008 @@ -230,7 +264,6 @@ func (mc *MessageConverter) convertMediaRequiringUpload(ctx context.Context, por // TODO all of these // case *tg.MessageMediaGeo: // messageMediaGeo#56e0d474 - // case *tg.MessageMediaContact: // messageMediaContact#70322949 // case *tg.MessageMediaUnsupported: // messageMediaUnsupported#9f84f49e // case *tg.MessageMediaVenue: // messageMediaVenue#2ec0533f // case *tg.MessageMediaGame: // messageMediaGame#fdb19008 diff --git a/pkg/connector/util/util.go b/pkg/connector/util/util.go new file mode 100644 index 00000000..d946119d --- /dev/null +++ b/pkg/connector/util/util.go @@ -0,0 +1,10 @@ +package util + +import ( + "fmt" + "strings" +) + +func FormatFullName(first, last string) string { + return strings.TrimSpace(fmt.Sprintf("%s %s", first, last)) +}