]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/transaction_handlers.go
Improve third party client compatability
[rbdr/mobius] / hotline / transaction_handlers.go
index 7f8cbef4e99a6afc3e269875418432c40b1e1470..d3238f4d05bc5d3b247d978cce94031c3525b5c6 100644 (file)
@@ -287,6 +287,7 @@ func HandleChatSend(cc *ClientConn, t *Transaction) (res []Transaction, err erro
 
 // HandleSendInstantMsg sends instant message to the user on the current server.
 // Fields used in the request:
+//
 //     103     User ID
 //     113     Options
 //             One of the following values:
@@ -897,17 +898,6 @@ func HandleUserBroadcast(cc *ClientConn, t *Transaction) (res []Transaction, err
        return res, err
 }
 
-func byteToInt(bytes []byte) (int, error) {
-       switch len(bytes) {
-       case 2:
-               return int(binary.BigEndian.Uint16(bytes)), nil
-       case 4:
-               return int(binary.BigEndian.Uint32(bytes)), nil
-       }
-
-       return 0, errors.New("unknown byte length")
-}
-
 // HandleGetClientInfoText returns user information for the specific user.
 //
 // Fields used in the request:
@@ -943,8 +933,6 @@ func HandleGetUserNameList(cc *ClientConn, t *Transaction) (res []Transaction, e
 }
 
 func HandleTranAgreed(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
-       cc.Agreed = true
-
        if t.GetField(fieldUserName).Data != nil {
                if cc.Authorize(accessAnyName) {
                        cc.UserName = t.GetField(fieldUserName).Data
@@ -1198,10 +1186,12 @@ func HandleNewNewsFldr(cc *ClientConn, t *Transaction) (res []Transaction, err e
        return res, err
 }
 
+// HandleGetNewsArtData gets the list of article names at the specified news path.
+
 // Fields used in the request:
 // 325 News path       Optional
-//
-// Reply fields:
+
+// Fields used in the reply:
 // 321 News article list data  Optional
 func HandleGetNewsArtNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        if !cc.Authorize(accessNewsReadArt) {
@@ -1224,47 +1214,51 @@ func HandleGetNewsArtNameList(cc *ClientConn, t *Transaction) (res []Transaction
        return res, err
 }
 
+// HandleGetNewsArtData requests information about the specific news article.
+// Fields used in the request:
+//
+// Request fields
+// 325 News path
+// 326 News article ID
+// 327 News article data flavor
+//
+// Fields used in the reply:
+// 328 News article title
+// 329 News article poster
+// 330 News article date
+// 331 Previous article ID
+// 332 Next article ID
+// 335 Parent article ID
+// 336 First child article ID
+// 327 News article data flavor        "Should be “text/plain”
+// 333 News article data       Optional (if data flavor is “text/plain”)
 func HandleGetNewsArtData(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        if !cc.Authorize(accessNewsReadArt) {
                res = append(res, cc.NewErrReply(t, "You are not allowed to read news."))
                return res, err
        }
 
-       // Request fields
-       // 325  News fp
-       // 326  News article ID
-       // 327  News article data flavor
-
-       pathStrs := ReadNewsPath(t.GetField(fieldNewsPath).Data)
-
        var cat NewsCategoryListData15
        cats := cc.Server.ThreadedNews.Categories
 
-       for _, fp := range pathStrs {
+       for _, fp := range ReadNewsPath(t.GetField(fieldNewsPath).Data) {
                cat = cats[fp]
                cats = cats[fp].SubCats
        }
-       newsArtID := t.GetField(fieldNewsArtID).Data
 
-       convertedArtID := binary.BigEndian.Uint16(newsArtID)
+       // The official Hotline clients will send the article ID as 2 bytes if possible, but
+       // some third party clients such as Frogblast and Heildrun will always send 4 bytes
+       convertedID, err := byteToInt(t.GetField(fieldNewsArtID).Data)
+       if err != nil {
+               return res, err
+       }
 
-       art := cat.Articles[uint32(convertedArtID)]
+       art := cat.Articles[uint32(convertedID)]
        if art == nil {
                res = append(res, cc.NewReply(t))
                return res, err
        }
 
-       // Reply fields
-       // 328  News article title
-       // 329  News article poster
-       // 330  News article date
-       // 331  Previous article ID
-       // 332  Next article ID
-       // 335  Parent article ID
-       // 336  First child article ID
-       // 327  News article data flavor        "Should be “text/plain”
-       // 333  News article data       Optional (if data flavor is “text/plain”)
-
        res = append(res, cc.NewReply(t,
                NewField(fieldNewsArtTitle, []byte(art.Title)),
                NewField(fieldNewsArtPoster, []byte(art.Poster)),
@@ -1325,7 +1319,10 @@ func HandleDelNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err er
        // 326  News article ID
        // 337  News article – recursive delete       Delete child articles (1) or not (0)
        pathStrs := ReadNewsPath(t.GetField(fieldNewsPath).Data)
-       ID := binary.BigEndian.Uint16(t.GetField(fieldNewsArtID).Data)
+       ID, err := byteToInt(t.GetField(fieldNewsArtID).Data)
+       if err != nil {
+               return res, err
+       }
 
        // TODO: Delete recursive
        cats := cc.Server.GetNewsCatByPath(pathStrs[:len(pathStrs)-1])
@@ -1363,13 +1360,21 @@ func HandlePostNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err e
        catName := pathStrs[len(pathStrs)-1]
        cat := cats[catName]
 
+       artID, err := byteToInt(t.GetField(fieldNewsArtID).Data)
+       if err != nil {
+               return res, err
+       }
+       convertedArtID := uint32(artID)
+       bs := make([]byte, 4)
+       binary.LittleEndian.PutUint32(bs, convertedArtID)
+
        newArt := NewsArtData{
                Title:         string(t.GetField(fieldNewsArtTitle).Data),
                Poster:        string(cc.UserName),
                Date:          toHotlineTime(time.Now()),
                PrevArt:       []byte{0, 0, 0, 0},
                NextArt:       []byte{0, 0, 0, 0},
-               ParentArt:     append([]byte{0, 0}, t.GetField(fieldNewsArtID).Data...),
+               ParentArt:     bs,
                FirstChildArt: []byte{0, 0, 0, 0},
                DataFlav:      []byte("text/plain"),
                Data:          string(t.GetField(fieldNewsArtData).Data),
@@ -1393,9 +1398,9 @@ func HandlePostNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err e
        }
 
        // Update parent article with first child reply
-       parentID := binary.BigEndian.Uint16(t.GetField(fieldNewsArtID).Data)
+       parentID := convertedArtID
        if parentID != 0 {
-               parentArt := cat.Articles[uint32(parentID)]
+               parentArt := cat.Articles[parentID]
 
                if bytes.Equal(parentArt.FirstChildArt, []byte{0, 0, 0, 0}) {
                        binary.BigEndian.PutUint32(parentArt.FirstChildArt, nextID)
@@ -1882,7 +1887,8 @@ func HandleJoinChat(cc *ClientConn, t *Transaction) (res []Transaction, err erro
 
 // HandleLeaveChat is sent from a v1.8+ Hotline client when the user exits a private chat
 // Fields used in the request:
-//     * 114   fieldChatID
+//   - 114     fieldChatID
+//
 // Reply is not expected.
 func HandleLeaveChat(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        chatID := t.GetField(fieldChatID).Data