Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
G07cha committed Aug 28, 2016
0 parents commit a4484b6
Show file tree
Hide file tree
Showing 10 changed files with 499 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
bin
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM golang:1.4

RUN mkdir -p /go/src/app
WORKDIR /go/src/app
COPY ./src /go/src/app

RUN go-wrapper download
RUN go-wrapper install

CMD ["go-wrapper", "run", "./*.go"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2016 Konstantin Azizov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
39 changes: 39 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Modified Makefile from https://gist.github.com/Stratus3D/a5be23866810735d7413

.PHONY: build doc fmt lint run test install vet

# Prepend our _vendor directory to the system GOPATH
# so that import path resolution will prioritize
# our third party snapshots.
GOPATH := ${PWD}/_vendor:${GOPATH}
export GOPATH

default: build

build: vet
go build -v -o ./bin/ftpbot ./src/

doc:
godoc -http=:6060 -index

# http://golang.org/cmd/go/#hdr-Run_gofmt_on_package_sources
fmt:
go fmt ./src/...

# https://github.com/golang/lint
# go get github.com/golang/lint/golint
lint:
golint ./src

run: build
./bin/ftpbot

test:
go test ./src/...


install:
cd src && go get && go install

vet:
go vet ./src/...
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# FTPBot

Interact with filesystem of remote computer or server from your PC or smartphone using a Telegram client.

## Getting started

1. Grab the latest release
2. [Create telegram bot](https://core.telegram.org/bots#3-how-do-i-create-a-bot)
3. Copy token and run the latest binary with `--token "%YOUR_TOKEN%"` argument

You can check all available options by running `ftpbot --help`. Don't see an option that you want in the list? Submit an issue about this!

## Development

Want to fix a bug or add future? Nice! If you're working on a thing that isn't listed in issues make sure to discuss it first.

There are 2 ways of building application:

### Build locally
Requirements:
- Go 1.6+
- make

```bash
make install
make
./bin/ftpbot --token "YOUR_TOKEN"
```

### Using docker

Insert `token` argument in Dockerfile and run next commands:

```bash
docker build .
docker run %container_id%
```

## License

MIT © [Konstantin Azizov](http://g07cha.github.io)
197 changes: 197 additions & 0 deletions src/fs-handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package main

import (
"io/ioutil"
"os"
"path"
"strconv"
"strings"

"github.com/tucnak/telebot"
)

// LS provide interface between telebot and native function to list files in current directory
func LS(bot *telebot.Bot, msg telebot.Message) error {
page := 0
path := GetCurrentState(&msg.Sender).currentPath
args := strings.Split(msg.Text, " ")
if len(args) > 1 {
page, _ = strconv.Atoi(args[1])
}

markup, err := lsToMarkup(path, page)
if err != nil {
return err
}

return bot.SendMessage(msg.Chat, "List of items in "+path, &telebot.SendOptions{
ReplyMarkup: markup,
})
}

// ShowActions determinates and show possible actions that could be done with file from passed query
func ShowActions(bot *telebot.Bot, msg telebot.Message) error {
filename := msg.Text[strings.Index(msg.Text, " ")+1:]
currentPath := GetCurrentState(&msg.Sender).currentPath
file, err := os.Open(path.Join(currentPath, filename))
if err != nil {
return err
}

defer file.Close()

fileInfo, err := file.Stat()
if err != nil {
return err
}

folderActions := []telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "Open",
Data: "/cd " + fileInfo.Name(),
},
}
fileActions := []telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "Download",
Data: "/download " + fileInfo.Name(),
},
}

// Setup markup with base actions
replyMarkup := &telebot.ReplyMarkup{
InlineKeyboard: [][]telebot.KeyboardButton{
[]telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "Delete",
Data: "/confirm delete " + fileInfo.Name(),
},
},
[]telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "Copy",
Data: "/cp " + fileInfo.Name(),
},
telebot.KeyboardButton{
Text: "Move",
Data: "/mv " + fileInfo.Name(),
},
},
[]telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "Rename",
Data: "/rename " + fileInfo.Name(),
},
},
},
}

var selectedActions []telebot.KeyboardButton

if fileInfo.IsDir() == true {
selectedActions = folderActions
} else {
selectedActions = fileActions
}

replyMarkup.InlineKeyboard = append(replyMarkup.InlineKeyboard, selectedActions)

return bot.SendMessage(msg.Chat, "Choose action for "+fileInfo.Name(), &telebot.SendOptions{
ReplyMarkup: *replyMarkup,
})
}

// ChangeDirectory updates current working directory for users and return file listing in new directory
func ChangeDirectory(bot *telebot.Bot, msg telebot.Message) error {
state := GetCurrentState(&msg.Sender)

newPath := path.Join(state.currentPath, strings.Split(msg.Text, " ")[1])
state.currentPath = newPath

markup, err := lsToMarkup(newPath, 0)
if err != nil {
return err
}

return bot.SendMessage(msg.Chat, "You are now in "+newPath, &telebot.SendOptions{
ReplyMarkup: markup,
})
}

// Download used for downloading files from fs
func Download(bot *telebot.Bot, msg telebot.Message) error {
filename := msg.Text[strings.Index(msg.Text, " ")+1:]
fileExt := filename[strings.LastIndex(filename, ".")+1:]

file, err := telebot.NewFile(path.Join(GetCurrentState(&msg.Sender).currentPath, filename))
if err != nil {
return err
}

switch {
case fileExt == "png" || fileExt == "jpg":
bot.SendPhoto(msg.Sender, &telebot.Photo{File: file}, nil)
case fileExt == "mp3":
bot.SendAudio(msg.Sender, &telebot.Audio{File: file}, nil)
case fileExt == "mp4":
bot.SendVideo(msg.Sender, &telebot.Video{Audio: telebot.Audio{File: file}}, nil)
}
return bot.SendDocument(msg.Sender, &telebot.Document{File: file}, nil)
}

func lsToMarkup(path string, page int) (telebot.ReplyMarkup, error) {
const (
maxItemsPerPage int = 30
maxItemsPerRow int = 3
)

reservedButtons := 1 // Back button by default
files, err := ioutil.ReadDir(path)
files = files[page*maxItemsPerPage:] // Apply paging
if err != nil {
return telebot.ReplyMarkup{}, err
}
if len(files) > maxItemsPerPage {
reservedButtons++ // Reserve slot for next page button
files = files[0:maxItemsPerPage]
}

markup := telebot.ReplyMarkup{
InlineKeyboard: make([][]telebot.KeyboardButton, RoundNumber(float32(len(files))/float32(maxItemsPerRow))+reservedButtons),
}
// Add "Back" button at start
markup.InlineKeyboard[0] = []telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "..",
Data: "/cd ..",
},
}

for i := 1; i <= len(files); i += maxItemsPerRow {
var row []telebot.KeyboardButton
if len(files)-i > maxItemsPerRow {
row = make([]telebot.KeyboardButton, maxItemsPerRow)
} else {
row = make([]telebot.KeyboardButton, len(files)-i)
}

for index, file := range files[i : i+len(row)] {
row[index] = telebot.KeyboardButton{
Text: file.Name(),
Data: "/actions " + file.Name(),
}
}
markup.InlineKeyboard[i/maxItemsPerRow+1] = row
}

if reservedButtons > 1 {
markup.InlineKeyboard[len(markup.InlineKeyboard)-1] = []telebot.KeyboardButton{
telebot.KeyboardButton{
Text: "Next page",
Data: "/ls " + strconv.Itoa(page+1),
},
}
}

return markup, nil
}

0 comments on commit a4484b6

Please sign in to comment.