]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/transaction_handlers.go
Implement "Refuse private messages" client preference
[rbdr/mobius] / hotline / transaction_handlers.go
index 23ee0e6696035eea952e66ca2a75dcb0a14695e3..abe2ea8d2c72c01695f7ad474f4c0c63c8857b38 100644 (file)
@@ -6,7 +6,6 @@ import (
        "errors"
        "fmt"
        "gopkg.in/yaml.v3"
-       "io/ioutil"
        "math/big"
        "os"
        "path"
@@ -322,14 +321,29 @@ func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, er
                reply.Fields = append(reply.Fields, NewField(fieldQuotingMsg, t.GetField(fieldQuotingMsg).Data))
        }
 
-       res = append(res, *reply)
-
        id, _ := byteToInt(ID.Data)
        otherClient, ok := cc.Server.Clients[uint16(id)]
        if !ok {
                return res, errors.New("invalid client ID")
        }
 
+       // Check if target user has "Refuse private messages" flag
+       flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(otherClient.Flags)))
+       if flagBitmap.Bit(userFLagRefusePChat) == 1 {
+               res = append(res,
+                       *NewTransaction(
+                               tranServerMsg,
+                               cc.ID,
+                               NewField(fieldData, []byte(string(otherClient.UserName)+" does not accept private messages.")),
+                               NewField(fieldUserName, otherClient.UserName),
+                               NewField(fieldUserID, *otherClient.ID),
+                               NewField(fieldOptions, []byte{0, 2}),
+                       ),
+               )
+       } else {
+               res = append(res, *reply)
+       }
+
        // Respond with auto reply if other client has it enabled
        if len(otherClient.AutoReply) > 0 {
                res = append(res,
@@ -463,7 +477,7 @@ func HandleSetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e
                                return res, err
                        }
                        if err != nil {
-                               panic(err)
+                               return res, err
                        }
                }
        }
