diff --git a/plugins/logs/language.hdf b/plugins/logs/language.hdf index 54fb3ef..6af1d81 100644 --- a/plugins/logs/language.hdf +++ b/plugins/logs/language.hdf @@ -7,6 +7,7 @@ Text { ShowAll = Show all messages AtLeastWarnings = Show warnings and errors OnlyErrors = Show errors only + DownloadLogFile = Download complete log AgeOfEvent = Time passed EventText = Description TimeUnits { diff --git a/plugins/logs/logs.py b/plugins/logs/logs.py index 3f30029..3560c0f 100644 --- a/plugins/logs/logs.py +++ b/plugins/logs/logs.py @@ -27,6 +27,7 @@ __revision__ = "$Id" import cryptobox.plugins.base import re import datetime +import cherrypy LOG_LEVELS = [ 'DEBUG', 'INFO', 'NOTICE', 'WARNING', 'ERROR' ] @@ -68,10 +69,24 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin): level = None for (index, line) in enumerate(self.__filter_log_content(lines, size, level)): self.__set_line_hdf_data(self.hdf_prefix + "Content.%d" % index, line) - self.hdf[self.hdf_prefix + "Destination"] = self.cbox.prefs["Log"]["Destination"].lower() + self.hdf[self.hdf_prefix + "Destination"] = \ + self.cbox.prefs["Log"]["Destination"].lower() return "show_log" + @cherrypy.expose + def download(self, **kargs): + """Download the complete log file + + **kargs are necessary - we have to ignore 'weblang' and so on ... + """ + log_file = self.__get_log_destination_file() + if log_file is None: + return "" + else: + return cherrypy.lib.cptools.serveFile(log_file, disposition="attachment", name="cryptobox_logfile.txt") + + def get_status(self): """The current status includes the log configuration details. """ @@ -79,7 +94,7 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin): self.cbox.prefs["Log"]["Level"], self.cbox.prefs["Log"]["Destination"], self.cbox.prefs["Log"]["Details"]) - + def __filter_log_content(self, lines, max_size, level): """Filter, sort and shorten the log content. @@ -122,7 +137,7 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin): if not match: ## we could not parse the line - just return the text without meta info return - ## matching was successfully - we can parse the line for details + ## matching was successful - we can parse the line for details ## calculate time difference of log line (aka: age of event) try: (year, month, day, hour, minute) = match.group( @@ -159,21 +174,31 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin): pass + def __get_log_destination_file(self): + """For non-file log destinations return 'None' and output a warning + """ + try: + if self.cbox.prefs["Log"]["Destination"].upper() == "FILE": + import os + return os.path.abspath(self.cbox.prefs["Log"]["Details"]) + else: + return None + except KeyError: + self.cbox.log.error( + "could not evaluate one of the following config settings: " + + "[Log]->Destination or [Log]->Details") + return None + + def __get_log_data(self, lines=None, max_size=None): """get the most recent log entries of the log file the maximum number and size of these entries can be limited by 'lines' and 'max_size' """ - # return nothing if the currently selected log output is not a file - try: - if self.cbox.prefs["Log"]["Destination"].upper() != "FILE": - return [] - log_file = self.cbox.prefs["Log"]["Details"] - except KeyError: - self.cbox.log.error( - "could not evaluate one of the following config settings: " - + "[Log]->Destination or [Log]->Details") + log_file = self.__get_log_destination_file() + ## return nothing if the currently selected log output is not a file + if log_file is None: return [] try: fdesc = open(log_file, "r") diff --git a/plugins/logs/show_log.cs b/plugins/logs/show_log.cs index 1e442ed..e78c63e 100644 --- a/plugins/logs/show_log.cs +++ b/plugins/logs/show_log.cs @@ -64,6 +64,10 @@ /with ?> + + + diff --git a/plugins/plugin-interface.txt b/plugins/plugin-interface.txt index 98cdbc2..2830193 100644 --- a/plugins/plugin-interface.txt +++ b/plugins/plugin-interface.txt @@ -56,6 +56,7 @@ Python code interface: never get called with an invalid device) - the python module which contains the plugin's class should also contain a class called 'unittests' - it should inherit WebInterfaceTestClass.WebInterfaceTestClass + - method "download" is exposed as "downloads/PLUGINNAME" Language file structure: diff --git a/plugins/plugin_manager/plugin_manager.py b/plugins/plugin_manager/plugin_manager.py index 7a460ac..e3f6f92 100644 --- a/plugins/plugin_manager/plugin_manager.py +++ b/plugins/plugin_manager/plugin_manager.py @@ -139,6 +139,10 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin): (vis_type, ) = pattern.match(key).groups() if vis_type: setting["visibility"].append(vis_type) + ## the plugin_manager _must_ always be visible + if (self.get_name() == name) and (not setting["visibility"]): + ## reset to default + setting["visibility"] = self.plugin_visibility[:] if args.has_key("%s_auth" % name): setting["requestAuth"] = True else: diff --git a/src/cryptobox/plugins/base.py b/src/cryptobox/plugins/base.py index 83f1c6b..e0e4a89 100644 --- a/src/cryptobox/plugins/base.py +++ b/src/cryptobox/plugins/base.py @@ -147,6 +147,13 @@ class CryptoBoxPlugin: return [] + @cherrypy.expose + def download(self, **kargs): + """Deliver a downloadable file - by default return nothing + """ + return "" + + @cherrypy.expose def get_icon(self, image=None, **kargs): """return the image data of the icon of the plugin diff --git a/src/cryptobox/web/sites.py b/src/cryptobox/web/sites.py index 9f665ec..68bf92b 100644 --- a/src/cryptobox/web/sites.py +++ b/src/cryptobox/web/sites.py @@ -58,6 +58,22 @@ class PluginIconHandler: +class PluginDownloadHandler: + """deliver downloadable files of available plugins via cherrypy + + the state (enabled/disabled) and the require-auth setting is ignored + """ + + def __init__(self, plugins): + for plugin in plugins.get_plugins(): + if not plugin: + continue + plname = plugin.get_name() + ## expose the get_icon function of this plugin + setattr(self, plname, plugin.download) + + + class WebInterfaceSites: """handle all http requests and render pages @@ -91,6 +107,9 @@ class WebInterfaceSites: ## publish plugin icons self.icons = PluginIconHandler(self.__plugin_manager) self.icons.exposed = True + ## publish plugin downloads + self.downloads = PluginDownloadHandler(self.__plugin_manager) + self.downloads.exposed = True ## announce that the server started up self.setup() @@ -206,7 +225,7 @@ class WebInterfaceSites: ## invalid base64 string pass except AttributeError: - ## no cherrypy response header defined + ## no cherrypy request header defined pass auth_dict = self.cbox.prefs.user_db["admins"] if user in auth_dict.keys(): @@ -245,6 +264,7 @@ class WebInterfaceSites: return self.return_plugin_action( self.__plugin_manager.get_plugin("disks"))(**param_dict) + def new_http_error_handler(self, error_code, message): """handle http errors gracefully @@ -387,7 +407,7 @@ class WebInterfaceSites: else: return lambda **args: handler(self, **args) - + @cherrypy.expose def test(self, weblang="", help="0", device=None): """test authentication - this function may be safely removed diff --git a/templates/macros.cs b/templates/macros.cs index 8adbf41..e73a335 100644 --- a/templates/macros.cs +++ b/templates/macros.cs @@ -175,8 +175,7 @@ def:reload_link(attr, value) ?>" title=""> " title=""> icon: help