def loadPlugins(self): # check if we are running in a frozen environment (pyinstaller --onefile) if getattr(sys, "frozen", False): bundle_dir = sys._MEIPASS # if we are running in a onefile environment, then copy all plugin to /tmp/... if bundle_dir != os.getcwd(): os.mkdir(os.path.join(bundle_dir, "plugins")) for root, dirs, files in os.walk( os.path.join(os.getcwd(), "plugins")): for file in files: shutil.copy(os.path.join(root, file), os.path.join(bundle_dir, "plugins")) print("copy", file) break # do not copy __pycache__ else: bundle_dir = os.getcwd() plugins_dir = os.path.join(bundle_dir, "plugins") for root, dirs, files in os.walk(plugins_dir): for file in files: modulename, ext = os.path.splitext(file) if ext == ".py": module = import_module("plugins." + modulename) for name, klass in inspect.getmembers( module, inspect.isclass): if klass.__module__ == "plugins." + modulename: instance = klass() if isinstance(instance, GeneratorInterface): Plugins.addGeneratorPlugin(name, instance) instance.setTextEdit(self.text_edit) #instance.registerContenType() break # not to list __pycache__
def __init__(self, core): self.core = core Client.__init__(self, config.host, config.ssl) self.hooks = Hooks() self.plugins = Plugins(self) self.max_trigger = 0 self.install_hooks(self) for name in config.autoload_plugins: self.plugins.load(name) self.nick = None self.channels = [] self.connect()
def __init__(self, parent=None, key_name=None, _app=None, _from_entity=False, **kwds): from plugin import Plugins self.plugins = Plugins(self) db.Model.__init__(self, parent, key_name, _app, _from_entity, **kwds)
def __init__(self, core): self.core = core Client.__init__(self, config.host, config.ssl) self.hooks = Hooks() self.plugins = Plugins(self) self.max_trigger = 0 self.install_hooks(self) self.nick = None self.channels = {} self.allow_rules = {'*': {'ANY': 1}, config.superuser: {'ANY': 1000}} self.deny_rules = {} self._name = '_bot' for name in config.autoload_plugins: self.plugins.load(name) self.connect()
if log_file != '-': handler = logging.handlers.RotatingFileHandler( log_file, maxBytes=int(master_config.get('log_file_size')), backupCount=int(master_config.get('log_file_count'))) handler.setFormatter( logging.Formatter(fmt=master_config.get('log_format'))) logging.getLogger().addHandler(handler) handler_syslog = logging.handlers.SysLogHandler(address=('localhost', 514)) handler_syslog.setFormatter( logging.Formatter(fmt=master_config.get('syslog_format'))) logging.getLogger().addHandler(handler_syslog) loaded_plugins = {} plugins = Plugins() for (plugin, config) in master_config.plugins().items(): (modulename, classname) = plugin.rsplit('.', 1) module = importlib.import_module(modulename) constructor = getattr(module, classname) loaded_plugins[plugin] = constructor(plugins, config) logging.info('Loaded plugin %s from %s', loaded_plugins[plugin].name(), plugin) # Some configuration, to load the port from? endpoint = UNIXServerEndpoint(reactor, './collect-master.sock') socat = None class Socat(protocol.ProcessProtocol): def connectionMade(self):
class Bot(Client): priority = 10 def __init__(self, core): self.core = core Client.__init__(self, config.host, config.ssl) self.hooks = Hooks() self.plugins = Plugins(self) self.max_trigger = 0 self.install_hooks(self) for name in config.autoload_plugins: self.plugins.load(name) self.nick = None self.channels = [] self.connect() def install_hook(self, owner, hook): hooks = owner._hooks = getattr(owner, '_hooks', []) data = hook[4] data['uninstall'] = lambda hook: hooks.remove(hook) self.hooks.install(hook) hooks.append(hook) def uninstall_hook(self, hook): self.hooks.uninstall(hook) def install_hooks(self, owner): priority = getattr(owner, 'priority', 100) for _, method in inspect.getmembers(owner, inspect.ismethod): try: for _type, desc in method.__func__._hooks: if _type == 'command': desc = desc.upper() elif _type == 'trigger': parts = tuple(desc.split()) self.max_trigger = max(self.max_trigger, len(parts)) desc = (len(parts),) + parts hook = self.hooks.create(method, _type, desc, priority) self.install_hook(owner, hook) except AttributeError: pass def uninstall_hooks(self, owner): for hook in owner._hooks[:]: self.uninstall_hook(hook) def call_event(self, event, *args): hooks = self.hooks.find('event', event) Hooks.call(hooks, *args) if event == 'line': line = args[0] msg = Message(line, self) self.call_command(msg.cmd, msg) def call_command(self, command, *args): hooks = self.hooks.find('command', command.upper()) Hooks.call(hooks, *args) if command == 'PRIVMSG': msg = args[0] trigger = self.detect_trigger(msg) if trigger: self.call_trigger(trigger, msg) def detect_trigger(self, msg): text = msg.param[-1] trigger = None if config.directed_triggers: if msg.channel: if text.lower().startswith(self.nick.lower()): nicklen = len(self.nick) if len(text) > nicklen and text[nicklen] in [',', ':']: trigger = text[nicklen + 1:] else: trigger = text else: if text.startswith('!'): trigger = text[1:] return trigger def call_trigger(self, trigger, *args): msg = args[0] for depth in range(self.max_trigger, 0, -1): parts = tuple(trigger.split(None, depth)) desc = (depth,) + parts[:depth] hooks = self.hooks.find('trigger', desc) if not hooks: continue targstr = parts[depth] if len(parts) > depth else '' targs = (' '.join(parts[:depth]),) + tuple(targstr.split()) Hooks.call(hooks, msg, targs, targstr) def set_interval(self, owner, fn, seconds): desc = time() + seconds data = {'seconds': seconds} hook = self.hooks.create(fn, 'timestamp', desc, data=data) self.install_hook(owner, hook) return hook def set_timeout(self, owner, fn, seconds): desc = time() + seconds hook = self.hooks.create(fn, 'timestamp', desc) self.install_hook(owner, hook) return hook def set_timer(self, owner, fn, timestamp): if timestamp <= time(): return None desc = timestamp hook = self.hooks.create(fn, 'timestamp', desc) self.install_hook(owner, hook) return hook def do_tick(self, timestamp): hooks = self.hooks.find('timestamp', 0, timestamp) Hooks.call(hooks, timestamp) for hook in hooks: _, desc, _, _, data = hook seconds = data.get('seconds', None) if seconds: with self.hooks.modify(hook): desc[0] += seconds else: self.hooks.uninstall(hook) def privmsg(self, target, text): self.send('PRIVMSG %s :%s' % (target, text)) def notice(self, target, text): self.send('NOTICE %s :%s' % (target, text)) def join(self, channels, keys=None): if type(channels) == str: channels = (channels,) if channels: channels = ','.join(channels) if keys: keys = ','.join(keys) self.send('JOIN %s %s' % (channels, keys)) else: self.send('JOIN %s' % channels) def part(self, channels, message=None): if type(channels) == str: channels = (channels,) if channels: channels = ','.join(channels) if message: self.send('PART %s :%s' % (channels, message)) else: self.send('PART %s' % channels) @hook def disconnect_event(self): del self.channels[:] @hook def shutdown_event(self, reason): self.send('QUIT :%s' % reason) for name in self.plugins.list(): self.plugins.unload(name, True) @hook def _001_command(self, msg): self.nick = msg.param[0] @hook def join_command(self, msg): if msg.nick == self.nick: self.channels.append(msg.param[0]) @hook def part_command(self, msg): if msg.nick == self.nick: self.channels.remove(msg.param[0]) @hook def kick_command(self, msg): if msg.param[1] == self.nick: self.channels.remove(msg.param[0]) @hook def nick_command(self, msg): if msg.nick == self.nick: self.nick = msg.param[0] @hook def ping_command(self, msg): self.send('PONG :%s' % msg.param[-1])
def createMenus(self): new_icon = QIcon(QPixmap(":/images/new.svg")) open_icon = QIcon(QPixmap(":/images/open.svg")) book_icon = QIcon(QPixmap(":/images/book.svg")) bold_icon = QIcon(QPixmap(":/images/bold.svg")) italic_icon = QIcon(QPixmap(":/images/italic.svg")) image_icon = QIcon(QPixmap(":/images/image.svg")) table_icon = QIcon(QPixmap(":/images/table.svg")) á_icon = QIcon(QPixmap(":/images/á.svg")) ã_icon = QIcon(QPixmap(":/images/ã.svg")) é_icon = QIcon(QPixmap(":/images/é.svg")) ê_icon = QIcon(QPixmap(":/images/ê.svg")) ó_icon = QIcon(QPixmap(":/images/ó.svg")) new_act = QAction(new_icon, "&New", self) new_act.setShortcuts(QKeySequence.New) new_act.setStatusTip("Create a new ebook project") new_act.triggered.connect(self.newFile) new_act.setToolTip("Create new ebook project") open_act = QAction(open_icon, "&Open", self) open_act.setShortcuts(QKeySequence.Open) open_act.setStatusTip("Open an existing ebook project") open_act.triggered.connect(self.open) open_act.setToolTip("Open an existing ebook project") book_act = QAction(book_icon, "&Create Book", self) book_act.setShortcuts(QKeySequence.SaveAs) book_act.setStatusTip("Create an ebook") book_act.triggered.connect(self.create) book_act.setToolTip("Create an ebook") pdf_act = QAction("Create &PDF", self) pdf_act.setStatusTip("Create PDF") pdf_act.setToolTip("Create PDF") pdf_act.triggered.connect(self.pdfExport) settings_act = QAction("&Settings", self) settings_act.setStatusTip("Open settings dialog") settings_act.triggered.connect(self.settingsDialog) settings_act.setToolTip("Open settings dialog") exit_act = QAction("E&xit", self) exit_act.setShortcuts(QKeySequence.Quit) exit_act.setStatusTip("Exit the application") exit_act.triggered.connect(self.close) self.undo_act = QAction("Undo", self) self.undo_act.setShortcut(QKeySequence.Undo) self.undo_act.setEnabled(False) self.undo_act.triggered.connect(self.doUndo) self.redo_act = QAction("Redo", self) self.redo_act.setShortcut(QKeySequence.Redo) self.redo_act.setEnabled(False) self.undo_act.triggered.connect(self.doRedo) self.cut_act = QAction("Cu&t", self) self.cut_act.setShortcut(QKeySequence.Cut) self.cut_act.triggered.connect(self.doCut) self.cut_act.setEnabled(False) self.copy_act = QAction("&Copy", self) self.copy_act.setShortcut(QKeySequence.Copy) self.copy_act.triggered.connect(self.doCopy) self.copy_act.setEnabled(False) self.paste_act = QAction("&Paste", self) self.paste_act.setShortcut(QKeySequence.Paste) self.paste_act.triggered.connect(self.doPaste) self.paste_act.setEnabled(False) bold_act = QAction(bold_icon, "Bold", self) bold_act.setShortcut(Qt.CTRL + Qt.Key_B) bold_act.triggered.connect(self.bold) italic_act = QAction(italic_icon, "Italic", self) italic_act.setShortcut(Qt.CTRL + Qt.Key_I) italic_act.triggered.connect(self.italic) image_act = QAction(image_icon, "Image", self) image_act.setShortcut(Qt.CTRL + Qt.Key_G) image_act.triggered.connect(self.insertImage) image_act.setToolTip("Insert an image") table_act = QAction(table_icon, "Table", self) table_act.setShortcut(Qt.CTRL + Qt.Key_T) table_act.triggered.connect(self.insertTable) table_act.setToolTip("Insert a table") á_act = QAction(á_icon, "á", self) á_act.triggered.connect(self.insertLetterA1) á_act.setToolTip("Insert letter á") ã_act = QAction(ã_icon, "ã", self) ã_act.triggered.connect(self.insertLetterA2) ã_act.setToolTip("Insert letter ã") é_act = QAction(é_icon, "é", self) é_act.triggered.connect(self.insertLetterE1) é_act.setToolTip("Insert letter é") ê_act = QAction(ê_icon, "ê", self) ê_act.triggered.connect(self.insertLetterE2) ê_act.setToolTip("Insert letter ê") ó_act = QAction(ó_icon, "ó", self) ó_act.triggered.connect(self.insertLetterO1) ó_act.setToolTip("Insert letter ó") about_act = QAction("&About", self) about_act.triggered.connect(self.about) about_act.setStatusTip("Show the application's About box") spell_act = QAction("&Spellcheck", self) spell_act.setShortcut(Qt.CTRL + Qt.Key_P) spell_act.triggered.connect(self.spellCheck) spell_act.setStatusTip("Spellcheck") file_menu = self.menuBar().addMenu("&File") file_menu.addAction(new_act) file_menu.addAction(open_act) file_menu.addAction(book_act) file_menu.addAction(pdf_act) file_menu.addSeparator() file_menu.addAction(settings_act) file_menu.addSeparator() file_menu.addAction(exit_act) edit_menu = self.menuBar().addMenu("&Edit") edit_menu.addAction(self.undo_act) edit_menu.addAction(self.redo_act) edit_menu.addSeparator() edit_menu.addAction(self.cut_act) edit_menu.addAction(self.copy_act) edit_menu.addAction(self.paste_act) format_menu = self.menuBar().addMenu("&Format") format_menu.addAction(bold_act) format_menu.addAction(italic_act) insert_menu = self.menuBar().addMenu("&Insert") insert_menu.addAction(image_act) insert_menu.addAction(table_act) for key in Plugins.generatorPluginNames(): gen = Plugins.getGeneratorPlugin(key) if gen: act = QAction(gen.display_name, self) #act.triggered.connect(self.insertTable) #act.setToolTip("Insert a table") insert_menu.addAction(act) act.triggered.connect(gen.menu_action) help_menu = self.menuBar().addMenu("&Help") help_menu.addAction(about_act) help_menu.addAction(spell_act) file_tool_bar = self.addToolBar("File") file_tool_bar.addAction(new_act) file_tool_bar.addAction(open_act) file_tool_bar.addAction(book_act) format_tool_bar = self.addToolBar("Format") format_tool_bar.addAction(bold_act) format_tool_bar.addAction(italic_act) insert_toolbar = self.addToolBar("Insert") insert_toolbar.addAction(image_act) insert_toolbar.addAction(table_act) insert_toolbar.addAction(á_act) insert_toolbar.addAction(ã_act) insert_toolbar.addAction(é_act) insert_toolbar.addAction(ê_act) insert_toolbar.addAction(ó_act)
class Blog(db.Model): owner = db.UserProperty() author = db.StringProperty(default='admin') rpcuser = db.StringProperty(default='admin') rpcpassword = db.StringProperty(default='') description = db.TextProperty() #baseurl = db.StringProperty(multiline=False, default=None) #urlpath = db.StringProperty(multiline=False) title = db.StringProperty(multiline=False, default='Micolog') subtitle = db.StringProperty(multiline=False, default='This is a micro blog.') entrycount = db.IntegerProperty(default=0) posts_per_page = db.IntegerProperty(default=10) feedurl = db.StringProperty(multiline=False, default='/feed') #blogversion = db.StringProperty(multiline=False, default='0.30') theme_name = db.StringProperty(multiline=False, default='default') enable_memcache = db.BooleanProperty(default=False) link_format = db.StringProperty(multiline=False, default='%(year)s/%(month)s/%(day)s/%(post_id)s.html') comment_notify_mail = db.BooleanProperty(default=True) #评论顺序 comments_order = db.IntegerProperty(default=0) #每页评论数 comments_per_page = db.IntegerProperty(default=20) #comment check type 0-No 1-算术 2-验证码 3-客户端计算 comment_check_type = db.IntegerProperty(default=1) #0 default 1 identicon avatar_style = db.IntegerProperty(default=0) blognotice = db.TextProperty(default='') domain = db.StringProperty() show_excerpt = db.BooleanProperty(default=True) version = 1.0 timedelta = db.FloatProperty(default=8.0)# hours language = db.StringProperty(default="en-us") sitemap_entries = db.IntegerProperty(default=30) sitemap_include_category = db.BooleanProperty(default=False) sitemap_include_tag = db.BooleanProperty(default=False) sitemap_ping = db.BooleanProperty(default=False) default_link_format = db.StringProperty(multiline=False, default='post/%(post_id)s') #todo #default_theme = Theme("default") #remove it #allow_pingback = db.BooleanProperty(default=False) #allow_trackback = db.BooleanProperty(default=False) @property def theme (self): return self.get_theme() langs = None application = None @classmethod def getBlog(cls,keyname='default'): blog=memcache.get("gblog") if not blog: blog=Blog.get_by_key_name(keyname) if not blog: blog=Blog(key_name = keyname) blog.InitBlogData() memcache.set("gblog",blog) return blog @property def vkey(self): return str(self.key.id) @property def baseurl(self): return "http://"+self.domain def InitBlogData(self): OptionSet.setValue('PluginActive',[u'googleAnalytics', u'wordpress', u'sys_plugin']) self.domain=os.environ['HTTP_HOST'] self.feedurl=self.baseurl+"/feed" os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' self.admin_essential = False if os.environ.has_key('HTTP_ACCEPT_LANGUAGE'): lang=os.environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0] from django.utils.translation import activate,to_locale self.language=to_locale(lang) self.admin_essential=False #from django.conf import settings #settings._target = None #activate(self.language) self.put() entry=Entry(title="Hello world!".decode('utf8')) entry.content='<p>Welcome to micolog %s. This is your first post. Edit or delete it, then start blogging!</p>'%self.version entry.published=True entry.put() link=Link(href='http://xuming.net',linktext="Xuming's blog".decode('utf8')) link.put() link=Link(href='http://eric.cloud-mes.com/',linktext="Eric Guo's blog".decode('utf8')) link.put() def __init__(self, parent=None, key_name=None, _app=None, _from_entity=False, **kwds): from plugin import Plugins self.plugins = Plugins(self) db.Model.__init__(self, parent, key_name, _app, _from_entity, **kwds) def tigger_filter(self, name, content, *arg1, **arg2): return self.plugins.tigger_filter(name, content, blog=self, *arg1, **arg2) def tigger_action(self, name, *arg1, **arg2): return self.plugins.tigger_action(name, blog=self, *arg1, **arg2) def tigger_urlmap(self, url, *arg1, **arg2): return self.plugins.tigger_urlmap(url, blog=self, *arg1, **arg2) def get_ziplist(self): return self.plugins.get_ziplist(); def save(self): self.put() def initialsetup(self): self.title = 'Your Blog Title' self.subtitle = 'Your Blog Subtitle' def get_theme(self): return Theme(self.theme_name); def get_langs(self): self.langs = LangIterator() return self.langs def cur_language(self): return self.get_langs().getlang(self.language) def rootpath(self): return os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) @vcache("blog.hotposts",args=("count")) def hotposts(self,count=8): return Entry.all().filter('entrytype =', 'post').filter("published =", True).order('-readtimes').fetch(count) @vcache("blog.recentposts",args=("count")) def recentposts(self,count=8): return Entry.all().filter('entrytype =', 'post').filter("published =", True).order('-date').fetch(count) @vcache("blog.postscount") def postscount(self): return Entry.all().filter('entrytype =', 'post').filter("published =", True).order('-date').count() @vcache("blog.sticky_entries") def sticky_entries(self): return Entry.all().filter('entrytype =','post')\ .filter('published =',True)\ .filter('sticky =',True)\ .order('-date') @vcache("blog.get_entries_paged",args=("entrytype","published","pindex","size")) def get_entries_paged(self,entrytype='post',published=True,pindex=1,size=20): return Entry.all().filter('entrytype =',entrytype).\ filter("published =", published).order('-sticky').order('-date').\ fetch(size, offset = (pindex-1) * size) @vcache("blog.get_blogrolls") def blogrolls(self): return Link.all().filter('linktype =','blogroll') @vcache("blog.get_archives") def archives(self): return Archive.all().order('-year').order('-month').fetch(12) @vcache("blog.get_alltags") def tags(self): return Tag.all() @vcache("blog.recent_comments",args=("count")) def recent_comments(self,count=5): return Comment.all().order('-date').fetch(count) @vcache("blog.get_categories") def categories(self): return Category.all()
class Bot(Client): default_priority = 100 def __init__(self, core): self.core = core Client.__init__(self, config.host, config.ssl) self.hooks = Hooks() self.plugins = Plugins(self) self.max_trigger = 0 self.install_hooks(self) self.nick = None self.channels = {} self.allow_rules = {'*': {'ANY': 1}, config.superuser: {'ANY': 1000}} self.deny_rules = {} self._name = '_bot' for name in config.autoload_plugins: self.plugins.load(name) self.connect() def install_hook(self, owner, hook): hooks = owner._hooks = getattr(owner, '_hooks', []) data = hook[4] data['uninstall'] = lambda hook: hooks.remove(hook) self.hooks.install(hook) hooks.append(hook) def uninstall_hook(self, hook): self.hooks.uninstall(hook) def install_hooks(self, owner): default_priority = getattr(owner, 'default_priority', 500) default_level = getattr(owner, 'default_level', 1) for _, method in inspect.getmembers(owner, inspect.ismethod): try: for _type, desc in method.__func__._hooks: if _type == 'command': desc = desc.upper() elif _type == 'trigger': parts = tuple(desc.split()) self.max_trigger = max(self.max_trigger, len(parts)) desc = (len(parts),) + parts try: method.__func__._level except AttributeError: method.__func__._level = default_level try: priority = method.__func__._priority except AttributeError: priority = default_priority hook = self.hooks.create(method, _type, desc, priority) self.install_hook(owner, hook) except AttributeError: pass def uninstall_hooks(self, owner): try: hooks = owner._hooks[:] except AttributeError: return for hook in hooks: self.uninstall_hook(hook) def call_event(self, event, *args): hooks = self.hooks.find('event', event) Hooks.call(hooks, *args) if event == 'line': line = args[0] msg = Message(line, self) self.call_command(msg.cmd, msg) def call_command(self, command, *args): if command in ('NOTICE', 'PRIVMSG'): self.apply_permissions(args[0]) if command == 'PRIVMSG': self.process_privmsg(args[0]) hooks = self.hooks.find('command', command.upper()) Hooks.call(hooks, *args) def apply_permissions(self, msg): msg.permissions = {} for pattern, rules in self.allow_rules.items(): regex = '^' + re.escape(pattern).replace('\\*', '.*') + '$' if not re.match(regex, msg.prefix): continue for plugin, level in rules.items(): current_level = msg.permissions.get(plugin, level) msg.permissions[plugin] = max(level, current_level) for pattern, rules in self.deny_rules.items(): regex = '^' + re.escape(pattern).replace('\\*', '.*') + '$' if not re.match(regex, msg.prefix): continue for plugin, level in rules.items(): if plugin == 'ANY': for plugin, current_level in msg.permissions.items(): msg.permissions[plugin] = min(level, current_level) continue current_level = msg.permissions.get(plugin, level) msg.permissions[plugin] = min(level, current_level) def process_privmsg(self, msg): trigger = self.detect_trigger(msg) if trigger: msg.trigger = True self.call_trigger(trigger, msg) elif msg.channel: for match in url_re.finditer(msg.param[1]): url = match.group(0) if not url.startswith(('http:', 'https:')): url = 'http://' + url self.do_url(msg, url) def detect_trigger(self, msg): text = msg.param[-1] trigger = None if config.directed_triggers: if msg.channel: if text.lower().startswith(self.nick.lower()): nicklen = len(self.nick) if len(text) > nicklen and text[nicklen] in [',', ':']: trigger = text[nicklen + 1:] else: trigger = text else: if text.startswith('!'): trigger = text[1:] return trigger def call_trigger(self, trigger, *args): authorized = True msg = args[0] for depth in range(self.max_trigger, 0, -1): parts = tuple(trigger.split(None, depth)) desc = (depth,) + parts[:depth] hooks = self.hooks.find('trigger', desc) if not hooks: continue for i, hook in enumerate(hooks): plugin = hook[3].im_self._name level = hook[3]._level if level > max(msg.permissions.get('ANY', 0), msg.permissions.get(plugin, 0)): del hooks[i] authorized = False if not hooks: continue targstr = parts[depth] if len(parts) > depth else u'' targs = (' '.join(parts[:depth]),) + tuple(targstr.split()) if Hooks.call(hooks, msg, targs, targstr): break if not authorized: msg.reply("You don't have permission to use that trigger") def set_interval(self, owner, fn, seconds): desc = time() + seconds data = {'seconds': seconds} hook = self.hooks.create(fn, 'timestamp', desc, data=data) self.install_hook(owner, hook) return hook def set_timeout(self, owner, fn, seconds): desc = time() + seconds hook = self.hooks.create(fn, 'timestamp', desc) self.install_hook(owner, hook) return hook def set_timer(self, owner, fn, timestamp): if timestamp <= time(): return None desc = timestamp hook = self.hooks.create(fn, 'timestamp', desc) self.install_hook(owner, hook) return hook def do_tick(self, timestamp): hooks = self.hooks.find('timestamp', 0, timestamp) Hooks.call(hooks, timestamp) for hook in hooks: _, desc, _, _, data = hook seconds = data.get('seconds', None) if seconds: with self.hooks.modify(hook): desc[0] += seconds else: self.hooks.uninstall(hook) def do_url(self, msg, url): match = domain_re.match(url) if not match: return domain = match.group(1) hooks = self.hooks.find('url', domain) hooks.extend(self.hooks.find('url', domain.replace('.', ' '))) if Hooks.call(hooks, msg, domain, url): return hooks = self.hooks.find('url', 'any') Hooks.call(hooks, msg, domain, url) def privmsg(self, target, text): self.send('PRIVMSG %s :%s' % (target, text)) def notice(self, target, text): self.send('NOTICE %s :%s' % (target, text)) def join(self, channels, keys=None): if isinstance(channels, str): channels = (channels,) if channels: channel_s = ','.join(channels) if keys: if isinstance(keys, str): keys = (keys,) key_s = ','.join(keys) self.send('JOIN %s %s' % (channel_s, key_s)) pairs = zip(channels, keys) for item in pairs: self.channels[item[0]] = {'key': item[1], 'joined': False, 'nicks': set()} else: self.send('JOIN %s' % channel_s) for channel in channels: self.channels[channel] = {'joined': False, 'nicks': set()} def part(self, channels, message=None): if type(channels) == str: channels = (channels,) if channels: channels = ','.join(channels) if message: self.send('PART %s :%s' % (channels, message)) else: self.send('PART %s' % channels) @hook def disconnect_event(self): for _, props in self.channels.items(): props['joined'] = False props['nicks'].clear() @hook @priority(1000) def shutdown_event(self, reason): self.send('QUIT :%s' % reason) for name in self.plugins.list(): self.plugins.unload(name, True) @hook def _001_command(self, msg): self.server = msg.source self.nick = msg.param[0] @hook def _353_command(self, msg): channel = msg.param[2] if self.channels.has_key(channel) and self.channels[channel]['joined']: nicks = self.channels[channel]['nicks'] for nick in msg.param[-1].split(): if nick.startswith(('~', '&', '@', '%', '+')): nicks.add(nick[1:]) else: nicks.add(nick) @hook def join_command(self, msg): channel = msg.param[0] if msg.source == self.nick: if not self.channels.has_key(channel): self.channels[channel] = {} self.channels[channel]['joined'] = True elif self.channels.has_key(channel): self.channels[channel]['nicks'].add(msg.source) @hook def kick_command(self, msg): channel = msg.param[0] if msg.param[1] == self.nick: if self.channels.has_key(channel): self.channels[channel]['joined'] = False if self.channels[channel].has_key('nicks'): self.channels[channel]['nicks'].clear() elif self.channels.has_key(channel): self.channels[channel]['nicks'].remove(msg.source) @hook def nick_command(self, msg): new_nick = msg.param[0] if msg.source == self.nick: self.nick = new_nick for _, props in self.channels.items(): if props.has_key('nicks') and msg.source in props['nicks']: props['nicks'].remove(msg.source) props['nicks'].add(new_nick) @hook @priority(1000) def part_command(self, msg): channel = msg.param[0] if msg.source == self.nick: if self.channels.has_key(channel): self.channels[channel]['joined'] = False if self.channels[channel].has_key('nicks'): self.channels[channel]['nicks'].clear() elif self.channels.has_key(channel): self.channels[channel]['nicks'].remove(msg.source) @hook def ping_command(self, msg): self.send('PONG :%s' % msg.param[-1]) @hook @priority(1000) def quit_command(self, msg): for _, props in self.channels.items(): if props.has_key('nicks') and msg.source in props['nicks']: props['nicks'].remove(msg.source)