diff --git a/libgm/gmproto/authentication.pb.go b/libgm/gmproto/authentication.pb.go index 50a688a..a5b8454 100644 --- a/libgm/gmproto/authentication.pb.go +++ b/libgm/gmproto/authentication.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: authentication.proto diff --git a/libgm/gmproto/client.pb.go b/libgm/gmproto/client.pb.go index 7849c05..b2bd6f4 100644 --- a/libgm/gmproto/client.pb.go +++ b/libgm/gmproto/client.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: client.proto @@ -2647,7 +2647,8 @@ type SendMessageResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Status SendMessageResponse_Status `protobuf:"varint,3,opt,name=status,proto3,enum=client.SendMessageResponse_Status" json:"status,omitempty"` + GoogleAccountSwitch *AccountChangeOrSomethingEvent `protobuf:"bytes,2,opt,name=googleAccountSwitch,proto3" json:"googleAccountSwitch,omitempty"` + Status SendMessageResponse_Status `protobuf:"varint,3,opt,name=status,proto3,enum=client.SendMessageResponse_Status" json:"status,omitempty"` } func (x *SendMessageResponse) Reset() { @@ -2682,6 +2683,13 @@ func (*SendMessageResponse) Descriptor() ([]byte, []int) { return file_client_proto_rawDescGZIP(), []int{41} } +func (x *SendMessageResponse) GetGoogleAccountSwitch() *AccountChangeOrSomethingEvent { + if x != nil { + return x.GoogleAccountSwitch + } + return nil +} + func (x *SendMessageResponse) GetStatus() SendMessageResponse_Status { if x != nil { return x.Status @@ -3289,7 +3297,8 @@ var file_client_proto_goTypes = []interface{}{ (*SIMPayload)(nil), // 67: settings.SIMPayload (*MessageInfo)(nil), // 68: conversations.MessageInfo (*MessageContent)(nil), // 69: conversations.MessageContent - (*ReactionData)(nil), // 70: conversations.ReactionData + (*AccountChangeOrSomethingEvent)(nil), // 70: events.AccountChangeOrSomethingEvent + (*ReactionData)(nil), // 71: conversations.ReactionData } var file_client_proto_depIdxs = []int32{ 58, // 0: client.ReceiveMessagesRequest.auth:type_name -> authentication.AuthMessage @@ -3329,19 +3338,20 @@ var file_client_proto_depIdxs = []int32{ 46, // 34: client.MessagePayload.messagePayloadContent:type_name -> client.MessagePayloadContent 68, // 35: client.MessagePayload.messageInfo:type_name -> conversations.MessageInfo 69, // 36: client.MessagePayloadContent.messageContent:type_name -> conversations.MessageContent - 4, // 37: client.SendMessageResponse.status:type_name -> client.SendMessageResponse.Status - 70, // 38: client.SendReactionRequest.reactionData:type_name -> conversations.ReactionData - 5, // 39: client.SendReactionRequest.action:type_name -> client.SendReactionRequest.Action - 67, // 40: client.SendReactionRequest.SIMPayload:type_name -> settings.SIMPayload - 57, // 41: client.TypingUpdateRequest.data:type_name -> client.TypingUpdateRequest.Data - 52, // 42: client.ReceiveMessagesRequest.UnknownEmptyObject2.unknown:type_name -> client.ReceiveMessagesRequest.UnknownEmptyObject1 - 60, // 43: client.AckMessageRequest.Message.device:type_name -> authentication.Device - 18, // 44: client.GetThumbnailResponse.Thumbnail.data:type_name -> client.ThumbnailData - 45, // [45:45] is the sub-list for method output_type - 45, // [45:45] is the sub-list for method input_type - 45, // [45:45] is the sub-list for extension type_name - 45, // [45:45] is the sub-list for extension extendee - 0, // [0:45] is the sub-list for field type_name + 70, // 37: client.SendMessageResponse.googleAccountSwitch:type_name -> events.AccountChangeOrSomethingEvent + 4, // 38: client.SendMessageResponse.status:type_name -> client.SendMessageResponse.Status + 71, // 39: client.SendReactionRequest.reactionData:type_name -> conversations.ReactionData + 5, // 40: client.SendReactionRequest.action:type_name -> client.SendReactionRequest.Action + 67, // 41: client.SendReactionRequest.SIMPayload:type_name -> settings.SIMPayload + 57, // 42: client.TypingUpdateRequest.data:type_name -> client.TypingUpdateRequest.Data + 52, // 43: client.ReceiveMessagesRequest.UnknownEmptyObject2.unknown:type_name -> client.ReceiveMessagesRequest.UnknownEmptyObject1 + 60, // 44: client.AckMessageRequest.Message.device:type_name -> authentication.Device + 18, // 45: client.GetThumbnailResponse.Thumbnail.data:type_name -> client.ThumbnailData + 46, // [46:46] is the sub-list for method output_type + 46, // [46:46] is the sub-list for method input_type + 46, // [46:46] is the sub-list for extension type_name + 46, // [46:46] is the sub-list for extension extendee + 0, // [0:46] is the sub-list for field type_name } func init() { file_client_proto_init() } @@ -3353,6 +3363,7 @@ func file_client_proto_init() { file_authentication_proto_init() file_settings_proto_init() file_util_proto_init() + file_events_proto_init() if !protoimpl.UnsafeEnabled { file_client_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyDittoActivityRequest); i { diff --git a/libgm/gmproto/client.pb.raw b/libgm/gmproto/client.pb.raw index eb5e3a5..01ccd24 100644 Binary files a/libgm/gmproto/client.pb.raw and b/libgm/gmproto/client.pb.raw differ diff --git a/libgm/gmproto/client.proto b/libgm/gmproto/client.proto index e12da56..86aba38 100644 --- a/libgm/gmproto/client.proto +++ b/libgm/gmproto/client.proto @@ -7,6 +7,7 @@ import "conversations.proto"; import "authentication.proto"; import "settings.proto"; import "util.proto"; +import "events.proto"; message NotifyDittoActivityRequest { // This is not actually a boolean: after logging out, field 2 has value 2, and field 3 has value 1. @@ -283,6 +284,7 @@ message SendMessageResponse { FAILURE_3 = 3; FAILURE_4 = 4; // not default sms app? } + events.AccountChangeOrSomethingEvent googleAccountSwitch = 2; Status status = 3; } diff --git a/libgm/gmproto/config.pb.go b/libgm/gmproto/config.pb.go index ad1af37..9b95b71 100644 --- a/libgm/gmproto/config.pb.go +++ b/libgm/gmproto/config.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: config.proto diff --git a/libgm/gmproto/conversations.pb.go b/libgm/gmproto/conversations.pb.go index 6bc266e..1a9f8a1 100644 --- a/libgm/gmproto/conversations.pb.go +++ b/libgm/gmproto/conversations.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: conversations.proto diff --git a/libgm/gmproto/events.pb.go b/libgm/gmproto/events.pb.go index 375db26..c5cd701 100644 --- a/libgm/gmproto/events.pb.go +++ b/libgm/gmproto/events.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: events.proto diff --git a/libgm/gmproto/pblite.pb.go b/libgm/gmproto/pblite.pb.go index 7d49b56..4e29c16 100644 --- a/libgm/gmproto/pblite.pb.go +++ b/libgm/gmproto/pblite.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: pblite.proto diff --git a/libgm/gmproto/rpc.pb.go b/libgm/gmproto/rpc.pb.go index af17c3e..cf1ca07 100644 --- a/libgm/gmproto/rpc.pb.go +++ b/libgm/gmproto/rpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: rpc.proto @@ -123,6 +123,7 @@ const ( ActionType_CREATE_GAIA_PAIRING_CLIENT_FINISHED ActionType = 45 ActionType_UNPAIR_GAIA_PAIRING ActionType = 46 ActionType_CANCEL_GAIA_PAIRING ActionType = 47 + ActionType_PREWARM ActionType = 48 ) // Enum value maps for ActionType. @@ -174,6 +175,7 @@ var ( 45: "CREATE_GAIA_PAIRING_CLIENT_FINISHED", 46: "UNPAIR_GAIA_PAIRING", 47: "CANCEL_GAIA_PAIRING", + 48: "PREWARM", } ActionType_value = map[string]int32{ "UNSPECIFIED": 0, @@ -222,6 +224,7 @@ var ( "CREATE_GAIA_PAIRING_CLIENT_FINISHED": 45, "UNPAIR_GAIA_PAIRING": 46, "CANCEL_GAIA_PAIRING": 47, + "PREWARM": 48, } ) diff --git a/libgm/gmproto/rpc.pb.raw b/libgm/gmproto/rpc.pb.raw index 2a1ef3a..ff7ea85 100644 Binary files a/libgm/gmproto/rpc.pb.raw and b/libgm/gmproto/rpc.pb.raw differ diff --git a/libgm/gmproto/rpc.proto b/libgm/gmproto/rpc.proto index 6abec8f..600845b 100644 --- a/libgm/gmproto/rpc.proto +++ b/libgm/gmproto/rpc.proto @@ -161,6 +161,7 @@ enum ActionType { CREATE_GAIA_PAIRING_CLIENT_FINISHED = 45; UNPAIR_GAIA_PAIRING = 46; CANCEL_GAIA_PAIRING = 47; + PREWARM = 48; } enum MessageType { diff --git a/libgm/gmproto/settings.pb.go b/libgm/gmproto/settings.pb.go index 7a210d6..2e40c37 100644 --- a/libgm/gmproto/settings.pb.go +++ b/libgm/gmproto/settings.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: settings.proto diff --git a/libgm/gmproto/ukey.pb.go b/libgm/gmproto/ukey.pb.go index 5f07c62..eb463b1 100644 --- a/libgm/gmproto/ukey.pb.go +++ b/libgm/gmproto/ukey.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: ukey.proto diff --git a/libgm/gmproto/util.pb.go b/libgm/gmproto/util.pb.go index d0b1c81..52c2de4 100644 --- a/libgm/gmproto/util.pb.go +++ b/libgm/gmproto/util.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: util.proto diff --git a/messagetracking.go b/messagetracking.go index 44fb219..065ee78 100644 --- a/messagetracking.go +++ b/messagetracking.go @@ -86,6 +86,7 @@ func (ose OutgoingStatusError) Is(other error) bool { func errorToStatusReason(err error) (reason event.MessageStatusReason, status event.MessageStatus, isCertain, sendNotice bool, humanMessage string) { var ose OutgoingStatusError + var rse *responseStatusError switch { case errors.Is(err, errUnexpectedParsedContentType), errors.Is(err, errUnknownMsgType): @@ -104,6 +105,8 @@ func errorToStatusReason(err error) (reason event.MessageStatusReason, status ev return event.MessageStatusTooOld, event.MessageStatusRetriable, false, true, "sending the message is taking long; is your phone online?" case errors.Is(err, errTargetNotFound): return event.MessageStatusGenericError, event.MessageStatusFail, true, false, "" + case errors.As(err, &rse): + return event.MessageStatusNetworkError, event.MessageStatusRetriable, true, true, rse.Error() case errors.As(err, &ose): return event.MessageStatusNetworkError, event.MessageStatusFail, true, true, ose.HumanError() default: diff --git a/portal.go b/portal.go index 0dc0258..4873c5d 100644 --- a/portal.go +++ b/portal.go @@ -2049,6 +2049,24 @@ func (portal *Portal) reuploadMedia(ctx context.Context, sender *User, content * return resp, nil } +type responseStatusError gmproto.SendMessageResponse + +func (rse *responseStatusError) Error() string { + switch rse.Status { + case 0: + if rse.GoogleAccountSwitch != nil && strings.ContainsRune(rse.GoogleAccountSwitch.GetAccount(), '@') { + return "Switch back to QR pairing or log in with Google account to send messages" + } + case gmproto.SendMessageResponse_FAILURE_2: + return "Unknown permanent error" + case gmproto.SendMessageResponse_FAILURE_3: + return "Unknown temporary error" + case gmproto.SendMessageResponse_FAILURE_4: + return "Google Messages is not your default SMS app" + } + return fmt.Sprintf("Unrecognized response status %d", rse.Status) +} + func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timings messageTimings) { ms := metricSender{portal: portal, timings: &timings} @@ -2093,7 +2111,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing } else if resp.Status != gmproto.SendMessageResponse_SUCCESS { outgoingMsg.Errored = true outgoingMsg.Acked = true - go ms.sendMessageMetrics(ctx, sender, evt, fmt.Errorf("response status %d", resp.Status), "Error sending", true) + go ms.sendMessageMetrics(ctx, sender, evt, (*responseStatusError)(resp), "Error sending", true) } else { outgoingMsg.Acked = true go ms.sendMessageMetrics(ctx, sender, evt, nil, "", true)