├── _config.yml
├── .gitignore
├── README.md
├── launch.sh
├── libs
├── redis.lua
├── JSON.lua
└── lua-redis.lua
├── bot.lua
└── tdcli.lua
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-tactile
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Lua sources
2 | luac.out
3 |
4 | # luarocks build files
5 | *.src.rock
6 | *.zip
7 | *.tar.gz
8 |
9 | # Object files
10 | *.o
11 | *.os
12 | *.ko
13 | *.obj
14 | *.elf
15 |
16 | # Precompiled Headers
17 | *.gch
18 | *.pch
19 |
20 | # Libraries
21 | *.lib
22 | *.a
23 | *.la
24 | *.lo
25 | *.def
26 | *.exp
27 |
28 | # Shared objects (inc. Windows DLLs)
29 | *.dll
30 | *.so
31 | *.so.*
32 | *.dylib
33 |
34 | # Executables
35 | *.exe
36 | *.out
37 | *.app
38 | *.i*86
39 | *.x86_64
40 | *.hex
41 |
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [GrandPlus](https://telegram.me/GrandPlus)
2 |
3 | # Developers!
4 |
5 |
6 | [mehran](https://github.com/mehmehran) ([Telegram](https://telegram.me/pythonscript))
7 | * * *
8 |
9 | # Install source
10 |
11 | * * *
12 | cd $HOME
13 |
14 | git clone https://github.com/GrandTM/GrandPlus.git
15 |
16 | cd GrandPlus
17 |
18 | chmod +x launch.sh
19 |
20 | ./launch.sh install
21 |
22 | ./launch.sh
23 |
24 | # Enter a phone number | confirmation code.
25 |
26 | * * *
27 |
28 | ### Our channel:
29 |
30 | [GrandTeam](https://telegram.me/GrandTeam)
31 |
32 |
--------------------------------------------------------------------------------
/launch.sh:
--------------------------------------------------------------------------------
1 | THIS_DIR=$(cd $(dirname $0); pwd)
2 | cd $THIS_DIR
3 |
4 | install() {
5 | wget "https://valtman.name/files/telegram-cli-1222"
6 | mv telegram-cli-1222 tg
7 | sudo chmod +x tg
8 | echo -e "———————————————————————————————————————————————————————————\n"
9 | echo -e " Write to launch a source command in the terminal ./launch.sh \n"
10 | echo -e "———————————————————————————————————————————————————————————\n"
11 | }
12 |
13 | if [ "$1" = "install" ]; then
14 | install
15 | else
16 | if [ ! -f ./tg ]; then
17 | echo "TG not found"
18 | echo "Run $0 install"
19 | exit 1
20 | fi
21 | ./tg -s bot.lua
22 | fi
23 |
--------------------------------------------------------------------------------
/libs/redis.lua:
--------------------------------------------------------------------------------
1 | local Redis = (loadfile "./libs/lua-redis.lua")()
2 | --local FakeRedis = (loadfile "./tg/max/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 |
--------------------------------------------------------------------------------
/libs/JSON.lua:
--------------------------------------------------------------------------------
1 | -- -*- coding: utf-8 -*-
2 | --
3 | -- Simple JSON encoding and decoding in pure Lua.
4 | --
5 | -- Copyright 2010-2014 Jeffrey Friedl
6 | -- http://regex.info/blog/
7 | --
8 | -- Latest version: http://regex.info/blog/lua/json
9 | --
10 | -- This code is released under a Creative Commons CC-BY "Attribution" License:
11 | -- http://creativecommons.org/licenses/by/3.0/deed.en_US
12 | --
13 | -- It can be used for any purpose so long as the copyright notice above,
14 | -- the web-page links above, and the 'AUTHOR_NOTE' string below are
15 | -- maintained. Enjoy.
16 | --
17 | local VERSION = 20141223.14 -- version history at end of file
18 | local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20141223.14 ]-"
19 |
20 | --
21 | -- The 'AUTHOR_NOTE' variable exists so that information about the source
22 | -- of the package is maintained even in compiled versions. It's also
23 | -- included in OBJDEF below mostly to quiet warnings about unused variables.
24 | --
25 | local OBJDEF = {
26 | VERSION = VERSION,
27 | AUTHOR_NOTE = AUTHOR_NOTE,
28 | }
29 |
30 |
31 | --
32 | -- Simple JSON encoding and decoding in pure Lua.
33 | -- http://www.json.org/
34 | --
35 | --
36 | -- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
37 | --
38 | -- local lua_value = JSON:decode(raw_json_text)
39 | --
40 | -- local raw_json_text = JSON:encode(lua_table_or_value)
41 | -- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
42 | --
43 | --
44 | --
45 | -- DECODING (from a JSON string to a Lua table)
46 | --
47 | --
48 | -- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
49 | --
50 | -- local lua_value = JSON:decode(raw_json_text)
51 | --
52 | -- If the JSON text is for an object or an array, e.g.
53 | -- { "what": "books", "count": 3 }
54 | -- or
55 | -- [ "Larry", "Curly", "Moe" ]
56 | --
57 | -- the result is a Lua table, e.g.
58 | -- { what = "books", count = 3 }
59 | -- or
60 | -- { "Larry", "Curly", "Moe" }
61 | --
62 | --
63 | -- The encode and decode routines accept an optional second argument,
64 | -- "etc", which is not used during encoding or decoding, but upon error
65 | -- is passed along to error handlers. It can be of any type (including nil).
66 | --
67 | --
68 | --
69 | -- ERROR HANDLING
70 | --
71 | -- With most errors during decoding, this code calls
72 | --
73 | -- JSON:onDecodeError(message, text, location, etc)
74 | --
75 | -- with a message about the error, and if known, the JSON text being
76 | -- parsed and the byte count where the problem was discovered. You can
77 | -- replace the default JSON:onDecodeError() with your own function.
78 | --
79 | -- The default onDecodeError() merely augments the message with data
80 | -- about the text and the location if known (and if a second 'etc'
81 | -- argument had been provided to decode(), its value is tacked onto the
82 | -- message as well), and then calls JSON.assert(), which itself defaults
83 | -- to Lua's built-in assert(), and can also be overridden.
84 | --
85 | -- For example, in an Adobe Lightroom plugin, you might use something like
86 | --
87 | -- function JSON:onDecodeError(message, text, location, etc)
88 | -- LrErrors.throwUserError("Internal Error: invalid JSON data")
89 | -- end
90 | --
91 | -- or even just
92 | --
93 | -- function JSON.assert(message)
94 | -- LrErrors.throwUserError("Internal Error: " .. message)
95 | -- end
96 | --
97 | -- If JSON:decode() is passed a nil, this is called instead:
98 | --
99 | -- JSON:onDecodeOfNilError(message, nil, nil, etc)
100 | --
101 | -- and if JSON:decode() is passed HTML instead of JSON, this is called:
102 | --
103 | -- JSON:onDecodeOfHTMLError(message, text, nil, etc)
104 | --
105 | -- The use of the fourth 'etc' argument allows stronger coordination
106 | -- between decoding and error reporting, especially when you provide your
107 | -- own error-handling routines. Continuing with the the Adobe Lightroom
108 | -- plugin example:
109 | --
110 | -- function JSON:onDecodeError(message, text, location, etc)
111 | -- local note = "Internal Error: invalid JSON data"
112 | -- if type(etc) = 'table' and etc.photo then
113 | -- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName')
114 | -- end
115 | -- LrErrors.throwUserError(note)
116 | -- end
117 | --
118 | -- :
119 | -- :
120 | --
121 | -- for i, photo in ipairs(photosToProcess) do
122 | -- :
123 | -- :
124 | -- local data = JSON:decode(someJsonText, { photo = photo })
125 | -- :
126 | -- :
127 | -- end
128 | --
129 | --
130 | --
131 | --
132 | --
133 | -- DECODING AND STRICT TYPES
134 | --
135 | -- Because both JSON objects and JSON arrays are converted to Lua tables,
136 | -- it's not normally possible to tell which original JSON type a
137 | -- particular Lua table was derived from, or guarantee decode-encode
138 | -- round-trip equivalency.
139 | --
140 | -- However, if you enable strictTypes, e.g.
141 | --
142 | -- JSON = assert(loadfile "JSON.lua")() --load the routines
143 | -- JSON.strictTypes = true
144 | --
145 | -- then the Lua table resulting from the decoding of a JSON object or
146 | -- JSON array is marked via Lua metatable, so that when re-encoded with
147 | -- JSON:encode() it ends up as the appropriate JSON type.
148 | --
149 | -- (This is not the default because other routines may not work well with
150 | -- tables that have a metatable set, for example, Lightroom API calls.)
151 | --
152 | --
153 | -- ENCODING (from a lua table to a JSON string)
154 | --
155 | -- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
156 | --
157 | -- local raw_json_text = JSON:encode(lua_table_or_value)
158 | -- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
159 | -- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false })
160 | --
161 | -- On error during encoding, this code calls:
162 | --
163 | -- JSON:onEncodeError(message, etc)
164 | --
165 | -- which you can override in your local JSON object.
166 | --
167 | -- The 'etc' in the error call is the second argument to encode()
168 | -- and encode_pretty(), or nil if it wasn't provided.
169 | --
170 | --
171 | -- PRETTY-PRINTING
172 | --
173 | -- An optional third argument, a table of options, allows a bit of
174 | -- configuration about how the encoding takes place:
175 | --
176 | -- pretty = JSON:encode(val, etc, {
177 | -- pretty = true, -- if false, no other options matter
178 | -- indent = " ", -- this provides for a three-space indent per nesting level
179 | -- align_keys = false, -- see below
180 | -- })
181 | --
182 | -- encode() and encode_pretty() are identical except that encode_pretty()
183 | -- provides a default options table if none given in the call:
184 | --
185 | -- { pretty = true, align_keys = false, indent = " " }
186 | --
187 | -- For example, if
188 | --
189 | -- JSON:encode(data)
190 | --
191 | -- produces:
192 | --
193 | -- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11}
194 | --
195 | -- then
196 | --
197 | -- JSON:encode_pretty(data)
198 | --
199 | -- produces:
200 | --
201 | -- {
202 | -- "city": "Kyoto",
203 | -- "climate": {
204 | -- "avg_temp": 16,
205 | -- "humidity": "high",
206 | -- "snowfall": "minimal"
207 | -- },
208 | -- "country": "Japan",
209 | -- "wards": 11
210 | -- }
211 | --
212 | -- The following three lines return identical results:
213 | -- JSON:encode_pretty(data)
214 | -- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " })
215 | -- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " })
216 | --
217 | -- An example of setting your own indent string:
218 | --
219 | -- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " })
220 | --
221 | -- produces:
222 | --
223 | -- {
224 | -- | "city": "Kyoto",
225 | -- | "climate": {
226 | -- | | "avg_temp": 16,
227 | -- | | "humidity": "high",
228 | -- | | "snowfall": "minimal"
229 | -- | },
230 | -- | "country": "Japan",
231 | -- | "wards": 11
232 | -- }
233 | --
234 | -- An example of setting align_keys to true:
235 | --
236 | -- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true })
237 | --
238 | -- produces:
239 | --
240 | -- {
241 | -- "city": "Kyoto",
242 | -- "climate": {
243 | -- "avg_temp": 16,
244 | -- "humidity": "high",
245 | -- "snowfall": "minimal"
246 | -- },
247 | -- "country": "Japan",
248 | -- "wards": 11
249 | -- }
250 | --
251 | -- which I must admit is kinda ugly, sorry. This was the default for
252 | -- encode_pretty() prior to version 20141223.14.
253 | --
254 | --
255 | -- AMBIGUOUS SITUATIONS DURING THE ENCODING
256 | --
257 | -- During the encode, if a Lua table being encoded contains both string
258 | -- and numeric keys, it fits neither JSON's idea of an object, nor its
259 | -- idea of an array. To get around this, when any string key exists (or
260 | -- when non-positive numeric keys exist), numeric keys are converted to
261 | -- strings.
262 | --
263 | -- For example,
264 | -- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
265 | -- produces the JSON object
266 | -- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
267 | --
268 | -- To prohibit this conversion and instead make it an error condition, set
269 | -- JSON.noKeyConversion = true
270 | --
271 |
272 |
273 |
274 |
275 | --
276 | -- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT
277 | --
278 | -- assert
279 | -- onDecodeError
280 | -- onDecodeOfNilError
281 | -- onDecodeOfHTMLError
282 | -- onEncodeError
283 | --
284 | -- If you want to create a separate Lua JSON object with its own error handlers,
285 | -- you can reload JSON.lua or use the :new() method.
286 | --
287 | ---------------------------------------------------------------------------
288 |
289 | local default_pretty_indent = " "
290 | local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent }
291 |
292 | local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray
293 | local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject
294 |
295 |
296 | function OBJDEF:newArray(tbl)
297 | return setmetatable(tbl or {}, isArray)
298 | end
299 |
300 | function OBJDEF:newObject(tbl)
301 | return setmetatable(tbl or {}, isObject)
302 | end
303 |
304 | local function unicode_codepoint_as_utf8(codepoint)
305 | --
306 | -- codepoint is a number
307 | --
308 | if codepoint <= 127 then
309 | return string.char(codepoint)
310 |
311 | elseif codepoint <= 2047 then
312 | --
313 | -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8
314 | --
315 | local highpart = math.floor(codepoint / 0x40)
316 | local lowpart = codepoint - (0x40 * highpart)
317 | return string.char(0xC0 + highpart,
318 | 0x80 + lowpart)
319 |
320 | elseif codepoint <= 65535 then
321 | --
322 | -- 1110yyyy 10yyyyxx 10xxxxxx
323 | --
324 | local highpart = math.floor(codepoint / 0x1000)
325 | local remainder = codepoint - 0x1000 * highpart
326 | local midpart = math.floor(remainder / 0x40)
327 | local lowpart = remainder - 0x40 * midpart
328 |
329 | highpart = 0xE0 + highpart
330 | midpart = 0x80 + midpart
331 | lowpart = 0x80 + lowpart
332 |
333 | --
334 | -- Check for an invalid character (thanks Andy R. at Adobe).
335 | -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070
336 | --
337 | if ( highpart == 0xE0 and midpart < 0xA0 ) or
338 | ( highpart == 0xED and midpart > 0x9F ) or
339 | ( highpart == 0xF0 and midpart < 0x90 ) or
340 | ( highpart == 0xF4 and midpart > 0x8F )
341 | then
342 | return "?"
343 | else
344 | return string.char(highpart,
345 | midpart,
346 | lowpart)
347 | end
348 |
349 | else
350 | --
351 | -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
352 | --
353 | local highpart = math.floor(codepoint / 0x40000)
354 | local remainder = codepoint - 0x40000 * highpart
355 | local midA = math.floor(remainder / 0x1000)
356 | remainder = remainder - 0x1000 * midA
357 | local midB = math.floor(remainder / 0x40)
358 | local lowpart = remainder - 0x40 * midB
359 |
360 | return string.char(0xF0 + highpart,
361 | 0x80 + midA,
362 | 0x80 + midB,
363 | 0x80 + lowpart)
364 | end
365 | end
366 |
367 | function OBJDEF:onDecodeError(message, text, location, etc)
368 | if text then
369 | if location then
370 | message = string.format("%s at char %d of: %s", message, location, text)
371 | else
372 | message = string.format("%s: %s", message, text)
373 | end
374 | end
375 |
376 | if etc ~= nil then
377 | message = message .. " (" .. OBJDEF:encode(etc) .. ")"
378 | end
379 |
380 | if self.assert then
381 | self.assert(false, message)
382 | else
383 | assert(false, message)
384 | end
385 | end
386 |
387 | OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError
388 | OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError
389 |
390 | function OBJDEF:onEncodeError(message, etc)
391 | if etc ~= nil then
392 | message = message .. " (" .. OBJDEF:encode(etc) .. ")"
393 | end
394 |
395 | if self.assert then
396 | self.assert(false, message)
397 | else
398 | assert(false, message)
399 | end
400 | end
401 |
402 | local function grok_number(self, text, start, etc)
403 | --
404 | -- Grab the integer part
405 | --
406 | local integer_part = text:match('^-?[1-9]%d*', start)
407 | or text:match("^-?0", start)
408 |
409 | if not integer_part then
410 | self:onDecodeError("expected number", text, start, etc)
411 | end
412 |
413 | local i = start + integer_part:len()
414 |
415 | --
416 | -- Grab an optional decimal part
417 | --
418 | local decimal_part = text:match('^%.%d+', i) or ""
419 |
420 | i = i + decimal_part:len()
421 |
422 | --
423 | -- Grab an optional exponential part
424 | --
425 | local exponent_part = text:match('^[eE][-+]?%d+', i) or ""
426 |
427 | i = i + exponent_part:len()
428 |
429 | local full_number_text = integer_part .. decimal_part .. exponent_part
430 | local as_number = tonumber(full_number_text)
431 |
432 | if not as_number then
433 | self:onDecodeError("bad number", text, start, etc)
434 | end
435 |
436 | return as_number, i
437 | end
438 |
439 |
440 | local function grok_string(self, text, start, etc)
441 |
442 | if text:sub(start,start) ~= '"' then
443 | self:onDecodeError("expected string's opening quote", text, start, etc)
444 | end
445 |
446 | local i = start + 1 -- +1 to bypass the initial quote
447 | local text_len = text:len()
448 | local VALUE = ""
449 | while i <= text_len do
450 | local c = text:sub(i,i)
451 | if c == '"' then
452 | return VALUE, i + 1
453 | end
454 | if c ~= '\\' then
455 | VALUE = VALUE .. c
456 | i = i + 1
457 | elseif text:match('^\\b', i) then
458 | VALUE = VALUE .. "\b"
459 | i = i + 2
460 | elseif text:match('^\\f', i) then
461 | VALUE = VALUE .. "\f"
462 | i = i + 2
463 | elseif text:match('^\\n', i) then
464 | VALUE = VALUE .. "\n"
465 | i = i + 2
466 | elseif text:match('^\\r', i) then
467 | VALUE = VALUE .. "\r"
468 | i = i + 2
469 | elseif text:match('^\\t', i) then
470 | VALUE = VALUE .. "\t"
471 | i = i + 2
472 | else
473 | local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
474 | if hex then
475 | i = i + 6 -- bypass what we just read
476 |
477 | -- We have a Unicode codepoint. It could be standalone, or if in the proper range and
478 | -- followed by another in a specific range, it'll be a two-code surrogate pair.
479 | local codepoint = tonumber(hex, 16)
480 | if codepoint >= 0xD800 and codepoint <= 0xDBFF then
481 | -- it's a hi surrogate... see whether we have a following low
482 | local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
483 | if lo_surrogate then
484 | i = i + 6 -- bypass the low surrogate we just read
485 | codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16)
486 | else
487 | -- not a proper low, so we'll just leave the first codepoint as is and spit it out.
488 | end
489 | end
490 | VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint)
491 |
492 | else
493 |
494 | -- just pass through what's escaped
495 | VALUE = VALUE .. text:match('^\\(.)', i)
496 | i = i + 2
497 | end
498 | end
499 | end
500 |
501 | self:onDecodeError("unclosed string", text, start, etc)
502 | end
503 |
504 | local function skip_whitespace(text, start)
505 |
506 | local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2
507 | if match_end then
508 | return match_end + 1
509 | else
510 | return start
511 | end
512 | end
513 |
514 | local grok_one -- assigned later
515 |
516 | local function grok_object(self, text, start, etc)
517 | if text:sub(start,start) ~= '{' then
518 | self:onDecodeError("expected '{'", text, start, etc)
519 | end
520 |
521 | local i = skip_whitespace(text, start + 1) -- +1 to skip the '{'
522 |
523 | local VALUE = self.strictTypes and self:newObject { } or { }
524 |
525 | if text:sub(i,i) == '}' then
526 | return VALUE, i + 1
527 | end
528 | local text_len = text:len()
529 | while i <= text_len do
530 | local key, new_i = grok_string(self, text, i, etc)
531 |
532 | i = skip_whitespace(text, new_i)
533 |
534 | if text:sub(i, i) ~= ':' then
535 | self:onDecodeError("expected colon", text, i, etc)
536 | end
537 |
538 | i = skip_whitespace(text, i + 1)
539 |
540 | local new_val, new_i = grok_one(self, text, i)
541 |
542 | VALUE[key] = new_val
543 |
544 | --
545 | -- Expect now either '}' to end things, or a ',' to allow us to continue.
546 | --
547 | i = skip_whitespace(text, new_i)
548 |
549 | local c = text:sub(i,i)
550 |
551 | if c == '}' then
552 | return VALUE, i + 1
553 | end
554 |
555 | if text:sub(i, i) ~= ',' then
556 | self:onDecodeError("expected comma or '}'", text, i, etc)
557 | end
558 |
559 | i = skip_whitespace(text, i + 1)
560 | end
561 |
562 | self:onDecodeError("unclosed '{'", text, start, etc)
563 | end
564 |
565 | local function grok_array(self, text, start, etc)
566 | if text:sub(start,start) ~= '[' then
567 | self:onDecodeError("expected '['", text, start, etc)
568 | end
569 |
570 | local i = skip_whitespace(text, start + 1) -- +1 to skip the '['
571 | local VALUE = self.strictTypes and self:newArray { } or { }
572 | if text:sub(i,i) == ']' then
573 | return VALUE, i + 1
574 | end
575 |
576 | local VALUE_INDEX = 1
577 |
578 | local text_len = text:len()
579 | while i <= text_len do
580 | local val, new_i = grok_one(self, text, i)
581 |
582 | -- can't table.insert(VALUE, val) here because it's a no-op if val is nil
583 | VALUE[VALUE_INDEX] = val
584 | VALUE_INDEX = VALUE_INDEX + 1
585 |
586 | i = skip_whitespace(text, new_i)
587 |
588 | --
589 | -- Expect now either ']' to end things, or a ',' to allow us to continue.
590 | --
591 | local c = text:sub(i,i)
592 | if c == ']' then
593 | return VALUE, i + 1
594 | end
595 | if text:sub(i, i) ~= ',' then
596 | self:onDecodeError("expected comma or '['", text, i, etc)
597 | end
598 | i = skip_whitespace(text, i + 1)
599 | end
600 | self:onDecodeError("unclosed '['", text, start, etc)
601 | end
602 |
603 |
604 | grok_one = function(self, text, start, etc)
605 | -- Skip any whitespace
606 | start = skip_whitespace(text, start)
607 |
608 | if start > text:len() then
609 | self:onDecodeError("unexpected end of string", text, nil, etc)
610 | end
611 |
612 | if text:find('^"', start) then
613 | return grok_string(self, text, start, etc)
614 |
615 | elseif text:find('^[-0123456789 ]', start) then
616 | return grok_number(self, text, start, etc)
617 |
618 | elseif text:find('^%{', start) then
619 | return grok_object(self, text, start, etc)
620 |
621 | elseif text:find('^%[', start) then
622 | return grok_array(self, text, start, etc)
623 |
624 | elseif text:find('^true', start) then
625 | return true, start + 4
626 |
627 | elseif text:find('^false', start) then
628 | return false, start + 5
629 |
630 | elseif text:find('^null', start) then
631 | return nil, start + 4
632 |
633 | else
634 | self:onDecodeError("can't parse JSON", text, start, etc)
635 | end
636 | end
637 |
638 | function OBJDEF:decode(text, etc)
639 | if type(self) ~= 'table' or self.__index ~= OBJDEF then
640 | OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, etc)
641 | end
642 |
643 | if text == nil then
644 | self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, etc)
645 | elseif type(text) ~= 'string' then
646 | self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, etc)
647 | end
648 |
649 | if text:match('^%s*$') then
650 | return nil
651 | end
652 |
653 | if text:match('^%s*<') then
654 | -- Can't be JSON... we'll assume it's HTML
655 | self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, etc)
656 | end
657 |
658 | --
659 | -- Ensure that it's not UTF-32 or UTF-16.
660 | -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3),
661 | -- but this package can't handle them.
662 | --
663 | if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then
664 | self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, etc)
665 | end
666 |
667 | local success, value = pcall(grok_one, self, text, 1, etc)
668 |
669 | if success then
670 | return value
671 | else
672 | -- if JSON:onDecodeError() didn't abort out of the pcall, we'll have received the error message here as "value", so pass it along as an assert.
673 | if self.assert then
674 | self.assert(false, value)
675 | else
676 | assert(false, value)
677 | end
678 | -- and if we're still here, return a nil and throw the error message on as a second arg
679 | return nil, value
680 | end
681 | end
682 |
683 | local function backslash_replacement_function(c)
684 | if c == "\n" then
685 | return "\\n"
686 | elseif c == "\r" then
687 | return "\\r"
688 | elseif c == "\t" then
689 | return "\\t"
690 | elseif c == "\b" then
691 | return "\\b"
692 | elseif c == "\f" then
693 | return "\\f"
694 | elseif c == '"' then
695 | return '\\"'
696 | elseif c == '\\' then
697 | return '\\\\'
698 | else
699 | return string.format("\\u%04x", c:byte())
700 | end
701 | end
702 |
703 | local chars_to_be_escaped_in_JSON_string
704 | = '['
705 | .. '"' -- class sub-pattern to match a double quote
706 | .. '%\\' -- class sub-pattern to match a backslash
707 | .. '%z' -- class sub-pattern to match a null
708 | .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters
709 | .. ']'
710 |
711 | local function json_string_literal(value)
712 | local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function)
713 | return '"' .. newval .. '"'
714 | end
715 |
716 | local function object_or_array(self, T, etc)
717 | --
718 | -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON
719 | -- object. If there are only numbers, it's a JSON array.
720 | --
721 | -- If we'll be converting to a JSON object, we'll want to sort the keys so that the
722 | -- end result is deterministic.
723 | --
724 | local string_keys = { }
725 | local number_keys = { }
726 | local number_keys_must_be_strings = false
727 | local maximum_number_key
728 |
729 | for key in pairs(T) do
730 | if type(key) == 'string' then
731 | table.insert(string_keys, key)
732 | elseif type(key) == 'number' then
733 | table.insert(number_keys, key)
734 | if key <= 0 or key >= math.huge then
735 | number_keys_must_be_strings = true
736 | elseif not maximum_number_key or key > maximum_number_key then
737 | maximum_number_key = key
738 | end
739 | else
740 | self:onEncodeError("can't encode table with a key of type " .. type(key), etc)
741 | end
742 | end
743 |
744 | if #string_keys == 0 and not number_keys_must_be_strings then
745 | --
746 | -- An empty table, or a numeric-only array
747 | --
748 | if #number_keys > 0 then
749 | return nil, maximum_number_key -- an array
750 | elseif tostring(T) == "JSON array" then
751 | return nil
752 | elseif tostring(T) == "JSON object" then
753 | return { }
754 | else
755 | -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects
756 | return nil
757 | end
758 | end
759 |
760 | table.sort(string_keys)
761 |
762 | local map
763 | if #number_keys > 0 then
764 | --
765 | -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array
766 | -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object.
767 | --
768 |
769 | if self.noKeyConversion then
770 | self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc)
771 | end
772 |
773 | --
774 | -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings
775 | --
776 | map = { }
777 | for key, val in pairs(T) do
778 | map[key] = val
779 | end
780 |
781 | table.sort(number_keys)
782 |
783 | --
784 | -- Throw numeric keys in there as strings
785 | --
786 | for _, number_key in ipairs(number_keys) do
787 | local string_key = tostring(number_key)
788 | if map[string_key] == nil then
789 | table.insert(string_keys , string_key)
790 | map[string_key] = T[number_key]
791 | else
792 | self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
793 | end
794 | end
795 | end
796 |
797 | return string_keys, nil, map
798 | end
799 |
800 | --
801 | -- Encode
802 | --
803 | -- 'options' is nil, or a table with possible keys:
804 | -- pretty -- if true, return a pretty-printed version
805 | -- indent -- a string (usually of spaces) used to indent each nested level
806 | -- align_keys -- if true, align all the keys when formatting a table
807 | --
808 | local encode_value -- must predeclare because it calls itself
809 | function encode_value(self, value, parents, etc, options, indent)
810 |
811 | if value == nil then
812 | return 'null'
813 |
814 | elseif type(value) == 'string' then
815 | return json_string_literal(value)
816 |
817 | elseif type(value) == 'number' then
818 | if value ~= value then
819 | --
820 | -- NaN (Not a Number).
821 | -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option.
822 | --
823 | return "null"
824 | elseif value >= math.huge then
825 | --
826 | -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should
827 | -- really be a package option. Note: at least with some implementations, positive infinity
828 | -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is.
829 | -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">="
830 | -- case first.
831 | --
832 | return "1e+9999"
833 | elseif value <= -math.huge then
834 | --
835 | -- Negative infinity.
836 | -- JSON has no INF, so we have to fudge the best we can. This should really be a package option.
837 | --
838 | return "-1e+9999"
839 | else
840 | return tostring(value)
841 | end
842 |
843 | elseif type(value) == 'boolean' then
844 | return tostring(value)
845 |
846 | elseif type(value) ~= 'table' then
847 | self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
848 |
849 | else
850 | --
851 | -- A table to be converted to either a JSON object or array.
852 | --
853 | local T = value
854 |
855 | if type(options) ~= 'table' then
856 | options = {}
857 | end
858 | if type(indent) ~= 'string' then
859 | indent = ""
860 | end
861 |
862 | if parents[T] then
863 | self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
864 | else
865 | parents[T] = true
866 | end
867 |
868 | local result_value
869 |
870 | local object_keys, maximum_number_key, map = object_or_array(self, T, etc)
871 | if maximum_number_key then
872 | --
873 | -- An array...
874 | --
875 | local ITEMS = { }
876 | for i = 1, maximum_number_key do
877 | table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent))
878 | end
879 |
880 | if options.pretty then
881 | result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]"
882 | else
883 | result_value = "[" .. table.concat(ITEMS, ",") .. "]"
884 | end
885 |
886 | elseif object_keys then
887 | --
888 | -- An object
889 | --
890 | local TT = map or T
891 |
892 | if options.pretty then
893 |
894 | local KEYS = { }
895 | local max_key_length = 0
896 | for _, key in ipairs(object_keys) do
897 | local encoded = encode_value(self, tostring(key), parents, etc, options, indent)
898 | if options.align_keys then
899 | max_key_length = math.max(max_key_length, #encoded)
900 | end
901 | table.insert(KEYS, encoded)
902 | end
903 | local key_indent = indent .. tostring(options.indent or "")
904 | local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "")
905 | local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s"
906 |
907 | local COMBINED_PARTS = { }
908 | for i, key in ipairs(object_keys) do
909 | local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent)
910 | table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val))
911 | end
912 | result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}"
913 |
914 | else
915 |
916 | local PARTS = { }
917 | for _, key in ipairs(object_keys) do
918 | local encoded_val = encode_value(self, TT[key], parents, etc, options, indent)
919 | local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent)
920 | table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val))
921 | end
922 | result_value = "{" .. table.concat(PARTS, ",") .. "}"
923 |
924 | end
925 | else
926 | --
927 | -- An empty array/object... we'll treat it as an array, though it should really be an option
928 | --
929 | result_value = "[]"
930 | end
931 |
932 | parents[T] = false
933 | return result_value
934 | end
935 | end
936 |
937 |
938 | function OBJDEF:encode(value, etc, options)
939 | if type(self) ~= 'table' or self.__index ~= OBJDEF then
940 | OBJDEF:onEncodeError("JSON:encode must be called in method format", etc)
941 | end
942 | return encode_value(self, value, {}, etc, options or nil)
943 | end
944 |
945 | function OBJDEF:encode_pretty(value, etc, options)
946 | if type(self) ~= 'table' or self.__index ~= OBJDEF then
947 | OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc)
948 | end
949 | return encode_value(self, value, {}, etc, options or default_pretty_options)
950 | end
951 |
952 | function OBJDEF.__tostring()
953 | return "JSON encode/decode package"
954 | end
955 |
956 | OBJDEF.__index = OBJDEF
957 |
958 | function OBJDEF:new(args)
959 | local new = { }
960 |
961 | if args then
962 | for key, val in pairs(args) do
963 | new[key] = val
964 | end
965 | end
966 |
967 | return setmetatable(new, OBJDEF)
968 | end
969 |
970 | return OBJDEF:new()
971 |
972 | --
973 | -- Version history:
974 | --
975 | -- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really
976 | -- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines
977 | -- more flexible, and changed the default encode_pretty() to be more generally useful.
978 | --
979 | -- Added a third 'options' argument to the encode() and encode_pretty() routines, to control
980 | -- how the encoding takes place.
981 | --
982 | -- Updated docs to add assert() call to the loadfile() line, just as good practice so that
983 | -- if there is a problem loading JSON.lua, the appropriate error message will percolate up.
984 | --
985 | -- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string,
986 | -- so that the source of the package, and its version number, are visible in compiled copies.
987 | --
988 | -- 20140911.12 Minor lua cleanup.
989 | -- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'.
990 | -- (Thanks to SmugMug's David Parry for these.)
991 | --
992 | -- 20140418.11 JSON nulls embedded within an array were being ignored, such that
993 | -- ["1",null,null,null,null,null,"seven"],
994 | -- would return
995 | -- {1,"seven"}
996 | -- It's now fixed to properly return
997 | -- {1, nil, nil, nil, nil, nil, "seven"}
998 | -- Thanks to "haddock" for catching the error.
999 | --
1000 | -- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up.
1001 | --
1002 | -- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2",
1003 | -- and this caused some problems.
1004 | --
1005 | -- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate,
1006 | -- and had of course diverged (encode_pretty didn't get the fixes that encode got, so
1007 | -- sometimes produced incorrect results; thanks to Mattie for the heads up).
1008 | --
1009 | -- Handle encoding tables with non-positive numeric keys (unlikely, but possible).
1010 | --
1011 | -- If a table has both numeric and string keys, or its numeric keys are inappropriate
1012 | -- (such as being non-positive or infinite), the numeric keys are turned into
1013 | -- string keys appropriate for a JSON object. So, as before,
1014 | -- JSON:encode({ "one", "two", "three" })
1015 | -- produces the array
1016 | -- ["one","two","three"]
1017 | -- but now something with mixed key types like
1018 | -- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
1019 | -- instead of throwing an error produces an object:
1020 | -- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
1021 | --
1022 | -- To maintain the prior throw-an-error semantics, set
1023 | -- JSON.noKeyConversion = true
1024 | --
1025 | -- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry.
1026 | --
1027 | -- 20130120.6 Comment update: added a link to the specific page on my blog where this code can
1028 | -- be found, so that folks who come across the code outside of my blog can find updates
1029 | -- more easily.
1030 | --
1031 | -- 20111207.5 Added support for the 'etc' arguments, for better error reporting.
1032 | --
1033 | -- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent.
1034 | --
1035 | -- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules:
1036 | --
1037 | -- * When encoding lua for JSON, Sparse numeric arrays are now handled by
1038 | -- spitting out full arrays, such that
1039 | -- JSON:encode({"one", "two", [10] = "ten"})
1040 | -- returns
1041 | -- ["one","two",null,null,null,null,null,null,null,"ten"]
1042 | --
1043 | -- In 20100810.2 and earlier, only up to the first non-null value would have been retained.
1044 | --
1045 | -- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999".
1046 | -- Version 20100810.2 and earlier created invalid JSON in both cases.
1047 | --
1048 | -- * Unicode surrogate pairs are now detected when decoding JSON.
1049 | --
1050 | -- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding
1051 | --
1052 | -- 20100731.1 initial public release
1053 | --
1054 |
--------------------------------------------------------------------------------
/bot.lua:
--------------------------------------------------------------------------------
1 | tdcli = dofile('./tdcli.lua')
2 | URL = require "socket.url"
3 | http = require "socket.http"
4 | https = require "ssl.https"
5 | ltn12 = require "ltn12"
6 | serpent = require ("serpent")
7 | db = require('redis')
8 | redis = db.connect('127.0.0.1', 6379)
9 | JSON = require('dkjson')
10 | http.TIMEOUT = 10
11 | --###############################--
12 | sudo_users = {305941305}
13 |
14 | --##########GetMessage###########--
15 | local function getMessage(chat_id, message_id,callback)
16 | tdcli_function ({
17 | ID = "GetMessage",
18 | chat_id_ = chat_id,
19 | message_id_ = message_id
20 | }, callback, nil)
21 | end
22 |
23 | --###############################--
24 | function is_sudo(msg)
25 | local var = false
26 | for v,user in pairs(sudo_users) do
27 | if user == msg.sender_user_id_ then
28 | var = true
29 | end
30 | end
31 | return var
32 | end
33 | --###############################--
34 | function is_owner(msg)
35 | local var = false
36 | local group_mods = redis:get('owners:'..msg.chat_id_)
37 | if group_mods == tostring(msg.sender_user_id_) then
38 | var = true
39 | end
40 | for v, user in pairs(sudo_users) do
41 | if user == msg.sender_user_id_ then
42 | var = true
43 | end
44 | end
45 | return var
46 | end
47 | --###############################--
48 | function is_momod(msg)
49 | local var = false
50 | if redis:sismember('mods:'..msg.chat_id_,msg.sender_user_id_) then
51 | var = true
52 | end
53 | if redis:get('owners:'..msg.chat_id_) == tostring(msg.sender_user_id_) then
54 | var = true
55 | end
56 | for v, user in pairs(sudo_users) do
57 | if user == msg.sender_user_id_ then
58 | var = true
59 | end
60 | end
61 | return var
62 | end
63 | --###############################--
64 | function is_banned(msg)
65 | local var = false
66 | local chat_id = msg.chat_id_
67 | local user_id = msg.sender_user_id_
68 | local hash = 'banned:'..chat_id
69 | local banned = redis:sismember(hash, user_id)
70 | if banned then
71 | var = true
72 | end
73 | return var
74 | end
75 | --###############################--
76 | function is_muted(msg)
77 | local var = false
78 | local chat_id = msg.chat_id_
79 | local user_id = msg.sender_user_id_
80 | local hash = 'muteusers:'..chat_id
81 | local muted = redis:sismember(hash, user_id)
82 | if muted then
83 | var = true
84 | end
85 | return var
86 | end
87 | --###############################--
88 | function is_gbanned(msg)
89 | local var = false
90 | local chat_id = msg.chat_id_
91 | local user_id = msg.sender_user_id_
92 | local hash = 'gbanned:'
93 | local banned = redis:sismember(hash, user_id)
94 | if banned then
95 | var = true
96 | end
97 | return var
98 | end
99 | --###############################--
100 | function vardump(value)
101 | print(serpent.block(value, {comment=false}))
102 | end
103 | function run(data,edited_msg)
104 | local msg = data.message_
105 | if edited_msg then
106 | msg = data
107 | end
108 | -- vardump(msg)
109 | local input = msg.content_.text_
110 | local chat_id = msg.chat_id_
111 | local user_id = msg.sender_user_id_
112 | local botgp = redis:get("addedgp"..chat_id)
113 | local wlcmsg = "wlc"..chat_id
114 | local setwlc = "setwlc"..chat_id
115 | local floodMax = "floodMax"..chat_id
116 | local floodTime = "floodTime"..chat_id
117 | local mutehash = 'muteall:'..chat_id
118 | local hashflood = "flood"..chat_id
119 | local hashbot = "bot"..chat_id
120 | local hashlink = "link"..chat_id
121 | local hashtag = "tag"..chat_id
122 | local hashusername = "username"..chat_id
123 | local hashforward = "forward"..chat_id
124 | local hasharabic = "arabic"..chat_id
125 | local hashtgservice = "tgservice"..chat_id
126 | local hasheng = "eng"..chat_id
127 | local hashbadword = "badword"..chat_id
128 | local hashedit = "edit"..chat_id
129 | local hashinline = "inline"..chat_id
130 | local hashemoji = "emoji"..chat_id
131 | local hashall = "all"..chat_id
132 | local hashsticker = "sticker"..chat_id
133 | local hashgif = "gif"..chat_id
134 | local hashcontact = "contact"..chat_id
135 | local hashphoto = "photo"..chat_id
136 | local hashaudio = "audio"..chat_id
137 | local hashvoice = "voice"..chat_id
138 | local hashvideo = "video"..chat_id
139 | local hashdocument = "document"..chat_id
140 | local hashtext1 = "text"..chat_id
141 | if not botgp and not is_sudo(msg) then
142 | return false
143 | end
144 | if msg.chat_id_ then
145 | local id = tostring(msg.chat_id_)
146 | if id:match('-100(%d+)') then
147 | chat_type = 'super'
148 | elseif id:match('^(%d+)') then
149 | chat_type = 'user'
150 | else
151 | chat_type = 'group'
152 | end
153 | end
154 | -------------------------------------------------------------------------------------------
155 | if redis:get(mutehash) == 'Enable' and not is_momod(msg) then
156 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
157 | end
158 | if msg.content_.sticker_ and redis:get(hashsticker) == 'Enable' and not is_momod(msg) then
159 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
160 | end
161 | if msg.content_.animation_ and redis:get(hashgif) == 'Enable' and not is_momod(msg) then
162 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
163 | end
164 | if msg.content_.contact_ and redis:get(hashgif) == 'Enable' and not is_momod(msg) then
165 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
166 | end
167 | if msg.content_.photo_ and redis:get(hashgif) == 'Enable' and not is_momod(msg) then
168 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
169 | end
170 | if msg.content_.audio_ and redis:get(hashaudio) == 'Enable' and not is_momod(msg) then
171 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
172 | end
173 | if msg.content_.voice_ and redis:get(hashvoice) == 'Enable' and not is_momod(msg) then
174 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
175 | end
176 | if msg.content_.video_ and redis:get(hashvideo) == 'Enable' and not is_momod(msg) then
177 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
178 | end
179 | if msg.content_.document_ and redis:get(hashdocument) == 'Enable' and not is_momod(msg) then
180 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
181 | end
182 | if msg.forward_info_ and redis:get(hashforward) == 'Enable' and not is_momod(msg) then
183 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
184 | end
185 | if msg.via_bot_user_id_ ~= 0 and redis:get(hashinline) == 'Enable' and not is_momod(msg) then
186 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
187 | end
188 |
189 | local floodMax = redis:get('floodMax') or 10
190 | local floodTime = redis:get('floodTime') or 150
191 | if msg and redis:get(hashflood) == 'Enable' and not is_momod(msg) then
192 | local hash = 'flood:'..msg.sender_user_id_..':'..msg.chat_id_..':msg-num'
193 | local msgs = tonumber(redis:get(hash) or 0)
194 | if msgs > (floodMax - 1) then
195 | tdcli.changeChatMemberStatus(msg.chat_id_, msg.sender_user_id_, "Kicked")
196 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر _'..msg.sender_user_id_..' به دلیل ارسال اسپم حذف شد!', 1, 'md')
197 | redis:setex(hash, floodTime, msgs+1)
198 | end
199 | end
200 |
201 |
202 | if msg.content_.ID == "MessageText" then
203 | local is_link_msg = input:match("[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm].[Mm][Ee]/") or input:match("[Tt].[Mm][Ee]/")
204 | if redis:get(hashlink) and is_link_msg and not is_momod(msg) then
205 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
206 | end
207 | if redis:get(hashtag) and input:match("#") and not is_momod(msg) then
208 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
209 | end
210 | if redis:get(hashusername) and input:match("@") and not is_momod(msg) then
211 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
212 |
213 | end
214 | if redis:get(hasharabic) and input:match("[\216-\219][\128-\191]") and not is_momod(msg) then
215 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
216 | end
217 | local is_english_msg = input:match("[a-z]") or input:match("[A-Z]")
218 | if redis:get(hasheng) and msg.content_.text_ and is_english_msg and not is_momod(msg) then
219 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
220 | end
221 | local is_fosh_msg = input:match("کیر") or input:match("کس") or input:match("کون") or input:match("85") or input:match("جنده") or input:match("ننه") or input:match("ننت") or input:match("مادر") or input:match("قهبه") or input:match("گایی") or input:match("سکس") or input:match("kir") or input:match("kos") or input:match("kon") or input:match("nne") or input:match("nnt")
222 | if redis:get(hashbadword) and is_fosh_msg and not is_momod(msg) then
223 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
224 | end
225 | local is_emoji_msg = input:match("😀") or input:match("😬") or input:match("😁") or input:match("😂") or input:match("😃") or input:match("😄") or input:match("😅") or input:match("☺️") or input:match("🙃") or input:match("🙂") or input:match("😊") or input:match("😉") or input:match("😇") or input:match("😆") or input:match("😋") or input:match("😌") or input:match("😍") or input:match("😘") or input:match("😗") or input:match("😙") or input:match("😚") or input:match("🤗") or input:match("😎") or input:match("🤓") or input:match("🤑") or input:match("😛") or input:match("😏") or input:match("😶") or input:match("😐") or input:match("😑") or input:match("😒") or input:match("🙄") or input:match("🤔") or input:match("😕") or input:match("😔") or input:match("😡") or input:match("😠") or input:match("😟") or input:match("😞") or input:match("😳") or input:match("🙁") or input:match("☹️") or input:match("😣") or input:match("😖") or input:match("😫") or input:match("😩") or input:match("😤") or input:match("😲") or input:match("😵") or input:match("😭") or input:match("😓") or input:match("😪") or input:match("😥") or input:match("😢") or input:match("🤐") or input:match("😷") or input:match("🤒") or input:match("🤕") or input:match("😴") or input:match("💋") or input:match("❤️")
226 | if redis:get(hashemoji) and is_emoji_msg and not is_momod(msg) then
227 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
228 | end
229 | end
230 | --###############################--
231 | local text = msg.content_.text_
232 | -- if text and text:match('[QWERTYUIOPASDFGHJKLZXCVBNM]') then
233 | -- text = text:lower()
234 | -- end
235 | if msg.content_.ID == "MessageText" then
236 | msg_type = 'text'
237 | if msg_type == 'text' and text and text:match('^[/$#!]') then
238 | text = text:gsub('^[/$!#]','')
239 | end
240 | end
241 | if text == "p r" and is_sudo(msg) then
242 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'ربات* موفقیت ریلود شد*',1, 'html')
243 | io.popen("pkill tg")
244 | end
245 | if text == "ping" then
246 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '*انلاینم....!*',1, 'md')
247 | end
248 | local hashadd = "addedgp"..chat_id
249 | if text == "add" and is_sudo(msg) then
250 | if botgp then
251 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '*ربات از قبل با موفقیت فعال شده بود!*', 1, 'md')
252 | else
253 | redis:set(hashadd, true)
254 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '*ربات با موفقیت فعال شد.*', 1, 'md')
255 | end
256 | end
257 | if text == "rem" and is_sudo(msg) then
258 | if not botgp then
259 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '*ربات از قبل با موفقیت غیر فعال شده بود!*', 1, 'md')
260 | else
261 | redis:del(hashadd, true)
262 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '*ربات با موفقیت غیر فعال شد.*', 1, 'md')
263 | end
264 | end
265 |
266 | if text == "setowner" and is_owner(msg) and msg.reply_to_message_id_ then
267 | function setowner_reply(extra, result, success)
268 | redis:del('owners:'..result.chat_id_)
269 | redis:set('owners:'..result.chat_id_,result.sender_user_id_)
270 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر *'..result.sender_user_id_..'* باموفقیت مالک گروه شد', 1, 'md')
271 | end
272 | getMessage(chat_id,msg.reply_to_message_id_,setowner_reply,nil)
273 | end
274 | if text == "owners" then
275 | local hash = 'owners:'..chat_id
276 | local owner = redis:get(hash)
277 | if owner == nil then
278 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'گروه هیچ مالکی ندارد ', 1, 'md')
279 | end
280 | local owner_list = redis:get('owners:'..chat_id)
281 | text = '* مالک گروه:* '..owner_list
282 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
283 | end
284 | if text and text:match('^setowner (.*)') and not text:find('@') and is_sudo(msg) then
285 | local so = {string.match(text, "^setowner (.*)$")}
286 | redis:del('owners:'..chat_id)
287 | redis:set('owners:'..chat_id,so[1])
288 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..so[1]..' به موفقیت مالک گروه شد', 1, 'md')
289 | end
290 | if text and text:match('^setowner (.*)') and text:find('@') and is_owner(msg) then
291 | local sou = {string.match(text, "^setowner (.*)$")}
292 | function Inline_Callback_(arg, data)
293 | redis:del('owners:'..chat_id)
294 | redis:set('owners:'..chat_id,sou[1])
295 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..sou[1]..' با موفقیت مالک گروه شد', 1, 'md')
296 | end
297 | tdcli_function ({ID = "SearchPublicChat",username_ =sou[1]}, Inline_Callback_, nil)
298 | end
299 |
300 |
301 | if text == "promote" and is_sudo(msg) and msg.reply_to_message_id_ then
302 | function setmod_reply(extra, result, success)
303 | redis:sadd('mods:'..result.chat_id_,result.sender_user_id_)
304 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..result.sender_user_id_..' به لیست ناظران گروه اضافه شد', 1, 'md')
305 | end
306 | getMessage(chat_id,msg.reply_to_message_id_,setmod_reply,nil)
307 | end
308 | if text == "demote" and is_sudo(msg) and msg.reply_to_message_id_ then
309 | function remmod_reply(extra, result, success)
310 | redis:srem('mods:'..result.chat_id_,result.sender_user_id_)
311 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..result.sender_user_id_..' از لیست ناظران گروه حذف شد', 1, 'md')
312 | end
313 | getMessage(chat_id,msg.reply_to_message_id_,remmod_reply,nil)
314 | end
315 | if text and text:match('^promote (.*)') and not text:find('@') and is_sudo(msg) then
316 | local pm = {string.match(text, "^promote (.*)$")}
317 | redis:sadd('mods:'..chat_id,pm[1])
318 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..pm[1]..' به لیست ناظران گروه اضافه شد', 1, 'md')
319 | end
320 | if text and text:match('^demote (.*)') and not text:find('@') and is_sudo(msg) then
321 | local dm = {string.match(text, "^demote (.*)$")}
322 | redis:srem('mods:'..chat_id,dm[1])
323 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..dm[1]..' از لیست ناظران گروه حذف شد', 1, 'md')
324 | end
325 | if text == "modlist" then
326 | if redis:scard('mods:'..chat_id) == 0 then
327 | text = "لیست ناظران گروه خالی است"
328 | else
329 | text = "لیست ناظران گروه\n"
330 | for k,v in pairs(redis:smembers('mods:'..chat_id)) do
331 | text = text..""..k.." - "..v.."\n"
332 | end
333 | end
334 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'html')
335 | end
336 | --[[if txet == "ban" and is_momod(msg) then
337 | function ban_reply(extra, result, success)
338 | redis:sadd('banned:'..result.chat_id_,result.sender_user_id_)
339 | tdcli.changeChatMemberStatus(result.chat_id_, result.sender_user_id_, 'Kicked')
340 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..result.sender_user_id_..' به لیست افراد بن شده اضافه شد', 1, 'md')
341 | end
342 | getMessage(chat_id,reply,ban_reply,nil)
343 | end
344 | end
345 | if text and text:match('^ban (.*)') and not text:find('@') and is_momod(msg) then
346 | local ki = {string.match(text, "^ban (.*)$")}
347 | redis:sadd('banned:'..chat_id,ki[1])
348 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..ki[1]..' به لیست افراد بن شده اضافه شد', 1, 'md')
349 | tdcli.changeChatMemberStatus(chat_id, ki[1], 'Kicked')
350 | end
351 | if text and text:match('^ban @(.*)') and is_momod(msg) then
352 | local ku = {string.match(text, "^ban @(.*)$")}
353 | redis:sadd('banned:'..chat_id,ku[1])
354 | function Inline_Callback_(arg, data)
355 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..ku[1]..' به لیست افراد بن شده اضافه شد', 1, 'html')
356 | tdcli.changeChatMemberStatus(chat_id, data.id_, 'Kicked')
357 | end
358 |
359 | if txet == "unban" and is_momod(msg) then
360 | function unban_reply(extra, result, success)
361 | redis:srem('banned:'..result.chat_id_,result.sender_user_id_)
362 |
363 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..result.sender_user_id_..' از لیست افراد بن شده حذف شد', 1, 'md')
364 | end
365 | getMessage(chat_id,reply,unban_reply,nil)
366 | end
367 | if text and text:match('^unban (.*)') and not text:find('@') and is_momod(msg) then
368 | local ki = {string.match(text, "^unban (.*)$")}
369 | redis:srem('banned:'..chat_id,ub[1])
370 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..ub[1]..' از لیست افراد بن شده حذف شد', 1, 'md')
371 | end
372 | if text and text:match('^unban @(.*)') and is_momod(msg) then
373 | local ku = {string.match(text, "^unban @(.*)$")}
374 | redis:srem('banned:'..chat_id,unb[1])
375 | function Inline_Callback_(arg, data)
376 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..unb[1]..' از لیست افراد بن شده حذف شد', 1, 'html')
377 | end
378 | tdcli_function ({ID = "SearchPublicChat",username_ =unb[1]}, Inline_Callback_, nil)
379 | end]]--
380 | if text == "banlist" then
381 |
382 | if redis:scard('banned:'..chat_id) == 0 then
383 | text = "لیست بن های گروه خالی است"
384 | else
385 | text = "بن لیست گروه\n"
386 | for k,v in pairs(redis:smembers('banned:'..chat_id)) do
387 | text = text..""..k.." - "..v.."\n"
388 | end
389 | end
390 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'html')
391 | end
392 | if text == "muteuser" and is_momod(msg) and msg.reply_to_message_id_ then
393 | function setmute_reply(extra, result, success)
394 | redis:sadd('muteusers:'..result.chat_id_,result.sender_user_id_)
395 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..result.sender_user_id_..' به لیست ساکت ها اضافه شد', 1, 'md')
396 | end
397 | getMessage(chat_id,msg.reply_to_message_id_,setmute_reply,nil)
398 | end
399 | if text == "unmuteuser" and is_momod(msg) and msg.reply_to_message_id_ then
400 | function demute_reply(extra, result, success)
401 | redis:srem('muteusers:'..result.chat_id_,result.sender_user_id_)
402 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..result.sender_user_id_..' از لیست ساکت ها حذف شد', 1, 'md')
403 | end
404 | getMessage(chat_id,msg.reply_to_message_id_,demute_reply,nil)
405 | end
406 | if text and text:match("^muteuser (%d+)") and is_momod(msg) then
407 | local mt = {string.match(text, "^muteuser (%d+)$")}
408 | redis:sadd('muteusers:'..chat_id,mt[1])
409 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..mt[1]..' به لیست ساکت ها اضافه شد', 1, 'md')
410 | end
411 | if text and text:match('^unmuteuser (%d+)$') and is_momod(msg) then
412 | local umt = {string.match(text, "^muteuser (%d+)$")}
413 | redis:srem('muteusers:'..chat_id,umt[1])
414 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'کاربر '..umt[1]..' از لیست ساکت ها حذف شد', 1, 'md')
415 | end
416 | if text == "mutelist" then
417 | if redis:scard('muteusers:'..chat_id) == 0 then
418 | text = "لیست بن های گروه خالی است"
419 | else
420 | text = "بن لیست گروه\n"
421 | for k,v in pairs(redis:smembers('muteusers:'..chat_id)) do
422 | text = text..""..k.." - "..v.."\n"
423 | end
424 | end
425 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'html')
426 | end
427 | if text and text:match("^clean (.*)$") and is_momod(msg) then
428 | local txt = {string.match(text, "^(clean) (.*)$")}
429 | if txt[2] == 'banlist' then
430 | redis:del('banned:'..msg.chat_id_)
431 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '_لیست بن با موفقیت حذف شد_', 1, 'md')
432 | end
433 | if txt[2] == 'modlist' then
434 | redis:del('mods:'..msg.chat_id_)
435 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '_لیست ناظران گروه با موفقیت حذف شد _', 1, 'md')
436 | end
437 | if txt[2] == 'mutelist' then
438 | redis:del('muted:'..msg.chat_id_)
439 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '_لیست ساکت های گروه با موفقیت حذف شد_', 1, 'md')
440 | end
441 |
442 | end
443 | if text == "delall" and msg.reply_to_message_id_ then
444 | function delall(extra, result, success)
445 | tdcli.deleteMessagesFromUser(result.chat_id_, result.sender_user_id_)
446 | end
447 | getMessage(chat_id, msg.reply_to_message_id_, delall, nil)
448 | end
449 | if text and text:match('^setlink (.*)/joinchat/(.*)') and is_owner(msg) then
450 | local l = {string.match(text, '^setlink (.*)/joinchat/(.*)')}
451 | redis:set('gplink'..chat_id,"https://t.me/joinchat/"..l[2])
452 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'لینک گروه با موفقیت ثبت شد.', 1, 'html')
453 | end
454 | if text == "link" and is_momod(msg) then
455 | local linkgp = redis:get('gplink'..chat_id)
456 | if not linkgp then
457 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'لینک ورود به گروه تنظیم نشده.\nثبت لینک جدید با دستور\n/setlink لینک', 1, 'html')
458 | return
459 | else
460 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'لینک گروه :\n'..linkgp, 1, 'html')
461 | end
462 | end
463 | if text and text:match('^setrules (.*)') and is_owner(msg) then redis:set('gprules'..chat_id,text:match('^setrules (.*)'))
464 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '*قوانین گروه با موفقیت تنظیم شد*', 1, 'md')
465 | end
466 | if text == "rules" then
467 | rules = redis:get('gprules'..chat_id)
468 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, 'قوانین گروه :\n'..rules, 1, 'html')
469 | end
470 | if text and text:match('^setname (.*)$') and is_momod(msg) then
471 | local matches = {string.match(text, '^setname (.*)$')}
472 | tdcli.changeChatTitle(chat_id, matches[1])
473 | end
474 | if text == "leave" and is_sudo(msg) then
475 | function botid(a,b,c)
476 | tdcli.changeChatMemberStatus(chat_id, b.id_, "Left")
477 | end
478 | tdcli.getMe(botid, nil)
479 | end
480 | if text == "settings" and is_momod(msg) then
481 | local text = "————————\n_📛تنظیمات گروه📛_ \n————————\n◾️قفللینک : "..(redis:get(hashlink) or "Disabled").."\n◾️️قفلفلود : "..(redis:get(hashflood) or "Disabled").."\n◾️قفلفوروارد : "..(redis:get(hashforward) or "Disabled").."\n◾️قفلتگ(#) "..(redis:get(hashtag) or "Disabled").."\n◾️قفلیوزرنیم(@) : "..(redis:get(hashusername) or "Disabled").."\n◾️قفلربات : "..(redis:get(hashbot) or "Disabled").."\n◾️قفلورودوخروج "..(redis:get(hashtgservice) or "Disabled").."\n◾️قفلعربی/فارسی : "..(redis:get(hasharabic) or "Disabled").."\n◾️قفلانگلیسی : "..(redis:get(hasheng) or "Disabled").."\n"
482 | text = text.."◾️️قفلفحش : "..(redis:get(hashbadword) or "Disabled").."\n◾️قفلمخاطب : "..(redis:get(hashcontact) or "Disabled").."\n◾️قفلاستیکر : "..(redis:get(hashsticker) or "Disabled").."\n"
483 | text = text.."◾️قفلکیبورانلاین : "..(redis:get(hashinline) or "Disabled").."\n◾️قفلایموجی : "..(redis:get(hashemoji) or "Disabled").."\n"
484 | text = text.."————————\n_📛فیلتر لیست📛_\n————————\n◾️فیلترگیف : "..(redis:get(hashgif) or "Disabled").."\n◾️فیلترعکس : "..(redis:get(hashphoto) or "Disabled").."\n◾️فیلتراهنگ : "..(redis:get(hashaudio) or "Disabled").."\n"
485 | text = text.."◾️فیلتروییس : "..(redis:get(hashvoice) or "Disabled").."\n◾️فیلترویدیو : "..(redis:get(hashvideo) or "Disabled").."\n◾️فیلترفایل : "..(redis:get(hashdocument) or "Disabled").."\n◾️فیلترمتن : "..(redis:get(hashtext1) or "Disabled").."\n"
486 | text = text.."————————\n_📛دیگر تنظیمات📛_\n————————\n◾️زمان فلود : *"..floodTime.."*\n◾️تعداد فلود : *"..floodMax.."*"
487 | text = string.gsub(text, "Enable", "✅")
488 | text = string.gsub(text, "Disabled", "⛔️")
489 | text = string.gsub(text, ":", "*>*")
490 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
491 | end
492 | if text == "lock flood" and is_momod(msg) then
493 | if redis:get(hashflood) == "Enable" then
494 | local text = "قفل فلود از قبل فعال شده بود!"
495 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
496 | else
497 | redis:set(hashflood ,"Enable")
498 | local text = "قفل فلود باموفقیت فعال شد!"
499 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
500 | end
501 | end
502 | if text == "unlock flood" and is_momod(msg) then
503 | if not redis:get(hashflood) == "Enable" then
504 | local text = "قفل فلود از قبل غیر فعال شده بود!"
505 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
506 | else
507 | redis:del(hashflood)
508 | local text = "قفل فلود باموفقیت غیر فعال شد!"
509 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
510 | end
511 | end
512 |
513 | if text == "lock bots" and is_momod(msg) then
514 | if redis:get(hashbot) == "Enable" then
515 | local text = "قفل ربات از قبل فعال شده بود!"
516 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
517 | else
518 | redis:set(hashbot ,"Enable")
519 | local text = "قفل ورود ربات باموفقیت فعال شد!"
520 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
521 | end
522 | end
523 | if text == "unlock bots" and is_momod(msg) then
524 | if not redis:get(hashbot) == "Enable" then
525 | local text = "قفل ربات از قبل غیر فعال شده بود!"
526 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
527 | else
528 | redis:del(hashbot)
529 | local text = "قفل ورود ربات باموفقیت غیر فعال شد!"
530 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
531 | end
532 | end
533 |
534 | if text == "lock tgservice" and is_momod(msg) then
535 | if redis:get(hashtgservice) == "Enable" then
536 | local text = "قفل پیام ورود و خروج از قبل فعال شده بود!"
537 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
538 | else
539 | redis:set(hashtgservice ,"Enable")
540 | local text = "قفل پیام ورود و خروج باموفقیت فعال شد"
541 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
542 | end
543 | end
544 | if text == "unlock tgservice" and is_momod(msg) then
545 | if not redis:get(hashtgservice) == "Enable" then
546 | local text = "قفل پیام ورود و خروج از قبل غیر فعال شده بود!"
547 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
548 | else
549 | redis:del(hashtgservice)
550 | local text = "قفل پیام ورود و خروج باموفقیت غیرفعال شد"
551 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
552 | end
553 | end
554 |
555 | if text == "lock links" and is_momod(msg) then
556 | if redis:get(hashlink) == "Enable" then
557 | local text = "قفل لینک از قبل فعال شده بود!"
558 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
559 | else
560 | redis:set(hashlink ,"Enable")
561 | local text = "قفل لینک باموفقیت فعال شد!"
562 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
563 | end
564 | end
565 | if text == "unlock links" and is_momod(msg) then
566 | if not redis:get(hashlink) == "Enable" then
567 | local text = "قفل لینک از قبل غیر فعال شده بود!"
568 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
569 | else
570 | redis:del(hashlink)
571 | local text = "قفل لینک باموفقیت غیر فعال شد!"
572 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
573 | end
574 | end
575 |
576 | if text == "lock tag" and is_momod(msg) then
577 | if redis:get(hashtag) == "Enable" then
578 | local text = "قفل تگ [#] از قبل فعال شده بود!"
579 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
580 | else
581 | redis:set(hashtag ,"Enable")
582 | local text = "قفل تگ [#] باموفقیت فعال شد!"
583 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
584 | end
585 | end
586 | if text == "unlock tag" and is_momod(msg) then
587 | if not redis:get(hashtag) == "Enable" then
588 | local text = "قفل تگ [#] از قبل غیر فعال شده بود!"
589 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
590 | else
591 | redis:del(hashtag)
592 | local text = "قفل تگ [#] باموفقیت غیر فعال شد!"
593 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
594 | end
595 | end
596 |
597 | if text == "lock username" and is_momod(msg) then
598 | if redis:get(hashusername) == "Enable" then
599 | local text = "قفل یوزرنیم (@) از قبل فعال شده بود!"
600 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
601 | else
602 | redis:set(hashusername ,"Enable")
603 | local text = "قفل یوزرنیم (@) باموفقیت فعال شد!"
604 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
605 | end
606 | end
607 | if text == "unlock username" and is_momod(msg) then
608 | if not redis:get(hashusername) == "Enable" then
609 | local text = "قفل یوزرنیم (@) از قبل غیر فعال شده بود!"
610 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
611 | else
612 | redis:del(hashusername)
613 | local text = "قفل نام یوزرنیم (@) باموفقیت غیر فعال شد!"
614 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
615 | end
616 | end
617 |
618 | if text == "lock forward" and is_momod(msg) then
619 | if redis:get(hashforward) == "Enable" then
620 | local text = "قفل فوروارد از قبل فعال شده بود!"
621 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
622 | else
623 | redis:set(hashforward ,"Enable")
624 | local text = "قفل فروارد باموفقیت فعال شد!"
625 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
626 | end
627 | end
628 | if text == "unlock forward" and is_momod(msg) then
629 | if not redis:get(hashforward) == "Enable" then
630 | local text = "قفل فوروارد از قبل غیر فعال شده بود!"
631 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
632 | else
633 | redis:del(hashforward)
634 | local text = "قفل فروارد باموفقیت غیر فعال شد!"
635 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
636 | end
637 | end
638 |
639 | if text == "lock arabic" and is_momod(msg) then
640 | if redis:get(hasharabic) == "Enable" then
641 | local text = "قفل عربی/فارسی از قبل فعال شده بود!"
642 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
643 | else
644 | redis:set(hasharabic ,"Enable")
645 | local text = "قفل زبان عربی/فارسی باموفقیت فعال شد!"
646 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
647 | end
648 | end
649 | if text == "unlock arabic" and is_momod(msg) then
650 | if not redis:get(hasharabic) == "Enable" then
651 | local text = "قفل عربی/فارسی از قبل غیر فعال شده بود!"
652 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
653 | else
654 | redis:del(hasharabic)
655 | local text = "قفل زبات عربی/فارسی باموفقیت غیر فعال شد!"
656 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
657 | end
658 | end
659 |
660 | if text == "lock english" and is_momod(msg) then
661 | if redis:get(hasheng) == "Enable" then
662 | local text = "قفل زبان انگلیسی از قبل فعال شده بود!"
663 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
664 | else
665 | redis:set(hasheng ,"Enable")
666 | local text = "قفل زبان انگلیسی باموفقیت فعال شد!"
667 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
668 | end
669 | end
670 | if text == "unlock english" and is_momod(msg) then
671 | if not redis:get(hasheng) == "Enable" then
672 | local text = "قفل زبان انگلیسی از قبل غیر فعال شده بود!"
673 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
674 | else
675 | redis:del(hasheng)
676 | local text = "قفل زبان انگلیسی باموفقیت غیر فعال شد!"
677 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
678 | end
679 | end
680 | if text == "lock fosh" and is_momod(msg) then
681 | if redis:get(hashbadword) == "Enable" then
682 | local text = "قفل فحش از قبل فعال شده بود!"
683 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
684 | else
685 | redis:set(hashbadword ,"Enable")
686 | local text = "قفل فحش باموفقیت فعال شد!"
687 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
688 | end
689 | end
690 | if text == "unlock fosh" and is_momod(msg) then
691 | if not redis:get(hashbadword) == "Enable" then
692 | local text = "قفل فحش از قبل غیر فعال شده بود!"
693 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
694 | else
695 | redis:del(hashbadword)
696 | local text = "قفل فحش باموفقیت غیر فعال شد!"
697 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
698 | end
699 | end
700 |
701 | if text == "lock inline" and is_momod(msg) then
702 | if redis:get(hashinline) == "Enable" then
703 | local text = "قفل دکمه شیشه ای از قبل فعال شده بود!"
704 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
705 | else
706 | redis:set(hashinline ,"Enable")
707 | local text = "قفل دکمه شیشه ای باموفقیت فعال شد!"
708 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
709 | end
710 | end
711 | if text == "unlock inline" and is_momod(msg) then
712 | if not redis:get(hashinline) == "Enable" then
713 | local text = "قفل دکمه شیشه ای از قبل غیر فعال شده بود!"
714 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
715 | else
716 | redis:del(hashinline)
717 | local text = "قفل دکمه شیشه ای باموفقیت غیر فعال شد!"
718 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
719 | end
720 | end
721 |
722 | if text == "lock emoji" and is_momod(msg) then
723 | if redis:get(hashemoji) == "Enable" then
724 | local text = "قفل ایموجی (😄) از قبل فعال شده بود!"
725 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
726 | else
727 | redis:set(hashemoji ,"Enable")
728 | local text = "قفل ایموجی (😄) باموفقیت فعال شد!"
729 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
730 | end
731 | end
732 |
733 | if text == "unlock emoji" and is_momod(msg) then
734 | if not redis:get(hashemoji) == "Enable" then
735 | local text = "قفل ایموجی (😄) از قبل غیر فعال شده بود!"
736 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
737 | else
738 | redis:del(hashemoji)
739 | local text = "قفل ایموجی (😄) باموفقیت غیر فعال شد!"
740 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
741 | end
742 | end
743 |
744 | if text == "lock contact" and is_momod(msg) then
745 | if redis:get(hashcontact) == "Enable" then
746 | local text = "قفل اشتراک گذاری مخاطبین از قبل فعال شده بود!"
747 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
748 | else
749 | redis:set(hashcontact ,"Enable")
750 | local text = "قفل اشتراک گذاری مخاطبین باموفقیت فعال شد!"
751 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
752 | end
753 | end
754 | if text == "unlock contact" and is_momod(msg) then
755 | if not redis:get(hashcontact) == "Enable" then
756 | local text = "قفل اشتراک گذاری مخاطبین از قبل غیر فعال شده بود!"
757 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
758 | else
759 | redis:del(hashcontact)
760 | local text = "قفل اشتراک گذاری مخاطبین باموفقیت غیر فعال شد!"
761 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
762 | end
763 | end
764 |
765 | if text == "lock sticker" and is_momod(msg) then
766 | if redis:get(hashcontact) == "Enable" then
767 | local text = "قفل ارسال استیکر از قبل فعال شده بود!"
768 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
769 | else
770 | redis:set(hashsticker ,"Enable")
771 | local text = "قفل ارسال استیکر باموفقیت فعال شد!"
772 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
773 | end
774 | end
775 | if text == "unlock sticker" and is_momod(msg) then
776 | if not redis:get(hashcontact) == "Enable" then
777 | local text = "قفل ارسال استیکر از قبل غیر فعال شده بود!"
778 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
779 | else
780 | redis:del(hashsticker)
781 | local text = "قفل ارسال استیکر باموفقیت غیر فعال شد!"
782 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
783 | end
784 | end
785 |
786 | if text == "mute gif" and is_momod(msg) then
787 | redis:set(hashgif ,"Enable")
788 | local text = "فیتلر گیف (عکس متحرک) باموفقیت فعال شد!"
789 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
790 | end
791 | if text == "unmute gif" and is_momod(msg) then
792 | redis:del(hashgif)
793 | local text = "فیتلر گیف (عکس متحرک) غیر فعال شد!"
794 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
795 | end
796 | if text == "mute photo" and is_momod(msg) then
797 | redis:set(hashphoto ,"Enable")
798 | local text = "فیتلرعکس باموفقیت فعال شد!"
799 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
800 | end
801 | if text == "unmute photo" and is_momod(msg) then
802 | redis:del(hashphoto)
803 | local text = "فیتلرعکس باموفقیت غیر فعال شد!"
804 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
805 | end
806 | if text == "mute audio" and is_momod(msg) then
807 | redis:set(hashaudio ,"Enable")
808 | local text = "فیتلر اهنگ باموفقیت فعال شد!"
809 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
810 | end
811 | if text == "unmute audio" and is_momod(msg) then
812 | redis:del(hashaudio)
813 | local text = "فیتلر اهنگ باموفقیت غیر فعال شد!"
814 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
815 | end
816 | if text == "mute voice" and is_momod(msg) then
817 | redis:set(hashvoice ,"Enable")
818 | local text = "فیتلر صدا باموفقیت فعال شد!"
819 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
820 | end
821 | if text == "unmute voice" and is_momod(msg) then
822 | redis:del(hashvoice)
823 | local text = "فیتلر صدا باموفقیت غیر فعال شد!"
824 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
825 | end
826 | if text == "mute video" and is_momod(msg) then
827 | redis:set(hashvideo ,"Enable")
828 | local text = "فیتلر فیلم باموفقیت فعال شد!"
829 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
830 | end
831 | if text == "unmute video" and is_momod(msg) then
832 | redis:del(hashvideo)
833 | local text = "فیتلر فیلم باموفقیت غیر فعال شد!"
834 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
835 | end
836 | if text == "mute document" and is_momod(msg) then
837 | redis:set(hashdocument ,"Enable")
838 | local text = "فیتلر فایل باموفقیت فعال شد!"
839 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
840 | end
841 | if text == "unmute document" and is_momod(msg) then
842 |
843 | redis:del(hashdocument)
844 | local text = "فیتلر فایل باموفقیت غیر فعال شد!"
845 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
846 | end
847 | if text == "mute text" and is_momod(msg) then
848 | redis:set(hashtext1 ,"Enable")
849 | local text = "فیتلر متن با موفقیت فعال شد!"
850 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
851 | end
852 | if text == "unmute text" and is_momod(msg) then
853 | redis:del(hashtext1)
854 | local text = "فیتلر متن با موفقیت غیر فعال شد!"
855 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, text, 1, 'md')
856 | end
857 | if text == 'pin' and is_momod(msg) then
858 | tdcli.pinChannelMessage(msg.chat_id_, msg.reply_to_message_id_, 1)
859 | end
860 | if text == "unpin" and is_momod(msg) then
861 | tdcli.unpinChannelMessage(chat_id, 1)
862 | end
863 | if text == "help" and is_momod(msg) then
864 | help = [[
865 | به زودی....!]]
866 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, help, 1, 'md')
867 | end
868 | if text == "del" and is_momod(msg) then
869 | tdcli.deleteMessages(chat_id, {[0] = msg.id_})
870 | tdcli.deleteMessages(chat_id,{[0] = reply_id})
871 | end
872 | if text == "gpinfo" and is_momod(msg) then
873 | function info(arg,data)
874 | -- vardump(data)
875 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, "اعطلاعات گروه\n*تعداد ادمین ها : *"..data.administrator_count_.."\n*تعداد ریمو شده ها : *"..data.kicked_count_.."\n*تعداد اعضا : *"..data.member_count_.."", 1, 'md')
876 | end
877 | tdcli.getChannelFull(chat_id, info, nil)
878 | end
879 | if text and text:match("^getpro (.*)$") then
880 | profilematches = {string.match(text, "^getpro (.*)$")}
881 | local function dl_photo(arg,data)
882 | tdcli.sendPhoto(msg.chat_id_, msg.id_, 0, 1, nil, data.photos_[0].sizes_[1].photo_.persistent_id_, nil)
883 | end
884 | tdcli.getUserProfilePhotos(user_id, profilematches[1] - 1, profilematches[1], dl_photo, nil)
885 | end
886 | if text and text:match('^setfloodtime (.*)$') and is_owner(msg) then
887 | redis:set('floodTime',text:match('setfloodtime (.*)'))
888 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '_حداکثر زمان اسپم تنظیم شد به_ : *'..text:match('setfloodtime (.*)')..'*', 1, 'md')
889 | end
890 | if text and text:match('^setflood (.*)$') and is_owner(msg) then
891 | redis:set('floodMax',text:match('setflood (.*)'))
892 | tdcli.sendMessage(msg.chat_id_, msg.id_, 1, '_حداکثر تعداد اسپم تنظیم شد به_ : *'..text:match('setflood (.*)')..'*', 1, 'md')
893 | end
894 | if text == "id" then
895 | function dl_photo(arg,data)
896 | local text = 'ایدی گروه : ['..msg.chat_id_:gsub('-100','').."]\nایدی شما : ["..msg.sender_user_id_.."]\nتعداد عکس های شما : ["..data.total_count_.."]"
897 | tdcli.sendPhoto(msg.chat_id_, msg.id_, 0, 1, nil, data.photos_[0].sizes_[1].photo_.persistent_id_, text)
898 | end
899 | tdcli.getUserProfilePhotos(user_id, 0, 1, dl_photo, nil)
900 | end
901 | end
902 | function tdcli_update_callback(data)
903 | if (data.ID == "UpdateNewMessage") then
904 | run(data)
905 | elseif data.ID == "UpdateMessageEdited" then
906 | local function edited_cb(arg, data)
907 | run(data,true)
908 | end
909 | getMessage(data.chat_id_, data.message_id_, edited_cb, nil)
910 | elseif (data.ID == "UpdateOption" and data.name_ == "my_id") then
911 | tdcli_function ({ID="GetChats", offset_order_="9223372036854775807", offset_chat_id_=0, limit_=20}, dl_cb, nil)
912 | end
913 | end
--------------------------------------------------------------------------------
/libs/lua-redis.lua:
--------------------------------------------------------------------------------
1 | local redis = {
2 | _VERSION = 'redis-lua 2.0.4',
3 | _DESCRIPTION = 'A Lua client library for the redis key value storage system.',
4 | _COPYRIGHT = 'Copyright (C) 2009-2012 Daniele Alessandri',
5 | }
6 |
7 | -- The following line is used for backwards compatibility in order to keep the `Redis`
8 | -- global module name. Using `Redis` is now deprecated so you should explicitly assign
9 | -- the module to a local variable when requiring it: `local redis = require('redis')`.
10 | Redis = redis
11 |
12 | local unpack = _G.unpack or table.unpack
13 | local network, request, response = {}, {}, {}
14 |
15 | local defaults = {
16 | host = '127.0.0.1',
17 | port = 6379,
18 | tcp_nodelay = true,
19 | path = nil
20 | }
21 |
22 | local function merge_defaults(parameters)
23 | if parameters == nil then
24 | parameters = {}
25 | end
26 | for k, v in pairs(defaults) do
27 | if parameters[k] == nil then
28 | parameters[k] = defaults[k]
29 | end
30 | end
31 | return parameters
32 | end
33 |
34 | local function parse_boolean(v)
35 | if v == '1' or v == 'true' or v == 'TRUE' then
36 | return true
37 | elseif v == '0' or v == 'false' or v == 'FALSE' then
38 | return false
39 | else
40 | return nil
41 | end
42 | end
43 |
44 | local function toboolean(value) return value == 1 end
45 |
46 | local function sort_request(client, command, key, params)
47 | --[[ params = {
48 | by = 'weight_*',
49 | get = 'object_*',
50 | limit = { 0, 10 },
51 | sort = 'desc',
52 | alpha = true,
53 | } ]]
54 | local query = { key }
55 |
56 | if params then
57 | if params.by then
58 | table.insert(query, 'BY')
59 | table.insert(query, params.by)
60 | end
61 |
62 | if type(params.limit) == 'table' then
63 | -- TODO: check for lower and upper limits
64 | table.insert(query, 'LIMIT')
65 | table.insert(query, params.limit[1])
66 | table.insert(query, params.limit[2])
67 | end
68 |
69 | if params.get then
70 | if (type(params.get) == 'table') then
71 | for _, getarg in pairs(params.get) do
72 | table.insert(query, 'GET')
73 | table.insert(query, getarg)
74 | end
75 | else
76 | table.insert(query, 'GET')
77 | table.insert(query, params.get)
78 | end
79 | end
80 |
81 | if params.sort then
82 | table.insert(query, params.sort)
83 | end
84 |
85 | if params.alpha == true then
86 | table.insert(query, 'ALPHA')
87 | end
88 |
89 | if params.store then
90 | table.insert(query, 'STORE')
91 | table.insert(query, params.store)
92 | end
93 | end
94 |
95 | request.multibulk(client, command, query)
96 | end
97 |
98 | local function zset_range_request(client, command, ...)
99 | local args, opts = {...}, { }
100 |
101 | if #args >= 1 and type(args[#args]) == 'table' then
102 | local options = table.remove(args, #args)
103 | if options.withscores then
104 | table.insert(opts, 'WITHSCORES')
105 | end
106 | end
107 |
108 | for _, v in pairs(opts) do table.insert(args, v) end
109 | request.multibulk(client, command, args)
110 | end
111 |
112 | local function zset_range_byscore_request(client, command, ...)
113 | local args, opts = {...}, { }
114 |
115 | if #args >= 1 and type(args[#args]) == 'table' then
116 | local options = table.remove(args, #args)
117 | if options.limit then
118 | table.insert(opts, 'LIMIT')
119 | table.insert(opts, options.limit.offset or options.limit[1])
120 | table.insert(opts, options.limit.count or options.limit[2])
121 | end
122 | if options.withscores then
123 | table.insert(opts, 'WITHSCORES')
124 | end
125 | end
126 |
127 | for _, v in pairs(opts) do table.insert(args, v) end
128 | request.multibulk(client, command, args)
129 | end
130 |
131 | local function zset_range_reply(reply, command, ...)
132 | local args = {...}
133 | local opts = args[4]
134 | if opts and (opts.withscores or string.lower(tostring(opts)) == 'withscores') then
135 | local new_reply = { }
136 | for i = 1, #reply, 2 do
137 | table.insert(new_reply, { reply[i], reply[i + 1] })
138 | end
139 | return new_reply
140 | else
141 | return reply
142 | end
143 | end
144 |
145 | local function zset_store_request(client, command, ...)
146 | local args, opts = {...}, { }
147 |
148 | if #args >= 1 and type(args[#args]) == 'table' then
149 | local options = table.remove(args, #args)
150 | if options.weights and type(options.weights) == 'table' then
151 | table.insert(opts, 'WEIGHTS')
152 | for _, weight in ipairs(options.weights) do
153 | table.insert(opts, weight)
154 | end
155 | end
156 | if options.aggregate then
157 | table.insert(opts, 'AGGREGATE')
158 | table.insert(opts, options.aggregate)
159 | end
160 | end
161 |
162 | for _, v in pairs(opts) do table.insert(args, v) end
163 | request.multibulk(client, command, args)
164 | end
165 |
166 | local function mset_filter_args(client, command, ...)
167 | local args, arguments = {...}, {}
168 | if (#args == 1 and type(args[1]) == 'table') then
169 | for k,v in pairs(args[1]) do
170 | table.insert(arguments, k)
171 | table.insert(arguments, v)
172 | end
173 | else
174 | arguments = args
175 | end
176 | request.multibulk(client, command, arguments)
177 | end
178 |
179 | local function hash_multi_request_builder(builder_callback)
180 | return function(client, command, ...)
181 | local args, arguments = {...}, { }
182 | if #args == 2 then
183 | table.insert(arguments, args[1])
184 | for k, v in pairs(args[2]) do
185 | builder_callback(arguments, k, v)
186 | end
187 | else
188 | arguments = args
189 | end
190 | request.multibulk(client, command, arguments)
191 | end
192 | end
193 |
194 | local function parse_info(response)
195 | local info = {}
196 | local current = info
197 |
198 | response:gsub('([^\r\n]*)\r\n', function(kv)
199 | if kv == '' then return end
200 |
201 | local section = kv:match('^# (%w+)$')
202 | if section then
203 | current = {}
204 | info[section:lower()] = current
205 | return
206 | end
207 |
208 | local k,v = kv:match(('([^:]*):([^:]*)'):rep(1))
209 | if k:match('db%d+') then
210 | current[k] = {}
211 | v:gsub(',', function(dbkv)
212 | local dbk,dbv = kv:match('([^:]*)=([^:]*)')
213 | current[k][dbk] = dbv
214 | end)
215 | else
216 | current[k] = v
217 | end
218 | end)
219 |
220 | return info
221 | end
222 |
223 | local function load_methods(proto, commands)
224 | local client = setmetatable ({}, getmetatable(proto))
225 |
226 | for cmd, fn in pairs(commands) do
227 | if type(fn) ~= 'function' then
228 | redis.error('invalid type for command ' .. cmd .. '(must be a function)')
229 | end
230 | client[cmd] = fn
231 | end
232 |
233 | for i, v in pairs(proto) do
234 | client[i] = v
235 | end
236 |
237 | return client
238 | end
239 |
240 | local function create_client(proto, client_socket, commands)
241 | local client = load_methods(proto, commands)
242 | client.error = redis.error
243 | client.network = {
244 | socket = client_socket,
245 | read = network.read,
246 | write = network.write,
247 | }
248 | client.requests = {
249 | multibulk = request.multibulk,
250 | }
251 | return client
252 | end
253 |
254 | -- ############################################################################
255 |
256 | function network.write(client, buffer)
257 | local _, err = client.network.socket:send(buffer)
258 | if err then client.error(err) end
259 | end
260 |
261 | function network.read(client, len)
262 | if len == nil then len = '*l' end
263 | local line, err = client.network.socket:receive(len)
264 | if not err then return line else client.error('connection error: ' .. err) end
265 | end
266 |
267 | -- ############################################################################
268 |
269 | function response.read(client)
270 | local payload = client.network.read(client)
271 | local prefix, data = payload:sub(1, -#payload), payload:sub(2)
272 |
273 | -- status reply
274 | if prefix == '+' then
275 | if data == 'OK' then
276 | return true
277 | elseif data == 'QUEUED' then
278 | return { queued = true }
279 | else
280 | return data
281 | end
282 |
283 | -- error reply
284 | elseif prefix == '-' then
285 | return client.error('redis error: ' .. data)
286 |
287 | -- integer reply
288 | elseif prefix == ':' then
289 | local number = tonumber(data)
290 |
291 | if not number then
292 | if res == 'nil' then
293 | return nil
294 | end
295 | client.error('cannot parse '..res..' as a numeric response.')
296 | end
297 |
298 | return number
299 |
300 | -- bulk reply
301 | elseif prefix == '$' then
302 | local length = tonumber(data)
303 |
304 | if not length then
305 | client.error('cannot parse ' .. length .. ' as data length')
306 | end
307 |
308 | if length == -1 then
309 | return nil
310 | end
311 |
312 | local nextchunk = client.network.read(client, length + 2)
313 |
314 | return nextchunk:sub(1, -3)
315 |
316 | -- multibulk reply
317 | elseif prefix == '*' then
318 | local count = tonumber(data)
319 |
320 | if count == -1 then
321 | return nil
322 | end
323 |
324 | local list = {}
325 | if count > 0 then
326 | local reader = response.read
327 | for i = 1, count do
328 | list[i] = reader(client)
329 | end
330 | end
331 | return list
332 |
333 | -- unknown type of reply
334 | else
335 | return client.error('unknown response prefix: ' .. prefix)
336 | end
337 | end
338 |
339 | -- ############################################################################
340 |
341 | function request.raw(client, buffer)
342 | local bufferType = type(buffer)
343 |
344 | if bufferType == 'table' then
345 | client.network.write(client, table.concat(buffer))
346 | elseif bufferType == 'string' then
347 | client.network.write(client, buffer)
348 | else
349 | client.error('argument error: ' .. bufferType)
350 | end
351 | end
352 |
353 | function request.multibulk(client, command, ...)
354 | local args = {...}
355 | local argsn = #args
356 | local buffer = { true, true }
357 |
358 | if argsn == 1 and type(args[1]) == 'table' then
359 | argsn, args = #args[1], args[1]
360 | end
361 |
362 | buffer[1] = '*' .. tostring(argsn + 1) .. "\r\n"
363 | buffer[2] = '$' .. #command .. "\r\n" .. command .. "\r\n"
364 |
365 | local table_insert = table.insert
366 | for _, argument in pairs(args) do
367 | local s_argument = tostring(argument)
368 | table_insert(buffer, '$' .. #s_argument .. "\r\n" .. s_argument .. "\r\n")
369 | end
370 |
371 | client.network.write(client, table.concat(buffer))
372 | end
373 |
374 | -- ############################################################################
375 |
376 | local function custom(command, send, parse)
377 | command = string.upper(command)
378 | return function(client, ...)
379 | send(client, command, ...)
380 | local reply = response.read(client)
381 |
382 | if type(reply) == 'table' and reply.queued then
383 | reply.parser = parse
384 | return reply
385 | else
386 | if parse then
387 | return parse(reply, command, ...)
388 | end
389 | return reply
390 | end
391 | end
392 | end
393 |
394 | local function command(command, opts)
395 | if opts == nil or type(opts) == 'function' then
396 | return custom(command, request.multibulk, opts)
397 | else
398 | return custom(command, opts.request or request.multibulk, opts.response)
399 | end
400 | end
401 |
402 | local define_command_impl = function(target, name, opts)
403 | local opts = opts or {}
404 | target[string.lower(name)] = custom(
405 | opts.command or string.upper(name),
406 | opts.request or request.multibulk,
407 | opts.response or nil
408 | )
409 | end
410 |
411 | local undefine_command_impl = function(target, name)
412 | target[string.lower(name)] = nil
413 | end
414 |
415 | -- ############################################################################
416 |
417 | local client_prototype = {}
418 |
419 | client_prototype.raw_cmd = function(client, buffer)
420 | request.raw(client, buffer .. "\r\n")
421 | return response.read(client)
422 | end
423 |
424 | -- obsolete
425 | client_prototype.define_command = function(client, name, opts)
426 | define_command_impl(client, name, opts)
427 | end
428 |
429 | -- obsolete
430 | client_prototype.undefine_command = function(client, name)
431 | undefine_command_impl(client, name)
432 | end
433 |
434 | client_prototype.quit = function(client)
435 | request.multibulk(client, 'QUIT')
436 | client.network.socket:shutdown()
437 | return true
438 | end
439 |
440 | client_prototype.shutdown = function(client)
441 | request.multibulk(client, 'SHUTDOWN')
442 | client.network.socket:shutdown()
443 | end
444 |
445 | -- Command pipelining
446 |
447 | client_prototype.pipeline = function(client, block)
448 | local requests, replies, parsers = {}, {}, {}
449 | local table_insert = table.insert
450 | local socket_write, socket_read = client.network.write, client.network.read
451 |
452 | client.network.write = function(_, buffer)
453 | table_insert(requests, buffer)
454 | end
455 |
456 | -- TODO: this hack is necessary to temporarily reuse the current
457 | -- request -> response handling implementation of redis-lua
458 | -- without further changes in the code, but it will surely
459 | -- disappear when the new command-definition infrastructure
460 | -- will finally be in place.
461 | client.network.read = function() return '+QUEUED' end
462 |
463 | local pipeline = setmetatable({}, {
464 | __index = function(env, name)
465 | local cmd = client[name]
466 | if not cmd then
467 | client.error('unknown redis command: ' .. name, 2)
468 | end
469 | return function(self, ...)
470 | local reply = cmd(client, ...)
471 | table_insert(parsers, #requests, reply.parser)
472 | return reply
473 | end
474 | end
475 | })
476 |
477 | local success, retval = pcall(block, pipeline)
478 |
479 | client.network.write, client.network.read = socket_write, socket_read
480 | if not success then client.error(retval, 0) end
481 |
482 | client.network.write(client, table.concat(requests, ''))
483 |
484 | for i = 1, #requests do
485 | local reply, parser = response.read(client), parsers[i]
486 | if parser then
487 | reply = parser(reply)
488 | end
489 | table_insert(replies, i, reply)
490 | end
491 |
492 | return replies, #requests
493 | end
494 |
495 | -- Publish/Subscribe
496 |
497 | do
498 | local channels = function(channels)
499 | if type(channels) == 'string' then
500 | channels = { channels }
501 | end
502 | return channels
503 | end
504 |
505 | local subscribe = function(client, ...)
506 | request.multibulk(client, 'subscribe', ...)
507 | end
508 | local psubscribe = function(client, ...)
509 | request.multibulk(client, 'psubscribe', ...)
510 | end
511 | local unsubscribe = function(client, ...)
512 | request.multibulk(client, 'unsubscribe')
513 | end
514 | local punsubscribe = function(client, ...)
515 | request.multibulk(client, 'punsubscribe')
516 | end
517 |
518 | local consumer_loop = function(client)
519 | local aborting, subscriptions = false, 0
520 |
521 | local abort = function()
522 | if not aborting then
523 | unsubscribe(client)
524 | punsubscribe(client)
525 | aborting = true
526 | end
527 | end
528 |
529 | return coroutine.wrap(function()
530 | while true do
531 | local message
532 | local response = response.read(client)
533 |
534 | if response[1] == 'pmessage' then
535 | message = {
536 | kind = response[1],
537 | pattern = response[2],
538 | channel = response[3],
539 | payload = response[4],
540 | }
541 | else
542 | message = {
543 | kind = response[1],
544 | channel = response[2],
545 | payload = response[3],
546 | }
547 | end
548 |
549 | if string.match(message.kind, '^p?subscribe$') then
550 | subscriptions = subscriptions + 1
551 | end
552 | if string.match(message.kind, '^p?unsubscribe$') then
553 | subscriptions = subscriptions - 1
554 | end
555 |
556 | if aborting and subscriptions == 0 then
557 | break
558 | end
559 | coroutine.yield(message, abort)
560 | end
561 | end)
562 | end
563 |
564 | client_prototype.pubsub = function(client, subscriptions)
565 | if type(subscriptions) == 'table' then
566 | if subscriptions.subscribe then
567 | subscribe(client, channels(subscriptions.subscribe))
568 | end
569 | if subscriptions.psubscribe then
570 | psubscribe(client, channels(subscriptions.psubscribe))
571 | end
572 | end
573 | return consumer_loop(client)
574 | end
575 | end
576 |
577 | -- Redis transactions (MULTI/EXEC)
578 |
579 | do
580 | local function identity(...) return ... end
581 | local emptytable = {}
582 |
583 | local function initialize_transaction(client, options, block, queued_parsers)
584 | local table_insert = table.insert
585 | local coro = coroutine.create(block)
586 |
587 | if options.watch then
588 | local watch_keys = {}
589 | for _, key in pairs(options.watch) do
590 | table_insert(watch_keys, key)
591 | end
592 | if #watch_keys > 0 then
593 | client:watch(unpack(watch_keys))
594 | end
595 | end
596 |
597 | local transaction_client = setmetatable({}, {__index=client})
598 | transaction_client.exec = function(...)
599 | client.error('cannot use EXEC inside a transaction block')
600 | end
601 | transaction_client.multi = function(...)
602 | coroutine.yield()
603 | end
604 | transaction_client.commands_queued = function()
605 | return #queued_parsers
606 | end
607 |
608 | assert(coroutine.resume(coro, transaction_client))
609 |
610 | transaction_client.multi = nil
611 | transaction_client.discard = function(...)
612 | local reply = client:discard()
613 | for i, v in pairs(queued_parsers) do
614 | queued_parsers[i]=nil
615 | end
616 | coro = initialize_transaction(client, options, block, queued_parsers)
617 | return reply
618 | end
619 | transaction_client.watch = function(...)
620 | client.error('WATCH inside MULTI is not allowed')
621 | end
622 | setmetatable(transaction_client, { __index = function(t, k)
623 | local cmd = client[k]
624 | if type(cmd) == "function" then
625 | local function queuey(self, ...)
626 | local reply = cmd(client, ...)
627 | assert((reply or emptytable).queued == true, 'a QUEUED reply was expected')
628 | table_insert(queued_parsers, reply.parser or identity)
629 | return reply
630 | end
631 | t[k]=queuey
632 | return queuey
633 | else
634 | return cmd
635 | end
636 | end
637 | })
638 | client:multi()
639 | return coro
640 | end
641 |
642 | local function transaction(client, options, coroutine_block, attempts)
643 | local queued_parsers, replies = {}, {}
644 | local retry = tonumber(attempts) or tonumber(options.retry) or 2
645 | local coro = initialize_transaction(client, options, coroutine_block, queued_parsers)
646 |
647 | local success, retval
648 | if coroutine.status(coro) == 'suspended' then
649 | success, retval = coroutine.resume(coro)
650 | else
651 | -- do not fail if the coroutine has not been resumed (missing t:multi() with CAS)
652 | success, retval = true, 'empty transaction'
653 | end
654 | if #queued_parsers == 0 or not success then
655 | client:discard()
656 | assert(success, retval)
657 | return replies, 0
658 | end
659 |
660 | local raw_replies = client:exec()
661 | if not raw_replies then
662 | if (retry or 0) <= 0 then
663 | client.error("MULTI/EXEC transaction aborted by the server")
664 | else
665 | --we're not quite done yet
666 | return transaction(client, options, coroutine_block, retry - 1)
667 | end
668 | end
669 |
670 | local table_insert = table.insert
671 | for i, parser in pairs(queued_parsers) do
672 | table_insert(replies, i, parser(raw_replies[i]))
673 | end
674 |
675 | return replies, #queued_parsers
676 | end
677 |
678 | client_prototype.transaction = function(client, arg1, arg2)
679 | local options, block
680 | if not arg2 then
681 | options, block = {}, arg1
682 | elseif arg1 then --and arg2, implicitly
683 | options, block = type(arg1)=="table" and arg1 or { arg1 }, arg2
684 | else
685 | client.error("Invalid parameters for redis transaction.")
686 | end
687 |
688 | if not options.watch then
689 | watch_keys = { }
690 | for i, v in pairs(options) do
691 | if tonumber(i) then
692 | table.insert(watch_keys, v)
693 | options[i] = nil
694 | end
695 | end
696 | options.watch = watch_keys
697 | elseif not (type(options.watch) == 'table') then
698 | options.watch = { options.watch }
699 | end
700 |
701 | if not options.cas then
702 | local tx_block = block
703 | block = function(client, ...)
704 | client:multi()
705 | return tx_block(client, ...) --can't wrap this in pcall because we're in a coroutine.
706 | end
707 | end
708 |
709 | return transaction(client, options, block)
710 | end
711 | end
712 |
713 | -- MONITOR context
714 |
715 | do
716 | local monitor_loop = function(client)
717 | local monitoring = true
718 |
719 | -- Tricky since the payload format changed starting from Redis 2.6.
720 | local pattern = '^(%d+%.%d+)( ?.- ?) ?"(%a+)" ?(.-)$'
721 |
722 | local abort = function()
723 | monitoring = false
724 | end
725 |
726 | return coroutine.wrap(function()
727 | client:monitor()
728 |
729 | while monitoring do
730 | local message, matched
731 | local response = response.read(client)
732 |
733 | local ok = response:gsub(pattern, function(time, info, cmd, args)
734 | message = {
735 | timestamp = tonumber(time),
736 | client = info:match('%d+.%d+.%d+.%d+:%d+'),
737 | database = tonumber(info:match('%d+')) or 0,
738 | command = cmd,
739 | arguments = args:match('.+'),
740 | }
741 | matched = true
742 | end)
743 |
744 | if not matched then
745 | client.error('Unable to match MONITOR payload: '..response)
746 | end
747 |
748 | coroutine.yield(message, abort)
749 | end
750 | end)
751 | end
752 |
753 | client_prototype.monitor_messages = function(client)
754 | return monitor_loop(client)
755 | end
756 | end
757 |
758 | -- ############################################################################
759 |
760 | local function connect_tcp(socket, parameters)
761 | local host, port = parameters.host, tonumber(parameters.port)
762 | local ok, err = socket:connect(host, port)
763 | if not ok then
764 | redis.error('could not connect to '..host..':'..port..' ['..err..']')
765 | end
766 | socket:setoption('tcp-nodelay', parameters.tcp_nodelay)
767 | return socket
768 | end
769 |
770 | local function connect_unix(socket, parameters)
771 | local ok, err = socket:connect(parameters.path)
772 | if not ok then
773 | redis.error('could not connect to '..parameters.path..' ['..err..']')
774 | end
775 | return socket
776 | end
777 |
778 | local function create_connection(parameters)
779 | if parameters.socket then
780 | return parameters.socket
781 | end
782 |
783 | local perform_connection, socket
784 |
785 | if parameters.scheme == 'unix' then
786 | perform_connection, socket = connect_unix, require('socket.unix')
787 | assert(socket, 'your build of LuaSocket does not support UNIX domain sockets')
788 | else
789 | if parameters.scheme then
790 | local scheme = parameters.scheme
791 | assert(scheme == 'redis' or scheme == 'tcp', 'invalid scheme: '..scheme)
792 | end
793 | perform_connection, socket = connect_tcp, require('socket').tcp
794 | end
795 |
796 | return perform_connection(socket(), parameters)
797 | end
798 |
799 | -- ############################################################################
800 |
801 | function redis.error(message, level)
802 | error(message, (level or 1) + 1)
803 | end
804 |
805 | function redis.connect(...)
806 | local args, parameters = {...}, nil
807 |
808 | if #args == 1 then
809 | if type(args[1]) == 'table' then
810 | parameters = args[1]
811 | else
812 | local uri = require('socket.url')
813 | parameters = uri.parse(select(1, ...))
814 | if parameters.scheme then
815 | if parameters.query then
816 | for k, v in parameters.query:gmatch('([-_%w]+)=([-_%w]+)') do
817 | if k == 'tcp_nodelay' or k == 'tcp-nodelay' then
818 | parameters.tcp_nodelay = parse_boolean(v)
819 | end
820 | end
821 | end
822 | else
823 | parameters.host = parameters.path
824 | end
825 | end
826 | elseif #args > 1 then
827 | local host, port = unpack(args)
828 | parameters = { host = host, port = port }
829 | end
830 |
831 | local commands = redis.commands or {}
832 | if type(commands) ~= 'table' then
833 | redis.error('invalid type for the commands table')
834 | end
835 |
836 | local socket = create_connection(merge_defaults(parameters))
837 | local client = create_client(client_prototype, socket, commands)
838 |
839 | return client
840 | end
841 |
842 | function redis.command(cmd, opts)
843 | return command(cmd, opts)
844 | end
845 |
846 | -- obsolete
847 | function redis.define_command(name, opts)
848 | define_command_impl(redis.commands, name, opts)
849 | end
850 |
851 | -- obsolete
852 | function redis.undefine_command(name)
853 | undefine_command_impl(redis.commands, name)
854 | end
855 |
856 | -- ############################################################################
857 |
858 | -- Commands defined in this table do not take the precedence over
859 | -- methods defined in the client prototype table.
860 |
861 | redis.commands = {
862 | -- commands operating on the key space
863 | exists = command('EXISTS', {
864 | response = toboolean
865 | }),
866 | del = command('DEL'),
867 | type = command('TYPE'),
868 | rename = command('RENAME'),
869 | renamenx = command('RENAMENX', {
870 | response = toboolean
871 | }),
872 | expire = command('EXPIRE', {
873 | response = toboolean
874 | }),
875 | pexpire = command('PEXPIRE', { -- >= 2.6
876 | response = toboolean
877 | }),
878 | expireat = command('EXPIREAT', {
879 | response = toboolean
880 | }),
881 | pexpireat = command('PEXPIREAT', { -- >= 2.6
882 | response = toboolean
883 | }),
884 | ttl = command('TTL'),
885 | pttl = command('PTTL'), -- >= 2.6
886 | move = command('MOVE', {
887 | response = toboolean
888 | }),
889 | dbsize = command('DBSIZE'),
890 | persist = command('PERSIST', { -- >= 2.2
891 | response = toboolean
892 | }),
893 | keys = command('KEYS', {
894 | response = function(response)
895 | if type(response) == 'string' then
896 | -- backwards compatibility path for Redis < 2.0
897 | local keys = {}
898 | response:gsub('[^%s]+', function(key)
899 | table.insert(keys, key)
900 | end)
901 | response = keys
902 | end
903 | return response
904 | end
905 | }),
906 | randomkey = command('RANDOMKEY', {
907 | response = function(response)
908 | if response == '' then
909 | return nil
910 | else
911 | return response
912 | end
913 | end
914 | }),
915 | sort = command('SORT', {
916 | request = sort_request,
917 | }),
918 |
919 | -- commands operating on string values
920 | set = command('SET'),
921 | setnx = command('SETNX', {
922 | response = toboolean
923 | }),
924 | setex = command('SETEX'), -- >= 2.0
925 | psetex = command('PSETEX'), -- >= 2.6
926 | mset = command('MSET', {
927 | request = mset_filter_args
928 | }),
929 | msetnx = command('MSETNX', {
930 | request = mset_filter_args,
931 | response = toboolean
932 | }),
933 | get = command('GET'),
934 | mget = command('MGET'),
935 | getset = command('GETSET'),
936 | incr = command('INCR'),
937 | incrby = command('INCRBY'),
938 | incrbyfloat = command('INCRBYFLOAT', { -- >= 2.6
939 | response = function(reply, command, ...)
940 | return tonumber(reply)
941 | end,
942 | }),
943 | decr = command('DECR'),
944 | decrby = command('DECRBY'),
945 | append = command('APPEND'), -- >= 2.0
946 | substr = command('SUBSTR'), -- >= 2.0
947 | strlen = command('STRLEN'), -- >= 2.2
948 | setrange = command('SETRANGE'), -- >= 2.2
949 | getrange = command('GETRANGE'), -- >= 2.2
950 | setbit = command('SETBIT'), -- >= 2.2
951 | getbit = command('GETBIT'), -- >= 2.2
952 |
953 | -- commands operating on lists
954 | rpush = command('RPUSH'),
955 | lpush = command('LPUSH'),
956 | llen = command('LLEN'),
957 | lrange = command('LRANGE'),
958 | ltrim = command('LTRIM'),
959 | lindex = command('LINDEX'),
960 | lset = command('LSET'),
961 | lrem = command('LREM'),
962 | lpop = command('LPOP'),
963 | rpop = command('RPOP'),
964 | rpoplpush = command('RPOPLPUSH'),
965 | blpop = command('BLPOP'), -- >= 2.0
966 | brpop = command('BRPOP'), -- >= 2.0
967 | rpushx = command('RPUSHX'), -- >= 2.2
968 | lpushx = command('LPUSHX'), -- >= 2.2
969 | linsert = command('LINSERT'), -- >= 2.2
970 | brpoplpush = command('BRPOPLPUSH'), -- >= 2.2
971 |
972 | -- commands operating on sets
973 | sadd = command('SADD'),
974 | srem = command('SREM'),
975 | spop = command('SPOP'),
976 | smove = command('SMOVE', {
977 | response = toboolean
978 | }),
979 | scard = command('SCARD'),
980 | sismember = command('SISMEMBER', {
981 | response = toboolean
982 | }),
983 | sinter = command('SINTER'),
984 | sinterstore = command('SINTERSTORE'),
985 | sunion = command('SUNION'),
986 | sunionstore = command('SUNIONSTORE'),
987 | sdiff = command('SDIFF'),
988 | sdiffstore = command('SDIFFSTORE'),
989 | smembers = command('SMEMBERS'),
990 | srandmember = command('SRANDMEMBER'),
991 |
992 | -- commands operating on sorted sets
993 | zadd = command('ZADD'),
994 | zincrby = command('ZINCRBY'),
995 | zrem = command('ZREM'),
996 | zrange = command('ZRANGE', {
997 | request = zset_range_request,
998 | response = zset_range_reply,
999 | }),
1000 | zrevrange = command('ZREVRANGE', {
1001 | request = zset_range_request,
1002 | response = zset_range_reply,
1003 | }),
1004 | zrangebyscore = command('ZRANGEBYSCORE', {
1005 | request = zset_range_byscore_request,
1006 | response = zset_range_reply,
1007 | }),
1008 | zrevrangebyscore = command('ZREVRANGEBYSCORE', { -- >= 2.2
1009 | request = zset_range_byscore_request,
1010 | response = zset_range_reply,
1011 | }),
1012 | zunionstore = command('ZUNIONSTORE', { -- >= 2.0
1013 | request = zset_store_request
1014 | }),
1015 | zinterstore = command('ZINTERSTORE', { -- >= 2.0
1016 | request = zset_store_request
1017 | }),
1018 | zcount = command('ZCOUNT'),
1019 | zcard = command('ZCARD'),
1020 | zscore = command('ZSCORE'),
1021 | zremrangebyscore = command('ZREMRANGEBYSCORE'),
1022 | zrank = command('ZRANK'), -- >= 2.0
1023 | zrevrank = command('ZREVRANK'), -- >= 2.0
1024 | zremrangebyrank = command('ZREMRANGEBYRANK'), -- >= 2.0
1025 |
1026 | -- commands operating on hashes
1027 | hset = command('HSET', { -- >= 2.0
1028 | response = toboolean
1029 | }),
1030 | hsetnx = command('HSETNX', { -- >= 2.0
1031 | response = toboolean
1032 | }),
1033 | hmset = command('HMSET', { -- >= 2.0
1034 | request = hash_multi_request_builder(function(args, k, v)
1035 | table.insert(args, k)
1036 | table.insert(args, v)
1037 | end),
1038 | }),
1039 | hincrby = command('HINCRBY'), -- >= 2.0
1040 | hincrbyfloat = command('HINCRBYFLOAT', {-- >= 2.6
1041 | response = function(reply, command, ...)
1042 | return tonumber(reply)
1043 | end,
1044 | }),
1045 | hget = command('HGET'), -- >= 2.0
1046 | hmget = command('HMGET', { -- >= 2.0
1047 | request = hash_multi_request_builder(function(args, k, v)
1048 | table.insert(args, v)
1049 | end),
1050 | }),
1051 | hdel = command('HDEL'), -- >= 2.0
1052 | hexists = command('HEXISTS', { -- >= 2.0
1053 | response = toboolean
1054 | }),
1055 | hlen = command('HLEN'), -- >= 2.0
1056 | hkeys = command('HKEYS'), -- >= 2.0
1057 | hvals = command('HVALS'), -- >= 2.0
1058 | hgetall = command('HGETALL', { -- >= 2.0
1059 | response = function(reply, command, ...)
1060 | local new_reply = { }
1061 | for i = 1, #reply, 2 do new_reply[reply[i]] = reply[i + 1] end
1062 | return new_reply
1063 | end
1064 | }),
1065 |
1066 | -- connection related commands
1067 | ping = command('PING', {
1068 | response = function(response) return response == 'PONG' end
1069 | }),
1070 | echo = command('ECHO'),
1071 | auth = command('AUTH'),
1072 | select = command('SELECT'),
1073 |
1074 | -- transactions
1075 | multi = command('MULTI'), -- >= 2.0
1076 | exec = command('EXEC'), -- >= 2.0
1077 | discard = command('DISCARD'), -- >= 2.0
1078 | watch = command('WATCH'), -- >= 2.2
1079 | unwatch = command('UNWATCH'), -- >= 2.2
1080 |
1081 | -- publish - subscribe
1082 | subscribe = command('SUBSCRIBE'), -- >= 2.0
1083 | unsubscribe = command('UNSUBSCRIBE'), -- >= 2.0
1084 | psubscribe = command('PSUBSCRIBE'), -- >= 2.0
1085 | punsubscribe = command('PUNSUBSCRIBE'), -- >= 2.0
1086 | publish = command('PUBLISH'), -- >= 2.0
1087 |
1088 | -- redis scripting
1089 | eval = command('EVAL'), -- >= 2.6
1090 | evalsha = command('EVALSHA'), -- >= 2.6
1091 | script = command('SCRIPT'), -- >= 2.6
1092 |
1093 | -- remote server control commands
1094 | bgrewriteaof = command('BGREWRITEAOF'),
1095 | config = command('CONFIG', { -- >= 2.0
1096 | response = function(reply, command, ...)
1097 | if (type(reply) == 'table') then
1098 | local new_reply = { }
1099 | for i = 1, #reply, 2 do new_reply[reply[i]] = reply[i + 1] end
1100 | return new_reply
1101 | end
1102 |
1103 | return reply
1104 | end
1105 | }),
1106 | client = command('CLIENT'), -- >= 2.4
1107 | slaveof = command('SLAVEOF'),
1108 | save = command('SAVE'),
1109 | bgsave = command('BGSAVE'),
1110 | lastsave = command('LASTSAVE'),
1111 | flushdb = command('FLUSHDB'),
1112 | flushall = command('FLUSHALL'),
1113 | monitor = command('MONITOR'),
1114 | time = command('TIME'), -- >= 2.6
1115 | slowlog = command('SLOWLOG', { -- >= 2.2.13
1116 | response = function(reply, command, ...)
1117 | if (type(reply) == 'table') then
1118 | local structured = { }
1119 | for index, entry in ipairs(reply) do
1120 | structured[index] = {
1121 | id = tonumber(entry[1]),
1122 | timestamp = tonumber(entry[2]),
1123 | duration = tonumber(entry[3]),
1124 | command = entry[4],
1125 | }
1126 | end
1127 | return structured
1128 | end
1129 |
1130 | return reply
1131 | end
1132 | }),
1133 | info = command('INFO', {
1134 | response = parse_info,
1135 | }),
1136 | }
1137 |
1138 | -- ############################################################################
1139 |
1140 | return redis
1141 |
--------------------------------------------------------------------------------
/tdcli.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | This program is free software; you can redistribute it and/or modify
3 | it under the terms of the GNU General Public License as published by
4 | the Free Software Foundation; either version 2 of the License, or
5 | (at your option) any later version.
6 |
7 | This program is distributed in the hope that it will be useful,
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | GNU General Public License for more details.
11 |
12 | You should have received a copy of the GNU General Public License
13 | along with this program; if not, write to the Free Software
14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15 | MA 02110-1301, USA.
16 |
17 | ]]--
18 |
19 | -- Vector example form is like this: {[0] = v} or {v1, v2, v3, [0] = v}
20 | -- If false or true crashed your telegram-cli, try to change true to 1 and false to 0
21 |
22 | -- Main table
23 | local M = {}
24 | local db = dofile 'libs/redis.lua'
25 | -- It's do nothing but suppress "lua: attempt to call a nil value" warning
26 | function dl_cb(arg, data)
27 | end
28 |
29 | -- @chat_id = user, group, channel, and broadcast
30 | -- @group_id = normal group
31 | -- @channel_id = channel and broadcast
32 | local function getChatId(chat_id)
33 | local chat = {}
34 | local chat_id = tostring(chat_id)
35 |
36 | if chat_id:match('^-100') then
37 | local channel_id = chat_id:gsub('-100', '')
38 | chat = {ID = channel_id, type = 'channel'}
39 | else
40 | local group_id = chat_id:gsub('-', '')
41 | chat = {ID = group_id, type = 'group'}
42 | end
43 |
44 | return chat
45 | end
46 |
47 | local function getInputFile(file)
48 | local input = tostring(file)
49 |
50 | if input:match('/') then
51 | infile = {ID = "InputFileLocal", path_ = file}
52 | elseif input:match('^%d+$') then
53 | infile = {ID = "InputFileId", id_ = file}
54 | else
55 | infile = {ID = "InputFilePersistentId", persistent_id_ = file}
56 | end
57 |
58 | return infile
59 | end
60 |
61 | -- User can send bold, italic, and monospace text uses HTML or Markdown format.
62 | local function getParseMode(parse_mode)
63 | if parse_mode then
64 | local mode = parse_mode:lower()
65 |
66 | if mode == 'markdown' or mode == 'md' then
67 | P = {ID = "TextParseModeMarkdown"}
68 | elseif mode == 'html' then
69 | P = {ID = "TextParseModeHTML"}
70 | end
71 | end
72 |
73 | return P
74 | end
75 |
76 | -- Send SendMessage request
77 | local function sendRequest(request_id, chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, callback, extra)
78 | tdcli_function ({
79 | ID = request_id,
80 | chat_id_ = chat_id,
81 | reply_to_message_id_ = reply_to_message_id,
82 | disable_notification_ = disable_notification,
83 | from_background_ = from_background,
84 | reply_markup_ = reply_markup,
85 | input_message_content_ = input_message_content,
86 | }, callback or dl_cb, extra)
87 | end
88 |
89 | -- Returns current authorization state, offline request
90 | local function getAuthState(dl_cb, cmd)
91 | tdcli_function ({
92 | ID = "GetAuthState",
93 | }, cb or dl_cb, cmd)
94 | end
95 |
96 | M.getAuthState = getAuthState
97 |
98 | -- Sets user's phone number and sends authentication code to the user.
99 | -- Works only when authGetState returns authStateWaitPhoneNumber.
100 | -- If phone number is not recognized or another error has happened, returns an error. Otherwise returns authStateWaitCode
101 | -- @phone_number User's phone number in any reasonable format
102 | -- @allow_flash_call Pass True, if code can be sent via flash call to the specified phone number
103 | -- @is_current_phone_number Pass true, if the phone number is used on the current device. Ignored if allow_flash_call is False
104 | local function setAuthPhoneNumber(phone_number, allow_flash_call, is_current_phone_number, cb, cmd)
105 | tdcli_function ({
106 | ID = "SetAuthPhoneNumber",
107 | phone_number_ = phone_number,
108 | allow_flash_call_ = allow_flash_call,
109 | is_current_phone_number_ = is_current_phone_number
110 | }, cb or dl_cb, cmd)
111 | end
112 |
113 | M.setAuthPhoneNumber = setAuthPhoneNumber
114 |
115 | -- Resends authentication code to the user.
116 | -- Works only when authGetState returns authStateWaitCode and next_code_type of result is not null.
117 | -- Returns authStateWaitCode on success
118 | local function resendAuthCode(dl_cb, cmd)
119 | tdcli_function ({
120 | ID = "ResendAuthCode",
121 | }, cb or dl_cb, cmd)
122 | end
123 |
124 | M.resendAuthCode = resendAuthCode
125 |
126 | -- Checks authentication code.
127 | -- Works only when authGetState returns authStateWaitCode.
128 | -- Returns authStateWaitPassword or authStateOk on success
129 | -- @code Verification code from SMS, Telegram message, voice call or flash call
130 | -- @first_name User first name, if user is yet not registered, 1-255 characters
131 | -- @last_name Optional user last name, if user is yet not registered, 0-255 characters
132 | local function checkAuthCode(code, first_name, last_name, cb, cmd)
133 | tdcli_function ({
134 | ID = "CheckAuthCode",
135 | code_ = code,
136 | first_name_ = first_name,
137 | last_name_ = last_name
138 | }, cb or dl_cb, cmd)
139 | end
140 |
141 | M.checkAuthCode = checkAuthCode
142 |
143 | -- Checks password for correctness.
144 | -- Works only when authGetState returns authStateWaitPassword.
145 | -- Returns authStateOk on success
146 | -- @password Password to check
147 | local function checkAuthPassword(password, cb, cmd)
148 | tdcli_function ({
149 | ID = "CheckAuthPassword",
150 | password_ = password
151 | }, cb or dl_cb, cmd)
152 | end
153 |
154 | M.checkAuthPassword = checkAuthPassword
155 |
156 | -- Requests to send password recovery code to email.
157 | -- Works only when authGetState returns authStateWaitPassword.
158 | -- Returns authStateWaitPassword on success
159 | local function requestAuthPasswordRecovery(dl_cb, cmd)
160 | tdcli_function ({
161 | ID = "RequestAuthPasswordRecovery",
162 | }, cb or dl_cb, cmd)
163 | end
164 |
165 | M.requestAuthPasswordRecovery = requestAuthPasswordRecovery
166 |
167 | -- Recovers password with recovery code sent to email.
168 | -- Works only when authGetState returns authStateWaitPassword.
169 | -- Returns authStateOk on success
170 | -- @recovery_code Recovery code to check
171 | local function recoverAuthPassword(recovery_code, cb, cmd)
172 | tdcli_function ({
173 | ID = "RecoverAuthPassword",
174 | recovery_code_ = recovery_code
175 | }, cb or dl_cb, cmd)
176 | end
177 |
178 | M.recoverAuthPassword = recoverAuthPassword
179 |
180 | -- Logs out user.
181 | -- If force == false, begins to perform soft log out, returns authStateLoggingOut after completion.
182 | -- If force == true then succeeds almost immediately without cleaning anything at the server, but returns error with code 401 and description "Unauthorized"
183 | -- @force If true, just delete all local data. Session will remain in list of active sessions
184 | local function resetAuth(force, cb, cmd)
185 | tdcli_function ({
186 | ID = "ResetAuth",
187 | force_ = force or nil
188 | }, cb or dl_cb, cmd)
189 | end
190 |
191 | M.resetAuth = resetAuth
192 |
193 | -- Check bot's authentication token to log in as a bot.
194 | -- Works only when authGetState returns authStateWaitPhoneNumber.
195 | -- Can be used instead of setAuthPhoneNumber and checkAuthCode to log in.
196 | -- Returns authStateOk on success
197 | -- @token Bot token
198 | local function checkAuthBotToken(token, cb, cmd)
199 | tdcli_function ({
200 | ID = "CheckAuthBotToken",
201 | token_ = token
202 | }, cb or dl_cb, cmd)
203 | end
204 |
205 | M.checkAuthBotToken = checkAuthBotToken
206 |
207 | -- Returns current state of two-step verification
208 | local function getPasswordState(dl_cb, cmd)
209 | tdcli_function ({
210 | ID = "GetPasswordState",
211 | }, cb or dl_cb, cmd)
212 | end
213 |
214 | M.getPasswordState = getPasswordState
215 |
216 | -- Changes user password.
217 | -- If new recovery email is specified, then error EMAIL_UNCONFIRMED is returned and password change will not be applied until email confirmation.
218 | -- Application should call getPasswordState from time to time to check if email is already confirmed
219 | -- @old_password Old user password
220 | -- @new_password New user password, may be empty to remove the password
221 | -- @new_hint New password hint, can be empty
222 | -- @set_recovery_email Pass True, if recovery email should be changed
223 | -- @new_recovery_email New recovery email, may be empty
224 | local function setPassword(old_password, new_password, new_hint, set_recovery_email, new_recovery_email, cb, cmd)
225 | tdcli_function ({
226 | ID = "SetPassword",
227 | old_password_ = old_password,
228 | new_password_ = new_password,
229 | new_hint_ = new_hint,
230 | set_recovery_email_ = set_recovery_email,
231 | new_recovery_email_ = new_recovery_email
232 | }, cb or dl_cb, cmd)
233 | end
234 |
235 | M.setPassword = setPassword
236 |
237 | -- Returns set up recovery email.
238 | -- This method can be used to verify a password provided by the user
239 | -- @password Current user password
240 | local function getRecoveryEmail(password, cb, cmd)
241 | tdcli_function ({
242 | ID = "GetRecoveryEmail",
243 | password_ = password
244 | }, cb or dl_cb, cmd)
245 | end
246 |
247 | M.getRecoveryEmail = getRecoveryEmail
248 |
249 | -- Changes user recovery email.
250 | -- If new recovery email is specified, then error EMAIL_UNCONFIRMED is returned and email will not be changed until email confirmation.
251 | -- Application should call getPasswordState from time to time to check if email is already confirmed.
252 | -- If new_recovery_email coincides with the current set up email succeeds immediately and aborts all other requests waiting for email confirmation
253 | -- @password Current user password
254 | -- @new_recovery_email New recovery email
255 | local function setRecoveryEmail(password, new_recovery_email, cb, cmd)
256 | tdcli_function ({
257 | ID = "SetRecoveryEmail",
258 | password_ = password,
259 | new_recovery_email_ = new_recovery_email
260 | }, cb or dl_cb, cmd)
261 | end
262 |
263 | M.setRecoveryEmail = setRecoveryEmail
264 |
265 | -- Requests to send password recovery code to email
266 | local function requestPasswordRecovery(dl_cb, cmd)
267 | tdcli_function ({
268 | ID = "RequestPasswordRecovery",
269 | }, cb or dl_cb, cmd)
270 | end
271 |
272 | M.requestPasswordRecovery = requestPasswordRecovery
273 |
274 | -- Recovers password with recovery code sent to email
275 | -- @recovery_code Recovery code to check
276 | local function recoverPassword(recovery_code, cb, cmd)
277 | tdcli_function ({
278 | ID = "RecoverPassword",
279 | recovery_code_ = tostring(recovery_code)
280 | }, cb or dl_cb, cmd)
281 | end
282 |
283 | M.recoverPassword = recoverPassword
284 |
285 | -- Returns current logged in user
286 | local function getMe(cb, cmd)
287 | tdcli_function ({
288 | ID = "GetMe",
289 | }, cb or dl_cb, cmd)
290 | end
291 |
292 | M.getMe = getMe
293 |
294 | -- Returns information about a user by its identifier, offline request if current user is not a bot
295 | -- @user_id User identifier
296 | local function getUser(user_id, cb, cmd)
297 | tdcli_function ({
298 | ID = "GetUser",
299 | user_id_ = user_id
300 | }, cb or dl_cb, cmd)
301 | end
302 |
303 | M.getUser = getUser
304 |
305 | -- Returns full information about a user by its identifier
306 | -- @user_id User identifier
307 | local function getUserFull(user_id, cb, cmd)
308 | tdcli_function ({
309 | ID = "GetUserFull",
310 | user_id_ = user_id
311 | }, cb or dl_cb, cmd)
312 | end
313 |
314 | M.getUserFull = getUserFull
315 |
316 | -- Returns information about a group by its identifier, offline request if current user is not a bot
317 | -- @group_id Group identifier
318 | local function getGroup(group_id, cb, cmd)
319 | tdcli_function ({
320 | ID = "GetGroup",
321 | group_id_ = getChatId(group_id).ID
322 | }, cb or dl_cb, cmd)
323 | end
324 |
325 | M.getGroup = getGroup
326 |
327 | -- Returns full information about a group by its identifier
328 | -- @group_id Group identifier
329 | local function getGroupFull(group_id, cb, cmd)
330 | tdcli_function ({
331 | ID = "GetGroupFull",
332 | group_id_ = getChatId(group_id).ID
333 | }, cb or dl_cb, cmd)
334 | end
335 |
336 | M.getGroupFull = getGroupFull
337 |
338 | -- Returns information about a channel by its identifier, offline request if current user is not a bot
339 | -- @channel_id Channel identifier
340 | local function getChannel(channel_id, cb, cmd)
341 | tdcli_function ({
342 | ID = "GetChannel",
343 | channel_id_ = getChatId(channel_id).ID
344 | }, cb or dl_cb, cmd)
345 | end
346 |
347 | M.getChannel = getChannel
348 |
349 | -- Returns full information about a channel by its identifier, cached for at most 1 minute
350 | -- @channel_id Channel identifier
351 | local function getChannelFull(channel_id, cb, cmd)
352 | tdcli_function ({
353 | ID = "GetChannelFull",
354 | channel_id_ = getChatId(channel_id).ID
355 | }, cb or dl_cb, cmd)
356 | end
357 |
358 | M.getChannelFull = getChannelFull
359 |
360 | -- Returns information about a secret chat by its identifier, offline request
361 | -- @secret_chat_id Secret chat identifier
362 | local function getSecretChat(secret_chat_id, cb, cmd)
363 | tdcli_function ({
364 | ID = "GetSecretChat",
365 | secret_chat_id_ = secret_chat_id
366 | }, cb or dl_cb, cmd)
367 | end
368 |
369 | M.getSecretChat = getSecretChat
370 |
371 | -- Returns information about a chat by its identifier, offline request if current user is not a bot
372 | -- @chat_id Chat identifier
373 | local function getChat(chat_id, cb, cmd)
374 | tdcli_function ({
375 | ID = "GetChat",
376 | chat_id_ = chat_id
377 | }, cb or dl_cb, cmd)
378 | end
379 |
380 | M.getChat = getChat
381 |
382 | -- Returns information about a message
383 | -- @chat_id Identifier of the chat, message belongs to
384 | -- @message_id Identifier of the message to get
385 | local function getMessage(chat_id, message_id, cb, cmd)
386 | tdcli_function ({
387 | ID = "GetMessage",
388 | chat_id_ = chat_id,
389 | message_id_ = message_id
390 | }, cb or dl_cb, cmd)
391 | end
392 |
393 | M.getMessage = getMessage
394 |
395 | -- Returns information about messages.
396 | -- If message is not found, returns null on the corresponding position of the result
397 | -- @chat_id Identifier of the chat, messages belongs to
398 | -- @message_ids Identifiers of the messages to get
399 | local function getMessages(chat_id, message_ids, cb, cmd)
400 | tdcli_function ({
401 | ID = "GetMessages",
402 | chat_id_ = chat_id,
403 | message_ids_ = message_ids -- vector
404 | }, cb or dl_cb, cmd)
405 | end
406 |
407 | M.getMessages = getMessages
408 |
409 | -- Returns information about a file, offline request
410 | -- @file_id Identifier of the file to get
411 | local function getFile(file_id, cb, cmd)
412 | tdcli_function ({
413 | ID = "GetFile",
414 | file_id_ = file_id
415 | }, cb or dl_cb, cmd)
416 | end
417 |
418 | M.getFile = getFile
419 |
420 | -- Returns information about a file by its persistent id, offline request
421 | -- @persistent_file_id Persistent identifier of the file to get
422 | local function getFilePersistent(persistent_file_id, cb, cmd)
423 | tdcli_function ({
424 | ID = "GetFilePersistent",
425 | persistent_file_id_ = persistent_file_id
426 | }, cb or dl_cb, cmd)
427 | end
428 |
429 | M.getFilePersistent = getFilePersistent
430 |
431 | -- Returns list of chats in the right order, chats are sorted by (order, chat_id) in decreasing order.
432 | -- For example, to get list of chats from the beginning, the offset_order should be equal 2^63 - 1
433 | -- @offset_order Chat order to return chats from
434 | -- @offset_chat_id Chat identifier to return chats from
435 | -- @limit Maximum number of chats to be returned
436 | local function getChats(offset_order, offset_chat_id, limit, cb, cmd)
437 | if not limit or limit > 20 then
438 | limit = 20
439 | end
440 |
441 | tdcli_function ({
442 | ID = "GetChats",
443 | offset_order_ = offset_order or 9223372036854775807,
444 | offset_chat_id_ = offset_chat_id or 0,
445 | limit_ = limit
446 | }, cb or dl_cb, cmd)
447 | end
448 |
449 | M.getChats = getChats
450 |
451 | -- Searches public chat by its username.
452 | -- Currently only private and channel chats can be public.
453 | -- Returns chat if found, otherwise some error is returned
454 | -- @username Username to be resolved
455 | local function searchPublicChat(username, cb, cmd)
456 | tdcli_function ({
457 | ID = "SearchPublicChat",
458 | username_ = username
459 | }, cb or dl_cb, cmd)
460 | end
461 |
462 | M.searchPublicChat = searchPublicChat
463 |
464 | -- Searches public chats by prefix of their username.
465 | -- Currently only private and channel (including supergroup) chats can be public.
466 | -- Returns meaningful number of results.
467 | -- Returns nothing if length of the searched username prefix is less than 5.
468 | -- Excludes private chats with contacts from the results
469 | -- @username_prefix Prefix of the username to search
470 | local function searchPublicChats(username_prefix, cb, cmd)
471 | tdcli_function ({
472 | ID = "SearchPublicChats",
473 | username_prefix_ = username_prefix
474 | }, cb or dl_cb, cmd)
475 | end
476 |
477 | M.searchPublicChats = searchPublicChats
478 |
479 | -- Searches for specified query in the title and username of known chats, offline request.
480 | -- Returns chats in the order of them in the chat list
481 | -- @query Query to search for, if query is empty, returns up to 20 recently found chats
482 | -- @limit Maximum number of chats to be returned
483 | local function searchChats(query, limit, cb, cmd)
484 | if not limit or limit > 20 then
485 | limit = 20
486 | end
487 |
488 | tdcli_function ({
489 | ID = "SearchChats",
490 | query_ = query,
491 | limit_ = limit
492 | }, cb or dl_cb, cmd)
493 | end
494 |
495 | M.searchChats = searchChats
496 |
497 | -- Adds chat to the list of recently found chats.
498 | -- The chat is added to the beginning of the list.
499 | -- If the chat is already in the list, at first it is removed from the list
500 | -- @chat_id Identifier of the chat to add
501 | local function addRecentlyFoundChat(chat_id, cb, cmd)
502 | tdcli_function ({
503 | ID = "AddRecentlyFoundChat",
504 | chat_id_ = chat_id
505 | }, cb or dl_cb, cmd)
506 | end
507 |
508 | M.addRecentlyFoundChat = addRecentlyFoundChat
509 |
510 | -- Deletes chat from the list of recently found chats
511 | -- @chat_id Identifier of the chat to delete
512 | local function deleteRecentlyFoundChat(chat_id, cb, cmd)
513 | tdcli_function ({
514 | ID = "DeleteRecentlyFoundChat",
515 | chat_id_ = chat_id
516 | }, cb or dl_cb, cmd)
517 | end
518 |
519 | M.deleteRecentlyFoundChat = deleteRecentlyFoundChat
520 |
521 | -- Clears list of recently found chats
522 | local function deleteRecentlyFoundChats(dl_cb, cmd)
523 | tdcli_function ({
524 | ID = "DeleteRecentlyFoundChats",
525 | }, cb or dl_cb, cmd)
526 | end
527 |
528 | M.deleteRecentlyFoundChats = deleteRecentlyFoundChats
529 |
530 | -- Returns list of common chats with an other given user.
531 | -- Chats are sorted by their type and creation date
532 | -- @user_id User identifier
533 | -- @offset_chat_id Chat identifier to return chats from, use 0 for the first request
534 | -- @limit Maximum number of chats to be returned, up to 100
535 | local function getCommonChats(user_id, offset_chat_id, limit, cb, cmd)
536 | if not limit or limit > 100 then
537 | limit = 100
538 | end
539 |
540 | tdcli_function ({
541 | ID = "GetCommonChats",
542 | user_id_ = user_id,
543 | offset_chat_id_ = offset_chat_id,
544 | limit_ = limit
545 | }, cb or dl_cb, cmd)
546 | end
547 |
548 | M.getCommonChats = getCommonChats
549 |
550 | -- Returns messages in a chat.
551 | -- Automatically calls openChat.
552 | -- Returns result in reverse chronological order, i.e. in order of decreasing message.message_id
553 | -- @chat_id Chat identifier
554 | -- @from_message_id Identifier of the message near which we need a history, you can use 0 to get results from the beginning, i.e. from oldest to newest
555 | -- @offset Specify 0 to get results exactly from from_message_id or negative offset to get specified message and some newer messages
556 | -- @limit Maximum number of messages to be returned, should be positive and can't be greater than 100.
557 | -- If offset is negative, limit must be greater than -offset.
558 | -- There may be less than limit messages returned even the end of the history is not reached
559 | local function getChatHistory(chat_id, from_message_id, offset, limit, cb, cmd)
560 | if not limit or limit > 100 then
561 | limit = 100
562 | end
563 |
564 | tdcli_function ({
565 | ID = "GetChatHistory",
566 | chat_id_ = chat_id,
567 | from_message_id_ = from_message_id,
568 | offset_ = offset or 0,
569 | limit_ = limit
570 | }, cb or dl_cb, cmd)
571 | end
572 |
573 | M.getChatHistory = getChatHistory
574 |
575 | -- Deletes all messages in the chat.
576 | -- Can't be used for channel chats
577 | -- @chat_id Chat identifier
578 | -- @remove_from_chat_list Pass true, if chat should be removed from the chat list
579 | local function deleteChatHistory(chat_id, remove_from_chat_list, cb, cmd)
580 | tdcli_function ({
581 | ID = "DeleteChatHistory",
582 | chat_id_ = chat_id,
583 | remove_from_chat_list_ = remove_from_chat_list
584 | }, cb or dl_cb, cmd)
585 | end
586 |
587 | M.deleteChatHistory = deleteChatHistory
588 |
589 | -- Searches for messages with given words in the chat.
590 | -- Returns result in reverse chronological order, i. e. in order of decreasimg message_id.
591 | -- Doesn't work in secret chats
592 | -- @chat_id Chat identifier to search in
593 | -- @query Query to search for
594 | -- @from_message_id Identifier of the message from which we need a history, you can use 0 to get results from beginning
595 | -- @limit Maximum number of messages to be returned, can't be greater than 100
596 | -- @filter Filter for content of searched messages
597 | -- filter = Empty|Animation|Audio|Document|Photo|Video|Voice|PhotoAndVideo|Url|ChatPhoto
598 | local function searchChatMessages(chat_id, query, from_message_id, limit, filter, cb, cmd)
599 | if not limit or limit > 100 then
600 | limit = 100
601 | end
602 |
603 | tdcli_function ({
604 | ID = "SearchChatMessages",
605 | chat_id_ = chat_id,
606 | query_ = query,
607 | from_message_id_ = from_message_id,
608 | limit_ = limit,
609 | filter_ = {
610 | ID = 'SearchMessagesFilter' .. filter
611 | },
612 | }, cb or dl_cb, cmd)
613 | end
614 |
615 | M.searchChatMessages = searchChatMessages
616 |
617 | -- Searches for messages in all chats except secret chats. Returns result in reverse chronological order, i. e. in order of decreasing (date, chat_id, message_id)
618 | -- @query Query to search for
619 | -- @offset_date Date of the message to search from, you can use 0 or any date in the future to get results from the beginning
620 | -- @offset_chat_id Chat identifier of the last found message or 0 for the first request
621 | -- @offset_message_id Message identifier of the last found message or 0 for the first request
622 | -- @limit Maximum number of messages to be returned, can't be greater than 100
623 | local function searchMessages(query, offset_date, offset_chat_id, offset_message_id, limit, cb, cmd)
624 | if not limit or limit > 100 then
625 | limit = 100
626 | end
627 |
628 | tdcli_function ({
629 | ID = "SearchMessages",
630 | query_ = query,
631 | offset_date_ = offset_date,
632 | offset_chat_id_ = offset_chat_id,
633 | offset_message_id_ = offset_message_id,
634 | limit_ = limit
635 | }, cb or dl_cb, cmd)
636 | end
637 |
638 | M.searchMessages = searchMessages
639 |
640 | -- Invites bot to a chat (if it is not in the chat) and send /start to it.
641 | -- Bot can't be invited to a private chat other than chat with the bot.
642 | -- Bots can't be invited to broadcast channel chats and secret chats.
643 | -- Returns sent message.
644 | -- UpdateChatTopMessage will not be sent, so returned message should be used to update chat top message
645 | -- @bot_user_id Identifier of the bot
646 | -- @chat_id Identifier of the chat
647 | -- @parameter Hidden parameter sent to bot for deep linking (https://api.telegram.org/bots#deep-linking)
648 | -- parameter=start|startgroup or custom as defined by bot creator
649 | local function sendBotStartMessage(bot_user_id, chat_id, parameter, cb, cmd)
650 | tdcli_function ({
651 | ID = "SendBotStartMessage",
652 | bot_user_id_ = bot_user_id,
653 | chat_id_ = chat_id,
654 | parameter_ = parameter
655 | }, cb or dl_cb, cmd)
656 | end
657 |
658 | M.sendBotStartMessage = sendBotStartMessage
659 |
660 | -- Sends result of the inline query as a message.
661 | -- Returns sent message.
662 | -- UpdateChatTopMessage will not be sent, so returned message should be used to update chat top message.
663 | -- Always clears chat draft message
664 | -- @chat_id Chat to send message
665 | -- @reply_to_message_id Identifier of a message to reply to or 0
666 | -- @disable_notification Pass true, to disable notification about the message, doesn't works in secret chats
667 | -- @from_background Pass true, if the message is sent from background
668 | -- @query_id Identifier of the inline query
669 | -- @result_id Identifier of the inline result
670 | local function sendInlineQueryResultMessage(chat_id, reply_to_message_id, disable_notification, from_background, query_id, result_id, cb, cmd)
671 | tdcli_function ({
672 | ID = "SendInlineQueryResultMessage",
673 | chat_id_ = chat_id,
674 | reply_to_message_id_ = reply_to_message_id,
675 | disable_notification_ = disable_notification,
676 | from_background_ = from_background,
677 | query_id_ = query_id,
678 | result_id_ = result_id
679 | }, cb or dl_cb, cmd)
680 | end
681 |
682 | M.sendInlineQueryResultMessage = sendInlineQueryResultMessage
683 |
684 | -- Forwards previously sent messages.
685 | -- Returns forwarded messages in the same order as message identifiers passed in message_ids.
686 | -- If message can't be forwarded, null will be returned instead of the message.
687 | -- UpdateChatTopMessage will not be sent, so returned messages should be used to update chat top message
688 | -- @chat_id Identifier of a chat to forward messages
689 | -- @from_chat_id Identifier of a chat to forward from
690 | -- @message_ids Identifiers of messages to forward
691 | -- @disable_notification Pass true, to disable notification about the message, doesn't works if messages are forwarded to secret chat
692 | -- @from_background Pass true, if the message is sent from background
693 | local function forwardMessages(chat_id, from_chat_id, message_ids, disable_notification, cb, cmd)
694 | tdcli_function ({
695 | ID = "ForwardMessages",
696 | chat_id_ = chat_id,
697 | from_chat_id_ = from_chat_id,
698 | message_ids_ = message_ids, -- vector
699 | disable_notification_ = disable_notification,
700 | from_background_ = 1
701 | }, cb or dl_cb, cmd)
702 | end
703 |
704 | M.forwardMessages = forwardMessages
705 |
706 | -- Changes current ttl setting in a secret chat and sends corresponding message
707 | -- @chat_id Chat identifier
708 | -- @ttl New value of ttl in seconds
709 | local function sendChatSetTtlMessage(chat_id, ttl, cb, cmd)
710 | tdcli_function ({
711 | ID = "SendChatSetTtlMessage",
712 | chat_id_ = chat_id,
713 | ttl_ = ttl
714 | }, cb or dl_cb, cmd)
715 | end
716 |
717 | M.sendChatSetTtlMessage = sendChatSetTtlMessage
718 |
719 | -- Deletes messages.
720 | -- UpdateDeleteMessages will not be sent for messages deleted through that function
721 | -- @chat_id Chat identifier
722 | -- @message_ids Identifiers of messages to delete
723 | local function deleteMessages(chat_id, message_ids, cb, cmd)
724 | tdcli_function ({
725 | ID = "DeleteMessages",
726 | chat_id_ = chat_id,
727 | message_ids_ = message_ids -- vector
728 | }, cb or dl_cb, cmd)
729 | end
730 |
731 | M.deleteMessages = deleteMessages
732 |
733 | -- Deletes all messages in the chat sent by the specified user.
734 | -- Works only in supergroup channel chats, needs appropriate privileges
735 | -- @chat_id Chat identifier
736 | -- @user_id User identifier
737 | local function deleteMessagesFromUser(chat_id, user_id, cb, cmd)
738 | tdcli_function ({
739 | ID = "DeleteMessagesFromUser",
740 | chat_id_ = chat_id,
741 | user_id_ = user_id
742 | }, cb or dl_cb, cmd)
743 | end
744 |
745 | M.deleteMessagesFromUser = deleteMessagesFromUser
746 |
747 | -- Edits text of text or game message.
748 | -- Non-bots can edit message in a limited period of time.
749 | -- Returns edited message after edit is complete server side
750 | -- @chat_id Chat the message belongs to
751 | -- @message_id Identifier of the message
752 | -- @reply_markup Bots only. New message reply markup
753 | -- @input_message_content New text content of the message. Should be of type InputMessageText
754 | local function editMessageText(chat_id, message_id, reply_markup, text, disable_web_page_preview, parse_mode, cb, cmd)
755 | local TextParseMode = getParseMode(parse_mode)
756 |
757 | tdcli_function ({
758 | ID = "EditMessageText",
759 | chat_id_ = chat_id,
760 | message_id_ = message_id,
761 | reply_markup_ = reply_markup, -- reply_markup:ReplyMarkup
762 | input_message_content_ = {
763 | ID = "InputMessageText",
764 | text_ = text,
765 | disable_web_page_preview_ = disable_web_page_preview,
766 | clear_draft_ = 0,
767 | entities_ = {},
768 | parse_mode_ = TextParseMode,
769 | },
770 | }, cb or dl_cb, cmd)
771 | end
772 |
773 | M.editMessageText = editMessageText
774 |
775 | -- Edits message content caption.
776 | -- Non-bots can edit message in a limited period of time.
777 | -- Returns edited message after edit is complete server side
778 | -- @chat_id Chat the message belongs to
779 | -- @message_id Identifier of the message
780 | -- @reply_markup Bots only. New message reply markup
781 | -- @caption New message content caption, 0-200 characters
782 | local function editMessageCaption(chat_id, message_id, reply_markup, caption, cb, cmd)
783 | tdcli_function ({
784 | ID = "EditMessageCaption",
785 | chat_id_ = chat_id,
786 | message_id_ = message_id,
787 | reply_markup_ = reply_markup, -- reply_markup:ReplyMarkup
788 | caption_ = caption
789 | }, cb or dl_cb, cmd)
790 | end
791 |
792 | M.editMessageCaption = editMessageCaption
793 |
794 | -- Bots only.
795 | -- Edits message reply markup.
796 | -- Returns edited message after edit is complete server side
797 | -- @chat_id Chat the message belongs to
798 | -- @message_id Identifier of the message
799 | -- @reply_markup New message reply markup
800 | local function editMessageReplyMarkup(inline_message_id, reply_markup, caption, cb, cmd)
801 | tdcli_function ({
802 | ID = "EditInlineMessageCaption",
803 | inline_message_id_ = inline_message_id,
804 | reply_markup_ = reply_markup, -- reply_markup:ReplyMarkup
805 | caption_ = caption
806 | }, cb or dl_cb, cmd)
807 | end
808 |
809 | M.editMessageReplyMarkup = editMessageReplyMarkup
810 |
811 | -- Bots only.
812 | -- Edits text of an inline text or game message sent via bot
813 | -- @inline_message_id Inline message identifier
814 | -- @reply_markup New message reply markup
815 | -- @input_message_content New text content of the message. Should be of type InputMessageText
816 | local function editInlineMessageText(inline_message_id, reply_markup, text, disable_web_page_preview, cb, cmd)
817 | tdcli_function ({
818 | ID = "EditInlineMessageText",
819 | inline_message_id_ = inline_message_id,
820 | reply_markup_ = reply_markup, -- reply_markup:ReplyMarkup
821 | input_message_content_ = {
822 | ID = "InputMessageText",
823 | text_ = text,
824 | disable_web_page_preview_ = disable_web_page_preview,
825 | clear_draft_ = 0,
826 | entities_ = {}
827 | },
828 | }, cb or dl_cb, cmd)
829 | end
830 |
831 | M.editInlineMessageText = editInlineMessageText
832 |
833 | -- Bots only.
834 | -- Edits caption of an inline message content sent via bot
835 | -- @inline_message_id Inline message identifier
836 | -- @reply_markup New message reply markup
837 | -- @caption New message content caption, 0-200 characters
838 | local function editInlineMessageCaption(inline_message_id, reply_markup, caption, cb, cmd)
839 | tdcli_function ({
840 | ID = "EditInlineMessageCaption",
841 | inline_message_id_ = inline_message_id,
842 | reply_markup_ = reply_markup, -- reply_markup:ReplyMarkup
843 | caption_ = caption
844 | }, cb or dl_cb, cmd)
845 | end
846 |
847 | M.editInlineMessageCaption = editInlineMessageCaption
848 |
849 | -- Bots only.
850 | -- Edits reply markup of an inline message sent via bot
851 | -- @inline_message_id Inline message identifier
852 | -- @reply_markup New message reply markup
853 | local function editInlineMessageReplyMarkup(inline_message_id, reply_markup, cb, cmd)
854 | tdcli_function ({
855 | ID = "EditInlineMessageReplyMarkup",
856 | inline_message_id_ = inline_message_id,
857 | reply_markup_ = reply_markup -- reply_markup:ReplyMarkup
858 | }, cb or dl_cb, cmd)
859 | end
860 |
861 | M.editInlineMessageReplyMarkup = editInlineMessageReplyMarkup
862 |
863 |
864 | -- Sends inline query to a bot and returns its results.
865 | -- Unavailable for bots
866 | -- @bot_user_id Identifier of the bot send query to
867 | -- @chat_id Identifier of the chat, where the query is sent
868 | -- @user_location User location, only if needed
869 | -- @query Text of the query
870 | -- @offset Offset of the first entry to return
871 | local function getInlineQueryResults(bot_user_id, chat_id, latitude, longitude, query, offset, cb, cmd)
872 | tdcli_function ({
873 | ID = "GetInlineQueryResults",
874 | bot_user_id_ = bot_user_id,
875 | chat_id_ = chat_id,
876 | user_location_ = {
877 | ID = "Location",
878 | latitude_ = latitude,
879 | longitude_ = longitude
880 | },
881 | query_ = query,
882 | offset_ = offset
883 | }, cb or dl_cb, cmd)
884 | end
885 |
886 | M.getInlineQueryResults = getInlineQueryResults
887 |
888 | -- Bots only.
889 | -- Sets result of the inline query
890 | -- @inline_query_id Identifier of the inline query
891 | -- @is_personal Does result of the query can be cached only for specified user
892 | -- @results Results of the query
893 | -- @cache_time Allowed time to cache results of the query in seconds
894 | -- @next_offset Offset for the next inline query, pass empty string if there is no more results
895 | -- @switch_pm_text If non-empty, this text should be shown on the button, which opens private chat with the bot and sends bot start message with parameter switch_pm_parameter
896 | -- @switch_pm_parameter Parameter for the bot start message
897 | local function answerInlineQuery(inline_query_id, is_personal, cache_time, next_offset, switch_pm_text, switch_pm_parameter, cb, cmd)
898 | tdcli_function ({
899 | ID = "AnswerInlineQuery",
900 | inline_query_id_ = inline_query_id,
901 | is_personal_ = is_personal,
902 | results_ = results, --vector,
903 | cache_time_ = cache_time,
904 | next_offset_ = next_offset,
905 | switch_pm_text_ = switch_pm_text,
906 | switch_pm_parameter_ = switch_pm_parameter
907 | }, cb or dl_cb, cmd)
908 | end
909 |
910 | M.answerInlineQuery = answerInlineQuery
911 |
912 | -- Sends callback query to a bot and returns answer to it.
913 | -- Unavailable for bots
914 | -- @chat_id Identifier of the chat with a message
915 | -- @message_id Identifier of the message, from which the query is originated
916 | -- @payload Query payload
917 | -- @text Text of the answer
918 | -- @show_alert If true, an alert should be shown to the user instead of a toast
919 | -- @url URL to be open
920 | local function getCallbackQueryAnswer(chat_id, message_id, text, show_alert, url, cb, cmd)
921 | tdcli_function ({
922 | ID = "GetCallbackQueryAnswer",
923 | chat_id_ = chat_id,
924 | message_id_ = message_id,
925 | payload_ = {
926 | ID = "CallbackQueryAnswer",
927 | text_ = text,
928 | show_alert_ = show_alert,
929 | url_ = url
930 | },
931 | }, cb or dl_cb, cmd)
932 | end
933 |
934 | M.getCallbackQueryAnswer = getCallbackQueryAnswer
935 |
936 | -- Bots only.
937 | -- Sets result of the callback query
938 | -- @callback_query_id Identifier of the callback query
939 | -- @text Text of the answer
940 | -- @show_alert If true, an alert should be shown to the user instead of a toast
941 | -- @url Url to be opened
942 | -- @cache_time Allowed time to cache result of the query in seconds
943 | local function answerCallbackQuery(callback_query_id, text, show_alert, url, cache_time, cb, cmd)
944 | tdcli_function ({
945 | ID = "AnswerCallbackQuery",
946 | callback_query_id_ = callback_query_id,
947 | text_ = text,
948 | show_alert_ = show_alert,
949 | url_ = url,
950 | cache_time_ = cache_time
951 | }, cb or dl_cb, cmd)
952 | end
953 |
954 | M.answerCallbackQuery = answerCallbackQuery
955 |
956 | -- Bots only.
957 | -- Updates game score of the specified user in the game
958 | -- @chat_id Chat a message with the game belongs to
959 | -- @message_id Identifier of the message
960 | -- @edit_message True, if message should be edited
961 | -- @user_id User identifier
962 | -- @score New score
963 | -- @force Pass True to update the score even if it decreases. If score is 0, user will be deleted from the high scores table
964 | local function setGameScore(chat_id, message_id, edit_message, user_id, score, force, cb, cmd)
965 | tdcli_function ({
966 | ID = "SetGameScore",
967 | chat_id_ = chat_id,
968 | message_id_ = message_id,
969 | edit_message_ = edit_message,
970 | user_id_ = user_id,
971 | score_ = score,
972 | force_ = force
973 | }, cb or dl_cb, cmd)
974 | end
975 |
976 | M.setGameScore = setGameScore
977 |
978 | -- Bots only.
979 | -- Updates game score of the specified user in the game
980 | -- @inline_message_id Inline message identifier
981 | -- @edit_message True, if message should be edited
982 | -- @user_id User identifier
983 | -- @score New score
984 | -- @force Pass True to update the score even if it decreases. If score is 0, user will be deleted from the high scores table
985 | local function setInlineGameScore(inline_message_id, edit_message, user_id, score, force, cb, cmd)
986 | tdcli_function ({
987 | ID = "SetInlineGameScore",
988 | inline_message_id_ = inline_message_id,
989 | edit_message_ = edit_message,
990 | user_id_ = user_id,
991 | score_ = score,
992 | force_ = force
993 | }, cb or dl_cb, cmd)
994 | end
995 |
996 | M.setInlineGameScore = setInlineGameScore
997 |
998 | -- Bots only.
999 | -- Returns game high scores and some part of the score table around of the specified user in the game
1000 | -- @chat_id Chat a message with the game belongs to
1001 | -- @message_id Identifier of the message
1002 | -- @user_id User identifie
1003 | local function getGameHighScores(chat_id, message_id, user_id, cb, cmd)
1004 | tdcli_function ({
1005 | ID = "GetGameHighScores",
1006 | chat_id_ = chat_id,
1007 | message_id_ = message_id,
1008 | user_id_ = user_id
1009 | }, cb or dl_cb, cmd)
1010 | end
1011 |
1012 | M.getGameHighScores = getGameHighScores
1013 |
1014 | -- Bots only.
1015 | -- Returns game high scores and some part of the score table around of the specified user in the game
1016 | -- @inline_message_id Inline message identifier
1017 | -- @user_id User identifier
1018 | local function getInlineGameHighScores(inline_message_id, user_id, cb, cmd)
1019 | tdcli_function ({
1020 | ID = "GetInlineGameHighScores",
1021 | inline_message_id_ = inline_message_id,
1022 | user_id_ = user_id
1023 | }, cb or dl_cb, cmd)
1024 | end
1025 |
1026 | M.getInlineGameHighScores = getInlineGameHighScores
1027 |
1028 | -- Deletes default reply markup from chat.
1029 | -- This method needs to be called after one-time keyboard or ForceReply reply markup has been used.
1030 | -- UpdateChatReplyMarkup will be send if reply markup will be changed
1031 | -- @chat_id Chat identifier
1032 | -- @message_id Message identifier of used keyboard
1033 | local function deleteChatReplyMarkup(chat_id, message_id, cb, cmd)
1034 | tdcli_function ({
1035 | ID = "DeleteChatReplyMarkup",
1036 | chat_id_ = chat_id,
1037 | message_id_ = message_id
1038 | }, cb or dl_cb, cmd)
1039 | end
1040 |
1041 | M.deleteChatReplyMarkup = deleteChatReplyMarkup
1042 |
1043 | -- Sends notification about user activity in a chat
1044 | -- @chat_id Chat identifier
1045 | -- @action Action description
1046 | -- action = Typing|Cancel|RecordVideo|UploadVideo|RecordVoice|UploadVoice|UploadPhoto|UploadDocument|GeoLocation|ChooseContact|StartPlayGame
1047 | local function sendChatAction(chat_id, action, progress, cb, cmd)
1048 | tdcli_function ({
1049 | ID = "SendChatAction",
1050 | chat_id_ = chat_id,
1051 | action_ = {
1052 | ID = "SendMessage" .. action .. "Action",
1053 | progress_ = progress or 100
1054 | }
1055 | }, cb or dl_cb, cmd)
1056 | end
1057 |
1058 | M.sendChatAction = sendChatAction
1059 |
1060 | -- Sends notification about screenshot taken in a chat.
1061 | -- Works only in secret chats
1062 | -- @chat_id Chat identifier
1063 | local function sendChatScreenshotTakenNotification(chat_id, cb, cmd)
1064 | tdcli_function ({
1065 | ID = "SendChatScreenshotTakenNotification",
1066 | chat_id_ = chat_id
1067 | }, cb or dl_cb, cmd)
1068 | end
1069 |
1070 | M.sendChatScreenshotTakenNotification = sendChatScreenshotTakenNotification
1071 |
1072 | -- Chat is opened by the user.
1073 | -- Many useful activities depends on chat being opened or closed. For example, in channels all updates are received only for opened chats
1074 | -- @chat_id Chat identifier
1075 | local function openChat(chat_id, cb, cmd)
1076 | tdcli_function ({
1077 | ID = "OpenChat",
1078 | chat_id_ = chat_id
1079 | }, cb or dl_cb, cmd)
1080 | end
1081 |
1082 | M.openChat = openChat
1083 |
1084 | -- Chat is closed by the user.
1085 | -- Many useful activities depends on chat being opened or closed.
1086 | -- @chat_id Chat identifier
1087 | local function closeChat(chat_id, cb, cmd)
1088 | tdcli_function ({
1089 | ID = "CloseChat",
1090 | chat_id_ = chat_id
1091 | }, cb or dl_cb, cmd)
1092 | end
1093 |
1094 | M.closeChat = closeChat
1095 |
1096 | -- Messages are viewed by the user.
1097 | -- Many useful activities depends on message being viewed. For example, marking messages as read, incrementing of view counter, updating of view counter, removing of deleted messages in channels
1098 | -- @chat_id Chat identifier
1099 | -- @message_ids Identifiers of viewed messages
1100 | local function viewMessages(chat_id, message_ids, cb, cmd)
1101 | tdcli_function ({
1102 | ID = "ViewMessages",
1103 | chat_id_ = chat_id,
1104 | message_ids_ = message_ids -- vector
1105 | }, cb or dl_cb, cmd)
1106 | end
1107 |
1108 | M.viewMessages = viewMessages
1109 |
1110 | -- Message content is opened, for example the user has opened a photo, a video, a document, a location or a venue or have listened to an audio or a voice message
1111 | -- @chat_id Chat identifier of the message
1112 | -- @message_id Identifier of the message with opened content
1113 | local function openMessageContent(chat_id, message_id, cb, cmd)
1114 | tdcli_function ({
1115 | ID = "OpenMessageContent",
1116 | chat_id_ = chat_id,
1117 | message_id_ = message_id
1118 | }, cb or dl_cb, cmd)
1119 | end
1120 |
1121 | M.openMessageContent = openMessageContent
1122 |
1123 | -- Returns existing chat corresponding to the given user
1124 | -- @user_id User identifier
1125 | local function createPrivateChat(user_id, cb, cmd)
1126 | tdcli_function ({
1127 | ID = "CreatePrivateChat",
1128 | user_id_ = user_id
1129 | }, cb or dl_cb, cmd)
1130 | end
1131 |
1132 | M.createPrivateChat = createPrivateChat
1133 |
1134 | -- Returns existing chat corresponding to the known group
1135 | -- @group_id Group identifier
1136 | local function createGroupChat(group_id, cb, cmd)
1137 | tdcli_function ({
1138 | ID = "CreateGroupChat",
1139 | group_id_ = getChatId(group_id).ID
1140 | }, cb or dl_cb, cmd)
1141 | end
1142 |
1143 | M.createGroupChat = createGroupChat
1144 |
1145 | -- Returns existing chat corresponding to the known channel
1146 | -- @channel_id Channel identifier
1147 | local function createChannelChat(channel_id, cb, cmd)
1148 | tdcli_function ({
1149 | ID = "CreateChannelChat",
1150 | channel_id_ = getChatId(channel_id).ID
1151 | }, cb or dl_cb, cmd)
1152 | end
1153 |
1154 | M.createChannelChat = createChannelChat
1155 |
1156 | -- Returns existing chat corresponding to the known secret chat
1157 | -- @secret_chat_id SecretChat identifier
1158 | local function createSecretChat(secret_chat_id, cb, cmd)
1159 | tdcli_function ({
1160 | ID = "CreateSecretChat",
1161 | secret_chat_id_ = secret_chat_id
1162 | }, cb or dl_cb, cmd)
1163 | end
1164 |
1165 | M.createSecretChat = createSecretChat
1166 |
1167 | -- Creates new group chat and send corresponding messageGroupChatCreate, returns created chat
1168 | -- @user_ids Identifiers of users to add to the group
1169 | -- @title Title of new group chat, 0-255 characters
1170 | local function createNewGroupChat(user_ids, title, cb, cmd)
1171 | tdcli_function ({
1172 | ID = "CreateNewGroupChat",
1173 | user_ids_ = user_ids, -- vector
1174 | title_ = title
1175 | }, cb or dl_cb, cmd)
1176 | end
1177 |
1178 | M.createNewGroupChat = createNewGroupChat
1179 |
1180 | -- Creates new channel chat and send corresponding messageChannelChatCreate, returns created chat
1181 | -- @title Title of new channel chat, 0-255 characters
1182 | -- @is_supergroup True, if supergroup chat should be created
1183 | -- @about Information about the channel, 0-255 characters
1184 | local function createNewChannelChat(title, is_supergroup, about, cb, cmd)
1185 | tdcli_function ({
1186 | ID = "CreateNewChannelChat",
1187 | title_ = title,
1188 | is_supergroup_ = is_supergroup,
1189 | about_ = about
1190 | }, cb or dl_cb, cmd)
1191 | end
1192 |
1193 | M.createNewChannelChat = createNewChannelChat
1194 |
1195 | -- Creates new secret chat, returns created chat
1196 | -- @user_id Identifier of a user to create secret chat with
1197 | local function createNewSecretChat(user_id, cb, cmd)
1198 | tdcli_function ({
1199 | ID = "CreateNewSecretChat",
1200 | user_id_ = user_id
1201 | }, cb or dl_cb, cmd)
1202 | end
1203 |
1204 | M.createNewSecretChat = createNewSecretChat
1205 |
1206 | -- Creates new channel supergroup chat from existing group chat and send corresponding messageChatMigrateTo and messageChatMigrateFrom. Deactivates group
1207 | -- @chat_id Group chat identifier
1208 | local function migrateGroupChatToChannelChat(chat_id, cb, cmd)
1209 | tdcli_function ({
1210 | ID = "MigrateGroupChatToChannelChat",
1211 | chat_id_ = chat_id
1212 | }, cb or dl_cb, cmd)
1213 | end
1214 |
1215 | M.migrateGroupChatToChannelChat = migrateGroupChatToChannelChat
1216 |
1217 | -- Changes chat title.
1218 | -- Title can't be changed for private chats.
1219 | -- Title will not change until change will be synchronized with the server.
1220 | -- Title will not be changed if application is killed before it can send request to the server.
1221 | -- There will be update about change of the title on success. Otherwise error will be returned
1222 | -- @chat_id Chat identifier
1223 | -- @title New title of a chat, 0-255 characters
1224 | local function changeChatTitle(chat_id, title, cb, cmd)
1225 | tdcli_function ({
1226 | ID = "ChangeChatTitle",
1227 | chat_id_ = chat_id,
1228 | title_ = title
1229 | }, cb or dl_cb, cmd)
1230 | end
1231 |
1232 | M.changeChatTitle = changeChatTitle
1233 |
1234 | -- Changes chat photo.
1235 | -- Photo can't be changed for private chats.
1236 | -- Photo will not change until change will be synchronized with the server.
1237 | -- Photo will not be changed if application is killed before it can send request to the server.
1238 | -- There will be update about change of the photo on success. Otherwise error will be returned
1239 | -- @chat_id Chat identifier
1240 | -- @photo New chat photo. You can use zero InputFileId to delete photo. Files accessible only by HTTP URL are not acceptable
1241 | local function changeChatPhoto(chat_id, photo, cb, cmd)
1242 | tdcli_function ({
1243 | ID = "ChangeChatPhoto",
1244 | chat_id_ = chat_id,
1245 | photo_ = getInputFile(photo)
1246 | }, cb or dl_cb, cmd)
1247 | end
1248 |
1249 | M.changeChatPhoto = changeChatPhoto
1250 |
1251 | -- Changes chat draft message
1252 | -- @chat_id Chat identifier
1253 | -- @draft_message New draft message, nullable
1254 | local function changeChatDraftMessage(chat_id, reply_to_message_id, text, disable_web_page_preview, clear_draft, parse_mode, cb, cmd)
1255 | local TextParseMode = getParseMode(parse_mode)
1256 |
1257 | tdcli_function ({
1258 | ID = "ChangeChatDraftMessage",
1259 | chat_id_ = chat_id,
1260 | draft_message_ = {
1261 | ID = "DraftMessage",
1262 | reply_to_message_id_ = reply_to_message_id,
1263 | input_message_text_ = {
1264 | ID = "InputMessageText",
1265 | text_ = text,
1266 | disable_web_page_preview_ = disable_web_page_preview,
1267 | clear_draft_ = clear_draft,
1268 | entities_ = {},
1269 | parse_mode_ = TextParseMode,
1270 | },
1271 | },
1272 | }, cb or dl_cb, cmd)
1273 | end
1274 |
1275 | M.changeChatDraftMessage = changeChatDraftMessage
1276 |
1277 | -- Adds new member to chat.
1278 | -- Members can't be added to private or secret chats.
1279 | -- Member will not be added until chat state will be synchronized with the server.
1280 | -- Member will not be added if application is killed before it can send request to the server
1281 | -- @chat_id Chat identifier
1282 | -- @user_id Identifier of the user to add
1283 | -- @forward_limit Number of previous messages from chat to forward to new member, ignored for channel chats
1284 | local function addChatMember(chat_id, user_id, forward_limit, cb, cmd)
1285 | tdcli_function ({
1286 | ID = "AddChatMember",
1287 | chat_id_ = chat_id,
1288 | user_id_ = user_id,
1289 | forward_limit_ = forward_limit or 50
1290 | }, cb or dl_cb, cmd)
1291 | end
1292 |
1293 | M.addChatMember = addChatMember
1294 |
1295 | -- Adds many new members to the chat.
1296 | -- Currently, available only for channels.
1297 | -- Can't be used to join the channel.
1298 | -- Member will not be added until chat state will be synchronized with the server.
1299 | -- Member will not be added if application is killed before it can send request to the server
1300 | -- @chat_id Chat identifier
1301 | -- @user_ids Identifiers of the users to add
1302 | local function addChatMembers(chat_id, user_ids, cb, cmd)
1303 | tdcli_function ({
1304 | ID = "AddChatMembers",
1305 | chat_id_ = chat_id,
1306 | user_ids_ = user_ids -- vector
1307 | }, cb or dl_cb, cmd)
1308 | end
1309 |
1310 | M.addChatMembers = addChatMembers
1311 |
1312 | -- Changes status of the chat member, need appropriate privileges.
1313 | -- In channel chats, user will be added to chat members if he is yet not a member and there is less than 200 members in the channel.
1314 | -- Status will not be changed until chat state will be synchronized with the server.
1315 | -- Status will not be changed if application is killed before it can send request to the server
1316 | -- @chat_id Chat identifier
1317 | -- @user_id Identifier of the user to edit status, bots can be editors in the channel chats
1318 | -- @status New status of the member in the chat
1319 | -- status = Creator|Editor|Moderator|Member|Left|Kicked
1320 | local function changeChatMemberStatus(chat_id, user_id, status, cb, cmd)
1321 | tdcli_function ({
1322 | ID = "ChangeChatMemberStatus",
1323 | chat_id_ = chat_id,
1324 | user_id_ = user_id,
1325 | status_ = {
1326 | ID = "ChatMemberStatus" .. status
1327 | },
1328 | }, cb or dl_cb, cmd)
1329 | end
1330 |
1331 | M.changeChatMemberStatus = changeChatMemberStatus
1332 |
1333 | -- Returns information about one participant of the chat
1334 | -- @chat_id Chat identifier
1335 | -- @user_id User identifier
1336 | local function getChatMember(chat_id, user_id, cb, cmd)
1337 | tdcli_function ({
1338 | ID = "GetChatMember",
1339 | chat_id_ = chat_id,
1340 | user_id_ = user_id
1341 | }, cb or dl_cb, cmd)
1342 | end
1343 |
1344 | M.getChatMember = getChatMember
1345 |
1346 | -- Asynchronously downloads file from cloud.
1347 | -- Updates updateFileProgress will notify about download progress.
1348 | -- Update updateFile will notify about successful download
1349 | -- @file_id Identifier of file to download
1350 | local function downloadFile(file_id, cb, cmd)
1351 | tdcli_function ({
1352 | ID = "DownloadFile",
1353 | file_id_ = file_id
1354 | }, cb or dl_cb, cmd)
1355 | end
1356 |
1357 | M.downloadFile = downloadFile
1358 |
1359 | -- Stops file downloading.
1360 | -- If file already downloaded do nothing.
1361 | -- @file_id Identifier of file to cancel download
1362 | local function cancelDownloadFile(file_id, cb, cmd)
1363 | tdcli_function ({
1364 | ID = "CancelDownloadFile",
1365 | file_id_ = file_id
1366 | }, cb or dl_cb, cmd)
1367 | end
1368 |
1369 | M.cancelDownloadFile = cancelDownloadFile
1370 |
1371 | -- Next part of a file was generated
1372 | -- @generation_id Identifier of the generation process
1373 | -- @ready Number of bytes already generated. Negative number means that generation has failed and should be terminated
1374 | local function setFileGenerationProgress(generation_id, ready, cb, cmd)
1375 | tdcli_function ({
1376 | ID = "SetFileGenerationProgress",
1377 | generation_id_ = generation_id,
1378 | ready_ = ready
1379 | }, cb or dl_cb, cmd)
1380 | end
1381 |
1382 | M.setFileGenerationProgress = setFileGenerationProgress
1383 |
1384 | -- Finishes file generation
1385 | -- @generation_id Identifier of the generation process
1386 | local function finishFileGeneration(generation_id, cb, cmd)
1387 | tdcli_function ({
1388 | ID = "FinishFileGeneration",
1389 | generation_id_ = generation_id
1390 | }, cb or dl_cb, cmd)
1391 | end
1392 |
1393 | M.finishFileGeneration = finishFileGeneration
1394 |
1395 | -- Generates new chat invite link, previously generated link is revoked.
1396 | -- Available for group and channel chats.
1397 | -- Only creator of the chat can export chat invite link
1398 | -- @chat_id Chat identifier
1399 | local function exportChatInviteLink(chat_id, cb, cmd)
1400 | tdcli_function ({
1401 | ID = "ExportChatInviteLink",
1402 | chat_id_ = chat_id
1403 | }, cb or dl_cb, cmd)
1404 | end
1405 |
1406 | M.exportChatInviteLink = exportChatInviteLink
1407 |
1408 | -- Checks chat invite link for validness and returns information about the corresponding chat
1409 | -- @invite_link Invite link to check. Should begin with "https://telegram.me/joinchat/"
1410 | local function checkChatInviteLink(link, cb, cmd)
1411 | tdcli_function ({
1412 | ID = "CheckChatInviteLink",
1413 | invite_link_ = link
1414 | }, cb or dl_cb, cmd)
1415 | end
1416 |
1417 | M.checkChatInviteLink = checkChatInviteLink
1418 |
1419 | -- Imports chat invite link, adds current user to a chat if possible.
1420 | -- Member will not be added until chat state will be synchronized with the server.
1421 | -- Member will not be added if application is killed before it can send request to the server
1422 | -- @invite_link Invite link to import. Should begin with "https://telegram.me/joinchat/"
1423 | local function importChatInviteLink(invite_link, cb, cmd)
1424 | tdcli_function ({
1425 | ID = "ImportChatInviteLink",
1426 | invite_link_ = invite_link
1427 | }, cb or dl_cb, cmd)
1428 | end
1429 |
1430 | M.importChatInviteLink = importChatInviteLink
1431 |
1432 | -- Adds user to black list
1433 | -- @user_id User identifier
1434 | local function blockUser(user_id, cb, cmd)
1435 | tdcli_function ({
1436 | ID = "BlockUser",
1437 | user_id_ = user_id
1438 | }, cb or dl_cb, cmd)
1439 | end
1440 |
1441 | M.blockUser = blockUser
1442 |
1443 | -- Removes user from black list
1444 | -- @user_id User identifier
1445 | local function unblockUser(user_id, cb, cmd)
1446 | tdcli_function ({
1447 | ID = "UnblockUser",
1448 | user_id_ = user_id
1449 | }, cb or dl_cb, cmd)
1450 | end
1451 |
1452 | M.unblockUser = unblockUser
1453 |
1454 | -- Returns users blocked by the current user
1455 | -- @offset Number of users to skip in result, must be non-negative
1456 | -- @limit Maximum number of users to return, can't be greater than 100
1457 | local function getBlockedUsers(offset, limit, cb, cmd)
1458 | tdcli_function ({
1459 | ID = "GetBlockedUsers",
1460 | offset_ = offset,
1461 | limit_ = limit
1462 | }, cb or dl_cb, cmd)
1463 | end
1464 |
1465 | M.getBlockedUsers = getBlockedUsers
1466 |
1467 | -- Adds new contacts/edits existing contacts, contacts user identifiers are ignored.
1468 | -- Returns list of corresponding users in the same order as input contacts.
1469 | -- If contact doesn't registered in Telegram, user with id == 0 will be returned
1470 | -- @contacts List of contacts to import/edit
1471 | local function importContacts(phone_number, first_name, last_name, user_id, cb, cmd)
1472 | tdcli_function ({
1473 | ID = "ImportContacts",
1474 | contacts_ = {[0] = {
1475 | phone_number_ = tostring(phone_number),
1476 | first_name_ = tostring(first_name),
1477 | last_name_ = tostring(last_name),
1478 | user_id_ = user_id
1479 | },
1480 | },
1481 | }, cb or dl_cb, cmd)
1482 | end
1483 |
1484 | M.importContacts = importContacts
1485 |
1486 | -- Searches for specified query in the first name, last name and username of the known user contacts
1487 | -- @query Query to search for, can be empty to return all contacts
1488 | -- @limit Maximum number of users to be returned
1489 | local function searchContacts(query, limit, cb, cmd)
1490 | tdcli_function ({
1491 | ID = "SearchContacts",
1492 | query_ = query,
1493 | limit_ = limit
1494 | }, cb or dl_cb, cmd)
1495 | end
1496 |
1497 | M.searchContacts = searchContacts
1498 |
1499 | -- Deletes users from contacts list
1500 | -- @user_ids Identifiers of users to be deleted
1501 | local function deleteContacts(user_ids, cb, cmd)
1502 | tdcli_function ({
1503 | ID = "DeleteContacts",
1504 | user_ids_ = user_ids -- vector
1505 | }, cb or dl_cb, cmd)
1506 | end
1507 |
1508 | M.deleteContacts = deleteContacts
1509 |
1510 | -- Returns profile photos of the user.
1511 | -- Result of this query can't be invalidated, so it must be used with care
1512 | -- @user_id User identifier
1513 | -- @offset Photos to skip, must be non-negative
1514 | -- @limit Maximum number of photos to be returned, can't be greater than 100
1515 | local function getUserProfilePhotos(user_id, offset, limit, cb, cmd)
1516 | tdcli_function ({
1517 | ID = "GetUserProfilePhotos",
1518 | user_id_ = user_id,
1519 | offset_ = offset,
1520 | limit_ = limit
1521 | }, cb or dl_cb, cmd)
1522 | end
1523 |
1524 | M.getUserProfilePhotos = getUserProfilePhotos
1525 |
1526 | -- Returns stickers corresponding to given emoji
1527 | -- @emoji String representation of emoji. If empty, returns all known stickers
1528 | local function getStickers(emoji, cb, cmd)
1529 | tdcli_function ({
1530 | ID = "GetStickers",
1531 | emoji_ = emoji
1532 | }, cb or dl_cb, cmd)
1533 | end
1534 |
1535 | M.getStickers = getStickers
1536 |
1537 | -- Returns list of installed sticker sets without archived sticker sets
1538 | -- @is_masks Pass true to return masks, pass false to return stickers
1539 | local function getStickerSets(is_masks, cb, cmd)
1540 | tdcli_function ({
1541 | ID = "GetStickerSets",
1542 | is_masks_ = is_masks
1543 | }, cb or dl_cb, cmd)
1544 | end
1545 |
1546 | M.getStickerSets = getStickerSets
1547 |
1548 | -- Returns list of archived sticker sets
1549 | -- @is_masks Pass true to return masks, pass false to return stickers
1550 | -- @offset_sticker_set_id Identifier of the sticker set from which return the result
1551 | -- @limit Maximum number of sticker sets to return
1552 | local function getArchivedStickerSets(is_masks, offset_sticker_set_id, limit, cb, cmd)
1553 | tdcli_function ({
1554 | ID = "GetArchivedStickerSets",
1555 | is_masks_ = is_masks,
1556 | offset_sticker_set_id_ = offset_sticker_set_id,
1557 | limit_ = limit
1558 | }, cb or dl_cb, cmd)
1559 | end
1560 |
1561 | M.getArchivedStickerSets = getArchivedStickerSets
1562 |
1563 | -- Returns list of trending sticker sets
1564 | local function getTrendingStickerSets(dl_cb, cmd)
1565 | tdcli_function ({
1566 | ID = "GetTrendingStickerSets"
1567 | }, cb or dl_cb, cmd)
1568 | end
1569 |
1570 | M.getTrendingStickerSets = getTrendingStickerSets
1571 |
1572 | -- Returns list of sticker sets attached to a file, currently only photos and videos can have attached sticker sets
1573 | -- @file_id File identifier
1574 | local function getAttachedStickerSets(file_id, cb, cmd)
1575 | tdcli_function ({
1576 | ID = "GetAttachedStickerSets",
1577 | file_id_ = file_id
1578 | }, cb or dl_cb, cmd)
1579 | end
1580 |
1581 | M.getAttachedStickerSets = getAttachedStickerSets
1582 |
1583 | -- Returns information about sticker set by its identifier
1584 | -- @set_id Identifier of the sticker set
1585 | local function getStickerSet(set_id, cb, cmd)
1586 | tdcli_function ({
1587 | ID = "GetStickerSet",
1588 | set_id_ = set_id
1589 | }, cb or dl_cb, cmd)
1590 | end
1591 |
1592 | M.getStickerSet = getStickerSet
1593 |
1594 | -- Searches sticker set by its short name
1595 | -- @name Name of the sticker set
1596 | local function searchStickerSet(name, cb, cmd)
1597 | tdcli_function ({
1598 | ID = "SearchStickerSet",
1599 | name_ = name
1600 | }, cb or dl_cb, cmd)
1601 | end
1602 |
1603 | M.searchStickerSet = searchStickerSet
1604 |
1605 | -- Installs/uninstalls or enables/archives sticker set.
1606 | -- Official sticker set can't be uninstalled, but it can be archived
1607 | -- @set_id Identifier of the sticker set
1608 | -- @is_installed New value of is_installed
1609 | -- @is_archived New value of is_archived
1610 | local function updateStickerSet(set_id, is_installed, is_archived, cb, cmd)
1611 | tdcli_function ({
1612 | ID = "UpdateStickerSet",
1613 | set_id_ = set_id,
1614 | is_installed_ = is_installed,
1615 | is_archived_ = is_archived
1616 | }, cb or dl_cb, cmd)
1617 | end
1618 |
1619 | M.updateStickerSet = updateStickerSet
1620 |
1621 | -- Trending sticker sets are viewed by the user
1622 | -- @sticker_set_ids Identifiers of viewed trending sticker sets
1623 | local function viewTrendingStickerSets(sticker_set_ids, cb, cmd)
1624 | tdcli_function ({
1625 | ID = "ViewTrendingStickerSets",
1626 | sticker_set_ids_ = sticker_set_ids -- vector
1627 | }, cb or dl_cb, cmd)
1628 | end
1629 |
1630 | M.viewTrendingStickerSets = viewTrendingStickerSets
1631 |
1632 | -- Changes the order of installed sticker sets
1633 | -- @is_masks Pass true to change masks order, pass false to change stickers order
1634 | -- @sticker_set_ids Identifiers of installed sticker sets in the new right order
1635 | local function reorderStickerSets(is_masks, sticker_set_ids, cb, cmd)
1636 | tdcli_function ({
1637 | ID = "ReorderStickerSets",
1638 | is_masks_ = is_masks,
1639 | sticker_set_ids_ = sticker_set_ids -- vector
1640 | }, cb or dl_cb, cmd)
1641 | end
1642 |
1643 | M.reorderStickerSets = reorderStickerSets
1644 |
1645 | -- Returns list of recently used stickers
1646 | -- @is_attached Pass true to return stickers and masks recently attached to photo or video files, pass false to return recently sent stickers
1647 | local function getRecentStickers(is_attached, cb, cmd)
1648 | tdcli_function ({
1649 | ID = "GetRecentStickers",
1650 | is_attached_ = is_attached
1651 | }, cb or dl_cb, cmd)
1652 | end
1653 |
1654 | M.getRecentStickers = getRecentStickers
1655 |
1656 | -- Manually adds new sticker to the list of recently used stickers.
1657 | -- New sticker is added to the beginning of the list.
1658 | -- If the sticker is already in the list, at first it is removed from the list
1659 | -- @is_attached Pass true to add the sticker to the list of stickers recently attached to photo or video files, pass false to add the sticker to the list of recently sent stickers
1660 | -- @sticker Sticker file to add
1661 | local function addRecentSticker(is_attached, sticker, cb, cmd)
1662 | tdcli_function ({
1663 | ID = "AddRecentSticker",
1664 | is_attached_ = is_attached,
1665 | sticker_ = getInputFile(sticker)
1666 | }, cb or dl_cb, cmd)
1667 | end
1668 |
1669 | M.addRecentSticker = addRecentSticker
1670 |
1671 | -- Removes a sticker from the list of recently used stickers
1672 | -- @is_attached Pass true to remove the sticker from the list of stickers recently attached to photo or video files, pass false to remove the sticker from the list of recently sent stickers
1673 | -- @sticker Sticker file to delete
1674 | local function deleteRecentSticker(is_attached, sticker, cb, cmd)
1675 | tdcli_function ({
1676 | ID = "DeleteRecentSticker",
1677 | is_attached_ = is_attached,
1678 | sticker_ = getInputFile(sticker)
1679 | }, cb or dl_cb, cmd)
1680 | end
1681 |
1682 | M.deleteRecentSticker = deleteRecentSticker
1683 |
1684 | -- Clears list of recently used stickers
1685 | -- @is_attached Pass true to clear list of stickers recently attached to photo or video files, pass false to clear the list of recently sent stickers
1686 | local function clearRecentStickers(is_attached, cb, cmd)
1687 | tdcli_function ({
1688 | ID = "ClearRecentStickers",
1689 | is_attached_ = is_attached
1690 | }, cb or dl_cb, cmd)
1691 | end
1692 |
1693 | M.clearRecentStickers = clearRecentStickers
1694 |
1695 | -- Returns emojis corresponding to a sticker
1696 | -- @sticker Sticker file identifier
1697 | local function getStickerEmojis(sticker, cb, cmd)
1698 | tdcli_function ({
1699 | ID = "GetStickerEmojis",
1700 | sticker_ = getInputFile(sticker)
1701 | }, cb or dl_cb, cmd)
1702 | end
1703 |
1704 | M.getStickerEmojis = getStickerEmojis
1705 |
1706 | -- Returns saved animations
1707 | local function getSavedAnimations(dl_cb, cmd)
1708 | tdcli_function ({
1709 | ID = "GetSavedAnimations",
1710 | }, cb or dl_cb, cmd)
1711 | end
1712 |
1713 | M.getSavedAnimations = getSavedAnimations
1714 |
1715 | -- Manually adds new animation to the list of saved animations.
1716 | -- New animation is added to the beginning of the list.
1717 | -- If the animation is already in the list, at first it is removed from the list.
1718 | -- Only non-secret video animations with MIME type "video/mp4" can be added to the list
1719 | -- @animation Animation file to add. Only known to server animations (i. e. successfully sent via message) can be added to the list
1720 | local function addSavedAnimation(animation, cb, cmd)
1721 | tdcli_function ({
1722 | ID = "AddSavedAnimation",
1723 | animation_ = getInputFile(animation)
1724 | }, cb or dl_cb, cmd)
1725 | end
1726 |
1727 | M.addSavedAnimation = addSavedAnimation
1728 |
1729 | -- Removes animation from the list of saved animations
1730 | -- @animation Animation file to delete
1731 | local function deleteSavedAnimation(animation, cb, cmd)
1732 | tdcli_function ({
1733 | ID = "DeleteSavedAnimation",
1734 | animation_ = getInputFile(animation)
1735 | }, cb or dl_cb, cmd)
1736 | end
1737 |
1738 | M.deleteSavedAnimation = deleteSavedAnimation
1739 |
1740 | -- Returns up to 20 recently used inline bots in the order of the last usage
1741 | local function getRecentInlineBots(dl_cb, cmd)
1742 | tdcli_function ({
1743 | ID = "GetRecentInlineBots",
1744 | }, cb or dl_cb, cmd)
1745 | end
1746 |
1747 | M.getRecentInlineBots = getRecentInlineBots
1748 |
1749 | -- Get web page preview by text of the message.
1750 | -- Do not call this function to often
1751 | -- @message_text Message text
1752 | local function getWebPagePreview(message_text, cb, cmd)
1753 | tdcli_function ({
1754 | ID = "GetWebPagePreview",
1755 | message_text_ = message_text
1756 | }, cb or dl_cb, cmd)
1757 | end
1758 |
1759 | M.getWebPagePreview = getWebPagePreview
1760 |
1761 | -- Returns notification settings for a given scope
1762 | -- @scope Scope to return information about notification settings
1763 | -- scope = Chat(chat_id)|PrivateChats|GroupChats|AllChats|
1764 | local function getNotificationSettings(scope, chat_id, cb, cmd)
1765 | tdcli_function ({
1766 | ID = "GetNotificationSettings",
1767 | scope_ = {
1768 | ID = 'NotificationSettingsFor' .. scope,
1769 | chat_id_ = chat_id or nil
1770 | },
1771 | }, cb or dl_cb, cmd)
1772 | end
1773 |
1774 | M.getNotificationSettings = getNotificationSettings
1775 |
1776 | -- Changes notification settings for a given scope
1777 | -- @scope Scope to change notification settings
1778 | -- @notification_settings New notification settings for given scope
1779 | -- scope = Chat(chat_id)|PrivateChats|GroupChats|AllChats|
1780 | local function setNotificationSettings(scope, chat_id, mute_for, show_preview, cb, cmd)
1781 | tdcli_function ({
1782 | ID = "SetNotificationSettings",
1783 | scope_ = {
1784 | ID = 'NotificationSettingsFor' .. scope,
1785 | chat_id_ = chat_id or nil
1786 | },
1787 | notification_settings_ = {
1788 | ID = "NotificationSettings",
1789 | mute_for_ = mute_for,
1790 | sound_ = "default",
1791 | show_preview_ = show_preview
1792 | }
1793 | }, cb or dl_cb, cmd)
1794 | end
1795 |
1796 | M.setNotificationSettings = setNotificationSettings
1797 |
1798 | -- Resets all notification settings to the default value.
1799 | -- By default the only muted chats are supergroups, sound is set to 'default' and message previews are showed
1800 | local function resetAllNotificationSettings(dl_cb, cmd)
1801 | tdcli_function ({
1802 | ID = "ResetAllNotificationSettings"
1803 | }, cb or dl_cb, cmd)
1804 | end
1805 |
1806 | M.resetAllNotificationSettings = resetAllNotificationSettings
1807 |
1808 | -- Uploads new profile photo for logged in user.
1809 | -- Photo will not change until change will be synchronized with the server.
1810 | -- Photo will not be changed if application is killed before it can send request to the server.
1811 | -- If something changes, updateUser will be sent
1812 | -- @photo_path Path to new profile photo
1813 | local function setProfilePhoto(photo_path, cb, cmd)
1814 | tdcli_function ({
1815 | ID = "SetProfilePhoto",
1816 | photo_path_ = photo_path
1817 | }, cb or dl_cb, cmd)
1818 | end
1819 |
1820 | M.setProfilePhoto = setProfilePhoto
1821 |
1822 | -- Deletes profile photo.
1823 | -- If something changes, updateUser will be sent
1824 | -- @profile_photo_id Identifier of profile photo to delete
1825 | local function deleteProfilePhoto(profile_photo_id, cb, cmd)
1826 | tdcli_function ({
1827 | ID = "DeleteProfilePhoto",
1828 | profile_photo_id_ = profile_photo_id
1829 | }, cb or dl_cb, cmd)
1830 | end
1831 |
1832 | M.deleteProfilePhoto = deleteProfilePhoto
1833 |
1834 | -- Changes first and last names of logged in user.
1835 | -- If something changes, updateUser will be sent
1836 | -- @first_name New value of user first name, 1-255 characters
1837 | -- @last_name New value of optional user last name, 0-255 characters
1838 | local function changeName(first_name, last_name, cb, cmd)
1839 | tdcli_function ({
1840 | ID = "ChangeName",
1841 | first_name_ = first_name,
1842 | last_name_ = last_name
1843 | }, cb or dl_cb, cmd)
1844 | end
1845 |
1846 | M.changeName = changeName
1847 |
1848 | -- Changes about information of logged in user
1849 | -- @about New value of userFull.about, 0-255 characters
1850 | local function changeAbout(about, cb, cmd)
1851 | tdcli_function ({
1852 | ID = "ChangeAbout",
1853 | about_ = about
1854 | }, cb or dl_cb, cmd)
1855 | end
1856 |
1857 | M.changeAbout = changeAbout
1858 |
1859 | -- Changes username of logged in user.
1860 | -- If something changes, updateUser will be sent
1861 | -- @username New value of username. Use empty string to remove username
1862 | local function changeUsername(username, cb, cmd)
1863 | tdcli_function ({
1864 | ID = "ChangeUsername",
1865 | username_ = username
1866 | }, cb or dl_cb, cmd)
1867 | end
1868 |
1869 | M.changeUsername = changeUsername
1870 |
1871 | -- Changes user's phone number and sends authentication code to the new user's phone number.
1872 | -- Returns authStateWaitCode with information about sent code on success
1873 | -- @phone_number New user's phone number in any reasonable format
1874 | -- @allow_flash_call Pass True, if code can be sent via flash call to the specified phone number
1875 | -- @is_current_phone_number Pass true, if the phone number is used on the current device. Ignored if allow_flash_call is False
1876 | local function changePhoneNumber(phone_number, allow_flash_call, is_current_phone_number, cb, cmd)
1877 | tdcli_function ({
1878 | ID = "ChangePhoneNumber",
1879 | phone_number_ = phone_number,
1880 | allow_flash_call_ = allow_flash_call,
1881 | is_current_phone_number_ = is_current_phone_number
1882 | }, cb or dl_cb, cmd)
1883 | end
1884 |
1885 | M.changePhoneNumber = changePhoneNumber
1886 |
1887 | -- Resends authentication code sent to change user's phone number.
1888 | -- Works only if in previously received authStateWaitCode next_code_type was not null.
1889 | -- Returns authStateWaitCode on success
1890 | local function resendChangePhoneNumberCode(dl_cb, cmd)
1891 | tdcli_function ({
1892 | ID = "ResendChangePhoneNumberCode",
1893 | }, cb or dl_cb, cmd)
1894 | end
1895 |
1896 | M.resendChangePhoneNumberCode = resendChangePhoneNumberCode
1897 |
1898 | -- Checks authentication code sent to change user's phone number.
1899 | -- Returns authStateOk on success
1900 | -- @code Verification code from SMS, voice call or flash call
1901 | local function checkChangePhoneNumberCode(code, cb, cmd)
1902 | tdcli_function ({
1903 | ID = "CheckChangePhoneNumberCode",
1904 | code_ = code
1905 | }, cb or dl_cb, cmd)
1906 | end
1907 |
1908 | M.checkChangePhoneNumberCode = checkChangePhoneNumberCode
1909 |
1910 | -- Returns all active sessions of logged in user
1911 | local function getActiveSessions(dl_cb, cmd)
1912 | tdcli_function ({
1913 | ID = "GetActiveSessions",
1914 | }, cb or dl_cb, cmd)
1915 | end
1916 |
1917 | M.getActiveSessions = getActiveSessions
1918 |
1919 | -- Terminates another session of logged in user
1920 | -- @session_id Session identifier
1921 | local function terminateSession(session_id, cb, cmd)
1922 | tdcli_function ({
1923 | ID = "TerminateSession",
1924 | session_id_ = session_id
1925 | }, cb or dl_cb, cmd)
1926 | end
1927 |
1928 | M.terminateSession = terminateSession
1929 |
1930 | -- Terminates all other sessions of logged in user
1931 | local function terminateAllOtherSessions(dl_cb, cmd)
1932 | tdcli_function ({
1933 | ID = "TerminateAllOtherSessions",
1934 | }, cb or dl_cb, cmd)
1935 | end
1936 |
1937 | M.terminateAllOtherSessions = terminateAllOtherSessions
1938 |
1939 | -- Gives or revokes all members of the group editor rights.
1940 | -- Needs creator privileges in the group
1941 | -- @group_id Identifier of the group
1942 | -- @anyone_can_edit New value of anyone_can_edit
1943 | local function toggleGroupEditors(group_id, anyone_can_edit, cb, cmd)
1944 | tdcli_function ({
1945 | ID = "ToggleGroupEditors",
1946 | group_id_ = getChatId(group_id).ID,
1947 | anyone_can_edit_ = anyone_can_edit
1948 | }, cb or dl_cb, cmd)
1949 | end
1950 |
1951 | M.toggleGroupEditors = toggleGroupEditors
1952 |
1953 | -- Changes username of the channel.
1954 | -- Needs creator privileges in the channel
1955 | -- @channel_id Identifier of the channel
1956 | -- @username New value of username. Use empty string to remove username
1957 | local function changeChannelUsername(channel_id, username, cb, cmd)
1958 | tdcli_function ({
1959 | ID = "ChangeChannelUsername",
1960 | channel_id_ = getChatId(channel_id).ID,
1961 | username_ = username
1962 | }, cb or dl_cb, cmd)
1963 | end
1964 |
1965 | M.changeChannelUsername = changeChannelUsername
1966 |
1967 | -- Gives or revokes right to invite new members to all current members of the channel.
1968 | -- Needs creator privileges in the channel.
1969 | -- Available only for supergroups
1970 | -- @channel_id Identifier of the channel
1971 | -- @anyone_can_invite New value of anyone_can_invite
1972 | local function toggleChannelInvites(channel_id, anyone_can_invite, cb, cmd)
1973 | tdcli_function ({
1974 | ID = "ToggleChannelInvites",
1975 | channel_id_ = getChatId(channel_id).ID,
1976 | anyone_can_invite_ = anyone_can_invite
1977 | }, cb or dl_cb, cmd)
1978 | end
1979 |
1980 | M.toggleChannelInvites = toggleChannelInvites
1981 |
1982 | -- Enables or disables sender signature on sent messages in the channel.
1983 | -- Needs creator privileges in the channel.
1984 | -- Not available for supergroups
1985 | -- @channel_id Identifier of the channel
1986 | -- @sign_messages New value of sign_messages
1987 | local function toggleChannelSignMessages(channel_id, sign_messages, cb, cmd)
1988 | tdcli_function ({
1989 | ID = "ToggleChannelSignMessages",
1990 | channel_id_ = getChatId(channel_id).ID,
1991 | sign_messages_ = sign_messages
1992 | }, cb or dl_cb, cmd)
1993 | end
1994 |
1995 | M.toggleChannelSignMessages = toggleChannelSignMessages
1996 |
1997 | -- Changes information about the channel.
1998 | -- Needs creator privileges in the broadcast channel or editor privileges in the supergroup channel
1999 | -- @channel_id Identifier of the channel
2000 | -- @about New value of about, 0-255 characters
2001 | local function changeChannelAbout(channel_id, about, cb, cmd)
2002 | tdcli_function ({
2003 | ID = "ChangeChannelAbout",
2004 | channel_id_ = getChatId(channel_id).ID,
2005 | about_ = about
2006 | }, cb or dl_cb, cmd)
2007 | end
2008 |
2009 | M.changeChannelAbout = changeChannelAbout
2010 |
2011 | -- Pins a message in a supergroup channel chat.
2012 | -- Needs editor privileges in the channel
2013 | -- @channel_id Identifier of the channel
2014 | -- @message_id Identifier of the new pinned message
2015 | -- @disable_notification True, if there should be no notification about the pinned message
2016 | local function pinChannelMessage(channel_id, message_id, disable_notification, cb, cmd)
2017 | tdcli_function ({
2018 | ID = "PinChannelMessage",
2019 | channel_id_ = getChatId(channel_id).ID,
2020 | message_id_ = message_id,
2021 | disable_notification_ = disable_notification
2022 | }, cb or dl_cb, cmd)
2023 | end
2024 |
2025 | M.pinChannelMessage = pinChannelMessage
2026 |
2027 | -- Removes pinned message in the supergroup channel.
2028 | -- Needs editor privileges in the channel
2029 | -- @channel_id Identifier of the channel
2030 | local function unpinChannelMessage(channel_id, cb, cmd)
2031 | tdcli_function ({
2032 | ID = "UnpinChannelMessage",
2033 | channel_id_ = getChatId(channel_id).ID
2034 | }, cb or dl_cb, cmd)
2035 | end
2036 |
2037 | M.unpinChannelMessage = unpinChannelMessage
2038 |
2039 | -- Reports some supergroup channel messages from a user as spam messages
2040 | -- @channel_id Channel identifier
2041 | -- @user_id User identifier
2042 | -- @message_ids Identifiers of messages sent in the supergroup by the user, the list should be non-empty
2043 | local function reportChannelSpam(channel_id, user_id, message_ids, cb, cmd)
2044 | tdcli_function ({
2045 | ID = "ReportChannelSpam",
2046 | channel_id_ = getChatId(channel_id).ID,
2047 | user_id_ = user_id,
2048 | message_ids_ = message_ids -- vector
2049 | }, cb or dl_cb, cmd)
2050 | end
2051 |
2052 | M.reportChannelSpam = reportChannelSpam
2053 |
2054 | -- Returns information about channel members or kicked from channel users.
2055 | -- Can be used only if channel_full->can_get_members == true
2056 | -- @channel_id Identifier of the channel
2057 | -- @filter Kind of channel users to return, defaults to channelMembersRecent
2058 | -- @offset Number of channel users to skip
2059 | -- @limit Maximum number of users be returned, can't be greater than 200
2060 | -- filter = Recent|Administrators|Kicked|Bots
2061 | local function getChannelMembers(channel_id, offset, filter, limit, cb, cmd)
2062 | if not limit or limit > 200 then
2063 | limit = 200
2064 | end
2065 |
2066 | tdcli_function ({
2067 | ID = "GetChannelMembers",
2068 | channel_id_ = getChatId(channel_id).ID,
2069 | filter_ = {
2070 | ID = "ChannelMembers" .. filter
2071 | },
2072 | offset_ = offset,
2073 | limit_ = limit
2074 | }, cb or dl_cb, cmd)
2075 | end
2076 |
2077 | M.getChannelMembers = getChannelMembers
2078 |
2079 | -- Deletes channel along with all messages in corresponding chat.
2080 | -- Releases channel username and removes all members.
2081 | -- Needs creator privileges in the channel.
2082 | -- Channels with more than 1000 members can't be deleted
2083 | -- @channel_id Identifier of the channel
2084 | local function deleteChannel(channel_id, cb, cmd)
2085 | tdcli_function ({
2086 | ID = "DeleteChannel",
2087 | channel_id_ = getChatId(channel_id).ID
2088 | }, cb or dl_cb, cmd)
2089 | end
2090 |
2091 | M.deleteChannel = deleteChannel
2092 |
2093 | -- Returns list of created public channels
2094 | local function getCreatedPublicChannels(dl_cb, cmd)
2095 | tdcli_function ({
2096 | ID = "GetCreatedPublicChannels"
2097 | }, cb or dl_cb, cmd)
2098 | end
2099 |
2100 | M.getCreatedPublicChannels = getCreatedPublicChannels
2101 |
2102 | -- Closes secret chat
2103 | -- @secret_chat_id Secret chat identifier
2104 | local function closeSecretChat(secret_chat_id, cb, cmd)
2105 | tdcli_function ({
2106 | ID = "CloseSecretChat",
2107 | secret_chat_id_ = secret_chat_id
2108 | }, cb or dl_cb, cmd)
2109 | end
2110 |
2111 | M.closeSecretChat = closeSecretChat
2112 |
2113 | -- Returns user that can be contacted to get support
2114 | local function getSupportUser(dl_cb, cmd)
2115 | tdcli_function ({
2116 | ID = "GetSupportUser",
2117 | }, cb or dl_cb, cmd)
2118 | end
2119 |
2120 | M.getSupportUser = getSupportUser
2121 |
2122 | -- Returns background wallpapers
2123 | local function getWallpapers(dl_cb, cmd)
2124 | tdcli_function ({
2125 | ID = "GetWallpapers",
2126 | }, cb or dl_cb, cmd)
2127 | end
2128 |
2129 | M.getWallpapers = getWallpapers
2130 |
2131 | -- Registers current used device for receiving push notifications
2132 | -- @device_token Device token
2133 | -- device_token = apns|gcm|mpns|simplePush|ubuntuPhone|blackberry
2134 | local function registerDevice(device_token, token, device_token_set, cb, cmd)
2135 | local dToken = {ID = device_token .. 'DeviceToken', token_ = token}
2136 |
2137 | if device_token_set then
2138 | dToken = {ID = "DeviceTokenSet", token_ = device_token_set} -- tokens:vector
2139 | end
2140 |
2141 | tdcli_function ({
2142 | ID = "RegisterDevice",
2143 | device_token_ = dToken
2144 | }, cb or dl_cb, cmd)
2145 | end
2146 |
2147 | M.registerDevice = registerDevice
2148 |
2149 | -- Returns list of used device tokens
2150 | local function getDeviceTokens(dl_cb, cmd)
2151 | tdcli_function ({
2152 | ID = "GetDeviceTokens",
2153 | }, cb or dl_cb, cmd)
2154 | end
2155 |
2156 | M.getDeviceTokens = getDeviceTokens
2157 |
2158 | -- Changes privacy settings
2159 | -- @key Privacy key
2160 | -- @rules New privacy rules
2161 | -- @privacyKeyUserStatus Privacy key for managing visibility of the user status
2162 | -- @privacyKeyChatInvite Privacy key for managing ability of invitation of the user to chats
2163 | -- @privacyRuleAllowAll Rule to allow all users
2164 | -- @privacyRuleAllowContacts Rule to allow all user contacts
2165 | -- @privacyRuleAllowUsers Rule to allow specified users
2166 | -- @user_ids User identifiers
2167 | -- @privacyRuleDisallowAll Rule to disallow all users
2168 | -- @privacyRuleDisallowContacts Rule to disallow all user contacts
2169 | -- @privacyRuleDisallowUsers Rule to disallow all specified users
2170 | -- key = UserStatus|ChatInvite
2171 | -- rules = AllowAll|AllowContacts|AllowUsers(user_ids)|DisallowAll|DisallowContacts|DisallowUsers(user_ids)
2172 | local function setPrivacy(key, rule, allowed_user_ids, disallowed_user_ids, cb, cmd)
2173 | local rules = {[0] = {ID = 'PrivacyRule' .. rule}}
2174 |
2175 | if allowed_user_ids then
2176 | rules = {
2177 | {
2178 | ID = 'PrivacyRule' .. rule
2179 | },
2180 | [0] = {
2181 | ID = "PrivacyRuleAllowUsers",
2182 | user_ids_ = allowed_user_ids -- vector
2183 | },
2184 | }
2185 | end
2186 | if disallowed_user_ids then
2187 | rules = {
2188 | {
2189 | ID = 'PrivacyRule' .. rule
2190 | },
2191 | [0] = {
2192 | ID = "PrivacyRuleDisallowUsers",
2193 | user_ids_ = disallowed_user_ids -- vector
2194 | },
2195 | }
2196 | end
2197 | if allowed_user_ids and disallowed_user_ids then
2198 | rules = {
2199 | {
2200 | ID = 'PrivacyRule' .. rule
2201 | },
2202 | {
2203 | ID = "PrivacyRuleAllowUsers",
2204 | user_ids_ = allowed_user_ids
2205 | },
2206 | [0] = {
2207 | ID = "PrivacyRuleDisallowUsers",
2208 | user_ids_ = disallowed_user_ids
2209 | },
2210 | }
2211 | end
2212 | tdcli_function ({
2213 | ID = "SetPrivacy",
2214 | key_ = {
2215 | ID = 'PrivacyKey' .. key
2216 | },
2217 | rules_ = {
2218 | ID = "PrivacyRules",
2219 | rules_ = rules
2220 | },
2221 | }, cb or dl_cb, cmd)
2222 | end
2223 |
2224 | M.setPrivacy = setPrivacy
2225 |
2226 | -- Returns current privacy settings
2227 | -- @key Privacy key
2228 | -- key = UserStatus|ChatInvite
2229 | local function getPrivacy(key, cb, cmd)
2230 | tdcli_function ({
2231 | ID = "GetPrivacy",
2232 | key_ = {
2233 | ID = "PrivacyKey" .. key
2234 | },
2235 | }, cb or dl_cb, cmd)
2236 | end
2237 |
2238 | M.getPrivacy = getPrivacy
2239 |
2240 | -- Returns value of an option by its name.
2241 | -- See list of available options on https://core.telegram.org/tdlib/options
2242 | -- @name Name of the option
2243 | local function getOption(name, cb, cmd)
2244 | tdcli_function ({
2245 | ID = "GetOption",
2246 | name_ = name
2247 | }, cb or dl_cb, cmd)
2248 | end
2249 |
2250 | M.getOption = getOption
2251 |
2252 | -- Sets value of an option.
2253 | -- See list of available options on https://core.telegram.org/tdlib/options.
2254 | -- Only writable options can be set
2255 | -- @name Name of the option
2256 | -- @value New value of the option
2257 | local function setOption(name, option, value, cb, cmd)
2258 | tdcli_function ({
2259 | ID = "SetOption",
2260 | name_ = name,
2261 | value_ = {
2262 | ID = 'Option' .. option,
2263 | value_ = value
2264 | },
2265 | }, cb or dl_cb, cmd)
2266 | end
2267 |
2268 | M.setOption = setOption
2269 |
2270 | -- Changes period of inactivity, after which the account of currently logged in user will be automatically deleted
2271 | -- @ttl New account TTL
2272 | local function changeAccountTtl(days, cb, cmd)
2273 | tdcli_function ({
2274 | ID = "ChangeAccountTtl",
2275 | ttl_ = {
2276 | ID = "AccountTtl",
2277 | days_ = days
2278 | },
2279 | }, cb or dl_cb, cmd)
2280 | end
2281 |
2282 | M.changeAccountTtl = changeAccountTtl
2283 |
2284 | -- Returns period of inactivity, after which the account of currently logged in user will be automatically deleted
2285 | local function getAccountTtl(dl_cb, cmd)
2286 | tdcli_function ({
2287 | ID = "GetAccountTtl",
2288 | }, cb or dl_cb, cmd)
2289 | end
2290 |
2291 | M.getAccountTtl = getAccountTtl
2292 |
2293 | -- Deletes the account of currently logged in user, deleting from the server all information associated with it.
2294 | -- Account's phone number can be used to create new account, but only once in two weeks
2295 | -- @reason Optional reason of account deletion
2296 | local function deleteAccount(reason, cb, cmd)
2297 | tdcli_function ({
2298 | ID = "DeleteAccount",
2299 | reason_ = reason
2300 | }, cb or dl_cb, cmd)
2301 | end
2302 |
2303 | M.deleteAccount = deleteAccount
2304 |
2305 | -- Returns current chat report spam state
2306 | -- @chat_id Chat identifier
2307 | local function getChatReportSpamState(chat_id, cb, cmd)
2308 | tdcli_function ({
2309 | ID = "GetChatReportSpamState",
2310 | chat_id_ = chat_id
2311 | }, cb or dl_cb, cmd)
2312 | end
2313 |
2314 | M.getChatReportSpamState = getChatReportSpamState
2315 |
2316 | -- Reports chat as a spam chat or as not a spam chat.
2317 | -- Can be used only if ChatReportSpamState.can_report_spam is true.
2318 | -- After this request ChatReportSpamState.can_report_spam became false forever
2319 | -- @chat_id Chat identifier
2320 | -- @is_spam_chat If true, chat will be reported as a spam chat, otherwise it will be marked as not a spam chat
2321 | local function changeChatReportSpamState(chat_id, is_spam_chat, cb, cmd)
2322 | tdcli_function ({
2323 | ID = "ChangeChatReportSpamState",
2324 | chat_id_ = chat_id,
2325 | is_spam_chat_ = is_spam_chat
2326 | }, cb or dl_cb, cmd)
2327 | end
2328 |
2329 | M.changeChatReportSpamState = changeChatReportSpamState
2330 |
2331 | -- Bots only.
2332 | -- Informs server about number of pending bot updates if they aren't processed for a long time
2333 | -- @pending_update_count Number of pending updates
2334 | -- @error_message Last error's message
2335 | local function setBotUpdatesStatus(pending_update_count, error_message, cb, cmd)
2336 | tdcli_function ({
2337 | ID = "SetBotUpdatesStatus",
2338 | pending_update_count_ = pending_update_count,
2339 | error_message_ = error_message
2340 | }, cb or dl_cb, cmd)
2341 | end
2342 |
2343 | M.setBotUpdatesStatus = setBotUpdatesStatus
2344 |
2345 | -- Returns Ok after specified amount of the time passed
2346 | -- @seconds Number of seconds before that function returns
2347 | local function setAlarm(seconds, cb, cmd)
2348 | tdcli_function ({
2349 | ID = "SetAlarm",
2350 | seconds_ = seconds
2351 | }, cb or dl_cb, cmd)
2352 | end
2353 |
2354 | M.setAlarm = setAlarm
2355 |
2356 | -- Text message
2357 | -- @text Text to send
2358 | -- @disable_notification Pass true, to disable notification about the message, doesn't works in secret chats
2359 | -- @from_background Pass true, if the message is sent from background
2360 | -- @reply_markup Bots only. Markup for replying to message
2361 | -- @disable_web_page_preview Pass true to disable rich preview for link in the message text
2362 | -- @clear_draft Pass true if chat draft message should be deleted
2363 | -- @entities Bold, Italic, Code, Pre, PreCode and TextUrl entities contained in the text. Non-bot users can't use TextUrl entities. Can't be used with non-null parse_mode
2364 | -- @parse_mode Text parse mode, nullable. Can't be used along with enitities
2365 | --[[local function sendText(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, text, disable_web_page_preview, parse_mode, cb, cmd)
2366 | local TextParseMode = getParseMode(parse_mode)
2367 | local input_message_content = {
2368 | ID = "InputMessageText",
2369 | text_ = text,
2370 | disable_web_page_preview_ = disable_web_page_preview,
2371 | clear_draft_ = 0,
2372 | entities_ = {},
2373 | parse_mode_ = TextParseMode,
2374 | }
2375 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2376 | end
2377 |
2378 | M.sendText = sendText
2379 | ]]
2380 | local function sendMessage(chat_id, reply_to_message_id, disable_notification, text, disable_web_page_preview, parse_mode)
2381 | local TextParseMode = getParseMode(parse_mode)
2382 | local tt = db:get('endmsg') or ''
2383 | tdcli_function ({
2384 | ID = "SendMessage",
2385 | chat_id_ = chat_id,
2386 | reply_to_message_id_ = reply_to_message_id,
2387 | disable_notification_ = disable_notification,
2388 | from_background_ = 1,
2389 | reply_markup_ = nil,
2390 | input_message_content_ = {
2391 | ID = "InputMessageText",
2392 | text_ = text..'\n\n'..tt,
2393 | disable_web_page_preview_ = disable_web_page_preview,
2394 | clear_draft_ = 0,
2395 | entities_ = {},
2396 | parse_mode_ = TextParseMode,
2397 | },
2398 | }, dl_cb, extra)
2399 | end
2400 |
2401 | M.sendMessage = sendMessage
2402 | -- Animation message
2403 | -- @animation Animation file to send
2404 | -- @thumb Animation thumb, if available
2405 | -- @width Width of the animation, may be replaced by the server
2406 | -- @height Height of the animation, may be replaced by the server
2407 | -- @caption Animation caption, 0-200 characters
2408 | local function sendAnimation(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, animation, width, height, caption, cb, cmd)
2409 | local input_message_content = {
2410 | ID = "InputMessageAnimation",
2411 | animation_ = getInputFile(animation),
2412 | width_ = 0,
2413 | height_ = 0,
2414 | caption_ = caption
2415 | }
2416 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2417 | end
2418 |
2419 | M.sendAnimation = sendAnimation
2420 |
2421 | -- Audio message
2422 | -- @audio Audio file to send
2423 | -- @album_cover_thumb Thumb of the album's cover, if available
2424 | -- @duration Duration of audio in seconds, may be replaced by the server
2425 | -- @title Title of the audio, 0-64 characters, may be replaced by the server
2426 | -- @performer Performer of the audio, 0-64 characters, may be replaced by the server
2427 | -- @caption Audio caption, 0-200 characters
2428 | local function sendAudio(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, audio, duration, title, performer, caption, cb, cmd)
2429 | local input_message_content = {
2430 | ID = "InputMessageAudio",
2431 | audio_ = getInputFile(audio),
2432 | duration_ = duration or 0,
2433 | title_ = title or 0,
2434 | performer_ = performer,
2435 | caption_ = caption
2436 | }
2437 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2438 | end
2439 |
2440 | M.sendAudio = sendAudio
2441 |
2442 | -- Document message
2443 | -- @document Document to send
2444 | -- @thumb Document thumb, if available
2445 | -- @caption Document caption, 0-200 characters
2446 | local function sendDocument(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, document, caption, cb, cmd)
2447 | local input_message_content = {
2448 | ID = "InputMessageDocument",
2449 | document_ = getInputFile(document),
2450 | caption_ = caption
2451 | }
2452 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2453 | end
2454 |
2455 | M.sendDocument = sendDocument
2456 |
2457 | -- Photo message
2458 | -- @photo Photo to send
2459 | -- @caption Photo caption, 0-200 characters
2460 | local function sendPhoto(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, photo, caption, cb, cmd)
2461 | local input_message_content = {
2462 | ID = "InputMessagePhoto",
2463 | photo_ = getInputFile(photo),
2464 | added_sticker_file_ids_ = {},
2465 | width_ = 0,
2466 | height_ = 0,
2467 | caption_ = caption
2468 | }
2469 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2470 | end
2471 |
2472 | M.sendPhoto = sendPhoto
2473 |
2474 | -- Sticker message
2475 | -- @sticker Sticker to send
2476 | -- @thumb Sticker thumb, if available
2477 | local function sendSticker(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, sticker, cb, cmd)
2478 | local input_message_content = {
2479 | ID = "InputMessageSticker",
2480 | sticker_ = getInputFile(sticker),
2481 | width_ = 0,
2482 | height_ = 0
2483 | }
2484 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2485 | end
2486 |
2487 | M.sendSticker = sendSticker
2488 |
2489 | -- Video message
2490 | -- @video Video to send
2491 | -- @thumb Video thumb, if available
2492 | -- @duration Duration of video in seconds
2493 | -- @width Video width
2494 | -- @height Video height
2495 | -- @caption Video caption, 0-200 characters
2496 | local function sendVideo(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, video, duration, width, height, caption, cb, cmd)
2497 | local input_message_content = {
2498 | ID = "InputMessageVideo",
2499 | video_ = getInputFile(video),
2500 | added_sticker_file_ids_ = {},
2501 | duration_ = duration or 0,
2502 | width_ = width or 0,
2503 | height_ = height or 0,
2504 | caption_ = caption
2505 | }
2506 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2507 | end
2508 |
2509 | M.sendVideo = sendVideo
2510 |
2511 | -- Voice message
2512 | -- @voice Voice file to send
2513 | -- @duration Duration of voice in seconds
2514 | -- @waveform Waveform representation of the voice in 5-bit format
2515 | -- @caption Voice caption, 0-200 characters
2516 | local function sendVoice(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, voice, duration, waveform, caption, cb, cmd)
2517 | local input_message_content = {
2518 | ID = "InputMessageVoice",
2519 | voice_ = getInputFile(voice),
2520 | duration_ = duration or 0,
2521 | waveform_ = waveform,
2522 | caption_ = caption
2523 | }
2524 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2525 | end
2526 |
2527 | M.sendVoice = sendVoice
2528 |
2529 | -- Message with location
2530 | -- @latitude Latitude of location in degrees as defined by sender
2531 | -- @longitude Longitude of location in degrees as defined by sender
2532 | local function sendLocation(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, latitude, longitude, cb, cmd)
2533 | local input_message_content = {
2534 | ID = "InputMessageLocation",
2535 | location_ = {
2536 | ID = "Location",
2537 | latitude_ = latitude,
2538 | longitude_ = longitude
2539 | },
2540 | }
2541 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2542 | end
2543 |
2544 | M.sendLocation = sendLocation
2545 |
2546 | -- Message with information about venue
2547 | -- @venue Venue to send
2548 | -- @latitude Latitude of location in degrees as defined by sender
2549 | -- @longitude Longitude of location in degrees as defined by sender
2550 | -- @title Venue name as defined by sender
2551 | -- @address Venue address as defined by sender
2552 | -- @provider Provider of venue database as defined by sender. Only "foursquare" need to be supported currently
2553 | -- @id Identifier of the venue in provider database as defined by sender
2554 | local function sendVenue(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, latitude, longitude, title, address, id, cb, cmd)
2555 | local input_message_content = {
2556 | ID = "InputMessageVenue",
2557 | venue_ = {
2558 | ID = "Venue",
2559 | location_ = {
2560 | ID = "Location",
2561 | latitude_ = latitude,
2562 | longitude_ = longitude
2563 | },
2564 | title_ = title,
2565 | address_ = address,
2566 | provider_ = 'foursquare',
2567 | id_ = id
2568 | },
2569 | }
2570 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2571 | end
2572 |
2573 | M.sendVenue = sendVenue
2574 |
2575 | -- User contact message
2576 | -- @contact Contact to send
2577 | -- @phone_number User's phone number
2578 | -- @first_name User first name, 1-255 characters
2579 | -- @last_name User last name
2580 | -- @user_id User identifier if known, 0 otherwise
2581 | local function sendContact(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, phone_number, first_name, last_name, user_id, cb, cmd)
2582 | local input_message_content = {
2583 | ID = "InputMessageContact",
2584 | contact_ = {
2585 | ID = "Contact",
2586 | phone_number_ = phone_number,
2587 | first_name_ = first_name,
2588 | last_name_ = last_name,
2589 | user_id_ = user_id
2590 | },
2591 | }
2592 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2593 | end
2594 |
2595 | M.sendContact = sendContact
2596 |
2597 | -- Message with a game
2598 | -- @bot_user_id User identifier of a bot owned the game
2599 | -- @game_short_name Game short name
2600 | local function sendGame(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, bot_user_id, game_short_name, cb, cmd)
2601 | local input_message_content = {
2602 | ID = "InputMessageGame",
2603 | bot_user_id_ = bot_user_id,
2604 | game_short_name_ = game_short_name
2605 | }
2606 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2607 | end
2608 |
2609 | M.sendGame = sendGame
2610 |
2611 | -- Forwarded message
2612 | -- @from_chat_id Chat identifier of the message to forward
2613 | -- @message_id Identifier of the message to forward
2614 | local function sendForwarded(chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, from_chat_id, message_id, cb, cmd)
2615 | local input_message_content = {
2616 | ID = "InputMessageForwarded",
2617 | from_chat_id_ = from_chat_id,
2618 | message_id_ = message_id,
2619 | in_game_share_ = in_game_share
2620 | }
2621 | sendRequest('SendMessage', chat_id, reply_to_message_id, disable_notification, from_background, reply_markup, input_message_content, cb, cmd)
2622 | end
2623 |
2624 | M.sendForwarded = sendForwarded
2625 |
2626 | return M
2627 |
--------------------------------------------------------------------------------