X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/a2ef262a164fc735b9b8471ac0c8001eea2b9bf6..HEAD:/hotline/transaction.go?ds=inline diff --git a/hotline/transaction.go b/hotline/transaction.go index f8c7dfd..fa1e96d 100644 --- a/hotline/transaction.go +++ b/hotline/transaction.go @@ -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{} }