예제 #1
0
    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__
예제 #2
0
파일: bot.py 프로젝트: Reggi3/jkent-pybot
    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()
예제 #3
0
파일: model.py 프로젝트: linin/micolog
 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)
예제 #4
0
    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()
예제 #5
0
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):
예제 #6
0
파일: bot.py 프로젝트: Reggi3/jkent-pybot
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])
예제 #7
0
    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)
예제 #8
0
파일: model.py 프로젝트: linin/micolog
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()
예제 #9
0
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)