### # Copyright (c) 2025, Stormux # # This plugin is licensed under the same terms as Limnoria itself. ### import supybot.utils as utils from supybot.commands import * import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks import supybot.world as world import supybot.schedule as schedule import supybot.conf as conf import supybot.ircmsgs as ircmsgs import time import re class Greet(callbacks.Plugin): """ A plugin to greet users when they join a channel. Features flood protection and timeout between greetings. """ def __init__(self, irc): self.__parent = super(Greet, self) self.__parent.__init__(irc) # Dictionary to store last greeting times per user self.lastGreetTime = {} # Default cooldown between greetings for the same user (in seconds) self.userCooldown = 300 # 5 minutes # Debug mode self.debugMode = False def doJoin(self, irc, msg): """ Called when someone joins a channel. """ channel = msg.args[0] nick = msg.nick # Log event for debugging if self.debugMode: self._logDebug(irc, f"JOIN event detected: {nick} joined {channel}") # Don't greet ourselves if nick == irc.nick: if self.debugMode: self._logDebug(irc, f"Not greeting self (bot)") return # Check if greetings are enabled for this channel if not self.registryValue('enabled', channel): if self.debugMode: self._logDebug(irc, f"Greetings disabled for {channel}") return # Get the greeting message for this channel greeting = self.registryValue('message', channel) if not greeting: if self.debugMode: self._logDebug(irc, f"No greeting message set for {channel}") return # Check if this user was greeted recently userKey = f"{nick.lower()}@{channel}" now = time.time() if userKey in self.lastGreetTime: lastTime = self.lastGreetTime[userKey] if now - lastTime < self.userCooldown: if self.debugMode: self._logDebug(irc, f"User {nick} was greeted too recently") return # Get the timeout timeout = self.registryValue('timeout', channel) or 3 if self.debugMode: self._logDebug(irc, f"Will greet in {channel} after {timeout}s: {greeting}") # Update last greet time for this user self.lastGreetTime[userKey] = now # Use a closure to capture the current values def sendGreeting(channelToGreet=channel, greetingMsg=greeting): if self.debugMode: self._logDebug(irc, f"Sending greeting in {channelToGreet}: {greetingMsg}") try: # Make sure the channel is still valid when we send the message if channelToGreet in irc.state.channels: irc.queueMsg(ircmsgs.privmsg(channelToGreet, greetingMsg)) except Exception as e: if self.debugMode: self._logDebug(irc, f"Error sending greeting: {str(e)}") # Schedule the greeting schedule.addEvent(sendGreeting, time.time() + timeout) def _logDebug(self, irc, message): """Send debug messages to the first available channel""" try: # Send to the owner via private message instead of to a channel for owner in self.registryValue('owners') or []: irc.queueMsg(ircmsgs.privmsg(owner, f"[GREET-DEBUG] {message}")) return # Fallback: send to the first available channel for channel in list(irc.state.channels): try: irc.queueMsg(ircmsgs.privmsg(channel, f"[GREET-DEBUG] {message}")) break except: continue except Exception as e: # Last resort, log to Supybot's logs self.log.error(f"Debug logging error: {str(e)}") @wrap(['channel']) def greettest(self, irc, msg, args, channel): """[] Test the greeting by sending it immediately. """ greeting = self.registryValue('message', channel) if greeting: irc.queueMsg(ircmsgs.privmsg(channel, greeting)) irc.replySuccess("Greeting test sent") else: irc.error("No greeting message is set for this channel") @wrap(['owner', 'channel']) def greettrigger(self, irc, msg, args, channel): """[] Simulates a join event with timeout (owner only). """ greeting = self.registryValue('message', channel) if not greeting: irc.error(f"No greeting message is set for {channel}") return # Get the timeout timeout = self.registryValue('timeout', channel) or 3 irc.replySuccess(f"Simulating join event with {timeout}s delay") # Schedule the greeting def sendGreeting(): irc.queueMsg(ircmsgs.privmsg(channel, greeting)) schedule.addEvent(sendGreeting, time.time() + timeout) @wrap(['owner', 'boolean']) def greetdebug(self, irc, msg, args, enable): """ Enables or disables debug mode (owner only). """ self.debugMode = enable if enable: irc.replySuccess("Debug mode enabled") else: irc.replySuccess("Debug mode disabled") @wrap(['channel']) def greeton(self, irc, msg, args, channel): """[] Enables greetings for a channel. """ self.setRegistryValue('enabled', True, channel) greeting = self.registryValue('message', channel) if greeting: irc.replySuccess(f"Greetings enabled for {channel}. Current greeting: \"{greeting}\"") else: irc.error(f"Greetings enabled for {channel}, but no greeting message is set.") @wrap(['channel']) def greetoff(self, irc, msg, args, channel): """[] Disables greetings for a channel. """ self.setRegistryValue('enabled', False, channel) irc.replySuccess(f"Greetings disabled for {channel}.") @wrap(['channel']) def greetclear(self, irc, msg, args, channel): """[] Removes the greeting message for a channel. """ self.setRegistryValue('message', '', channel) self.setRegistryValue('enabled', False, channel) irc.replySuccess(f"Greeting message cleared and disabled for {channel}.") @wrap(['channel']) def greetstatus(self, irc, msg, args, channel): """[] Shows the current greeting status and message for a channel. """ enabled = self.registryValue('enabled', channel) message = self.registryValue('message', channel) timeout = self.registryValue('timeout', channel) or 3 if enabled and message: irc.reply(f"Greetings are enabled for {channel}. Timeout: {timeout} seconds. Message: \"{message}\"") elif enabled and not message: irc.reply(f"Greetings are enabled for {channel}, but no message is set.") else: irc.reply(f"Greetings are disabled for {channel}. Message: \"{message or 'None'}\"") @wrap(['channel', 'positiveInt']) def greettimeout(self, irc, msg, args, channel, seconds): """[] Sets the timeout in seconds between joins before sending a greeting. Default is 3 seconds. """ self.setRegistryValue('timeout', seconds, channel) irc.replySuccess(f"Greeting timeout for {channel} set to {seconds} seconds.") @wrap(['channel', 'text']) def greet(self, irc, msg, args, channel, text): """[] Sets the greeting message for a channel. The greeting will be sent when users join the channel, with flood protection. To manage greetings, use the other commands: greeton - Enables greetings for the channel greetoff - Disables greetings for the channel greetclear - Removes the greeting message for the channel greetdebug on|off - Enables/disables debug mode (owner only) greettest - Immediately sends the greeting to test the message greettrigger - Simulates a join event with timeout (owner only) greetstatus - Shows current status and message greettimeout - Sets delay before greeting Examples: greet #channel Welcome to our channel! """ self.setRegistryValue('message', text, channel) self.setRegistryValue('enabled', True, channel) irc.replySuccess(f"Greeting message for {channel} set to: \"{text}\"") Class = Greet # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: