/usr/lib/python2.7/dist-packages/Mailnag/common/plugins.py is in mailnag 1.0.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | #!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# plugins.py
#
# Copyright 2013, 2014 Patrick Ulbrich <zulu99@gmx.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
import os
import imp
import inspect
import logging
from common.config import cfg_folder
from common.dist_cfg import LIB_DIR
PLUGIN_LIB_PATH = os.path.join(LIB_DIR, 'plugins')
PLUGIN_USER_PATH = os.path.join(cfg_folder, 'plugins')
PLUGIN_PATHS = [ PLUGIN_LIB_PATH, PLUGIN_USER_PATH ]
#
# All known hook types.
#
# TODO : make this class an enum
# when Mailnag is ported to python3
class HookTypes:
# func signature:
# IN: None
# OUT: None
MAIL_CHECK = 'mail-check'
# func signature:
# IN: new mails, all mails
# OUT: None
MAILS_ADDED = 'mails-added'
# func signature:
# IN: remaining mails
# OUT: None
MAILS_REMOVED = 'mails-removed'
# func signature:
# IN: all mails
# OUT: filtered mails
FILTER_MAILS = 'filter-mails'
#
# Registry class for plugin hooks.
#
# Registered hook functions must not block the mailnag daemon.
# Hook functions with an execution time > 1s should be
# implemented non-blocking (i. e. asynchronously).
class HookRegistry:
def __init__(self):
self._hooks = {
HookTypes.MAIL_CHECK : [],
HookTypes.MAILS_ADDED : [],
HookTypes.MAILS_REMOVED : [],
HookTypes.FILTER_MAILS : []
}
def register_hook_func(self, hooktype, func):
self._hooks[hooktype].append(func)
def unregister_hook_func(self, hooktype, func):
self._hooks[hooktype].remove(func)
def get_hook_funcs(self, hooktype):
return self._hooks[hooktype]
# Abstract base class for a MailnagController instance
# passed to plugins.
class MailnagController:
# Returns a HookRegistry object.
def get_hooks(self): pass
# Shuts down the Mailnag process.
# May throw an InvalidOperationException.
def shutdown(self): pass
# Enforces a manual mail check.
# May throw an InvalidOperationException.
def check_for_mails(self): pass
# Marks the mail with specified mail_id as read.
# May throw an InvalidOperationException.
def mark_mail_as_read(self, mail_id): pass
#
# Mailnag Plugin base class
#
class Plugin:
def __init__(self):
# Plugins shouldn't do anything in the constructor.
# They are expected to start living if they are actually
# enabled (i.e. in the enable() method).
# Plugin data isn't enabled yet and call to methods like
# get_mailnag_controller() or get_config().
pass
#
# Abstract methods,
# to be overriden by derived plugin types.
#
def enable(self):
# Plugins are expected to
# register all hooks here.
raise NotImplementedError
def disable(self):
# Plugins are expected to
# unregister all hooks here,
# free all allocated resources,
# and terminate threads (if any).
raise NotImplementedError
def get_manifest(self):
# Plugins are expected to
# return a tuple of the following form:
# (name, description, version, author, mandatory).
raise NotImplementedError
def get_default_config(self):
# Plugins are expected to return a
# dictionary with default values.
raise NotImplementedError
def has_config_ui(self):
# Plugins are expected to return True if
# they provide a configuration widget,
# otherwise they must return False.
raise NotImplementedError
def get_config_ui(self):
# Plugins are expected to
# return a GTK widget here.
# Return None if the plugin
# does not need a config widget.
raise NotImplementedError
def load_ui_from_config(self, config_ui):
# Plugins are expected to
# load their config values (get_config())
# in the widget returned by get_config_ui().
raise NotImplementedError
def save_ui_to_config(self, config_ui):
# Plugins are expected to
# save the config values of the widget
# returned by get_config_ui() to their config
# (get_config()).
raise NotImplementedError
#
# Public methods
#
def init(self, modname, cfg, mailnag_controller):
config = {}
# try to load plugin config
if cfg.has_section(modname):
for name, value in cfg.items(modname):
config[name] = value
# sync with default config
default_config = self.get_default_config()
for k, v in default_config.iteritems():
if not config.has_key(k):
config[k] = v
self._modname = modname
self._config = config
self._mailnag_controller = mailnag_controller
def get_name(self):
name = self.get_manifest()[0]
return name
def get_modname(self):
return self._modname
def get_config(self):
return self._config
#
# Protected methods
#
def get_mailnag_controller(self):
return self._mailnag_controller
#
# Static methods
#
# Note : Plugin instances do not own
# a reference to MailnagController object
# when instantiated in *config mode*.
@staticmethod
def load_plugins(cfg, mailnag_controller = None, filter_names = None):
plugins = []
plugin_types = Plugin._load_plugin_types()
for modname, t in plugin_types:
try:
if (filter_names == None) or (modname in filter_names):
p = t()
p.init(modname, cfg, mailnag_controller)
plugins.append(p)
except:
logging.exception("Failed to instantiate plugin '%s'" % modname)
return plugins
@staticmethod
def _load_plugin_types():
plugin_types = []
for path in PLUGIN_PATHS:
if not os.path.exists(path):
continue
for f in os.listdir(path):
mod = None
modname, ext = os.path.splitext(f)
try:
if ext.lower() == '.py':
if not os.path.exists(os.path.join(path, modname + '.pyc')):
mod = imp.load_source(modname, os.path.join(path, f))
elif ext.lower() == '.pyc':
mod = imp.load_compiled(modname, os.path.join(path, f))
if mod != None:
for t in dir(mod):
t = getattr(mod, t)
if inspect.isclass(t) and \
(inspect.getmodule(t) == mod) and \
issubclass(t, Plugin):
plugin_types.append((modname, t))
except:
logging.exception("Error while opening plugin file '%s'" % f)
return plugin_types
|