From: Ruben Beltran del Rio Date: Tue, 4 Feb 2025 20:37:02 +0000 (+0100) Subject: Share replacement code X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/commitdiff_plain/6d81feb101da689092d3370c1dc55be89e11fd35?hp=ba201a220aa723f98c6a81d74dc4229bf89b282a Share replacement code --- diff --git a/internal/mobius/friendship_quest_file_extensions.go b/internal/mobius/friendship_quest_file_extensions.go index f04868c..98d82ff 100644 --- a/internal/mobius/friendship_quest_file_extensions.go +++ b/internal/mobius/friendship_quest_file_extensions.go @@ -12,192 +12,131 @@ import ( ) // ResolveUserPath processes paths for the special `~` directory. -// If the requested path starts with `~`, it returns the user's corresponding folder. func ResolveUserPath(cc *hotline.ClientConn, requestedPath string) (string, error) { - if strings.HasPrefix(requestedPath, "~") { - userFolder := filepath.Join("~", cc.Account.Login) - actualUserFolder := filepath.Join(cc.FileRoot(), userFolder) - if stat, err := os.Stat(actualUserFolder); err == nil && stat.IsDir() { - return strings.Replace(requestedPath, "~", userFolder, 1), nil - } else { - return "", fmt.Errorf("user folder does not exist") - } + if !strings.HasPrefix(requestedPath, "~") { + return requestedPath, nil + } + + userFolder := filepath.Join("~", cc.Account.Login) + actualUserFolder := filepath.Join(cc.FileRoot(), userFolder) + if stat, err := os.Stat(actualUserFolder); err == nil && stat.IsDir() { + return strings.Replace(requestedPath, "~", userFolder, 1), nil } - return requestedPath, nil + + return "", fmt.Errorf("user folder does not exist") } // updateTransactionPath updates the FieldFilePath in a transaction in-place. func updateTransactionPath(t *hotline.Transaction, newPath string) { - for i, field := range t.Fields { - if field.Type == hotline.FieldFilePath { - - // Convert newPath to the correct binary format - encodedPath, err := txtEncoder.String(newPath) - if err != nil { - return // Encoding failure, don't update - } - - // Convert the new path into the correct binary format for FilePath - fpBytes, err := encodeFilePath(encodedPath) - if err != nil { - return - } - - // Assign correctly formatted binary path - t.Fields[i].Data = fpBytes - return - } - } + for i, field := range t.Fields { + if field.Type == hotline.FieldFilePath { + if encodedPath, err := txtEncoder.String(newPath); err == nil { + if fpBytes, err := encodeFilePath(encodedPath); err == nil { + t.Fields[i].Data = fpBytes + } + } + return + } + } } -// Encode a string path into hotline.FilePath binary format +// encodeFilePath encodes a string path into hotline.FilePath binary format. func encodeFilePath(path string) ([]byte, error) { - components := strings.Split(path, string(filepath.Separator)) - var fp hotline.FilePath - - // Set the item count - binary.BigEndian.PutUint16(fp.ItemCount[:], uint16(len(components))) - - var buffer bytes.Buffer - err := binary.Write(&buffer, binary.BigEndian, fp.ItemCount) - if err != nil { - return nil, err - } - - for _, component := range components { - if component == "" { - continue - } - - if len(component) > 255 { // Ensure component size is within range - return nil, fmt.Errorf("file path component too long") - } - - // Convert to MacRoman encoding - encodedComponent, err := txtEncoder.String(component) - if err != nil { - return nil, err - } - - // Write length and name - buffer.Write([]byte{0x00, 0x00, byte(len(encodedComponent))}) // Leading bytes - buffer.Write([]byte(encodedComponent)) - } - - return buffer.Bytes(), nil -} + components := strings.Split(path, string(filepath.Separator)) + var fp hotline.FilePath + binary.BigEndian.PutUint16(fp.ItemCount[:], uint16(len(components))) -// HandleGetFileNameListWithUserFolders modifies the file listing behavior for `~` -func HandleGetFileNameListWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { - requestedPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil) - if err != nil { - return res + var buffer bytes.Buffer + if err := binary.Write(&buffer, binary.BigEndian, fp.ItemCount); err != nil { + return nil, err } - if requestedPath == cc.FileRoot() { - fileNames, err := hotline.GetFileNameList(cc.FileRoot(), cc.Server.Config.IgnoreFiles) - if err != nil { - return res - } - - userFolder := filepath.Join(cc.FileRoot(), "~", cc.Account.Login) - if stat, err := os.Stat(userFolder); err != nil || !stat.IsDir() { - filteredFiles := []hotline.Field{} - for _, file := range fileNames { - if !strings.Contains(string(file.Data), "~") { - filteredFiles = append(filteredFiles, file) - } - } - return append(res, cc.NewReply(t, filteredFiles...)) + for _, component := range components { + if component == "" || len(component) > 255 { + return nil, fmt.Errorf("invalid file path component") } - return append(res, cc.NewReply(t, fileNames...)) - } - - if strings.HasPrefix(requestedPath, filepath.Join(cc.FileRoot(), "~")) { - resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) + encodedComponent, err := txtEncoder.String(component) if err != nil { - return res + return nil, err } - updateTransactionPath(t, resolvedPath) - return HandleGetFileNameList(cc, t) + buffer.Write([]byte{0x00, 0x00, byte(len(encodedComponent))}) + buffer.Write([]byte(encodedComponent)) } - return HandleGetFileNameList(cc, t) + return buffer.Bytes(), nil } -// HandleUploadFileWithUserFolders ensures uploads go to the correct user folder when using `~`. -func HandleUploadFileWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { +// handleFileTransaction handles various file operations that require resolving `~` +func handleFileTransaction(cc *hotline.ClientConn, t *hotline.Transaction, handler func(*hotline.ClientConn, *hotline.Transaction) []hotline.Transaction, errMsg string) []hotline.Transaction { requestedPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil) if err != nil { - return res + return nil } resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) if err != nil { - return cc.NewErrReply(t, "Cannot upload to non-existent user folder.") + return cc.NewErrReply(t, errMsg) } updateTransactionPath(t, resolvedPath) - return HandleUploadFile(cc, t) + return handler(cc, t) } -// HandleUploadFolderWithUserFolders ensures directory uploads go to the correct user folder when using `~`. -func HandleUploadFolderWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { - requestedPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil) - if err != nil { - return res - } - - resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) - if err != nil { - return cc.NewErrReply(t, "Cannot upload to non-existent user folder.") - } +// File operation handlers +func HandleUploadFileWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) []hotline.Transaction { + return handleFileTransaction(cc, t, HandleUploadFile, "Cannot upload to non-existent user folder.") +} - updateTransactionPath(t, resolvedPath) - return HandleUploadFolder(cc, t) +func HandleUploadFolderWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) []hotline.Transaction { + return handleFileTransaction(cc, t, HandleUploadFolder, "Cannot upload to non-existent user folder.") } -func HandleDeleteFileWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { - requestedPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil) - if err != nil { - return res - } +func HandleDeleteFileWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) []hotline.Transaction { + return handleFileTransaction(cc, t, HandleDeleteFile, "Cannot delete non-existent file.") +} - resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) - if err != nil { - return cc.NewErrReply(t, "Cannot delete non-existent file.") - } +func HandleDownloadFileWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) []hotline.Transaction { + return handleFileTransaction(cc, t, HandleDownloadFile, "Cannot download non-existent user file.") +} - updateTransactionPath(t, resolvedPath) - return HandleDeleteFile(cc, t) +func HandleDownloadFolderWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) []hotline.Transaction { + return handleFileTransaction(cc, t, HandleDownloadFolder, "Cannot download non-existent user folder.") } -func HandleDownloadFileWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { +// HandleGetFileNameListWithUserFolders modifies the file listing behavior for `~` +func HandleGetFileNameListWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) []hotline.Transaction { requestedPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil) if err != nil { - return res + return nil } - resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) - if err != nil { - return cc.NewErrReply(t, "Cannot download non-existent user file.") - } - - updateTransactionPath(t, resolvedPath) - return HandleDownloadFile(cc, t) -} + if requestedPath == cc.FileRoot() { + fileNames, err := hotline.GetFileNameList(cc.FileRoot(), cc.Server.Config.IgnoreFiles) + if err != nil { + return nil + } -func HandleDownloadFolderWithUserFolders(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { - requestedPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil) - if err != nil { - return res + userFolder := filepath.Join(cc.FileRoot(), "~", cc.Account.Login) + if stat, err := os.Stat(userFolder); err != nil || !stat.IsDir() { + filteredFiles := make([]hotline.Field, 0, len(fileNames)) + for _, file := range fileNames { + if !strings.Contains(string(file.Data), "~") { + filteredFiles = append(filteredFiles, file) + } + } + return []hotline.Transaction{cc.NewReply(t, filteredFiles...)} + } + return []hotline.Transaction{cc.NewReply(t, fileNames...)} } - resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) - if err != nil { - return cc.NewErrReply(t, "Cannot download non-existent user folder.") + if strings.HasPrefix(requestedPath, filepath.Join(cc.FileRoot(), "~")) { + resolvedPath, err := ResolveUserPath(cc, requestedPath[len(cc.FileRoot())+1:]) + if err != nil { + return nil + } + updateTransactionPath(t, resolvedPath) + return HandleGetFileNameList(cc, t) } - updateTransactionPath(t, resolvedPath) - return HandleDownloadFolder(cc, t) + return HandleGetFileNameList(cc, t) }