├── data
├── BDManager
└── photos
│ └── BDManager
├── download_path
└── BDManager
├── autobd.sh
├── libs
├── redis.lua
├── serpent.lua
└── dkjson.lua
├── README.md
├── beyond.sh
├── plugins
├── plugins.lua
├── msg_checks.lua
├── fun.lua
├── tools.lua
└── banhammer.lua
├── bot
├── bot.lua
├── methods.lua
└── utils.lua
└── LICENSE
/data/BDManager:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/photos/BDManager:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/download_path/BDManager:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/autobd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | COUNTER=1
3 | while(true) do
4 | ./beyond.sh
5 | let COUNTER=COUNTER+1
6 | done
7 |
--------------------------------------------------------------------------------
/libs/redis.lua:
--------------------------------------------------------------------------------
1 | local Redis = (loadfile "./libs/lua-redis.lua")()
2 | local FakeRedis = (loadfile "./libs/fakeredis.lua")()
3 |
4 | local params = {
5 | host = '127.0.0.1',
6 | port = 6379,
7 | }
8 |
9 | -- Overwrite HGETALL
10 | Redis.commands.hgetall = Redis.command('hgetall', {
11 | response = function(reply, command, ...)
12 | local new_reply = { }
13 | for i = 1, #reply, 2 do new_reply[reply[i]] = reply[i + 1] end
14 | return new_reply
15 | end
16 | })
17 |
18 | local redis = nil
19 |
20 | -- Won't launch an error if fails
21 | local ok = pcall(function()
22 | redis = Redis.connect(params)
23 | end)
24 |
25 | if not ok then
26 |
27 | local fake_func = function()
28 | print('\27[31mCan\'t connect with Redis, install/configure it!\27[39m')
29 | end
30 | fake_func()
31 | fake = FakeRedis.new()
32 |
33 | print('\27[31mRedis addr: '..params.host..'\27[39m')
34 | print('\27[31mRedis port: '..params.port..'\27[39m')
35 |
36 | redis = setmetatable({fakeredis=true}, {
37 | __index = function(a, b)
38 | if b ~= 'data' and fake[b] then
39 | fake_func(b)
40 | end
41 | return fake[b] or fake_func
42 | end })
43 |
44 | end
45 |
46 |
47 | return redis
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [BDManager v2.0](https://t.me/BeyondTeam)
2 | An advanced administration bot based on BDMessenger
3 |
4 | [](https://core.telegram.org/bots/api)
5 | [](https://t.me/BeyondTeam)
6 |
7 | * * *
8 |
9 | ## Configure
10 |
11 | * Put Your Bot `TOKEN` At Line `3` in bot.lua
12 | * Put Your `Telegram ID` At Line `6 & 189` in bot.lua
13 | * Put Your `Channel ID` At Line `5` in bot.lua
14 |
15 | # Installation
16 |
17 | ```sh
18 | # Let's install the bot.
19 | cd $HOME
20 | git clone https://github.com/BeyondTeam/BDManager.git
21 | cd BDManager
22 | chmod +x beyond.sh
23 | ./beyond.sh install
24 | ./beyond.sh
25 |
26 |
27 | # For Auto Launch:
28 | chmod 777 autobd.sh
29 | tmux
30 | ./autobd.sh
31 | # End ;)
32 | ```
33 | ### One command
34 | To install everything in one command, use:
35 | ```sh
36 | cd $HOME && git clone https://github.com/BeyondTeam/BDManager.git && cd BDManager && chmod +x beyond.sh && ./beyond.sh install && ./beyond.sh
37 | ```
38 |
39 |
40 | # Support and Development
41 |
42 | More information [Beyond Global Chat](https://t.me/joinchat/AAAAAEGaKOxC8K6cJ3bCcw)
43 |
44 | # Special thanks to
45 |
46 | `Beyond Team Members`
47 |
48 | * * *
49 |
50 | # Developers!
51 |
52 | [SoLiD](https://github.com/solid021) ([Telegram](https://t.me/SoLiD))
53 |
54 | [MAKAN](https://github.com/makanj) ([Telegram](https://t.me/MAKAN))
55 |
56 | [ToOfan](https://github.com/To0fan) ([Telegram](https://t.me/ToOfan))
57 |
58 | [TheNIS](https://t.me/bypa3r)
59 |
60 | ### Our Telegram Channel:
61 |
62 | [@BeyondTeam](https://t.me/BeyondTeam)
63 |
64 | ### Our Forum:
65 |
66 | [Beyond Team Forum](https://Beyond-Dev.ir)
67 |
--------------------------------------------------------------------------------
/beyond.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | THIS_DIR=$(cd $(dirname $0); pwd)
4 | cd $THIS_DIR
5 |
6 | install() {
7 | sudo apt-get update -y
8 | sudo apt-get upgrade -y
9 | sudo apt-get install lua5.1 lua-socket lua-sec redis-server curl -y
10 | sudo apt-get install libreadline-dev libssl-dev lua5.2 luarocks liblua5.2-dev curl libcurl4-gnutls-dev -y
11 | git clone http://github.com/keplerproject/luarocks
12 | cd luarocks
13 | ./configure --lua-version=5.2
14 | make build
15 | sudo make install
16 | sudo luarocks install Lua-cURL
17 | sudo luarocks install oauth
18 | sudo luarocks install redis-lua
19 | sudo luarocks install lua-cjson
20 | sudo luarocks install ansicolors
21 | sudo luarocks install serpent
22 | cd ..
23 | }
24 |
25 | function print_logo() {
26 | green " ____ ____ _____"
27 | green " | _ )| _ \ |_ _|___ ____ __ __"
28 | green " | _ \| |_) ) | |/ .__| _ \_| \/ |"
29 | green " |____/|____/ |_|\____/\_____|_/\/\_|"
30 | echo -e "\n\e[0m"
31 | }
32 |
33 | function logo_play() {
34 | declare -A txtlogo
35 | seconds="0.010"
36 | txtlogo[1]=" ____ ____ _____"
37 | txtlogo[2]="| _ )| _ \ |_ _|___ ____ __ __"
38 | txtlogo[3]="| _ \| |_) ) | |/ .__| _ \_| \/ |"
39 | txtlogo[4]="|____/|____/ |_|\____/\_____|_/\/\_|"
40 | printf "\e[31m\t"
41 | for i in ${!txtlogo[@]}; do
42 | for x in `seq 0 ${#txtlogo[$i]}`; do
43 | printf "${txtlogo[$i]:$x:1}"
44 | sleep $seconds
45 | done
46 | printf "\n\t"
47 | done
48 | printf "\n"
49 | echo -e "\e[0m"
50 | }
51 |
52 | function beyondteam() {
53 | echo -e "\e[0m"
54 | green " >>>> We Are Not Attacker "
55 | green " >>>> We Are Not Alliance "
56 | white " >>>> We Are Programmer "
57 | white " >>>> We Are The Best "
58 | red " >>>> We Are Family "
59 | red " >>>> @BeyondTeam "
60 | echo -e "\e[0m"
61 | }
62 |
63 | red() {
64 | printf '\e[1;31m%s\n\e[0;39;49m' "$@"
65 | }
66 | green() {
67 | printf '\e[1;32m%s\n\e[0;39;49m' "$@"
68 | }
69 | white() {
70 | printf '\e[1;37m%s\n\e[0;39;49m' "$@"
71 | }
72 | update() {
73 | git pull
74 | }
75 |
76 | if [ "$1" = "install" ]; then
77 | print_logo
78 | beyondteam
79 | logo_play
80 | install
81 | elif [ "$1" = "update" ]; then
82 | logo_play
83 | beyondteam
84 | update
85 | exit 1
86 | else
87 | print_logo
88 | beyondteam
89 | logo_play
90 | green "Beyond Manager Bot running..."
91 | lua ./bot/bot.lua
92 | fi
93 |
--------------------------------------------------------------------------------
/plugins/plugins.lua:
--------------------------------------------------------------------------------
1 | do
2 |
3 | -- Returns the key (index) in the config.enabled_plugins table
4 | local function plugin_enabled( name )
5 | for k,v in pairs(_config.enabled_plugins) do
6 | if name == v then
7 | return k
8 | end
9 | end
10 | -- If not found
11 | return false
12 | end
13 |
14 | -- Returns true if file exists in plugins folder
15 | local function plugin_exists( name )
16 | for k,v in pairs(plugins_names()) do
17 | if name..'.lua' == v then
18 | return true
19 | end
20 | end
21 | return false
22 | end
23 |
24 | local function list_all_plugins(only_enabled)
25 | local tmp = '\n\n[BeyondTeam](Telegram.Me/BeyondTeam)'
26 | local text = ''
27 | local nsum = 0
28 | for k, v in pairs( plugins_names( )) do
29 | -- ✔ enabled, ❌ disabled
30 | local status = '*|✖️|>*'
31 | nsum = nsum+1
32 | nact = 0
33 | -- Check if is enabled
34 | for k2, v2 in pairs(_config.enabled_plugins) do
35 | if v == v2..'.lua' then
36 | status = '*|✔|>*'
37 | end
38 | nact = nact+1
39 | end
40 | if not only_enabled or status == '*|✔|>*'then
41 | -- get the name
42 | v = string.match (v, "(.*)%.lua")
43 | text = text..nsum..'.'..status..' '..check_markdown(v)..' \n'
44 | end
45 | end
46 | local text = text..'\n\n'..nsum..' *📂plugins installed*\n\n'..nact..' _✔️plugins enabled_\n\n'..nsum-nact..' _❌plugins disabled_\n\n[BeyondTeam](Telegram.Me/BeyondTeam)'
47 | return text
48 | end
49 |
50 | local function list_plugins(only_enabled)
51 | local text = ''
52 | local nsum = 0
53 | for k, v in pairs( plugins_names( )) do
54 | -- ✔ enabled, ❌ disabled
55 | local status = '*|✖️|>*'
56 | nsum = nsum+1
57 | nact = 0
58 | -- Check if is enabled
59 | for k2, v2 in pairs(_config.enabled_plugins) do
60 | if v == v2..'.lua' then
61 | status = '*|✔|>*'
62 | end
63 | nact = nact+1
64 | end
65 | if not only_enabled or status == '*|✔|>*'then
66 | -- get the name
67 | v = string.match (v, "(.*)%.lua")
68 | -- text = text..v..' '..status..'\n'
69 | end
70 | end
71 | local text = text.."\n_🔃All Plugins Reloaded_\n\n"..nact.." *✔️Plugins Enabled*\n"..nsum.." *📂Plugins Installed*\n\n[BeyondTeam](Telegram.Me/BeyondTeam)"
72 | return text
73 | end
74 |
75 | local function reload_plugins( )
76 | bot_run()
77 | plugins = {}
78 | load_plugins()
79 | return list_plugins(true)
80 | end
81 |
82 |
83 | local function enable_plugin( plugin_name )
84 | print('checking if '..plugin_name..' exists')
85 | -- Check if plugin is enabled
86 | if plugin_enabled(plugin_name) then
87 | return ''..plugin_name..' _is enabled_'
88 | end
89 | -- Checks if plugin exists
90 | if plugin_exists(plugin_name) then
91 | -- Add to the config table
92 | table.insert(_config.enabled_plugins, plugin_name)
93 | print(plugin_name..' added to _config table')
94 | save_config()
95 | -- Reload the plugins
96 | return reload_plugins( )
97 | else
98 | return ''..plugin_name..' _does not exists_'
99 | end
100 | end
101 |
102 | local function disable_plugin( name, chat )
103 | -- Check if plugins exists
104 | if not plugin_exists(name) then
105 | return ' '..name..' _does not exists_'
106 | end
107 | local k = plugin_enabled(name)
108 | -- Check if plugin is enabled
109 | if not k then
110 | return ' '..name..' _not enabled_'
111 | end
112 | -- Disable and reload
113 | table.remove(_config.enabled_plugins, k)
114 | save_config( )
115 | return reload_plugins(true)
116 | end
117 |
118 | local function disable_plugin_on_chat(receiver, plugin)
119 | if not plugin_exists(plugin) then
120 | return "_Plugin doesn't exists_"
121 | end
122 |
123 | if not _config.disabled_plugin_on_chat then
124 | _config.disabled_plugin_on_chat = {}
125 | end
126 |
127 | if not _config.disabled_plugin_on_chat[receiver] then
128 | _config.disabled_plugin_on_chat[receiver] = {}
129 | end
130 |
131 | _config.disabled_plugin_on_chat[receiver][plugin] = true
132 |
133 | save_config()
134 | return ' '..plugin..' _disabled on this chat_'
135 | end
136 |
137 | local function reenable_plugin_on_chat(receiver, plugin)
138 | if not _config.disabled_plugin_on_chat then
139 | return 'There aren\'t any disabled plugins'
140 | end
141 |
142 | if not _config.disabled_plugin_on_chat[receiver] then
143 | return 'There aren\'t any disabled plugins for this chat'
144 | end
145 |
146 | if not _config.disabled_plugin_on_chat[receiver][plugin] then
147 | return '_This plugin is not disabled_'
148 | end
149 |
150 | _config.disabled_plugin_on_chat[receiver][plugin] = false
151 | save_config()
152 | return ' '..plugin..' is enabled again'
153 | end
154 |
155 | local function run(msg, matches)
156 | -- Show the available plugins
157 | if is_sudo(msg) then
158 | if matches[1]:lower() == 'plist' then --after changed to moderator mode, set only sudo
159 | return list_all_plugins()
160 | end
161 | end
162 | -- Re-enable a plugin for this chat
163 | if matches[1] == 'pl' then
164 | if matches[2] == '+' and matches[4] == 'chat' then
165 | if is_momod(msg) then
166 | local receiver = msg.to.id
167 | local plugin = matches[3]
168 | print("enable "..plugin..' on this chat')
169 | return reenable_plugin_on_chat(receiver, plugin)
170 | end
171 | end
172 |
173 | -- Enable a plugin
174 | if matches[2] == '+' and is_sudo(msg) then --after changed to moderator mode, set only sudo
175 | if is_mod(msg) then
176 | local plugin_name = matches[3]
177 | print("enable: "..matches[3])
178 | return enable_plugin(plugin_name)
179 | end
180 | end
181 | -- Disable a plugin on a chat
182 | if matches[2] == '-' and matches[4] == 'chat' then
183 | if is_mod(msg) then
184 | local plugin = matches[3]
185 | local receiver = msg.to.id
186 | print("disable "..plugin..' on this chat')
187 | return disable_plugin_on_chat(receiver, plugin)
188 | end
189 | end
190 | -- Disable a plugin
191 | if matches[2] == '-' and is_sudo(msg) then --after changed to moderator mode, set only sudo
192 | if matches[3] == 'plugins' then
193 | return 'This plugin can\'t be disabled'
194 | end
195 | print("disable: "..matches[3])
196 | return disable_plugin(matches[3])
197 | end
198 | if matches[2] == '*' and is_sudo(msg) then --after changed to moderator mode, set only sudo
199 | return reload_plugins(true)
200 | end
201 | end
202 | -- Reload all the plugins!
203 | if matches[1]:lower() == 'reload' and is_sudo(msg) then --after changed to moderator mode, set only sudo
204 | return reload_plugins(true)
205 | end
206 | end
207 |
208 | return {
209 | description = "Plugin to manage other plugins. Enable, disable or reload.",
210 | usage = {
211 | moderator = {
212 | "!plug disable [plugin] chat : disable plugin only this chat.",
213 | "!plug enable [plugin] chat : enable plugin only this chat.",
214 | },
215 | sudo = {
216 | "!plist : list all plugins.",
217 | "!pl + [plugin] : enable plugin.",
218 | "!pl - [plugin] : disable plugin.",
219 | "!pl * : reloads all plugins." },
220 | },
221 | patterns = {
222 | "^[!/](plist)$",
223 | "^[!/](pl) (+) ([%w_%.%-]+)$",
224 | "^[!/](pl) (-) ([%w_%.%-]+)$",
225 | "^[!/](pl) (+) ([%w_%.%-]+) (chat)",
226 | "^[!/](pl) (-) ([%w_%.%-]+) (chat)",
227 | "^[!/](pl) (*)$",
228 | "^[!/](reload)$"
229 | },
230 | run = run
231 | }
232 |
233 | end
234 |
235 |
--------------------------------------------------------------------------------
/libs/serpent.lua:
--------------------------------------------------------------------------------
1 | local n, v = "serpent", 0.28 -- (C) 2012-15 Paul Kulchenko; MIT License
2 | local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
3 | local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
4 | local badtype = {thread = true, userdata = true, cdata = true}
5 | local keyword, globals, G = {}, {}, (_G or _ENV)
6 | for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
7 | 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
8 | 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
9 | for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
10 | for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
11 | for k,v in pairs(G[g] or {}) do globals[v] = g..'.'..k end end
12 |
13 | local function s(t, opts)
14 | local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
15 | local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
16 | local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
17 | local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge)
18 | local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0
19 | local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)",
20 | -- tostring(val) is needed because __tostring may return a non-string value
21 | function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end
22 | local function safestr(s) return type(s) == "number" and tostring(huge and snum[tostring(s)] or s)
23 | or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
24 | or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
25 | local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
26 | local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
27 | and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end
28 | local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
29 | local n = name == nil and '' or name
30 | local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
31 | local safe = plain and n or '['..safestr(n)..']'
32 | return (path or '')..(plain and path and '.' or '')..safe, safe end
33 | local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding
34 | local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
35 | local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end
36 | table.sort(k, function(a,b)
37 | -- sort numeric keys first: k[key] is not nil for numerical keys
38 | return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
39 | < (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
40 | local function val2str(t, name, indent, insref, path, plainindex, level)
41 | local ttype, level, mt = type(t), (level or 0), getmetatable(t)
42 | local spath, sname = safename(path, name)
43 | local tag = plainindex and
44 | ((type(name) == "number") and '' or name..space..'='..space) or
45 | (name ~= nil and sname..space..'='..space or '')
46 | if seen[t] then -- already seen this element
47 | sref[#sref+1] = spath..space..'='..space..seen[t]
48 | return tag..'nil'..comment('ref', level) end
49 | if type(mt) == 'table' and (mt.__serialize or mt.__tostring) then -- knows how to serialize itself
50 | seen[t] = insref or spath
51 | if mt.__serialize then t = mt.__serialize(t) else t = tostring(t) end
52 | ttype = type(t) end -- new value falls through to be serialized
53 | if ttype == "table" then
54 | if level >= maxl then return tag..'{}'..comment('max', level) end
55 | seen[t] = insref or spath
56 | if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
57 | local maxn, o, out = math.min(#t, maxnum or #t), {}, {}
58 | for key = 1, maxn do o[key] = key end
59 | if not maxnum or #o < maxnum then
60 | local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables
61 | for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end
62 | if maxnum and #o > maxnum then o[maxnum+1] = nil end
63 | if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end
64 | local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output)
65 | for n, key in ipairs(o) do
66 | local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
67 | if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
68 | or opts.keyallow and not opts.keyallow[key]
69 | or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
70 | or sparse and value == nil then -- skipping nils; do nothing
71 | elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then
72 | if not seen[key] and not globals[key] then
73 | sref[#sref+1] = 'placeholder'
74 | local sname = safename(iname, gensym(key)) -- iname is table for local variables
75 | sref[#sref] = val2str(key,sname,indent,sname,iname,true) end
76 | sref[#sref+1] = 'placeholder'
77 | local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']'
78 | sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path))
79 | else
80 | out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1)
81 | end
82 | end
83 | local prefix = string.rep(indent or '', level)
84 | local head = indent and '{\n'..prefix..indent or '{'
85 | local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
86 | local tail = indent and "\n"..prefix..'}' or '}'
87 | return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level)
88 | elseif badtype[ttype] then
89 | seen[t] = insref or spath
90 | return tag..globerr(t, level)
91 | elseif ttype == 'function' then
92 | seen[t] = insref or spath
93 | local ok, res = pcall(string.dump, t)
94 | local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
95 | "((loadstring or load)("..safestr(res)..",'@serialized'))")..comment(t, level))
96 | return tag..(func or globerr(t, level))
97 | else return tag..safestr(t) end -- handle all other types
98 | end
99 | local sepr = indent and "\n" or ";"..space
100 | local body = val2str(t, name, indent) -- this call also populates sref
101 | local tail = #sref>1 and table.concat(sref, sepr)..sepr or ''
102 | local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or ''
103 | return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
104 | end
105 |
106 | local function deserialize(data, opts)
107 | local env = (opts and opts.safe == false) and G
108 | or setmetatable({}, {
109 | __index = function(t,k) return t end,
110 | __call = function(t,...) error("cannot call functions") end
111 | })
112 | local f, res = (loadstring or load)('return '..data, nil, nil, env)
113 | if not f then f, res = (loadstring or load)(data, nil, nil, env) end
114 | if not f then return f, res end
115 | if setfenv then setfenv(f, env) end
116 | return pcall(f)
117 | end
118 |
119 | local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
120 | return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
121 | load = deserialize,
122 | dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
123 | line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
124 | block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
125 |
--------------------------------------------------------------------------------
/bot/bot.lua:
--------------------------------------------------------------------------------
1 | package.path = package.path..';.luarocks/share/lua/5.2/?.lua;.luarocks/share/lua/5.2/?/init.lua'
2 | package.cpath = package.cpath..';.luarocks/lib/lua/5.2/?.so'
3 | bot_token = "Token"
4 | send_api = "https://api.telegram.org/bot"..bot_token
5 | BeyondTeam = -1001011351482
6 | sudo_id = 157059515
7 | http = require('socket.http')
8 | https = require('ssl.https')
9 | URL = require('socket.url')
10 | curl = require('cURL')
11 | ltn12 = require("ltn12")
12 | cUrl_Command = curl.easy{verbose = true}
13 | redis = (loadfile "./libs/redis.lua")()
14 | json = (loadfile "./libs/JSON.lua")()
15 | JSON = (loadfile "./libs/dkjson.lua")()
16 | serpent = (loadfile "./libs/serpent.lua")()
17 | require('./bot/methods')
18 | require('./bot/utils')
19 | -- @BeyondTeam
20 | function bot_run()
21 | bot = nil
22 | while not bot do
23 | bot = send_req(send_api.."/getMe")
24 | end
25 | bot = bot.result
26 | local runlog = bot.first_name.." [@"..bot.username.."]\nis run in: "..os.date("%F - %H:%M:%S")
27 | print(runlog)
28 | send_msg(sudo_id, runlog)
29 | last_update = last_update or 0
30 | last_cron = last_cron or os.time()
31 | startbot = true
32 | our_id = bot.id
33 | end
34 |
35 | function send_req(url)
36 | local dat, res = https.request(url)
37 | local tab = JSON.decode(dat)
38 | if res ~= 200 then return false end
39 | if not tab.ok then return false end
40 | return tab
41 | end
42 |
43 | function bot_updates(offset)
44 | local url = send_api.."/getUpdates?timeout=10"
45 | if offset then
46 | url = url.."&offset="..offset
47 | end
48 | return send_req(url)
49 | end
50 |
51 | function load_data(filename)
52 | local f = io.open(filename)
53 | if not f then
54 | return {}
55 | end
56 | local s = f:read('*all')
57 | f:close()
58 | local data = JSON.decode(s)
59 | return data
60 | end
61 |
62 | function save_data(filename, data)
63 | local s = JSON.encode(data)
64 | local f = io.open(filename, 'w')
65 | f:write(s)
66 | f:close()
67 | end
68 |
69 | function msg_valid(msg)
70 | local msg_time = os.time() - 60
71 | if msg.date < tonumber(msg_time) then
72 | print('\27[36m》》OLD MESSAGE《《\27[39m')
73 | return false
74 | end
75 | if is_silent_user(msg.from.id, msg.chat.id) then
76 | del_msg(msg.chat.id, tonumber(msg.message_id))
77 | return false
78 | end
79 | if is_banned(msg.from.id, msg.chat.id) then
80 | del_msg(msg.chat.id, tonumber(msg.message_id))
81 | kick_user(msg.from.id, msg.chat.id)
82 | return false
83 | end
84 | if is_gbanned(msg.from.id) then
85 | del_msg(msg.chat.id, tonumber(msg.message_id))
86 | kick_user(msg.from.id, msg.chat.id)
87 | return false
88 | end
89 | return true
90 | end
91 |
92 | -- Returns a table with matches or nil
93 | function match_pattern(pattern, text, lower_case)
94 | if text then
95 | local matches = {}
96 | if lower_case then
97 | matches = { string.match(text:lower(), pattern) }
98 | else
99 | matches = { string.match(text, pattern) }
100 | end
101 | if next(matches) then
102 | return matches
103 | end
104 | end
105 | -- nil
106 | end
107 | plugins = {}
108 | function match_plugins(msg)
109 | for name, plugin in pairs(plugins) do
110 | match_plugin(plugin, name, msg)
111 | end
112 | end
113 |
114 | function match_plugin(plugin, plugin_name, msg)
115 |
116 | -- Go over patterns. If one matches it's enough.
117 | if plugin.pre_process then
118 | --If plugin is for privileged users only
119 | local result = plugin.pre_process(msg)
120 | if result then
121 | print("pre process: ", plugin_name)
122 | end
123 | end
124 | for k, pattern in pairs(plugin.patterns) do
125 | local matches = match_pattern(pattern, msg.text or msg.caption or msg.query)
126 | if matches then
127 | if not is_BDChannel_member(msg.from.id, msg.chat.id, msg.message_id) then
128 | local hash = "group_lang:"..msg.chat.id
129 | local lang = redis:get(hash)
130 | keyboard = {}
131 | keyboard.inline_keyboard = {
132 | {
133 | {text= 'Beyond Team Channel' ,url = 'Telegram.Me/BeyondTeam'}
134 | }
135 | }
136 | if lang then
137 | tkey = '_ابتدا در کانال تیم بیوند عضو شوید و دوباره تلاش کنید_'
138 | else
139 | tkey = '_First Join To_ *Beyond Team Channel* _And Try Again_'
140 | end
141 | send_key(msg.chat.id, tkey, keyboard, msg.message_id, "md")
142 | return
143 | end
144 | print("msg matches: ", pattern)
145 | -- Function exists
146 | if plugin.run then
147 | -- If plugin is for privileged users only
148 | local result = plugin.run(msg, matches)
149 | if result then
150 | send_msg(msg.chat.id, result, msg.message_id, "md")
151 | end
152 | end
153 | end
154 | end
155 | end
156 | local function handle_inline_keyboards_cb(msg)
157 | msg.text = '###cb:'..msg.data
158 | msg.cb = true
159 | if msg.new_chat_member then
160 | msg.service = true
161 | msg.text = '###new_chat_member'
162 | end
163 | if msg.message then
164 | msg.old_text = msg.message.text
165 | msg.old_date = msg.message.date
166 | msg.message_id = msg.message.message_id
167 | msg.chat = msg.message.chat
168 | msg.message_id = msg.message.message_id
169 | msg.chat = msg.message.chat
170 | else -- if keyboard send via
171 | msg.chat = {type = 'inline', id = msg.from.id, title = msg.from.first_name}
172 | msg.message_id = msg.inline_message_id
173 | end
174 | msg.cb_id = msg.id
175 | msg.date = os.time()
176 | msg.message = nil
177 | msg.target_id = msg.data:match('.*:(-?%d+)')
178 | return get_var(msg)
179 | end
180 | -- Save the content of _config to config.lua
181 | function save_config( )
182 | serialize_to_file(_config, './data/config.lua')
183 | print ('saved config into ./data/config.lua')
184 | end
185 |
186 | -- Create a basic config.json file and saves it.
187 | function create_config( )
188 | io.write('\n\27[1;33m>> Input your Telegram ID for set Sudo :\27[0;39;49m')
189 | local SUDO = tonumber(io.read())
190 | if not tostring(SUDO):match('%d+') then
191 | SUDO = 157059515
192 | end
193 | -- A simple config with basic plugins and ourselves as privileged user
194 | config = {
195 | enabled_plugins = {
196 | "plugins",
197 | "msg_checks",
198 | "groupmanager",
199 | "tools",
200 | "banhammer",
201 | "fun"
202 | },
203 | sudo_users = {157059515, SUDO},--Sudo users
204 | master_id = SUDO,
205 | admins = {},
206 | disabled_channels = {},
207 | moderation = {data = './data/moderation.json'},
208 | info_text = [[*》Beyond Manager V2.0*
209 | `》An advanced administration bot based on` *BDMessenger*
210 |
211 | 》[Beyond Manager](https://github.com/BeyondTeam/BDManager)
212 |
213 | *》Admins :*
214 | *》Founder & Developer :* [SoLiD](Telegram.Me/SoLiD)
215 | _》Developer & Sponser :_ [MAKAN](Telegram.Me/MAKAN)
216 | _》Developer :_ [ToOfan](Telegram.Me/ToOfan)
217 | _》Developer :_ [TheNIS](Telegram.Me/bypa3r)
218 |
219 | *》Special thanks to :*
220 | `Beyond Team Members`
221 |
222 | *》Our channel :*
223 | 》[BeyondTeam](Telegram.Me/BeyondTeam)
224 |
225 | *》Our Site :*
226 | [Beyond Team Forum](beyond-dev.ir)
227 | ]],
228 | }
229 | serialize_to_file(config, './data/config.lua')
230 | print('saved config into ./data/config.lua')
231 | end
232 |
233 | -- Returns the config from config.lua file.
234 | -- If file doesn't exist, create it.
235 | function load_config( )
236 | local f = io.open('./data/config.lua', "r")
237 | -- If config.lua doesn't exist
238 | if not f then
239 | print ("Created new config file: data/config.lua")
240 | create_config()
241 | else
242 | f:close()
243 | end
244 | local config = loadfile ("./data/config.lua")()
245 | for v,user in pairs(config.sudo_users) do
246 | print("Sudo user: " .. user)
247 | end
248 | return config
249 | end
250 | _config = load_config( )
251 |
252 | -- Enable plugins in config.json
253 | function load_plugins()
254 | for k, v in pairs(_config.enabled_plugins) do
255 | print("Loading plugin", v)
256 |
257 | local ok, err = pcall(function()
258 | local t = loadfile("plugins/"..v..'.lua')()
259 | plugins[v] = t
260 | end)
261 |
262 | if not ok then
263 | print('\27[31mError loading plugin '..v..'\27[39m')
264 | print(tostring(io.popen("lua plugins/"..v..".lua"):read('*all')))
265 | print('\27[31m'..err..'\27[39m')
266 | end
267 |
268 | end
269 | end
270 |
271 | bot_run()
272 | load_plugins()
273 | while startbot do
274 | local res = bot_updates(last_update+1)
275 | if res then
276 | for i,v in ipairs(res.result) do
277 | last_update = v.update_id
278 | if v.edited_message then
279 | get_var(v.edited_message)
280 | elseif v.message then
281 | if msg_valid(v.message) then
282 | get_var(v.message)
283 | end
284 | elseif v.inline_query then
285 | get_var_inline(v.inline_query)
286 | elseif v.callback_query then
287 | handle_inline_keyboards_cb(v.callback_query)
288 | end
289 | end
290 | else
291 | print("error while")
292 | end
293 | if last_cron < os.time() - 30 then
294 | for name, plugin in pairs(plugins) do
295 | if plugin.cron then
296 | local res, err = pcall(
297 | function()
298 | plugin.cron()
299 | end
300 |
301 | )
302 | end
303 | if not res then print('error: '..err) end
304 | end
305 | last_cron = os.time()
306 | end
307 | end
308 |
309 |
310 |
--------------------------------------------------------------------------------
/plugins/msg_checks.lua:
--------------------------------------------------------------------------------
1 | --Begin msg_checks.lua By @SoLiD
2 | local function pre_process(msg)
3 | if not msg.query then
4 | local status = getChatAdministrators(msg.to.id)
5 | local data = load_data(_config.moderation.data)
6 | local chat = msg.to.id
7 | local user = msg.from.id
8 | local is_channel = msg.to.type == "supergroup"
9 | local is_chat = msg.to.type == "group"
10 | local auto_leave = 'AutoLeaveBot'
11 | local TIME_CHECK = 2
12 | if data[tostring(chat)] then
13 | if data[tostring(chat)]['settings']['time_check'] then
14 | TIME_CHECK = tonumber(data[tostring(chat)]['settings']['time_check'])
15 | end
16 | end
17 | if is_channel or is_chat then
18 | if msg.text then
19 | if msg.text:match("(.*)") then
20 | if not data[tostring(msg.to.id)] and not redis:get(auto_leave) and not is_admin(msg) then
21 | send_msg(msg.to.id, "_This Is Not One Of My_ *Groups*", nil, "md")
22 | leave_group(chat)
23 | end
24 | end
25 | end
26 | if data[tostring(chat)] and data[tostring(chat)]['mutes'] then
27 | mutes = data[tostring(chat)]['mutes']
28 | else
29 | return
30 | end
31 | if mutes.mute_all then
32 | mute_all = mutes.mute_all
33 | else
34 | mute_all = 'no'
35 | end
36 | if mutes.mute_gif then
37 | mute_gif = mutes.mute_gif
38 | else
39 | mute_gif = 'no'
40 | end
41 | if mutes.mute_photo then
42 | mute_photos = mutes.mute_photo
43 | else
44 | mute_photos = 'no'
45 | end
46 | if mutes.mute_sticker then
47 | mute_sticker = mutes.mute_sticker
48 | else
49 | mute_sticker = 'no'
50 | end
51 | if mutes.mute_contact then
52 | mute_contact = mutes.mute_contact
53 | else
54 | mute_contact = 'no'
55 | end
56 | if mutes.mute_text then
57 | mute_text = mutes.mute_text
58 | else
59 | mute_text = 'no'
60 | end
61 | if mutes.mute_forward then
62 | mute_forward = mutes.mute_forward
63 | else
64 | mute_forward = 'no'
65 | end
66 | if mutes.mute_location then
67 | mute_location = mutes.mute_location
68 | else
69 | mute_location = 'no'
70 | end
71 | if mutes.mute_document then
72 | mute_document = mutes.mute_document
73 | else
74 | mute_document = 'no'
75 | end
76 | if mutes.mute_voice then
77 | mute_voice = mutes.mute_voice
78 | else
79 | mute_voice = 'no'
80 | end
81 | if mutes.mute_audio then
82 | mute_audio = mutes.mute_audio
83 | else
84 | mute_audio = 'no'
85 | end
86 | if mutes.mute_video then
87 | mute_video = mutes.mute_video
88 | else
89 | mute_video = 'no'
90 | end
91 | if mutes.mute_tgservice then
92 | mute_tgservice = mutes.mute_tgservice
93 | else
94 | mute_tgservice = 'no'
95 | end
96 | if data[tostring(chat)] and data[tostring(chat)]['settings'] then
97 | settings = data[tostring(chat)]['settings']
98 | else
99 | return
100 | end
101 | if settings.lock_link then
102 | lock_link = settings.lock_link
103 | else
104 | lock_link = 'no'
105 | end
106 | if settings.lock_bots then
107 | lock_bot = settings.lock_bots
108 | else
109 | lock_bot = 'no'
110 | end
111 | if settings.lock_tag then
112 | lock_tag = settings.lock_tag
113 | else
114 | lock_tag = 'no'
115 | end
116 | if settings.lock_pin then
117 | lock_pin = settings.lock_pin
118 | else
119 | lock_pin = 'no'
120 | end
121 | if settings.lock_mention then
122 | lock_mention = settings.lock_mention
123 | else
124 | lock_mention = 'no'
125 | end
126 | if settings.lock_edit then
127 | lock_edit = settings.lock_edit
128 | else
129 | lock_edit = 'no'
130 | end
131 | if settings.lock_spam then
132 | lock_spam = settings.lock_spam
133 | else
134 | lock_spam = 'no'
135 | end
136 | if settings.flood then
137 | lock_flood = settings.flood
138 | else
139 | lock_flood = 'no'
140 | end
141 | if settings.lock_markdown then
142 | lock_markdown = settings.lock_markdown
143 | else
144 | lock_markdown = 'no'
145 | end
146 | if settings.lock_webpage then
147 | lock_webpage = settings.lock_webpage
148 | else
149 | lock_webpage = 'no'
150 | end
151 |
152 | if msg.newuser then
153 | if msg.newuser.username ~= nil then
154 | if string.sub(msg.newuser.username:lower(), -3) == 'bot' and not is_owner(msg) and lock_bot == "yes" then
155 | kick_user(msg.newuser.id, chat)
156 | end
157 | end
158 | end
159 | if msg.service and mute_tgservice == "yes" then
160 | del_msg(chat, tonumber(msg.id))
161 | end
162 | if not msg.cb and not is_mod(msg) and not is_whitelist(msg.from.id, msg.to.id) then
163 | if msg.pinned_message and is_channel then
164 | if lock_pin == "yes" and not is_owner(msg) then
165 | local pin_msg = data[tostring(msg.to.id)]['pin']
166 | if pin_msg then
167 | pinChatMessage(msg.to.id, pin_msg)
168 | elseif not pin_msg then
169 | unpinChatMessage(msg.to.id)
170 | end
171 | send_msg(msg.to.id, 'User ID : '..msg.from.id..'\nUsername : '..('@'..msg.from.username or 'No Username')..'\nYou Have Not Permission To Pin Message, Last Message Has Been Pinned Again', msg.id, "html")
172 | end
173 | end
174 | if msg.message_edited and lock_edit == "yes" then
175 | if is_channel then
176 | del_msg(chat, tonumber(msg.id))
177 | elseif is_chat then
178 | kick_user(user, chat)
179 | end
180 | end
181 | if msg.fwd_from and mute_forward == "yes" then
182 | if is_channel then
183 | del_msg(chat, tonumber(msg.id))
184 | elseif is_chat then
185 | kick_user(user, chat)
186 | end
187 | end
188 | if msg.photo and mute_photos == "yes" then
189 | if is_channel then
190 | del_msg(chat, tonumber(msg.id))
191 | elseif is_chat then
192 | kick_user(user, chat)
193 | end
194 | end
195 | if msg.video and mute_video == "yes" then
196 | if is_channel then
197 | del_msg(chat, tonumber(msg.id))
198 | elseif is_chat then
199 | kick_user(user, chat)
200 | end
201 | end
202 | if msg.document and mute_document == "yes" and msg.document.mime_type ~= "audio/mpeg" and msg.document.mime_type ~= "video/mp4" then
203 | if is_channel then
204 | del_msg(chat, tonumber(msg.id))
205 | elseif is_chat then
206 | kick_user(user, chat)
207 | end
208 | end
209 | if msg.sticker and mute_sticker == "yes" then
210 | if is_channel then
211 | del_msg(chat, tonumber(msg.id))
212 | elseif is_chat then
213 | kick_user(user, chat)
214 | end
215 | end
216 | if msg.document and msg.document.mime_type == "video/mp4" and mute_gif == "yes" then
217 | if is_channel then
218 | del_msg(chat, tonumber(msg.id))
219 | elseif is_chat then
220 | kick_user(user, chat)
221 | end
222 | end
223 | if msg.contact and mute_contact == "yes" then
224 | if is_channel then
225 | del_msg(chat, tonumber(msg.id))
226 | elseif is_chat then
227 | kick_user(user, chat)
228 | end
229 | end
230 | if msg.location and mute_location == "yes" then
231 | if is_channel then
232 | del_msg(chat, tonumber(msg.id))
233 | elseif is_chat then
234 | kick_user(user, chat)
235 | end
236 | end
237 | if msg.voice and mute_voice == "yes" then
238 | if is_channel then
239 | del_msg(chat, tonumber(msg.id))
240 | elseif is_chat then
241 | kick_user(user, chat)
242 | end
243 | end
244 | if msg.document and msg.document.mime_type == "audio/mpeg" and mute_audio == "yes" then
245 | if is_channel then
246 | del_msg(chat, tonumber(msg.id))
247 | elseif is_chat then
248 | kick_user(user, chat)
249 | end
250 | end
251 | if msg.caption then
252 | local link_caption = msg.caption:match("[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm].[Mm][Ee]/") or msg.caption:match("[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm].[Dd][Oo][Gg]/") or msg.caption:match("[Tt].[Mm][Ee]/") or msg.caption:match("[Tt][Ll][Gg][Rr][Mm].[Mm][Ee]/")
253 | if link_caption
254 | and lock_link == "yes" then
255 | if is_channel then
256 | del_msg(chat, tonumber(msg.id))
257 | elseif is_chat then
258 | kick_user(user, chat)
259 | end
260 | end
261 | local tag_caption = msg.caption:match("@") or msg.caption:match("#")
262 | if tag_caption and lock_tag == "yes" then
263 | if is_channel then
264 | del_msg(chat, tonumber(msg.id))
265 | elseif is_chat then
266 | kick_user(user, chat)
267 | end
268 | end
269 | if is_filter(msg, msg.caption) then
270 | if is_channel then
271 | del_msg(chat, tonumber(msg.id))
272 | elseif is_chat then
273 | kick_user(user, chat)
274 | end
275 | end
276 | end
277 | if msg.text then
278 | local _nl, ctrl_chars = string.gsub(msg.text, '%c', '')
279 | local max_chars = 40
280 | if data[tostring(msg.to.id)] then
281 | if data[tostring(msg.to.id)]['settings']['set_char'] then
282 | max_chars = tonumber(data[tostring(msg.to.id)]['settings']['set_char'])
283 | end
284 | end
285 | local _nl, real_digits = string.gsub(msg.text, '%d', '')
286 | local max_real_digits = tonumber(max_chars) * 50
287 | local max_len = tonumber(max_chars) * 51
288 | if lock_spam == "yes" then
289 | if string.len(msg.text) > max_len or ctrl_chars > max_chars or real_digits > max_real_digits then
290 | if is_channel then
291 | del_msg(chat, tonumber(msg.id))
292 | elseif is_chat then
293 | kick_user(user, chat)
294 | end
295 | end
296 | end
297 | local link_msg = msg.text:match("[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm].[Mm][Ee]/") or msg.text:match("[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm].[Dd][Oo][Gg]/") or msg.text:match("[Tt].[Mm][Ee]/") or msg.text:match("[Tt][Ll][Gg][Rr][Mm].[Mm][Ee]/")
298 | if link_msg
299 | and lock_link == "yes" then
300 | if is_channel then
301 | del_msg(chat, tonumber(msg.id))
302 | elseif is_chat then
303 | kick_user(user, chat)
304 | end
305 | end
306 | local tag_msg = msg.text:match("@") or msg.text:match("#")
307 | if tag_msg and lock_tag == "yes" then
308 | if is_channel then
309 | del_msg(chat, tonumber(msg.id))
310 | elseif is_chat then
311 | kick_user(user, chat)
312 | end
313 | end
314 | if is_filter(msg, msg.text) then
315 | if is_channel then
316 | del_msg(chat, tonumber(msg.id))
317 | elseif is_chat then
318 | kick_user(user, chat)
319 | end
320 | end
321 |
322 | if msg.text:match("(.*)")
323 | and mute_text == "yes" then
324 | if is_channel then
325 | del_msg(chat, tonumber(msg.id))
326 | elseif is_chat then
327 | kick_user(user, chat)
328 | end
329 | end
330 | end
331 | if mute_all == "yes" then
332 | if is_channel then
333 | del_msg(chat, tonumber(msg.id))
334 | elseif is_chat then
335 | kick_user(user, chat)
336 | end
337 | end
338 | if msg.entities then
339 | for i,entity in pairs(msg.entities) do
340 | if entity.type == "text_mention" then
341 | if lock_mention == "yes" then
342 | if is_channel then
343 | del_msg(chat, tonumber(msg.id))
344 | elseif is_chat then
345 | kick_user(user, chat)
346 | end
347 | end
348 | end
349 | if entity.type == "url" or entity.type == "text_link" then
350 | if lock_webpage == "yes" then
351 | if is_channel then
352 | del_msg(chat, tonumber(msg.id))
353 | elseif is_chat then
354 | kick_user(user, chat)
355 | end
356 | end
357 | end
358 | if entity.type == "bold" or entity.type == "code" or entity.type == "italic" then
359 | if lock_markdown == "yes" then
360 | if is_channel then
361 | del_msg(chat, tonumber(msg.id))
362 | elseif is_chat then
363 | kick_user(user, chat)
364 | end
365 | end
366 | end
367 | end
368 | end
369 | if msg.to.type ~= 'private' and not is_mod(msg) and not is_whitelist(msg.from.id, msg.to.id) then
370 | if lock_flood == "yes" then
371 | local hash = 'user:'..user..':msgs'
372 | local msgs = tonumber(redis:get(hash) or 0)
373 | local NUM_MSG_MAX = 5
374 | if data[tostring(chat)] then
375 | if data[tostring(chat)]['settings']['num_msg_max'] then
376 | NUM_MSG_MAX = tonumber(data[tostring(chat)]['settings']['num_msg_max'])
377 | end
378 | end
379 | if msgs > NUM_MSG_MAX then
380 | if msg.from.username then
381 | user_name = "@"..check_markdown(msg.from.username)
382 | else
383 | user_name = escape_markdown(msg.from.first_name)
384 | end
385 | if redis:get('sender:'..user..':flood') then
386 | return
387 | else
388 | del_msg(chat, msg.id)
389 | kick_user(user, chat)
390 | del_msg(chat, msg.id)
391 | send_msg(chat, "_User_ "..user_name.." `[ "..user.." ]` _has been_ *kicked* _because of_ *flooding*", nil, "md")
392 | redis:setex('sender:'..user..':flood', 30, true)
393 | end
394 | end
395 | redis:setex(hash, TIME_CHECK, msgs+1)
396 | end
397 | end
398 | end
399 | end
400 | end
401 | end
402 | return {
403 | patterns = {},
404 | pre_process = pre_process
405 | }
406 | --End msg_checks.lua @BeyondTeam
407 |
--------------------------------------------------------------------------------
/plugins/fun.lua:
--------------------------------------------------------------------------------
1 |
2 | --Begin Fun.lua By @BeyondTeam
3 | --Special Thx To @ToOfan
4 | --------------------------------
5 |
6 | local function run_bash(str)
7 | local cmd = io.popen(str)
8 | local result = cmd:read('*all')
9 | return result
10 | end
11 | --------------------------------
12 | local api_key = nil
13 | local base_api = "https://maps.googleapis.com/maps/api"
14 | --------------------------------
15 | local function get_latlong(area)
16 | local api = base_api .. "/geocode/json?"
17 | local parameters = "address=".. (URL.escape(area) or "")
18 | if api_key ~= nil then
19 | parameters = parameters .. "&key="..api_key
20 | end
21 | local res, code = https.request(api..parameters)
22 | if code ~=200 then return nil end
23 | local data = json:decode(res)
24 | if (data.status == "ZERO_RESULTS") then
25 | return nil
26 | end
27 | if (data.status == "OK") then
28 | lat = data.results[1].geometry.location.lat
29 | lng = data.results[1].geometry.location.lng
30 | acc = data.results[1].geometry.location_type
31 | types= data.results[1].types
32 | return lat,lng,acc,types
33 | end
34 | end
35 | --------------------------------
36 | local function get_staticmap(area)
37 | local api = base_api .. "/staticmap?"
38 | local lat,lng,acc,types = get_latlong(area)
39 | local scale = types[1]
40 | if scale == "locality" then
41 | zoom=8
42 | elseif scale == "country" then
43 | zoom=4
44 | else
45 | zoom = 13
46 | end
47 | local parameters =
48 | "size=600x300" ..
49 | "&zoom=" .. zoom ..
50 | "¢er=" .. URL.escape(area) ..
51 | "&markers=color:red"..URL.escape("|"..area)
52 | if api_key ~= nil and api_key ~= "" then
53 | parameters = parameters .. "&key="..api_key
54 | end
55 | return lat, lng, api..parameters
56 | end
57 | --------------------------------
58 | local function get_weather(msg, location)
59 | local hash = "group_lang:"..msg.to.id
60 | local lang = redis:get(hash)
61 | print("Finding weather in ", location)
62 | local BASE_URL = "http://api.openweathermap.org/data/2.5/weather"
63 | local url = BASE_URL
64 | url = url..'?q='..location..'&APPID=eedbc05ba060c787ab0614cad1f2e12b'
65 | url = url..'&units=metric'
66 | local b, c, h = http.request(url)
67 | if c ~= 200 then return nil end
68 | local weather = json:decode(b)
69 | local city = weather.name
70 | local country = weather.sys.country
71 | if not lang then
72 | temp = 'The temperature of '..city..' is now '..weather.main.temp..' ° C\n____________________'
73 | else
74 | temp = 'دمای شهر '..city..' هم اکنون '..weather.main.temp..' درجه سانتی گراد می باشد\n____________________'
75 | end
76 | if not lang then
77 | conditions = 'Current weather conditions : '
78 | else
79 | conditions = 'شرایط فعلی آب و هوا : '
80 | end
81 | if weather.weather[1].main == 'Clear' then
82 | if not lang then
83 | conditions = conditions .. 'Sunny☀'
84 | else
85 | conditions = conditions .. 'آفتابی☀'
86 | end
87 | elseif weather.weather[1].main == 'Clouds' then
88 | if not lang then
89 | conditions = conditions .. 'Cloudy ☁☁'
90 | else
91 | conditions = conditions .. 'ابری ☁☁'
92 | end
93 | elseif weather.weather[1].main == 'Rain' then
94 | if not lang then
95 | conditions = conditions .. 'Rainy ☔'
96 | else
97 | conditions = conditions .. 'بارانی ☔'
98 | end
99 | elseif weather.weather[1].main == 'Thunderstorm' then
100 | if not lang then
101 | conditions = conditions .. 'Stormy ☔☔☔☔'
102 | else
103 | conditions = conditions .. 'طوفانی ☔☔☔☔'
104 | end
105 | elseif weather.weather[1].main == 'Mist' then
106 | if not lang then
107 | conditions = conditions .. 'Mist 💨'
108 | else
109 | conditions = conditions .. 'مه 💨'
110 | end
111 | end
112 | return temp .. '\n' .. conditions..'\n@BeyondTeam'
113 | end
114 | --------------------------------
115 | local function calc(msg, exp)
116 | local hash = "group_lang:"..msg.to.id
117 | local lang = redis:get(hash)
118 | url = 'http://api.mathjs.org/v1/'
119 | url = url..'?expr='..URL.escape(exp)
120 | b,c = http.request(url)
121 | text = nil
122 | if c == 200 then
123 | if not lang then
124 | text = 'Result = '..b..'\n____________________\n@BeyondTeam'
125 | else
126 | text = 'نتیجه = '..b..'\n____________________\n@BeyondTeam'
127 | end
128 | elseif c == 400 then
129 | text = b
130 | else
131 | text = 'Unexpected error\n'
132 | ..'Is api.mathjs.org up?'
133 | end
134 | return text
135 | end
136 | --------------------------------
137 | function run(msg, matches)
138 | local hash = "group_lang:"..msg.to.id
139 | local lang = redis:get(hash)
140 | if matches[1]:lower() == 'calc' and matches[2] then
141 | if msg.to.type == "private" then
142 | return
143 | end
144 | return calc(msg, matches[2])
145 | end
146 | --------------------------------
147 | if matches[1]:lower() == 'praytime' then
148 | if matches[2] then
149 | city = matches[2]
150 | elseif not matches[2] then
151 | city = 'Tehran'
152 | end
153 | local lat,lng,url = get_staticmap(city)
154 | local dumptime = run_bash('date +%s')
155 | local code = http.request('http://api.aladhan.com/timings/'..dumptime..'?latitude='..lat..'&longitude='..lng..'&timezonestring=Asia/Tehran&method=7')
156 | local jdat = json:decode(code)
157 | local data = jdat.data.timings
158 | if not lang then
159 | text = 'City: '..city
160 | text = text..'\nMorning Azan: '..data.Fajr
161 | text = text..'\nSunrise: '..data.Sunrise
162 | text = text..'\nNoon Azan: '..data.Dhuhr
163 | text = text..'\nSunset: '..data.Sunset
164 | text = text..'\nMaghrib Azan: '..data.Maghrib
165 | text = text..'\nIsha: '..data.Isha
166 | text = text.."\n@BeyondTeam"
167 | else
168 | text = 'شهر: '..city
169 | text = text..'\nاذان صبح: '..data.Fajr
170 | text = text..'\nطلوع آفتاب: '..data.Sunrise
171 | text = text..'\nاذان ظهر: '..data.Dhuhr
172 | text = text..'\nغروب آفتاب: '..data.Sunset
173 | text = text..'\nاذان مغرب: '..data.Maghrib
174 | text = text..'\nعشاء : '..data.Isha
175 | text = text.."\n@BeyondTeam"
176 | end
177 | return text
178 | end
179 | --------------------------------
180 | if matches[1] == 'tosticker' then
181 | if msg.reply_to_message then
182 | if msg.reply_to_message.photo then
183 | if msg.reply_to_message.photo[3] then
184 | fileid = msg.reply_to_message.photo[3].file_id
185 | elseif msg.reply_to_message.photo[2] then
186 | fileid = msg.reply_to_message.photo[2].file_id
187 | else
188 | fileid = msg.reply_to_message.photo[1].file_id
189 | end
190 | downloadFile(fileid, "./download_path/"..msg.to.id..".webp")
191 | sleep(1)
192 | sendDocument(msg.to.id, "./download_path/"..msg.to.id..".webp", msg.id, "@BeyondTeam")
193 | end
194 | end
195 | end
196 | --------------------------------
197 | if matches[1] == 'tophoto' then
198 | if msg.reply_to_message then
199 | if msg.reply_to_message.sticker then
200 | downloadFile(msg.reply_to_message.sticker.file_id, "./download_path/"..msg.to.id..".jpg")
201 | sleep(1)
202 | sendPhoto(msg.to.id, "./download_path/"..msg.to.id..".jpg", "@BeyondTeam", msg.id)
203 | end
204 | end
205 | end
206 | --------------------------------
207 | if matches[1]:lower() == 'weather' then
208 | city = matches[2]:lower()
209 | local wtext = get_weather(msg, city)
210 | if not wtext then
211 | if not lang then
212 | wtext = 'Imported location is not correct'
213 | else
214 | wtext = 'مکان وارد شده صحیح نیست'
215 | end
216 | end
217 | return wtext
218 | end
219 | --------------------------------
220 | if matches[1]:lower() == 'time' then
221 | local url , res = http.request('http://api.beyond-dev.ir/time/')
222 | if res ~= 200 then
223 | return "No connection"
224 | end
225 | local colors = {'blue','green','yellow','magenta','Orange','DarkOrange','red'}
226 | local fonts = {'mathbf','mathit','mathfrak','mathrm'}
227 | local jdat = json:decode(url)
228 | local url = 'http://latex.codecogs.com/png.download?'..'\\dpi{600}%20\\huge%20\\'..fonts[math.random(#fonts)]..'{{\\color{'..colors[math.random(#colors)]..'}'..jdat.ENtime..'}}'
229 | local file = download_to_file(url,'time.webp')
230 | sendDocument(msg.to.id, file, msg.id, "@BeyondTeam")
231 |
232 | end
233 | --------------------------------
234 | if matches[1]:lower() == 'voice' then
235 | local text = matches[2]
236 | textc = text:gsub(' ','.')
237 |
238 | if msg.to.type == 'private' then
239 | return nil
240 | else
241 | local url = "http://tts.baidu.com/text2audio?lan=en&ie=UTF-8&text="..textc
242 | local file = download_to_file(url,'BD-Manager.mp3')
243 | sendDocument(msg.to.id, file, msg.id, "@BeyondTeam")
244 | end
245 | end
246 |
247 | --------------------------------
248 | if matches[1]:lower() == 'tr' then
249 | local to = matches[2]
250 | local res, url = http.request('http://api.beyond-dev.ir/translate?from=.&to='..to..'&text='..URL.escape(matches[3])..'&simple=json')
251 | data = json:decode(res)
252 | if not lang then
253 | return 'Language : '..data.to..'\nTranslation : '..data.translate..'\n____________________\n@BeyondTeam'
254 | else
255 | return 'زبان : '..data.to..'\nترجمه : '..data.translate..'\n____________________\n@BeyondTeam'
256 | end
257 | end
258 | --------------------------------
259 | if matches[1]:lower() == 'short' then
260 | local longlink = http.request('http://api.beyond-dev.ir/shortLink?url='..matches[2])
261 | local shlink = json:decode(longlink)
262 | if shlink.status then
263 | if not lang then
264 | return 'Short Links:\nGoogle: '..(shlink.results.google or '')..'\nOpizo: '..(shlink.results.opizo or '')..'\nBitly: '..(shlink.results.bitly or '')..'\nYon: '..(shlink.results.yon or '')..'\nLlink: '..(shlink.results.llink or '')..'\nU2S: '..(shlink.results.u2s or '')..'\nShorte: '..(shlink.results.shorte or '')
265 | else
266 | return 'لینک های کوتاه شده :\nGoogle: '..(shlink.results.google or '')..'\nOpizo: '..(shlink.results.opizo or '')..'\nBitly: '..(shlink.results.bitly or '')..'\nYon: '..(shlink.results.yon or '')..'\nLlink: '..(shlink.results.llink or '')..'\nU2S: '..(shlink.results.u2s or '')..'\nShorte: '..(shlink.results.shorte or '')
267 | end
268 | else
269 | if not lang then
270 | return '_Input Correct Link!_'
271 | else
272 | return '_لینک صحیح را وارد کنید!_'
273 | end
274 | end
275 | end
276 | --------------------------------
277 | if matches[1]:lower() == 'sticker' then
278 | local eq = URL.escape(matches[2])
279 | local w = "500"
280 | local h = "500"
281 | local txtsize = "100"
282 | local txtclr = "ff2e4357"
283 | if matches[3] then
284 | txtclr = matches[3]
285 | end
286 | if matches[4] then
287 | txtsize = matches[4]
288 | end
289 | if matches[5] and matches[6] then
290 | w = matches[5]
291 | h = matches[6]
292 | end
293 | local url = "https://assets.imgix.net/examples/clouds.jpg?blur=150&w="..w.."&h="..h.."&fit=crop&txt="..eq.."&txtsize="..txtsize.."&txtclr="..txtclr.."&txtalign=middle,center&txtfont=Futura%20Condensed%20Medium&mono=ff6598cc"
294 | local receiver = msg.to.id
295 | local file = download_to_file(url,'text.webp')
296 | sendDocument(msg.to.id, file, msg.id, "@BeyondTeam")
297 | end
298 | --------------------------------
299 | if matches[1]:lower() == 'photo' then
300 | local eq = URL.escape(matches[2])
301 | local w = "500"
302 | local h = "500"
303 | local txtsize = "100"
304 | local txtclr = "ff2e4357"
305 | if matches[3] then
306 | txtclr = matches[3]
307 | end
308 | if matches[4] then
309 | txtsize = matches[4]
310 | end
311 | if matches[5] and matches[6] then
312 | w = matches[5]
313 | h = matches[6]
314 | end
315 | local url = "https://assets.imgix.net/examples/clouds.jpg?blur=150&w="..w.."&h="..h.."&fit=crop&txt="..eq.."&txtsize="..txtsize.."&txtclr="..txtclr.."&txtalign=middle,center&txtfont=Futura%20Condensed%20Medium&mono=ff6598cc"
316 | local receiver = msg.to.id
317 | local file = download_to_file(url,'text.jpg')
318 | sendPhoto(msg.to.id, file, "@BeyondTeam", msg.id)
319 | end
320 | if matches[1] == 'fal' then
321 | local url , res = http.request('http://api.beyond-dev.ir/fal')
322 | if res ~= 200 then return "No connection" end
323 | local jdat = json:decode(url)
324 | if not lang then
325 | fal = "*Poems*:\n"..jdat.poem.."\n\n*Interpretation:*\n"..jdat.mean..'\n\n@BeyondTeam'
326 | else
327 | fal = "_غزل:_\n"..jdat.poem.."\n\n_تعبیر فال:_\n"..jdat.mean..'\n\n@BeyondTeam'
328 | end
329 | return fal
330 | end
331 | if matches[1] == 'bazaar' or matches[1] == 'fibazaar' then
332 | if matches[1] == 'bazaar' then
333 | xurl = 'http://api.beyond-dev.ir/bazaar/?q='..URL.escape(matches[2])
334 | elseif matches[1] == 'fibazaar' then
335 | xurl = 'http://api.beyond-dev.ir/bazaar/?price=yes&q='..URL.escape(matches[2])
336 | end
337 | local url , res = http.request(xurl)
338 | if res ~= 200 then return "No connection" end
339 | local jdat = json:decode(url)
340 | if not lang then
341 | bazaar = "Results:\n"..jdat.information
342 | else
343 | bazaar = "نتایج:\n"..jdat.information
344 | end
345 | return check_markdown(bazaar)
346 | end
347 | --------------------------------
348 | if matches[1] == "helpfun" then
349 | if not lang then
350 | helpfun = [[
351 | _Beyond Manager Fun Help Commands:_
352 |
353 | *!time*
354 | _Get time in a sticker_
355 |
356 | *!short* `[link]`
357 | _Make short url_
358 |
359 | *!voice* `[text]`
360 | _Convert text to voice_
361 |
362 | *!tr* `[lang] [word]`
363 | _Translates multy languages_
364 | _Example:_
365 | *!tr fa hi*
366 |
367 | *!sticker* `[word]`
368 | _Convert text to sticker_
369 |
370 | *!photo* `[word]`
371 | _Convert text to photo_
372 |
373 | *!calc* `[number]`
374 | Calculator
375 |
376 | *!praytime* `[city]`
377 | _Get Patent (Pray Time)_
378 |
379 | *!tosticker* `[reply]`
380 | _Convert photo to sticker_
381 |
382 | *!tophoto* `[reply]`
383 | _Convert text to photo_
384 |
385 | *!weather* `[city]`
386 | _Get weather_
387 |
388 | *!bazaar* `[App Name]`
389 | _Search in CafeBazaar market_
390 |
391 | *!fibazaar* `[App Name]`
392 | _Search in CafeBazaar market with app price_
393 |
394 | *!fal*
395 | _Fale Hafez_
396 |
397 | _You can use_ *[!/#]* _at the beginning of commands._
398 |
399 | *Good luck ;)*]]
400 | else
401 |
402 | helpfun = [[
403 | _راهنمای فان ربات بیوند منیجر:_
404 |
405 | *!time*
406 | _دریافت ساعت به صورت استیکر_
407 |
408 | *!short* `[link]`
409 | _کوتاه کننده لینک_
410 |
411 | *!voice* `[text]`
412 | _تبدیل متن به صدا_
413 |
414 | *!tr* `[lang]` `[word]`
415 | _ترجمه به زبانهای مختلف_
416 | _مثال:_
417 | _!tr en سلام_
418 |
419 | *!sticker* `[word]`
420 | _تبدیل متن به استیکر_
421 |
422 | *!photo* `[word]`
423 | _تبدیل متن به عکس_
424 |
425 | *!calc* `[number]`
426 | _ماشین حساب_
427 |
428 | *!praytime* `[city]`
429 | _اعلام ساعات شرعی_
430 |
431 | *!tosticker* `[reply]`
432 | _تبدیل عکس به استیکر_
433 |
434 | *!tophoto* `[reply]`
435 | _تبدیل استیکربه عکس_
436 |
437 | *!weather* `[city]`
438 | _دریافت اب وهوا_
439 |
440 | *!bazaar* `[App Name]`
441 | _جستجو در برنامه های بازار_
442 |
443 | *!fibazaar* `[App Name]`
444 | _جستجو در برنامه های بازار با درج قیمت برنامه_
445 |
446 | *!fal*
447 | _فال حافظ_
448 |
449 | *شما میتوانید از [!/#] در اول دستورات برای اجرای آنها بهره بگیرید*
450 |
451 | موفق باشید ;)]]
452 | end
453 | return helpfun.."\n@BeyondTeam"
454 | end
455 |
456 | end
457 | --------------------------------
458 | return {
459 | patterns = {
460 | "^[!/#](helpfun)$",
461 | "^[!/#](weather) (.*)$",
462 | "^[!/#](calc) (.*)$",
463 | "^[#!/](time)$",
464 | "^[#!/](tophoto)$",
465 | "^[#!/](tosticker)$",
466 | "^[!/#](voice) +(.*)$",
467 | "^[/!#]([Pp]raytime) (.*)$",
468 | "^[/!#](praytime)$",
469 | "^[!/#]([Tt]r) ([^%s]+) (.*)$",
470 | "^[!/#]([Ss]hort) (.*)$",
471 | "^[!/#](photo) (.+)$",
472 | "^[!/#](sticker) (.+)$",
473 | '^[/!](fal)$',
474 | '^[/!](bazaar) (.*)$',
475 | '^[/!](fibazaar) (.*)$',
476 | },
477 | run = run,
478 | }
479 |
480 | --#by @BeyondTeam :)
481 |
--------------------------------------------------------------------------------
/bot/methods.lua:
--------------------------------------------------------------------------------
1 | -- @BeyondTeam
2 | function getUser(user_id)
3 | local url = http.request('https://www.api.beyond-dev.ir/getUser?token='..bot_token..'&user_id='..user_id)
4 | local user = JSON.decode(url)
5 | return user
6 | end
7 |
8 | function resolve_username(username)
9 | local url = http.request('https://www.api.beyond-dev.ir/getUser?token='..bot_token..'&username='..username)
10 | local user = JSON.decode(url)
11 | return user
12 | end
13 |
14 | function send_msg(chat_id, text, reply_to_message_id, markdown)
15 |
16 | local url = send_api .. '/sendMessage?chat_id=' .. chat_id .. '&text=' .. URL.escape(text)
17 |
18 | if reply_to_message_id then
19 | url = url .. '&reply_to_message_id=' .. reply_to_message_id
20 | end
21 |
22 | if markdown == 'md' or markdown == 'markdown' then
23 | url = url..'&parse_mode=Markdown'
24 | elseif markdown == 'html' then
25 | url = url..'&parse_mode=HTML'
26 | end
27 |
28 | return send_req(url)
29 |
30 | end
31 |
32 | function edit(chat_id, message_id, text, keyboard, markdown)
33 |
34 | local url = send_api .. '/editMessageText?chat_id=' .. chat_id .. '&message_id='..message_id..'&text=' .. URL.escape(text)
35 |
36 | if markdown then
37 | url = url .. '&parse_mode=Markdown'
38 | end
39 |
40 | url = url .. '&disable_web_page_preview=true'
41 |
42 | if keyboard then
43 | url = url..'&reply_markup='..JSON.encode(keyboard)
44 | end
45 |
46 | return send_req(url)
47 |
48 | end
49 | function send(chat_id, text, keyboard, markdown)
50 |
51 | local url = send_api.. '/sendMessage?chat_id=' .. chat_id
52 |
53 | if markdown then
54 | url = url .. '&parse_mode=Markdown'
55 | end
56 |
57 | url = url..'&text='..URL.escape(text)
58 |
59 | url = url..'&reply_markup='..JSON.encode(keyboard)
60 |
61 | return send_req(url)
62 |
63 | end
64 | function send_document(chat_id, name)
65 | local send = send_api.."/sendDocument"
66 | local curl_command = 'curl -s "'..send..'" -F "chat_id='..chat_id..'" -F "document=@'..name..'"'
67 | return io.popen(curl_command):read("*all")
68 | end
69 |
70 | function fwd_msg(chat_id, from_chat_id, message_id)
71 |
72 | local url = send_api .. '/forwardMessage?chat_id=' .. chat_id .. '&from_chat_id=' .. from_chat_id .. '&message_id=' .. message_id
73 |
74 | return send_req(url)
75 |
76 | end
77 | function edit_key(chat_id, message_id, reply_markup)
78 |
79 | local url = send_api .. '/editMessageReplyMarkup?chat_id=' .. chat_id ..
80 | '&message_id='..message_id..
81 | '&reply_markup='..URL.escape(JSON.encode(reply_markup))
82 |
83 | return send_req(url)
84 |
85 | end
86 | function send_key(chat_id, text, keyboard, reply_to_message_id, markdown)
87 |
88 | local url = send_api .. '/sendMessage?chat_id=' .. chat_id
89 |
90 | if reply_to_message_id then
91 | url = url .. '&reply_to_message_id=' .. reply_to_message_id
92 | end
93 |
94 | if markdown == 'md' or markdown == 'markdown' then
95 | url = url..'&parse_mode=Markdown'
96 | elseif markdown == 'html' then
97 | url = url..'&parse_mode=HTML'
98 | end
99 |
100 | url = url..'&text='..URL.escape(text)
101 |
102 | url = url..'&disable_web_page_preview=true'
103 |
104 | url = url..'&reply_markup='..URL.escape(JSON.encode(keyboard))
105 | return send_req(url)
106 | end
107 |
108 | function edit_msg(chat_id, message_id, text, keyboard, markdown)
109 |
110 | local url = send_api .. '/editMessageText?chat_id=' .. chat_id .. '&message_id='..message_id..'&text=' .. URL.escape(text)
111 |
112 | if markdown then
113 | url = url .. '&parse_mode=Markdown'
114 | end
115 |
116 | url = url .. '&disable_web_page_preview=true'
117 |
118 | if keyboard then
119 | url = url..'&reply_markup='..JSON.encode(keyboard)
120 | end
121 |
122 | return send_req(url)
123 |
124 | end
125 |
126 | function edit_inline(inline_message_id, text, keyboard)
127 | local urlk = send_api .. '/editMessageText?inline_message_id='..inline_message_id..'&text=' .. URL.escape(text)
128 | urlk = urlk .. '&parse_mode=Markdown'
129 | if keyboard then
130 | urlk = urlk..'&reply_markup='..URL.escape(json:encode(keyboard))
131 | end
132 | return send_req(urlk)
133 | end
134 |
135 | function get_alert(callback_query_id, text, show_alert)
136 |
137 | local url = send_api .. '/answerCallbackQuery?callback_query_id=' .. callback_query_id .. '&text=' .. URL.escape(text)
138 |
139 | if show_alert then
140 | url = url..'&show_alert=true'
141 | end
142 |
143 | return send_req(url)
144 |
145 | end
146 |
147 | function send_inline(inline_query_id, query_id , title , description , text , keyboard)
148 | local results = {{}}
149 | results[1].id = query_id
150 | results[1].type = 'article'
151 | results[1].description = description
152 | results[1].title = title
153 | results[1].message_text = text
154 | url = send_api .. '/answerInlineQuery?inline_query_id=' .. inline_query_id ..'&results=' .. URL.escape(json:encode(results))..'&parse_mode=Markdown&cache_time=' .. 1
155 | url = send_api .. '&parse_mode=Markdown'
156 | if keyboard then
157 | results[1].reply_markup = keyboard
158 | url = send_api .. '/answerInlineQuery?inline_query_id=' .. inline_query_id ..'&results=' .. URL.escape(json:encode(results))..'&parse_mode=Markdown&cache_time=' .. 1
159 | end
160 | return send_req(url)
161 | end
162 |
163 | function edit_key(chat_id, message_id, reply_markup)
164 |
165 | local url = send_api .. '/editMessageReplyMarkup?chat_id=' .. chat_id ..
166 | '&message_id='..message_id..
167 | '&reply_markup='..URL.escape(JSON.encode(reply_markup))
168 |
169 | return send_req(url)
170 |
171 | end
172 |
173 | function string:input()
174 | if not self:find(' ') then
175 | return false
176 | end
177 | return self:sub(self:find(' ')+1)
178 | end
179 |
180 | function serialize_to_file(data, file, uglify)
181 | file = io.open(file, 'w+')
182 | local serialized
183 | if not uglify then
184 | serialized = serpent.block(data, {
185 | comment = false,
186 | name = '_'
187 | })
188 | else
189 | serialized = serpent.dump(data)
190 | end
191 | file:write(serialized)
192 | file:close()
193 | end
194 |
195 | function is_sudo(msg)
196 | local var = false
197 | -- Check users id in config
198 | for v,user in pairs(_config.sudo_users) do
199 | if user == msg.from.id then
200 | var = true
201 | end
202 | end
203 | return var
204 | end
205 |
206 | function getChatMember(chat_id, user_id)
207 | local url = send_api .. '/getChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id
208 | return send_req(url)
209 | end
210 |
211 | function getChatAdministrators(chat_id)
212 | local url = send_api .. '/getChatAdministrators?chat_id=' .. chat_id
213 | return send_req(url)
214 | end
215 |
216 | function unbanChatMember(chat_id, user_id)
217 | local url = send_api .. '/unbanChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id
218 | return send_req(url)
219 | end
220 |
221 | function leave_group(chat_id)
222 | local url = send_api .. '/leaveChat?chat_id=' .. chat_id
223 | return send_req(url)
224 | end
225 |
226 | function del_msg(chat_id, message_id)
227 | local url = send_api..'/deletemessage?chat_id='..chat_id..'&message_id='..message_id
228 | return send_req(url)
229 | end
230 |
231 | function kick_user(user_id, chat_id)
232 | local url = send_api .. '/kickChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id
233 | return send_req(url)
234 | end
235 |
236 | function getChatMembersCount(chat_id)
237 |
238 | local url = send_api .. '/getChatMembersCount?chat_id=' .. chat_id
239 |
240 | return send_req(url)
241 |
242 | end
243 |
244 | function downloadFile(file_id, download_path)
245 |
246 | if not file_id then return nil, "file_id not specified" end
247 | if not download_path then return nil, "download_path not specified" end
248 |
249 | local response = {}
250 |
251 | local file_info = getFile(file_id)
252 | local download_file_path = download_path or "downloads/" .. file_info.result.file_path
253 |
254 | local download_file = io.open(download_file_path, "w")
255 |
256 | if not download_file then return nil, "download_file could not be created"
257 | else
258 | local success, code, headers, status = https.request{
259 | url = "https://api.telegram.org/file/bot" .. bot_token .. "/" .. file_info.result.file_path,
260 | --source = ltn12.source.string(body),
261 | sink = ltn12.sink.file(download_file),
262 | }
263 |
264 | local r = {
265 | success = true,
266 | download_path = download_file_path,
267 | file = file_info.result
268 | }
269 | return r
270 | end
271 | end
272 |
273 | function restrictChatMember(chat_id, user_id, can_send_messages, can_send_media_messages, can_send_other_messages, can_add_web_page_previews, until_date)
274 |
275 | local url = send_api .. '/restrictChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id
276 |
277 | if can_send_messages then
278 | url = url .. '&can_send_messages=true'
279 | else
280 | url = url .. '&can_send_messages=false'
281 | end
282 |
283 | if can_send_media_messages then
284 | url = url .. '&can_send_media_messages=true'
285 | else
286 | url = url .. '&can_send_media_messages=false'
287 | end
288 |
289 | if can_send_other_messages then
290 | url = url .. '&can_send_other_messages=true'
291 | else
292 | url = url .. '&can_send_other_messages=false'
293 | end
294 |
295 | if can_add_web_page_previews then
296 | url = url .. '&can_add_web_page_previews=true'
297 | else
298 | url = url .. '&can_add_web_page_previews=false'
299 | end
300 |
301 | if until_date then
302 | url = url .. '&until_date='..until_date
303 | end
304 | return send_req(url)
305 |
306 | end
307 |
308 | function restrictChatMember(chat_id, user_id, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, can_restrict_members, can_pin_messages, can_promote_members)
309 |
310 | local url = send_api .. '/restrictChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id
311 |
312 | if can_change_info then
313 | url = url .. '&can_change_info=true'
314 | else
315 | url = url .. '&can_change_info=false'
316 | end
317 |
318 | if can_post_messages then
319 | url = url .. '&can_post_messages=true'
320 | else
321 | url = url .. '&can_post_messages=false'
322 | end
323 |
324 | if can_edit_messages then
325 | url = url .. '&can_edit_messages=true'
326 | else
327 | url = url .. '&can_edit_messages=false'
328 | end
329 |
330 | if can_delete_messages then
331 | url = url .. '&can_delete_messages=true'
332 | else
333 | url = url .. '&can_delete_messages=false'
334 | end
335 |
336 | if can_invite_users then
337 | url = url .. '&can_invite_users=true'
338 | else
339 | url = url .. '&can_invite_users=false'
340 | end
341 |
342 | if can_restrict_members then
343 | url = url .. '&can_restrict_members=true'
344 | else
345 | url = url .. '&can_restrict_members=false'
346 | end
347 |
348 | if can_pin_messages then
349 | url = url .. '&can_pin_messages=true'
350 | else
351 | url = url .. '&can_pin_messages=false'
352 | end
353 |
354 | if can_promote_members then
355 | url = url .. '&can_promote_members=true'
356 | else
357 | url = url .. '&can_promote_members=false'
358 | end
359 | return send_req(url)
360 |
361 | end
362 |
363 | function exportChatInviteLink(chat_id)
364 |
365 | local url = send_api .. '/exportChatInviteLink?chat_id=' .. chat_id
366 | return send_req(url)
367 |
368 | end
369 |
370 | function setChatPhoto(chat_id, photo)
371 |
372 | local url = send_api .. '/setChatPhoto'
373 | cUrl_Command:setopt_url(url)
374 |
375 | local form = curl.form()
376 | form:add_content("chat_id", chat_id)
377 | form:add_file("photo", photo)
378 | data = {}
379 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
380 | :setopt_httppost(form)
381 | :perform()
382 | return table.concat(data), c:getinfo_response_code()
383 |
384 | end
385 |
386 | function deleteChatPhoto(chat_id)
387 |
388 | local url = send_api .. '/deleteChatPhoto?chat_id=' .. chat_id
389 | return send_req(url)
390 |
391 | end
392 |
393 | function setChatTitle(chat_id, title)
394 |
395 | local url = send_api .. '/setChatTitle?chat_id=' .. chat_id .. '&title=' .. URL.escape(title)
396 | return send_req(url)
397 |
398 | end
399 |
400 | function setChatDescription(chat_id, description)
401 |
402 | local url = send_api .. '/setChatDescription?chat_id=' .. chat_id .. '&description=' .. URL.escape(description)
403 | return send_req(url)
404 |
405 | end
406 |
407 | function pinChatMessage(chat_id, message_id, disable_notification)
408 |
409 | local url = send_api .. '/pinChatMessage?chat_id=' .. chat_id .. '&message_id=' .. message_id
410 | if disable_notification then
411 | url = url .. '&disable_notification=false'
412 | end
413 | return send_req(url)
414 |
415 | end
416 |
417 | function unpinChatMessage(chat_id)
418 |
419 | local url = send_api .. '/unpinChatMessage?chat_id=' .. chat_id
420 | return send_req(url)
421 |
422 | end
423 |
424 | function sendPhotoById(chat_id, file_id, reply_to_message_id, caption)
425 |
426 | local url = send_api .. '/sendPhoto?chat_id=' .. chat_id .. '&photo=' .. file_id
427 |
428 | if reply_to_message_id then
429 | url = url..'&reply_to_message_id='..reply_to_message_id
430 | end
431 | if caption then
432 | url = url..'&caption='..URL.escape(caption)
433 | end
434 |
435 | return send_req(url)
436 |
437 | end
438 |
439 | function sendPhoto(chat_id, photo, caption, reply_to_message_id, reply_markup, disable_notification)
440 |
441 | local url = send_api .. '/sendPhoto'
442 | cUrl_Command:setopt_url(url)
443 |
444 | local form = curl.form()
445 | form:add_content("chat_id", chat_id)
446 | form:add_file("photo", photo)
447 |
448 | if reply_to_message_id then
449 | form:add_content("reply_to_message_id", reply_to_message_id)
450 | end
451 |
452 | if caption then
453 | form:add_content("caption", caption)
454 | end
455 |
456 | if reply_markup then
457 | form:add_content("reply_markup", URL.escape(JSON.encode(reply_markup)))
458 | end
459 |
460 | if disable_notification then
461 | form:add_content("disable_notification", 'false')
462 | end
463 |
464 | data = {}
465 |
466 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
467 | :setopt_httppost(form)
468 | :perform()
469 |
470 | return table.concat(data), c:getinfo_response_code()
471 | end
472 |
473 | function sendAudio(chat_id, audio, reply_to_message_id, caption, title, duration, performer, reply_markup, disable_notification)
474 |
475 | local url = send_api .. '/sendAudio'
476 | cUrl_Command:setopt_url(url)
477 |
478 | local form = curl.form()
479 | form:add_content("chat_id", chat_id)
480 | form:add_file("audio", audio)
481 |
482 | if reply_to_message_id then
483 | form:add_content("reply_to_message_id", reply_to_message_id)
484 | end
485 |
486 | if caption then
487 | form:add_content("caption", caption)
488 | end
489 |
490 | if duration then
491 | form:add_content("duration", duration)
492 | end
493 |
494 | if performer then
495 | form:add_content("performer", performer)
496 | end
497 |
498 | if title then
499 | form:add_content("title", title)
500 | end
501 |
502 | if reply_markup then
503 | form:add_content("reply_markup", URL.escape(JSON.encode(reply_markup)))
504 | end
505 |
506 | if disable_notification then
507 | form:add_content("disable_notification", 'false')
508 | end
509 |
510 | data = {}
511 |
512 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
513 | :setopt_httppost(form)
514 | :perform()
515 |
516 | return table.concat(data), c:getinfo_response_code()
517 |
518 | end
519 |
520 | function sendDocument(chat_id, document, reply_to_message_id, caption, reply_markup, disable_notification)
521 |
522 | local url = send_api .. '/sendDocument'
523 | cUrl_Command:setopt_url(url)
524 |
525 | local form = curl.form()
526 | form:add_content("chat_id", chat_id)
527 | form:add_file("document", document)
528 |
529 | if reply_to_message_id then
530 | form:add_content("reply_to_message_id", reply_to_message_id)
531 | end
532 |
533 | if caption then
534 | form:add_content("caption", caption)
535 | end
536 |
537 | if reply_markup then
538 | form:add_content("reply_markup", URL.escape(JSON.encode(reply_markup)))
539 | end
540 |
541 | if disable_notification then
542 | form:add_content("disable_notification", 'false')
543 | end
544 |
545 | data = {}
546 |
547 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
548 | :setopt_httppost(form)
549 | :perform()
550 |
551 | return table.concat(data), c:getinfo_response_code()
552 |
553 | end
554 |
555 | function sendSticker(chat_id, sticker, reply_to_message_id, reply_markup, disable_notification)
556 |
557 | local url = send_api .. '/sendSticker'
558 | cUrl_Command:setopt_url(url)
559 |
560 | local form = curl.form()
561 | form:add_content("chat_id", chat_id)
562 | form:add_file("sticker", sticker)
563 |
564 | if reply_to_message_id then
565 | form:add_content("reply_to_message_id", reply_to_message_id)
566 | end
567 |
568 | if reply_markup then
569 | form:add_content("reply_markup", URL.escape(JSON.encode(reply_markup)))
570 | end
571 |
572 | if disable_notification then
573 | form:add_content("disable_notification", 'false')
574 | end
575 |
576 | data = {}
577 |
578 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
579 | :setopt_httppost(form)
580 | :perform()
581 |
582 | return table.concat(data), c:getinfo_response_code()
583 |
584 | end
585 |
586 | function sendVideo(chat_id, video, duration, caption, reply_to_message_id, reply_markup, width, height, disable_notification)
587 |
588 | local url = send_api .. '/sendVideo'
589 | cUrl_Command:setopt_url(url)
590 |
591 | local form = curl.form()
592 | form:add_content("chat_id", chat_id)
593 | form:add_file("video", video)
594 |
595 | if reply_to_message_id then
596 | form:add_content("reply_to_message_id", reply_to_message_id)
597 | end
598 |
599 | if duration then
600 | form:add_content("duration", duration)
601 | end
602 |
603 | if caption then
604 | form:add_content("caption", caption)
605 | end
606 |
607 | if reply_markup then
608 | form:add_content("reply_markup", URL.escape(JSON.encode(reply_markup)))
609 | end
610 |
611 | if width then
612 | form:add_content("width", width)
613 | end
614 |
615 | if height then
616 | form:add_content("height", height)
617 | end
618 | if disable_notification then
619 | form:add_content("disable_notification", 'false')
620 | end
621 | data = {}
622 |
623 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
624 | :setopt_httppost(form)
625 | :perform()
626 |
627 | return table.concat(data), c:getinfo_response_code()
628 |
629 | end
630 |
631 | function sendVoice(chat_id, voice, reply_to_message_id, caption, duration, reply_markup, disable_notification)
632 |
633 | local url = send_api .. '/sendVoice'
634 | cUrl_Command:setopt_url(url)
635 |
636 | local form = curl.form()
637 | form:add_content("chat_id", chat_id)
638 | form:add_file("voice", voice)
639 |
640 | if reply_to_message_id then
641 | form:add_content("reply_to_message_id", reply_to_message_id)
642 | end
643 |
644 | if caption then
645 | form:add_content("caption", caption)
646 | end
647 |
648 | if duration then
649 | form:add_content("duration", duration)
650 | end
651 |
652 | if reply_markup then
653 | form:add_content("reply_markup", URL.escape(JSON.encode(reply_markup)))
654 | end
655 | if disable_notification then
656 | form:add_content("disable_notification", 'false')
657 | end
658 | data = {}
659 |
660 | local c = cUrl_Command:setopt_writefunction(table.insert, data)
661 | :setopt_httppost(form)
662 | :perform()
663 |
664 | return table.concat(data), c:getinfo_response_code()
665 |
666 | end
667 |
668 | function sendLocation(chat_id, latitude, longitude, reply_to_message_id, reply_markup, disable_notification)
669 |
670 | local url = send_api .. '/sendLocation?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude
671 |
672 | if reply_to_message_id then
673 | url = url .. '&reply_to_message_id=' .. reply_to_message_id
674 | end
675 |
676 | if disable_notification then
677 | url = url .. '&disable_notification=false'
678 | end
679 |
680 | if reply_markup then
681 | url = url..'&reply_markup='..URL.escape(JSON.encode(reply_markup))
682 | end
683 |
684 | return send_req(url)
685 |
686 | end
687 |
688 | function sendContact(chat_id, phone_number, first_name, last_name, reply_to_message_id, reply_markup, disable_notification)
689 |
690 | local url = send_api.. '/sendContact?chat_id=' .. chat_id .. '&phone_number=' .. phone_number .. '&first_name=' .. first_name
691 |
692 | if last_name then
693 | url = url .. '&last_name=' .. last_name
694 | end
695 |
696 | if reply_to_message_id then
697 | url = url .. '&reply_to_message_id=' .. reply_to_message_id
698 | end
699 |
700 | if disable_notification then
701 | url = url .. '&disable_notification=false'
702 | end
703 |
704 | if reply_markup then
705 | url = url..'&reply_markup='..URL.escape(JSON.encode(reply_markup))
706 | end
707 |
708 | return send_req(url)
709 |
710 | end
711 |
712 | -- action = typing, upload_photo, record_video, upload_video, record_audio, upload_audio, upload_document, find_location
713 | function sendChatAction(chat_id, action)
714 |
715 | local url = send_api .. '/sendChatAction?chat_id=' .. chat_id .. '&action=' .. action
716 | return send_req(url)
717 |
718 | end
719 |
720 | function getUserProfilePhotos(user_id, offset, limit)
721 |
722 | local url = send_api .. '/getUserProfilePhotos?user_id='..user_id
723 | if offset then
724 | url = url..'&offset='..offset
725 | end
726 | if limit then
727 | if tonumber(limit) > 100 then
728 | limit = 100
729 | end
730 | url = url..'&limit='..limit
731 | end
732 | return send_req(url)
733 |
734 | end
735 |
736 | function getFile(file_id)
737 |
738 | local url = send_api .. '/getFile?file_id='..file_id
739 | return send_req(url)
740 |
741 | end
742 |
--------------------------------------------------------------------------------
/plugins/tools.lua:
--------------------------------------------------------------------------------
1 | -- @BeyondTeam
2 | local function getindex(t,id)
3 | for i,v in pairs(t) do
4 | if v == id then
5 | return i
6 | end
7 | end
8 | return nil
9 | end
10 |
11 | local function index_function(user_id)
12 | for k,v in pairs(_config.admins) do
13 | if user_id == v[1] then
14 | print(k)
15 | return k
16 | end
17 | end
18 | -- If not found
19 | return false
20 | end
21 |
22 | local function reload_plugins( )
23 | plugins = {}
24 | load_plugins()
25 | end
26 |
27 | --By @SoLiD021
28 | local function already_sudo(user_id)
29 | for k,v in pairs(_config.sudo_users) do
30 | if user_id == v then
31 | return k
32 | end
33 | end
34 | -- If not found
35 | return false
36 | end
37 |
38 | --By @SoLiD021
39 | local function already_admin(user_id)
40 | for k,v in pairs(_config.admins) do
41 | if user_id == v[1] then
42 | print(k)
43 | return k
44 | end
45 | end
46 | -- If not found
47 | return false
48 | end
49 |
50 | --By @SoLiD
51 | local function sudolist(msg)
52 | local hash = "group_lang:"..msg.to.id
53 | local lang = redis:get(hash)
54 | local sudo_users = _config.sudo_users
55 | if not lang then
56 | text = "*List of sudo users :*\n"
57 | else
58 | text = "_لیست سودو های ربات :_\n"
59 | end
60 | for i=1,#sudo_users do
61 | text = text..i.." - "..sudo_users[i].."\n"
62 | end
63 | return text
64 | end
65 |
66 | local function adminlist(msg)
67 | local hash = "group_lang:"..msg.to.id
68 | local lang = redis:get(hash)
69 | if not lang then
70 | text = "*List of bot admins :*\n"
71 | else
72 | text = "_لیست ادمین های ربات :_\n"
73 | end
74 | local compare = text
75 | local i = 1
76 | for v,user in pairs(_config.admins) do
77 | text = text..i..'- '..(user[2] or '')..' ➣ ('..user[1]..')\n'
78 | i = i +1
79 | end
80 | if compare == text then
81 | if not lang then
82 | text = '_No_ *admins* _available_'
83 | else
84 | text = '_هیچ ادمینی برای ربات تعیین نشده_'
85 | end
86 | end
87 | return text
88 | end
89 |
90 | local function chat_list(msg)
91 | local hash = "group_lang:"..msg.to.id
92 | local lang = redis:get(hash)
93 | i = 1
94 | local data = load_data(_config.moderation.data)
95 | local groups = 'groups'
96 | if not data[tostring(groups)] then
97 | if not lang then
98 | return '_No_ *groups* _at the moment_'
99 | else
100 | return '_هیچ گروهی ثبت نشده_'
101 | end
102 | end
103 | if not lang then
104 | message = '*List of Groups:*\n\n'
105 | else
106 | message = '_لیست گروه های ربات:_\n\n'
107 | end
108 | for k,v in pairsByKeys(data[tostring(groups)]) do
109 | local group_id = v
110 | if data[tostring(group_id)] then
111 | settings = data[tostring(group_id)]['settings']
112 | end
113 | for m,n in pairsByKeys(settings) do
114 | if m == 'set_name' then
115 | name = n:gsub("", "")
116 | chat_name = name:gsub("", "")
117 | group_name_id = name .. '\n(ID: ' ..group_id.. ')\n\n'
118 | if name:match("[\216-\219][\128-\191]") then
119 | group_info = i..' - \n'..group_name_id
120 | else
121 | group_info = i..' - '..group_name_id
122 | end
123 | i = i + 1
124 | end
125 | end
126 | message = message..group_info
127 | end
128 | return message
129 | end
130 |
131 | local function run(msg, matches)
132 | local hash = "group_lang:"..msg.to.id
133 | local lang = redis:get(hash)
134 | local data = load_data(_config.moderation.data)
135 | if matches[1] == "sudolist" and is_sudo(msg) then
136 | return sudolist(msg)
137 | end
138 | if tonumber(msg.from.id) == tonumber(sudo_id) then
139 | if matches[1] == "visudo" then
140 | if not matches[2] and msg.reply_to_message then
141 | if msg.reply.username then
142 | username = "@"..check_markdown(msg.reply.username)
143 | else
144 | username = escape_markdown(msg.reply.print_name)
145 | end
146 | if already_sudo(tonumber(msg.reply.id)) then
147 | if not lang then
148 | return "_User_ "..username.." `"..msg.reply.id.."` _is already_ *sudoer*"
149 | else
150 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _از قبل سودو ربات بود_"
151 | end
152 | else
153 | table.insert(_config.sudo_users, tonumber(msg.reply.id))
154 | print(msg.reply.id..' added to sudo users')
155 | save_config()
156 | reload_plugins(true)
157 | if not lang then
158 | return "_User_ "..username.." `"..msg.reply.id.."` _is now_ *sudoer*"
159 | else
160 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _به مقام سودو ربات منتصب شد_"
161 | end
162 | end
163 | elseif matches[2] and matches[2]:match('^%d+') then
164 | if not getUser(matches[2]).result then
165 | return "*User not found*"
166 | end
167 | local user_name = '@'..check_markdown(getUser(matches[2]).information.username)
168 | if not user_name then
169 | user_name = escape_markdown(getUser(matches[2]).information.first_name)
170 | end
171 | if already_sudo(tonumber(matches[2])) then
172 | if not lang then
173 | return "_User_ "..user_name.." `"..matches[2].."` _is already_ *sudoer*"
174 | else
175 | return "_کاربر_ "..user_name.." `"..matches[2].."` _از قبل سودو ربات بود_"
176 | end
177 | else
178 | table.insert(_config.sudo_users, tonumber(matches[2]))
179 | print(matches[2]..' added to sudo users')
180 | save_config()
181 | reload_plugins(true)
182 | if not lang then
183 | return "_User_ "..user_name.." `"..matches[2].."` _is now_ *sudoer*"
184 | else
185 | return "_کاربر_ "..user_name.." `"..matches[2].."` _به مقام سودو ربات منتصب شد_"
186 | end
187 | end
188 | elseif matches[2] and not matches[2]:match('^%d+') then
189 | if not resolve_username(matches[2]).result then
190 | return "*User not found*"
191 | end
192 | local status = resolve_username(matches[2])
193 | if already_sudo(tonumber(status.information.id)) then
194 | if not lang then
195 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _is already_ *sudoer*"
196 | else
197 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _از قبل سودو ربات بود_"
198 | end
199 | else
200 | table.insert(_config.sudo_users, tonumber(status.information.id))
201 | print(status.information.id..' added to sudo users')
202 | save_config()
203 | reload_plugins(true)
204 | if not lang then
205 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _is now_ *sudoer*"
206 | else
207 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _به مقام سودو ربات منتصب شد_"
208 | end
209 | end
210 | end
211 | end
212 | if matches[1] == "desudo" then
213 | if not matches[2] and msg.reply_to_message then
214 | if msg.reply.username then
215 | username = "@"..check_markdown(msg.reply.username)
216 | else
217 | username = escape_markdown(msg.reply.print_name)
218 | end
219 | if not already_sudo(tonumber(msg.reply.id)) then
220 | if not lang then
221 | return "_User_ "..username.." `"..msg.reply.id.."` _is not_ *sudoer*"
222 | else
223 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _از قبل سودو ربات نبود_"
224 | end
225 | else
226 | table.remove(_config.sudo_users, getindex( _config.sudo_users, tonumber(msg.reply.id)))
227 | save_config()
228 | reload_plugins(true)
229 | if not lang then
230 | return "_User_ "..username.." `"..msg.reply.id.."` _is no longer_ *sudoer*"
231 | else
232 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _از مقام سودو ربات برکنار شد_"
233 | end
234 | end
235 | elseif matches[2] and matches[2]:match('^%d+') then
236 | if not getUser(matches[2]).result then
237 | return "*User not found*"
238 | end
239 | local user_name = '@'..check_markdown(getUser(matches[2]).information.username)
240 | if not user_name then
241 | user_name = escape_markdown(getUser(matches[2]).information.first_name)
242 | end
243 | if not already_sudo(tonumber(matches[2])) then
244 | if not lang then
245 | return "_User_ "..user_name.." `"..matches[2].."` _is not_ *sudoer*"
246 | else
247 | return "_کاربر_ "..user_name.." `"..matches[2].."` _از قبل سودو ربات نبود_"
248 | end
249 | else
250 | table.remove(_config.sudo_users, getindex( _config.sudo_users, tonumber(matches[2])))
251 | save_config()
252 | reload_plugins(true)
253 | if not lang then
254 | return "_User_ "..user_name.." `"..matches[2].."` _is no longer_ *sudoer*"
255 | else
256 | return "_کاربر_ "..user_name.." `"..matches[2].."` _از مقام سودو ربات برکنار شد_"
257 | end
258 | end
259 | elseif matches[2] and not matches[2]:match('^%d+') then
260 | if not resolve_username(matches[2]).result then
261 | return "*User not found*"
262 | end
263 | local status = resolve_username(matches[2])
264 | if not already_sudo(tonumber(status.information.id)) then
265 | if not lang then
266 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _is not_ *sudoer*"
267 | else
268 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _از قبل سودو ربات نبود_"
269 | end
270 | else
271 | table.remove(_config.sudo_users, getindex( _config.sudo_users, tonumber(status.information.id)))
272 | save_config()
273 | reload_plugins(true)
274 | if not lang then
275 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _is no longer_ *sudoer*"
276 | else
277 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _از مقام سودو ربات برکنار شد_"
278 | end
279 | end
280 | end
281 | end
282 | end
283 | if is_sudo(msg) then
284 | if matches[1] == "adminprom" then
285 | if not matches[2] and msg.reply_to_message then
286 | if msg.reply.username then
287 | username = "@"..check_markdown(msg.reply.username)
288 | else
289 | username = escape_markdown(msg.reply.print_name)
290 | end
291 | if already_admin(tonumber(msg.reply.id)) then
292 | if not lang then
293 | return "_User_ "..username.." `"..msg.reply.id.."` _is already an_ *admin*"
294 | else
295 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _از قبل ادمین ربات بود_"
296 | end
297 | else
298 | table.insert(_config.admins, {tonumber(msg.reply.id), username})
299 | save_config()
300 | if not lang then
301 | return "_User_ "..username.." `"..msg.reply.id.."` _has been promoted as_ *admin*"
302 | else
303 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _به مقام ادمین ربات منتصب شد_"
304 | end
305 | end
306 | elseif matches[2] and matches[2]:match('^%d+') then
307 | if not getUser(matches[2]).result then
308 | return "*User not found*"
309 | end
310 | local user_name = '@'..check_markdown(getUser(matches[2]).information.username)
311 | if not user_name then
312 | user_name = escape_markdown(getUser(matches[2]).information.first_name)
313 | end
314 | if already_admin(tonumber(matches[2])) then
315 | if not lang then
316 | return "_User_ "..user_name.." `"..matches[2].."` _is already an_ *admin*"
317 | else
318 | return "_کاربر_ "..user_name.." `"..matches[2].."` _از قبل ادمین ربات بود_"
319 | end
320 | else
321 | table.insert(_config.admins, {tonumber(matches[2]), user_name})
322 | save_config()
323 | if not lang then
324 | return "_User_ "..user_name.." `"..matches[2].."` _has been promoted as_ *admin*"
325 | else
326 | return "_کاربر_ "..user_name.." `"..matches[2].."` _به مقام ادمین ربات منتصب شد_"
327 | end
328 | end
329 | elseif matches[2] and not matches[2]:match('^%d+') then
330 | if not resolve_username(matches[2]).result then
331 | return "*User not found*"
332 | end
333 | local status = resolve_username(matches[2])
334 | if already_admin(tonumber(status.information.id)) then
335 | if not lang then
336 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _is already an_ *admin*"
337 | else
338 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _از قبل ادمین ربات بود_"
339 | end
340 | else
341 | table.insert(_config.admins, {tonumber(status.information.id), '@'..check_markdown(status.information.username)})
342 | save_config()
343 | if not lang then
344 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _has been promoted as_ *admin*"
345 | else
346 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _به مقام ادمین ربات منتصب شد_"
347 | end
348 | end
349 | end
350 | end
351 | if matches[1] == "admindem" then
352 | if not matches[2] and msg.reply_to_message then
353 | if msg.reply.username then
354 | username = "@"..check_markdown(msg.reply.username)
355 | else
356 | username = escape_markdown(msg.reply.print_name)
357 | end
358 | if not already_admin(tonumber(msg.reply.id)) then
359 | if not lang then
360 | return "_User_ "..username.." `"..msg.reply.id.."` _is not_ *admin*"
361 | else
362 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _از قبل ادمین ربات نبود_"
363 | end
364 | else
365 | local nameid = index_function(tonumber(msg.reply.id))
366 | table.remove(_config.admins, nameid)
367 | save_config()
368 | if not lang then
369 | return "_User_ "..username.." `"..msg.reply.id.."` _has been demoted from_ *admin*"
370 | else
371 | return "_کاربر_ "..username.." `"..msg.reply.id.."` _از مقام ادمین ربات برکنار شد_"
372 | end
373 | end
374 | elseif matches[2] and matches[2]:match('^%d+') then
375 | if not getUser(matches[2]).result then
376 | return "*User not found*"
377 | end
378 | local user_name = '@'..check_markdown(getUser(matches[2]).information.username)
379 | if not user_name then
380 | user_name = escape_markdown(getUser(matches[2]).information.first_name)
381 | end
382 | if not already_admin(tonumber(matches[2])) then
383 | if not lang then
384 | return "_User_ "..user_name.." `"..matches[2].."` _is not_ *admin*"
385 | else
386 | return "_کاربر_ "..user_name.." `"..matches[2].."` _از قبل ادمین ربات نبود_"
387 | end
388 | else
389 | local nameid = index_function(tonumber(matches[2]))
390 | table.remove(_config.admins, nameid)
391 | save_config()
392 | if not lang then
393 | return "_User_ "..user_name.." `"..matches[2].."` _has been demoted from_ *admin*"
394 | else
395 | return "_کاربر_ "..user_name.." `"..matches[2].."` _از مقام ادمین ربات برکنار شد_"
396 | end
397 | end
398 | elseif matches[2] and not matches[2]:match('^%d+') then
399 | if not resolve_username(matches[2]).result then
400 | return "*User not found*"
401 | end
402 | local status = resolve_username(matches[2])
403 | if not already_admin(tonumber(status.information.id)) then
404 | if not lang then
405 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _is not_ *admin*"
406 | else
407 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _از قبل ادمین ربات نبود_"
408 | end
409 | else
410 | local nameid = index_function(tonumber(status.information.id))
411 | table.remove(_config.admins, nameid)
412 | save_config()
413 | if not lang then
414 | return "_User_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _has been demoted from_ *admin*"
415 | else
416 | return "_کاربر_ @"..check_markdown(status.information.username).." `"..status.information.id.."` _از مقام ادمین ربات برکنار شد_"
417 | end
418 | end
419 | end
420 | end
421 | end
422 | if is_sudo(msg) then
423 | if matches[1]:lower() == "sendfile" and matches[2] and matches[3] then
424 | local send_file = "./"..matches[2].."/"..matches[3]
425 | sendDocument(msg.to.id, send_file, msg.id, "@BeyondTeam")
426 | end
427 | if matches[1]:lower() == "sendplug" and matches[2] then
428 | local plug = "./plugins/"..matches[2]..".lua"
429 | sendDocument(msg.to.id, plug, msg.id, "@BeyondTeam")
430 | end
431 | if matches[1]:lower() == "savefile" and matches[2]then
432 | local fn = matches[2]:gsub('(.*)/', '')
433 | local pt = matches[2]:gsub('/'..fn..'$', '')
434 | if msg.reply_to_message then
435 | if msg.reply_to_message.photo then
436 | if msg.reply_to_message.photo[3] then
437 | fileid = msg.reply_to_message.photo[3].file_id
438 | elseif msg.reply_to_message.photo[2] then
439 | fileid = msg.reply_to_message.photo[2].file_id
440 | else
441 | fileid = msg.reply_to_message.photo[1].file_id
442 | end
443 | elseif msg.reply_to_message.sticker then
444 | fileid = msg.reply_to_message.sticker.file_id
445 | elseif msg.reply_to_message.voice then
446 | fileid = msg.reply_to_message.voice.file_id
447 | elseif msg.reply_to_message.video then
448 | fileid = msg.reply_to_message.video.file_id
449 | elseif msg.reply_to_message.document then
450 | fileid = msg.reply_to_message.document.file_id
451 | end
452 | downloadFile(fileid, "./"..pt.."/"..fn)
453 | if not lang then
454 | return "*File* `"..fn.."` _has been saved in_ *"..pt.."*"
455 | else
456 | return "_فایل_ `"..fn.."` _در پوشه_ *"..pt.."* _ذخیره شد_"
457 | end
458 | end
459 | end
460 | if matches[1]:lower() == "save" and matches[2] then
461 | if msg.reply_to_message then
462 | if msg.reply_to_message.document then
463 | fileid = msg.reply_to_message.document.file_id
464 | filename = msg.reply_to_message.document.file_name
465 | if tostring(filename):match(".lua") then
466 | downloadFile(fileid, "./plugins/"..matches[2]..".lua")
467 | if not lang then
468 | return "*Plugin* `"..matches[2]..".lua` _has been saved_"
469 | else
470 | return "_پلاگین_* `"..matches[2]..".lua` _با موفقیت ذخیره شد_"
471 | end
472 | end
473 | end
474 | end
475 | end
476 | if matches[1] == 'adminlist' and is_admin(msg) then
477 | return adminlist(msg)
478 | end
479 | if matches[1] == 'chats' and is_admin(msg) then
480 | return chat_list(msg)
481 | end
482 | if matches[1] == 'grem' and matches[2] and is_admin(msg) then
483 | local hashgp = "group_lang:"..matches[2]
484 | local langgp = redis:get(hashgp)
485 | local data = load_data(_config.moderation.data)
486 | -- Group configuration removal
487 | data[tostring(matches[2])] = nil
488 | save_data(_config.moderation.data, data)
489 | local groups = 'groups'
490 | if not data[tostring(groups)] then
491 | data[tostring(groups)] = nil
492 | save_data(_config.moderation.data, data)
493 | end
494 | data[tostring(groups)][tostring(matches[2])] = nil
495 | save_data(_config.moderation.data, data)
496 | if not langgp then
497 | send_msg(matches[2], "Group has been removed by admin command", nil, 'md')
498 | else
499 | send_msg(matches[2], "گروه به دستور ادمین و یا سودو ربات از لیست گروه های مدیریتی ربات حذف شد", nil, 'md')
500 | end
501 | if not lang then
502 | return '_Group_ *'..matches[2]..'* _removed_'
503 | else
504 | return '_گروه_ *'..matches[2]..'* _از لیست گروه های مدیریتی ربات حذف شد_'
505 | end
506 | end
507 | if matches[1] == 'leave' and is_admin(msg) then
508 | leave_group(msg.to.id)
509 | end
510 | if matches[1] == 'bc' and is_admin(msg) and matches[2] and matches[3] then
511 | local text = matches[2]
512 | send_msg(matches[3], text) end
513 | end
514 | if matches[1] == 'broadcast' and is_sudo(msg) then
515 | local data = load_data(_config.moderation.data)
516 | local bc = matches[2]
517 | for k,v in pairs(data) do
518 | send_msg(k, bc)
519 | end
520 | end
521 | if matches[1] == 'autoleave' and is_admin(msg) then
522 | local hash = 'AutoLeaveBot'
523 | --Enable Auto Leave
524 | if matches[2] == 'enable' then
525 | redis:del(hash)
526 | return 'Auto leave has been enabled'
527 | --Disable Auto Leave
528 | elseif matches[2] == 'disable' then
529 | redis:set(hash, true)
530 | return 'Auto leave has been disabled'
531 | --Auto Leave Status
532 | elseif matches[2] == 'status' then
533 | if not redis:get(hash) then
534 | return 'Auto leave is enable'
535 | else
536 | return 'Auto leave is disable'
537 | end
538 | end
539 | end
540 | ---------------Help Tools----------------
541 | if matches[1] == "helptools" and is_admin(msg) then
542 | local text = [[
543 |
544 | _Sudoer And Admins Beyond Bot Help :_
545 |
546 | *!visudo* `[username|id|reply]`
547 | _Add Sudo_
548 |
549 | *!desudo* `[username|id|reply]`
550 | _Demote Sudo_
551 |
552 | *!sudolist *
553 | _Sudo(s) list_
554 |
555 | *!adminprom* `[username|id|reply]`
556 | _Add admin for bot_
557 |
558 | *!admindem* `[username|id|reply]`
559 | _Demote bot admin_
560 |
561 | *!adminlist *
562 | _Admin(s) list_
563 |
564 | *!leave *
565 | _Leave current group_
566 |
567 | *!autoleave* `[disable/enable]`
568 | _Automatically leaves group_
569 |
570 | *!chats*
571 | _List of added groups_
572 |
573 | *!grem* `[id]`
574 | _Remove a group from Database_
575 |
576 | *!broadcast* `[text]`
577 | _Send message to all added groups_
578 |
579 | *!bc* `[text] [GroupID]`
580 | _Send message to a specific group_
581 |
582 | *!sendfile* `[folder] [file]`
583 | _Send file from folder_
584 |
585 | *!sendplug* `[plug]`
586 | _Send plugin_
587 |
588 | *!save* `[plugin name] [reply]`
589 | _Save plugin by reply_
590 |
591 | *!savefile* `[address/filename] [reply]`
592 | _Save File by reply to specific folder_
593 |
594 | _You can use_ *[!/]* _at the beginning of commands._
595 |
596 | `This help is only for sudoers/bot admins.`
597 |
598 | *This means only the sudoers and its bot admins can use mentioned commands.*
599 |
600 | *Good luck ;)*]]
601 |
602 | local fatext = [[
603 |
604 | _راهنمای سودو و مدیران ربات بیوند :_
605 |
606 | *!visudo* `[username|id|reply]`
607 | _ارتقا به مقام سودو_
608 |
609 | *!desudo* `[username|id|reply]`
610 | _حذف مقام سودو_
611 |
612 | *!sudolist *
613 | _لیست سودو_
614 |
615 | *!adminprom* `[username|id|reply]`
616 | _ارتقا به ادمین ربات_
617 |
618 | *!admindem* `[username|id|reply]`
619 | _حذف ادمین ربات_
620 |
621 | *!adminlist *
622 | _لیست ادمین_
623 |
624 | *!leave *
625 | _خروج ربات از گروه فعلی_
626 |
627 | *!autoleave* `[disable/enable]`
628 | _خروج خودکار_
629 |
630 | *!chats*
631 | _لیست گروههای ربات_
632 |
633 | *!grem* `[id]`
634 | _حذف گروه با ایدی از لیست گروههای ربات_
635 |
636 | *!broadcast* `[text]`
637 | _ارسال پیام همگانی به گروههای ربات_
638 |
639 | *!bc* `[text] [GroupID]`
640 | _ارسال پیام به گروه مورد نظر_
641 |
642 | *!sendfile* `[folder] [file]`
643 | _دریافت فابل از پوشه ربات_
644 |
645 | *!sendplug* `[plug]`
646 | _دریافت پلاگین های ربات_
647 |
648 | *!save* `[plugin name] [reply]`
649 | _ذخیره پلاگین در پوشه پلاگین ها_
650 |
651 | *!savefile* `[address/filename] [reply]`
652 | _ذخیره فایل در پوشه های ربات_
653 |
654 | *شما میتوانید از [/!] در اول دستورات برای اجرای آنها بهره بگیرید*
655 |
656 | _این راهنما فقط برای سودو ها/ادمین های ربات میباشد!_
657 |
658 | `این به این معناست که فقط سودو ها/ادمین های ربات میتوانند از دستورات بالا استفاده کنند!`
659 |
660 | *موفق باشید ;)*]]
661 | if lang then
662 | return fatext
663 | else
664 | return text
665 | end
666 | end
667 | end
668 | return {
669 | patterns = {
670 | "^[!/](helptools)$",
671 | "^[!/](visudo)$",
672 | "^[!/](desudo)$",
673 | "^[!/](visudo) (.*)$",
674 | "^[!/](desudo) (.*)$",
675 | "^[!/](sudolist)$",
676 | "^[!/](adminprom)$",
677 | "^[!/](admindem)$",
678 | "^[!/](adminprom) (.*)$",
679 | "^[!/](admindem) (.*)$",
680 | "^[!/](adminlist)$",
681 | "^[!/](chats)$",
682 | "^[!/](sendfile) (.*) (.*)$",
683 | "^[!/](savefile) (.*)$",
684 | "^[!/](bc) (.*) (-%d+)$",
685 | "^[!/](broadcast) (.*)$",
686 | "^[!/](sendplug) (.*)$",
687 | "^[!/](save) (.*)$",
688 | "^[!/](leave)$",
689 | "^[!/](autoleave) (.*)$",
690 | "^[!/](grem) (-%d+)$",
691 | },
692 | run = run,
693 | pre_process = pre_process
694 | }
695 |
696 | -- @BeyondTeam
697 |
--------------------------------------------------------------------------------
/plugins/banhammer.lua:
--------------------------------------------------------------------------------
1 | -- @BeyondTeam
2 | local function BeyondTeam(msg, matches)
3 | local hash = "group_lang:"..msg.to.id
4 | local lang = redis:get(hash)
5 | local data = load_data(_config.moderation.data)
6 | ----------------Kick ----------------
7 | if matches[1] == 'kick' and is_mod(msg) then
8 | if msg.reply_id then
9 | if tonumber(msg.reply.id) == tonumber(our_id) then
10 | if not lang then
11 | return "*I can't kick my self*"
12 | else
13 | return "_من قادر به اخراج کردن خود نیستم_"
14 | end
15 | end
16 | if is_mod1(msg.to.id, msg.reply.id) then
17 | if not lang then
18 | return "_You can't_ *kick* _mods, owners, bot admins_"
19 | else
20 | return "_شما نمیتوانید مدیران،صاحبان گروه و ادمین های ربات را اخراج کنید_"
21 | end
22 | else
23 | kick_user(msg.reply.id, msg.to.id)
24 | end
25 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
26 | if not resolve_username(matches[2]).result then
27 | if not lang then
28 | return "*User not found*"
29 | else
30 | return "_کاربر یافت نشد_"
31 | end
32 | end
33 | local User = resolve_username(matches[2]).information
34 | if tonumber(User.id) == tonumber(our_id) then
35 | if not lang then
36 | return "*I can't kick my self*"
37 | else
38 | return "_من قادر به اخراج کردن خود نیستم_"
39 | end
40 | end
41 | if is_mod1(msg.to.id, User.id) then
42 | if not lang then
43 | return "_You can't_ *kick* _mods, owners, bot admins_"
44 | else
45 | return "_شما نمیتوانید مدیران،صاحبان گروه و ادمین های ربات را اخراج کنید_"
46 | end
47 | else
48 | kick_user(User.id, msg.to.id)
49 | end
50 | elseif matches[2] and string.match(matches[2], '^%d+$') then
51 | if tonumber(matches[2]) == tonumber(our_id) then
52 | if not lang then
53 | return "*I can't kick my self*"
54 | else
55 | return "_من قادر به اخراج کردن خود نیستم_"
56 | end
57 | end
58 | if is_mod1(msg.to.id, tonumber(matches[2])) then
59 | if not lang then
60 | return "_You can't_ *kick* _mods, owners, bot admins_"
61 | else
62 | return "_شما نمیتوانید مدیران،صاحبان گروه و ادمین های ربات را اخراج کنید_"
63 | end
64 | else
65 | kick_user(tonumber(matches[2]), msg.to.id)
66 | end
67 | end
68 | end
69 |
70 | ---------------Ban-------------------
71 |
72 | if matches[1] == 'ban' and is_mod(msg) then
73 | if msg.reply_id then
74 | if msg.reply.username then
75 | un = "@"..check_markdown(msg.reply.username)
76 | else
77 | un = escape_markdown(msg.reply.print_name)
78 | end
79 | if tonumber(msg.reply.id) == tonumber(our_id) then
80 | if not lang then
81 | return "*I can't ban my self*"
82 | else
83 | return "_من قادر به محروم کردن خود از گروه نیستم_"
84 | end
85 | end
86 | if is_mod1(msg.to.id, msg.reply.id) then
87 | if not lang then
88 | return "_You can't_ *ban* _mods, owners, bot admins_"
89 | else
90 | return "_شما نمیتوانید مدیران،صاحبان گروه و ادمین های ربات را از گروه محروم کنید_"
91 | end
92 | end
93 | if is_banned(msg.reply.id, msg.to.id) then
94 | if not lang then
95 | return "_User_ "..un.." `"..msg.reply.id.."` _is already_ *banned*"
96 | else
97 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از گروه محروم بود_"
98 | end
99 | else
100 | ban_user(un, msg.reply.id, msg.to.id)
101 | kick_user(msg.reply.id, msg.to.id)
102 | if not lang then
103 | return "_User_ "..un.." `"..msg.reply.id.."` _has been_ *banned*"
104 | else
105 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از گروه محروم شد_"
106 | end
107 | end
108 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
109 | if not resolve_username(matches[2]).result then
110 | if not lang then
111 | return "*User not found*"
112 | else
113 | return "_کاربر یافت نشد_"
114 | end
115 | end
116 | local User = resolve_username(matches[2]).information
117 | if tonumber(User.id) == tonumber(our_id) then
118 | if not lang then
119 | return "*I can't ban my self*"
120 | else
121 | return "_من قادر به محروم کردن خود از گروه نیستم_"
122 | end
123 | end
124 | if is_mod1(msg.to.id, User.id) then
125 | if not lang then
126 | return "_You can't_ *ban* _mods, owners, bot admins_"
127 | else
128 | return "_شما نمیتوانید مدیران،صاحبان گروه و ادمین های ربات را از گروه محروم کنید_"
129 | end
130 | end
131 | if is_banned(User.id, msg.to.id) then
132 | if not lang then
133 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _is already_ *banned*"
134 | else
135 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از گروه محروم بود_"
136 | end
137 | else
138 | ban_user(check_markdown(User.username), User.id, msg.to.id)
139 | kick_user(User.id, msg.to.id)
140 | if not lang then
141 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _has been_ *banned*"
142 | else
143 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از گروه محروم شد_"
144 | end
145 | end
146 | elseif matches[2] and string.match(matches[2], '^%d+$') then
147 | if tonumber(matches[2]) == tonumber(our_id) then
148 | if not lang then
149 | return "*I can't ban my self*"
150 | else
151 | return "_من قادر به محروم کردن خود از گروه نیستم_"
152 | end
153 | end
154 | if is_mod1(msg.to.id, tonumber(matches[2])) then
155 | if not lang then
156 | return "_You can't_ *ban* _mods, owners, bot admins_"
157 | else
158 | return "_شما نمیتوانید مدیران،صاحبان گروه و ادمین های ربات را از گروه محروم کنید_"
159 | end
160 | end
161 | if is_banned(tonumber(matches[2]), msg.to.id) then
162 | if not lang then
163 | return "_User_ `"..matches[2].."` _is already_ *banned*"
164 | else
165 | return "_کاربر_ `"..matches[2].."` _از گروه محروم بود_"
166 | end
167 | else
168 | ban_user('', matches[2], msg.to.id)
169 | kick_user(tonumber(matches[2]), msg.to.id)
170 | if not lang then
171 | return "_User_ `"..matches[2].."` _has been_ *banned*"
172 | else
173 | return "_کاربر_ `"..matches[2].."` _از گروه محروم شد_"
174 | end
175 | end
176 | end
177 | end
178 |
179 | ---------------Unban-------------------
180 |
181 | if matches[1] == 'unban' and is_mod(msg) then
182 | if msg.reply_id then
183 | if msg.reply.username then
184 | un = "@"..check_markdown(msg.reply.username)
185 | else
186 | un = escape_markdown(msg.reply.print_name)
187 | end
188 | if not is_banned(msg.reply.id, msg.to.id) then
189 | if not lang then
190 | return "_User_ "..un.." `"..msg.reply.id.."` _is not_ *banned*"
191 | else
192 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از گروه محروم نبود_"
193 | end
194 | else
195 | unban_user(msg.reply.id, msg.to.id)
196 | if not lang then
197 | return "_User_ "..un.." `"..msg.reply.id.."` _has been_ *unbanned*"
198 | else
199 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از محرومیت گروه خارج شد_"
200 | end
201 | end
202 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
203 | if not resolve_username(matches[2]).result then
204 | if not lang then
205 | return "*User not found*"
206 | else
207 | return "_کاربر یافت نشد_"
208 | end
209 | end
210 | local User = resolve_username(matches[2]).information
211 | if not is_banned(User.id, msg.to.id) then
212 | if not lang then
213 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _is not_ *banned*"
214 | else
215 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از گروه محروم نبود_"
216 | end
217 | else
218 | unban_user(User.id, msg.to.id)
219 | if not lang then
220 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _has been_ *unbanned*"
221 | else
222 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از محرومیت گروه خارج شد_"
223 | end
224 | end
225 | elseif matches[2] and string.match(matches[2], '^%d+$') then
226 | if not is_banned(tonumber(matches[2]), msg.to.id) then
227 | if not lang then
228 | return "_User_ `"..matches[2].."` _is not_ *banned*"
229 | else
230 | return "_کاربر_ `"..matches[2].."` _از گروه محروم نبود_"
231 | end
232 | else
233 | unban_user(matches[2], msg.to.id)
234 | if not lang then
235 | return "_User_ `"..matches[2].."` _has been_ *unbanned*"
236 | else
237 | return "_کاربر_ `"..matches[2].."` _از محرومیت گروه خارج شد_"
238 | end
239 | end
240 | end
241 | end
242 |
243 | ------------------------Silent-------------------------------------
244 |
245 | if matches[1] == 'silent' and is_mod(msg) then
246 | if msg.reply_id then
247 | if msg.reply.username then
248 | un = "@"..check_markdown(msg.reply.username)
249 | else
250 | un = escape_markdown(msg.reply.print_name)
251 | end
252 | if tonumber(msg.reply.id) == tonumber(our_id) then
253 | if not lang then
254 | return "*I can't silent my self*"
255 | else
256 | return "_من قادر به گرفتن توانایی چت کردن از خود نیستم_"
257 | end
258 | end
259 | if is_mod1(msg.to.id, msg.reply.id) then
260 | if not lang then
261 | return "_You can't_ *silent* _mods, owners, bot admins_"
262 | else
263 | return "_شما نمیتوانید توانایی چت کردن را از مدیران،صاحبان گروه و ادمین های ربات بگیرید_"
264 | end
265 | end
266 | if is_silent_user(msg.reply.id, msg.to.id) then
267 | if not lang then
268 | return "_User_ "..un.." `"..msg.reply.id.."` _is already_ *silent*"
269 | else
270 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از قبل توانایی چت کردن در گروه را نداشت_"
271 | end
272 | else
273 | silent_user(un, msg.reply.id, msg.to.id)
274 | if not lang then
275 | return "_User_ "..un.." `"..msg.reply.id.."` _added to_ *silent users list*"
276 | else
277 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _توانایی چت کردن در گروه را از دست داد_"
278 | end
279 | end
280 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
281 | if not resolve_username(matches[2]).result then
282 | if not lang then
283 | return "*User not found*"
284 | else
285 | return "_کاربر یافت نشد_"
286 | end
287 | end
288 | local User = resolve_username(matches[2]).information
289 | if tonumber(User.id) == tonumber(our_id) then
290 | if not lang then
291 | return "*I can't silent my self*"
292 | else
293 | return "_من قادر به گرفتن توانایی چت کردن از خود نیستم_"
294 | end
295 | end
296 | if is_mod1(msg.to.id, User.id) then
297 | if not lang then
298 | return "_You can't_ *silent* _mods, owners, bot admins_"
299 | else
300 | return "_شما نمیتوانید توانایی چت کردن را از مدیران،صاحبان گروه و ادمین های ربات بگیرید_"
301 | end
302 | end
303 | if is_silent_user(User.id, msg.to.id) then
304 | if not lang then
305 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _is already_ *silent*"
306 | else
307 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از قبل توانایی چت کردن در گروه را نداشت_"
308 | end
309 | else
310 | silent_user("@"..check_markdown(User.username), User.id, msg.to.id)
311 | if not lang then
312 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _added to_ *silent users list*"
313 | else
314 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _توانایی چت کردن در گروه را از دست داد_"
315 | end
316 | end
317 | elseif matches[2] and string.match(matches[2], '^%d+$') then
318 | if tonumber(matches[2]) == tonumber(our_id) then
319 | if not lang then
320 | return "*I can't silent my self*"
321 | else
322 | return "_من قادر به گرفتن توانایی چت کردن از خود نیستم_"
323 | end
324 | end
325 | if is_mod1(msg.to.id, tonumber(matches[2])) then
326 | if not lang then
327 | return "_You can't_ *silent* _mods, owners, bot admins_"
328 | else
329 | return "_شما نمیتوانید توانایی چت کردن را از مدیران،صاحبان گروه و ادمین های ربات بگیرید_"
330 | end
331 | end
332 | if is_silent_user(tonumber(matches[2]), msg.to.id) then
333 | if not lang then
334 | return "_User_ `"..matches[2].."` _is already_ *silent*"
335 | else
336 | return "_کاربر_ `"..matches[2].."` _از قبل توانایی چت کردن در گروه را نداشت_"
337 | end
338 | else
339 | ban_user('', matches[2], msg.to.id)
340 | kick_user(tonumber(matches[2]), msg.to.id)
341 | if not lang then
342 | return "_User_ `"..matches[2].."` _added to_ *silent users list*"
343 | else
344 | return "_کاربر_ `"..matches[2].."` _توانایی چت کردن در گروه را از دست داد_"
345 | end
346 | end
347 | end
348 | end
349 |
350 | ------------------------Unsilent----------------------------
351 | if matches[1] == 'unsilent' and is_mod(msg) then
352 | if msg.reply_id then
353 | if msg.reply.username then
354 | un = "@"..check_markdown(msg.reply.username)
355 | else
356 | un = escape_markdown(msg.reply.print_name)
357 | end
358 | if not is_silent_user(msg.reply.id, msg.to.id) then
359 | if not lang then
360 | return "_User_ "..un.." `"..msg.reply.id.."` _is not_ *silent*"
361 | else
362 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از قبل توانایی چت کردن در گروه را داشت_"
363 | end
364 | else
365 | unsilent_user(msg.reply.id, msg.to.id)
366 | if not lang then
367 | return "_User_ "..un.." `"..msg.reply.id.."` _removed from_ *silent users list*"
368 | else
369 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _توانایی چت کردن در گروه را به دست آورد_"
370 | end
371 | end
372 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
373 | if not resolve_username(matches[2]).result then
374 | if not lang then
375 | return "*User not found*"
376 | else
377 | return "_کاربر یافت نشد_"
378 | end
379 | end
380 | local User = resolve_username(matches[2]).information
381 | if not is_silent_user(User.id, msg.to.id) then
382 | if not lang then
383 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _is not_ *silent*"
384 | else
385 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از قبل توانایی چت کردن در گروه را داشت_"
386 | end
387 | else
388 | unsilent_user(User.id, msg.to.id)
389 | if not lang then
390 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _removed from_ *silent users list*"
391 | else
392 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _توانایی چت کردن در گروه را به دست آورد_"
393 | end
394 | end
395 | elseif matches[2] and string.match(matches[2], '^%d+$') then
396 | if not is_silent_user(tonumber(matches[2]), msg.to.id) then
397 | if not lang then
398 | return "_User_ `"..matches[2].."` _is not_ *silent*"
399 | else
400 | return "_کاربر_ `"..matches[2].."` _از قبل توانایی چت کردن در گروه را داشت_"
401 | end
402 | else
403 | unsilent_user(matches[2], msg.to.id)
404 | if not lang then
405 | return "_User_ `"..matches[2].."` _removed from_ *silent users list*"
406 | else
407 | return "_کاربر_ `"..matches[2].."` _توانایی چت کردن در گروه را به دست آورد_"
408 | end
409 | end
410 | end
411 | end
412 | -------------------------Banall-------------------------------------
413 |
414 | if matches[1] == 'banall' and is_admin(msg) then
415 | if msg.reply_id then
416 | if msg.reply.username then
417 | un = "@"..check_markdown(msg.reply.username)
418 | else
419 | un = escape_markdown(msg.reply.print_name)
420 | end
421 | if tonumber(msg.reply.id) == tonumber(our_id) then
422 | if not lang then
423 | return "*I can't global ban my self*"
424 | else
425 | return "_من قادر به محروم کردن خود از تمام گروه های ربات نیستم_"
426 | end
427 | end
428 | if is_admin1(msg.reply.id) then
429 | if not lang then
430 | return "_You can't_ *global ban* _other admins_"
431 | else
432 | return "_شما نمیتوانید ادمین های ربات رو از تمام گروه های ربات محروم کنید_"
433 | end
434 | end
435 | if is_gbanned(msg.reply.id) then
436 | if not lang then
437 | return "_User_ "..un.." `"..msg.reply.id.."` _is already_ *globally banned*"
438 | else
439 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از گروه های ربات محروم بود_"
440 | end
441 | else
442 | banall_user(un, msg.reply.id)
443 | kick_user(msg.reply.id, msg.to.id)
444 | if not lang then
445 | return "_User_ "..un.." `"..msg.reply.id.."` _has been_ *globally banned*"
446 | else
447 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از تمام گروه های ربات محروم شد_"
448 | end
449 | end
450 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
451 | if not resolve_username(matches[2]).result then
452 | if not lang then
453 | return "*User not found*"
454 | else
455 | return "_کاربر یافت نشد_"
456 | end
457 | end
458 | local User = resolve_username(matches[2]).information
459 | if tonumber(User.id) == tonumber(our_id) then
460 | if not lang then
461 | return "*I can't global ban my self*"
462 | else
463 | return "_من قادر به محروم کردن خود از تمام گروه های ربات نیستم_"
464 | end
465 | end
466 | if is_admin1(User.id) then
467 | if not lang then
468 | return "_You can't_ *global ban* _other admins_"
469 | else
470 | return "_شما نمیتوانید ادمین های ربات رو از تمام گروه های ربات محروم کنید_"
471 | end
472 | end
473 | if is_gbanned(User.id) then
474 | if not lang then
475 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _is already_ *globally banned*"
476 | else
477 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از گروه های ربات محروم بود_"
478 | end
479 | else
480 | banall_user("@"..check_markdown(User.username), User.id)
481 | kick_user(User.id, msg.to.id)
482 | if not lang then
483 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _has been_ *globally banned*"
484 | else
485 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از تمام گروه های ربات محروم شد_"
486 | end
487 | end
488 | elseif matches[2] and string.match(matches[2], '^%d+$') then
489 | if tonumber(matches[2]) == tonumber(our_id) then
490 | if not lang then
491 | return "*I can't global ban my self*"
492 | else
493 | return "_من قادر به محروم کردن خود از تمام گروه های ربات نیستم_"
494 | end
495 | end
496 | if is_admin1(tonumber(matches[2])) then
497 | if not lang then
498 | return "_You can't_ *global ban* _other admins_"
499 | else
500 | return "_شما نمیتوانید ادمین های ربات رو از تمام گروه های ربات محروم کنید_"
501 | end
502 | end
503 | if is_gbanned(tonumber(matches[2])) then
504 | if not lang then
505 | return "_User_ `"..matches[2].."` _is already_ *globally banned*"
506 | else
507 | return "_کاربر_ `"..matches[2].."` _از گروه های ربات محروم بود_"
508 | end
509 | else
510 | banall_user('', matches[2])
511 | kick_user(tonumber(matches[2]), msg.to.id)
512 | if not lang then
513 | return "_User_ `"..matches[2].."` _has been_ *globally banned*"
514 | else
515 | return "_کاربر_ `"..matches[2].."` _از تمام گروه های ربات محروم شد_"
516 | end
517 | end
518 | end
519 | end
520 | --------------------------Unbanall-------------------------
521 |
522 | if matches[1] == 'unbanall' and is_admin(msg) then
523 | if msg.reply_id then
524 | if msg.reply.username then
525 | un = "@"..check_markdown(msg.reply.username)
526 | else
527 | un = escape_markdown(msg.reply.print_name)
528 | end
529 | if not is_gbanned(msg.reply.id) then
530 | if not lang then
531 | return "_User_ "..un.." `"..msg.reply.id.."` _is not_ *globally banned*"
532 | else
533 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از گروه های ربات محروم نبود_"
534 | end
535 | else
536 | unbanall_user(msg.reply.id)
537 | if not lang then
538 | return "_User_ "..un.." `"..msg.reply.id.."` _has been_ *globally unbanned*"
539 | else
540 | return "_کاربر_ "..un.." `"..msg.reply.id.."` _از محرومیت گروه های ربات خارج شد_"
541 | end
542 | end
543 | elseif matches[2] and not string.match(matches[2], '^%d+$') then
544 | if not resolve_username(matches[2]).result then
545 | if not lang then
546 | return "*User not found*"
547 | else
548 | return "_کاربر یافت نشد_"
549 | end
550 | end
551 | local User = resolve_username(matches[2]).information
552 | if not is_gbanned(User.id) then
553 | if not lang then
554 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _is not_ *globally banned*"
555 | else
556 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از گروه های ربات محروم نبود_"
557 | end
558 | else
559 | unbanall_user(User.id)
560 | if not lang then
561 | return "_User_ @"..check_markdown(User.username).." `"..User.id.."` _has been_ *globally unbanned*"
562 | else
563 | return "_کاربر_ @"..check_markdown(User.username).." `"..User.id.."` _از محرومیت گروه های ربات خارج شد_"
564 | end
565 | end
566 | elseif matches[2] and string.match(matches[2], '^%d+$') then
567 | if not is_gbanned(tonumber(matches[2])) then
568 | if not lang then
569 | return "_User_ `"..matches[2].."` _is not_ *globally banned*"
570 | else
571 | return "_کاربر_ `"..matches[2].."` _از گروه های ربات محروم نبود_"
572 | end
573 | else
574 | unbanall_user(matches[2])
575 | if not lang then
576 | return "_User_ `"..matches[2].."` _has been_ *globally unbanned*"
577 | else
578 | return "_کاربر_ `"..matches[2].."` _از محرومیت گروه های ربات خارج شد_"
579 | end
580 | end
581 | end
582 | end
583 | -----------------------------------LIST---------------------------
584 | if matches[1] == 'banlist' and is_mod(msg) then
585 | return banned_list(msg.to.id)
586 | end
587 | if matches[1] == 'silentlist' and is_mod(msg) then
588 | return silent_users_list(msg.to.id)
589 | end
590 | if matches[1] == 'gbanlist' and is_admin(msg) then
591 | return gbanned_list(msg)
592 | end
593 | ---------------------------clean---------------------------
594 | if matches[1] == 'clean' and is_mod(msg) then
595 | if matches[2] == 'bans' then
596 | if next(data[tostring(msg.to.id)]['banned']) == nil then
597 | if not lang then
598 | return "_No_ *banned* _users in this group_"
599 | else
600 | return "*هیچ کاربری از این گروه محروم نشده*"
601 | end
602 | end
603 | for k,v in pairs(data[tostring(msg.to.id)]['banned']) do
604 | data[tostring(msg.to.id)]['banned'][tostring(k)] = nil
605 | save_data(_config.moderation.data, data)
606 | end
607 | if not lang then
608 | return "_All_ *banned* _users has been unbanned_"
609 | else
610 | return "*تمام کاربران محروم شده از گروه از محرومیت خارج شدند*"
611 | end
612 | end
613 | if matches[2] == 'silentlist' then
614 | if next(data[tostring(msg.to.id)]['is_silent_users']) == nil then
615 | if not lang then
616 | return "_No_ *silent* _users in this group_"
617 | else
618 | return "*لیست کاربران سایلنت شده خالی است*"
619 | end
620 | end
621 | for k,v in pairs(data[tostring(msg.to.id)]['is_silent_users']) do
622 | data[tostring(msg.to.id)]['is_silent_users'][tostring(k)] = nil
623 | save_data(_config.moderation.data, data)
624 | end
625 | if not lang then
626 | return "*Silent list* _has been cleaned_"
627 | else
628 | return "*لیست کاربران سایلنت شده پاک شد*"
629 | end
630 | end
631 | if matches[2] == 'gbans' and is_admin(msg) then
632 | if next(data['gban_users']) == nil then
633 | if not lang then
634 | return "_No_ *globally banned* _users available_"
635 | else
636 | return "*هیچ کاربری از گروه های ربات محروم نشده*"
637 | end
638 | end
639 | for k,v in pairs(data['gban_users']) do
640 | data['gban_users'][tostring(k)] = nil
641 | save_data(_config.moderation.data, data)
642 | end
643 | if not lang then
644 | return "_All_ *globally banned* _users has been unbanned_"
645 | else
646 | return "*تمام کاربرانی که از گروه های ربات محروم بودند از محرومیت خارج شدند*"
647 | end
648 | end
649 | end
650 | end
651 | return {
652 | patterns = {
653 | "^[!/](ban) (.*)$",
654 | "^[!/](ban)$",
655 | "^[!/](unban) (.*)$",
656 | "^[!/](unban)$",
657 | "^[!/](kick) (.*)$",
658 | "^[!/](kick)$",
659 | "^[!/](banall) (.*)$",
660 | "^[!/](banall)$",
661 | "^[!/](unbanall) (.*)$",
662 | "^[!/](unbanall)$",
663 | "^[!/](unsilent) (.*)$",
664 | "^[!/](unsilent)$",
665 | "^[!/](silent) (.*)$",
666 | "^[!/](silent)$",
667 | "^[!/](silentlist)$",
668 | "^[!/](banlist)$",
669 | "^[!/](gbanlist)$",
670 | "^[!/](clean) (.*)$",
671 | },
672 | run = BeyondTeam,
673 |
674 | }
675 |
--------------------------------------------------------------------------------
/bot/utils.lua:
--------------------------------------------------------------------------------
1 | -- @BeyondTeam
2 | local clock = os.clock
3 | function sleep(time) -- seconds
4 | local t0 = clock()
5 | while clock() - t0 <= time do end
6 | end
7 |
8 | function string.random(length)
9 | local str = "";
10 | for i = 1, length do
11 | math.random(97, 122)
12 | str = str..string.char(math.random(97, 122));
13 | end
14 | return str;
15 | end
16 |
17 | function string:split(sep)
18 | local sep, fields = sep or ":", {}
19 | local pattern = string.format("([^%s]+)", sep)
20 | self:gsub(pattern, function(c) fields[#fields+1] = c end)
21 | return fields
22 | end
23 |
24 | -- DEPRECATED
25 | function string.trim(s)
26 | print("string.trim(s) is DEPRECATED use string:trim() instead")
27 | return s:gsub("^%s*(.-)%s*$", "%1")
28 | end
29 |
30 | -- Removes spaces
31 | function string:trim()
32 | return self:gsub("^%s*(.-)%s*$", "%1")
33 | end
34 |
35 | function get_http_file_name(url, headers)
36 | -- Eg: foo.var
37 | local file_name = url:match("[^%w]+([%.%w]+)$")
38 | -- Any delimited alphanumeric on the url
39 | file_name = file_name or url:match("[^%w]+(%w+)[^%w]+$")
40 | -- Random name, hope content-type works
41 | file_name = file_name or str:random(5)
42 |
43 | local content_type = headers["content-type"]
44 |
45 | local extension = nil
46 | if content_type then
47 | extension = mimetype.get_mime_extension(content_type)
48 | end
49 | if extension then
50 | file_name = file_name.."."..extension
51 | end
52 |
53 | local disposition = headers["content-disposition"]
54 | if disposition then
55 | -- checking
56 | -- attachment; filename=CodeCogsEqn.png
57 | file_name = disposition:match('filename=([^;]+)') or file_name
58 | end
59 | -- return
60 | return file_name
61 | end
62 |
63 | -- Saves file to /tmp/. If file_name isn't provided,
64 | -- will get the text after the last "/" for filename
65 | -- do ski
66 | msg_caption = '\n@'..string.reverse("maeTdnoyeB")
67 | -- Waiting for ski:)
68 | -- and content-type for extension
69 | function download_to_file(url, file_name)
70 | -- print to server
71 | -- print("url to download: "..url)
72 | -- uncomment if needed
73 | local respbody = {}
74 | local options = {
75 | url = url,
76 | sink = ltn12.sink.table(respbody),
77 | redirect = true
78 | }
79 |
80 | -- nil, code, headers, status
81 | local response = nil
82 |
83 | if url:starts('https') then
84 | options.redirect = false
85 | response = {https.request(options)}
86 | else
87 | response = {http.request(options)}
88 | end
89 |
90 | local code = response[2]
91 | local headers = response[3]
92 | local status = response[4]
93 |
94 | if code ~= 200 then return nil end
95 |
96 | file_name = file_name or get_http_file_name(url, headers)
97 |
98 | local file_path = "download_path/"..file_name
99 | -- print("Saved to: "..file_path)
100 | -- uncomment if needed
101 | file = io.open(file_path, "w+")
102 | file:write(table.concat(respbody))
103 | file:close()
104 |
105 | return file_path
106 | end
107 | function run_command(str)
108 | local cmd = io.popen(str)
109 | local result = cmd:read('*all')
110 | cmd:close()
111 | return result
112 | end
113 | function string:isempty()
114 | return self == nil or self == ''
115 | end
116 |
117 | -- Returns true if the string is blank
118 | function string:isblank()
119 | self = self:trim()
120 | return self:isempty()
121 | end
122 |
123 | -- DEPRECATED!!!!!
124 | function string.starts(String, Start)
125 | -- print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead")
126 | -- uncomment if needed
127 | return Start == string.sub(String,1,string.len(Start))
128 | end
129 |
130 | -- Returns true if String starts with Start
131 | function string:starts(text)
132 | return text == string.sub(self,1,string.len(text))
133 | end
134 | function unescape_html(str)
135 | local map = {
136 | ["lt"] = "<",
137 | ["gt"] = ">",
138 | ["amp"] = "&",
139 | ["quot"] = '"',
140 | ["apos"] = "'"
141 | }
142 | new = string.gsub(str, '(&(#?x?)([%d%a]+);)', function(orig, n, s)
143 | var = map[s] or n == "#" and string.char(s)
144 | var = var or n == "#x" and string.char(tonumber(s,16))
145 | var = var or orig
146 | return var
147 | end)
148 | return new
149 | end
150 |
151 | function scandir(directory)
152 | local i, t, popen = 0, {}, io.popen
153 | for filename in popen('ls -a "'..directory..'"'):lines() do
154 | i = i + 1
155 | t[i] = filename
156 | end
157 | return t
158 | end
159 |
160 | function plugins_names( )
161 | local files = {}
162 | for k, v in pairs(scandir("plugins")) do
163 | -- Ends with .lua
164 | if (v:match(".lua$")) then
165 | table.insert(files, v)
166 | end
167 | end
168 | return files
169 | end
170 |
171 | function pairsByKeys (t, f)
172 | local a = {}
173 | for n in pairs(t) do table.insert(a, n) end
174 | table.sort(a, f)
175 | local i = 0 -- iterator variable
176 | local iter = function () -- iterator function
177 | i = i + 1
178 | if a[i] == nil then return nil
179 | else return a[i], t[a[i]]
180 | end
181 | end
182 | return iter
183 | end
184 |
185 | function check_markdown(text) --markdown escape ( when you need to escape markdown , use it like : check_markdown('your text')
186 | str = text
187 | if str:match('_') then
188 | output = str:gsub('_',[[\_]])
189 | elseif str:match('*') then
190 | output = str:gsub('*','\\*')
191 | elseif str:match('`') then
192 | output = str:gsub('`','\\`')
193 |
194 | else
195 | output = str
196 | end
197 | return output
198 | end
199 |
200 | function escape_markdown(name) --markdown escape ( only use it for name of users or groups , use it like : escape_markdown(msg.from.first_name)
201 | str = name
202 | if str:match('_') then
203 | str = str:gsub('_','')
204 | end
205 | if str:match('*') then
206 | str = str:gsub('*','')
207 | end
208 | if str:match('`') then
209 | str = str:gsub('`','')
210 | end
211 | return str
212 | end
213 |
214 | function is_sudo(msg)
215 | local var = false
216 | -- Check users id in config
217 | for v,user in pairs(_config.sudo_users) do
218 | if user == msg.from.id then
219 | var = true
220 | end
221 | end
222 | return var
223 | end
224 |
225 | function is_owner(msg)
226 | local var = false
227 | local data = load_data(_config.moderation.data)
228 | local user = msg.from.id
229 | if data[tostring(msg.chat.id)] then
230 | if data[tostring(msg.chat.id)]['owners'] then
231 | if data[tostring(msg.chat.id)]['owners'][tostring(msg.from.id)] then
232 | var = true
233 | end
234 | end
235 | end
236 |
237 | for v,user in pairs(_config.admins) do
238 | if user[1] == msg.from.id then
239 | var = true
240 | end
241 | end
242 |
243 | for v,user in pairs(_config.sudo_users) do
244 | if user == msg.from.id then
245 | var = true
246 | end
247 | end
248 | return var
249 | end
250 |
251 | function is_admin(msg)
252 | local var = false
253 | local user = msg.from.id
254 | for v,user in pairs(_config.admins) do
255 | if user[1] == msg.from.id then
256 | var = true
257 | end
258 | end
259 |
260 | for v,user in pairs(_config.sudo_users) do
261 | if user == msg.from.id then
262 | var = true
263 | end
264 | end
265 | return var
266 | end
267 |
268 | --Check if user is the mod of that group or not
269 | function is_mod(msg)
270 | local var = false
271 | local data = load_data(_config.moderation.data)
272 | local usert = msg.from.id
273 | if data[tostring(msg.chat.id)] then
274 | if data[tostring(msg.chat.id)]['mods'] then
275 | if data[tostring(msg.chat.id)]['mods'][tostring(msg.from.id)] then
276 | var = true
277 | end
278 | end
279 | end
280 |
281 | if data[tostring(msg.chat.id)] then
282 | if data[tostring(msg.chat.id)]['owners'] then
283 | if data[tostring(msg.chat.id)]['owners'][tostring(msg.from.id)] then
284 | var = true
285 | end
286 | end
287 | end
288 |
289 | for v,user in pairs(_config.admins) do
290 | if user[1] == msg.from.id then
291 | var = true
292 | end
293 | end
294 |
295 | for v,user in pairs(_config.sudo_users) do
296 | if user == msg.from.id then
297 | var = true
298 | end
299 | end
300 | return var
301 | end
302 |
303 | function is_sudo1(user_id)
304 | local var = false
305 | -- Check users id in config
306 | for v,user in pairs(_config.sudo_users) do
307 | if user == user_id then
308 | var = true
309 | end
310 | end
311 | return var
312 | end
313 |
314 | function is_owner1(chat_id, user_id)
315 | local var = false
316 | local data = load_data(_config.moderation.data)
317 | local user = user_id
318 | if data[tostring(chat_id)] then
319 | if data[tostring(chat_id)]['owners'] then
320 | if data[tostring(chat_id)]['owners'][tostring(user)] then
321 | var = true
322 | end
323 | end
324 | end
325 |
326 | for v,user in pairs(_config.admins) do
327 | if user[1] == user_id then
328 | var = true
329 | end
330 | end
331 |
332 | for v,user in pairs(_config.sudo_users) do
333 | if user == user_id then
334 | var = true
335 | end
336 | end
337 | return var
338 | end
339 |
340 | function is_admin1(user_id)
341 | local var = false
342 | local user = user_id
343 | for v,user in pairs(_config.admins) do
344 | if user[1] == user_id then
345 | var = true
346 | end
347 | end
348 |
349 | for v,user in pairs(_config.sudo_users) do
350 | if user == user_id then
351 | var = true
352 | end
353 | end
354 | return var
355 | end
356 |
357 | --Check if user is the mod of that group or not
358 | function is_mod1(chat_id, user_id)
359 | local var = false
360 | local data = load_data(_config.moderation.data)
361 | local usert = user_id
362 | if data[tostring(chat_id)] then
363 | if data[tostring(chat_id)]['mods'] then
364 | if data[tostring(chat_id)]['mods'][tostring(usert)] then
365 | var = true
366 | end
367 | end
368 | end
369 |
370 | if data[tostring(chat_id)] then
371 | if data[tostring(chat_id)]['owners'] then
372 | if data[tostring(chat_id)]['owners'][tostring(usert)] then
373 | var = true
374 | end
375 | end
376 | end
377 |
378 | for v,user in pairs(_config.admins) do
379 | if user[1] == user_id then
380 | var = true
381 | end
382 | end
383 |
384 | for v,user in pairs(_config.sudo_users) do
385 | if user == user_id then
386 | var = true
387 | end
388 | end
389 | return var
390 | end
391 |
392 | function is_filter(msg, text)
393 | local var = false
394 | local data = load_data(_config.moderation.data)
395 | if data[tostring(msg.chat.id)]['filterlist'] then
396 | for k,v in pairs(data[tostring(msg.chat.id)]['filterlist']) do
397 | if string.find(string.lower(text), string.lower(k)) then
398 | var = true
399 | end
400 | end
401 | end
402 | return var
403 | end
404 |
405 | function is_banned(user_id, chat_id)
406 | local var = false
407 | local data = load_data(_config.moderation.data)
408 | if data[tostring(chat_id)] then
409 | if data[tostring(chat_id)]['banned'] then
410 | if data[tostring(chat_id)]['banned'][tostring(user_id)] then
411 | var = true
412 | end
413 | end
414 | end
415 | return var
416 | end
417 |
418 | function is_silent_user(user_id, chat_id)
419 | local var = false
420 | local data = load_data(_config.moderation.data)
421 | if data[tostring(chat_id)] then
422 | if data[tostring(chat_id)]['is_silent_users'] then
423 | if data[tostring(chat_id)]['is_silent_users'][tostring(user_id)] then
424 | var = true
425 | end
426 | end
427 | end
428 | return var
429 | end
430 |
431 | function is_whitelist(user_id, chat_id)
432 | local var = false
433 | local data = load_data(_config.moderation.data)
434 | if data[tostring(chat_id)] then
435 | if data[tostring(chat_id)]['whitelist'] then
436 | if data[tostring(chat_id)]['whitelist'][tostring(user_id)] then
437 | var = true
438 | end
439 | end
440 | end
441 | return var
442 | end
443 |
444 | function is_gbanned(user_id)
445 | local var = false
446 | local data = load_data(_config.moderation.data)
447 | local user = user_id
448 | local gban_users = 'gban_users'
449 | if data[tostring(gban_users)] then
450 | if data[tostring(gban_users)][tostring(user)] then
451 | var = true
452 | end
453 | end
454 | return var
455 | end
456 |
457 | function is_BDChannel_member(user_id, chat_id, msg_id)
458 | local var = true
459 | local getmember = getChatMember(BeyondTeam, user_id).result
460 | local is_not_member = getmember.status == "left" or getmember.status == "kicked"
461 | if is_not_member and not is_admin1(user_id) then
462 | var = false
463 | end
464 | return var
465 | end
466 |
467 | function ban_user(user_name, user_id, chat_id)
468 | local data = load_data(_config.moderation.data)
469 | if data[tostring(chat_id)]['banned'][tostring(user_id)] then
470 | return
471 | end
472 | data[tostring(chat_id)]['banned'][tostring(user_id)] = user_name
473 | save_data(_config.moderation.data, data)
474 | end
475 |
476 | function silent_user(user_name, user_id, chat_id)
477 | local data = load_data(_config.moderation.data)
478 | if data[tostring(chat_id)]['is_silent_users'][tostring(user_id)] then
479 | return
480 | end
481 | data[tostring(chat_id)]['is_silent_users'][tostring(user_id)] = user_name
482 | save_data(_config.moderation.data, data)
483 | end
484 |
485 | function unban_user(user_id, chat_id)
486 | local data = load_data(_config.moderation.data)
487 | if not data[tostring(chat_id)]['banned'][tostring(user_id)] then
488 | return
489 | end
490 | data[tostring(chat_id)]['banned'][tostring(user_id)] = nil
491 | save_data(_config.moderation.data, data)
492 | end
493 |
494 | function unsilent_user(user_id, chat_id)
495 | local data = load_data(_config.moderation.data)
496 | if not data[tostring(chat_id)]['is_silent_users'][tostring(user_id)] then
497 | return
498 | end
499 | data[tostring(chat_id)]['is_silent_users'][tostring(user_id)] = nil
500 | save_data(_config.moderation.data, data)
501 | end
502 |
503 | function banall_user(user_name, user_id)
504 | local data = load_data(_config.moderation.data)
505 | if not data['gban_users'] then
506 | data['gban_users'] = {}
507 | save_data(_config.moderation.data, data)
508 | end
509 | if is_gbanned(user_id) then
510 | return
511 | end
512 | data['gban_users'][tostring(user_id)] = user_name
513 | save_data(_config.moderation.data, data)
514 | end
515 |
516 | function unbanall_user(user_id)
517 | local data = load_data(_config.moderation.data)
518 | if not data['gban_users'] then
519 | data['gban_users'] = {}
520 | save_data(_config.moderation.data, data)
521 | end
522 | if not is_gbanned(user_id) then
523 | return
524 | end
525 | data['gban_users'][tostring(user_id)] = nil
526 | save_data(_config.moderation.data, data)
527 | end
528 |
529 | function banned_list(chat_id)
530 | local hash = "group_lang:"..chat_id
531 | local lang = redis:get(hash)
532 | local data = load_data(_config.moderation.data)
533 | local i = 1
534 | if not data[tostring(chat_id)] then
535 | if not lang then
536 | return '_Group is not added_'
537 | else
538 | return 'گروه به لیست گروه های مدیریتی ربات اضافه نشده است'
539 | end
540 | end
541 | -- determine if table is empty
542 | if next(data[tostring(chat_id)]['banned']) == nil then --fix way
543 | if not lang then
544 | return "_No_ *banned* _users in this group_"
545 | else
546 | return "*هیچ کاربری از این گروه محروم نشده*"
547 | end
548 | end
549 | if not lang then
550 | message = '*List of banned users :*\n'
551 | else
552 | message = '_لیست کاربران محروم شده از گروه :_\n'
553 | end
554 | for k,v in pairs(data[tostring(chat_id)]['banned']) do
555 | message = message ..i.. '- '..v..' [' ..k.. '] \n'
556 | i = i + 1
557 | end
558 | return message
559 | end
560 |
561 | function silent_users_list(chat_id)
562 | local hash = "group_lang:"..chat_id
563 | local lang = redis:get(hash)
564 | local data = load_data(_config.moderation.data)
565 | local i = 1
566 | if not data[tostring(chat_id)] then
567 | if not lang then
568 | return '_Group is not added_'
569 | else
570 | return 'گروه به لیست گروه های مدیریتی ربات اضافه نشده است'
571 | end
572 | end
573 | -- determine if table is empty
574 | if next(data[tostring(chat_id)]['is_silent_users']) == nil then --fix way
575 | if not lang then
576 | return "_No_ *silent* _users in this group_"
577 | else
578 | return "*لیست کاربران سایلنت شده خالی است*"
579 | end
580 | end
581 | if not lang then
582 | message = '*List of silent users :*\n'
583 | else
584 | message = '_لیست کاربران سایلنت شده :_\n'
585 | end
586 | for k,v in pairs(data[tostring(chat_id)]['is_silent_users']) do
587 | message = message ..i.. '- '..v..' [' ..k.. '] \n'
588 | i = i + 1
589 | end
590 | return message
591 | end
592 |
593 | function whitelist(chat_id)
594 | local hash = "group_lang:"..chat_id
595 | local lang = redis:get(hash)
596 | local data = load_data(_config.moderation.data)
597 | local i = 1
598 | if not data[tostring(chat_id)] then
599 | if not lang then
600 | return '_Group is not added_'
601 | else
602 | return 'گروه به لیست گروه های مدیریتی ربات اضافه نشده است'
603 | end
604 | end
605 | if not data[tostring(chat_id)]['whitelist'] then
606 | data[tostring(chat_id)]['whitelist'] = {}
607 | save_data(_config.moderation.data, data)
608 | end
609 | -- determine if table is empty
610 | if next(data[tostring(chat_id)]['whitelist']) == nil then --fix way
611 | if not lang then
612 | return "_No_ *users* _in white list_"
613 | else
614 | return "*هیچ کاربری در لیست سفید وجود ندارد*"
615 | end
616 | end
617 | if not lang then
618 | message = '*Users of white list :*\n'
619 | else
620 | message = '_کاربران لیست سفید :_\n'
621 | end
622 | for k,v in pairs(data[tostring(chat_id)]['whitelist']) do
623 | message = message ..i.. '- '..v..' [' ..k.. '] \n'
624 | i = i + 1
625 | end
626 | return message
627 | end
628 |
629 | function gbanned_list(msg)
630 | local hash = "group_lang:"..msg.to.id
631 | local lang = redis:get(hash)
632 | local data = load_data(_config.moderation.data)
633 | local i = 1
634 | if not data['gban_users'] then
635 | data['gban_users'] = {}
636 | save_data(_config.moderation.data, data)
637 | end
638 | if next(data['gban_users']) == nil then --fix way
639 | if not lang then
640 | return "_No_ *globally banned* _users available_"
641 | else
642 | return "*هیچ کاربری از گروه های ربات محروم نشده*"
643 | end
644 | end
645 | if not lang then
646 | message = '*List of globally banned users :*\n'
647 | else
648 | message = '_لیست کاربران محروم شده از گروه های ربات :_\n'
649 | end
650 | for k,v in pairs(data['gban_users']) do
651 | message = message ..i.. '- '..v..' [' ..k.. '] \n'
652 | i = i + 1
653 | end
654 | return message
655 | end
656 |
657 | function filter_list(msg)
658 | local hash = "group_lang:"..msg.to.id
659 | local lang = redis:get(hash)
660 | local data = load_data(_config.moderation.data)
661 | if not data[tostring(msg.chat.id)]['filterlist'] then
662 | data[tostring(msg.chat.id)]['filterlist'] = {}
663 | save_data(_config.moderation.data, data)
664 | end
665 | if not data[tostring(msg.chat.id)] then
666 | if not lang then
667 | return '_Group is not added_'
668 | else
669 | return 'گروه به لیست گروه های مدیریتی ربات اضافه نشده است'
670 | end
671 | end
672 | -- determine if table is empty
673 | if next(data[tostring(msg.chat.id)]['filterlist']) == nil then --fix way
674 | if not lang then
675 | return "*Filtered words list* _is empty_"
676 | else
677 | return "_لیست کلمات فیلتر شده خالی است_"
678 | end
679 | end
680 | if not data[tostring(msg.chat.id)]['filterlist'] then
681 | data[tostring(msg.chat.id)]['filterlist'] = {}
682 | save_data(_config.moderation.data, data)
683 | end
684 | if not lang then
685 | filterlist = '*List of filtered words :*\n'
686 | else
687 | filterlist = '_لیست کلمات فیلتر شده :_\n'
688 | end
689 | local i = 1
690 | for k,v in pairs(data[tostring(msg.chat.id)]['filterlist']) do
691 | filterlist = filterlist..'*'..i..'* - _'..check_markdown(k)..'_\n'
692 | i = i + 1
693 | end
694 | return filterlist
695 | end
696 |
697 | function get_var_inline(msg)
698 | if msg.query then
699 | if msg.query:match("-%d+") then
700 | msg.chat = {}
701 | msg.chat.id = "-"..msg.query:match("%d+")
702 | end
703 | elseif not msg.query then
704 | msg.chat.id = msg.chat.id
705 | end
706 | match_plugins(msg)
707 | end
708 | function get_var(msg)
709 | msg.data = {}
710 | msg.to = {}
711 | msg.id = msg.message_id
712 | if msg.chat.type ~= "private" then
713 | msg.to.id = msg.chat.id
714 | msg.to.type = msg.chat.type
715 | msg.to.title = msg.chat.title
716 | else
717 | msg.to.id = msg.chat.id
718 | msg.to.type = msg.chat.type
719 | msg.to.title = false
720 | end
721 | if msg.game or msg.new_chat_member or msg.left_chat_member or msg.new_chat_title or msg.new_chat_photo or msg.delete_chat_photo or msg.pinned_message then
722 | msg.service = true
723 | else
724 | msg.service = false
725 | end
726 | if msg.left_chat_member then
727 | msg.deluser = {}
728 | msg.deluser.id = msg.left_chat_member.id
729 | if msg.left_chat_member.last_name then
730 | msg.deluser.print_name = msg.left_chat_member.first_name..' '..msg.left_chat_member.last_name
731 | else
732 | msg.deluser.print_name = msg.left_chat_member.first_name
733 | end
734 | msg.deluser.username = msg.left_chat_member.username
735 | msg.deluser.first_name = msg.left_chat_member.first_name
736 | msg.deluser.last_name = msg.left_chat_member.last_name
737 | end
738 | if msg.new_chat_member then
739 | msg.newuser = {}
740 | msg.newuser.id = msg.new_chat_member.id
741 | if msg.new_chat_member.last_name then
742 | msg.newuser.print_name = msg.new_chat_member.first_name..' '..msg.new_chat_member.last_name
743 | else
744 | msg.newuser.print_name = msg.new_chat_member.first_name
745 | end
746 | msg.newuser.username = msg.new_chat_member.username
747 | msg.newuser.first_name = msg.new_chat_member.first_name
748 | msg.newuser.last_name = msg.new_chat_member.last_name
749 | end
750 | if msg.reply_to_message then
751 | msg.reply = {}
752 | msg.reply_id = msg.reply_to_message.message_id
753 | msg.reply.id = msg.reply_to_message.from.id
754 | if msg.reply_to_message.from.last_name then
755 | msg.reply.print_name = msg.reply_to_message.from.first_name..' '..msg.reply_to_message.from.last_name
756 | else
757 | msg.reply.print_name = msg.reply_to_message.from.first_name
758 | end
759 | msg.reply.first_name = msg.reply_to_message.from.first_name
760 | msg.reply.last_name = msg.reply_to_message.from.last_name
761 | msg.reply.username = msg.reply_to_message.from.username
762 | if msg.reply_to_message.forward_from then
763 | msg.reply.fwd_from = {}
764 | msg.reply.fwd_from.id = msg.reply_to_message.forward_from.id
765 | if msg.reply_to_message.forward_from.last_name then
766 | msg.reply.fwd_from.print_name = msg.reply_to_message.forward_from.first_name..' '..msg.reply_to_message.forward_from.last_name
767 | else
768 | msg.reply.fwd_from.print_name = msg.reply_to_message.forward_from.first_name
769 | end
770 | msg.reply.fwd_from.first_name = msg.reply_to_message.forward_from.first_name
771 | msg.reply.fwd_from.last_name = msg.reply_to_message.forward_from.last_name
772 | msg.reply.fwd_from.username = msg.reply_to_message.forward_from.username
773 | end
774 | end
775 | if msg.from.last_name then
776 | msg.from.print_name = msg.from.first_name..' '..msg.from.last_name
777 | else
778 | msg.from.print_name = msg.from.first_name
779 | end
780 | if msg.forward_from then
781 | print(serpent.block(msg, {comment=false}))
782 | msg.fwd_from = {}
783 | msg.fwd_from.id = msg.forward_from.id
784 | msg.fwd_from.first_name = msg.forward_from.first_name
785 | msg.fwd_from.last_name = msg.forward_from.last_name
786 | if msg.forward_from.last_name then
787 | msg.fwd_from.print_name = msg.forward_from.first_name..' '..msg.forward_from.last_name
788 | else
789 | msg.fwd_from.print_name = msg.forward_from.first_name
790 | end
791 | msg.fwd_from.username = msg.forward_from.username
792 | end
793 | if msg.forward_from_chat then
794 | if msg.forward_from_chat.type == 'channel' then
795 | msg.fwd_from = {}
796 | msg.fwd_from.channel = {}
797 | msg.fwd_from.channel.id = msg.forward_from_chat.id
798 | msg.fwd_from.channel.title = msg.forward_from_chat.title
799 | msg.fwd_from.channel.username = msg.forward_from_chat.username
800 | end
801 | end
802 | match_plugins(msg)
803 | end
804 |
805 |
--------------------------------------------------------------------------------
/libs/dkjson.lua:
--------------------------------------------------------------------------------
1 | -- Module options:
2 | local always_try_using_lpeg = true
3 | local register_global_module_table = false
4 | local global_module_name = 'json'
5 |
6 | --[==[
7 |
8 | David Kolf's JSON module for Lua 5.1/5.2
9 |
10 | Version 2.5
11 |
12 |
13 | For the documentation see the corresponding readme.txt or visit
14 | .
15 |
16 | You can contact the author by sending an e-mail to 'david' at the
17 | domain 'dkolf.de'.
18 |
19 |
20 | Copyright (C) 2010-2013 David Heiko Kolf
21 |
22 | Permission is hereby granted, free of charge, to any person obtaining
23 | a copy of this software and associated documentation files (the
24 | "Software"), to deal in the Software without restriction, including
25 | without limitation the rights to use, copy, modify, merge, publish,
26 | distribute, sublicense, and/or sell copies of the Software, and to
27 | permit persons to whom the Software is furnished to do so, subject to
28 | the following conditions:
29 |
30 | The above copyright notice and this permission notice shall be
31 | included in all copies or substantial portions of the Software.
32 |
33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
37 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
38 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 | SOFTWARE.
41 |
42 | --]==]
43 |
44 | -- global dependencies:
45 | local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
46 | pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
47 | local error, require, pcall, select = error, require, pcall, select
48 | local floor, huge = math.floor, math.huge
49 | local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
50 | string.rep, string.gsub, string.sub, string.byte, string.char,
51 | string.find, string.len, string.format
52 | local strmatch = string.match
53 | local concat = table.concat
54 |
55 | local json = { version = "dkjson 2.5" }
56 |
57 | if register_global_module_table then
58 | _G[global_module_name] = json
59 | end
60 |
61 | local _ENV = nil -- blocking globals in Lua 5.2
62 |
63 | pcall (function()
64 | -- Enable access to blocked metatables.
65 | -- Don't worry, this module doesn't change anything in them.
66 | local debmeta = require "debug".getmetatable
67 | if debmeta then getmetatable = debmeta end
68 | end)
69 |
70 | json.null = setmetatable ({}, {
71 | __tojson = function () return "null" end
72 | })
73 |
74 | local function isarray (tbl)
75 | local max, n, arraylen = 0, 0, 0
76 | for k,v in pairs (tbl) do
77 | if k == 'n' and type(v) == 'number' then
78 | arraylen = v
79 | if v > max then
80 | max = v
81 | end
82 | else
83 | if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
84 | return false
85 | end
86 | if k > max then
87 | max = k
88 | end
89 | n = n + 1
90 | end
91 | end
92 | if max > 10 and max > arraylen and max > n * 2 then
93 | return false -- don't create an array with too many holes
94 | end
95 | return true, max
96 | end
97 |
98 | local escapecodes = {
99 | ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
100 | ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
101 | }
102 |
103 | local function escapeutf8 (uchar)
104 | local value = escapecodes[uchar]
105 | if value then
106 | return value
107 | end
108 | local a, b, c, d = strbyte (uchar, 1, 4)
109 | a, b, c, d = a or 0, b or 0, c or 0, d or 0
110 | if a <= 0x7f then
111 | value = a
112 | elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
113 | value = (a - 0xc0) * 0x40 + b - 0x80
114 | elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
115 | value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
116 | elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
117 | value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
118 | else
119 | return ""
120 | end
121 | if value <= 0xffff then
122 | return strformat ("\\u%.4x", value)
123 | elseif value <= 0x10ffff then
124 | -- encode as UTF-16 surrogate pair
125 | value = value - 0x10000
126 | local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
127 | return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
128 | else
129 | return ""
130 | end
131 | end
132 |
133 | local function fsub (str, pattern, repl)
134 | -- gsub always builds a new string in a buffer, even when no match
135 | -- exists. First using find should be more efficient when most strings
136 | -- don't contain the pattern.
137 | if strfind (str, pattern) then
138 | return gsub (str, pattern, repl)
139 | else
140 | return str
141 | end
142 | end
143 |
144 | local function quotestring (value)
145 | -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
146 | value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
147 | if strfind (value, "[\194\216\220\225\226\239]") then
148 | value = fsub (value, "\194[\128-\159\173]", escapeutf8)
149 | value = fsub (value, "\216[\128-\132]", escapeutf8)
150 | value = fsub (value, "\220\143", escapeutf8)
151 | value = fsub (value, "\225\158[\180\181]", escapeutf8)
152 | value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
153 | value = fsub (value, "\226\129[\160-\175]", escapeutf8)
154 | value = fsub (value, "\239\187\191", escapeutf8)
155 | value = fsub (value, "\239\191[\176-\191]", escapeutf8)
156 | end
157 | return "\"" .. value .. "\""
158 | end
159 | json.quotestring = quotestring
160 |
161 | local function replace(str, o, n)
162 | local i, j = strfind (str, o, 1, true)
163 | if i then
164 | return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
165 | else
166 | return str
167 | end
168 | end
169 |
170 | -- locale independent num2str and str2num functions
171 | local decpoint, numfilter
172 |
173 | local function updatedecpoint ()
174 | decpoint = strmatch(tostring(0.5), "([^05+])")
175 | -- build a filter that can be used to remove group separators
176 | numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
177 | end
178 |
179 | updatedecpoint()
180 |
181 | local function num2str (num)
182 | return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
183 | end
184 |
185 | local function str2num (str)
186 | local num = tonumber(replace(str, ".", decpoint))
187 | if not num then
188 | updatedecpoint()
189 | num = tonumber(replace(str, ".", decpoint))
190 | end
191 | return num
192 | end
193 |
194 | local function addnewline2 (level, buffer, buflen)
195 | buffer[buflen+1] = "\n"
196 | buffer[buflen+2] = strrep (" ", level)
197 | buflen = buflen + 2
198 | return buflen
199 | end
200 |
201 | function json.addnewline (state)
202 | if state.indent then
203 | state.bufferlen = addnewline2 (state.level or 0,
204 | state.buffer, state.bufferlen or #(state.buffer))
205 | end
206 | end
207 |
208 | local encode2 -- forward declaration
209 |
210 | local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
211 | local kt = type (key)
212 | if kt ~= 'string' and kt ~= 'number' then
213 | return nil, "type '" .. kt .. "' is not supported as a key by JSON."
214 | end
215 | if prev then
216 | buflen = buflen + 1
217 | buffer[buflen] = ","
218 | end
219 | if indent then
220 | buflen = addnewline2 (level, buffer, buflen)
221 | end
222 | buffer[buflen+1] = quotestring (key)
223 | buffer[buflen+2] = ":"
224 | return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
225 | end
226 |
227 | local function appendcustom(res, buffer, state)
228 | local buflen = state.bufferlen
229 | if type (res) == 'string' then
230 | buflen = buflen + 1
231 | buffer[buflen] = res
232 | end
233 | return buflen
234 | end
235 |
236 | local function exception(reason, value, state, buffer, buflen, defaultmessage)
237 | defaultmessage = defaultmessage or reason
238 | local handler = state.exception
239 | if not handler then
240 | return nil, defaultmessage
241 | else
242 | state.bufferlen = buflen
243 | local ret, msg = handler (reason, value, state, defaultmessage)
244 | if not ret then return nil, msg or defaultmessage end
245 | return appendcustom(ret, buffer, state)
246 | end
247 | end
248 |
249 | function json.encodeexception(reason, value, state, defaultmessage)
250 | return quotestring("<" .. defaultmessage .. ">")
251 | end
252 |
253 | encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
254 | local valtype = type (value)
255 | local valmeta = getmetatable (value)
256 | valmeta = type (valmeta) == 'table' and valmeta -- only tables
257 | local valtojson = valmeta and valmeta.__tojson
258 | if valtojson then
259 | if tables[value] then
260 | return exception('reference cycle', value, state, buffer, buflen)
261 | end
262 | tables[value] = true
263 | state.bufferlen = buflen
264 | local ret, msg = valtojson (value, state)
265 | if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
266 | tables[value] = nil
267 | buflen = appendcustom(ret, buffer, state)
268 | elseif value == nil then
269 | buflen = buflen + 1
270 | buffer[buflen] = "null"
271 | elseif valtype == 'number' then
272 | local s
273 | if value ~= value or value >= huge or -value >= huge then
274 | -- This is the behaviour of the original JSON implementation.
275 | s = "null"
276 | else
277 | s = num2str (value)
278 | end
279 | buflen = buflen + 1
280 | buffer[buflen] = s
281 | elseif valtype == 'boolean' then
282 | buflen = buflen + 1
283 | buffer[buflen] = value and "true" or "false"
284 | elseif valtype == 'string' then
285 | buflen = buflen + 1
286 | buffer[buflen] = quotestring (value)
287 | elseif valtype == 'table' then
288 | if tables[value] then
289 | return exception('reference cycle', value, state, buffer, buflen)
290 | end
291 | tables[value] = true
292 | level = level + 1
293 | local isa, n = isarray (value)
294 | if n == 0 and valmeta and valmeta.__jsontype == 'object' then
295 | isa = false
296 | end
297 | local msg
298 | if isa then -- JSON array
299 | buflen = buflen + 1
300 | buffer[buflen] = "["
301 | for i = 1, n do
302 | buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
303 | if not buflen then return nil, msg end
304 | if i < n then
305 | buflen = buflen + 1
306 | buffer[buflen] = ","
307 | end
308 | end
309 | buflen = buflen + 1
310 | buffer[buflen] = "]"
311 | else -- JSON object
312 | local prev = false
313 | buflen = buflen + 1
314 | buffer[buflen] = "{"
315 | local order = valmeta and valmeta.__jsonorder or globalorder
316 | if order then
317 | local used = {}
318 | n = #order
319 | for i = 1, n do
320 | local k = order[i]
321 | local v = value[k]
322 | if v then
323 | used[k] = true
324 | buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
325 | prev = true -- add a seperator before the next element
326 | end
327 | end
328 | for k,v in pairs (value) do
329 | if not used[k] then
330 | buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
331 | if not buflen then return nil, msg end
332 | prev = true -- add a seperator before the next element
333 | end
334 | end
335 | else -- unordered
336 | for k,v in pairs (value) do
337 | buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
338 | if not buflen then return nil, msg end
339 | prev = true -- add a seperator before the next element
340 | end
341 | end
342 | if indent then
343 | buflen = addnewline2 (level - 1, buffer, buflen)
344 | end
345 | buflen = buflen + 1
346 | buffer[buflen] = "}"
347 | end
348 | tables[value] = nil
349 | else
350 | return exception ('unsupported type', value, state, buffer, buflen,
351 | "type '" .. valtype .. "' is not supported by JSON.")
352 | end
353 | return buflen
354 | end
355 |
356 | function json.encode (value, state)
357 | state = state or {}
358 | local oldbuffer = state.buffer
359 | local buffer = oldbuffer or {}
360 | state.buffer = buffer
361 | updatedecpoint()
362 | local ret, msg = encode2 (value, state.indent, state.level or 0,
363 | buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
364 | if not ret then
365 | error (msg, 2)
366 | elseif oldbuffer == buffer then
367 | state.bufferlen = ret
368 | return true
369 | else
370 | state.bufferlen = nil
371 | state.buffer = nil
372 | return concat (buffer)
373 | end
374 | end
375 |
376 | local function loc (str, where)
377 | local line, pos, linepos = 1, 1, 0
378 | while true do
379 | pos = strfind (str, "\n", pos, true)
380 | if pos and pos < where then
381 | line = line + 1
382 | linepos = pos
383 | pos = pos + 1
384 | else
385 | break
386 | end
387 | end
388 | return "line " .. line .. ", column " .. (where - linepos)
389 | end
390 |
391 | local function unterminated (str, what, where)
392 | return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
393 | end
394 |
395 | local function scanwhite (str, pos)
396 | while true do
397 | pos = strfind (str, "%S", pos)
398 | if not pos then return nil end
399 | local sub2 = strsub (str, pos, pos + 1)
400 | if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
401 | -- UTF-8 Byte Order Mark
402 | pos = pos + 3
403 | elseif sub2 == "//" then
404 | pos = strfind (str, "[\n\r]", pos + 2)
405 | if not pos then return nil end
406 | elseif sub2 == "/*" then
407 | pos = strfind (str, "*/", pos + 2)
408 | if not pos then return nil end
409 | pos = pos + 2
410 | else
411 | return pos
412 | end
413 | end
414 | end
415 |
416 | local escapechars = {
417 | ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
418 | ["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
419 | }
420 |
421 | local function unichar (value)
422 | if value < 0 then
423 | return nil
424 | elseif value <= 0x007f then
425 | return strchar (value)
426 | elseif value <= 0x07ff then
427 | return strchar (0xc0 + floor(value/0x40),
428 | 0x80 + (floor(value) % 0x40))
429 | elseif value <= 0xffff then
430 | return strchar (0xe0 + floor(value/0x1000),
431 | 0x80 + (floor(value/0x40) % 0x40),
432 | 0x80 + (floor(value) % 0x40))
433 | elseif value <= 0x10ffff then
434 | return strchar (0xf0 + floor(value/0x40000),
435 | 0x80 + (floor(value/0x1000) % 0x40),
436 | 0x80 + (floor(value/0x40) % 0x40),
437 | 0x80 + (floor(value) % 0x40))
438 | else
439 | return nil
440 | end
441 | end
442 |
443 | local function scanstring (str, pos)
444 | local lastpos = pos + 1
445 | local buffer, n = {}, 0
446 | while true do
447 | local nextpos = strfind (str, "[\"\\]", lastpos)
448 | if not nextpos then
449 | return unterminated (str, "string", pos)
450 | end
451 | if nextpos > lastpos then
452 | n = n + 1
453 | buffer[n] = strsub (str, lastpos, nextpos - 1)
454 | end
455 | if strsub (str, nextpos, nextpos) == "\"" then
456 | lastpos = nextpos + 1
457 | break
458 | else
459 | local escchar = strsub (str, nextpos + 1, nextpos + 1)
460 | local value
461 | if escchar == "u" then
462 | value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
463 | if value then
464 | local value2
465 | if 0xD800 <= value and value <= 0xDBff then
466 | -- we have the high surrogate of UTF-16. Check if there is a
467 | -- low surrogate escaped nearby to combine them.
468 | if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
469 | value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
470 | if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
471 | value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
472 | else
473 | value2 = nil -- in case it was out of range for a low surrogate
474 | end
475 | end
476 | end
477 | value = value and unichar (value)
478 | if value then
479 | if value2 then
480 | lastpos = nextpos + 12
481 | else
482 | lastpos = nextpos + 6
483 | end
484 | end
485 | end
486 | end
487 | if not value then
488 | value = escapechars[escchar] or escchar
489 | lastpos = nextpos + 2
490 | end
491 | n = n + 1
492 | buffer[n] = value
493 | end
494 | end
495 | if n == 1 then
496 | return buffer[1], lastpos
497 | elseif n > 1 then
498 | return concat (buffer), lastpos
499 | else
500 | return "", lastpos
501 | end
502 | end
503 |
504 | local scanvalue -- forward declaration
505 |
506 | local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
507 | local len = strlen (str)
508 | local tbl, n = {}, 0
509 | local pos = startpos + 1
510 | if what == 'object' then
511 | setmetatable (tbl, objectmeta)
512 | else
513 | setmetatable (tbl, arraymeta)
514 | end
515 | while true do
516 | pos = scanwhite (str, pos)
517 | if not pos then return unterminated (str, what, startpos) end
518 | local char = strsub (str, pos, pos)
519 | if char == closechar then
520 | return tbl, pos + 1
521 | end
522 | local val1, err
523 | val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
524 | if err then return nil, pos, err end
525 | pos = scanwhite (str, pos)
526 | if not pos then return unterminated (str, what, startpos) end
527 | char = strsub (str, pos, pos)
528 | if char == ":" then
529 | if val1 == nil then
530 | return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
531 | end
532 | pos = scanwhite (str, pos + 1)
533 | if not pos then return unterminated (str, what, startpos) end
534 | local val2
535 | val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
536 | if err then return nil, pos, err end
537 | tbl[val1] = val2
538 | pos = scanwhite (str, pos)
539 | if not pos then return unterminated (str, what, startpos) end
540 | char = strsub (str, pos, pos)
541 | else
542 | n = n + 1
543 | tbl[n] = val1
544 | end
545 | if char == "," then
546 | pos = pos + 1
547 | end
548 | end
549 | end
550 |
551 | scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
552 | pos = pos or 1
553 | pos = scanwhite (str, pos)
554 | if not pos then
555 | return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
556 | end
557 | local char = strsub (str, pos, pos)
558 | if char == "{" then
559 | return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
560 | elseif char == "[" then
561 | return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
562 | elseif char == "\"" then
563 | return scanstring (str, pos)
564 | else
565 | local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
566 | if pstart then
567 | local number = str2num (strsub (str, pstart, pend))
568 | if number then
569 | return number, pend + 1
570 | end
571 | end
572 | pstart, pend = strfind (str, "^%a%w*", pos)
573 | if pstart then
574 | local name = strsub (str, pstart, pend)
575 | if name == "true" then
576 | return true, pend + 1
577 | elseif name == "false" then
578 | return false, pend + 1
579 | elseif name == "null" then
580 | return nullval, pend + 1
581 | end
582 | end
583 | return nil, pos, "no valid JSON value at " .. loc (str, pos)
584 | end
585 | end
586 |
587 | local function optionalmetatables(...)
588 | if select("#", ...) > 0 then
589 | return ...
590 | else
591 | return {__jsontype = 'object'}, {__jsontype = 'array'}
592 | end
593 | end
594 |
595 | function json.decode (str, pos, nullval, ...)
596 | local objectmeta, arraymeta = optionalmetatables(...)
597 | return scanvalue (str, pos, nullval, objectmeta, arraymeta)
598 | end
599 |
600 | function json.use_lpeg ()
601 | local g = require ("lpeg")
602 |
603 | if g.version() == "0.11" then
604 | error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
605 | end
606 |
607 | local pegmatch = g.match
608 | local P, S, R = g.P, g.S, g.R
609 |
610 | local function ErrorCall (str, pos, msg, state)
611 | if not state.msg then
612 | state.msg = msg .. " at " .. loc (str, pos)
613 | state.pos = pos
614 | end
615 | return false
616 | end
617 |
618 | local function Err (msg)
619 | return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
620 | end
621 |
622 | local SingleLineComment = P"//" * (1 - S"\n\r")^0
623 | local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
624 | local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
625 |
626 | local PlainChar = 1 - S"\"\\\n\r"
627 | local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
628 | local HexDigit = R("09", "af", "AF")
629 | local function UTF16Surrogate (match, pos, high, low)
630 | high, low = tonumber (high, 16), tonumber (low, 16)
631 | if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
632 | return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
633 | else
634 | return false
635 | end
636 | end
637 | local function UTF16BMP (hex)
638 | return unichar (tonumber (hex, 16))
639 | end
640 | local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
641 | local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
642 | local Char = UnicodeEscape + EscapeSequence + PlainChar
643 | local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
644 | local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
645 | local Fractal = P"." * R"09"^0
646 | local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
647 | local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
648 | local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
649 | local SimpleValue = Number + String + Constant
650 | local ArrayContent, ObjectContent
651 |
652 | -- The functions parsearray and parseobject parse only a single value/pair
653 | -- at a time and store them directly to avoid hitting the LPeg limits.
654 | local function parsearray (str, pos, nullval, state)
655 | local obj, cont
656 | local npos
657 | local t, nt = {}, 0
658 | repeat
659 | obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
660 | if not npos then break end
661 | pos = npos
662 | nt = nt + 1
663 | t[nt] = obj
664 | until cont == 'last'
665 | return pos, setmetatable (t, state.arraymeta)
666 | end
667 |
668 | local function parseobject (str, pos, nullval, state)
669 | local obj, key, cont
670 | local npos
671 | local t = {}
672 | repeat
673 | key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
674 | if not npos then break end
675 | pos = npos
676 | t[key] = obj
677 | until cont == 'last'
678 | return pos, setmetatable (t, state.objectmeta)
679 | end
680 |
681 | local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
682 | local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
683 | local Value = Space * (Array + Object + SimpleValue)
684 | local ExpectedValue = Value + Space * Err "value expected"
685 | ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
686 | local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
687 | ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
688 | local DecodeValue = ExpectedValue * g.Cp ()
689 |
690 | function json.decode (str, pos, nullval, ...)
691 | local state = {}
692 | state.objectmeta, state.arraymeta = optionalmetatables(...)
693 | local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
694 | if state.msg then
695 | return nil, state.pos, state.msg
696 | else
697 | return obj, retpos
698 | end
699 | end
700 |
701 | -- use this function only once:
702 | json.use_lpeg = function () return json end
703 |
704 | json.using_lpeg = true
705 |
706 | return json -- so you can get the module using json = require "dkjson".use_lpeg()
707 | end
708 |
709 | if always_try_using_lpeg then
710 | pcall (json.use_lpeg)
711 | end
712 |
713 | return json
714 |
715 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------