]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/transaction.go
Account for the root
[rbdr/mobius] / hotline / transaction.go
index f8c7dfda71437a57f1deec3eba80d2468013c9a1..fa1e96dba5d47f6b2e256caa38d7a72e99afc82b 100644 (file)
@@ -7,70 +7,71 @@ import (
        "errors"
        "fmt"
        "io"
-       "log/slog"
        "math/rand"
        "slices"
 )
 
+type TranType [2]byte
+
 var (
-       TranError                = [2]byte{0x00, 0x00} // 0
-       TranGetMsgs              = [2]byte{0x00, 0x65} // 101
-       TranNewMsg               = [2]byte{0x00, 0x66} // 102
-       TranOldPostNews          = [2]byte{0x00, 0x67} // 103
-       TranServerMsg            = [2]byte{0x00, 0x68} // 104
-       TranChatSend             = [2]byte{0x00, 0x69} // 105
-       TranChatMsg              = [2]byte{0x00, 0x6A} // 106
-       TranLogin                = [2]byte{0x00, 0x6B} // 107
-       TranSendInstantMsg       = [2]byte{0x00, 0x6C} // 108
-       TranShowAgreement        = [2]byte{0x00, 0x6D} // 109
-       TranDisconnectUser       = [2]byte{0x00, 0x6E} // 110
-       TranDisconnectMsg        = [2]byte{0x00, 0x6F} // 111
-       TranInviteNewChat        = [2]byte{0x00, 0x70} // 112
-       TranInviteToChat         = [2]byte{0x00, 0x71} // 113
-       TranRejectChatInvite     = [2]byte{0x00, 0x72} // 114
-       TranJoinChat             = [2]byte{0x00, 0x73} // 115
-       TranLeaveChat            = [2]byte{0x00, 0x74} // 116
-       TranNotifyChatChangeUser = [2]byte{0x00, 0x75} // 117
-       TranNotifyChatDeleteUser = [2]byte{0x00, 0x76} // 118
-       TranNotifyChatSubject    = [2]byte{0x00, 0x77} // 119
-       TranSetChatSubject       = [2]byte{0x00, 0x78} // 120
-       TranAgreed               = [2]byte{0x00, 0x79} // 121
-       TranServerBanner         = [2]byte{0x00, 0x7A} // 122
-       TranGetFileNameList      = [2]byte{0x00, 0xC8} // 200
-       TranDownloadFile         = [2]byte{0x00, 0xCA} // 202
-       TranUploadFile           = [2]byte{0x00, 0xCB} // 203
-       TranNewFolder            = [2]byte{0x00, 0xCD} // 205
-       TranDeleteFile           = [2]byte{0x00, 0xCC} // 204
-       TranGetFileInfo          = [2]byte{0x00, 0xCE} // 206
-       TranSetFileInfo          = [2]byte{0x00, 0xCF} // 207
-       TranMoveFile             = [2]byte{0x00, 0xD0} // 208
-       TranMakeFileAlias        = [2]byte{0x00, 0xD1} // 209
-       TranDownloadFldr         = [2]byte{0x00, 0xD2} // 210
-       TranDownloadInfo         = [2]byte{0x00, 0xD3} // 211
-       TranDownloadBanner       = [2]byte{0x00, 0xD4} // 212
-       TranUploadFldr           = [2]byte{0x00, 0xD5} // 213
-       TranGetUserNameList      = [2]byte{0x01, 0x2C} // 300
-       TranNotifyChangeUser     = [2]byte{0x01, 0x2D} // 301
-       TranNotifyDeleteUser     = [2]byte{0x01, 0x2E} // 302
-       TranGetClientInfoText    = [2]byte{0x01, 0x2F} // 303
-       TranSetClientUserInfo    = [2]byte{0x01, 0x30} // 304
-       TranListUsers            = [2]byte{0x01, 0x5C} // 348
-       TranUpdateUser           = [2]byte{0x01, 0x5D} // 349
-       TranNewUser              = [2]byte{0x01, 0x5E} // 350
-       TranDeleteUser           = [2]byte{0x01, 0x5F} // 351
-       TranGetUser              = [2]byte{0x01, 0x60} // 352
-       TranSetUser              = [2]byte{0x01, 0x61} // 353
-       TranUserAccess           = [2]byte{0x01, 0x62} // 354
-       TranUserBroadcast        = [2]byte{0x01, 0x63} // 355
-       TranGetNewsCatNameList   = [2]byte{0x01, 0x72} // 370
-       TranGetNewsArtNameList   = [2]byte{0x01, 0x73} // 371
-       TranDelNewsItem          = [2]byte{0x01, 0x7C} // 380
-       TranNewNewsFldr          = [2]byte{0x01, 0x7D} // 381
-       TranNewNewsCat           = [2]byte{0x01, 0x7E} // 382
-       TranGetNewsArtData       = [2]byte{0x01, 0x90} // 400
-       TranPostNewsArt          = [2]byte{0x01, 0x9A} // 410
-       TranDelNewsArt           = [2]byte{0x01, 0x9B} // 411
-       TranKeepAlive            = [2]byte{0x01, 0xF4} // 500
+       TranError                = TranType{0x00, 0x00} // 0
+       TranGetMsgs              = TranType{0x00, 0x65} // 101
+       TranNewMsg               = TranType{0x00, 0x66} // 102
+       TranOldPostNews          = TranType{0x00, 0x67} // 103
+       TranServerMsg            = TranType{0x00, 0x68} // 104
+       TranChatSend             = TranType{0x00, 0x69} // 105
+       TranChatMsg              = TranType{0x00, 0x6A} // 106
+       TranLogin                = TranType{0x00, 0x6B} // 107
+       TranSendInstantMsg       = TranType{0x00, 0x6C} // 108
+       TranShowAgreement        = TranType{0x00, 0x6D} // 109
+       TranDisconnectUser       = TranType{0x00, 0x6E} // 110
+       TranDisconnectMsg        = TranType{0x00, 0x6F} // 111
+       TranInviteNewChat        = TranType{0x00, 0x70} // 112
+       TranInviteToChat         = TranType{0x00, 0x71} // 113
+       TranRejectChatInvite     = TranType{0x00, 0x72} // 114
+       TranJoinChat             = TranType{0x00, 0x73} // 115
+       TranLeaveChat            = TranType{0x00, 0x74} // 116
+       TranNotifyChatChangeUser = TranType{0x00, 0x75} // 117
+       TranNotifyChatDeleteUser = TranType{0x00, 0x76} // 118
+       TranNotifyChatSubject    = TranType{0x00, 0x77} // 119
+       TranSetChatSubject       = TranType{0x00, 0x78} // 120
+       TranAgreed               = TranType{0x00, 0x79} // 121
+       TranServerBanner         = TranType{0x00, 0x7A} // 122
+       TranGetFileNameList      = TranType{0x00, 0xC8} // 200
+       TranDownloadFile         = TranType{0x00, 0xCA} // 202
+       TranUploadFile           = TranType{0x00, 0xCB} // 203
+       TranNewFolder            = TranType{0x00, 0xCD} // 205
+       TranDeleteFile           = TranType{0x00, 0xCC} // 204
+       TranGetFileInfo          = TranType{0x00, 0xCE} // 206
+       TranSetFileInfo          = TranType{0x00, 0xCF} // 207
+       TranMoveFile             = TranType{0x00, 0xD0} // 208
+       TranMakeFileAlias        = TranType{0x00, 0xD1} // 209
+       TranDownloadFldr         = TranType{0x00, 0xD2} // 210
+       TranDownloadInfo         = TranType{0x00, 0xD3} // 211
+       TranDownloadBanner       = TranType{0x00, 0xD4} // 212
+       TranUploadFldr           = TranType{0x00, 0xD5} // 213
+       TranGetUserNameList      = TranType{0x01, 0x2C} // 300
+       TranNotifyChangeUser     = TranType{0x01, 0x2D} // 301
+       TranNotifyDeleteUser     = TranType{0x01, 0x2E} // 302
+       TranGetClientInfoText    = TranType{0x01, 0x2F} // 303
+       TranSetClientUserInfo    = TranType{0x01, 0x30} // 304
+       TranListUsers            = TranType{0x01, 0x5C} // 348
+       TranUpdateUser           = TranType{0x01, 0x5D} // 349
+       TranNewUser              = TranType{0x01, 0x5E} // 350
+       TranDeleteUser           = TranType{0x01, 0x5F} // 351
+       TranGetUser              = TranType{0x01, 0x60} // 352
+       TranSetUser              = TranType{0x01, 0x61} // 353
+       TranUserAccess           = TranType{0x01, 0x62} // 354
+       TranUserBroadcast        = TranType{0x01, 0x63} // 355
+       TranGetNewsCatNameList   = TranType{0x01, 0x72} // 370
+       TranGetNewsArtNameList   = TranType{0x01, 0x73} // 371
+       TranDelNewsItem          = TranType{0x01, 0x7C} // 380
+       TranNewNewsFldr          = TranType{0x01, 0x7D} // 381
+       TranNewNewsCat           = TranType{0x01, 0x7E} // 382
+       TranGetNewsArtData       = TranType{0x01, 0x90} // 400
+       TranPostNewsArt          = TranType{0x01, 0x9A} // 410
+       TranDelNewsArt           = TranType{0x01, 0x9B} // 411
+       TranKeepAlive            = TranType{0x01, 0xF4} // 500
 )
 
 type Transaction struct {
@@ -84,76 +85,71 @@ type Transaction struct {
        ParamCount [2]byte  // Number of the parameters for this transaction
        Fields     []Field
 
-       clientID   [2]byte // Internal identifier for target client
-       readOffset int     // Internal offset to track read progress
+       ClientID   ClientID // Internal identifier for target client
+       readOffset int      // Internal offset to track read progress
 }
 
-type TranType [2]byte
-
 var tranTypeNames = map[TranType]string{
-       TranChatMsg:            "Receive Chat",
-       TranNotifyChangeUser:   "TranNotifyChangeUser",
-       TranError:              "TranError",
-       TranShowAgreement:      "TranShowAgreement",
-       TranUserAccess:         "TranUserAccess",
-       TranNotifyDeleteUser:   "TranNotifyDeleteUser",
-       TranAgreed:             "TranAgreed",
-       TranChatSend:           "Send Chat",
-       TranDelNewsArt:         "TranDelNewsArt",
-       TranDelNewsItem:        "TranDelNewsItem",
-       TranDeleteFile:         "TranDeleteFile",
-       TranDeleteUser:         "TranDeleteUser",
-       TranDisconnectUser:     "TranDisconnectUser",
-       TranDownloadFile:       "TranDownloadFile",
-       TranDownloadFldr:       "TranDownloadFldr",
-       TranGetClientInfoText:  "TranGetClientInfoText",
-       TranGetFileInfo:        "TranGetFileInfo",
-       TranGetFileNameList:    "TranGetFileNameList",
-       TranGetMsgs:            "TranGetMsgs",
-       TranGetNewsArtData:     "TranGetNewsArtData",
-       TranGetNewsArtNameList: "TranGetNewsArtNameList",
-       TranGetNewsCatNameList: "TranGetNewsCatNameList",
-       TranGetUser:            "TranGetUser",
-       TranGetUserNameList:    "tranHandleGetUserNameList",
-       TranInviteNewChat:      "TranInviteNewChat",
-       TranInviteToChat:       "TranInviteToChat",
-       TranJoinChat:           "TranJoinChat",
-       TranKeepAlive:          "TranKeepAlive",
-       TranLeaveChat:          "TranJoinChat",
-       TranListUsers:          "TranListUsers",
-       TranMoveFile:           "TranMoveFile",
-       TranNewFolder:          "TranNewFolder",
-       TranNewNewsCat:         "TranNewNewsCat",
-       TranNewNewsFldr:        "TranNewNewsFldr",
-       TranNewUser:            "TranNewUser",
-       TranUpdateUser:         "TranUpdateUser",
-       TranOldPostNews:        "TranOldPostNews",
-       TranPostNewsArt:        "TranPostNewsArt",
-       TranRejectChatInvite:   "TranRejectChatInvite",
-       TranSendInstantMsg:     "TranSendInstantMsg",
-       TranSetChatSubject:     "TranSetChatSubject",
-       TranMakeFileAlias:      "TranMakeFileAlias",
-       TranSetClientUserInfo:  "TranSetClientUserInfo",
-       TranSetFileInfo:        "TranSetFileInfo",
-       TranSetUser:            "TranSetUser",
-       TranUploadFile:         "TranUploadFile",
-       TranUploadFldr:         "TranUploadFldr",
-       TranUserBroadcast:      "TranUserBroadcast",
-       TranDownloadBanner:     "TranDownloadBanner",
+       TranChatMsg:            "Receive chat",
+       TranNotifyChangeUser:   "User change",
+       TranError:              "Error",
+       TranShowAgreement:      "Show agreement",
+       TranUserAccess:         "User access",
+       TranNotifyDeleteUser:   "User left",
+       TranAgreed:             "Accept agreement",
+       TranChatSend:           "Send chat",
+       TranDelNewsArt:         "Delete news article",
+       TranDelNewsItem:        "Delete news item",
+       TranDeleteFile:         "Delete file",
+       TranDeleteUser:         "Delete user",
+       TranDisconnectUser:     "Disconnect user",
+       TranDownloadFile:       "Download file",
+       TranDownloadFldr:       "Download folder",
+       TranGetClientInfoText:  "Get client info",
+       TranGetFileInfo:        "Get file info",
+       TranGetFileNameList:    "Get file list",
+       TranGetMsgs:            "Get messages",
+       TranGetNewsArtData:     "Get news article",
+       TranGetNewsArtNameList: "Get news article list",
+       TranGetNewsCatNameList: "Get news categories",
+       TranGetUser:            "Get user",
+       TranGetUserNameList:    "Get user list",
+       TranInviteNewChat:      "Invite to new chat",
+       TranInviteToChat:       "Invite to chat",
+       TranJoinChat:           "Join chat",
+       TranKeepAlive:          "Keepalive",
+       TranLeaveChat:          "Leave chat",
+       TranListUsers:          "List user accounts",
+       TranMoveFile:           "Move file",
+       TranNewFolder:          "Create folder",
+       TranNewNewsCat:         "Create news category",
+       TranNewNewsFldr:        "Create news bundle",
+       TranNewUser:            "Create user account",
+       TranUpdateUser:         "Update user account",
+       TranOldPostNews:        "Post to message board",
+       TranPostNewsArt:        "Create news article",
+       TranRejectChatInvite:   "Decline chat invite",
+       TranSendInstantMsg:     "Send message",
+       TranSetChatSubject:     "Set chat subject",
+       TranMakeFileAlias:      "Make file alias",
+       TranSetClientUserInfo:  "Set client user info",
+       TranSetFileInfo:        "Set file info",
+       TranSetUser:            "Set user",
+       TranUploadFile:         "Upload file",
+       TranUploadFldr:         "Upload folder",
+       TranUserBroadcast:      "Send broadcast",
+       TranDownloadBanner:     "Download banner",
 }
 
-func (t TranType) LogValue() slog.Value {
-       return slog.StringValue(tranTypeNames[t])
-}
-
-// NewTransaction creates a new Transaction with the specified type, client ID, and optional fields.
-func NewTransaction(t, clientID [2]byte, fields ...Field) Transaction {
+// NewTransaction creates a new Transaction with the specified type, client, and optional fields.
+func NewTransaction(t TranType, clientID ClientID, fields ...Field) Transaction {
        transaction := Transaction{
                Type:     t,
-               clientID: clientID,
+               ClientID: clientID,
                Fields:   fields,
        }
 
+       // Give the transaction a random ID.
        binary.BigEndian.PutUint32(transaction.ID[:], rand.Uint32())
 
        return transaction
@@ -184,7 +180,7 @@ func (t *Transaction) Write(p []byte) (n int, err error) {
        copy(t.ParamCount[:], p[20:22])
 
        scanner := bufio.NewScanner(bytes.NewReader(p[22:tranLen]))
-       scanner.Split(fieldScanner)
+       scanner.Split(FieldScanner)
 
        for i := 0; i < int(paramCount); i++ {
                if !scanner.Scan() {
@@ -227,45 +223,6 @@ func transactionScanner(data []byte, _ bool) (advance int, token []byte, err err
 
 const minFieldLen = 4
 
-func ReadFields(paramCount []byte, buf []byte) ([]Field, error) {
-       paramCountInt := int(binary.BigEndian.Uint16(paramCount))
-       if paramCountInt > 0 && len(buf) < minFieldLen {
-               return []Field{}, fmt.Errorf("invalid field length %v", len(buf))
-       }
-
-       // A Field consists of:
-       // ID: 2 bytes
-       // Size: 2 bytes
-       // Data: FieldSize number of bytes
-       var fields []Field
-       for i := 0; i < paramCountInt; i++ {
-               if len(buf) < minFieldLen {
-                       return []Field{}, fmt.Errorf("invalid field length %v", len(buf))
-               }
-               fieldID := buf[0:2]
-               fieldSize := buf[2:4]
-               fieldSizeInt := int(binary.BigEndian.Uint16(buf[2:4]))
-               expectedLen := minFieldLen + fieldSizeInt
-               if len(buf) < expectedLen {
-                       return []Field{}, fmt.Errorf("field length too short")
-               }
-
-               fields = append(fields, Field{
-                       ID:        [2]byte(fieldID),
-                       FieldSize: [2]byte(fieldSize),
-                       Data:      buf[4 : 4+fieldSizeInt],
-               })
-
-               buf = buf[fieldSizeInt+4:]
-       }
-
-       if len(buf) != 0 {
-               return []Field{}, fmt.Errorf("extra field bytes")
-       }
-
-       return fields, nil
-}
-
 // Read implements the io.Reader interface for Transaction
 func (t *Transaction) Read(p []byte) (int, error) {
        payloadSize := t.Size()
@@ -318,12 +275,12 @@ func (t *Transaction) Size() []byte {
        return bs
 }
 
-func (t *Transaction) GetField(id [2]byte) Field {
+func (t *Transaction) GetField(id [2]byte) *Field {
        for _, field := range t.Fields {
-               if id == field.ID {
-                       return field
+               if id == field.Type {
+                       return &field
                }
        }
 
-       return Field{}
+       return &Field{}
 }