forked from x/icebergs
opt nfs
This commit is contained in:
parent
6c9b2c0b8b
commit
62d614d321
103
base/nfs/cat.go
Normal file
103
base/nfs/cat.go
Normal file
@ -0,0 +1,103 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/aaa"
|
||||
"github.com/shylinux/icebergs/base/mdb"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"bufio"
|
||||
"bytes"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func _cat_ext(name string) string {
|
||||
return strings.ToLower(kit.Select(path.Base(name), strings.TrimPrefix(path.Ext(name), ".")))
|
||||
}
|
||||
func _cat_right(m *ice.Message, name string) bool {
|
||||
switch strings.Split(name, "/")[0] {
|
||||
case kit.SSH_ETC, kit.SSH_VAR:
|
||||
if m.Warn(m.Option(ice.MSG_USERROLE) == aaa.VOID, ice.ErrNotRight, "of", name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
func _cat_show(m *ice.Message, name string) {
|
||||
if !_cat_right(m, name) {
|
||||
return // 没有权限
|
||||
}
|
||||
|
||||
// 本地文件
|
||||
if f, e := os.Open(path.Join(m.Option(DIR_ROOT), name)); e == nil {
|
||||
defer f.Close()
|
||||
|
||||
switch cb := m.Optionv(kit.Keycb(CAT)).(type) {
|
||||
case func(string, int):
|
||||
bio := bufio.NewScanner(f)
|
||||
for i := 0; bio.Scan(); i++ {
|
||||
cb(bio.Text(), i)
|
||||
}
|
||||
|
||||
default:
|
||||
if s, e := f.Stat(); m.Assert(e) {
|
||||
buf := make([]byte, s.Size())
|
||||
if n, e := f.Read(buf); m.Assert(e) {
|
||||
m.Log_IMPORT(kit.MDB_FILE, name, kit.MDB_SIZE, n)
|
||||
m.Echo(string(buf[:n]))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 打包文件
|
||||
if b, ok := ice.BinPack[name]; ok {
|
||||
m.Logs("binpack", name, kit.MDB_SIZE, len(b))
|
||||
m.Echo(string(b))
|
||||
return
|
||||
}
|
||||
|
||||
// 远程文件
|
||||
switch cb := m.Optionv(kit.Keycb(CAT)).(type) {
|
||||
case func(string, int):
|
||||
bio := bufio.NewScanner(bytes.NewBufferString(m.Cmdx("web.spide", "dev", "raw", "GET", path.Join("/share/local/", name))))
|
||||
for i := 0; bio.Scan(); i++ {
|
||||
cb(bio.Text(), i)
|
||||
}
|
||||
default:
|
||||
m.Cmdy("web.spide", "dev", "raw", "GET", path.Join("/share/local/", name))
|
||||
}
|
||||
}
|
||||
|
||||
const CAT = "cat"
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
CAT: {Name: CAT, Help: "文件", Value: kit.Data(
|
||||
kit.SSH_SOURCE, kit.Dict(
|
||||
"sh", "true", "shy", "true", "py", "true",
|
||||
"go", "true", "vim", "true", "js", "true",
|
||||
"conf", "true", "json", "true",
|
||||
"makefile", "true",
|
||||
),
|
||||
)},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
CAT: {Name: "cat path auto", Help: "文件", Action: map[string]*ice.Action{
|
||||
mdb.RENDER: {Name: "render type name text", Help: "渲染", Hand: func(m *ice.Message, arg ...string) {
|
||||
_cat_show(m, path.Join(arg[2], arg[1]))
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 || strings.HasSuffix(arg[0], "/") {
|
||||
m.Cmdy(DIR, arg)
|
||||
return
|
||||
}
|
||||
_cat_show(m, arg[0])
|
||||
}},
|
||||
},
|
||||
})
|
||||
}
|
196
base/nfs/dir.go
Normal file
196
base/nfs/dir.go
Normal file
@ -0,0 +1,196 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/mdb"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"bufio"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func _dir_show(m *ice.Message, root string, name string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string) *ice.Message {
|
||||
if !_cat_right(m, name) {
|
||||
return m // 没有权限
|
||||
}
|
||||
|
||||
fs, e := ioutil.ReadDir(path.Join(root, name))
|
||||
if e != nil { // 单个文件
|
||||
ls, _ := ioutil.ReadDir(path.Dir(path.Join(root, name)))
|
||||
for _, k := range ls {
|
||||
if k.Name() == path.Base(name) {
|
||||
fs = append(fs, k)
|
||||
}
|
||||
}
|
||||
name = path.Dir(name)
|
||||
}
|
||||
|
||||
for _, f := range fs {
|
||||
if f.Name() == "." || f.Name() == ".." {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(f.Name(), ".") && dir_type != TYPE_ALL {
|
||||
continue
|
||||
}
|
||||
|
||||
p := path.Join(root, name, f.Name())
|
||||
if !(dir_type == TYPE_CAT && f.IsDir() || dir_type == TYPE_DIR && !f.IsDir()) && (dir_reg == nil || dir_reg.MatchString(f.Name())) {
|
||||
for _, field := range fields {
|
||||
switch field {
|
||||
case kit.MDB_TIME:
|
||||
m.Push(field, f.ModTime().Format(ice.MOD_TIME))
|
||||
case kit.MDB_TYPE:
|
||||
m.Push(field, kit.Select(CAT, DIR, f.IsDir()))
|
||||
|
||||
case "tree":
|
||||
if level == 0 {
|
||||
m.Push(field, f.Name())
|
||||
} else {
|
||||
m.Push(field, strings.Repeat("| ", level-1)+"|-"+f.Name())
|
||||
}
|
||||
case "full":
|
||||
m.Push(field, path.Join(root, name, f.Name())+kit.Select("", "/", f.IsDir()))
|
||||
|
||||
case kit.MDB_PATH:
|
||||
m.Push(field, path.Join(name, f.Name())+kit.Select("", "/", f.IsDir()))
|
||||
case kit.MDB_FILE:
|
||||
m.Push(field, f.Name()+kit.Select("", "/", f.IsDir()))
|
||||
case kit.MDB_NAME:
|
||||
m.Push(field, f.Name())
|
||||
|
||||
case kit.MDB_LINK:
|
||||
m.PushDownload(kit.MDB_LINK, kit.Select("", f.Name(), !f.IsDir()), path.Join(root, name, f.Name()))
|
||||
|
||||
case kit.MDB_SIZE:
|
||||
if f.IsDir() {
|
||||
if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil {
|
||||
m.Push(field, len(ls))
|
||||
} else {
|
||||
m.Push(field, 0)
|
||||
}
|
||||
} else {
|
||||
m.Push(field, kit.FmtSize(f.Size()))
|
||||
}
|
||||
case kit.MDB_LINE:
|
||||
if f.IsDir() {
|
||||
if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil {
|
||||
m.Push(field, len(ls))
|
||||
} else {
|
||||
m.Push(field, 0)
|
||||
}
|
||||
} else {
|
||||
nline := 0
|
||||
if f, e := os.Open(p); m.Assert(e) {
|
||||
defer f.Close()
|
||||
for bio := bufio.NewScanner(f); bio.Scan(); nline++ {
|
||||
bio.Text()
|
||||
}
|
||||
}
|
||||
m.Push(field, nline)
|
||||
}
|
||||
case kit.MDB_HASH, "hashs":
|
||||
var h [20]byte
|
||||
if f.IsDir() {
|
||||
if d, e := ioutil.ReadDir(p); m.Assert(e) {
|
||||
meta := []string{}
|
||||
for _, v := range d {
|
||||
meta = append(meta, fmt.Sprintf("%s%d%s", v.Name(), v.Size(), v.ModTime()))
|
||||
}
|
||||
sort.Strings(meta)
|
||||
h = sha1.Sum([]byte(strings.Join(meta, "")))
|
||||
}
|
||||
} else {
|
||||
if f, e := ioutil.ReadFile(path.Join(name, f.Name())); m.Assert(e) {
|
||||
h = sha1.Sum(f)
|
||||
}
|
||||
}
|
||||
|
||||
m.Push(kit.MDB_HASH, kit.Select(hex.EncodeToString(h[:6]), hex.EncodeToString(h[:]), field == kit.MDB_HASH))
|
||||
default:
|
||||
m.Push(field, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.IsDir() && deep {
|
||||
_dir_show(m, root, path.Join(name, f.Name()), level+1, deep, dir_type, dir_reg, fields)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
func _dir_search(m *ice.Message, kind, name string) {
|
||||
if kind == kit.MDB_FOREACH {
|
||||
return
|
||||
}
|
||||
|
||||
msg := _dir_show(m.Spawn(), "./", "", 0, true, TYPE_BOTH, nil, strings.Split("time,type,name,text", ","))
|
||||
msg.Table(func(index int, value map[string]string, head []string) {
|
||||
if !strings.Contains(value[kit.MDB_NAME], name) {
|
||||
return
|
||||
}
|
||||
|
||||
if value[kit.MDB_TYPE] == CAT {
|
||||
value[kit.MDB_TYPE] = _cat_ext(value[kit.MDB_NAME])
|
||||
}
|
||||
|
||||
m.PushSearch(kit.SSH_CMD, CAT, value)
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
TYPE_ALL = "all"
|
||||
TYPE_DIR = "dir"
|
||||
TYPE_CAT = "cat"
|
||||
TYPE_BOTH = "both"
|
||||
)
|
||||
const (
|
||||
DIR_ROOT = "dir_root"
|
||||
DIR_TYPE = "dir_type"
|
||||
DIR_DEEP = "dir_deep"
|
||||
DIR_REG = "dir_reg"
|
||||
)
|
||||
const DIR = "dir"
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
DIR: {Name: DIR, Help: "目录", Value: kit.Data()},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
DIR: {Name: "dir path field... auto upload", Help: "目录", Action: map[string]*ice.Action{
|
||||
mdb.SEARCH: {Name: "search type name", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
|
||||
_dir_search(m, arg[0], arg[1])
|
||||
}},
|
||||
mdb.RENDER: {Name: "render type name text", Help: "渲染", Hand: func(m *ice.Message, arg ...string) {
|
||||
_dir_show(m, arg[2], arg[1], 0, m.Option(DIR_DEEP) == "true", kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)),
|
||||
nil, kit.Split("time,size,type,path"))
|
||||
}},
|
||||
|
||||
mdb.UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) {
|
||||
up := kit.Simple(m.Optionv(ice.MSG_UPLOAD))
|
||||
if p := path.Join(m.Option(kit.MDB_PATH), up[1]); m.Option(ice.MSG_USERPOD) == "" {
|
||||
m.Cmdy("cache", "watch", up[0], p)
|
||||
} else {
|
||||
m.Cmdy("spide", "dev", "save", p, "GET", kit.MergeURL2(m.Option(ice.MSG_USERWEB), "/share/cache/"+up[0]))
|
||||
}
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, "")
|
||||
}
|
||||
_dir_show(m, kit.Select("./", m.Option(DIR_ROOT)), arg[0],
|
||||
0, m.Options(DIR_DEEP), kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), kit.Regexp(m.Option(DIR_REG)),
|
||||
kit.Split(kit.Select("time,size,path", strings.Join(arg[1:], ","))))
|
||||
m.SortTimeR(kit.MDB_TIME)
|
||||
}},
|
||||
},
|
||||
})
|
||||
}
|
106
base/nfs/save.go
Normal file
106
base/nfs/save.go
Normal file
@ -0,0 +1,106 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func _save_file(m *ice.Message, name string, text ...string) {
|
||||
if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
for _, v := range text {
|
||||
if n, e := f.WriteString(v); m.Assert(e) {
|
||||
m.Log_EXPORT(kit.MDB_FILE, p, kit.MDB_SIZE, n)
|
||||
}
|
||||
}
|
||||
m.Echo(p)
|
||||
}
|
||||
}
|
||||
func _push_file(m *ice.Message, name string, text ...string) {
|
||||
p := path.Join(m.Option(DIR_ROOT), name)
|
||||
if strings.Contains(p, "/") {
|
||||
os.MkdirAll(path.Dir(p), ice.MOD_DIR)
|
||||
}
|
||||
|
||||
if f, e := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, ice.MOD_FILE); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
for _, k := range text {
|
||||
if n, e := f.WriteString(k); m.Assert(e) {
|
||||
m.Log_EXPORT(kit.MDB_FILE, p, kit.MDB_SIZE, n)
|
||||
}
|
||||
}
|
||||
m.Echo(p)
|
||||
}
|
||||
}
|
||||
func _copy_file(m *ice.Message, name string, from ...string) {
|
||||
if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
for _, v := range from {
|
||||
if s, e := os.Open(v); !m.Warn(e != nil, e) {
|
||||
defer s.Close()
|
||||
|
||||
if n, e := io.Copy(f, s); !m.Warn(e != nil, e) {
|
||||
m.Log_IMPORT(kit.MDB_FILE, v, kit.MDB_SIZE, n)
|
||||
m.Log_EXPORT(kit.MDB_FILE, p, kit.MDB_SIZE, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
m.Echo(p)
|
||||
}
|
||||
}
|
||||
func _link_file(m *ice.Message, name string, from string) {
|
||||
if from == "" {
|
||||
return
|
||||
}
|
||||
os.Remove(name)
|
||||
os.MkdirAll(path.Dir(name), ice.MOD_DIR)
|
||||
os.Link(from, name)
|
||||
m.Echo(name)
|
||||
}
|
||||
func _defs_file(m *ice.Message, name string, text ...string) {
|
||||
if _, e := os.Stat(path.Join(m.Option(DIR_ROOT), name)); os.IsNotExist(e) {
|
||||
_save_file(m, name, text...)
|
||||
}
|
||||
}
|
||||
|
||||
const SAVE = "save"
|
||||
const PUSH = "push"
|
||||
const COPY = "copy"
|
||||
const LINK = "link"
|
||||
const DEFS = "defs"
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Commands: map[string]*ice.Command{
|
||||
SAVE: {Name: "save file text...", Help: "保存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
arg = append(arg, m.Option(kit.MDB_CONTENT))
|
||||
}
|
||||
_save_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
PUSH: {Name: "push file text...", Help: "追加", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
arg = append(arg, m.Option(kit.MDB_CONTENT))
|
||||
}
|
||||
_push_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
COPY: {Name: "copy file from...", Help: "复制", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
_copy_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
LINK: {Name: "link file from", Help: "链接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
_link_file(m, arg[0], arg[1])
|
||||
}},
|
||||
DEFS: {Name: "defs file text...", Help: "默认", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
_defs_file(m, arg[0], arg[1:]...)
|
||||
}},
|
||||
},
|
||||
})
|
||||
}
|
62
base/nfs/tail.go
Normal file
62
base/nfs/tail.go
Normal file
@ -0,0 +1,62 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/cli"
|
||||
"github.com/shylinux/icebergs/base/mdb"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
func _tail_create(m *ice.Message, arg ...string) {
|
||||
if m.Option(kit.MDB_HASH) == "" {
|
||||
m.Option(kit.MDB_HASH, m.Cmdx(mdb.INSERT, TAIL, "", mdb.HASH, arg))
|
||||
}
|
||||
|
||||
kit.ForEach(kit.Split(m.Option(kit.MDB_FILE), ","), func(file string) {
|
||||
r, w := io.Pipe()
|
||||
m.Go(func() {
|
||||
for bio := bufio.NewScanner(r); bio.Scan(); {
|
||||
m.Log_IMPORT(kit.MDB_FILE, file, kit.MDB_SIZE, len(bio.Text()))
|
||||
m.Grow(TAIL, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_HASH)), kit.Dict(
|
||||
kit.MDB_FILE, file, kit.MDB_SIZE, len(bio.Text()), kit.MDB_TEXT, bio.Text(),
|
||||
))
|
||||
}
|
||||
})
|
||||
|
||||
m.Option(cli.CMD_STDOUT, w)
|
||||
m.Option(cli.CMD_STDERR, w)
|
||||
m.Option(mdb.CACHE_CLEAR_ON_EXIT, "true")
|
||||
m.Cmd(cli.DAEMON, TAIL, "-n", "0", "-f", file)
|
||||
})
|
||||
}
|
||||
|
||||
const TAIL = "tail"
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
TAIL: {Name: TAIL, Help: "跟踪", Value: kit.Data()},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
TAIL: {Name: "tail hash id auto create", Help: "跟踪", Action: map[string]*ice.Action{
|
||||
mdb.CREATE: {Name: "create file name", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
|
||||
_tail_create(m, arg...)
|
||||
}},
|
||||
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(mdb.DELETE, TAIL, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH))
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Option(mdb.FIELDS, kit.Select("time,hash,count,name,file", kit.Select("time,id,file,text", mdb.DETAIL, len(arg) > 1), len(arg) > 0))
|
||||
|
||||
if m.Cmdy(mdb.SELECT, TAIL, "", mdb.ZONE, arg); len(arg) == 0 {
|
||||
m.PushAction(mdb.REMOVE)
|
||||
} else if len(arg) == 1 {
|
||||
m.Option(ice.MSG_CONTROL, ice.CONTROL_PAGE)
|
||||
}
|
||||
}},
|
||||
},
|
||||
})
|
||||
}
|
56
base/nfs/trash.go
Normal file
56
base/nfs/trash.go
Normal file
@ -0,0 +1,56 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/cli"
|
||||
"github.com/shylinux/icebergs/base/mdb"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func _trash_create(m *ice.Message, name string) {
|
||||
if s, e := os.Stat(name); e == nil {
|
||||
if s.IsDir() {
|
||||
tar := path.Base(name) + ".tar.gz"
|
||||
m.Cmd(cli.SYSTEM, "tar", "zcf", tar, name)
|
||||
name = tar
|
||||
}
|
||||
|
||||
if f, e := os.Open(name); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
h := kit.Hashs(f)
|
||||
p := path.Join(m.Conf(TRASH, kit.META_PATH), h[:2], h)
|
||||
os.MkdirAll(path.Dir(p), ice.MOD_DIR)
|
||||
os.Rename(name, p)
|
||||
m.Cmdy(mdb.INSERT, TRASH, "", mdb.LIST, kit.MDB_FILE, p, kit.MDB_FROM, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TRASH = "trash"
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
TRASH: {Name: TRASH, Help: "删除", Value: kit.Data(kit.MDB_PATH, "var/trash")},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
TRASH: {Name: "trash file auto", Help: "删除", Action: map[string]*ice.Action{
|
||||
"recover": {Name: "recover", Help: "恢复", Hand: func(m *ice.Message, arg ...string) {
|
||||
os.Rename(m.Option(kit.MDB_FILE), m.Option(kit.MDB_FROM))
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Option(mdb.FIELDS, "time,id,file,from")
|
||||
m.Cmdy(mdb.SELECT, TRASH, "", mdb.LIST)
|
||||
m.PushAction("recover")
|
||||
return
|
||||
}
|
||||
_trash_create(m, arg[0])
|
||||
}},
|
||||
},
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user