@@ -582,7 +596,7 @@ func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err err
        // fieldFilePath is only present for nested paths
        if t.GetField(fieldFilePath).Data != nil {
                var newFp FilePath
-               err := newFp.UnmarshalBinary(t.GetField(fieldFilePath).Data)
+               _, err := newFp.Write(t.GetField(fieldFilePath).Data)
                if err != nil {
                        return nil, err
                }
@@ -921,7 +935,7 @@ func HandleTranAgreed(cc *ClientConn, t *Transaction) (res []Transaction, err er
        cc.Icon = t.GetField(fieldUserIconID).Data
 
        cc.logger = cc.logger.With("name", string(cc.UserName))
-       cc.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%x", cc.Version))
+       cc.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%v", func() int { i, _ := byteToInt(cc.Version); return i }()))
 
        options := t.GetField(fieldOptions).Data
        optBitmap := big.NewInt(int64(binary.BigEndian.Uint16(options)))
@@ -1001,14 +1015,14 @@ func HandleTranOldPostNews(cc *ClientConn, t *Transaction) (res []Transaction, e
        newsPost := fmt.Sprintf(newsTemplate+"\r", cc.UserName, time.Now().Format(newsDateTemplate), t.GetField(fieldData).Data)
        newsPost = strings.Replace(newsPost, "\n", "\r", -1)
 
-       // update news in memory
-       cc.Server.FlatNews = append([]byte(newsPost), cc.Server.FlatNews...)
-
        // update news on disk
-       if err := ioutil.WriteFile(cc.Server.ConfigDir+"MessageBoard.txt", cc.Server.FlatNews, 0644); err != nil {
+       if err := cc.Server.FS.WriteFile(filepath.Join(cc.Server.ConfigDir, "MessageBoard.txt"), cc.Server.FlatNews, 0644); err != nil {
                return res, err
        }
 
+       // update news in memory
+       cc.Server.FlatNews = append([]byte(newsPost), cc.Server.FlatNews...)
+
        // Notify all clients of updated news
        cc.sendAll(
                tranNewMsg,
@@ -1244,18 +1258,15 @@ func HandleGetNewsArtData(cc *ClientConn, t *Transaction) (res []Transaction, er
        return res, err
 }
 
+// HandleDelNewsItem deletes an existing threaded news folder or category from the server.
+// Fields used in the request:
+// 325 News path
+// Fields used in the reply:
+// None
 func HandleDelNewsItem(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
-       // Has multiple access flags: News Delete Folder (37) or News Delete Category (35)
-       // TODO: Implement
-
        pathStrs := ReadNewsPath(t.GetField(fieldNewsPath).Data)
 
-       // TODO: determine if path is a Folder (Bundle) or Category and check for permission
-
-       cc.logger.Infof("DelNewsItem %v", pathStrs)
-
        cats := cc.Server.ThreadedNews.Categories
-
        delName := pathStrs[len(pathStrs)-1]
        if len(pathStrs) > 1 {
                for _, fp := range pathStrs[0 : len(pathStrs)-1] {
@@ -1263,17 +1274,23 @@ func HandleDelNewsItem(cc *ClientConn, t *Transaction) (res []Transaction, err e
                }
        }
 
+       if bytes.Compare(cats[delName].Type, []byte{0, 3}) == 0 {
+               if !cc.Authorize(accessNewsDeleteCat) {
+                       return append(res, cc.NewErrReply(t, "You are not allowed to delete news categories.")), nil
+               }
+       } else {
+               if !cc.Authorize(accessNewsDeleteFldr) {
+                       return append(res, cc.NewErrReply(t, "You are not allowed to delete news folders.")), nil
+               }
+       }
+
        delete(cats, delName)
 
-       err = cc.Server.writeThreadedNews()
-       if err != nil {
+       if err := cc.Server.writeThreadedNews(); err != nil {
                return res, err
        }
 
-       // Reply params: none
-       res = append(res, cc.NewReply(t))
-
-       return res, err
+       return append(res, cc.NewReply(t)), nil
 }
 
 func HandleDelNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
@@ -1472,7 +1489,7 @@ func HandleDownloadFolder(cc *ClientConn, t *Transaction) (res []Transaction, er
        fileTransfer := cc.newFileTransfer(FolderDownload, t.GetField(fieldFileName).Data, t.GetField(fieldFilePath).Data, transferSize)
 
        var fp FilePath
-       err = fp.UnmarshalBinary(t.GetField(fieldFilePath).Data)
+       _, err = fp.Write(t.GetField(fieldFilePath).Data)
        if err != nil {
                return res, err
        }
@@ -1496,7 +1513,7 @@ func HandleDownloadFolder(cc *ClientConn, t *Transaction) (res []Transaction, er
 func HandleUploadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        var fp FilePath
        if t.GetField(fieldFilePath).Data != nil {
-               if err = fp.UnmarshalBinary(t.GetField(fieldFilePath).Data); err != nil {
+               if _, err = fp.Write(t.GetField(fieldFilePath).Data); err != nil {
                        return res, err
                }
        }
@@ -1541,7 +1558,7 @@ func HandleUploadFile(cc *ClientConn, t *Transaction) (res []Transaction, err er
 
        var fp FilePath
        if filePath != nil {
-               if err = fp.UnmarshalBinary(filePath); err != nil {
+               if _, err = fp.Write(filePath); err != nil {
                        return res, err
                }
        }
@@ -1658,7 +1675,7 @@ func HandleGetFileNameList(cc *ClientConn, t *Transaction) (res []Transaction, e
 
        var fp FilePath
        if t.GetField(fieldFilePath).Data != nil {
-               if err = fp.UnmarshalBinary(t.GetField(fieldFilePath).Data); err != nil {
+               if _, err = fp.Write(t.GetField(fieldFilePath).Data); err != nil {
                        return res, err
                }
        }
@@ -1702,15 +1719,33 @@ func HandleInviteNewChat(cc *ClientConn, t *Transaction) (res []Transaction, err
        targetID := t.GetField(fieldUserID).Data
        newChatID := cc.Server.NewPrivateChat(cc)
 
-       res = append(res,
-               *NewTransaction(
-                       tranInviteToChat,
-                       &targetID,
-                       NewField(fieldChatID, newChatID),
-                       NewField(fieldUserName, cc.UserName),
-                       NewField(fieldUserID, *cc.ID),
-               ),
-       )
+       // Check if target user has "Refuse private chat" flag
+       binary.BigEndian.Uint16(targetID)
+       targetClient := cc.Server.Clients[binary.BigEndian.Uint16(targetID)]
+
+       flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(targetClient.Flags)))
+       if flagBitmap.Bit(userFLagRefusePChat) == 1 {
+               res = append(res,
+                       *NewTransaction(
+                               tranServerMsg,
+                               cc.ID,
+                               NewField(fieldData, []byte(string(targetClient.UserName)+" does not accept private chats.")),
+                               NewField(fieldUserName, targetClient.UserName),
+                               NewField(fieldUserID, *targetClient.ID),
+                               NewField(fieldOptions, []byte{0, 2}),
+                       ),
+               )
+       } else {
+               res = append(res,
+                       *NewTransaction(
+                               tranInviteToChat,
+                               &targetID,
+                               NewField(fieldChatID, newChatID),
+                               NewField(fieldUserName, cc.UserName),
+                               NewField(fieldUserID, *cc.ID),
+                       ),
+               )
+       }
 
        res = append(res,
                cc.NewReply(t,
@@ -1918,6 +1953,12 @@ func HandleMakeAlias(cc *ClientConn, t *Transaction) (res []Transaction, err err
        return res, err
 }
 
+// HandleDownloadBanner handles requests for a new banner from the server
+// Fields used in the request:
+// None
+// Fields used in the reply:
+// 107 fieldRefNum                     Used later for transfer
+// 108 fieldTransferSize       Size of data to be downloaded
 func HandleDownloadBanner(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        fi, err := cc.Server.FS.Stat(filepath.Join(cc.Server.ConfigDir, cc.Server.Config.BannerFile))
        if err != nil {