Skip to content

Commit a4484b6

Browse files
committed
Initial commit
0 parents  commit a4484b6

File tree

10 files changed

+499
-0
lines changed

10 files changed

+499
-0
lines changed

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Compiled Object files, Static and Dynamic libs (Shared Objects)
2+
*.o
3+
*.a
4+
*.so
5+
6+
# Folders
7+
_obj
8+
_test
9+
10+
# Architecture specific extensions/prefixes
11+
*.[568vq]
12+
[568vq].out
13+
14+
*.cgo1.go
15+
*.cgo2.c
16+
_cgo_defun.c
17+
_cgo_gotypes.go
18+
_cgo_export.*
19+
20+
_testmain.go
21+
22+
*.exe
23+
*.test
24+
*.prof
25+
26+
# Output of the go coverage tool, specifically when used with LiteIDE
27+
*.out
28+
bin

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM golang:1.4
2+
3+
RUN mkdir -p /go/src/app
4+
WORKDIR /go/src/app
5+
COPY ./src /go/src/app
6+
7+
RUN go-wrapper download
8+
RUN go-wrapper install
9+
10+
CMD ["go-wrapper", "run", "./*.go"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2016 Konstantin Azizov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Modified Makefile from https://gist.github.com/Stratus3D/a5be23866810735d7413
2+
3+
.PHONY: build doc fmt lint run test install vet
4+
5+
# Prepend our _vendor directory to the system GOPATH
6+
# so that import path resolution will prioritize
7+
# our third party snapshots.
8+
GOPATH := ${PWD}/_vendor:${GOPATH}
9+
export GOPATH
10+
11+
default: build
12+
13+
build: vet
14+
go build -v -o ./bin/ftpbot ./src/
15+
16+
doc:
17+
godoc -http=:6060 -index
18+
19+
# http://golang.org/cmd/go/#hdr-Run_gofmt_on_package_sources
20+
fmt:
21+
go fmt ./src/...
22+
23+
# https://github.com/golang/lint
24+
# go get github.com/golang/lint/golint
25+
lint:
26+
golint ./src
27+
28+
run: build
29+
./bin/ftpbot
30+
31+
test:
32+
go test ./src/...
33+
34+
35+
install:
36+
cd src && go get && go install
37+
38+
vet:
39+
go vet ./src/...

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# FTPBot
2+
3+
Interact with filesystem of remote computer or server from your PC or smartphone using a Telegram client.
4+
5+
## Getting started
6+
7+
1. Grab the latest release
8+
2. [Create telegram bot](https://core.telegram.org/bots#3-how-do-i-create-a-bot)
9+
3. Copy token and run the latest binary with `--token "%YOUR_TOKEN%"` argument
10+
11+
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!
12+
13+
## Development
14+
15+
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.
16+
17+
There are 2 ways of building application:
18+
19+
### Build locally
20+
Requirements:
21+
- Go 1.6+
22+
- make
23+
24+
```bash
25+
make install
26+
make
27+
./bin/ftpbot --token "YOUR_TOKEN"
28+
```
29+
30+
### Using docker
31+
32+
Insert `token` argument in Dockerfile and run next commands:
33+
34+
```bash
35+
docker build .
36+
docker run %container_id%
37+
```
38+
39+
## License
40+
41+
MIT © [Konstantin Azizov](http://g07cha.github.io)

src/fs-handlers.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package main
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path"
7+
"strconv"
8+
"strings"
9+
10+
"github.com/tucnak/telebot"
11+
)
12+
13+
// LS provide interface between telebot and native function to list files in current directory
14+
func LS(bot *telebot.Bot, msg telebot.Message) error {
15+
page := 0
16+
path := GetCurrentState(&msg.Sender).currentPath
17+
args := strings.Split(msg.Text, " ")
18+
if len(args) > 1 {
19+
page, _ = strconv.Atoi(args[1])
20+
}
21+
22+
markup, err := lsToMarkup(path, page)
23+
if err != nil {
24+
return err
25+
}
26+
27+
return bot.SendMessage(msg.Chat, "List of items in "+path, &telebot.SendOptions{
28+
ReplyMarkup: markup,
29+
})
30+
}
31+
32+
// ShowActions determinates and show possible actions that could be done with file from passed query
33+
func ShowActions(bot *telebot.Bot, msg telebot.Message) error {
34+
filename := msg.Text[strings.Index(msg.Text, " ")+1:]
35+
currentPath := GetCurrentState(&msg.Sender).currentPath
36+
file, err := os.Open(path.Join(currentPath, filename))
37+
if err != nil {
38+
return err
39+
}
40+
41+
defer file.Close()
42+
43+
fileInfo, err := file.Stat()
44+
if err != nil {
45+
return err
46+
}
47+
48+
folderActions := []telebot.KeyboardButton{
49+
telebot.KeyboardButton{
50+
Text: "Open",
51+
Data: "/cd " + fileInfo.Name(),
52+
},
53+
}
54+
fileActions := []telebot.KeyboardButton{
55+
telebot.KeyboardButton{
56+
Text: "Download",
57+
Data: "/download " + fileInfo.Name(),
58+
},
59+
}
60+
61+
// Setup markup with base actions
62+
replyMarkup := &telebot.ReplyMarkup{
63+
InlineKeyboard: [][]telebot.KeyboardButton{
64+
[]telebot.KeyboardButton{
65+
telebot.KeyboardButton{
66+
Text: "Delete",
67+
Data: "/confirm delete " + fileInfo.Name(),
68+
},
69+
},
70+
[]telebot.KeyboardButton{
71+
telebot.KeyboardButton{
72+
Text: "Copy",
73+
Data: "/cp " + fileInfo.Name(),
74+
},
75+
telebot.KeyboardButton{
76+
Text: "Move",
77+
Data: "/mv " + fileInfo.Name(),
78+
},
79+
},
80+
[]telebot.KeyboardButton{
81+
telebot.KeyboardButton{
82+
Text: "Rename",
83+
Data: "/rename " + fileInfo.Name(),
84+
},
85+
},
86+
},
87+
}
88+
89+
var selectedActions []telebot.KeyboardButton
90+
91+
if fileInfo.IsDir() == true {
92+
selectedActions = folderActions
93+
} else {
94+
selectedActions = fileActions
95+
}
96+
97+
replyMarkup.InlineKeyboard = append(replyMarkup.InlineKeyboard, selectedActions)
98+
99+
return bot.SendMessage(msg.Chat, "Choose action for "+fileInfo.Name(), &telebot.SendOptions{
100+
ReplyMarkup: *replyMarkup,
101+
})
102+
}
103+
104+
// ChangeDirectory updates current working directory for users and return file listing in new directory
105+
func ChangeDirectory(bot *telebot.Bot, msg telebot.Message) error {
106+
state := GetCurrentState(&msg.Sender)
107+
108+
newPath := path.Join(state.currentPath, strings.Split(msg.Text, " ")[1])
109+
state.currentPath = newPath
110+
111+
markup, err := lsToMarkup(newPath, 0)
112+
if err != nil {
113+
return err
114+
}
115+
116+
return bot.SendMessage(msg.Chat, "You are now in "+newPath, &telebot.SendOptions{
117+
ReplyMarkup: markup,
118+
})
119+
}
120+
121+
// Download used for downloading files from fs
122+
func Download(bot *telebot.Bot, msg telebot.Message) error {
123+
filename := msg.Text[strings.Index(msg.Text, " ")+1:]
124+
fileExt := filename[strings.LastIndex(filename, ".")+1:]
125+
126+
file, err := telebot.NewFile(path.Join(GetCurrentState(&msg.Sender).currentPath, filename))
127+
if err != nil {
128+
return err
129+
}
130+
131+
switch {
132+
case fileExt == "png" || fileExt == "jpg":
133+
bot.SendPhoto(msg.Sender, &telebot.Photo{File: file}, nil)
134+
case fileExt == "mp3":
135+
bot.SendAudio(msg.Sender, &telebot.Audio{File: file}, nil)
136+
case fileExt == "mp4":
137+
bot.SendVideo(msg.Sender, &telebot.Video{Audio: telebot.Audio{File: file}}, nil)
138+
}
139+
return bot.SendDocument(msg.Sender, &telebot.Document{File: file}, nil)
140+
}
141+
142+
func lsToMarkup(path string, page int) (telebot.ReplyMarkup, error) {
143+
const (
144+
maxItemsPerPage int = 30
145+
maxItemsPerRow int = 3
146+
)
147+
148+
reservedButtons := 1 // Back button by default
149+
files, err := ioutil.ReadDir(path)
150+
files = files[page*maxItemsPerPage:] // Apply paging
151+
if err != nil {
152+
return telebot.ReplyMarkup{}, err
153+
}
154+
if len(files) > maxItemsPerPage {
155+
reservedButtons++ // Reserve slot for next page button
156+
files = files[0:maxItemsPerPage]
157+
}
158+
159+
markup := telebot.ReplyMarkup{
160+
InlineKeyboard: make([][]telebot.KeyboardButton, RoundNumber(float32(len(files))/float32(maxItemsPerRow))+reservedButtons),
161+
}
162+
// Add "Back" button at start
163+
markup.InlineKeyboard[0] = []telebot.KeyboardButton{
164+
telebot.KeyboardButton{
165+
Text: "..",
166+
Data: "/cd ..",
167+
},
168+
}
169+
170+
for i := 1; i <= len(files); i += maxItemsPerRow {
171+
var row []telebot.KeyboardButton
172+
if len(files)-i > maxItemsPerRow {
173+
row = make([]telebot.KeyboardButton, maxItemsPerRow)
174+
} else {
175+
row = make([]telebot.KeyboardButton, len(files)-i)
176+
}
177+
178+
for index, file := range files[i : i+len(row)] {
179+
row[index] = telebot.KeyboardButton{
180+
Text: file.Name(),
181+
Data: "/actions " + file.Name(),
182+
}
183+
}
184+
markup.InlineKeyboard[i/maxItemsPerRow+1] = row
185+
}
186+
187+
if reservedButtons > 1 {
188+
markup.InlineKeyboard[len(markup.InlineKeyboard)-1] = []telebot.KeyboardButton{
189+
telebot.KeyboardButton{
190+
Text: "Next page",
191+
Data: "/ls " + strconv.Itoa(page+1),
192+
},
193+
}
194+
}
195+
196+
return markup, nil
197+
}

0 commit comments

Comments
 (0)