Additional IRC commands and bot tasks for EarwigBot https://en.wikipedia.org/wiki/User:EarwigBot
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

132 linhas
5.2 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2021 Ben Kurtovic <ben.kurtovic@gmail.com>
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. # SOFTWARE.
  22. import base64
  23. import cPickle as pickle
  24. import re
  25. from earwigbot.commands import Command
  26. from earwigbot.config.permissions import User
  27. class PartWhen(Command):
  28. """Ask the bot to part the channel when a condition is met."""
  29. name = "partwhen"
  30. commands = ["partwhen", "unpartwhen"]
  31. hooks = ["join", "msg"]
  32. def setup(self):
  33. self._conds = self._load_conditions()
  34. def check(self, data):
  35. if data.is_command and data.command in self.commands:
  36. return True
  37. try:
  38. if data.line[1] == "JOIN":
  39. if data.chan in self._conds and "join" in self._conds[data.chan]:
  40. return True
  41. except IndexError:
  42. pass
  43. return False
  44. def process(self, data):
  45. if data.line[1] == "JOIN":
  46. self._handle_join(data)
  47. return
  48. if not self.config.irc["permissions"].is_admin(data):
  49. self.reply(data, "You must be a bot admin to use this command.")
  50. return
  51. channel = data.chan
  52. args = data.args
  53. if args and args[0].startswith("#"):
  54. # "!partwhen #channel <event> <args>..."
  55. channel = args[0]
  56. args = args[1:]
  57. if data.command == "unpartwhen":
  58. if self._conds.get(channel):
  59. del self._conds[channel]
  60. self._save_conditions()
  61. self.reply(data, "Cleared part conditions for {0}.".format(
  62. "this channel" if channel == data.chan else channel))
  63. else:
  64. self.reply(data, "No part conditions set.")
  65. return
  66. if not args:
  67. conds = self._conds.get(channel, {})
  68. existing = "; ".join("{0} {1}".format(cond, ", ".join(str(user) for user in users))
  69. for cond, users in conds.iteritems())
  70. if existing:
  71. status = "Current part conditions: {0}.".format(existing)
  72. else:
  73. status = "No part conditions set for {0}.".format(
  74. "this channel" if channel == data.chan else channel)
  75. self.reply(data, "{0} Usage: !{1} [<channel>] <event> <args>...".format(
  76. status, data.command))
  77. return
  78. event = args[0]
  79. args = args[1:]
  80. if event == "join":
  81. if not args:
  82. self.reply(data, "Join event requires an argument for the user joining, "
  83. "in nick!ident@host syntax.")
  84. return
  85. cond = args[0]
  86. match = re.match(r"(.*?)!(.*?)@(.*?)$", cond)
  87. if not match:
  88. self.reply(data, "User join pattern is invalid; should use "
  89. "nick!ident@host syntax.")
  90. return
  91. conds = self._conds.setdefault(channel, {}).setdefault("join", [])
  92. conds.append(User(match.group(1), match.group(2), match.group(3)))
  93. self._save_conditions()
  94. self.reply(data, "Okay, I will leave {0} when {1} joins.".format(
  95. "the channel" if channel == data.chan else channel, cond))
  96. else:
  97. self.reply(data, "Unknown event: {0} (valid events: join).".format(event))
  98. def _handle_join(self, data):
  99. user = User(data.nick, data.ident, data.host)
  100. conds = self._conds.get(data.chan, {}).get("join", {})
  101. for cond in conds:
  102. if user in cond:
  103. self.logger.info("Parting {0} because {1} met join condition {2}".format(
  104. data.chan, str(user), str(cond)))
  105. self.part(data.chan, "Requested to leave when {0} joined".format(data.nick))
  106. break
  107. def _load_conditions(self):
  108. permdb = self.config.irc["permissions"]
  109. try:
  110. raw = permdb.get_attr("command:partwhen", "data")
  111. except KeyError:
  112. return {}
  113. return pickle.loads(base64.b64decode(raw))
  114. def _save_conditions(self):
  115. permdb = self.config.irc["permissions"]
  116. raw = base64.b64encode(pickle.dumps(self._conds, pickle.HIGHEST_PROTOCOL))
  117. permdb.set_attr("command:partwhen", "data", raw)