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="">