@@ -13,33 +13,65 @@ import (
1313// MessageRow is the output of `msg list`. Text is the message text when
1414// present; for media-only messages, Text is the caption (may be empty).
1515type MessageRow struct {
16- ID int `json:"id"`
17- Ref string `json:"ref,omitempty"`
18- Date string `json:"date"` // RFC3339
19- FromID int64 `json:"from_id,omitempty"`
20- FromRef string `json:"from_ref,omitempty"`
21- FromKind string `json:"from_kind,omitempty"`
22- FromTitle string `json:"from_title,omitempty"`
23- FromUsername string `json:"from_username,omitempty"`
24- ReplyToID int `json:"reply_to_id,omitempty"`
25- Text string `json:"text,omitempty"`
26- HasMedia bool `json:"has_media,omitempty"`
27- MediaKind string `json:"media_kind,omitempty"` // "photo" | "video" | "document" | "voice" | "audio" | "sticker" | "poll" | "web_page" | "other"
28- Views int `json:"views,omitempty"`
29- IsPinned bool `json:"is_pinned,omitempty"`
16+ ID int `json:"id"`
17+ Ref string `json:"ref,omitempty"`
18+ Date string `json:"date"` // RFC3339
19+ FromID int64 `json:"from_id,omitempty"`
20+ FromRef string `json:"from_ref,omitempty"`
21+ FromKind string `json:"from_kind,omitempty"`
22+ FromTitle string `json:"from_title,omitempty"`
23+ FromUsername string `json:"from_username,omitempty"`
24+ ReplyToID int `json:"reply_to_id,omitempty"`
25+ Text string `json:"text,omitempty"`
26+ Entities []MessageEntity `json:"entities,omitempty"`
27+ Buttons []MessageButton `json:"buttons,omitempty"`
28+ Forward * ForwardInfo `json:"forward,omitempty"`
29+ HasMedia bool `json:"has_media,omitempty"`
30+ MediaKind string `json:"media_kind,omitempty"` // "photo" | "video" | "document" | "voice" | "audio" | "sticker" | "poll" | "web_page" | "other"
31+ Views int `json:"views,omitempty"`
32+ IsPinned bool `json:"is_pinned,omitempty"`
33+ }
34+
35+ // MessageEntity is a flattened representation of a Telegram message entity.
36+ type MessageEntity struct {
37+ Type string `json:"type"`
38+ Text string `json:"text,omitempty"`
39+ URL string `json:"url,omitempty"`
40+ }
41+
42+ // MessageButton is a flattened representation of an inline-keyboard button.
43+ // Only buttons we know how to render to a URL are exposed.
44+ type MessageButton struct {
45+ Row int `json:"row"`
46+ Text string `json:"text,omitempty"`
47+ URL string `json:"url,omitempty"`
48+ Type string `json:"type,omitempty"` // "url" | "switch_inline" | "callback" | "web_app" | ...
49+ }
50+
51+ // ForwardInfo describes the origin of a forwarded message.
52+ type ForwardInfo struct {
53+ From * PeerObject `json:"from,omitempty"`
54+ FromName string `json:"from_name,omitempty"`
55+ Date string `json:"date,omitempty"` // RFC3339, original send time
56+ ChannelPostID int `json:"channel_post_id,omitempty"`
57+ PostAuthor string `json:"post_author,omitempty"`
58+ Link string `json:"link,omitempty"` // deep-link to original post when known
3059}
3160
3261func (r MessageRow ) MarshalJSON () ([]byte , error ) {
3362 type messageRowJSON struct {
34- Ref string `json:"ref,omitempty"`
35- ID int `json:"id,omitempty"`
36- Date string `json:"date,omitempty"`
37- From * PeerObject `json:"from,omitempty"`
38- Text string `json:"text,omitempty"`
39- Media * MediaObject `json:"media,omitempty"`
40- ReplyTo int `json:"reply_to,omitempty"`
41- Views int `json:"views,omitempty"`
42- IsPinned bool `json:"is_pinned,omitempty"`
63+ Ref string `json:"ref,omitempty"`
64+ ID int `json:"id,omitempty"`
65+ Date string `json:"date,omitempty"`
66+ From * PeerObject `json:"from,omitempty"`
67+ Text string `json:"text,omitempty"`
68+ Entities []MessageEntity `json:"entities,omitempty"`
69+ Buttons []MessageButton `json:"buttons,omitempty"`
70+ Forward * ForwardInfo `json:"forward,omitempty"`
71+ Media * MediaObject `json:"media,omitempty"`
72+ ReplyTo int `json:"reply_to,omitempty"`
73+ Views int `json:"views,omitempty"`
74+ IsPinned bool `json:"is_pinned,omitempty"`
4375 }
4476 var from * PeerObject
4577 if r .FromID != 0 || r .FromRef != "" || r .FromTitle != "" || r .FromUsername != "" || r .FromKind != "" {
@@ -56,6 +88,9 @@ func (r MessageRow) MarshalJSON() ([]byte, error) {
5688 Date : r .Date ,
5789 From : from ,
5890 Text : r .Text ,
91+ Entities : r .Entities ,
92+ Buttons : r .Buttons ,
93+ Forward : r .Forward ,
5994 Media : media ,
6095 ReplyTo : r .ReplyToID ,
6196 Views : r .Views ,
@@ -199,6 +234,13 @@ func messageHeader(r MessageRow) string {
199234 if r .ReplyToID > 0 {
200235 parts = append (parts , "reply " + strconv .Itoa (r .ReplyToID ))
201236 }
237+ if r .Forward != nil {
238+ if label := forwardLabel (r .Forward ); label != "" {
239+ parts = append (parts , "fwd " + label )
240+ } else {
241+ parts = append (parts , "fwd" )
242+ }
243+ }
202244 if r .Views > 0 {
203245 parts = append (parts , strconv .Itoa (r .Views )+ " views" )
204246 }
@@ -208,6 +250,24 @@ func messageHeader(r MessageRow) string {
208250 return strings .Join (parts , " · " )
209251}
210252
253+ func forwardLabel (f * ForwardInfo ) string {
254+ if f == nil {
255+ return ""
256+ }
257+ if f .From != nil {
258+ if f .From .Username != "" {
259+ return "@" + f .From .Username
260+ }
261+ if f .From .Title != "" {
262+ return f .From .Title
263+ }
264+ if f .From .Ref != "" {
265+ return f .From .Ref
266+ }
267+ }
268+ return f .FromName
269+ }
270+
211271func shortMessageDate (s string ) string {
212272 t , err := time .Parse (time .RFC3339 , s )
213273 if err != nil {
0 commit comments