simplFT/server/server/commands.go

145 lines
3.2 KiB
Go

package server
import (
"bytes"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
)
// GetFile sends the file to the client and returns true if it succeeds and false otherwise.
func GetFile(c Client, path string) (int, error) {
fileName, sanitized := sanitizeFilePath(path)
if sanitized {
return 0, ErrSlashNotAllowed
}
stack, ok := c.Stack().(*StringStack)
if !ok {
return 0, ErrStackCast
}
file, err := os.Open(MakePathFromStringStack(stack) + fileName)
if err != nil {
log.Println(err)
return 0, err
}
defer file.Close()
data, err := readFileData(file)
if err != nil {
return 0, err
}
n, err := c.Connection().Write(data)
if err != nil {
log.Println(err)
return 0, err
}
if n == 0 {
// This happens when the user ties to get the current directory
return 0, GetNoBitsError
}
return n, nil
}
func readFileData(file *os.File) ([]byte, error) {
data, err := ioutil.ReadAll(file)
if err != nil {
log.Println(err)
return nil, err
}
return data, nil
}
func sanitizeFilePath(path string) (string, bool) {
var fileName string
var sanitized bool
// Make sure the user can't request any files on the system.
lastForwardSlash := strings.LastIndex(path, "/")
if lastForwardSlash != -1 {
// Eliminate the last forward slash i.e ../../asdas will become asdas
fileName = path[lastForwardSlash+1:]
sanitized = true
} else {
fileName = path
sanitized = false
}
return fileName, sanitized
}
// ListFiles list the files from path and sends them to the connection
func ListFiles(c Client) error {
stack, ok := c.Stack().(*StringStack)
if !ok {
return ErrStackCast
}
files, err := ioutil.ReadDir(MakePathFromStringStack(stack))
if err != nil {
return err
}
buffer := bytes.NewBufferString("Directory Mode Size LastModified Name\n")
for _, f := range files {
buffer.WriteString(strconv.FormatBool(f.IsDir()) + " " + string(f.Mode().String()) + " " +
strconv.FormatInt(f.Size(), 10) + " " + f.ModTime().String() + " " + string(f.Name()) + " " + "\n")
}
_, err = c.Connection().Write(buffer.Bytes())
if err != nil {
return err
}
return nil
}
// ClearScreen cleans the client's screen by sending clear to the terminal.
func ClearScreen(c Client) error {
// Ansi clear: 1b 5b 48 1b 5b 4a
// clear | hexdump -C
var b = []byte{0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x4a}
_, err := c.Connection().Write(b)
return err
}
// ChangeDirectoryCommand changes the directory to the given directory
func ChangeDirectoryCommand(c Client, directory string) error {
var err error
path, sanitized := sanitizeFilePath(directory)
if sanitized {
return ErrSlashNotAllowed
}
stack, ok := c.Stack().(*StringStack)
if !ok {
return ErrStackCast
}
if path == "." {
err = nil
} else if path == ".." {
err = ChangeDirectoryToPrevious(stack)
} else {
err = ChangeDirectory(stack, path)
}
return err
}
func ShowHelp(c Client) error {
var helpText = `
The available commands are:
get <filename> - Download the requested filename.
ls - List the files in the current directory.
cd - Changes the directory.
clear - Clear the screen.
exit - Close the connection with the server.c
`
_, err := c.Connection().Write([]byte(helpText))
return err
}