plugin interface implemented

example plugins added: date and network
moved "logs" to plugins
This commit is contained in:
lars 2006-09-12 08:55:20 +00:00
parent 5af79f90b6
commit dba8ca79fd
27 changed files with 483 additions and 174 deletions

View file

@ -26,6 +26,9 @@ class CryptoBox:
put things like logging, conf and oter stuff in here,
that might be used by more classes, it will be passed on to them'''
VERSION = "0.3~1"
def __init__(self, config_file=None):
import CryptoBoxSettings
self.log = self.__getStartupLogger()
@ -141,13 +144,14 @@ class CryptoBoxProps(CryptoBox):
return []
try:
fd = open(log_file, "r")
if maxSize: content = fd.readlines(maxSize)
else: content = fd.readlines()
if maxSize: fd.seek(-maxSize, 2) # seek relative to the end of the file
content = fd.readlines()
fd.close()
except IOError:
self.log.warn("failed to read the log file (%s)" % log_file)
return []
if lines: content = content[-lines:]
content.reverse()
return content

View file

@ -8,6 +8,15 @@ class CryptoBoxError(Exception):
pass
class CBPluginError(CryptoBoxError):
"""should be raised for plugin specific problems"""
class CBPluginActionError(CBPluginError):
"""should be raised when a plugin action failed"""
pass
class CBConfigError(CryptoBoxError):
"""any kind of error related to the configuration of a cryptobox"""
pass

View file

@ -171,6 +171,7 @@ NameDatabase = fileWriteable(default="/var/cache/cryptobox/volumen_names.db")
TemplateDir = directoryExists(default="/usr/share/cryptobox/template")
LangDir = directoryExists(default="/usr/share/cryptobox/lang")
DocDir = directoryExists(default="/usr/share/doc/cryptobox/html")
PluginDir = directoryExists(default="/usr/share/cryptobox/plugins")
[Log]
Level = option("debug", "info", "warn", "error", default="warn")

View file

@ -0,0 +1,76 @@
# $Id$
import imp
import os
import logging
class PluginManager:
"""manage available plugins"""
def __init__(self, plugin_dirs=None):
self.log = logging.getLogger("CryptoBox")
if hasattr(plugin_dirs, "__iter__"):
self.plugin_dirs = [os.path.abspath(dir) for dir in plugin_dirs]
else:
self.plugin_dirs = [os.path.abspath(plugin_dirs)]
def allPlugins(self):
for plfile in self.__getPluginFiles():
yield os.path.basename(plfile)[:-3]
def getPlugin(self, name):
for plfile in self.__getPluginFiles():
if name == os.path.basename(plfile)[:-3]:
return imp.load_source(name, plfile)
else:
return None
def getTemplateFileName(self, plname, template_name):
"""return the name of the template file, if it is part of the mentioned plugin
"""
result = [os.path.join(os.path.dirname(cur_file), template_name + ".cs")
for cur_file in self.__getPluginFiles()
if plname == os.path.basename(cur_file)[:-3]]
for templ_file in result:
if os.access(templ_file, os.R_OK) and os.path.isfile(templ_file):
return templ_file
else:
return None
def loadLanguageData(self, hdf, lang="en"):
for plfile in self.__getPluginFiles():
langdir = os.path.join(os.path.dirname(plfile), "lang")
selected_langfile = os.path.join(langdir, lang + ".hdf")
default_langfile = os.path.join(langdir, "en.hdf")
for langfile in (selected_langfile, default_langfile):
if os.access(langfile, os.R_OK):
self.log.debug("Loading plugin language file: %s" % langfile)
hdf.readFile(langfile)
break
else:
self.log.debug("Couldn't find a plugin language file (%s)" % default_langfile)
def __getPluginFiles(self):
result = []
for dir in [os.path.abspath(e) for e in self.plugin_dirs if os.access(e, os.R_OK) and os.path.isdir(e)]:
for plname in [f for f in os.listdir(dir)]:
pldir = os.path.join(dir, plname)
plfile = os.path.join(pldir, plname + ".py")
if os.path.isfile(plfile) and os.access(plfile, os.R_OK):
result.append(plfile)
return result
if __name__ == "__main__":
x = PluginManager("../plugins")
for a in x.allPlugins():
print "Plugin: %s" % a
print x.getPlugin(a).getStatus()

View file

@ -1,7 +1,7 @@
import os
import CryptoBoxContainer
## useful constant for many functions
## useful constant for some functions
CONT_TYPES = CryptoBoxContainer.CryptoBoxContainer.Types
class WebInterfaceDataset(dict):
@ -16,6 +16,31 @@ class WebInterfaceDataset(dict):
self.__setCryptoBoxState()
def setPluginState(self, plugins):
for pl in plugins.allPlugins():
self["Data.Status.Modules." + pl] = plugins.getPlugin(pl).getStatus(self.cbox)
def setCurrentDiskState(self, device):
for container in self.cbox.getContainerList():
if container.getDevice() == device:
isEncrypted = (container.getType() == CONT_TYPES["luks"]) and 1 or 0
isPlain = (container.getType() == CONT_TYPES["plain"]) and 1 or 0
isMounted = container.isMounted() and 1 or 0
self["Data.CurrentDisk.device"] = container.getDevice()
self["Data.CurrentDisk.name"] = container.getName()
self["Data.CurrentDisk.encryption"] = isEncrypted
self["Data.CurrentDisk.plaintext"] = isPlain
self["Data.CurrentDisk.active"] = isMounted
if isMounted:
(size, avail, used) = container.getCapacity()
percent = used / size
self["Data.CurrentDisk.capacity.used"] = used
self["Data.CurrentDisk.capacity.free"] = avail
self["Data.CurrentDisk.capacity.size"] = size
self["Data.CurrentDisk.capacity.percent"] = percent
def __setConfigValues(self):
self["Settings.TemplateDir"] = os.path.abspath(self.prefs["Locations"]["TemplateDir"])
self["Settings.LanguageDir"] = os.path.abspath(self.prefs["Locations"]["LangDir"])
@ -26,6 +51,7 @@ class WebInterfaceDataset(dict):
def __setCryptoBoxState(self):
self["Data.Version"] = self.cbox.VERSION
avail_counter = 0
active_counter = 0
for container in self.cbox.getContainerList():
@ -45,26 +71,6 @@ class WebInterfaceDataset(dict):
## TODO: open issues: Data.Config.AdminPasswordIsSet
def setCurrentDiskState(self, device):
for container in self.cbox.getContainerList():
if container.getDevice() == device:
isEncrypted = (container.getType() == CONT_TYPES["luks"]) and 1 or 0
isPlain = (container.getType() == CONT_TYPES["plain"]) and 1 or 0
isMounted = container.isMounted() and 1 or 0
self["Data.CurrentDisk.device"] = container.getDevice()
self["Data.CurrentDisk.name"] = container.getName()
self["Data.CurrentDisk.encryption"] = isEncrypted
self["Data.CurrentDisk.plaintext"] = isPlain
self["Data.CurrentDisk.active"] = isMounted
if isMounted:
(size, avail, used) = container.getCapacity()
percent = used / size
self["Data.CurrentDisk.capacity.used"] = used
self["Data.CurrentDisk.capacity.free"] = avail
self["Data.CurrentDisk.capacity.size"] = size
self["Data.CurrentDisk.capacity.percent"] = percent
def __getLanguageName(self, lang):
import neo_cgi, neo_util, neo_cs
hdf_path = os.path.join(self.prefs["Locations"]["LangDir"], lang + ".hdf")

View file

@ -1,6 +1,8 @@
import CryptoBox
import WebInterfaceDataset
import re
from Plugins import PluginManager
from CryptoBoxExceptions import *
class WebInterfaceSites:
'''
@ -14,6 +16,16 @@ class WebInterfaceSites:
self.log = logging.getLogger("CryptoBox")
self.prefs = self.cbox.prefs
self.__resetDataset()
self.plugins = PluginManager(self.prefs["Locations"]["PluginDir"])
self.__exposePlugins()
def __exposePlugins(self):
for plname in self.plugins.allPlugins():
self.log.info("Plugin '%s' loaded" % plname)
## this should be the "easiest" way to expose all modules as URLs
setattr(self, "module_" + plname, self.return_module_action(plname))
setattr(getattr(self, "module_" + plname), "exposed", True)
def __resetDataset(self):
@ -65,12 +77,6 @@ class WebInterfaceSites:
return self.__render("show_status")
def config(self,weblang=""):
self.__resetDataset()
self.__setWebLang(weblang)
pass
def doc(self,page="",weblang=""):
'''prints the offline wikipage
'''
@ -86,22 +92,11 @@ class WebInterfaceSites:
self.dataset["Data.Doc.Page"] ="CryptoBoxUser"
return self.__render("show_doc")
def system(self, shutdowntype="", weblang=""):
# TODO: check weblang
def system(self, weblang=""):
self.__resetDataset()
self.__setWebLang(weblang)
if shutdowntype == "reboot":
self.dataset["Data.Success"] = "ReBoot"
self.dataset["Data.Redirect.Action"] = "show_status"
self.dataset["Data.Redirect.Delay"] = "180"
self.log.info("TODO: call function for system reboot")
elif shutdowntype == "poweroff":
self.dataset["Data.Success"] = "PowerOff"
self.log.info("TODO: call function for system shutdown")
else:
self.log.warn("This shutdown-mode (%s) is not supported." % shutdowntype)
return self.__render("form_system")
@ -315,7 +310,27 @@ class WebInterfaceSites:
return self.__render("show_status")
return self.__render("show_volume")
def return_module_action(self, module):
def handler(**args):
self.__resetDataset()
try:
self.__setWebLang(args["weblang"])
del args["weblang"]
except KeyError:
pass
plugin = self.plugins.getPlugin(module)
try:
nextTemplate = plugin.doAction(self.cbox, **args)
except CBPluginActionError, errMsg:
self.log.debug(errMsg)
self.dataset["Data.Warning"] = errMsg
nextTemplate = "empty"
plugin.prepareForm(self.dataset, self.cbox)
return self.__render(nextTemplate, module)
return handler
'''
## DONE: these functions are pythonized
#################### show_log #######################
@ -403,7 +418,7 @@ class WebInterfaceSites:
return False
def __render(self, template):
def __render(self, template, module=None):
'''renders from clearsilver templates and returns the resulting html
Gets a dictionary with all settings, nessessary for rendering.
@ -411,7 +426,6 @@ class WebInterfaceSites:
object, that calls this render method. This might be bloat but
this way the render method has always a complete, actual set of values.
'''
import os
try:
import neo_cgi, neo_util, neo_cs
@ -421,7 +435,11 @@ class WebInterfaceSites:
sys.stderr.write(errorMsg)
raise ImportError, errorMsg
self.dataset["Data.Action"] = template
module_cs_file = False
if module:
module_cs_file = self.plugins.getTemplateFileName(module, template)
default_cs_file = os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs")
self.dataset["Data.TemplateFile"] = module_cs_file or default_cs_file
self.log.info("rendering site: " + template)
cs_path = os.path.join(self.prefs["Locations"]["TemplateDir"], "main.cs")
@ -435,11 +453,16 @@ class WebInterfaceSites:
log.error("Couldn't read language file: %s" % hdf_path)
return "Couldn't read language file: %s" % hdf_path
## add the current state of the plugins to the hdf dataset
self.dataset.setPluginState(self.plugins)
hdf = neo_util.HDF()
hdf.readFile(hdf_path)
self.log.debug(self.dataset)
for key in self.dataset.keys():
hdf.setValue(key,str(self.dataset[key]))
## load languaga data of plugins
self.plugins.loadLanguageData(hdf, lang=self.dataset["Settings.Language"])
cs = neo_cs.CS(hdf)
cs.parseFile(cs_path)
return cs.render()
@ -462,6 +485,7 @@ class WebInterfaceSites:
test.exposed = True
"""
## TODO: check this before anything else
if self.cbox.getAvailableDocLanguages():

View file

@ -32,6 +32,11 @@ LangDir = ../lang
#DocDir = /usr/share/doc/cryptobox/html
DocDir = ../doc/html
# path to the plugin directory
#PluginDir = /usr/share/cryptobox/plugins
PluginDir = ../plugins
[Log]
# possible values are "debug", "info", "warn" and "error" or numbers from

View file

@ -48,6 +48,7 @@ MountParentDir = %s
TemplateDir = ../templates
LangDir = ../lang
DocDir = ../doc/html
PluginDir = ../plugins
[Log]
Level = debug
Destination = file

View file

@ -134,36 +134,11 @@ Lang {
Text = Die ausgewählte Sprache ist nicht verfügbar!
}
InvalidIP {
Title = Ungültige IP
Text = Die ausgewählte Netzwerkadresse ist nicht gültig!
}
InvalidTimeOut {
Title = Ungültige Zeitabschaltung
Text = Der ausgewählte Wert der Zeitabschaltung ist nicht gültig!
}
ConfigTimeOutFailed {
Title = Fehler beim Ändern der Zeitabschaltung
Text = Der Wert der Zeitabschaltung konnte nicht geändert werden!
}
ConfigLanguageFailed {
Title = Fehler beim Ändern der Spracheinstellung
Text = Die Spracheinstellung konnte nicht geändert werden!
}
ConfigIPFailed {
Title = Fehler beim Ändern der Netzwerkadresse
Text = Die Netzwerkadresse konnte nicht geändert werden!
}
IPAddressChanged {
Title = Änderung der Netzwerk-Adresse
Text = Die Netzwerk-Adresse der CryptoBox wurde verändert. In wenigen Sekunden werden sie zu der neuen Adresse umgeleitet.
}
NoDiskAvailableForMount {
Title = Kein Daten-Container verfügbar
Text = Es ist kein inaktiver Daten-Container verfügbar. Vielleicht sind bereits alle Container aktiv?

View file

@ -11,7 +11,6 @@ Lang {
Mount = Activation of encrypted data
Umount = Deactivation of encrypted data
Config = CryptoBox configuration
Log = CryptoBox logfiles
System = System
Status = Status
Volume = Properties of
@ -31,7 +30,6 @@ Lang {
PartitionInfo = Current partioning of the disk:
IPAddress = Network address (IP) of the CryptoBox:
TimeOut = Timeout for deactivation of the encrypted filesystem (in minutes):
EmptyLog = The logfiles of the CryptoBox are empty.
SelectLanguage = Language preferences:
RedirectNote = Click here if your browser does not support automatic redirection.
ProjectHomePage = Website of project
@ -59,7 +57,6 @@ Lang {
Config = Configuration
PowerOff = Shutdown
ReBoot = Reboot
Protocol = Show logfiles
Documentation = Help
Status = Status
System = System
@ -134,35 +131,12 @@ Lang {
Text = The selected language is not available!
}
InvalidIP {
Title = Invalid IP address
Text = The selected network address is not valid!
}
InvalidTimeOut {
Title = Invalid timeout
Text = The selected timeout is not valid!
}
ConfigTimeOutFailed {
Title = Error during change of timeout
Text = The timeout value could not be changed!
}
ConfigLanguageFailed {
Title = Error during change of language preferences
Text = The language preferences could not be changed!
}
ConfigIPFailed {
Title = Error during change of network address
Text = The network address could not be changed!
}
IPAddressChanged {
Title = Change of network address
Text = The network address has been changed. In a few seconds you will get redirected to the new address.
}
NoDiskAvailableForMount {
Title = No partition available

View file

@ -125,35 +125,10 @@ Lang {
Text = Izbrani jezik ni na voljo!
}
InvalidIP {
Title = Napačen IP naslov
Text = Izbran omrežni naslov ni veljaven!
}
InvalidTimeOut {
Title = Nepravilen čas preklica
Text = Izbran čas preklica ni veljaven!
}
ConfigTimeOutFailed {
Title = Napaka med spremembo časa preklica
Text = Časa preklica ne morete spremeniti!
}
ConfigLanguageFailed {
Title = Napaka med spremembo jezikovnih nastavitev
Text = Spreminjanje jezikovnih nastavitev ni mogoče.
}
ConfigIPFailed {
Title = Napaka med spreminjanjem omrežnega naslova.
Text = Spreminjanje omrežnega naslova ni mogoče.
}
IPAddressChanged {
Title = Sprememba omrežnega naslova
Text = Omrežni naslov je spremenjen. V nekaj sekundah boste preusmerjeni na nov naslov.
}
}

View file

@ -0,0 +1,36 @@
from CryptoBoxExceptions import CBPluginActionError
def prepareForm(hdf, cbox):
date = __getCurrentDate()
hdf["Data.Modules.date.year"] = date.year
hdf["Data.Modules.date.month"] = date.month
hdf["Data.Modules.date.day"] = date.day
hdf["Data.Modules.date.hour"] = date.hour
hdf["Data.Modules.date.minute"] = date.minute
def doAction(cbox, store=None, year=0, month=0, day=0, hour=0, minute=0):
import datetime
if store:
try:
year, month, day = int(year), int(month), int(day)
hour, minute = int(hour), int(minute)
new_date = datetime.datetime(year, month, day, hour, minute)
except ValueError:
raise CBPluginActionError, "InvalidDate"
# TODO: how to set the current time? (and how to become root?)
## we will continue with the system menue
return "form_system"
else:
return "form_date"
def getStatus(cbox):
return str(__getCurrentDate())
def __getCurrentDate():
import datetime
return datetime.datetime(2000,1,1).now()

View file

@ -0,0 +1,42 @@
<?cs # $Id$ ?>
<h1><?cs var:html_escape(Lang.Title.ConfigDate) ?></h1>
<?cs call:print_form_header("module_date") ?>
<p><label for="date"><?cs var:html_escape(Lang.Text.Date) ?>: </label><br/>
<select name="day" size="0"><?cs
loop: x = #1, #31, #1 ?>
<?cs if:x == Data.Modules.date.day ?><option selected="selected"><?cs
else ?><option><?cs /if ?><?cs var:x ?></option><?cs /loop ?>
</select>
<select name="month" size="0"><?cs
loop: x = #1, #12, #1 ?>
<?cs if:x == Data.Modules.date.month ?><option selected="selected" <?cs
else ?><option <?cs /if ?>value="<?cs var:x ?>"><?cs
var:html_escape(Lang.Text.Months[x]) ?></option><?cs /loop ?>
</select>
<select name="year" size="0"><?cs
loop: x = #2006, #2025, #1 ?>
<?cs if:x == Data.Modules.date.year ?><option selected="selected"><?cs
else ?><option><?cs /if ?><?cs var:x ?></option><?cs /loop ?>
</select></p>
<p><label for="time"><?cs var:html_escape(Lang.Text.Time) ?>: </label><br/>
<select name="hour" size="0"><?cs
loop: x = #0, #23, #1 ?>
<?cs if:x == Data.Modules.date.hour ?><option selected="selected"><?cs
else ?><option><?cs /if ?><?cs if:x<10 ?>0<?cs /if ?><?cs var:x ?></option><?cs /loop ?>
</select>&nbsp;:&nbsp;
<select name="minute" size="0"><?cs
loop: x = #0, #59, #1 ?>
<?cs if:x == Data.Modules.date.minute ?><option selected="selected"><?cs
else ?><option><?cs /if ?><?cs if:x<10 ?>0<?cs /if ?><?cs var:x ?></option><?cs /loop ?>
</select></p>
<input type="hidden" name="store" value="yes" />
<button type="submit"><?cs var:html_escape(Lang.Button.ConfigDate) ?></button>
</form>

View file

@ -0,0 +1,35 @@
Lang {
Title.ConfigDate = Date and time setting
Button.ConfigDate = Set date and time
Text.Date = Date
Text.Time = Time
Text.Months {
1 = January
2 = February
3 = March
4 = April
5 = May
6 = June
7 = July
8 = August
9 = September
10 = October
11 = November
12 = December
}
Modules.date {
Name = Change date and time
Link = Set date/time
Rank = 10
}
WarningMessage.InvalidDate {
Title = Invalid value
Text = An invalid value for date or time was supplied. Please try again.
}
}

View file

@ -0,0 +1,13 @@
Lang {
Title.Log = CryptoBox logfiles
Text.EmptyLog = The logfile of the CryptoBox is empty.
Modules.logs {
Name = Show the content of the log file
Link = Show the log file
Rank = 90
}
}

View file

@ -0,0 +1,21 @@
from CryptoBoxExceptions import CBPluginActionError
def prepareForm(hdf, cbox):
hdf["Data.Modules.logs.Content"] = __getLogContent(cbox)
def doAction(cbox):
return "show_log"
def getStatus(cbox):
return "%s:%s:%s" % (
cbox.prefs["Log"]["Level"],
cbox.prefs["Log"]["Destination"],
cbox.prefs["Log"]["Details"])
def __getLogContent(cbox, lines=30, maxSize=2000):
return "<br/>".join(cbox.getLogData(lines, maxSize))

View file

@ -0,0 +1,13 @@
<?cs # $Id: show_log.cs 374 2006-05-30 18:47:34Z lars $ ?>
<div id="log">
<h1><?cs var:html_escape(Lang.Title.Log) ?></h1>
<?cs if:Data.Modules.logs.Content ?>
<p class="console"><?cs var:Data.Modules.logs.Content ?></p>
<?cs else ?>
<p><?cs var:html_escape(Lang.Text.EmptyLog) ?></p>
<?cs /if ?>
</div>

View file

@ -0,0 +1,22 @@
<?cs # $Id$ ?>
<h1><?cs var:html_escape(Lang.Title.Network) ?></h1>
<?cs call:print_form_header("module_network") ?>
<p><label for="ip"><?cs var:html_escape(Lang.Text.IP) ?>: </label><br/>
<input type="text" name="ip1" size="3" id="ip" value="<?cs
var:Data.Modules.network.ip.oc1 ?>" />.
<input type="text" name="ip2" size="3" value="<?cs
var:Data.Modules.network.ip.oc2 ?>" />.
<input type="text" name="ip3" size="3" value="<?cs
var:Data.Modules.network.ip.oc3 ?>" />.
<input type="text" name="ip4" size="3" value="<?cs
var:Data.Modules.network.ip.oc4 ?>" /></p>
<input type="hidden" name="store" value="yes" />
<button type="submit"><?cs var:html_escape(Lang.Button.Network) ?></button>
</form>

View file

@ -0,0 +1,20 @@
Lang {
Title.Network = Network settings
Button.Network = Update settings
Text.IP = Network address
Modules.network {
Name = Configure network
Link = Configure network
Rank = 30
}
Warning.InvalidIP {
Title = Invalid value
Text = An invalid network address (IP) was supplied. Please try again.
}
}

View file

@ -0,0 +1,33 @@
from CryptoBoxExceptions import CBPluginActionError
def prepareForm(hdf, cbox):
(oc1, oc2, oc3, oc4) = __getCurrentIP()
hdf["Data.Modules.network.ip.oc1"] = oc1
hdf["Data.Modules.network.ip.oc2"] = oc2
hdf["Data.Modules.network.ip.oc3"] = oc3
hdf["Data.Modules.network.ip.oc4"] = oc4
def doAction(cbox, store=None, ip1="", ip2="", ip3="", ip4=""):
if store:
try:
# TODO: check the IP here
pass
except ValueError:
raise CBPluginActionError, "InvalidIP"
# TODO: how to set the new IP? (and how to become root?)
## we will continue with the system menue
return "form_system"
else:
return "form_network"
def getStatus(cbox):
return "%d.%d.%d.%d" % __getCurrentIP()
def __getCurrentIP():
# TODO: for now we only provide a dummy
return (192,168,0,23)

View file

@ -0,0 +1,36 @@
The following directory structure is required:
- python code: plugins/MODULENAME/MODULENAME.py (all lower case is recommended)
- language files: plugins/MODULENAME/lang/(en|de|??).hdf
- clearsilver templates: plugins/MODULENAME/*.cs
Python code interface:
def prepareForm(hdf, cbox):
- here you may add some items to the hdf dataset used by the templates
- the recommended namespace is Data.Modules.MODULENAME.???
def doAction(cbox, store=None, ???):
- this function will get called whenever this module is involved in a request
- all arguments should be optional (e.g. for displaying a form without previous input values)
- the argument "store" should be used to process a form submission (just a recommendation)
- if the processing failed for some reason (invalid input, ...), it should raise a CBPluginException (e.g. CBPluginActionError) - the error message should be the name of a warning message (maybe defined in the plugin specific language file) - e.g. "InvalidDate" for Lang.WarningMessage.InvalidDate
- the return value should be the name of the template that should be displayed after processing (a template file in the module directory takes precedence over global template files)
def def getStatus(cbox):
- returns a string, that described a state connected to this module (e.g. the current date and time (for the "date" plugin)
Language file structure:
- the following values _must_ be defined:
Lang.Modules.MODULENAME.Name (a short description)
Lang.Modules.MODULENAME.Link (the visible text for links to this module)
Lang.Modules.MODULENAME.Rank (defines the order of the plugins displayed)
- all other elements should follow the usual structure of language files
Clearsilver template:
- should start with a "<h1>" tag
- links to the module (e.g. in form headers) could look like the following:
<?cs call:link("module_MODULENAME",'','','','') ?>
- a hidden input field called "store" should be used to indicate a form submission

View file

@ -7,29 +7,31 @@
</div><!-- end of 'words' -->
<div id="footer">
<?cs # Development or not ?>
<?cs if:(Data.Status.DevelopmentMode == 1) ?>
<div id="development">!Development Mode!</div>
<?cs /if ?>
<?cs # Version ?>
v<?cs var:Data.Version ?>&nbsp;&nbsp;
<a href="http://cryptobox.org" title="<?cs var:html_escape(Lang.Text.ProjectHomePage) ?>">CryptoBox-Home</a> <?cs var:html_escape(Lang.Text.ProjectNote) ?>&nbsp;<a href="https://systemausfall.org/senselab" title="systemausfall.org">sense.lab</a>
<?cs # Development or not ?><?cs
if:(Data.Status.DevelopmentMode == 1) ?>
<div id="development">!Development Mode!</div><?cs /if ?>
<?cs var:Data.Version ?>&nbsp;&nbsp;
<a href="http://cryptobox.org" title="<?cs var:html_escape(Lang.Text.ProjectHomePage) ?>">CryptoBox-Home</a>&nbsp;&nbsp;&nbsp;<?cs var:html_escape(Lang.Text.ProjectNote) ?>&nbsp;<a href="https://systemausfall.org/senselab" title="systemausfall.org">sense.lab</a>
</div>
</div>
</div>
</div><!-- end of 'content' -->
</div><!-- end of 'main' -->
<?cs # TODO: update these status settings - most are outdated ... ?>
<!-- CBOX-STATUS-begin - used for validation - do not touch!
Data.Config.IP=<?cs var:Data.Config.IP ?>
Data.Config.Language=<?cs var:Data.Config.Language ?>
Data.Config.TimeOut=<?cs var:Data.Config.TimeOut ?>
Data.Status.Config=<?cs var:Data.Status.Config ?>
Data.Status.InitRunning=<?cs var:Data.Status.InitRunning ?>
Data.Status.IP=<?cs var:Data.Status.IP ?>
Data.Status.Mounted=<?cs var:Data.Status.Mounted ?>
CBOX-STATUS-end -->
Data.Config.IP=<?cs var:html_escape(Data.Config.IP) ?>
Data.Config.Language=<?cs var:html_escape(Data.Config.Language) ?>
Data.Config.TimeOut=<?cs var:html_escape(Data.Config.TimeOut) ?>
Data.Status.Config=<?cs var:html_escape(Data.Status.Config) ?>
Data.Status.InitRunning=<?cs var:html_escape(Data.Status.InitRunning) ?>
Data.Status.IP=<?cs var:html_escape(Data.Status.IP) ?>
Data.Status.Mounted=<?cs var:html_escape(Data.Status.Mounted) ?>
<?cs each:x = Data.Status.Modules ?>Data.Status.Modules.<?cs
var:name(x) ?>=<?cs var: html_escape(x) ?>
<?cs /each
?>CBOX-STATUS-end -->
<?cs # $Revision$ ?>
<!-- $Revision$ -->
</body>
</html>

View file

@ -4,25 +4,24 @@
<p><ul>
<?cs # poweroff ?>
<li><a href="<?cs call:link('system','type','poweroff','','') ?>" title="<?cs var:html_escape(Lang.Button.PowerOff) ?>">
<?cs var:html_escape(Lang.Button.PowerOff) ?></a></li>
<?cs # sort the Plugins - using the most stupid way :) ?>
<?cs loop: order = #0, #100, #1
?><?cs # plugins ?><?cs each:x = Lang.Modules
?><?cs if:x.Rank == order ?>
<li><a href="<?cs call:link('module_' + name(x),'','','','') ?>" title="<?cs
var:html_escape(x.Link) ?>"><?cs var:html_escape(x.Link) ?></a></li><?cs
/if ?><?cs
/each ?><?cs
/loop ?>
<?cs # maybe someone forgot to set the rank of a module: we try to catch them ?>
<?cs # reboot ?>
<li><a href="<?cs call:link('system','type','reboot','','') ?>" title="<?cs
var:html_escape(Lang.Button.ReBoot) ?>"><?cs var:html_escape(Lang.Button.ReBoot) ?></a></li>
<?cs # plugins ?><?cs each:x = Lang.Modules ?><?cs
if:!x.Rank || !(x.Rank >= 0 && x.Rank <= 100) ?>
<li><a href="<?cs call:link('module_' + name(x),'','','','') ?>" title="<?cs
var:html_escape(x.Link) ?>"><?cs var:html_escape(x.Link) ?></a></li><?cs
/if ?><?cs
/each ?>
<?cs # config ?>
<li><a href="<?cs call:link('config_ask','','','','') ?>" title="<?cs
var:html_escape(Lang.Button.Config) ?>"><?cs var:html_escape(Lang.Button.Config) ?></a></li>
<?cs # initialize ?>
<li><a href="<?cs call:link('init_ask','','','','') ?>" title="<?cs
var:html_escape(Lang.Button.DoInit) ?>"><?cs var:html_escape(Lang.Button.DoInit) ?></a></li>
<?cs # show log files ?>
<li><a href="<?cs call:link('logs','','','','') ?>" title="<?cs var:html_escape(Lang.Button.Protocol) ?>"><?cs var:html_escape(Lang.Button.Protocol) ?></a></li>
</ul></p>
</div>

View file

@ -3,14 +3,14 @@
<?cs include:Settings.TemplateDir + '/macros.cs' ?>
<?cs include:Settings.TemplateDir + '/header.cs' ?>
<!-- chosen cryptobox template: <?cs var:Data.Action ?> -->
<!-- chosen cryptobox template: <?cs var:Data.TemplateFile ?> -->
<?cs if:Data.Error ?>
<?cs include:Settings.TemplateDir + '/error.cs' ?>
<?cs else ?>
<?cs if:Data.Warning ?><?cs call:warning(Data.Warning) ?><?cs /if ?>
<?cs if:Data.Success ?><?cs call:success(Data.Success) ?><?cs /if ?>
<?cs include:Settings.TemplateDir + '/' + Data.Action + '.cs' ?>
<?cs include:Data.TemplateFile ?>
<?cs /if ?>
<?cs include:Settings.TemplateDir + '/footer.cs' ?>

View file

@ -1,13 +0,0 @@
<?cs # $Id$ ?>
<div id="log">
<h1><?cs var:html_escape(Lang.Title.Log) ?></h1>
<?cs if:Data.Log ?>
<p class="console"><?cs var:Data.Log ?></p>
<?cs else ?>
<p><?cs var:html_escape(Lang.Text.EmptyLog) ?></p>
<?cs /if ?>
</div>

View file

@ -21,7 +21,7 @@
?>"><?cs var:partition.name ?></a></li><?cs /if ?><?cs /each ?></ul><?cs /if ?>
<?cs if:Data.activeDisksCount < subcount(Data.Disks) ?>
<p><?cs var:html_escape(Lang.Text.PassivePartitions) ?>:
<ul><?cs each:partition = Data.Disks ?><?cs if:partition.active ?>
<ul><?cs each:partition = Data.Disks ?><?cs if:!partition.active ?>
<li><a href="<?cs call:link('show_volume','device',partition.device,'','')
?>"><?cs var:partition.name ?></a></li><?cs /if ?><?cs /each ?></ul><?cs /if ?>
<?cs /if ?>

View file

@ -29,7 +29,7 @@
<?cs if:!Data.CurrentDisk.active ?>
<h2>Change the name of the container</h2>
<?cs call:print_form_header("volume_name_set") ?>
<p><label for="vol_name"><?cs var:html_escape(Lang.Text.ContainerName) ?></label>
<p><label for="volume_name"><?cs var:html_escape(Lang.Text.ContainerName) ?></label>
<input type="text" name="volume_name" size="20" id="volume_name" value="<?cs var:html_escape(Data.CurrentDisk.name) ?>" />
<input type="hidden" name="device" value="<?cs var:html_escape(Data.CurrentDisk.device) ?>" />
<button type="submit"><?cs var:html_escape(Lang.Button.ContainerNameSet) ?></button></p>