├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── bot
├── seedbot.lua
└── utils.lua
├── data
├── .gitkeep
└── photos
│ └── .gitkeep
├── groups
├── all
│ └── [group_id]all.txt
├── lists
│ └── [group_id]memberlist.txt
└── logs
│ ├── [group_id]log.txt
│ └── [group_id]stats.txt
├── launch.sh
├── libs
├── JSON.lua
├── dkjson.lua
├── mimetype.lua
└── redis.lua
├── patches
└── disable-python-and-libjansson.patch
└── plugins
├── admin.lua
├── all.lua
├── anti_spam.lua
├── arabic_lock.lua
├── banhammer.lua
├── broadcast.lua
├── download_media.lua
├── get.lua
├── ingroup.lua
├── inpm.lua
├── inrealm.lua
├── invite.lua
├── leave_ban.lua
├── onservice.lua
├── owners.lua
├── set.lua
└── stats.lua
/.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 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "tg"]
2 | path = tg
3 | url = https://github.com/SEEDTEAM/tg
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [TeleSeed](https://telegram.me/TeleSeed)
2 |
3 | [](https://gitter.im/SEEDTEAM/TeleSeed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 | **An advanced and powerful administration bot based on [yagop/telegram-bot](https://github.com/yagop/telegram-bot) licensed under the [GNU Affero General Public License](https://github.com/SEEDTEAM/TeleSeed/blob/master/LICENSE)**.
6 | # Features
7 |
8 | * **A powerful antispam system with custom sensitivity for each group**
9 | * **Multiple realms (admin groups)**
10 | * **Recalcitrant to any kind of spamming (X/Y bots, name/photo changers, etc.)**
11 | * **Global banning**
12 | * **Broadcast to all groups**
13 | * **Group links**
14 | * **Kick, ban and unban by reply**
15 | * **Groups, ban and global ban list**
16 | * **Logging anything that happens in a group**
17 | * **Invitation by username**
18 | * **Group administration via private messages**
19 | * **Only mods, owner and admin can add bots**
20 | * **Arabic lock**
21 | * **And more!**
22 |
23 | **Table of Contents**
24 | - [TeleSeed](#teleseed)
25 | - [Features](#features)
26 | - [Commands](#commands)
27 | - [Admins commands](#admins-commands)
28 | - [Realm creation](#realm-creation)
29 | - [Group creation](#group-creation)
30 | - [Adding and removing realms](#add-or-remove-realms)
31 | - [Adding and removing groups](#add-or-remove-groups)
32 | - [Leaving groups](#leaving)
33 | - [Everything about groups](#everything-about-groups)
34 | - [Setting descriptions in realm](#setting-description-in-realm)
35 | - [Setting group names in realm](#setting-group-name-in-realm)
36 | - [Setting rules in realm](#setting-rules-in-realm)
37 | - [Locking group names/photos/flood/members in realm](#lock-groups-namefloodphotomember-in-realm)
38 | - [Unlocking group names/photos/flood/members](#unlock-groups-namefloodphotomember)
39 | - [Group settings in realm](#group-setting-in-realm)
40 | - [Adding admins](#add-admin)
41 | - [Removing admins](#remove-admin)
42 | - [Admin/group listing in realm](#adminsgroup-list-in-realm)
43 | - [Broadcasting](#broadcast)
44 | - [Realm help](#realm-help)
45 | - [Global ban commands](#global-ban-commands)
46 | - [Set group owner](#set-group-owner)
47 | - [Bot stats](#bot-stats)
48 | - [Owner and mod commands](#owners-and-mods-commands)
49 | - [Hammer](#hammer)
50 | - [Locking a group's name/members/bots/arabic/flood](#group-namememberarabicfloodbots-lock)
51 | - [Unlocking a group's name/members/bots/arabic/flood](#group-namememberarabicfloodbots-unlock)
52 | - [Cleaning a group's modlist/rules/about/members](#group-modlistrulesaboutmember-clean)
53 | - [Seting a group's rules/about](#set-groups-rulesabout)
54 | - [Setting or changing a group's owner](#setting-or-changing-group-photo)
55 | - [Setting or changing a group's photo](#setting-or-changing-group-photo)
56 | - [Changing a group's name](#changing-group-name)
57 | - [Group links](#group-link)
58 | - [Promoting and demoting mods](#promote-and-demote-mods)
59 | - [Resolving usernames](#resolve-username)
60 | - [Flood sensitivity](#flood-sensitivity)
61 | - [Group rules and about](#group-rules-and-about)
62 | - [Group settings](#group-settings)
63 | - [Modlist](#modlist)
64 | - [Help](#help)
65 | - [Owner](#owner)
66 | - [Save and Get](#save-and-get)
67 | - [Id](#id)
68 | - [Group stats](#group-stats)
69 | - [Member list](#member-list)
70 | - [Group help](#group-help)
71 | - [In private commands](#in-private-commands)
72 | - [Hammer](#hammer)
73 | - [Cleaning](#cleaning)
74 | - [Setting flood sensitivity](#setting-flood-sensitivity)
75 | - [Locking a group's members/name](#lock-groups-membername)
76 | - [Unlocking a group's members/name](#unlock-groups-membername)
77 | - [Group link](#group-link)
78 | - [Changing name/rules](#change-namerulesname)
79 | - [Group log](#group-log)
80 | - [Join](#join)
81 | - [Installation](#installation)
82 | - [One command](#one-command)
83 | - [Realm configuration](#realm-configuration)
84 | - [Support and development](#support-and-development)
85 | - [Special thanks to:](#special-thanks-to)
86 | - [Our team!](#our-team)
87 |
88 |
89 | # Commands
90 | ## Admins commands
91 | **Only admins and sudo users can run these commands.**
92 | ### Group creation
93 | >[!/]creategroup [group name]
94 | >
95 | >>[!/]creategroup SEED
96 | >>>will create a group
97 | >>>
98 | >>>_Only works in realms for admins but, sudo users can use it everywhere_
99 |
100 | ### Realm creation
101 | >[!/]createrealm [realm name]
102 | >
103 | >>[!/]createrealm SEED
104 | >>>will create a realm
105 | >>>
106 | >>>_Only works in realms for admins but, sudo users can use it everywhere_
107 |
108 | ### Add or remove realms
109 | >[!/]add realm
110 | >>This command will add that group
111 | >
112 | >[!/]rem realm
113 | >>This command will remove that group
114 |
115 |
116 | ### Add or remove groups
117 | >[!/]add
118 | >>This command will add that group
119 | >
120 | >[!/]rem
121 | >>This command will remove that group
122 |
123 | ### Leaving
124 | >[!/]leave
125 | >>Bot will leave that group
126 |
127 | ### Everything about groups
128 | >[!/]all
129 | >>This command will return everything about that group
130 | >
131 | >[!/]all [group_id]
132 | >>_Only onwer, admin and sudo users can use this command_
133 |
134 |
135 | ### Setting description in realm
136 | > [!/]setabout [group_id] [text]
137 | >>[!/]setabout 123456789 about
138 | >>>This command will set [text] as description of [group_id]
139 |
140 |
141 | ### Setting group name in realm
142 | > [!/]setname [group_id] [text]
143 | >>[!/]setname 123456789 SEED
144 | >>>This command will set [text] as name of [group_id]
145 |
146 | ### Setting rules in realm
147 | > [!/]setrules [group_id] [text]
148 | >>[!/]setrules 123456789 rules !
149 | >>>This command will set [text] as rules of [group_id]
150 |
151 |
152 | ### Lock groups name|flood|photo|member in realm
153 | > [!/]lock [group_id] [name|flood|photo|member]
154 | >>[!/]lock 123456789 name
155 | >>>This command will lock name|flood|photo|member of [group_id]
156 |
157 |
158 | ### Unlock groups name|flood|photo|member
159 | > [!/]unlock [group_id] [name|flood|photo|member]
160 | >>[!/]unlock 123456789 name
161 | >>>This command will unlock name|flood|photo|member of [group_id]
162 |
163 | ## Group setting in realm
164 | >[!/]setting [group_id]
165 | >>[!/]setting 12345678
166 | >>>This command will return settings of [group_id]
167 |
168 | ### Add admin
169 | >[!/]addadmin [username]
170 | >>[!/]addadmin @username
171 | >>>This command will add username as admin
172 | >>>
173 | >>>_Only works in realms_
174 |
175 | ### Remove admin
176 | >[!/]removeadmin [username]
177 | >
178 | >>[!/]removeadmin @username
179 | >>>This command will add username as admin
180 | >>>
181 | >>>_Only works in realms_ [username]
182 |
183 | ### Admins|group list in realm
184 | >[!/]list [admins|groups]
185 | >>[!/]list groups
186 | >>>This command will return admins|groups list
187 |
188 | ### Broadcast
189 | >[!/]broadcast [text]
190 | >>[!/]broadcast Hello !
191 | >>>This command will send text to all groups
192 | >>>
193 | >>>_Only sudo users can run this command_
194 | >
195 | >[!/]bc [group_id] [text]
196 | >>[!/]bc 123456789 Hello !
197 | >>>This command will send text to [group_id]
198 |
199 | ## Global ban commands
200 | >[!/]banall [id]
201 | >>[!/]banall 123456789
202 | >>>This commands will globally ban [id]
203 | >
204 | >/sync_gbans
205 | >>Sync your global bans with teleseed
206 | >
207 | >[!/]unbanall [id]
208 | >>[!/]unbanall 123456789
209 | >>>This commands will remove [id] from global bans
210 | >
211 | >[!/]gbanlist
212 | >>This command will return global bans ids
213 | >
214 | >[!/]banlist [group_id]
215 | >>[!/]banlist 123456789
216 | >>>This command will return banned user of [group_id]
217 |
218 | ### Set group owner
219 | >[!/]setgpowner [group_id] [User_id]
220 | >>[!/]setgpowner 123456789 987654321
221 | >>>This command will set [User_id] as the owner of [group_id]
222 |
223 | ### Bot stats
224 | >[!/]stats teleseed
225 | >>This command will return bot stats
226 |
227 | # Realm Help
228 | >[!/]help
229 | >>Get realm commands list
230 |
231 |
232 |
233 |
234 | ## Owners and mods commands
235 |
236 | _Sudo users and admins can also use this commands in all groups_
237 |
238 | ### Hammer
239 |
240 | >[!/]kick [username|id]
241 | >>[!/]kick @useranme
242 | >>[!/]kick 123456789
243 | >>>This command will remove that user
244 | >
245 | >[!/]ban [username|id]
246 | >>[!/]ban @username
247 | >>[!/]ban 123456789
248 | >>>this command will ban and remove that user
249 | >
250 | >[!/]unban [id]
251 | >>[!/]unban 12345678
252 | >>>This command will unban that user
253 | >
254 | >[!/]banlist
255 | >>This command will return bans list
256 |
257 | ### Group name|member|arabic|flood|bots lock
258 | >[!/]lock [name|member|arabic|flood|bots]
259 | >>[!/]lock flood
260 | >>>This command will lock name|member|arabic|flood|bots of groups
261 |
262 | ### Group name|member|arabic|flood|bots unlock
263 | >[!/]unlock [name|member|arabic|flood|bots]
264 | >>[!/]unlock flood
265 | >>>This command will unlock name|member|arabic|flood|bots of groups
266 |
267 | ### Group modlist|rules|about|member clean
268 | >[!/]clean [modlist|rules|about|member]
269 | >>[!/]clean modlist
270 | >>>This command will clean modlist|rules|about|member
271 | >>>_/clean member will kick all users except owner,admins and bot and it's for owners only_
272 |
273 | ### Set groups rules|about
274 | >[!/]set [rules|about] [text]
275 | >>[!/]set rules don't spam!
276 | >>
277 | >>No NSFW
278 | >>> This command will set [text] as the rules|about of groups
279 |
280 | ### Setting or changing group owner
281 | >[!/]setowner [id]
282 | >>[!/]setowner 123456789
283 | >>>This command will set id as owner of that group
284 |
285 | ### Setting or changing group photo
286 | >[!/]setphoto
287 | >> This command will change or set group photo
288 | >>_also locks photo_
289 |
290 | ### Changing Group name
291 | >[!/]setname [name]
292 | >>[!/]setname SEED
293 | >>>This command will set [name] as name of groups
294 |
295 | ### Group link
296 | >[!/]newlink
297 | >>This command will revoke group link
298 | >
299 | >[!/]link
300 | >>This command will return group link
301 |
302 | ### Promote and demote mods
303 | >[!/]promote [username]
304 | >>[!/]promote @username
305 | >>>This command will promote @username as moderator
306 | >
307 | >[!/]demote [username]
308 | >>[!/]demote @username
309 | >>> This command will demote @username
310 |
311 | ### Resolve username
312 | >[!/]res [username]
313 | >>[!/]res @username
314 | >>>This command will return info about that username
315 |
316 | ### Flood sensitivity
317 | >[!/]setflood [value]
318 | >>[!/]setflood 15
319 | >>> will set flood sensitivity to [value]
320 |
321 | ### Group rules and about
322 | >[!/]about
323 | >>This command will return group description
324 | >
325 | >[!/]rules
326 | >>This command will return group rules
327 | >>>_normal users can use it too_
328 |
329 | ### Group settings
330 | >[!/]setting
331 | >>This command will return group settings
332 |
333 | ### Modlist
334 | >[!/]modlist
335 | >>This command will return group moderators
336 | >>>_normal users can use it too_
337 |
338 | ### Help
339 | >[!/]help
340 |
341 | ### Owner
342 | >[!/]owner
343 | >>This command will return owners id
344 |
345 | ### Save and get
346 | >[!/]save [title] [text]
347 | >>[!/]save spam Don't spam !
348 | >>>This command will save text as that title
349 | >
350 | >[!/]get [title]
351 | >>[!/]get spam
352 | >>>This command will return text of that title
353 |
354 | ### Id
355 | >[!/]id
356 | >>This command will return user or group id
357 | >>_can be triggered by reply_
358 | >>
359 | >>_Normal users can use it_
360 |
361 | ### Group stats
362 | >[!/]stats
363 | >>This command will return group message statistic in a .txt file
364 | >
365 | >[!/]statslist
366 | >>This command will return group message statistic
367 |
368 | ### Member list
369 | >[!/]who
370 | >>This command will return member list in a .txt file
371 | >
372 | >[!/]wholist
373 | >>This command will return member list
374 |
375 | # Group Help
376 | >[!/]help
377 | >>Get commands list
378 |
379 |
380 |
381 | ## In private commands
382 |
383 | **These commands only works in bots private**
384 |
385 | ### Hammer
386 | >[!/]owners group_id [kick|ban|unban] user_id
387 | >>[!/]owners 1234567 kick 1234567
388 |
389 | ### Cleaning
390 | >[!/]owners group_id clean [modlist|rules|about]
391 | >>[!/]owners 1234567 clean modlist
392 |
393 | ### Setting flood sensitivity
394 | >[!/]owners group_id setflood value
395 | >>[!/]owners 1234567 setflood 17
396 |
397 | ### Lock groups member|name
398 | >[!/]owners group_id lock [member|name]
399 | >>[!/]owners 1234567 lock member
400 |
401 | #### unlock groups member|name
402 | >[!/]owner group_id unlock [member|name]
403 | >>[!/]owners 1234567 unlock name
404 |
405 | ### Group link
406 | >[!/]owners group_id get link
407 | >>[!/]owners 1234567 get link
408 | >
409 | >[!/]owners group_id new link
410 | >>[!/]owners 1234567 new link
411 |
412 | ### Change name|rules|name
413 | >[!/]changename [group_id] [name]
414 | >>[!/]changename 123456789 SEED
415 | >
416 | >[!/]changrules [group_id] [rules]
417 | >>[!/]changrules 123456789 rules !
418 | >
419 | >[!/]changeabout [group_id] [about]
420 | >>[!/]changeabout 123456789 about !
421 |
422 | ### Group log
423 | >[!/]loggroup [group_id]
424 | >>[!/]loggroup 123456789
425 |
426 | ### Join
427 | >[!/]oin [group_id]
428 | >> This command will add user in [group_id]
429 |
430 |
431 | **U can use both "/" and "!"**
432 |
433 | # Installation
434 |
435 | ```sh
436 | # Install dependencies.
437 | # Tested on Ubuntu 14.04. For other OSs, check out https://github.com/yagop/telegram-bot/wiki/Installation
438 | sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev make autoconf unzip git redis-server g++ libjansson-dev libpython-dev expat libexpat1-dev
439 |
440 | # Let's install the bot.
441 | cd $HOME
442 | git clone https://github.com/SEEDTEAM/TeleSeed.git
443 | cd TeleSeed
444 | chmod +x launch.sh
445 | ./launch.sh install
446 | ./launch.sh # Enter a phone number & confirmation code.
447 | ```
448 | ### One command
449 | To install everything in one command (useful for VPS deployment) on Debian-based distros, use:
450 | ```sh
451 | #https://github.com/yagop/telegram-bot/wiki/Installation
452 | sudo apt-get update; sudo apt-get upgrade -y --force-yes; sudo apt-get dist-upgrade -y --force-yes; sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson* libpython-dev make autoconf unzip git redis-server g++ -y --force-yes && git clone https://github.com/SEEDTEAM/TeleSeed.git && cd TeleSeed && chmod +x launch.sh && ./launch.sh install && ./launch.sh
453 | ```
454 | ### Realm configuration
455 |
456 | After you run the bot for first time, send it `!id`. Get your ID and stop the bot.
457 |
458 | Open ./data/config.lua and add your ID to the "sudo_users" section in the following format:
459 | ```
460 | sudo_users = {
461 | 110626080,
462 | 103649648,
463 | 111020322,
464 | 0,
465 | YourID
466 | }
467 | ```
468 | Then restart the bot.
469 |
470 | Create a realm using the `!createrealm` command.
471 |
472 | # Support and development
473 |
474 | Check out this [tutorial by Telegram Geeks](http://telegramgeeks.com/2016/01/teleseed-tutorial/) for further assistance with setup and installation.
475 |
476 | **Do not contact us** in private for support.
477 | Join our bot development group by sending `/join 56670147` to [@TeleSeed](https://telegram.me/TeleSeed)
478 |
479 | # Special thanks to
480 | [@seyedan25](https://telegram.me/seyedan25)
481 |
482 | For managing [@teleseed](https://telegram.me/TeleSeed) on Telegram.
483 |
484 | [@Vamptacus](https://telegram.me/Vamptacus)
485 |
486 | For graphic designs.
487 |
488 | [topkecleon](https://github.com/topkecleon)
489 |
490 | [Juan Potato](https://github.com/JuanPotato)
491 |
492 | # Our team!
493 |
494 | [Alphonse](https://github.com/hmon) ([Telegram](https://telegram.me/iwals))
495 |
496 | [I M /-\ N](https://github.com/imandaneshi) ([Telegram](https://telegram.me/imandaneshi))
497 |
498 | [Siyanew](https://github.com/Siyanew) ([Telegram](https://telegram.me/Siyanew))
499 |
500 | [Rondoozle](https://github.com/Rondoozle) ([Telegram](https://telegram.me/POTUS))
501 |
502 | ### Our Telegram channels:
503 |
504 | English: [@SeedChannel](https://telegram.me/seedchannel)
505 |
506 | Persian: [@IranSeed](https://telegram.me/iranseed)
507 |
--------------------------------------------------------------------------------
/bot/seedbot.lua:
--------------------------------------------------------------------------------
1 | package.path = package.path .. ';.luarocks/share/lua/5.2/?.lua'
2 | ..';.luarocks/share/lua/5.2/?/init.lua'
3 | package.cpath = package.cpath .. ';.luarocks/lib/lua/5.2/?.so'
4 |
5 | require("./bot/utils")
6 |
7 | VERSION = '2'
8 |
9 | -- This function is called when tg receive a msg
10 | function on_msg_receive (msg)
11 | if not started then
12 | return
13 | end
14 |
15 | local receiver = get_receiver(msg)
16 | print (receiver)
17 |
18 | --vardump(msg)
19 | msg = pre_process_service_msg(msg)
20 | if msg_valid(msg) then
21 | msg = pre_process_msg(msg)
22 | if msg then
23 | match_plugins(msg)
24 | if redis:get("bot:markread") then
25 | if redis:get("bot:markread") == "on" then
26 | mark_read(receiver, ok_cb, false)
27 | end
28 | end
29 | end
30 | end
31 | end
32 |
33 | function ok_cb(extra, success, result)
34 | end
35 |
36 | function on_binlog_replay_end()
37 | started = true
38 | postpone (cron_plugins, false, 60*5.0)
39 |
40 | _config = load_config()
41 |
42 | -- load plugins
43 | plugins = {}
44 | load_plugins()
45 | end
46 |
47 | function msg_valid(msg)
48 | -- Don't process outgoing messages
49 | if msg.out then
50 | print('\27[36mNot valid: msg from us\27[39m')
51 | return false
52 | end
53 |
54 | -- Before bot was started
55 | if msg.date < now then
56 | print('\27[36mNot valid: old msg\27[39m')
57 | return false
58 | end
59 |
60 | if msg.unread == 0 then
61 | print('\27[36mNot valid: readed\27[39m')
62 | return false
63 | end
64 |
65 | if not msg.to.id then
66 | print('\27[36mNot valid: To id not provided\27[39m')
67 | return false
68 | end
69 |
70 | if not msg.from.id then
71 | print('\27[36mNot valid: From id not provided\27[39m')
72 | return false
73 | end
74 |
75 | if msg.from.id == our_id then
76 | print('\27[36mNot valid: Msg from our id\27[39m')
77 | return false
78 | end
79 |
80 | if msg.to.type == 'encr_chat' then
81 | print('\27[36mNot valid: Encrypted chat\27[39m')
82 | return false
83 | end
84 |
85 | if msg.from.id == 777000 then
86 | local login_group_id = 1
87 | --It will send login codes to this chat
88 | send_large_msg('chat#id'..login_group_id, msg.text)
89 | end
90 |
91 | return true
92 | end
93 |
94 | --
95 | function pre_process_service_msg(msg)
96 | if msg.service then
97 | local action = msg.action or {type=""}
98 | -- Double ! to discriminate of normal actions
99 | msg.text = "!!tgservice " .. action.type
100 |
101 | -- wipe the data to allow the bot to read service messages
102 | if msg.out then
103 | msg.out = false
104 | end
105 | if msg.from.id == our_id then
106 | msg.from.id = 0
107 | end
108 | end
109 | return msg
110 | end
111 |
112 | -- Apply plugin.pre_process function
113 | function pre_process_msg(msg)
114 | for name,plugin in pairs(plugins) do
115 | if plugin.pre_process and msg then
116 | print('Preprocess', name)
117 | msg = plugin.pre_process(msg)
118 | end
119 | end
120 |
121 | return msg
122 | end
123 |
124 | -- Go over enabled plugins patterns.
125 | function match_plugins(msg)
126 | for name, plugin in pairs(plugins) do
127 | match_plugin(plugin, name, msg)
128 | end
129 | end
130 |
131 | -- Check if plugin is on _config.disabled_plugin_on_chat table
132 | local function is_plugin_disabled_on_chat(plugin_name, receiver)
133 | local disabled_chats = _config.disabled_plugin_on_chat
134 | -- Table exists and chat has disabled plugins
135 | if disabled_chats and disabled_chats[receiver] then
136 | -- Checks if plugin is disabled on this chat
137 | for disabled_plugin,disabled in pairs(disabled_chats[receiver]) do
138 | if disabled_plugin == plugin_name and disabled then
139 | local warning = 'Plugin '..disabled_plugin..' is disabled on this chat'
140 | print(warning)
141 | send_msg(receiver, warning, ok_cb, false)
142 | return true
143 | end
144 | end
145 | end
146 | return false
147 | end
148 |
149 | function match_plugin(plugin, plugin_name, msg)
150 | local receiver = get_receiver(msg)
151 |
152 | -- Go over patterns. If one matches it's enough.
153 | for k, pattern in pairs(plugin.patterns) do
154 | local matches = match_pattern(pattern, msg.text)
155 | if matches then
156 | print("msg matches: ", pattern)
157 |
158 | if is_plugin_disabled_on_chat(plugin_name, receiver) then
159 | return nil
160 | end
161 | -- Function exists
162 | if plugin.run then
163 | -- If plugin is for privileged users only
164 | if not warns_user_not_allowed(plugin, msg) then
165 | local result = plugin.run(msg, matches)
166 | if result then
167 | send_large_msg(receiver, result)
168 | end
169 | end
170 | end
171 | -- One patterns matches
172 | return
173 | end
174 | end
175 | end
176 |
177 | -- DEPRECATED, use send_large_msg(destination, text)
178 | function _send_msg(destination, text)
179 | send_large_msg(destination, text)
180 | end
181 |
182 | -- Save the content of _config to config.lua
183 | function save_config( )
184 | serialize_to_file(_config, './data/config.lua')
185 | print ('saved config into ./data/config.lua')
186 | end
187 |
188 | -- Returns the config from config.lua file.
189 | -- If file doesn't exist, create it.
190 | function load_config( )
191 | local f = io.open('./data/config.lua', "r")
192 | -- If config.lua doesn't exist
193 | if not f then
194 | print ("Created new config file: data/config.lua")
195 | create_config()
196 | else
197 | f:close()
198 | end
199 | local config = loadfile ("./data/config.lua")()
200 | for v,user in pairs(config.sudo_users) do
201 | print("Allowed user: " .. user)
202 | end
203 | return config
204 | end
205 |
206 | -- Create a basic config.json file and saves it.
207 | function create_config( )
208 | -- A simple config with basic plugins and ourselves as privileged user
209 | config = {
210 | enabled_plugins = {
211 | "onservice",
212 | "inrealm",
213 | "ingroup",
214 | "inpm",
215 | "banhammer",
216 | "stats",
217 | "anti_spam",
218 | "owners",
219 | "arabic_lock",
220 | "set",
221 | "get",
222 | "broadcast",
223 | "download_media",
224 | "invite",
225 | "all",
226 | "leave_ban",
227 | "admin"
228 | },
229 | sudo_users = {110626080,103649648,143723991,111020322,0,tonumber(our_id)},--Sudo users
230 | disabled_channels = {},
231 | moderation = {data = 'data/moderation.json'},
232 | about_text = [[Teleseed v2 - Open Source
233 | An advance Administration bot based on yagop/telegram-bot
234 |
235 | https://github.com/SEEDTEAM/TeleSeed
236 |
237 | Our team!
238 | Alphonse (@Iwals)
239 | I M /-\ N (@Imandaneshi)
240 | Siyanew (@Siyanew)
241 | Rondoozle (@Potus)
242 | Seyedan (@Seyedan25)
243 |
244 | Special thanks to:
245 | Juan Potato
246 | Siyanew
247 | Topkecleon
248 | Vamptacus
249 |
250 | Our channels:
251 | English: @TeleSeedCH
252 | Persian: @IranSeed
253 | ]],
254 | help_text_realm = [[
255 | Realm Commands:
256 |
257 | !creategroup [name]
258 | Create a group
259 |
260 | !createrealm [name]
261 | Create a realm
262 |
263 | !setname [name]
264 | Set realm name
265 |
266 | !setabout [group_id] [text]
267 | Set a group's about text
268 |
269 | !setrules [grupo_id] [text]
270 | Set a group's rules
271 |
272 | !lock [grupo_id] [setting]
273 | Lock a group's setting
274 |
275 | !unlock [grupo_id] [setting]
276 | Unock a group's setting
277 |
278 | !wholist
279 | Get a list of members in group/realm
280 |
281 | !who
282 | Get a file of members in group/realm
283 |
284 | !type
285 | Get group type
286 |
287 | !kill chat [grupo_id]
288 | Kick all memebers and delete group
289 |
290 | !kill realm [realm_id]
291 | Kick all members and delete realm
292 |
293 | !addadmin [id|username]
294 | Promote an admin by id OR username *Sudo only
295 |
296 | !removeadmin [id|username]
297 | Demote an admin by id OR username *Sudo only
298 |
299 | !list groups
300 | Get a list of all groups
301 |
302 | !list realms
303 | Get a list of all realms
304 |
305 | !log
306 | Get a logfile of current group or realm
307 |
308 | !broadcast [text]
309 | !broadcast Hello !
310 | Send text to all groups
311 | » Only sudo users can run this command
312 |
313 | !bc [group_id] [text]
314 | !bc 123456789 Hello !
315 | This command will send text to [group_id]
316 |
317 | » U can use both "/" and "!"
318 |
319 | » Only mods, owner and admin can add bots in group
320 |
321 | » Only moderators and owner can use kick,ban,unban,newlink,link,setphoto,setname,lock,unlock,set rules,set about and settings commands
322 |
323 | » Only owner can use res,setowner,promote,demote and log commands
324 |
325 | ]],
326 | help_text = [[
327 | Commands list :
328 |
329 | !kick [username|id]
330 | You can also do it by reply
331 |
332 | !ban [ username|id]
333 | You can also do it by reply
334 |
335 | !unban [id]
336 | You can also do it by reply
337 |
338 | !who
339 | Members list
340 |
341 | !modlist
342 | Moderators list
343 |
344 | !promote [username]
345 | Promote someone
346 |
347 | !demote [username]
348 | Demote someone
349 |
350 | !kickme
351 | Will kick user
352 |
353 | !about
354 | Group description
355 |
356 | !setphoto
357 | Set and locks group photo
358 |
359 | !setname [name]
360 | Set group name
361 |
362 | !rules
363 | Group rules
364 |
365 | !id
366 | Return group id or user id
367 |
368 | !help
369 | Get commands list
370 |
371 | !lock [member|name|bots|leave]
372 | Locks [member|name|bots|leaveing]
373 |
374 | !unlock [member|name|bots|leave]
375 | Unlocks [member|name|bots|leaving]
376 |
377 | !set rules [text]
378 | Set [text] as rules
379 |
380 | !set about [text]
381 | Set [text] as about
382 |
383 | !settings
384 | Returns group settings
385 |
386 | !newlink
387 | Create/revoke your group link
388 |
389 | !link
390 | Returns group link
391 |
392 | !owner
393 | Returns group owner id
394 |
395 | !setowner [id]
396 | Will set id as owner
397 |
398 | !setflood [value]
399 | Set [value] as flood sensitivity
400 |
401 | !stats
402 | Simple message statistics
403 |
404 | !save [value] [text]
405 | Save [text] as [value]
406 |
407 | !get [value]
408 | Returns text of [value]
409 |
410 | !clean [modlist|rules|about]
411 | Will clear [modlist|rules|about] and set it to nil
412 |
413 | !res [username]
414 | Returns user id
415 |
416 | !log
417 | Will return group logs
418 |
419 | !banlist
420 | Will return group ban list
421 |
422 | » U can use both "/" and "!"
423 |
424 | » Only mods, owner and admin can add bots in group
425 |
426 | » Only moderators and owner can use kick,ban,unban,newlink,link,setphoto,setname,lock,unlock,set rules,set about and settings commands
427 |
428 | » Only owner can use res,setowner,promote,demote and log commands
429 |
430 | ]]
431 | }
432 | serialize_to_file(config, './data/config.lua')
433 | print('saved config into ./data/config.lua')
434 | end
435 |
436 | function on_our_id (id)
437 | our_id = id
438 | end
439 |
440 | function on_user_update (user, what)
441 | --vardump (user)
442 | end
443 |
444 | function on_chat_update (chat, what)
445 |
446 | end
447 |
448 | function on_secret_chat_update (schat, what)
449 | --vardump (schat)
450 | end
451 |
452 | function on_get_difference_end ()
453 | end
454 |
455 | -- Enable plugins in config.json
456 | function load_plugins()
457 | for k, v in pairs(_config.enabled_plugins) do
458 | print("Loading plugin", v)
459 |
460 | local ok, err = pcall(function()
461 | local t = loadfile("plugins/"..v..'.lua')()
462 | plugins[v] = t
463 | end)
464 |
465 | if not ok then
466 | print('\27[31mError loading plugin '..v..'\27[39m')
467 | print(tostring(io.popen("lua plugins/"..v..".lua"):read('*all')))
468 | print('\27[31m'..err..'\27[39m')
469 | end
470 |
471 | end
472 | end
473 |
474 |
475 | -- custom add
476 | function load_data(filename)
477 |
478 | local f = io.open(filename)
479 | if not f then
480 | return {}
481 | end
482 | local s = f:read('*all')
483 | f:close()
484 | local data = JSON.decode(s)
485 |
486 | return data
487 |
488 | end
489 |
490 | function save_data(filename, data)
491 |
492 | local s = JSON.encode(data)
493 | local f = io.open(filename, 'w')
494 | f:write(s)
495 | f:close()
496 |
497 | end
498 |
499 | -- Call and postpone execution for cron plugins
500 | function cron_plugins()
501 |
502 | for name, plugin in pairs(plugins) do
503 | -- Only plugins with cron function
504 | if plugin.cron ~= nil then
505 | plugin.cron()
506 | end
507 | end
508 |
509 | -- Called again in 2 mins
510 | postpone (cron_plugins, false, 120)
511 | end
512 |
513 | -- Start and load values
514 | our_id = 0
515 | now = os.time()
516 | math.randomseed(now)
517 | started = false
518 |
--------------------------------------------------------------------------------
/bot/utils.lua:
--------------------------------------------------------------------------------
1 | URL = require "socket.url"
2 | http = require "socket.http"
3 | https = require "ssl.https"
4 | ltn12 = require "ltn12"
5 | serpent = require "serpent"
6 | feedparser = require "feedparser"
7 |
8 | json = (loadfile "./libs/JSON.lua")()
9 | mimetype = (loadfile "./libs/mimetype.lua")()
10 | redis = (loadfile "./libs/redis.lua")()
11 | JSON = (loadfile "./libs/dkjson.lua")()
12 |
13 | http.TIMEOUT = 10
14 |
15 |
16 | function get_receiver(msg)
17 | if msg.to.type == 'user' then
18 | return 'user#id'..msg.from.id
19 | end
20 | if msg.to.type == 'chat' then
21 | return 'chat#id'..msg.to.id
22 | end
23 | if msg.to.type == 'encr_chat' then
24 | return msg.to.print_name
25 | end
26 | end
27 |
28 | function is_chat_msg( msg )
29 | if msg.to.type == 'chat' then
30 | return true
31 | end
32 | return false
33 | end
34 |
35 | function string.random(length)
36 | local str = "";
37 | for i = 1, length do
38 | math.random(97, 122)
39 | str = str..string.char(math.random(97, 122));
40 | end
41 | return str;
42 | end
43 |
44 | function string:split(sep)
45 | local sep, fields = sep or ":", {}
46 | local pattern = string.format("([^%s]+)", sep)
47 | self:gsub(pattern, function(c) fields[#fields+1] = c end)
48 | return fields
49 | end
50 |
51 | -- DEPRECATED
52 | function string.trim(s)
53 | print("string.trim(s) is DEPRECATED use string:trim() instead")
54 | return s:gsub("^%s*(.-)%s*$", "%1")
55 | end
56 |
57 | -- Removes spaces
58 | function string:trim()
59 | return self:gsub("^%s*(.-)%s*$", "%1")
60 | end
61 |
62 | function get_http_file_name(url, headers)
63 | -- Eg: foo.var
64 | local file_name = url:match("[^%w]+([%.%w]+)$")
65 | -- Any delimited alphanumeric on the url
66 | file_name = file_name or url:match("[^%w]+(%w+)[^%w]+$")
67 | -- Random name, hope content-type works
68 | file_name = file_name or str:random(5)
69 |
70 | local content_type = headers["content-type"]
71 |
72 | local extension = nil
73 | if content_type then
74 | extension = mimetype.get_mime_extension(content_type)
75 | end
76 | if extension then
77 | file_name = file_name.."."..extension
78 | end
79 |
80 | local disposition = headers["content-disposition"]
81 | if disposition then
82 | -- attachment; filename=CodeCogsEqn.png
83 | file_name = disposition:match('filename=([^;]+)') or file_name
84 | end
85 |
86 | return file_name
87 | end
88 |
89 | -- Saves file to /tmp/. If file_name isn't provided,
90 | -- will get the text after the last "/" for filename
91 | -- and content-type for extension
92 | function download_to_file(url, file_name)
93 | print("url to download: "..url)
94 |
95 | local respbody = {}
96 | local options = {
97 | url = url,
98 | sink = ltn12.sink.table(respbody),
99 | redirect = true
100 | }
101 |
102 | -- nil, code, headers, status
103 | local response = nil
104 |
105 | if url:starts('https') then
106 | options.redirect = false
107 | response = {https.request(options)}
108 | else
109 | response = {http.request(options)}
110 | end
111 |
112 | local code = response[2]
113 | local headers = response[3]
114 | local status = response[4]
115 |
116 | if code ~= 200 then return nil end
117 |
118 | file_name = file_name or get_http_file_name(url, headers)
119 |
120 | local file_path = "/tmp/"..file_name
121 | print("Saved to: "..file_path)
122 |
123 | file = io.open(file_path, "w+")
124 | file:write(table.concat(respbody))
125 | file:close()
126 |
127 | return file_path
128 | end
129 |
130 | function vardump(value)
131 | print(serpent.block(value, {comment=false}))
132 | end
133 |
134 | -- taken from http://stackoverflow.com/a/11130774/3163199
135 | function scandir(directory)
136 | local i, t, popen = 0, {}, io.popen
137 | for filename in popen('ls -a "'..directory..'"'):lines() do
138 | i = i + 1
139 | t[i] = filename
140 | end
141 | return t
142 | end
143 |
144 | -- http://www.lua.org/manual/5.2/manual.html#pdf-io.popen
145 | function run_command(str)
146 | local cmd = io.popen(str)
147 | local result = cmd:read('*all')
148 | cmd:close()
149 | return result
150 | end
151 |
152 | -- User has privileges
153 | function is_sudo(msg)
154 | local var = false
155 | -- Check users id in config
156 | for v,user in pairs(_config.sudo_users) do
157 | if user == msg.from.id then
158 | var = true
159 | end
160 | end
161 | return var
162 | end
163 |
164 | -- Returns the name of the sender
165 | function get_name(msg)
166 | local name = msg.from.first_name
167 | if name == nil then
168 | name = msg.from.id
169 | end
170 | return name
171 | end
172 |
173 | -- Returns at table of lua files inside plugins
174 | function plugins_names( )
175 | local files = {}
176 | for k, v in pairs(scandir("plugins")) do
177 | -- Ends with .lua
178 | if (v:match(".lua$")) then
179 | table.insert(files, v)
180 | end
181 | end
182 | return files
183 | end
184 |
185 | -- Function name explains what it does.
186 | function file_exists(name)
187 | local f = io.open(name,"r")
188 | if f ~= nil then
189 | io.close(f)
190 | return true
191 | else
192 | return false
193 | end
194 | end
195 |
196 | -- Save into file the data serialized for lua.
197 | -- Set uglify true to minify the file.
198 | function serialize_to_file(data, file, uglify)
199 | file = io.open(file, 'w+')
200 | local serialized
201 | if not uglify then
202 | serialized = serpent.block(data, {
203 | comment = false,
204 | name = '_'
205 | })
206 | else
207 | serialized = serpent.dump(data)
208 | end
209 | file:write(serialized)
210 | file:close()
211 | end
212 |
213 | -- Returns true if the string is empty
214 | function string:isempty()
215 | return self == nil or self == ''
216 | end
217 |
218 | -- Returns true if the string is blank
219 | function string:isblank()
220 | self = self:trim()
221 | return self:isempty()
222 | end
223 |
224 | -- DEPRECATED!!!!!
225 | function string.starts(String, Start)
226 | print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead")
227 | return Start == string.sub(String,1,string.len(Start))
228 | end
229 |
230 | -- Returns true if String starts with Start
231 | function string:starts(text)
232 | return text == string.sub(self,1,string.len(text))
233 | end
234 |
235 | -- Send image to user and delete it when finished.
236 | -- cb_function and cb_extra are optionals callback
237 | function _send_photo(receiver, file_path, cb_function, cb_extra)
238 | local cb_extra = {
239 | file_path = file_path,
240 | cb_function = cb_function,
241 | cb_extra = cb_extra
242 | }
243 | -- Call to remove with optional callback
244 | send_photo(receiver, file_path, cb_function, cb_extra)
245 | end
246 |
247 | -- Download the image and send to receiver, it will be deleted.
248 | -- cb_function and cb_extra are optionals callback
249 | function send_photo_from_url(receiver, url, cb_function, cb_extra)
250 | -- If callback not provided
251 | cb_function = cb_function or ok_cb
252 | cb_extra = cb_extra or false
253 |
254 | local file_path = download_to_file(url, false)
255 | if not file_path then -- Error
256 | local text = 'Error downloading the image'
257 | send_msg(receiver, text, cb_function, cb_extra)
258 | else
259 | print("File path: "..file_path)
260 | _send_photo(receiver, file_path, cb_function, cb_extra)
261 | end
262 | end
263 |
264 | -- Same as send_photo_from_url but as callback function
265 | function send_photo_from_url_callback(cb_extra, success, result)
266 | local receiver = cb_extra.receiver
267 | local url = cb_extra.url
268 |
269 | local file_path = download_to_file(url, false)
270 | if not file_path then -- Error
271 | local text = 'Error downloading the image'
272 | send_msg(receiver, text, ok_cb, false)
273 | else
274 | print("File path: "..file_path)
275 | _send_photo(receiver, file_path, ok_cb, false)
276 | end
277 | end
278 |
279 | -- Send multiple images asynchronous.
280 | -- param urls must be a table.
281 | function send_photos_from_url(receiver, urls)
282 | local cb_extra = {
283 | receiver = receiver,
284 | urls = urls,
285 | remove_path = nil
286 | }
287 | send_photos_from_url_callback(cb_extra)
288 | end
289 |
290 | -- Use send_photos_from_url.
291 | -- This function might be difficult to understand.
292 | function send_photos_from_url_callback(cb_extra, success, result)
293 | -- cb_extra is a table containing receiver, urls and remove_path
294 | local receiver = cb_extra.receiver
295 | local urls = cb_extra.urls
296 | local remove_path = cb_extra.remove_path
297 |
298 | -- The previously image to remove
299 | if remove_path ~= nil then
300 | os.remove(remove_path)
301 | print("Deleted: "..remove_path)
302 | end
303 |
304 | -- Nil or empty, exit case (no more urls)
305 | if urls == nil or #urls == 0 then
306 | return false
307 | end
308 |
309 | -- Take the head and remove from urls table
310 | local head = table.remove(urls, 1)
311 |
312 | local file_path = download_to_file(head, false)
313 | local cb_extra = {
314 | receiver = receiver,
315 | urls = urls,
316 | remove_path = file_path
317 | }
318 |
319 | -- Send first and postpone the others as callback
320 | send_photo(receiver, file_path, send_photos_from_url_callback, cb_extra)
321 | end
322 |
323 | -- Callback to remove a file
324 | function rmtmp_cb(cb_extra, success, result)
325 | local file_path = cb_extra.file_path
326 | local cb_function = cb_extra.cb_function or ok_cb
327 | local cb_extra = cb_extra.cb_extra
328 |
329 | if file_path ~= nil then
330 | os.remove(file_path)
331 | print("Deleted: "..file_path)
332 | end
333 | -- Finally call the callback
334 | cb_function(cb_extra, success, result)
335 | end
336 |
337 | -- Send document to user and delete it when finished.
338 | -- cb_function and cb_extra are optionals callback
339 | function _send_document(receiver, file_path, cb_function, cb_extra)
340 | local cb_extra = {
341 | file_path = file_path,
342 | cb_function = cb_function or ok_cb,
343 | cb_extra = cb_extra or false
344 | }
345 | -- Call to remove with optional callback
346 | send_document(receiver, file_path, rmtmp_cb, cb_extra)
347 | end
348 |
349 | -- Download the image and send to receiver, it will be deleted.
350 | -- cb_function and cb_extra are optionals callback
351 | function send_document_from_url(receiver, url, cb_function, cb_extra)
352 | local file_path = download_to_file(url, false)
353 | print("File path: "..file_path)
354 | _send_document(receiver, file_path, cb_function, cb_extra)
355 | end
356 |
357 | -- Parameters in ?a=1&b=2 style
358 | function format_http_params(params, is_get)
359 | local str = ''
360 | -- If is get add ? to the beginning
361 | if is_get then str = '?' end
362 | local first = true -- Frist param
363 | for k,v in pairs (params) do
364 | if v then -- nil value
365 | if first then
366 | first = false
367 | str = str..k.. "="..v
368 | else
369 | str = str.."&"..k.. "="..v
370 | end
371 | end
372 | end
373 | return str
374 | end
375 |
376 | -- Check if user can use the plugin and warns user
377 | -- Returns true if user was warned and false if not warned (is allowed)
378 | function warns_user_not_allowed(plugin, msg)
379 | if not user_allowed(plugin, msg) then
380 | local text = 'This plugin requires privileged user'
381 | local receiver = get_receiver(msg)
382 | send_msg(receiver, text, ok_cb, false)
383 | return true
384 | else
385 | return false
386 | end
387 | end
388 |
389 | -- Check if user can use the plugin
390 | function user_allowed(plugin, msg)
391 | if plugin.privileged and not is_sudo(msg) then
392 | return false
393 | end
394 | return true
395 | end
396 |
397 |
398 | function send_order_msg(destination, msgs)
399 | local cb_extra = {
400 | destination = destination,
401 | msgs = msgs
402 | }
403 | send_order_msg_callback(cb_extra, true)
404 | end
405 |
406 | function send_order_msg_callback(cb_extra, success, result)
407 | local destination = cb_extra.destination
408 | local msgs = cb_extra.msgs
409 | local file_path = cb_extra.file_path
410 | if file_path ~= nil then
411 | os.remove(file_path)
412 | print("Deleted: " .. file_path)
413 | end
414 | if type(msgs) == 'string' then
415 | send_large_msg(destination, msgs)
416 | elseif type(msgs) ~= 'table' then
417 | return
418 | end
419 | if #msgs < 1 then
420 | return
421 | end
422 | local msg = table.remove(msgs, 1)
423 | local new_cb_extra = {
424 | destination = destination,
425 | msgs = msgs
426 | }
427 | if type(msg) == 'string' then
428 | send_msg(destination, msg, send_order_msg_callback, new_cb_extra)
429 | elseif type(msg) == 'table' then
430 | local typ = msg[1]
431 | local nmsg = msg[2]
432 | new_cb_extra.file_path = nmsg
433 | if typ == 'document' then
434 | send_document(destination, nmsg, send_order_msg_callback, new_cb_extra)
435 | elseif typ == 'image' or typ == 'photo' then
436 | send_photo(destination, nmsg, send_order_msg_callback, new_cb_extra)
437 | elseif typ == 'audio' then
438 | send_audio(destination, nmsg, send_order_msg_callback, new_cb_extra)
439 | elseif typ == 'video' then
440 | send_video(destination, nmsg, send_order_msg_callback, new_cb_extra)
441 | else
442 | send_file(destination, nmsg, send_order_msg_callback, new_cb_extra)
443 | end
444 | end
445 | end
446 |
447 | -- Same as send_large_msg_callback but friendly params
448 | function send_large_msg(destination, text)
449 | local cb_extra = {
450 | destination = destination,
451 | text = text
452 | }
453 | send_large_msg_callback(cb_extra, true)
454 | end
455 |
456 | -- If text is longer than 4096 chars, send multiple msg.
457 | -- https://core.telegram.org/method/messages.sendMessage
458 | function send_large_msg_callback(cb_extra, success, result)
459 | local text_max = 4096
460 |
461 | local destination = cb_extra.destination
462 | local text = cb_extra.text
463 | local text_len = string.len(text)
464 | local num_msg = math.ceil(text_len / text_max)
465 |
466 | if num_msg <= 1 then
467 | send_msg(destination, text, ok_cb, false)
468 | else
469 |
470 | local my_text = string.sub(text, 1, 4096)
471 | local rest = string.sub(text, 4096, text_len)
472 |
473 | local cb_extra = {
474 | destination = destination,
475 | text = rest
476 | }
477 |
478 | send_msg(destination, my_text, send_large_msg_callback, cb_extra)
479 | end
480 | end
481 |
482 | -- Returns a table with matches or nil
483 | function match_pattern(pattern, text, lower_case)
484 | if text then
485 | local matches = {}
486 | if lower_case then
487 | matches = { string.match(text:lower(), pattern) }
488 | else
489 | matches = { string.match(text, pattern) }
490 | end
491 | if next(matches) then
492 | return matches
493 | end
494 | end
495 | -- nil
496 | end
497 |
498 | -- Function to read data from files
499 | function load_from_file(file, default_data)
500 | local f = io.open(file, "r+")
501 | -- If file doesn't exists
502 | if f == nil then
503 | -- Create a new empty table
504 | default_data = default_data or {}
505 | serialize_to_file(default_data, file)
506 | print ('Created file', file)
507 | else
508 | print ('Data loaded from file', file)
509 | f:close()
510 | end
511 | return loadfile (file)()
512 | end
513 |
514 | -- See http://stackoverflow.com/a/14899740
515 | function unescape_html(str)
516 | local map = {
517 | ["lt"] = "<",
518 | ["gt"] = ">",
519 | ["amp"] = "&",
520 | ["quot"] = '"',
521 | ["apos"] = "'"
522 | }
523 | new = string.gsub(str, '(&(#?x?)([%d%a]+);)', function(orig, n, s)
524 | var = map[s] or n == "#" and string.char(s)
525 | var = var or n == "#x" and string.char(tonumber(s,16))
526 | var = var or orig
527 | return var
528 | end)
529 | return new
530 | end
531 |
532 |
533 |
534 | --Check if this chat is realm or not
535 | function is_realm(msg)
536 | local var = false
537 | local realms = 'realms'
538 | local data = load_data(_config.moderation.data)
539 | local chat = msg.to.id
540 | if data[tostring(realms)] then
541 | if data[tostring(realms)][tostring(msg.to.id)] then
542 | var = true
543 | end
544 | return var
545 | end
546 | end
547 | --Check if this chat is a group or not
548 | function is_group(msg)
549 | local var = false
550 | local groups = 'groups'
551 | local data = load_data(_config.moderation.data)
552 | local chat = msg.to.id
553 | if data[tostring(groups)] then
554 | if data[tostring(groups)][tostring(msg.to.id)] then
555 | var = true
556 | end
557 | return var
558 | end
559 | end
560 |
561 |
562 | function savelog(group, logtxt)
563 |
564 | local text = (os.date("[ %c ]=> "..logtxt.."\n \n"))
565 | local file = io.open("./groups/logs/"..group.."log.txt", "a")
566 |
567 | file:write(text)
568 |
569 | file:close()
570 |
571 | end
572 |
573 | function user_print_name(user)
574 | if user.print_name then
575 | return user.print_name
576 | end
577 | local text = ''
578 | if user.first_name then
579 | text = user.last_name..' '
580 | end
581 | if user.lastname then
582 | text = text..user.last_name
583 | end
584 | return text
585 | end
586 |
587 | --Check if user is the owner of that group or not
588 | function is_owner(msg)
589 | local var = false
590 | local data = load_data(_config.moderation.data)
591 | local user = msg.from.id
592 |
593 | if data[tostring(msg.to.id)] then
594 | if data[tostring(msg.to.id)]['set_owner'] then
595 | if data[tostring(msg.to.id)]['set_owner'] == tostring(user) then
596 | var = true
597 | end
598 | end
599 | end
600 |
601 | if data['admins'] then
602 | if data['admins'][tostring(user)] then
603 | var = true
604 | end
605 | end
606 | for v,user in pairs(_config.sudo_users) do
607 | if user == msg.from.id then
608 | var = true
609 | end
610 | end
611 | return var
612 | end
613 |
614 | function is_owner2(user_id, group_id)
615 | local var = false
616 | local data = load_data(_config.moderation.data)
617 |
618 | if data[tostring(group_id)] then
619 | if data[tostring(group_id)]['set_owner'] then
620 | if data[tostring(group_id)]['set_owner'] == tostring(user_id) then
621 | var = true
622 | end
623 | end
624 | end
625 |
626 | if data['admins'] then
627 | if data['admins'][tostring(user_id)] then
628 | var = true
629 | end
630 | end
631 | for v,user in pairs(_config.sudo_users) do
632 | if user == user_id then
633 | var = true
634 | end
635 | end
636 | return var
637 | end
638 |
639 | --Check if user is admin or not
640 | function is_admin(msg)
641 | local var = false
642 | local data = load_data(_config.moderation.data)
643 | local user = msg.from.id
644 | local admins = 'admins'
645 | if data[tostring(admins)] then
646 | if data[tostring(admins)][tostring(user)] then
647 | var = true
648 | end
649 | end
650 | for v,user in pairs(_config.sudo_users) do
651 | if user == msg.from.id then
652 | var = true
653 | end
654 | end
655 | return var
656 | end
657 |
658 | function is_admin2(user_id)
659 | local var = false
660 | local data = load_data(_config.moderation.data)
661 | local user = user_id
662 | local admins = 'admins'
663 | if data[tostring(admins)] then
664 | if data[tostring(admins)][tostring(user)] then
665 | var = true
666 | end
667 | end
668 | for v,user in pairs(_config.sudo_users) do
669 | if user == user_id then
670 | var = true
671 | end
672 | end
673 | return var
674 | end
675 |
676 |
677 |
678 | --Check if user is the mod of that group or not
679 | function is_momod(msg)
680 | local var = false
681 | local data = load_data(_config.moderation.data)
682 | local user = msg.from.id
683 | if data[tostring(msg.to.id)] then
684 | if data[tostring(msg.to.id)]['moderators'] then
685 | if data[tostring(msg.to.id)]['moderators'][tostring(user)] then
686 | var = true
687 | end
688 | end
689 | end
690 |
691 | if data[tostring(msg.to.id)] then
692 | if data[tostring(msg.to.id)]['set_owner'] then
693 | if data[tostring(msg.to.id)]['set_owner'] == tostring(user) then
694 | var = true
695 | end
696 | end
697 | end
698 |
699 | if data['admins'] then
700 | if data['admins'][tostring(user)] then
701 | var = true
702 | end
703 | end
704 | for v,user in pairs(_config.sudo_users) do
705 | if user == msg.from.id then
706 | var = true
707 | end
708 | end
709 | return var
710 | end
711 |
712 | function is_momod2(user_id, group_id)
713 | local var = false
714 | local data = load_data(_config.moderation.data)
715 | local usert = user_id
716 | if data[tostring(group_id)] then
717 | if data[tostring(group_id)]['moderators'] then
718 | if data[tostring(group_id)]['moderators'][tostring(usert)] then
719 | var = true
720 | end
721 | end
722 | end
723 |
724 | if data[tostring(group_id)] then
725 | if data[tostring(group_id)]['set_owner'] then
726 | if data[tostring(group_id)]['set_owner'] == tostring(user_id) then
727 | var = true
728 | end
729 | end
730 | end
731 |
732 | if data['admins'] then
733 | if data['admins'][tostring(user_id)] then
734 | var = true
735 | end
736 | end
737 | for v,user in pairs(_config.sudo_users) do
738 | if user == usert then
739 | var = true
740 | end
741 | end
742 | return var
743 | end
744 |
745 | -- Returns the name of the sender
746 | function kick_user(user_id, chat_id)
747 | if tonumber(user_id) == tonumber(our_id) then -- Ignore bot
748 | return
749 | end
750 | if is_owner2(user_id, chat_id) then -- Ignore admins
751 | return
752 | end
753 | local chat = 'chat#id'..chat_id
754 | local user = 'user#id'..user_id
755 | chat_del_user(chat, user, ok_cb, true)
756 | end
757 |
758 | -- Ban
759 | function ban_user(user_id, chat_id)
760 | if tonumber(user_id) == tonumber(our_id) then -- Ignore bot
761 | return
762 | end
763 | if is_admin2(user_id) then -- Ignore admins
764 | return
765 | end
766 | -- Save to redis
767 | local hash = 'banned:'..chat_id
768 | redis:sadd(hash, user_id)
769 | -- Kick from chat
770 | kick_user(user_id, chat_id)
771 | end
772 | -- Global ban
773 | function banall_user(user_id)
774 | if tonumber(user_id) == tonumber(our_id) then -- Ignore bot
775 | return
776 | end
777 | if is_admin2(user_id) then -- Ignore admins
778 | return
779 | end
780 | -- Save to redis
781 | local hash = 'gbanned'
782 | redis:sadd(hash, user_id)
783 | end
784 | -- Global unban
785 | function unbanall_user(user_id)
786 | --Save on redis
787 | local hash = 'gbanned'
788 | redis:srem(hash, user_id)
789 | end
790 |
791 | -- Check if user_id is banned in chat_id or not
792 | function is_banned(user_id, chat_id)
793 | --Save on redis
794 | local hash = 'banned:'..chat_id
795 | local banned = redis:sismember(hash, user_id)
796 | return banned or false
797 | end
798 |
799 | -- Check if user_id is globally banned or not
800 | function is_gbanned(user_id)
801 | --Save on redis
802 | local hash = 'gbanned'
803 | local banned = redis:sismember(hash, user_id)
804 | return banned or false
805 | end
806 |
807 | -- Returns chat_id ban list
808 | function ban_list(chat_id)
809 | local hash = 'banned:'..chat_id
810 | local list = redis:smembers(hash)
811 | local text = "Ban list !\n\n"
812 | for k,v in pairs(list) do
813 | local user_info = redis:hgetall('user:'..v)
814 | -- vardump(user_info)
815 | if user_info then
816 | if user_info.username then
817 | user = '@'..user_info.username
818 | elseif user_info.print_name and not user_info.username then
819 | user = string.gsub(user_info.print_name, "_", " ")
820 | else
821 | user = ''
822 | end
823 | text = text..k.." - "..user.." ["..v.."]\n"
824 | end
825 | end
826 | return text
827 | end
828 |
829 | -- Returns globally ban list
830 | function banall_list()
831 | local hash = 'gbanned'
832 | local list = redis:smembers(hash)
833 | local text = "global bans !\n\n"
834 | for k,v in pairs(list) do
835 | local user_info = redis:hgetall('user:'..v)
836 | -- vardump(user_info)
837 | if user_info then
838 | if user_info.username then
839 | user = '@'..user_info.username
840 | elseif user_info.print_name and not user_info.username then
841 | user = string.gsub(user_info.print_name, "_", " ")
842 | else
843 | user = ''
844 | end
845 | text = text..k.." - "..user.." ["..v.."]\n"
846 | end
847 | end
848 | return text
849 | end
850 |
851 | -- /id by reply
852 | function get_message_callback_id(extra, success, result)
853 | if result.to.type == 'chat' then
854 | local chat = 'chat#id'..result.to.id
855 | send_large_msg(chat, result.from.id)
856 | else
857 | return 'Use This in Your Groups'
858 | end
859 | end
860 |
861 | -- kick by reply for mods and owner
862 | function Kick_by_reply(extra, success, result)
863 | if result.to.type == 'chat' then
864 | local chat = 'chat#id'..result.to.id
865 | if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot
866 | return "I won't kick myself"
867 | end
868 | if is_momod2(result.from.id, result.to.id) then -- Ignore mods,owner,admin
869 | return "you can't kick mods,owner and admins"
870 | end
871 | chat_del_user(chat, 'user#id'..result.from.id, ok_cb, false)
872 | else
873 | return 'Use This in Your Groups'
874 | end
875 | end
876 |
877 | -- Kick by reply for admins
878 | function Kick_by_reply_admins(extra, success, result)
879 | if result.to.type == 'chat' then
880 | local chat = 'chat#id'..result.to.id
881 | if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot
882 | return "I won't kick myself"
883 | end
884 | if is_admin2(result.from.id) then -- Ignore admins
885 | return
886 | end
887 | chat_del_user(chat, 'user#id'..result.from.id, ok_cb, false)
888 | else
889 | return 'Use This in Your Groups'
890 | end
891 | end
892 |
893 | --Ban by reply for admins
894 | function ban_by_reply(extra, success, result)
895 | if result.to.type == 'chat' then
896 | local chat = 'chat#id'..result.to.id
897 | if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot
898 | return "I won't ban myself"
899 | end
900 | if is_momod2(result.from.id, result.to.id) then -- Ignore mods,owner,admin
901 | return "you can't kick mods,owner and admins"
902 | end
903 | ban_user(result.from.id, result.to.id)
904 | send_large_msg(chat, "User "..result.from.id.." Banned")
905 | else
906 | return 'Use This in Your Groups'
907 | end
908 | end
909 |
910 | -- Ban by reply for admins
911 | function ban_by_reply_admins(extra, success, result)
912 | if result.to.type == 'chat' then
913 | local chat = 'chat#id'..result.to.id
914 | if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot
915 | return "I won't ban myself"
916 | end
917 | if is_admin2(result.from.id) then -- Ignore admins
918 | return
919 | end
920 | ban_user(result.from.id, result.to.id)
921 | send_large_msg(chat, "User "..result.from.id.." Banned")
922 | else
923 | return 'Use This in Your Groups'
924 | end
925 | end
926 |
927 | -- Unban by reply
928 | function unban_by_reply(extra, success, result)
929 | if result.to.type == 'chat' then
930 | local chat = 'chat#id'..result.to.id
931 | if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot
932 | return "I won't unban myself"
933 | end
934 | send_large_msg(chat, "User "..result.from.id.." Unbanned")
935 | -- Save on redis
936 | local hash = 'banned:'..result.to.id
937 | redis:srem(hash, result.from.id)
938 | else
939 | return 'Use This in Your Groups'
940 | end
941 | end
942 | function banall_by_reply(extra, success, result)
943 | if result.to.type == 'chat' then
944 | local chat = 'chat#id'..result.to.id
945 | if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot
946 | return "I won't banall myself"
947 | end
948 | if is_admin2(result.from.id) then -- Ignore admins
949 | return
950 | end
951 | local name = user_print_name(result.from)
952 | banall_user(result.from.id)
953 | chat_del_user(chat, 'user#id'..result.from.id, ok_cb, false)
954 | send_large_msg(chat, "User "..name.."["..result.from.id.."] hammered")
955 | else
956 | return 'Use This in Your Groups'
957 | end
958 | end
959 |
--------------------------------------------------------------------------------
/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bambooir/TeleSeed/6d8b9444c43255b2a6c6ec1b48fbb2ca11e4fd05/data/.gitkeep
--------------------------------------------------------------------------------
/data/photos/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bambooir/TeleSeed/6d8b9444c43255b2a6c6ec1b48fbb2ca11e4fd05/data/photos/.gitkeep
--------------------------------------------------------------------------------
/groups/all/[group_id]all.txt:
--------------------------------------------------------------------------------
1 | [group_id] logs !
2 |
--------------------------------------------------------------------------------
/groups/lists/[group_id]memberlist.txt:
--------------------------------------------------------------------------------
1 | [group_id] memeberlist !
2 |
--------------------------------------------------------------------------------
/groups/logs/[group_id]log.txt:
--------------------------------------------------------------------------------
1 | [group_id] logs !
2 |
--------------------------------------------------------------------------------
/groups/logs/[group_id]stats.txt:
--------------------------------------------------------------------------------
1 | [group_id] stats !
2 |
--------------------------------------------------------------------------------
/launch.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | THIS_DIR=$(cd $(dirname $0); pwd)
4 | cd $THIS_DIR
5 |
6 | update() {
7 | git pull
8 | git submodule update --init --recursive
9 | install_rocks
10 | }
11 |
12 | # Will install luarocks on THIS_DIR/.luarocks
13 | install_luarocks() {
14 | git clone https://github.com/keplerproject/luarocks.git
15 | cd luarocks
16 | git checkout tags/v2.2.1 # Current stable
17 |
18 | PREFIX="$THIS_DIR/.luarocks"
19 |
20 | ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config
21 |
22 | RET=$?; if [ $RET -ne 0 ];
23 | then echo "Error. Exiting."; exit $RET;
24 | fi
25 |
26 | make build && make install
27 | RET=$?; if [ $RET -ne 0 ];
28 | then echo "Error. Exiting.";exit $RET;
29 | fi
30 |
31 | cd ..
32 | rm -rf luarocks
33 | }
34 |
35 | install_rocks() {
36 | ./.luarocks/bin/luarocks install luasocket
37 | RET=$?; if [ $RET -ne 0 ];
38 | then echo "Error. Exiting."; exit $RET;
39 | fi
40 |
41 | ./.luarocks/bin/luarocks install oauth
42 | RET=$?; if [ $RET -ne 0 ];
43 | then echo "Error. Exiting."; exit $RET;
44 | fi
45 |
46 | ./.luarocks/bin/luarocks install redis-lua
47 | RET=$?; if [ $RET -ne 0 ];
48 | then echo "Error. Exiting."; exit $RET;
49 | fi
50 |
51 | ./.luarocks/bin/luarocks install lua-cjson
52 | RET=$?; if [ $RET -ne 0 ];
53 | then echo "Error. Exiting."; exit $RET;
54 | fi
55 |
56 | ./.luarocks/bin/luarocks install fakeredis
57 | RET=$?; if [ $RET -ne 0 ];
58 | then echo "Error. Exiting."; exit $RET;
59 | fi
60 |
61 | ./.luarocks/bin/luarocks install luafilesystem
62 | RET=$?; if [ $RET -ne 0 ];
63 | then echo "Error. Exiting."; exit $RET;
64 | fi
65 |
66 | ./.luarocks/bin/luarocks install lub
67 | RET=$?; if [ $RET -ne 0 ];
68 | then echo "Error. Exiting."; exit $RET;
69 | fi
70 |
71 | ./.luarocks/bin/luarocks install luaexpat
72 | RET=$?; if [ $RET -ne 0 ];
73 | then echo "Error. Exiting."; exit $RET;
74 | fi
75 |
76 | ./.luarocks/bin/luarocks install xml
77 | RET=$?; if [ $RET -ne 0 ];
78 | then echo "Error. Exiting."; exit $RET;
79 | fi
80 |
81 | ./.luarocks/bin/luarocks install feedparser
82 | RET=$?; if [ $RET -ne 0 ];
83 | then echo "Error. Exiting."; exit $RET;
84 | fi
85 |
86 | ./.luarocks/bin/luarocks install serpent
87 | RET=$?; if [ $RET -ne 0 ];
88 | then echo "Error. Exiting."; exit $RET;
89 | fi
90 | }
91 |
92 | install() {
93 | git pull
94 | git submodule update --init --recursive
95 | patch -i "patches/disable-python-and-libjansson.patch" -p 0 --batch --forward
96 | RET=$?;
97 |
98 | cd tg
99 | if [ $RET -ne 0 ]; then
100 | autoconf -i
101 | fi
102 | ./configure && make
103 |
104 | RET=$?; if [ $RET -ne 0 ]; then
105 | echo "Error. Exiting."; exit $RET;
106 | fi
107 | cd ..
108 | install_luarocks
109 | install_rocks
110 | }
111 |
112 | if [ "$1" = "install" ]; then
113 | install
114 | elif [ "$1" = "update" ]; then
115 | update
116 | else
117 | if [ ! -f ./tg/telegram.h ]; then
118 | echo "tg not found"
119 | echo "Run $0 install"
120 | exit 1
121 | fi
122 |
123 | if [ ! -f ./tg/bin/telegram-cli ]; then
124 | echo "tg binary not found"
125 | echo "Run $0 install"
126 | exit 1
127 | fi
128 |
129 | ./tg/bin/telegram-cli -k ./tg/tg-server.pub -s ./bot/seedbot.lua -l 1 -E $@
130 | fi
131 |
--------------------------------------------------------------------------------
/libs/dkjson.lua:
--------------------------------------------------------------------------------
1 | -- Module options:
2 | local always_try_using_lpeg = true
3 | local register_global_module_table = false
4 | local global_module_name = 'json'
5 |
6 | --[==[
7 |
8 | David Kolf's JSON module for Lua 5.1/5.2
9 | ========================================
10 | *Version 2.4*
11 | In the default configuration this module writes no global values, not even
12 | the module table. Import it using
13 | json = require ("dkjson")
14 | In environments where `require` or a similiar function are not available
15 | and you cannot receive the return value of the module, you can set the
16 | option `register_global_module_table` to `true`. The module table will
17 | then be saved in the global variable with the name given by the option
18 | `global_module_name`.
19 | Exported functions and values:
20 | `json.encode (object [, state])`
21 | --------------------------------
22 | Create a string representing the object. `Object` can be a table,
23 | a string, a number, a boolean, `nil`, `json.null` or any object with
24 | a function `__tojson` in its metatable. A table can only use strings
25 | and numbers as keys and its values have to be valid objects as
26 | well. It raises an error for any invalid data types or reference
27 | cycles.
28 | `state` is an optional table with the following fields:
29 | - `indent`
30 | When `indent` (a boolean) is set, the created string will contain
31 | newlines and indentations. Otherwise it will be one long line.
32 | - `keyorder`
33 | `keyorder` is an array to specify the ordering of keys in the
34 | encoded output. If an object has keys which are not in this array
35 | they are written after the sorted keys.
36 | - `level`
37 | This is the initial level of indentation used when `indent` is
38 | set. For each level two spaces are added. When absent it is set
39 | to 0.
40 | - `buffer`
41 | `buffer` is an array to store the strings for the result so they
42 | can be concatenated at once. When it isn't given, the encode
43 | function will create it temporary and will return the
44 | concatenated result.
45 | - `bufferlen`
46 | When `bufferlen` is set, it has to be the index of the last
47 | element of `buffer`.
48 | - `tables`
49 | `tables` is a set to detect reference cycles. It is created
50 | temporary when absent. Every table that is currently processed
51 | is used as key, the value is `true`.
52 |
53 | When `state.buffer` was set, the return value will be `true` on
54 | success. Without `state.buffer` the return value will be a string.
55 |
56 | `json.decode (string [, position [, null]])`
57 | --------------------------------------------
58 |
59 | Decode `string` starting at `position` or at 1 if `position` was
60 | omitted.
61 |
62 | `null` is an optional value to be returned for null values. The
63 | default is `nil`, but you could set it to `json.null` or any other
64 | value.
65 |
66 | The return values are the object or `nil`, the position of the next
67 | character that doesn't belong to the object, and in case of errors
68 | an error message.
69 | Two metatables are created. Every array or object that is decoded gets
70 | a metatable with the `__jsontype` field set to either `array` or
71 | `object`. If you want to provide your own metatables use the syntax
72 | json.decode (string, position, null, objectmeta, arraymeta)
73 | To prevent the assigning of metatables pass `nil`:
74 | json.decode (string, position, null, nil)
75 | `.__jsonorder`
76 | -------------------------
77 | `__jsonorder` can overwrite the `keyorder` for a specific table.
78 | `.__jsontype`
79 | ------------------------
80 | `__jsontype` can be either `"array"` or `"object"`. This value is only
81 | checked for empty tables. (The default for empty tables is `"array"`).
82 | `.__tojson (self, state)`
83 | ------------------------------------
84 | You can provide your own `__tojson` function in a metatable. In this
85 | function you can either add directly to the buffer and return true,
86 | or you can return a string. On errors nil and a message should be
87 | returned.
88 | `json.null`
89 | -----------
90 | You can use this value for setting explicit `null` values.
91 | `json.version`
92 | --------------
93 | Set to `"dkjson 2.4"`.
94 | `json.quotestring (string)`
95 | ---------------------------
96 | Quote a UTF-8 string and escape critical characters using JSON
97 | escape sequences. This function is only necessary when you build
98 | your own `__tojson` functions.
99 | `json.addnewline (state)`
100 | -------------------------
101 | When `state.indent` is set, add a newline to `state.buffer` and spaces
102 | according to `state.level`.
103 | LPeg support
104 | ------------
105 | When the local configuration variable `always_try_using_lpeg` is set,
106 | this module tries to load LPeg to replace the `decode` function. The
107 | speed increase is significant. You can get the LPeg module at
108 | .
109 | When LPeg couldn't be loaded, the pure Lua functions stay active.
110 |
111 | In case you don't want this module to require LPeg on its own,
112 | disable the option `always_try_using_lpeg` in the options section at
113 | the top of the module.
114 | In this case you can later load LPeg support using
115 | ### `json.use_lpeg ()`
116 | Require the LPeg module and replace the functions `quotestring` and
117 | and `decode` with functions that use LPeg patterns.
118 | This function returns the module table, so you can load the module
119 | using:
120 | json = require "dkjson".use_lpeg()
121 | Alternatively you can use `pcall` so the JSON module still works when
122 | LPeg isn't found.
123 |
124 | json = require "dkjson"
125 | pcall (json.use_lpeg)
126 |
127 | ### `json.using_lpeg`
128 |
129 | This variable is set to `true` when LPeg was loaded successfully.
130 |
131 | ---------------------------------------------------------------------
132 |
133 | Contact
134 | -------
135 |
136 | You can contact the author by sending an e-mail to 'david' at the
137 | domain 'dkolf.de'.
138 |
139 | ---------------------------------------------------------------------
140 |
141 | *Copyright (C) 2010-2013 David Heiko Kolf*
142 |
143 | Permission is hereby granted, free of charge, to any person obtaining
144 | a copy of this software and associated documentation files (the
145 | "Software"), to deal in the Software without restriction, including
146 | without limitation the rights to use, copy, modify, merge, publish,
147 | distribute, sublicense, and/or sell copies of the Software, and to
148 | permit persons to whom the Software is furnished to do so, subject to
149 | the following conditions:
150 |
151 | The above copyright notice and this permission notice shall be
152 | included in all copies or substantial portions of the Software.
153 |
154 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
155 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
156 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
157 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
158 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
159 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
160 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
161 | SOFTWARE.
162 |
163 |
168 |
169 |
--------------------------------------------------------------------------------
/libs/mimetype.lua:
--------------------------------------------------------------------------------
1 | -- Thanks to https://github.com/catwell/lua-toolbox/blob/master/mime.types
2 | do
3 |
4 | local mimetype = {}
5 |
6 | -- TODO: Add more?
7 | local types = {
8 | ["text/html"] = "html",
9 | ["text/css"] = "css",
10 | ["text/xml"] = "xml",
11 | ["image/gif"] = "gif",
12 | ["image/jpeg"] = "jpg",
13 | ["application/x-javascript"] = "js",
14 | ["application/atom+xml"] = "atom",
15 | ["application/rss+xml"] = "rss",
16 | ["text/mathml"] = "mml",
17 | ["text/plain"] = "txt",
18 | ["text/vnd.sun.j2me.app-descriptor"] = "jad",
19 | ["text/vnd.wap.wml"] = "wml",
20 | ["text/x-component"] = "htc",
21 | ["image/png"] = "png",
22 | ["image/tiff"] = "tiff",
23 | ["image/vnd.wap.wbmp"] = "wbmp",
24 | ["image/x-icon"] = "ico",
25 | ["image/x-jng"] = "jng",
26 | ["image/x-ms-bmp"] = "bmp",
27 | ["image/svg+xml"] = "svg",
28 | ["image/webp"] = "webp",
29 | ["application/java-archive"] = "jar",
30 | ["application/mac-binhex40"] = "hqx",
31 | ["application/msword"] = "doc",
32 | ["application/pdf"] = "pdf",
33 | ["application/postscript"] = "ps",
34 | ["application/rtf"] = "rtf",
35 | ["application/vnd.ms-excel"] = "xls",
36 | ["application/vnd.ms-powerpoint"] = "ppt",
37 | ["application/vnd.wap.wmlc"] = "wmlc",
38 | ["application/vnd.google-earth.kml+xml"] = "kml",
39 | ["application/vnd.google-earth.kmz"] = "kmz",
40 | ["application/x-7z-compressed"] = "7z",
41 | ["application/x-cocoa"] = "cco",
42 | ["application/x-java-archive-diff"] = "jardiff",
43 | ["application/x-java-jnlp-file"] = "jnlp",
44 | ["application/x-makeself"] = "run",
45 | ["application/x-perl"] = "pl",
46 | ["application/x-pilot"] = "prc",
47 | ["application/x-rar-compressed"] = "rar",
48 | ["application/x-redhat-package-manager"] = "rpm",
49 | ["application/x-sea"] = "sea",
50 | ["application/x-shockwave-flash"] = "swf",
51 | ["application/x-stuffit"] = "sit",
52 | ["application/x-tcl"] = "tcl",
53 | ["application/x-x509-ca-cert"] = "crt",
54 | ["application/x-xpinstall"] = "xpi",
55 | ["application/xhtml+xml"] = "xhtml",
56 | ["application/zip"] = "zip",
57 | ["application/octet-stream"] = "bin",
58 | ["audio/midi"] = "mid",
59 | ["audio/mpeg"] = "mp3",
60 | ["audio/ogg"] = "ogg",
61 | ["audio/x-m4a"] = "m4a",
62 | ["audio/x-realaudio"] = "ra",
63 | ["video/3gpp"] = "3gpp",
64 | ["video/mp4"] = "mp4",
65 | ["video/mpeg"] = "mpeg",
66 | ["video/quicktime"] = "mov",
67 | ["video/webm"] = "webm",
68 | ["video/x-flv"] = "flv",
69 | ["video/x-m4v"] = "m4v",
70 | ["video/x-mng"] = "mng",
71 | ["video/x-ms-asf"] = "asf",
72 | ["video/x-ms-wmv"] = "wmv",
73 | ["video/x-msvideo"] = "avi"
74 | }
75 |
76 | -- Returns the common file extension from a content-type
77 | function mimetype.get_mime_extension(content_type)
78 | return types[content_type]
79 | end
80 |
81 | -- Returns the mimetype and subtype
82 | function mimetype.get_content_type(extension)
83 | for k,v in pairs(types) do
84 | if v == extension then
85 | return k
86 | end
87 | end
88 | end
89 |
90 | -- Returns the mimetype without the subtype
91 | function mimetype.get_content_type_no_sub(extension)
92 | for k,v in pairs(types) do
93 | if v == extension then
94 | -- Before /
95 | return k:match('([%w-]+)/')
96 | end
97 | end
98 | end
99 |
100 | return mimetype
101 | end
--------------------------------------------------------------------------------
/libs/redis.lua:
--------------------------------------------------------------------------------
1 | local Redis = require 'redis'
2 | local FakeRedis = require 'fakeredis'
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
--------------------------------------------------------------------------------
/patches/disable-python-and-libjansson.patch:
--------------------------------------------------------------------------------
1 | --- tg/configure.ac 2015-10-24 14:23:51.964259062 +0200
2 | +++ tg/configure.ac 2015-10-24 14:05:10.111062758 +0200
3 | @@ -61,93 +61,43 @@
4 | ],[
5 | ])
6 |
7 | +# liblua is required
8 | AC_MSG_CHECKING([for liblua])
9 | -AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua],
10 | - [
11 | - if test "x$enableval" = "xno" ; then
12 | - AC_MSG_RESULT([disabled])
13 | - else
14 | - AC_MSG_RESULT([enabled])
15 | - AX_PROG_LUA([],[],
16 | - [
17 | - AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])])
18 | - AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])])
19 | - [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ]
20 | - [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ]
21 | - AC_DEFINE(USE_LUA,1,[use lua])
22 | - ],
23 | - [
24 | - AC_MSG_ERROR([No lua found. Try --disable-liblua])
25 | - ])
26 | - fi
27 | - ],[
28 | - AC_MSG_RESULT([enabled])
29 | - AX_PROG_LUA([],[],
30 | - [
31 | - AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])])
32 | - AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])])
33 | - [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ]
34 | - [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ]
35 | - AC_DEFINE(USE_LUA,1,[use lua])
36 | - ],
37 | - [
38 | - AC_MSG_ERROR([No lua found. Try --disable-liblua])
39 | - ])
40 | - ])
41 | -
42 | -AC_MSG_CHECKING([for python])
43 | -AC_ARG_ENABLE(python,[--enable-python/--disable-python],
44 | +AC_MSG_RESULT([enabled])
45 | +AX_PROG_LUA([],[],
46 | [
47 | - if test "x$enableval" = "xno" ; then
48 | - AC_MSG_RESULT([disabled])
49 | - else
50 | - AC_MSG_RESULT([enabled])
51 | -
52 | - AX_PYTHON()
53 | - AC_SUBST([PYTHON_FOUND])
54 | - if test $PYTHON_FOUND = no ; then
55 | - AC_MSG_ERROR([No supported python lib version found. Try --disable-python])
56 | - else
57 | - AC_SUBST([PYTHON_LIBS])
58 | - AC_SUBST([PYTHON_CFLAGS])
59 | - EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
60 | - CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
61 | - AC_DEFINE(USE_PYTHON,1,[use python])
62 | - fi
63 | - fi
64 | - ],[
65 | - AC_MSG_RESULT([enabled])
66 | -
67 | - AX_PYTHON()
68 | - AC_SUBST([PYTHON_FOUND])
69 | - if test $PYTHON_FOUND = no ; then
70 | - AC_MSG_ERROR([No supported python lib version found. Try --disable-python])
71 | - else
72 | - AC_SUBST([PYTHON_LIBS])
73 | - AC_SUBST([PYTHON_CFLAGS])
74 | - EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
75 | - CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
76 | - AC_DEFINE(USE_PYTHON,1,[use python])
77 | - fi
78 | + AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Install them])])
79 | + AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Install them])])
80 | + [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ]
81 | + [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ]
82 | + AC_DEFINE(USE_LUA,1,[use lua])
83 | + ],
84 | + [
85 | + AC_MSG_ERROR([No lua found. Install lua])
86 | ])
87 |
88 | +# Optional
89 | +AC_MSG_CHECKING([for python])
90 | +AX_PYTHON()
91 | +AC_SUBST([PYTHON_FOUND])
92 | +if test $PYTHON_FOUND = no ; then
93 | + AC_MSG_RESULT([disabled])
94 | +else
95 | + AC_SUBST([PYTHON_LIBS])
96 | + AC_SUBST([PYTHON_CFLAGS])
97 | + EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
98 | + CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
99 | + AC_DEFINE(USE_PYTHON,1,[use python])
100 | +fi
101 |
102 | -
103 | +# Optional
104 | AC_MSG_CHECKING([for libjansson])
105 | -AC_ARG_ENABLE(json,[--enable-json/--disable-json],
106 | - [
107 | - if test "x$enableval" = "xno" ; then
108 | - AC_MSG_RESULT([disabled])
109 | - else
110 | - AC_MSG_RESULT([enabled])
111 | - AC_CHECK_LIB([jansson],[json_array_set_new],[],AC_MSG_ERROR([No libjansson found. Try --disable-json]))
112 | - AC_DEFINE(USE_JSON,1,[use json])
113 | - fi
114 | - ],[
115 | +AC_CHECK_LIB([jansson],[json_array_set_new],
116 | + [
117 | AC_MSG_RESULT([enabled])
118 | - AC_CHECK_LIB([jansson],[json_array_set_new],[],AC_MSG_ERROR([No libjansson found. Try --disable-json]))
119 | AC_DEFINE(USE_JSON,1,[use json])
120 | - ])
121 | + ],
122 | + [AC_MSG_RESULT([disabled])])
123 |
124 | #check for custom prog name
125 | AC_MSG_CHECKING([progname])
126 | @@ -193,4 +143,3 @@
127 | AC_SUBST(EXTRA_LIBS)
128 | AC_CONFIG_FILES([Makefile])
129 | AC_OUTPUT
130 | -
131 |
--------------------------------------------------------------------------------
/plugins/admin.lua:
--------------------------------------------------------------------------------
1 | local function set_bot_photo(msg, success, result)
2 | local receiver = get_receiver(msg)
3 | if success then
4 | local file = 'data/photos/bot.jpg'
5 | print('File downloaded to:', result)
6 | os.rename(result, file)
7 | print('File moved to:', file)
8 | set_profile_photo(file, ok_cb, false)
9 | send_large_msg(receiver, 'Photo changed!', ok_cb, false)
10 | redis:del("bot:photo")
11 | else
12 | print('Error downloading: '..msg.id)
13 | send_large_msg(receiver, 'Failed, please try again!', ok_cb, false)
14 | end
15 | end
16 | local function parsed_url(link)
17 | local parsed_link = URL.parse(link)
18 | local parsed_path = URL.parse_path(parsed_link.path)
19 | return parsed_path[2]
20 | end
21 | local function get_contact_list_callback (cb_extra, success, result)
22 | local text = " "
23 | for k,v in pairs(result) do
24 | if v.print_name and v.id and v.phone then
25 | text = text..string.gsub(v.print_name , "_" , " ").." ["..v.id.."] = "..v.phone.."\n"
26 | end
27 | end
28 | local file = io.open("contact_list.txt", "w")
29 | file:write(text)
30 | file:flush()
31 | file:close()
32 | send_document("user#id"..cb_extra.target,"contact_list.txt", ok_cb, false)--.txt format
33 | local file = io.open("contact_list.json", "w")
34 | file:write(json:encode_pretty(result))
35 | file:flush()
36 | file:close()
37 | send_document("user#id"..cb_extra.target,"contact_list.json", ok_cb, false)--json format
38 | end
39 | local function user_info_callback(cb_extra, success, result)
40 | result.access_hash = nil
41 | result.flags = nil
42 | result.phone = nil
43 | if result.username then
44 | result.username = '@'..result.username
45 | end
46 | result.print_name = result.print_name:gsub("_","")
47 | local text = serpent.block(result, {comment=false})
48 | text = text:gsub("[{}]", "")
49 | text = text:gsub('"', "")
50 | text = text:gsub(",","")
51 | if cb_extra.msg.to.type == "chat" then
52 | send_large_msg("chat#id"..cb_extra.msg.to.id, text)
53 | else
54 | send_large_msg("user#id"..cb_extra.msg.to.id, text)
55 | end
56 | end
57 | local function get_dialog_list_callback(cb_extra, success, result)
58 | local text = ""
59 | for k,v in pairs(result) do
60 | if v.peer then
61 | if v.peer.type == "chat" then
62 | text = text.."group{"..v.peer.title.."}["..v.peer.id.."]("..v.peer.members_num..")"
63 | else
64 | if v.peer.print_name and v.peer.id then
65 | text = text.."user{"..v.peer.print_name.."}["..v.peer.id.."]"
66 | end
67 | if v.peer.username then
68 | text = text.."("..v.peer.username..")"
69 | end
70 | if v.peer.phone then
71 | text = text.."'"..v.peer.phone.."'"
72 | end
73 | end
74 | end
75 | if v.message then
76 | text = text..'\nlast msg >\nmsg id = '..v.message.id
77 | if v.message.text then
78 | text = text .. "\n text = "..v.message.text
79 | end
80 | if v.message.action then
81 | text = text.."\n"..serpent.block(v.message.action, {comment=false})
82 | end
83 | if v.message.from then
84 | if v.message.from.print_name then
85 | text = text.."\n From > \n"..string.gsub(v.message.from.print_name, "_"," ").."["..v.message.from.id.."]"
86 | end
87 | if v.message.from.username then
88 | text = text.."( "..v.message.from.username.." )"
89 | end
90 | if v.message.from.phone then
91 | text = text.."' "..v.message.from.phone.." '"
92 | end
93 | end
94 | end
95 | text = text.."\n\n"
96 | end
97 | local file = io.open("dialog_list.txt", "w")
98 | file:write(text)
99 | file:flush()
100 | file:close()
101 | send_document("user#id"..cb_extra.target,"dialog_list.txt", ok_cb, false)--.txt format
102 | local file = io.open("dialog_list.json", "w")
103 | file:write(json:encode_pretty(result))
104 | file:flush()
105 | file:close()
106 | send_document("user#id"..cb_extra.target,"dialog_list.json", ok_cb, false)--json format
107 | end
108 | local function run(msg,matches)
109 | local data = load_data(_config.moderation.data)
110 | local receiver = get_receiver(msg)
111 | local group = msg.to.id
112 | if not is_admin(msg) then
113 | return
114 | end
115 | if msg.media then
116 | if msg.media.type == 'photo' and redis:get("bot:photo") then
117 | if redis:get("bot:photo") == 'waiting' then
118 | load_photo(msg.id, set_bot_photo, msg)
119 | end
120 | end
121 | end
122 | if matches[1] == "setbotphoto" then
123 | redis:set("bot:photo", "waiting")
124 | return 'Please send me bot photo now'
125 | end
126 | if matches[1] == "markread" then
127 | if matches[2] == "on" then
128 | redis:set("bot:markread", "on")
129 | return "Mark read > on"
130 | end
131 | if matches[2] == "off" then
132 | redis:del("bot:markread")
133 | return "Mark read > off"
134 | end
135 | return
136 | end
137 | if matches[1] == "pm" then
138 | send_large_msg("user#id"..matches[2],matches[3])
139 | return "Msg sent"
140 | end
141 | if matches[1] == "block" then
142 | if is_admin2(matches[2]) then
143 | return "You can't block admins"
144 | end
145 | block_user("user#id"..matches[2],ok_cb,false)
146 | return "User blocked"
147 | end
148 | if matches[1] == "unblock" then
149 | unblock_user("user#id"..matches[2],ok_cb,false)
150 | return "User unblocked"
151 | end
152 | if matches[1] == "import" then--join by group link
153 | local hash = parsed_url(matches[2])
154 | import_chat_link(hash,ok_cb,false)
155 | end
156 | if matches[1] == "contactlist" then
157 | get_contact_list(get_contact_list_callback, {target = msg.from.id})
158 | return "I've sent contact list with both json and text format to your private"
159 | end
160 | if matches[1] == "addcontact" and matches[2] then add_contact(matches[2],matches[3],matches[4],ok_cb,false)
161 | return "Number "..matches[2].." add from contact list"
162 | end
163 | if matches[1] == "delcontact" then
164 | del_contact("user#id"..matches[2],ok_cb,false)
165 | return "User "..matches[2].." removed from contact list"
166 | end
167 | if matches[1] == "dialoglist" then
168 | get_dialog_list(get_dialog_list_callback, {target = msg.from.id})
169 | return "I've sent dialog list with both json and text format to your private"
170 | end
171 | if matches[1] == "whois" then
172 | user_info("user#id"..matches[2],user_info_callback,{msg=msg})
173 | end
174 | if matches[1] == "sync_gbans" then
175 | if not is_sudo(msg) then-- Sudo only
176 | return
177 | end
178 | local url = "http://seedteam.org/Teleseed/Global_bans.json"
179 | local SEED_gbans = http.request(url)
180 | local jdat = json:decode(SEED_gbans)
181 | for k,v in pairs(jdat) do
182 | redis:hset('user:'..v, 'print_name', k)
183 | banall_user(v)
184 | print(k, v.." Globally banned")
185 | end
186 | end
187 | return
188 | end
189 | return {
190 | patterns = {
191 | "^[!/](pm) (%d+) (.*)$",
192 | "^[!/](import) (.*)$",
193 | "^[!/](unblock) (%d+)$",
194 | "^[!/](block) (%d+)$",
195 | "^[!/](markread) (on)$",
196 | "^[!/](markread) (off)$",
197 | "^[!/](setbotphoto)$",
198 | "%[(photo)%]",
199 | "^[!/](contactlist)$",
200 | "^[!/](dialoglist)$",
201 | "^[!/](delcontact) (%d+)$",
202 | "^[!/](addcontact) (.*) (.*) (.*)$",
203 | "^[!/](whois) (%d+)$",
204 | "^/(sync_gbans)$"--sync your global bans with seed
205 | },
206 | run = run,
207 | }
208 | --By @imandaneshi :)
209 | --https://github.com/SEEDTEAM/TeleSeed/blob/master/plugins/admin.lua
210 |
--------------------------------------------------------------------------------
/plugins/all.lua:
--------------------------------------------------------------------------------
1 | do
2 | data = load_data(_config.moderation.data)
3 | local function get_msgs_user_chat(user_id, chat_id)
4 | local user_info = {}
5 | local uhash = 'user:'..user_id
6 | local user = redis:hgetall(uhash)
7 | local um_hash = 'msgs:'..user_id..':'..chat_id
8 | user_info.msgs = tonumber(redis:get(um_hash) or 0)
9 | user_info.name = user_print_name(user)..' ['..user_id..']'
10 | return user_info
11 | end
12 | local function chat_stats(chat_id)
13 | local hash = 'chat:'..chat_id..':users'
14 | local users = redis:smembers(hash)
15 | local users_info = {}
16 | for i = 1, #users do
17 | local user_id = users[i]
18 | local user_info = get_msgs_user_chat(user_id, chat_id)
19 | table.insert(users_info, user_info)
20 | end
21 | table.sort(users_info, function(a, b)
22 | if a.msgs and b.msgs then
23 | return a.msgs > b.msgs
24 | end
25 | end)
26 | local text = 'Chat stats:\n'
27 | for k,user in pairs(users_info) do
28 | text = text..user.name..' = '..user.msgs..'\n'
29 | end
30 | return text
31 | end
32 |
33 | local function get_group_type(target)
34 | local data = load_data(_config.moderation.data)
35 | local group_type = data[tostring(target)]['group_type']
36 | if not group_type or group_type == nil then
37 | return 'No group type available.'
38 | end
39 | return group_type
40 | end
41 | local function show_group_settings(target)
42 | local data = load_data(_config.moderation.data)
43 | if data[tostring(target)] then
44 | if data[tostring(target)]['settings']['flood_msg_max'] then
45 | NUM_MSG_MAX = tonumber(data[tostring(target)]['settings']['flood_msg_max'])
46 | print('custom'..NUM_MSG_MAX)
47 | else
48 | NUM_MSG_MAX = 5
49 | end
50 | end
51 | local settings = data[tostring(target)]['settings']
52 | local text = "Lock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member.."\nflood sensitivity : "..NUM_MSG_MAX
53 | return text
54 | end
55 |
56 | local function get_description(target)
57 | local data = load_data(_config.moderation.data)
58 | local data_cat = 'description'
59 | if not data[tostring(target)][data_cat] then
60 | return 'No description available.'
61 | end
62 | local about = data[tostring(target)][data_cat]
63 | return about
64 | end
65 |
66 | local function get_rules(target)
67 | local data = load_data(_config.moderation.data)
68 | local data_cat = 'rules'
69 | if not data[tostring(target)][data_cat] then
70 | return 'No rules available.'
71 | end
72 | local rules = data[tostring(target)][data_cat]
73 | return rules
74 | end
75 |
76 |
77 | local function modlist(target)
78 | local data = load_data(_config.moderation.data)
79 | local groups = 'groups'
80 | if not data[tostring(groups)] or not data[tostring(groups)][tostring(target)] then
81 | return 'Group is not added or is Realm.'
82 | end
83 | if next(data[tostring(target)]['moderators']) == nil then
84 | return 'No moderator in this group.'
85 | end
86 | local i = 1
87 | local message = '\nList of moderators :\n'
88 | for k,v in pairs(data[tostring(target)]['moderators']) do
89 | message = message ..i..' - @'..v..' [' ..k.. '] \n'
90 | i = i + 1
91 | end
92 | return message
93 | end
94 |
95 | local function get_link(target)
96 | local data = load_data(_config.moderation.data)
97 | local group_link = data[tostring(target)]['settings']['set_link']
98 | if not group_link or group_link == nil then
99 | return "No link"
100 | end
101 | return "Group link:\n"..group_link
102 | end
103 |
104 | local function all(target, receiver)
105 | local text = "All the things I know about this group\n\n"
106 | local group_type = get_group_type(target)
107 | text = text.."Group Type: \n"..group_type
108 | local settings = show_group_settings(target)
109 | text = text.."\n\nGroup settings: \n"..settings
110 | local rules = get_rules(target)
111 | text = text.."\n\nRules: \n"..rules
112 | local description = get_description(target)
113 | text = text.."\n\nAbout: \n"..description
114 | local modlist = modlist(target)
115 | text = text.."\n\nMods: \n"..modlist
116 | local link = get_link(target)
117 | text = text.."\n\nLink: \n"..link
118 | local stats = chat_stats(target)
119 | text = text.."\n\n"..stats
120 | local ban_list = ban_list(target)
121 | text = text.."\n\n"..ban_list
122 | local file = io.open("./groups/all/"..target.."all.txt", "w")
123 | file:write(text)
124 | file:flush()
125 | file:close()
126 | send_document(receiver,"./groups/all/"..target.."all.txt", ok_cb, false)
127 | return
128 | end
129 |
130 | function run(msg, matches)
131 | if matches[1] == "all" and matches[2] and is_owner2(msg.from.id, matches[2]) then
132 | local receiver = get_receiver(msg)
133 | local target = matches[2]
134 | return all(target, receiver)
135 | end
136 | if not is_owner(msg) then
137 | return
138 | end
139 | if matches[1] == "all" and not matches[2] then
140 | local receiver = get_receiver(msg)
141 | if not is_owner(msg) then
142 | return
143 | end
144 | return all(msg.to.id, receiver)
145 | end
146 | end
147 |
148 |
149 | return {
150 | patterns = {
151 | "^[!/](all)$",
152 | "^[!/](all) (%d+)$"
153 | },
154 | run = run
155 | }
156 | end
157 |
--------------------------------------------------------------------------------
/plugins/anti_spam.lua:
--------------------------------------------------------------------------------
1 |
2 | --An empty table for solving multiple kicking problem(thanks to @topkecleon )
3 | kicktable = {}
4 |
5 | do
6 |
7 | local TIME_CHECK = 2 -- seconds
8 | local data = load_data(_config.moderation.data)
9 | -- Save stats, ban user
10 | local function pre_process(msg)
11 | -- Ignore service msg
12 | if msg.service then
13 | return msg
14 | end
15 | if msg.from.id == our_id then
16 | return msg
17 | end
18 |
19 | -- Save user on Redis
20 | if msg.from.type == 'user' then
21 | local hash = 'user:'..msg.from.id
22 | print('Saving user', hash)
23 | if msg.from.print_name then
24 | redis:hset(hash, 'print_name', msg.from.print_name)
25 | end
26 | if msg.from.first_name then
27 | redis:hset(hash, 'first_name', msg.from.first_name)
28 | end
29 | if msg.from.last_name then
30 | redis:hset(hash, 'last_name', msg.from.last_name)
31 | end
32 | if msg.from.username then
33 | redis:hset(hash, 'username', msg.from.username)
34 | end
35 | end
36 |
37 | -- Save stats on Redis
38 | if msg.to.type == 'chat' then
39 | -- User is on chat
40 | local hash = 'chat:'..msg.to.id..':users'
41 | redis:sadd(hash, msg.from.id)
42 | end
43 |
44 |
45 |
46 | -- Total user msgs
47 | local hash = 'msgs:'..msg.from.id..':'..msg.to.id
48 | redis:incr(hash)
49 |
50 | --Load moderation data
51 | local data = load_data(_config.moderation.data)
52 | if data[tostring(msg.to.id)] then
53 | --Check if flood is one or off
54 | if data[tostring(msg.to.id)]['settings']['flood'] == 'no' then
55 | return msg
56 | end
57 | end
58 |
59 | -- Check flood
60 | if msg.from.type == 'user' then
61 | local hash = 'user:'..msg.from.id..':msgs'
62 | local msgs = tonumber(redis:get(hash) or 0)
63 | local data = load_data(_config.moderation.data)
64 | local NUM_MSG_MAX = 5
65 | if data[tostring(msg.to.id)] then
66 | if data[tostring(msg.to.id)]['settings']['flood_msg_max'] then
67 | NUM_MSG_MAX = tonumber(data[tostring(msg.to.id)]['settings']['flood_msg_max'])--Obtain group flood sensitivity
68 | end
69 | end
70 | local max_msg = NUM_MSG_MAX * 1
71 | if msgs > max_msg then
72 | local user = msg.from.id
73 | -- Ignore mods,owner and admins
74 | if is_momod(msg) then
75 | return msg
76 | end
77 | local chat = msg.to.id
78 | local user = msg.from.id
79 | -- Return end if user was kicked before
80 | if kicktable[user] == true then
81 | return
82 | end
83 | kick_user(user, chat)
84 | if msg.to.type == "user" then
85 | block_user("user#id"..msg.from.id,ok_cb,false)--Block user if spammed in private
86 | end
87 | local name = user_print_name(msg.from)
88 | --save it to log file
89 | savelog(msg.to.id, name.." ["..msg.from.id.."] spammed and kicked ! ")
90 | -- incr it on redis
91 | local gbanspam = 'gban:spam'..msg.from.id
92 | redis:incr(gbanspam)
93 | local gbanspam = 'gban:spam'..msg.from.id
94 | local gbanspamonredis = redis:get(gbanspam)
95 | --Check if user has spammed is group more than 4 times
96 | if gbanspamonredis then
97 | if tonumber(gbanspamonredis) == 4 and not is_owner(msg) then
98 | --Global ban that user
99 | banall_user(msg.from.id)
100 | local gbanspam = 'gban:spam'..msg.from.id
101 | --reset the counter
102 | redis:set(gbanspam, 0)
103 | local username = " "
104 | if msg.from.username ~= nil then
105 | username = msg.from.username
106 | end
107 | local name = user_print_name(msg.from)
108 | --Send this to that chat
109 | send_large_msg("chat#id"..msg.to.id, "User [ "..name.." ]"..msg.from.id.." Globally banned (spamming)")
110 | local log_group = 1 --set log group caht id
111 | --send it to log group
112 | send_large_msg("chat#id"..log_group, "User [ "..name.." ] ( @"..username.." )"..msg.from.id.." Globally banned from ( "..msg.to.print_name.." ) [ "..msg.to.id.." ] (spamming)")
113 | end
114 | end
115 | kicktable[user] = true
116 | msg = nil
117 | end
118 | redis:setex(hash, TIME_CHECK, msgs+1)
119 | end
120 | return msg
121 | end
122 |
123 | local function cron()
124 | --clear that table on the top of the plugins
125 | kicktable = {}
126 | end
127 |
128 | return {
129 | patterns = {},
130 | cron = cron,
131 | pre_process = pre_process
132 | }
133 |
134 | end
135 |
--------------------------------------------------------------------------------
/plugins/arabic_lock.lua:
--------------------------------------------------------------------------------
1 |
2 | antiarabic = {}-- An empty table for solving multiple kicking problem
3 |
4 | do
5 | local function run(msg, matches)
6 | if is_momod(msg) then -- Ignore mods,owner,admins
7 | return
8 | end
9 | local data = load_data(_config.moderation.data)
10 | if data[tostring(msg.to.id)]['settings']['lock_arabic'] then
11 | if data[tostring(msg.to.id)]['settings']['lock_arabic'] == 'yes' then
12 | if antiarabic[msg.from.id] == true then
13 | return
14 | end
15 | send_large_msg("chat#id".. msg.to.id , "Arabic is not allowed here")
16 | local name = user_print_name(msg.from)
17 | savelog(msg.to.id, name.." ["..msg.from.id.."] kicked (arabic was locked) ")
18 | chat_del_user('chat#id'..msg.to.id,'user#id'..msg.from.id,ok_cb,false)
19 | antiarabic[msg.from.id] = true
20 | return
21 | end
22 | end
23 | return
24 | end
25 | local function cron()
26 | antiarabic = {} -- Clear antiarabic table
27 | end
28 | return {
29 | patterns = {
30 | "([\216-\219][\128-\191])"
31 | },
32 | run = run,
33 | cron = cron
34 | }
35 |
36 | end
37 |
--------------------------------------------------------------------------------
/plugins/banhammer.lua:
--------------------------------------------------------------------------------
1 |
2 | local function pre_process(msg)
3 | -- SERVICE MESSAGE
4 | if msg.action and msg.action.type then
5 | local action = msg.action.type
6 | -- Check if banned user joins chat by link
7 | if action == 'chat_add_user_link' then
8 | local user_id = msg.from.id
9 | print('Checking invited user '..user_id)
10 | local banned = is_banned(user_id, msg.to.id)
11 | if banned or is_gbanned(user_id) then -- Check it with redis
12 | print('User is banned!')
13 | local name = user_print_name(msg.from)
14 | savelog(msg.to.id, name.." ["..msg.from.id.."] is banned and kicked ! ")-- Save to logs
15 | kick_user(user_id, msg.to.id)
16 | end
17 | end
18 | -- Check if banned user joins chat
19 | if action == 'chat_add_user' then
20 | local user_id = msg.action.user.id
21 | print('Checking invited user '..user_id)
22 | local banned = is_banned(user_id, msg.to.id)
23 | if banned or is_gbanned(user_id) then -- Check it with redis
24 | print('User is banned!')
25 | local name = user_print_name(msg.from)
26 | savelog(msg.to.id, name.." ["..msg.from.id.."] added a banned user >"..msg.action.user.id)-- Save to logs
27 | kick_user(user_id, msg.to.id)
28 | local banhash = 'addedbanuser:'..msg.to.id..':'..msg.from.id
29 | redis:incr(banhash)
30 | local banhash = 'addedbanuser:'..msg.to.id..':'..msg.from.id
31 | local banaddredis = redis:get(banhash)
32 | if banaddredis then
33 | if tonumber(banaddredis) == 4 and not is_owner(msg) then
34 | kick_user(msg.from.id, msg.to.id)-- Kick user who adds ban ppl more than 3 times
35 | end
36 | if tonumber(banaddredis) == 8 and not is_owner(msg) then
37 | ban_user(msg.from.id, msg.to.id)-- Kick user who adds ban ppl more than 7 times
38 | local banhash = 'addedbanuser:'..msg.to.id..':'..msg.from.id
39 | redis:set(banhash, 0)-- Reset the Counter
40 | end
41 | end
42 | end
43 | if data[tostring(msg.to.id)] then
44 | if data[tostring(msg.to.id)]['settings'] then
45 | if data[tostring(msg.to.id)]['settings']['lock_bots'] then
46 | bots_protection = data[tostring(msg.to.id)]['settings']['lock_bots']
47 | end
48 | end
49 | end
50 | if msg.action.user.username ~= nil then
51 | if string.sub(msg.action.user.username:lower(), -3) == 'bot' and not is_momod(msg) and bots_protection == "yes" then --- Will kick bots added by normal users
52 | local name = user_print_name(msg.from)
53 | savelog(msg.to.id, name.." ["..msg.from.id.."] added a bot > @".. msg.action.user.username)-- Save to logs
54 | kick_user(msg.action.user.id, msg.to.id)
55 | end
56 | end
57 | end
58 | -- No further checks
59 | return msg
60 | end
61 | -- banned user is talking !
62 | if msg.to.type == 'chat' then
63 | local data = load_data(_config.moderation.data)
64 | local group = msg.to.id
65 | local texttext = 'groups'
66 | --if not data[tostring(texttext)][tostring(msg.to.id)] and not is_realm(msg) then -- Check if this group is one of my groups or not
67 | --chat_del_user('chat#id'..msg.to.id,'user#id'..our_id,ok_cb,false)
68 | --return
69 | --end
70 | local user_id = msg.from.id
71 | local chat_id = msg.to.id
72 | local banned = is_banned(user_id, chat_id)
73 | if banned or is_gbanned(user_id) then -- Check it with redis
74 | print('Banned user talking!')
75 | local name = user_print_name(msg.from)
76 | savelog(msg.to.id, name.." ["..msg.from.id.."] banned user is talking !")-- Save to logs
77 | kick_user(user_id, chat_id)
78 | msg.text = ''
79 | end
80 | end
81 | return msg
82 | end
83 |
84 | local function kick_ban_res(extra, success, result)
85 | --vardump(result)
86 | --vardump(extra)
87 | local member_id = result.id
88 | local user_id = member_id
89 | local member = result.username
90 | local chat_id = extra.chat_id
91 | local from_id = extra.from_id
92 | local get_cmd = extra.get_cmd
93 | local receiver = "chat#id"..chat_id
94 | if get_cmd == "kick" then
95 | if member_id == from_id then
96 | return send_large_msg(receiver, "You can't kick yourself")
97 | end
98 | if is_momod2(member_id, chat_id) and not is_admin2(sender) then
99 | return send_large_msg(receiver, "You can't kick mods/owner/admins")
100 | end
101 | return kick_user(member_id, chat_id)
102 | elseif get_cmd == 'ban' then
103 | if is_momod2(member_id, chat_id) and not is_admin2(sender) then
104 | return send_large_msg(receiver, "You can't ban mods/owner/admins")
105 | end
106 | send_large_msg(receiver, 'User @'..member..' ['..member_id..'] banned')
107 | return ban_user(member_id, chat_id)
108 | elseif get_cmd == 'unban' then
109 | send_large_msg(receiver, 'User @'..member..' ['..member_id..'] unbanned')
110 | local hash = 'banned:'..chat_id
111 | redis:srem(hash, member_id)
112 | return 'User '..user_id..' unbanned'
113 | elseif get_cmd == 'banall' then
114 | send_large_msg(receiver, 'User @'..member..' ['..member_id..'] globally banned')
115 | return banall_user(member_id, chat_id)
116 | elseif get_cmd == 'unbanall' then
117 | send_large_msg(receiver, 'User @'..member..' ['..member_id..'] un-globally banned')
118 | return unbanall_user(member_id, chat_id)
119 | end
120 | end
121 |
122 | local function run(msg, matches)
123 | if matches[1]:lower() == 'id' then
124 | if msg.to.type == "user" then
125 | return "Bot ID: "..msg.to.id.. "\n\nYour ID: "..msg.from.id
126 | end
127 | if type(msg.reply_id) ~= "nil" then
128 | local name = user_print_name(msg.from)
129 | savelog(msg.to.id, name.." ["..msg.from.id.."] used /id ")
130 | id = get_message(msg.reply_id,get_message_callback_id, false)
131 | elseif matches[1]:lower() == 'id' then
132 | local name = user_print_name(msg.from)
133 | savelog(msg.to.id, name.." ["..msg.from.id.."] used /id ")
134 | return "Group ID for " ..string.gsub(msg.to.print_name, "_", " ").. ":\n\n"..msg.to.id
135 | end
136 | end
137 | if matches[1]:lower() == 'kickme' then-- /kickme
138 | local receiver = get_receiver(msg)
139 | if msg.to.type == 'chat' then
140 | local name = user_print_name(msg.from)
141 | savelog(msg.to.id, name.." ["..msg.from.id.."] left using kickme ")-- Save to logs
142 | chat_del_user("chat#id"..msg.to.id, "user#id"..msg.from.id, ok_cb, false)
143 | end
144 | end
145 |
146 | if not is_momod(msg) then -- Ignore normal users
147 | return
148 | end
149 |
150 | if matches[1]:lower() == "banlist" then -- Ban list !
151 | local chat_id = msg.to.id
152 | if matches[2] and is_admin(msg) then
153 | chat_id = matches[2]
154 | end
155 | return ban_list(chat_id)
156 | end
157 | if matches[1]:lower() == 'ban' then-- /ban
158 | if type(msg.reply_id)~="nil" and is_momod(msg) then
159 | if is_admin(msg) then
160 | local msgr = get_message(msg.reply_id,ban_by_reply_admins, false)
161 | else
162 | msgr = get_message(msg.reply_id,ban_by_reply, false)
163 | end
164 | end
165 | local user_id = matches[2]
166 | local chat_id = msg.to.id
167 | if string.match(matches[2], '^%d+$') then
168 | if tonumber(matches[2]) == tonumber(our_id) then
169 | return
170 | end
171 | if not is_admin(msg) and is_momod2(matches[2], msg.to.id) then
172 | return "you can't ban mods/owner/admins"
173 | end
174 | if tonumber(matches[2]) == tonumber(msg.from.id) then
175 | return "You can't ban your self !"
176 | end
177 | local name = user_print_name(msg.from)
178 | savelog(msg.to.id, name.." ["..msg.from.id.."] baned user ".. matches[2])
179 | ban_user(user_id, chat_id)
180 | else
181 | local cbres_extra = {
182 | chat_id = msg.to.id,
183 | get_cmd = 'ban',
184 | from_id = msg.from.id
185 | }
186 | local username = matches[2]
187 | local username = string.gsub(matches[2], '@', '')
188 | res_user(username, kick_ban_res, cbres_extra)
189 | end
190 | end
191 |
192 |
193 | if matches[1]:lower() == 'unban' then -- /unban
194 | if type(msg.reply_id)~="nil" and is_momod(msg) then
195 | local msgr = get_message(msg.reply_id,unban_by_reply, false)
196 | end
197 | local user_id = matches[2]
198 | local chat_id = msg.to.id
199 | local targetuser = matches[2]
200 | if string.match(targetuser, '^%d+$') then
201 | local user_id = targetuser
202 | local hash = 'banned:'..chat_id
203 | redis:srem(hash, user_id)
204 | local name = user_print_name(msg.from)
205 | savelog(msg.to.id, name.." ["..msg.from.id.."] unbaned user ".. matches[2])
206 | return 'User '..user_id..' unbanned'
207 | else
208 | local cbres_extra = {
209 | chat_id = msg.to.id,
210 | get_cmd = 'unban',
211 | from_id = msg.from.id
212 | }
213 | local username = matches[2]
214 | local username = string.gsub(matches[2], '@', '')
215 | res_user(username, kick_ban_res, cbres_extra)
216 | end
217 | end
218 |
219 | if matches[1]:lower() == 'kick' then
220 | if type(msg.reply_id)~="nil" and is_momod(msg) then
221 | if is_admin(msg) then
222 | local msgr = get_message(msg.reply_id,Kick_by_reply_admins, false)
223 | else
224 | msgr = get_message(msg.reply_id,Kick_by_reply, false)
225 | end
226 | end
227 |
228 | if string.match(matches[2], '^%d+$') then
229 | if tonumber(matches[2]) == tonumber(our_id) then
230 | return
231 | end
232 | if not is_admin(msg) and is_momod2(matches[2], msg.to.id) then
233 | return "you can't kick mods/owner/admins"
234 | end
235 | if tonumber(matches[2]) == tonumber(msg.from.id) then
236 | return "You can't kick your self !"
237 | end
238 | local user_id = matches[2]
239 | local chat_id = msg.to.id
240 | name = user_print_name(msg.from)
241 | savelog(msg.to.id, name.." ["..msg.from.id.."] kicked user ".. matches[2])
242 | kick_user(user_id, chat_id)
243 | else
244 | local cbres_extra = {
245 | chat_id = msg.to.id,
246 | get_cmd = 'kick',
247 | from_id = msg.from.id
248 | }
249 | local username = matches[2]
250 | local username = string.gsub(matches[2], '@', '')
251 | res_user(username, kick_ban_res, cbres_extra)
252 | end
253 | end
254 |
255 |
256 | if not is_admin(msg) then
257 | return
258 | end
259 |
260 | if matches[1]:lower() == 'banall' then -- Global ban
261 | if type(msg.reply_id) ~="nil" and is_admin(msg) then
262 | return get_message(msg.reply_id,banall_by_reply, false)
263 | end
264 | local user_id = matches[2]
265 | local chat_id = msg.to.id
266 | local targetuser = matches[2]
267 | if string.match(targetuser, '^%d+$') then
268 | if tonumber(matches[2]) == tonumber(our_id) then
269 | return false
270 | end
271 | banall_user(targetuser)
272 | return 'User ['..user_id..' ] globally banned'
273 | else
274 | local cbres_extra = {
275 | chat_id = msg.to.id,
276 | get_cmd = 'banall',
277 | from_id = msg.from.id
278 | }
279 | local username = matches[2]
280 | local username = string.gsub(matches[2], '@', '')
281 | res_user(username, kick_ban_res, cbres_extra)
282 | end
283 | end
284 | if matches[1]:lower() == 'unbanall' then -- Global unban
285 | local user_id = matches[2]
286 | local chat_id = msg.to.id
287 | if string.match(matches[2], '^%d+$') then
288 | if tonumber(matches[2]) == tonumber(our_id) then
289 | return false
290 | end
291 | unbanall_user(user_id)
292 | return 'User ['..user_id..' ] removed from global ban list'
293 | else
294 | local cbres_extra = {
295 | chat_id = msg.to.id,
296 | get_cmd = 'unbanall',
297 | from_id = msg.from.id
298 | }
299 | local username = matches[2]
300 | local username = string.gsub(matches[2], '@', '')
301 | res_user(username, kick_ban_res, cbres_extra)
302 | end
303 | end
304 | if matches[1]:lower() == "gbanlist" then -- Global ban list
305 | return banall_list()
306 | end
307 | end
308 |
309 | return {
310 | patterns = {
311 | "^[!/]([Bb]anall) (.*)$",
312 | "^[!/]([Bb]anall)$",
313 | "^[!/]([Bb]anlist) (.*)$",
314 | "^[!/]([Bb]anlist)$",
315 | "^[!/]([Gg]banlist)$",
316 | "^[!/]([Bb]an) (.*)$",
317 | "^[!/]([Kk]ick)$",
318 | "^[!/]([Uu]nban) (.*)$",
319 | "^[!/]([Uu]nbanall) (.*)$",
320 | "^[!/]([Uu]nbanall)$",
321 | "^[!/]([Kk]ick) (.*)$",
322 | "^[!/]([Kk]ickme)$",
323 | "^[!/]([Bb]an)$",
324 | "^[!/]([Uu]nban)$",
325 | "^[!/]([Ii]d)$",
326 | "^!!tgservice (.+)$"
327 | },
328 | run = run,
329 | pre_process = pre_process
330 | }
331 |
332 |
--------------------------------------------------------------------------------
/plugins/broadcast.lua:
--------------------------------------------------------------------------------
1 | local function run(msg, matches)
2 | if matches[1] == 'bc' and is_admin(msg) then
3 | local response = matches[3]
4 | send_large_msg("chat#id"..matches[2], response)
5 | end
6 | if matches[1] == 'broadcast' then
7 | if is_sudo(msg) then -- Only sudo !
8 | local data = load_data(_config.moderation.data)
9 | local groups = 'groups'
10 | local response = matches[2]
11 | for k,v in pairs(data[tostring(groups)]) do
12 | chat_id = v
13 | local receiver = 'chat#id'..chat_id
14 | send_large_msg(receiver, response)
15 | end
16 | end
17 | end
18 | end
19 | return {
20 | patterns = {
21 | "^[!/](broadcast) +(.+)$",
22 | "^[!/](bc) (%d+) (.*)$"
23 | },
24 | run = run
25 | }
26 |
--------------------------------------------------------------------------------
/plugins/download_media.lua:
--------------------------------------------------------------------------------
1 | local function callback(extra, success, result) -- Calback for load_photo in line 17
2 | if success then
3 | print('File downloaded to:', result)
4 | else
5 | print('Error downloading: '..extra)
6 | end
7 | end
8 |
9 | local function run(msg, matches)
10 | if not is_momod(msg) then -- Will download images only from mods,owner and admins
11 | return
12 | end
13 | if msg.media then
14 | if msg.media.type == 'photo' then
15 | load_photo(msg.id, callback, msg.id)
16 | end
17 | end
18 | end
19 |
20 | local function pre_process(msg)
21 | if not msg.text and msg.media then
22 | msg.text = '['..msg.media.type..']'
23 | end
24 | return msg
25 | end
26 |
27 | return {
28 | run = run,
29 | patterns = {
30 | '%[(photo)%]'
31 | },
32 | pre_process = pre_process
33 | }
34 |
--------------------------------------------------------------------------------
/plugins/get.lua:
--------------------------------------------------------------------------------
1 | local function get_variables_hash(msg)
2 | if msg.to.type == 'chat' then
3 | return 'chat:'..msg.to.id..':variables'
4 | end
5 | end
6 |
7 | local function get_value(msg, var_name)
8 | local hash = get_variables_hash(msg)
9 | if hash then
10 | local value = redis:hget(hash, var_name)
11 | if not value then
12 | return
13 | else
14 | return var_name..' :\n'..value
15 | end
16 | end
17 | end
18 |
19 | local function run(msg, matches)
20 | if not is_momod(msg) then -- only for mods,owner and admins
21 | return
22 | end
23 | if matches[2] then
24 | local name = user_print_name(msg.from)
25 | savelog(msg.to.id, name.." ["..msg.from.id.."] used /get ".. matches[2])-- save to logs
26 | return get_value(msg, matches[2])
27 | else
28 | return
29 | end
30 | end
31 |
32 | return {
33 | patterns = {
34 | "^([!/]get) (.+)$"
35 | },
36 | run = run
37 | }
38 |
--------------------------------------------------------------------------------
/plugins/inpm.lua:
--------------------------------------------------------------------------------
1 | do
2 | local function pairsByKeys (t, f)
3 | local a = {}
4 | for n in pairs(t) do table.insert(a, n) end
5 | table.sort(a, f)
6 | local i = 0 -- iterator variable
7 | local iter = function () -- iterator function
8 | i = i + 1
9 | if a[i] == nil then return nil
10 | else return a[i], t[a[i]]
11 | end
12 | end
13 | return iter
14 | end
15 |
16 | local function chat_list(msg)
17 | local data = load_data(_config.moderation.data)
18 | local groups = 'groups'
19 | if not data[tostring(groups)] then
20 | return 'No groups at the moment'
21 | end
22 | local message = 'List of Groups:\n*Use /join (ID) to join*\n\n '
23 | for k,v in pairs(data[tostring(groups)]) do
24 | local settings = data[tostring(v)]['settings']
25 | for m,n in pairsByKeys(settings) do
26 | if m == 'set_name' then
27 | name = n
28 | end
29 | end
30 |
31 | message = message .. '👥 '.. name .. ' (ID: ' .. v .. ')\n\n '
32 | end
33 | local file = io.open("./groups/lists/listed_groups.txt", "w")
34 | file:write(message)
35 | file:flush()
36 | file:close()
37 | return message
38 | end
39 |
40 | local function run(msg, matches)
41 | if msg.to.type ~= 'chat' or is_sudo(msg) or is_admin(msg) and is_realm(msg) then
42 | local data = load_data(_config.moderation.data)
43 | if matches[1] == 'join' and data[tostring(matches[2])] then
44 | if is_banned(msg.from.id, matches[2]) then
45 | return 'You are banned.'
46 | end
47 | if is_gbanned(msg.from.id) then
48 | return 'You are globally banned.'
49 | end
50 | if data[tostring(matches[2])]['settings']['lock_member'] == 'yes' and not is_owner2(msg.from.id, matches[2]) then
51 | return 'Group is private.'
52 | end
53 | local chat_id = "chat#id"..matches[2]
54 | local user_id = "user#id"..msg.from.id
55 | chat_add_user(chat_id, user_id, ok_cb, false)
56 | local group_name = data[tostring(matches[2])]['settings']['set_name']
57 | return "Added you to chat:\n\n👥"..group_name.." (ID:"..matches[2]..")"
58 | elseif matches[1] == 'join' and not data[tostring(matches[2])] then
59 |
60 | return "Chat not found."
61 | end
62 | if matches[1] == 'chats'then
63 | if is_admin(msg) and msg.to.type == 'chat' then
64 | return chat_list(msg)
65 | elseif msg.to.type ~= 'chat' then
66 | return chat_list(msg)
67 | end
68 | end
69 | if matches[1] == 'chatlist'then
70 | if is_admin(msg) and msg.to.type == 'chat' then
71 | send_document("chat#id"..msg.from.id, "./groups/lists/listed_groups.txt", ok_cb, false)
72 | elseif msg.to.type ~= 'chat' then
73 | send_document("user#id"..msg.from.id, "./groups/lists/listed_groups.txt", ok_cb, false)
74 | end
75 | end
76 | end
77 | end
78 |
79 | return {
80 | patterns = {
81 | "^[/!](chats)$",
82 | "^[/!](chatlist)$",
83 | "^[/!](join) (.*)$",
84 | "^[/!](kickme) (.*)$",
85 | "^!!tgservice (chat_add_user)$"
86 | },
87 | run = run,
88 | }
89 | end
90 |
91 |
--------------------------------------------------------------------------------
/plugins/inrealm.lua:
--------------------------------------------------------------------------------
1 | -- data saved to moderation.json
2 | -- check moderation plugin
3 | do
4 |
5 | local function create_group(msg)
6 | -- superuser and admins only (because sudo are always has privilege)
7 | if is_sudo(msg) or is_realm(msg) and is_admin(msg) then
8 | local group_creator = msg.from.print_name
9 | create_group_chat (group_creator, group_name, ok_cb, false)
10 | return 'Group [ '..string.gsub(group_name, '_', ' ')..' ] has been created.'
11 | end
12 | end
13 |
14 | local function create_realm(msg)
15 | -- superuser and admins only (because sudo are always has privilege)
16 | if is_sudo(msg) or is_realm(msg) and is_admin(msg) then
17 | local group_creator = msg.from.print_name
18 | create_group_chat (group_creator, group_name, ok_cb, false)
19 | return 'Realm [ '..string.gsub(group_name, '_', ' ')..' ] has been created.'
20 | end
21 | end
22 |
23 |
24 | local function killchat(cb_extra, success, result)
25 | local receiver = cb_extra.receiver
26 | local chat_id = "chat#id"..result.id
27 | local chatname = result.print_name
28 | for k,v in pairs(result.members) do
29 | kick_user_any(v.id, result.id)
30 | end
31 | end
32 |
33 | local function killrealm(cb_extra, success, result)
34 | local receiver = cb_extra.receiver
35 | local chat_id = "chat#id"..result.id
36 | local chatname = result.print_name
37 | for k,v in pairs(result.members) do
38 | kick_user_any(v.id, result.id)
39 | end
40 | end
41 |
42 | local function get_group_type(msg)
43 | local data = load_data(_config.moderation.data)
44 | if data[tostring(msg.to.id)] then
45 | if not data[tostring(msg.to.id)]['group_type'] then
46 | return 'No group type available.'
47 | end
48 | local group_type = data[tostring(msg.to.id)]['group_type']
49 | return group_type
50 | else
51 | return 'Chat type not found.'
52 | end
53 | end
54 |
55 | local function callbackres(extra, success, result)
56 | --vardump(result)
57 | local user = result.id
58 | local name = string.gsub(result.print_name, "_", " ")
59 | local chat = 'chat#id'..extra.chatid
60 | send_large_msg(chat, user..'\n'..name)
61 | return user
62 | end
63 |
64 | local function set_description(msg, data, target, about)
65 | if not is_admin(msg) then
66 | return "For admins only!"
67 | end
68 | local data_cat = 'description'
69 | data[tostring(target)][data_cat] = about
70 | save_data(_config.moderation.data, data)
71 | return 'Set group description to:\n'..about
72 | end
73 |
74 | local function set_rules(msg, data, target)
75 | if not is_admin(msg) then
76 | return "For admins only!"
77 | end
78 | local data_cat = 'rules'
79 | data[tostring(target)][data_cat] = rules
80 | save_data(_config.moderation.data, data)
81 | return 'Set group rules to:\n'..rules
82 | end
83 | -- lock/unlock group name. bot automatically change group name when locked
84 | local function lock_group_name(msg, data, target)
85 | if not is_admin(msg) then
86 | return "For admins only!"
87 | end
88 | local group_name_set = data[tostring(target)]['settings']['set_name']
89 | local group_name_lock = data[tostring(target)]['settings']['lock_name']
90 | if group_name_lock == 'yes' then
91 | return 'Group name is already locked'
92 | else
93 | data[tostring(target)]['settings']['lock_name'] = 'yes'
94 | save_data(_config.moderation.data, data)
95 | rename_chat('chat#id'..target, group_name_set, ok_cb, false)
96 | return 'Group name has been locked'
97 | end
98 | end
99 |
100 | local function unlock_group_name(msg, data, target)
101 | if not is_admin(msg) then
102 | return "For admins only!"
103 | end
104 | local group_name_set = data[tostring(target)]['settings']['set_name']
105 | local group_name_lock = data[tostring(target)]['settings']['lock_name']
106 | if group_name_lock == 'no' then
107 | return 'Group name is already unlocked'
108 | else
109 | data[tostring(target)]['settings']['lock_name'] = 'no'
110 | save_data(_config.moderation.data, data)
111 | return 'Group name has been unlocked'
112 | end
113 | end
114 | --lock/unlock group member. bot automatically kick new added user when locked
115 | local function lock_group_member(msg, data, target)
116 | if not is_admin(msg) then
117 | return "For admins only!"
118 | end
119 | local group_member_lock = data[tostring(target)]['settings']['lock_member']
120 | if group_member_lock == 'yes' then
121 | return 'Group members are already locked'
122 | else
123 | data[tostring(target)]['settings']['lock_member'] = 'yes'
124 | save_data(_config.moderation.data, data)
125 | end
126 | return 'Group members has been locked'
127 | end
128 |
129 | local function unlock_group_member(msg, data, target)
130 | if not is_admin(msg) then
131 | return "For admins only!"
132 | end
133 | local group_member_lock = data[tostring(target)]['settings']['lock_member']
134 | if group_member_lock == 'no' then
135 | return 'Group members are not locked'
136 | else
137 | data[tostring(target)]['settings']['lock_member'] = 'no'
138 | save_data(_config.moderation.data, data)
139 | return 'Group members has been unlocked'
140 | end
141 | end
142 |
143 | --lock/unlock group photo. bot automatically keep group photo when locked
144 | local function lock_group_photo(msg, data, target)
145 | if not is_admin(msg) then
146 | return "For admins only!"
147 | end
148 | local group_photo_lock = data[tostring(target)]['settings']['lock_photo']
149 | if group_photo_lock == 'yes' then
150 | return 'Group photo is already locked'
151 | else
152 | data[tostring(target)]['settings']['set_photo'] = 'waiting'
153 | save_data(_config.moderation.data, data)
154 | end
155 | return 'Please send me the group photo now'
156 | end
157 |
158 | local function unlock_group_photo(msg, data, target)
159 | if not is_admin(msg) then
160 | return "For admins only!"
161 | end
162 | local group_photo_lock = data[tostring(target)]['settings']['lock_photo']
163 | if group_photo_lock == 'no' then
164 | return 'Group photo is not locked'
165 | else
166 | data[tostring(target)]['settings']['lock_photo'] = 'no'
167 | save_data(_config.moderation.data, data)
168 | return 'Group photo has been unlocked'
169 | end
170 | end
171 |
172 | local function lock_group_flood(msg, data, target)
173 | if not is_admin(msg) then
174 | return "For admins only!"
175 | end
176 | local group_flood_lock = data[tostring(target)]['settings']['flood']
177 | if group_flood_lock == 'yes' then
178 | return 'Group flood is locked'
179 | else
180 | data[tostring(target)]['settings']['flood'] = 'yes'
181 | save_data(_config.moderation.data, data)
182 | return 'Group flood has been locked'
183 | end
184 | end
185 |
186 | local function unlock_group_flood(msg, data, target)
187 | if not is_admin(msg) then
188 | return "For admins only!"
189 | end
190 | local group_flood_lock = data[tostring(target)]['settings']['flood']
191 | if group_flood_lock == 'no' then
192 | return 'Group flood is not locked'
193 | else
194 | data[tostring(target)]['settings']['flood'] = 'no'
195 | save_data(_config.moderation.data, data)
196 | return 'Group flood has been unlocked'
197 | end
198 | end
199 | -- show group settings
200 | local function show_group_settings(msg, data, target)
201 | local data = load_data(_config.moderation.data, data)
202 | if not is_admin(msg) then
203 | return "For admins only!"
204 | end
205 | local settings = data[tostring(target)]['settings']
206 | local text = "Group settings:\nLock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member
207 | return text
208 | end
209 |
210 | local function returnids(cb_extra, success, result)
211 |
212 | local receiver = cb_extra.receiver
213 | local chat_id = "chat#id"..result.id
214 | local chatname = result.print_name
215 | local text = 'Users in '..string.gsub(chatname,"_"," ")..' ('..result.id..'):'..'\n'..''
216 | for k,v in pairs(result.members) do
217 | if v.print_name then
218 | local username = ""
219 | text = text .. "- " .. string.gsub(v.print_name,"_"," ") .. " (" .. v.id .. ") \n"
220 | end
221 | end
222 | send_large_msg(receiver, text)
223 | local file = io.open("./groups/lists/"..result.id.."memberlist.txt", "w")
224 | file:write(text)
225 | file:flush()
226 | file:close()
227 | end
228 |
229 | local function returnidsfile(cb_extra, success, result)
230 | local receiver = cb_extra.receiver
231 | local chat_id = "chat#id"..result.id
232 | local chatname = result.print_name
233 | local text = 'Users in '..string.gsub(chatname,"_"," ")..' ('..result.id..'):'..'\n'..''
234 | for k,v in pairs(result.members) do
235 | if v.print_name then
236 | local username = ""
237 | text = text .. "- " .. string.gsub(v.print_name,"_"," ") .. " (" .. v.id .. ") \n"
238 | end
239 | end
240 | local file = io.open("./groups/lists/"..result.id.."memberlist.txt", "w")
241 | file:write(text)
242 | file:flush()
243 | file:close()
244 | send_document("chat#id"..result.id,"./groups/lists/"..result.id.."memberlist.txt", ok_cb, false)
245 | end
246 |
247 | local function admin_promote(msg, admin_id)
248 | if not is_sudo(msg) then
249 | return "Access denied!"
250 | end
251 | local admins = 'admins'
252 | if not data[tostring(admins)] then
253 | data[tostring(admins)] = {}
254 | save_data(_config.moderation.data, data)
255 | end
256 | if data[tostring(admins)][tostring(admin_id)] then
257 | return admin_name..' is already an admin.'
258 | end
259 | data[tostring(admins)][tostring(admin_id)] = admin_id
260 | save_data(_config.moderation.data, data)
261 | return admin_id..' has been promoted as admin.'
262 | end
263 |
264 | local function admin_demote(msg, admin_id)
265 | if not is_sudo(msg) then
266 | return "Access denied!"
267 | end
268 | local data = load_data(_config.moderation.data)
269 | local admins = 'admins'
270 | if not data[tostring(admins)] then
271 | data[tostring(admins)] = {}
272 | save_data(_config.moderation.data, data)
273 | end
274 | if not data[tostring(admins)][tostring(admin_id)] then
275 | return admin_id..' is not an admin.'
276 | end
277 | data[tostring(admins)][tostring(admin_id)] = nil
278 | save_data(_config.moderation.data, data)
279 | return admin_id..' has been demoted from admin.'
280 | end
281 |
282 | local function admin_list(msg)
283 | local data = load_data(_config.moderation.data)
284 | local admins = 'admins'
285 | if not data[tostring(admins)] then
286 | data[tostring(admins)] = {}
287 | save_data(_config.moderation.data, data)
288 | end
289 | local message = 'List for Realm admins:\n'
290 | for k,v in pairs(data[tostring(admins)]) do
291 | message = message .. '- (at)' .. v .. ' [' .. k .. '] ' ..'\n'
292 | end
293 | return message
294 | end
295 |
296 | local function groups_list(msg)
297 | local data = load_data(_config.moderation.data)
298 | local groups = 'groups'
299 | if not data[tostring(groups)] then
300 | return 'No groups at the moment'
301 | end
302 | local message = 'List of groups:\n'
303 | for k,v in pairs(data[tostring(groups)]) do
304 | local settings = data[tostring(v)]['settings']
305 | for m,n in pairs(settings) do
306 | if m == 'set_name' then
307 | name = n
308 | end
309 | end
310 | local group_owner = "No owner"
311 | if data[tostring(v)]['set_owner'] then
312 | group_owner = tostring(data[tostring(v)]['set_owner'])
313 | end
314 | local group_link = "No link"
315 | if data[tostring(v)]['settings']['set_link'] then
316 | group_link = data[tostring(v)]['settings']['set_link']
317 | end
318 |
319 | message = message .. '- '.. name .. ' (' .. v .. ') ['..group_owner..'] \n {'..group_link.."}\n"
320 |
321 |
322 | end
323 | local file = io.open("./groups/lists/groups.txt", "w")
324 | file:write(message)
325 | file:flush()
326 | file:close()
327 | return message
328 |
329 | end
330 | local function realms_list(msg)
331 | local data = load_data(_config.moderation.data)
332 | local realms = 'realms'
333 | if not data[tostring(realms)] then
334 | return 'No Realms at the moment'
335 | end
336 | local message = 'List of Realms:\n'
337 | for k,v in pairs(data[tostring(realms)]) do
338 | local settings = data[tostring(v)]['settings']
339 | for m,n in pairs(settings) do
340 | if m == 'set_name' then
341 | name = n
342 | end
343 | end
344 | local group_owner = "No owner"
345 | if data[tostring(v)]['admins_in'] then
346 | group_owner = tostring(data[tostring(v)]['admins_in'])
347 | end
348 | local group_link = "No link"
349 | if data[tostring(v)]['settings']['set_link'] then
350 | group_link = data[tostring(v)]['settings']['set_link']
351 | end
352 | message = message .. '- '.. name .. ' (' .. v .. ') ['..group_owner..'] \n {'..group_link.."}\n"
353 | end
354 | local file = io.open("./groups/lists/realms.txt", "w")
355 | file:write(message)
356 | file:flush()
357 | file:close()
358 | return message
359 | end
360 | local function admin_user_promote(receiver, member_username, member_id)
361 | local data = load_data(_config.moderation.data)
362 | if not data['admins'] then
363 | data['admins'] = {}
364 | save_data(_config.moderation.data, data)
365 | end
366 | if data['admins'][tostring(member_id)] then
367 | return send_large_msg(receiver, member_username..' is already as admin.')
368 | end
369 | data['admins'][tostring(member_id)] = member_username
370 | save_data(_config.moderation.data, data)
371 | return send_large_msg(receiver, '@'..member_username..' has been promoted as admin.')
372 | end
373 |
374 | local function admin_user_demote(receiver, member_username, member_id)
375 | local data = load_data(_config.moderation.data)
376 | if not data['admins'] then
377 | data['admins'] = {}
378 | save_data(_config.moderation.data, data)
379 | end
380 | if not data['admins'][tostring(member_id)] then
381 | return send_large_msg(receiver, member_username..' is not an admin.')
382 | end
383 | data['admins'][tostring(member_id)] = nil
384 | save_data(_config.moderation.data, data)
385 | return send_large_msg(receiver, 'Admin '..member_username..' has been demoted.')
386 | end
387 |
388 |
389 | local function username_id(cb_extra, success, result)
390 | local mod_cmd = cb_extra.mod_cmd
391 | local receiver = cb_extra.receiver
392 | local member = cb_extra.member
393 | local text = 'No user @'..member..' in this group.'
394 | for k,v in pairs(result.members) do
395 | vusername = v.username
396 | if vusername == member then
397 | member_username = member
398 | member_id = v.id
399 | if mod_cmd == 'addadmin' then
400 | return admin_user_promote(receiver, member_username, member_id)
401 | elseif mod_cmd == 'removeadmin' then
402 | return admin_user_demote(receiver, member_username, member_id)
403 | end
404 | end
405 | end
406 | send_large_msg(receiver, text)
407 | end
408 |
409 | local function set_log_group(msg)
410 | if not is_admin(msg) then
411 | return
412 | end
413 | local log_group = data[tostring(groups)][tostring(msg.to.id)]['log_group']
414 | if log_group == 'yes' then
415 | return 'Log group is already set'
416 | else
417 | data[tostring(groups)][tostring(msg.to.id)]['log_group'] = 'yes'
418 | save_data(_config.moderation.data, data)
419 | return 'Log group has been set'
420 | end
421 | end
422 |
423 | local function unset_log_group(msg)
424 | if not is_admin(msg) then
425 | return
426 | end
427 | local log_group = data[tostring(groups)][tostring(msg.to.id)]['log_group']
428 | if log_group == 'no' then
429 | return 'Log group is already disabled'
430 | else
431 | data[tostring(groups)][tostring(msg.to.id)]['log_group'] = 'no'
432 | save_data(_config.moderation.data, data)
433 | return 'log group has been disabled'
434 | end
435 | end
436 |
437 | local function help()
438 | local help_text = tostring(_config.help_text_realm)
439 | return help_text
440 | end
441 |
442 | function run(msg, matches)
443 | --vardump(msg)
444 | local name_log = user_print_name(msg.from)
445 | if matches[1] == 'log' and is_owner(msg) then
446 | savelog(msg.to.id, "log file created by owner")
447 | send_document("chat#id"..msg.to.id,"./groups/"..msg.to.id.."log.txt", ok_cb, false)
448 | end
449 |
450 | if matches[1] == 'who' and is_momod(msg) then
451 | local name = user_print_name(msg.from)
452 | savelog(msg.to.id, name.." ["..msg.from.id.."] requested member list ")
453 | local receiver = get_receiver(msg)
454 | chat_info(receiver, returnidsfile, {receiver=receiver})
455 | end
456 | if matches[1] == 'wholist' and is_momod(msg) then
457 | local name = user_print_name(msg.from)
458 | savelog(msg.to.id, name.." ["..msg.from.id.."] requested member list in a file")
459 | local receiver = get_receiver(msg)
460 | chat_info(receiver, returnids, {receiver=receiver})
461 | end
462 |
463 | if matches[1] == 'creategroup' and matches[2] then
464 | group_name = matches[2]
465 | group_type = 'group'
466 | return create_group(msg)
467 | end
468 |
469 | if not is_sudo(msg) or not is_admin(msg) and not is_realm(msg) then
470 | return --Do nothing
471 | end
472 |
473 | if matches[1] == 'createrealm' and matches[2] then
474 | group_name = matches[2]
475 | group_type = 'realm'
476 | return create_realm(msg)
477 | end
478 |
479 | local data = load_data(_config.moderation.data)
480 | local receiver = get_receiver(msg)
481 | if matches[2] then if data[tostring(matches[2])] then
482 | local settings = data[tostring(matches[2])]['settings']
483 | if matches[1] == 'setabout' and matches[2] then
484 | local target = matches[2]
485 | local about = matches[3]
486 | return set_description(msg, data, target, about)
487 | end
488 | if matches[1] == 'setrules' then
489 | rules = matches[3]
490 | local target = matches[2]
491 | return set_rules(msg, data, target)
492 | end
493 | if matches[1] == 'lock' then --group lock *
494 | local target = matches[2]
495 | if matches[3] == 'name' then
496 | return lock_group_name(msg, data, target)
497 | end
498 | if matches[3] == 'member' then
499 | return lock_group_member(msg, data, target)
500 | end
501 | if matches[3] == 'photo' then
502 | return lock_group_photo(msg, data, target)
503 | end
504 | if matches[3] == 'flood' then
505 | return lock_group_flood(msg, data, target)
506 | end
507 | end
508 | if matches[1] == 'unlock' then --group unlock *
509 | local target = matches[2]
510 | if matches[3] == 'name' then
511 | return unlock_group_name(msg, data, target)
512 | end
513 | if matches[3] == 'member' then
514 | return unlock_group_member(msg, data, target)
515 | end
516 | if matches[3] == 'photo' then
517 | return unlock_group_photo(msg, data, target)
518 | end
519 | if matches[3] == 'flood' then
520 | return unlock_group_flood(msg, data, target)
521 | end
522 | end
523 | if matches[1] == 'settings' and data[tostring(matches[2])]['settings'] then
524 | local target = matches[2]
525 | return show_group_settings(msg, data, target)
526 | end
527 |
528 | if matches[1] == 'setname' and is_realm(msg) then
529 | local new_name = string.gsub(matches[2], '_', ' ')
530 | data[tostring(msg.to.id)]['settings']['set_name'] = new_name
531 | save_data(_config.moderation.data, data)
532 | local group_name_set = data[tostring(msg.to.id)]['settings']['set_name']
533 | local to_rename = 'chat#id'..msg.to.id
534 | rename_chat(to_rename, group_name_set, ok_cb, false)
535 | savelog(msg.to.id, "Realm { "..msg.to.print_name.." } name changed to [ "..new_name.." ] by "..name_log.." ["..msg.from.id.."]")
536 | end
537 | if matches[1] == 'setgpname' and is_admin(msg) then
538 | local new_name = string.gsub(matches[3], '_', ' ')
539 | data[tostring(matches[2])]['settings']['set_name'] = new_name
540 | save_data(_config.moderation.data, data)
541 | local group_name_set = data[tostring(matches[2])]['settings']['set_name']
542 | local to_rename = 'chat#id'..matches[2]
543 | rename_chat(to_rename, group_name_set, ok_cb, false)
544 | savelog(msg.to.id, "Group { "..msg.to.print_name.." } name changed to [ "..new_name.." ] by "..name_log.." ["..msg.from.id.."]")
545 | end
546 |
547 | end
548 | end
549 | if matches[1] == 'help' and is_realm(msg) then
550 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /help")
551 | return help()
552 | end
553 | if matches[1] == 'set' then
554 | if matches[2] == 'loggroup' then
555 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] set as log group")
556 | return set_log_group(msg)
557 | end
558 | end
559 | if matches[1] == 'kill' and matches[2] == 'chat' then
560 | if not is_admin(msg) then
561 | return nil
562 | end
563 | if is_realm(msg) then
564 | local receiver = 'chat#id'..matches[3]
565 | return modrem(msg),
566 | print("Closing Group: "..receiver),
567 | chat_info(receiver, killchat, {receiver=receiver})
568 | else
569 | return 'Error: Group '..matches[3]..' not found'
570 | end
571 | end
572 | if matches[1] == 'kill' and matches[2] == 'realm' then
573 | if not is_admin(msg) then
574 | return nil
575 | end
576 | if is_realm(msg) then
577 | local receiver = 'chat#id'..matches[3]
578 | return realmrem(msg),
579 | print("Closing realm: "..receiver),
580 | chat_info(receiver, killrealm, {receiver=receiver})
581 | else
582 | return 'Error: Realm '..matches[3]..' not found'
583 | end
584 | end
585 | if matches[1] == 'chat_add_user' then
586 | if not msg.service then
587 | return "Are you trying to troll me?"
588 | end
589 | local user = 'user#id'..msg.action.user.id
590 | local chat = 'chat#id'..msg.to.id
591 | if not is_admin(msg) then
592 | chat_del_user(chat, user, ok_cb, true)
593 | end
594 | end
595 | if matches[1] == 'addadmin' then
596 | if string.match(matches[2], '^%d+$') then
597 | local admin_id = matches[2]
598 | print("user "..admin_id.." has been promoted as admin")
599 | return admin_promote(msg, admin_id)
600 | else
601 | local member = string.gsub(matches[2], "@", "")
602 | local mod_cmd = "addadmin"
603 | chat_info(receiver, username_id, {mod_cmd= mod_cmd, receiver=receiver, member=member})
604 | end
605 | end
606 | if matches[1] == 'removeadmin' then
607 | if string.match(matches[2], '^%d+$') then
608 | local admin_id = matches[2]
609 | print("user "..admin_id.." has been demoted")
610 | return admin_demote(msg, admin_id)
611 | else
612 | local member = string.gsub(matches[2], "@", "")
613 | local mod_cmd = "removeadmin"
614 | chat_info(receiver, username_id, {mod_cmd= mod_cmd, receiver=receiver, member=member})
615 | end
616 | end
617 | if matches[1] == 'type'then
618 | local group_type = get_group_type(msg)
619 | return group_type
620 | end
621 | if matches[1] == 'list' and matches[2] == 'admins' then
622 | return admin_list(msg)
623 | end
624 | if matches[1] == 'list' and matches[2] == 'groups' then
625 | if msg.to.type == 'chat' then
626 | groups_list(msg)
627 | send_document("chat#id"..msg.to.id, "./groups/lists/groups.txt", ok_cb, false)
628 | return "Group list created" --group_list(msg)
629 | elseif msg.to.type == 'user' then
630 | groups_list(msg)
631 | send_document("user#id"..msg.from.id, "./groups/lists/groups.txt", ok_cb, false)
632 | return "Group list created" --group_list(msg)
633 | end
634 | end
635 | if matches[1] == 'list' and matches[2] == 'realms' then
636 | if msg.to.type == 'chat' then
637 | realms_list(msg)
638 | send_document("chat#id"..msg.to.id, "./groups/lists/realms.txt", ok_cb, false)
639 | return "Realms list created" --realms_list(msg)
640 | elseif msg.to.type == 'user' then
641 | realms_list(msg)
642 | send_document("user#id"..msg.from.id, "./groups/lists/realms.txt", ok_cb, false)
643 | return "Realms list created" --realms_list(msg)
644 | end
645 | end
646 | if matches[1] == 'res' and is_momod(msg) then
647 | local cbres_extra = {
648 | chatid = msg.to.id
649 | }
650 | local username = matches[2]
651 | local username = username:gsub("@","")
652 | savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /res "..username)
653 | return res_user(username, callbackres, cbres_extra)
654 | end
655 | end
656 |
657 |
658 |
659 | return {
660 | patterns = {
661 | "^[!/](creategroup) (.*)$",
662 | "^[!/](createrealm) (.*)$",
663 | "^[!/](setabout) (%d+) (.*)$",
664 | "^[!/](setrules) (%d+) (.*)$",
665 | "^[!/](setname) (.*)$",
666 | "^[!/](setgpname) (%d+) (.*)$",
667 | "^[!/](setname) (%d+) (.*)$",
668 | "^[!/](lock) (%d+) (.*)$",
669 | "^[!/](unlock) (%d+) (.*)$",
670 | "^[!/](setting) (%d+)$",
671 | "^[!/](wholist)$",
672 | "^[!/](who)$",
673 | "^[!/](type)$",
674 | "^[!/](kill) (chat) (%d+)$",
675 | "^[!/](kill) (realm) (%d+)$",
676 | "^[!/](addadmin) (.*)$", -- sudoers only
677 | "^[!/](removeadmin) (.*)$", -- sudoers only
678 | "^[!/](list) (.*)$",
679 | "^[!/](log)$",
680 | "^[!/](help)$",
681 | "^!!tgservice (.+)$",
682 | },
683 | run = run
684 | }
685 | end
686 |
687 |
688 |
--------------------------------------------------------------------------------
/plugins/invite.lua:
--------------------------------------------------------------------------------
1 | do
2 | local function callbackres(extra, success, result) -- Callback for res_user in line 27
3 | local user = 'user#id'..result.id
4 | local chat = 'chat#id'..extra.chatid
5 | if is_banned(result.id, extra.chatid) then -- Ignore bans
6 | send_large_msg(chat, 'User is banned.')
7 | elseif is_gbanned(result.id) then -- Ignore globall bans
8 | send_large_msg(chat, 'User is globaly banned.')
9 | else
10 | chat_add_user(chat, user, ok_cb, false) -- Add user on chat
11 | end
12 | end
13 | function run(msg, matches)
14 | local data = load_data(_config.moderation.data)
15 | if not is_realm(msg) then
16 | if data[tostring(msg.to.id)] and data[tostring(msg.to.id)]['settings']['lock_member'] == 'yes' and not is_admin(msg) then
17 | return 'Group is private.'
18 | end
19 | end
20 | if msg.to.type ~= 'chat' then
21 | return
22 | end
23 | if not is_momod(msg) then
24 | return
25 | end
26 | --if not is_admin(msg) then -- For admins only !
27 | --return 'Only admins can invite.'
28 | --end
29 | local cbres_extra = {chatid = msg.to.id}
30 | local username = matches[1]
31 | local username = username:gsub("@","")
32 | res_user(username, callbackres, cbres_extra)
33 | end
34 | return {
35 | patterns = {
36 | "^[!/]invite (.*)$"
37 | },
38 | run = run
39 | }
40 |
41 | end
42 |
--------------------------------------------------------------------------------
/plugins/leave_ban.lua:
--------------------------------------------------------------------------------
1 | local function run(msg, matches)
2 | local data = load_data(_config.moderation.data)
3 | if msg.action and msg.action.type then
4 | local action = msg.action.type
5 | if data[tostring(msg.to.id)] then
6 | if data[tostring(msg.to.id)]['settings'] then
7 | if data[tostring(msg.to.id)]['settings']['leave_ban'] then
8 | leave_ban = data[tostring(msg.to.id)]['settings']['leave_ban']
9 | end
10 | end
11 | end
12 | if action == 'chat_del_user' and not is_momod2(msg.action.user.id) and leave_ban == 'yes' then
13 | local user_id = msg.action.user.id
14 | local chat_id = msg.to.id
15 | ban_user(user_id, chat_id)
16 | end
17 | end
18 | end
19 |
20 |
21 | return {
22 | patterns = {
23 | "^!!tgservice (.*)$"
24 | },
25 | run = run
26 | }
27 |
--------------------------------------------------------------------------------
/plugins/onservice.lua:
--------------------------------------------------------------------------------
1 | do
2 | -- Will leave the group if be added
3 | local function run(msg, matches)
4 | local bot_id = our_id -- your bot id
5 | -- like local bot_id = 1234567
6 | if matches[1] == 'leave' and is_admin(msg) then
7 | chat_del_user("chat#id"..msg.to.id, 'user#id'..bot_id, ok_cb, false)
8 | elseif msg.action.type == "chat_add_user" and msg.action.user.id == tonumber(bot_id) and not is_sudo(msg) then
9 | send_large_msg("chat#id"..msg.to.id, 'this is not one of my groups.', ok_cb, false)
10 | chat_del_user("chat#id"..msg.to.id, 'user#id'..bot_id, ok_cb, false)
11 | block_user("user#id"..msg.from.id,ok_cb,false)
12 | end
13 | end
14 |
15 | return {
16 | patterns = {
17 | "^[!/](leave)$",
18 | "^!!tgservice (.+)$",
19 | },
20 | run = run
21 | }
22 | end
23 |
--------------------------------------------------------------------------------
/plugins/owners.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | local function lock_group_namemod(msg, data, target)
4 | local group_name_set = data[tostring(target)]['settings']['set_name']
5 | local group_name_lock = data[tostring(target)]['settings']['lock_name']
6 | if group_name_lock == 'yes' then
7 | return 'Group name is already locked'
8 | else
9 | data[tostring(target)]['settings']['lock_name'] = 'yes'
10 | save_data(_config.moderation.data, data)
11 | rename_chat('chat#id'..target, group_name_set, ok_cb, false)
12 | return 'Group name has been locked'
13 | end
14 | end
15 |
16 | local function unlock_group_namemod(msg, data, target)
17 | local group_name_set = data[tostring(target)]['settings']['set_name']
18 | local group_name_lock = data[tostring(target)]['settings']['lock_name']
19 | if group_name_lock == 'no' then
20 | return 'Group name is already unlocked'
21 | else
22 | data[tostring(target)]['settings']['lock_name'] = 'no'
23 | save_data(_config.moderation.data, data)
24 | return 'Group name has been unlocked'
25 | end
26 | end
27 |
28 | local function lock_group_floodmod(msg, data, target)
29 | local group_flood_lock = data[tostring(target)]['settings']['flood']
30 | if group_flood_lock == 'yes' then
31 | return 'Group flood is locked'
32 | else
33 | data[tostring(target)]['settings']['flood'] = 'yes'
34 | save_data(_config.moderation.data, data)
35 | return 'Group flood has been locked'
36 | end
37 | end
38 |
39 | local function unlock_group_floodmod(msg, data, target)
40 | local group_flood_lock = data[tostring(target)]['settings']['flood']
41 | if group_flood_lock == 'no' then
42 | return 'Group flood is not locked'
43 | else
44 | data[tostring(target)]['settings']['flood'] = 'no'
45 | save_data(_config.moderation.data, data)
46 | return 'Group flood has been unlocked'
47 | end
48 | end
49 |
50 | local function lock_group_membermod(msg, data, target)
51 | local group_member_lock = data[tostring(target)]['settings']['lock_member']
52 | if group_member_lock == 'yes' then
53 | return 'Group members are already locked'
54 | else
55 | data[tostring(target)]['settings']['lock_member'] = 'yes'
56 | save_data(_config.moderation.data, data)
57 | end
58 | return 'Group members has been locked'
59 | end
60 |
61 | local function unlock_group_membermod(msg, data, target)
62 | local group_member_lock = data[tostring(target)]['settings']['lock_member']
63 | if group_member_lock == 'no' then
64 | return 'Group members are not locked'
65 | else
66 | data[tostring(target)]['settings']['lock_member'] = 'no'
67 | save_data(_config.moderation.data, data)
68 | return 'Group members has been unlocked'
69 | end
70 | end
71 |
72 | local function unlock_group_photomod(msg, data, target)
73 | local group_photo_lock = data[tostring(target)]['settings']['lock_photo']
74 | if group_photo_lock == 'no' then
75 | return 'Group photo is not locked'
76 | else
77 | data[tostring(target)]['settings']['lock_photo'] = 'no'
78 | save_data(_config.moderation.data, data)
79 | return 'Group photo has been unlocked'
80 | end
81 | end
82 |
83 | local function show_group_settingsmod(msg, data, target)
84 | local data = load_data(_config.moderation.data)
85 | if data[tostring(msg.to.id)] then
86 | if data[tostring(msg.to.id)]['settings']['flood_msg_max'] then
87 | NUM_MSG_MAX = tonumber(data[tostring(msg.to.id)]['settings']['flood_msg_max'])
88 | print('custom'..NUM_MSG_MAX)
89 | else
90 | NUM_MSG_MAX = 5
91 | end
92 | end
93 | local settings = data[tostring(target)]['settings']
94 | local text = "Group settings:\nLock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member.."\nflood sensitivity : "..NUM_MSG_MAX
95 | return text
96 | end
97 |
98 | local function set_rules(target, rules)
99 | local data = load_data(_config.moderation.data)
100 | local data_cat = 'rules'
101 | data[tostring(target)][data_cat] = rules
102 | save_data(_config.moderation.data, data)
103 | return 'Set group rules to:\n'..rules
104 | end
105 |
106 | local function set_description(target, about)
107 | local data = load_data(_config.moderation.data)
108 | local data_cat = 'description'
109 | data[tostring(target)][data_cat] = about
110 | save_data(_config.moderation.data, data)
111 | return 'Set group description to:\n'..about
112 | end
113 |
114 | local function run(msg, matches)
115 | if msg.to.type ~= 'chat' then
116 | local chat_id = matches[1]
117 | local receiver = get_receiver(msg)
118 | local data = load_data(_config.moderation.data)
119 | if matches[2] == 'ban' then
120 | local chat_id = matches[1]
121 | if not is_owner2(msg.from.id, chat_id) then
122 | return "You are not the owner of this group"
123 | end
124 | if tonumber(matches[3]) == tonumber(our_id) then return false end
125 | local user_id = matches[3]
126 | if tonumber(matches[3]) == tonumber(msg.from.id) then
127 | return "You can't ban yourself"
128 | end
129 | ban_user(matches[3], matches[1])
130 | local name = user_print_name(msg.from)
131 | savelog(matches[1], name.." ["..msg.from.id.."] banned user ".. matches[3])
132 | return 'User '..user_id..' banned'
133 | end
134 | if matches[2] == 'unban' then
135 | if tonumber(matches[3]) == tonumber(our_id) then return false end
136 | local chat_id = matches[1]
137 | if not is_owner2(msg.from.id, chat_id) then
138 | return "You are not the owner of this group"
139 | end
140 | local user_id = matches[3]
141 | if tonumber(matches[3]) == tonumber(msg.from.id) then
142 | return "You can't unban yourself"
143 | end
144 | local hash = 'banned:'..matches[1]
145 | redis:srem(hash, user_id)
146 | local name = user_print_name(msg.from)
147 | savelog(matches[1], name.." ["..msg.from.id.."] unbanned user ".. matches[3])
148 | return 'User '..user_id..' unbanned'
149 | end
150 | if matches[2] == 'kick' then
151 | local chat_id = matches[1]
152 | if not is_owner2(msg.from.id, chat_id) then
153 | return "You are not the owner of this group"
154 | end
155 | if tonumber(matches[3]) == tonumber(our_id) then return false end
156 | local user_id = matches[3]
157 | if tonumber(matches[3]) == tonumber(msg.from.id) then
158 | return "You can't kick yourself"
159 | end
160 | kick_user(matches[3], matches[1])
161 | local name = user_print_name(msg.from)
162 | savelog(matches[1], name.." ["..msg.from.id.."] kicked user ".. matches[3])
163 | return 'User '..user_id..' kicked'
164 | end
165 | if matches[2] == 'clean' then
166 | if matches[3] == 'modlist' then
167 | if not is_owner2(msg.from.id, chat_id) then
168 | return "You are not the owner of this group"
169 | end
170 | for k,v in pairs(data[tostring(matches[1])]['moderators']) do
171 | data[tostring(matches[1])]['moderators'][tostring(k)] = nil
172 | save_data(_config.moderation.data, data)
173 | end
174 | local name = user_print_name(msg.from)
175 | savelog(matches[1], name.." ["..msg.from.id.."] cleaned modlist")
176 | end
177 | if matches[3] == 'rules' then
178 | if not is_owner2(msg.from.id, chat_id) then
179 | return "You are not the owner of this group"
180 | end
181 | local data_cat = 'rules'
182 | data[tostring(matches[1])][data_cat] = nil
183 | save_data(_config.moderation.data, data)
184 | local name = user_print_name(msg.from)
185 | savelog(matches[1], name.." ["..msg.from.id.."] cleaned rules")
186 | end
187 | if matches[3] == 'about' then
188 | if not is_owner2(msg.from.id, chat_id) then
189 | return "You are not the owner of this group"
190 | end
191 | local data_cat = 'description'
192 | data[tostring(matches[1])][data_cat] = nil
193 | save_data(_config.moderation.data, data)
194 | local name = user_print_name(msg.from)
195 | savelog(matches[1], name.." ["..msg.from.id.."] cleaned about")
196 | end
197 | end
198 | if matches[2] == "setflood" then
199 | if not is_owner2(msg.from.id, chat_id) then
200 | return "You are not the owner of this group"
201 | end
202 | if tonumber(matches[3]) < 5 or tonumber(matches[3]) > 20 then
203 | return "Wrong number,range is [5-20]"
204 | end
205 | local flood_max = matches[3]
206 | data[tostring(matches[1])]['settings']['flood_msg_max'] = flood_max
207 | save_data(_config.moderation.data, data)
208 | local name = user_print_name(msg.from)
209 | savelog(matches[1], name.." ["..msg.from.id.."] set flood to ["..matches[3].."]")
210 | return 'Group flood has been set to '..matches[3]
211 | end
212 | if matches[2] == 'lock' then
213 | if not is_owner2(msg.from.id, chat_id) then
214 | return "You are not the owner of this group"
215 | end
216 | local target = matches[1]
217 | if matches[3] == 'name' then
218 | local name = user_print_name(msg.from)
219 | savelog(matches[1], name.." ["..msg.from.id.."] locked name ")
220 | return lock_group_namemod(msg, data, target)
221 | end
222 | if matches[3] == 'member' then
223 | local name = user_print_name(msg.from)
224 | savelog(matches[1], name.." ["..msg.from.id.."] locked member ")
225 | return lock_group_membermod(msg, data, target)
226 | end
227 | end
228 | if matches[2] == 'unlock' then
229 | if not is_owner2(msg.from.id, chat_id) then
230 | return "You are not the owner of this group"
231 | end
232 | local target = matches[1]
233 | if matches[3] == 'name' then
234 | local name = user_print_name(msg.from)
235 | savelog(matches[1], name.." ["..msg.from.id.."] unlocked name ")
236 | return unlock_group_namemod(msg, data, target)
237 | end
238 | if matches[3] == 'member' then
239 | local name = user_print_name(msg.from)
240 | savelog(matches[1], name.." ["..msg.from.id.."] unlocked member ")
241 | return unlock_group_membermod(msg, data, target)
242 | end
243 | end
244 | if matches[2] == 'new' then
245 | if matches[3] == 'link' then
246 | if not is_owner2(msg.from.id, chat_id) then
247 | return "You are not the owner of this group"
248 | end
249 | local function callback (extra , success, result)
250 | local receiver = 'chat#'..matches[1]
251 | vardump(result)
252 | data[tostring(matches[1])]['settings']['set_link'] = result
253 | save_data(_config.moderation.data, data)
254 | return
255 | end
256 | local receiver = 'chat#'..matches[1]
257 | local name = user_print_name(msg.from)
258 | savelog(matches[1], name.." ["..msg.from.id.."] revoked group link ")
259 | export_chat_link(receiver, callback, true)
260 | return "Created a new new link ! \n owner can get it by /owners "..matches[1].." get link"
261 | end
262 | end
263 | if matches[2] == 'get' then
264 | if matches[3] == 'link' then
265 | if not is_owner2(msg.from.id, chat_id) then
266 | return "You are not the owner of this group"
267 | end
268 | local group_link = data[tostring(matches[1])]['settings']['set_link']
269 | if not group_link then
270 | return "Create a link using /newlink first !"
271 | end
272 | local name = user_print_name(msg.from)
273 | savelog(matches[1], name.." ["..msg.from.id.."] requested group link ["..group_link.."]")
274 | return "Group link:\n"..group_link
275 | end
276 | end
277 | if matches[1] == 'changeabout' and matches[2] and is_owner2(msg.from.id, matches[2]) then
278 | local target = matches[2]
279 | local about = matches[3]
280 | local name = user_print_name(msg.from)
281 | savelog(matches[2], name.." ["..msg.from.id.."] has changed group description to ["..matches[3].."]")
282 | return set_description(target, about)
283 | end
284 | if matches[1] == 'changerules' and is_owner2(msg.from.id, matches[2]) then
285 | local rules = matches[3]
286 | local target = matches[2]
287 | local name = user_print_name(msg.from)
288 | savelog(matches[2], name.." ["..msg.from.id.."] has changed group rules to ["..matches[3].."]")
289 | return set_rules(target, rules)
290 | end
291 | if matches[1] == 'changename' and is_owner2(msg.from.id, matches[2]) then
292 | local new_name = string.gsub(matches[3], '_', ' ')
293 | data[tostring(matches[2])]['settings']['set_name'] = new_name
294 | save_data(_config.moderation.data, data)
295 | local group_name_set = data[tostring(matches[2])]['settings']['set_name']
296 | local to_rename = 'chat#id'..matches[2]
297 | local name = user_print_name(msg.from)
298 | savelog(matches[2], "Group {} name changed to [ "..new_name.." ] by "..name.." ["..msg.from.id.."]")
299 | rename_chat(to_rename, group_name_set, ok_cb, false)
300 | end
301 | if matches[1] == 'loggroup' and matches[2] and is_owner2(msg.from.id, matches[2]) then
302 | savelog(matches[2], "------")
303 | send_document("user#id".. msg.from.id,"./groups/logs/"..matches[2].."log.txt", ok_cb, false)
304 | end
305 | end
306 | end
307 | return {
308 | patterns = {
309 | "^[!/]owners (%d+) ([^%s]+) (.*)$",
310 | "^[!/]owners (%d+) ([^%s]+)$",
311 | "^[!/](changeabout) (%d+) (.*)$",
312 | "^[!/](changerules) (%d+) (.*)$",
313 | "^[!/](changename) (%d+) (.*)$",
314 | "^[!/](loggroup) (%d+)$"
315 | },
316 | run = run
317 | }
318 |
--------------------------------------------------------------------------------
/plugins/set.lua:
--------------------------------------------------------------------------------
1 | local function save_value(msg, name, value)
2 | if (not name or not value) then
3 | return "Usage: !set var_name value"
4 | end
5 | local hash = nil
6 | if msg.to.type == 'chat' then
7 | hash = 'chat:'..msg.to.id..':variables'
8 | end
9 | if hash then
10 | redis:hset(hash, name, value)
11 | return "Saved "..name
12 | end
13 | end
14 | local function run(msg, matches)
15 | if not is_momod(msg) then
16 | return "For moderators only!"
17 | end
18 | local name = string.sub(matches[1], 1, 50)
19 | local value = string.sub(matches[2], 1, 1000)
20 | local name1 = user_print_name(msg.from)
21 | savelog(msg.to.id, name1.." ["..msg.from.id.."] saved ["..name.."] as > "..value )
22 | local text = save_value(msg, name, value)
23 | return text
24 | end
25 |
26 | return {
27 | patterns = {
28 | "^[!/]save ([^%s]+) (.+)$"
29 | },
30 | run = run
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/plugins/stats.lua:
--------------------------------------------------------------------------------
1 | do
2 |
3 | -- Returns a table with `name` and `msgs`
4 | local function get_msgs_user_chat(user_id, chat_id)
5 | local user_info = {}
6 | local uhash = 'user:'..user_id
7 | local user = redis:hgetall(uhash)
8 | local um_hash = 'msgs:'..user_id..':'..chat_id
9 | user_info.msgs = tonumber(redis:get(um_hash) or 0)
10 | user_info.name = user_print_name(user)..' ['..user_id..']'
11 | return user_info
12 | end
13 |
14 | local function chat_stats(chat_id)
15 | -- Users on chat
16 | local hash = 'chat:'..chat_id..':users'
17 | local users = redis:smembers(hash)
18 | local users_info = {}
19 | -- Get user info
20 | for i = 1, #users do
21 | local user_id = users[i]
22 | local user_info = get_msgs_user_chat(user_id, chat_id)
23 | table.insert(users_info, user_info)
24 | end
25 | -- Sort users by msgs number
26 | table.sort(users_info, function(a, b)
27 | if a.msgs and b.msgs then
28 | return a.msgs > b.msgs
29 | end
30 | end)
31 | local text = 'users in this chat \n'
32 | for k,user in pairs(users_info) do
33 | text = text..user.name..' = '..user.msgs..'\n'
34 | end
35 | local file = io.open("./groups/lists/"..chat_id.."stats.txt", "w")
36 | file:write(text)
37 | file:flush()
38 | file:close()
39 | send_document("chat#id"..chat_id,"./groups/lists/"..chat_id.."stats.txt", ok_cb, false)
40 | return --text
41 | end
42 |
43 | local function chat_stats2(chat_id)
44 | -- Users on chat
45 | local hash = 'chat:'..chat_id..':users'
46 | local users = redis:smembers(hash)
47 | local users_info = {}
48 |
49 | -- Get user info
50 | for i = 1, #users do
51 | local user_id = users[i]
52 | local user_info = get_msgs_user_chat(user_id, chat_id)
53 | table.insert(users_info, user_info)
54 | end
55 |
56 | -- Sort users by msgs number
57 | table.sort(users_info, function(a, b)
58 | if a.msgs and b.msgs then
59 | return a.msgs > b.msgs
60 | end
61 | end)
62 |
63 | local text = 'users in this chat \n'
64 | for k,user in pairs(users_info) do
65 | text = text..user.name..' = '..user.msgs..'\n'
66 | end
67 | return text
68 | end
69 | -- Save stats, ban user
70 | local function bot_stats()
71 |
72 | local redis_scan = [[
73 | local cursor = '0'
74 | local count = 0
75 |
76 | repeat
77 | local r = redis.call("SCAN", cursor, "MATCH", KEYS[1])
78 | cursor = r[1]
79 | count = count + #r[2]
80 | until cursor == '0'
81 | return count]]
82 |
83 | -- Users
84 | local hash = 'msgs:*:'..our_id
85 | local r = redis:eval(redis_scan, 1, hash)
86 | local text = 'Users: '..r
87 |
88 | hash = 'chat:*:users'
89 | r = redis:eval(redis_scan, 1, hash)
90 | text = text..'\nGroups: '..r
91 | return text
92 | end
93 | local function run(msg, matches)
94 | if matches[1]:lower() == 'teleseed' then -- Put everything you like :)
95 | local about = _config.about_text
96 | local name = user_print_name(msg.from)
97 | savelog(msg.to.id, name.." ["..msg.from.id.."] used /teleseed ")
98 | return about
99 | end
100 | if matches[1]:lower() == "statslist" then
101 | if not is_momod(msg) then
102 | return "For mods only !"
103 | end
104 | local chat_id = msg.to.id
105 | local name = user_print_name(msg.from)
106 | savelog(msg.to.id, name.." ["..msg.from.id.."] requested group stats ")
107 | return chat_stats2(chat_id)
108 | end
109 | if matches[1]:lower() == "stats" then
110 | if not matches[2] then
111 | if not is_momod(msg) then
112 | return "For mods only !"
113 | end
114 | if msg.to.type == 'chat' then
115 | local chat_id = msg.to.id
116 | local name = user_print_name(msg.from)
117 | savelog(msg.to.id, name.." ["..msg.from.id.."] requested group stats ")
118 | return chat_stats(chat_id)
119 | else
120 | return
121 | end
122 | end
123 | if matches[2] == "teleseed" then -- Put everything you like :)
124 | if not is_admin(msg) then
125 | return "For admins only !"
126 | else
127 | return bot_stats()
128 | end
129 | end
130 | if matches[2] == "group" then
131 | if not is_admin(msg) then
132 | return "For admins only !"
133 | else
134 | return chat_stats(matches[3])
135 | end
136 | end
137 | end
138 | end
139 | return {
140 | patterns = {
141 | "^[!/]([Ss]tats)$",
142 | "^[!/]([Ss]tatslist)$",
143 | "^[!/]([Ss]tats) (group) (%d+)",
144 | "^[!/]([Ss]tats) (teleseed)",-- Put everything you like :)
145 | "^[!/]([Tt]eleseed)"-- Put everything you like :)
146 | },
147 | run = run
148 | }
149 |
150 | end
151 |
--------------------------------------------------------------------------------