language namespace for plugins separated

plugin interface changed ("prepareForm" removed)
plugins do not raise exceptions anymore
first part of the partitioning plugin
device-specific stuff moved to CryptoBoxTools
This commit is contained in:
lars 2006-09-14 12:33:01 +00:00
parent f2a7ceb61c
commit de3280806f
26 changed files with 622 additions and 309 deletions

View file

@ -18,6 +18,7 @@ import CryptoBoxContainer
from CryptoBoxExceptions import * from CryptoBoxExceptions import *
import re import re
import os import os
import CryptoBoxTools
@ -112,10 +113,16 @@ class CryptoBoxProps(CryptoBox):
def __init__(self, config_file=None): def __init__(self, config_file=None):
'''read config and fill class variables''' '''read config and fill class variables'''
CryptoBox.__init__(self, config_file) CryptoBox.__init__(self, config_file)
self.__reReadContainerList()
def __reReadContainerList(self):
self.containers = [] self.containers = []
for device in self.__getAvailablePartitions(): for device in CryptoBoxTools.getAvailablePartitions():
if self.isDeviceAllowed(device): if self.isDeviceAllowed(device):
self.containers.append(CryptoBoxContainer.CryptoBoxContainer(device, self)) self.containers.append(CryptoBoxContainer.CryptoBoxContainer(device, self))
## sort by container name
self.containers.sort(cmp = lambda x,y: x.getName() < y.getName() and -1 or 1)
def isDeviceAllowed(self, devicename): def isDeviceAllowed(self, devicename):
@ -185,9 +192,22 @@ class CryptoBoxProps(CryptoBox):
"assign a name to a uuid in the ContainerNameDatabase" "assign a name to a uuid in the ContainerNameDatabase"
used_uuid = self.getUUIDForName(name) used_uuid = self.getUUIDForName(name)
"first remove potential conflicting uuid/name combination" "first remove potential conflicting uuid/name combination"
if used_uuid: del self.prefs.nameDB[used_uuid] if used_uuid:
## remember the container which name was overriden
for e in self.containers:
if e.getName() == name:
forcedRename = e
break
del self.prefs.nameDB[used_uuid]
self.prefs.nameDB[uuid] = name self.prefs.nameDB[uuid] = name
self.prefs.nameDB.write() self.prefs.nameDB.write()
## rename the container that lost its name (necessary while we use cherrypy)
if used_uuid:
## this is surely not the best way to regenerate the name
dev = e.getDevice()
old_index = self.containers.index(e)
self.containers.remove(e)
self.containers.insert(old_index, CryptoBoxContainer.CryptoBoxContainer(dev,self))
def getNameForUUID(self, uuid): def getNameForUUID(self, uuid):
@ -244,102 +264,6 @@ class CryptoBoxProps(CryptoBox):
return [] return []
""" ************ internal stuff starts here *********** """
def __getAvailablePartitions(self):
"retrieve a list of all available containers"
ret_list = []
try:
"the following reads all lines of /proc/partitions and adds the mentioned devices"
fpart = open("/proc/partitions", "r")
try:
line = fpart.readline()
while line:
p_details = line.split()
if (len(p_details) == 4):
"the following code prevents double entries like /dev/hda and /dev/hda1"
(p_major, p_minor, p_size, p_device) = p_details
if re.search('^[0-9]*$', p_major) and re.search('^[0-9]*$', p_minor):
p_parent = re.sub('[1-9]?[0-9]$', '', p_device)
if p_parent == p_device:
if [e for e in ret_list if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
"major partition - its children are already in the list"
pass
else:
"major partition - but there are no children for now"
ret_list.append(p_device)
else:
"minor partition - remove parent if necessary"
if p_parent in ret_list: ret_list.remove(p_parent)
ret_list.append(p_device)
line = fpart.readline()
finally:
fpart.close()
return [self.__getAbsoluteDeviceName(e) for e in ret_list]
except IOError:
self.log.warning("Could not read /proc/partitions")
return []
def __getAbsoluteDeviceName(self, shortname):
""" returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1")
this does also work for device mapper devices
if the result is non-unique, one arbitrary value is returned"""
if re.search('^/', shortname): return shortname
default = os.path.join("/dev", shortname)
if os.path.exists(default): return default
result = self.__findMajorMinorOfDevice(shortname)
"if no valid major/minor was found -> exit"
if not result: return default
(major, minor) = result
"for device-mapper devices (major == 254) ..."
if major == 254:
result = self.__findMajorMinorDeviceName("/dev/mapper", major, minor)
if result: return result[0]
"now check all files in /dev"
result = self.__findMajorMinorDeviceName("/dev", major, minor)
if result: return result[0]
return default
def __findMajorMinorOfDevice(self, device):
"return the major/minor numbers of a block device by querying /sys/block/?/dev"
if not os.path.exists(os.path.join("/sys/block", device)): return None
blockdev_info_file = os.path.join(os.path.join("/sys/block", device), "dev")
try:
f_blockdev_info = open(blockdev_info_file, "r")
blockdev_info = f_blockdev_info.read()
f_blockdev_info.close()
(str_major, str_minor) = blockdev_info.split(":")
"numeric conversion"
try:
major = int(str_major)
minor = int(str_minor)
return (major, minor)
except ValueError:
"unknown device numbers -> stop guessing"
return None
except IOError:
pass
def __findMajorMinorDeviceName(self, dir, major, minor):
"returns the names of devices with the specified major and minor number"
collected = []
try:
subdirs = [os.path.join(dir, e) for e in os.listdir(dir) if (not os.path.islink(os.path.join(dir, e))) and os.path.isdir(os.path.join(dir, e))]
"do a recursive call to parse the directory tree"
for dirs in subdirs:
collected.extend(self.__findMajorMinorDeviceName(dirs, major, minor))
"filter all device inodes in this directory"
collected.extend([os.path.realpath(os.path.join(dir, e)) for e in os.listdir(dir) if (os.major(os.stat(os.path.join(dir, e)).st_rdev) == major) and (os.minor(os.stat(os.path.join(dir, e)).st_rdev) == minor)])
result = []
for e in collected:
if e not in result: result.append(e)
return collected
except OSError:
return []
if __name__ == "__main__": if __name__ == "__main__":
cb = CryptoBox() cb = CryptoBox()

View file

@ -205,6 +205,7 @@ class CryptoBoxContainer:
def __getUUID(self): def __getUUID(self):
"""return UUID for luks partitions, ext2/3 and vfat filesystems""" """return UUID for luks partitions, ext2/3 and vfat filesystems"""
emergency_default = self.device.replace(os.path.sep, "_")
devnull = None devnull = None
try: try:
devnull = open(os.devnull, "w") devnull = open(os.devnull, "w")
@ -214,7 +215,7 @@ class CryptoBoxContainer:
shell=False, shell=False,
stdin=None, stdin=None,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=devnull, stderr=subprocess.PIPE,
args=[self.Progs["blkid"], args=[self.Progs["blkid"],
"-s", "UUID", "-s", "UUID",
"-o", "value", "-o", "value",
@ -225,10 +226,10 @@ class CryptoBoxContainer:
result = proc.stdout.read().strip() result = proc.stdout.read().strip()
if proc.returncode != 0: if proc.returncode != 0:
self.log.warn("retrieving of partition type via 'blkid' failed: %s" % (proc.stderr.read().strip(), )) self.log.warn("retrieving of partition type via 'blkid' failed: %s" % (proc.stderr.read().strip(), ))
return None return emergency_default
devnull.close() devnull.close()
if result: return result if result: return result
return self.device.replace(os.path.sep, "_") return emergency_default
def __getTypeOfPartition(self): def __getTypeOfPartition(self):

View file

@ -0,0 +1,117 @@
import logging
import os
import re
logger = logging.getLogger("CryptoBox")
def getAvailablePartitions():
"retrieve a list of all available containers"
ret_list = []
try:
"the following reads all lines of /proc/partitions and adds the mentioned devices"
fpart = open("/proc/partitions", "r")
try:
line = fpart.readline()
while line:
p_details = line.split()
if (len(p_details) == 4):
"the following code prevents double entries like /dev/hda and /dev/hda1"
(p_major, p_minor, p_size, p_device) = p_details
if re.search('^[0-9]*$', p_major) and re.search('^[0-9]*$', p_minor):
p_parent = re.sub('[1-9]?[0-9]$', '', p_device)
if p_parent == p_device:
if [e for e in ret_list if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
"major partition - its children are already in the list"
pass
else:
"major partition - but there are no children for now"
ret_list.append(p_device)
else:
"minor partition - remove parent if necessary"
if p_parent in ret_list: ret_list.remove(p_parent)
ret_list.append(p_device)
line = fpart.readline()
finally:
fpart.close()
return map(getAbsoluteDeviceName, ret_list)
except IOError:
logger.warning("Could not read /proc/partitions")
return []
def getAbsoluteDeviceName(shortname):
""" returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1")
this does also work for device mapper devices
if the result is non-unique, one arbitrary value is returned"""
if re.search('^/', shortname): return shortname
default = os.path.join("/dev", shortname)
if os.path.exists(default): return default
result = findMajorMinorOfDevice(shortname)
"if no valid major/minor was found -> exit"
if not result: return default
(major, minor) = result
"for device-mapper devices (major == 254) ..."
if major == 254:
result = findMajorMinorDeviceName("/dev/mapper", major, minor)
if result: return result[0]
"now check all files in /dev"
result = findMajorMinorDeviceName("/dev", major, minor)
if result: return result[0]
return default
def findMajorMinorOfDevice(device):
"return the major/minor numbers of a block device by querying /sys/block/?/dev"
if not os.path.exists(os.path.join(os.path.sep,"sys","block",device)): return None
blockdev_info_file = os.path.join(os.path.join(os.path.sep,"sys","block", device), "dev")
try:
f_blockdev_info = open(blockdev_info_file, "r")
blockdev_info = f_blockdev_info.read()
f_blockdev_info.close()
(str_major, str_minor) = blockdev_info.split(":")
"numeric conversion"
try:
major = int(str_major)
minor = int(str_minor)
return (major, minor)
except ValueError:
"unknown device numbers -> stop guessing"
return None
except IOError:
pass
def findMajorMinorDeviceName(dir, major, minor):
"returns the names of devices with the specified major and minor number"
collected = []
try:
subdirs = [os.path.join(dir, e) for e in os.listdir(dir) if (not os.path.islink(os.path.join(dir, e))) and os.path.isdir(os.path.join(dir, e))]
"do a recursive call to parse the directory tree"
for dirs in subdirs:
collected.extend(findMajorMinorDeviceName(dirs, major, minor))
"filter all device inodes in this directory"
collected.extend([os.path.realpath(os.path.join(dir, e)) for e in os.listdir(dir) if (os.major(os.stat(os.path.join(dir, e)).st_rdev) == major) and (os.minor(os.stat(os.path.join(dir, e)).st_rdev) == minor)])
## remove double entries
result = []
for e in collected:
if e not in result: result.append(e)
return result
except OSError:
return []
def getParentBlockDevices():
devs = []
for line in file("/proc/partitions"):
p_details = line.split()
## we expect four values - otherwise continue with next iteration
if len(p_details) != 4: continue
(p_major, p_minor, p_size, p_device) = p_details
## we expect numeric values in the first two columns
if re.search(u'\D',p_major) or re.search(u'\D',p_minor): continue
## now let us check, if it is a (parent) block device or a partition
if not os.path.isdir(os.path.join(os.path.sep, "sys", "block", p_device)): continue
devs.append(p_device)
return map(getAbsoluteDeviceName, devs)

View file

@ -44,14 +44,19 @@ class PluginManager:
def loadLanguageData(self, hdf, lang="en"): def loadLanguageData(self, hdf, lang="en"):
import neo_cgi, neo_util
for plfile in self.__getPluginFiles(): for plfile in self.__getPluginFiles():
plname = os.path.basename(plfile)[:-3]
langdir = os.path.join(os.path.dirname(plfile), "lang") langdir = os.path.join(os.path.dirname(plfile), "lang")
selected_langfile = os.path.join(langdir, lang + ".hdf") selected_langfile = os.path.join(langdir, lang + ".hdf")
default_langfile = os.path.join(langdir, "en.hdf") default_langfile = os.path.join(langdir, "en.hdf")
for langfile in (selected_langfile, default_langfile): for langfile in (selected_langfile, default_langfile):
if os.access(langfile, os.R_OK): if os.access(langfile, os.R_OK):
self.log.debug("Loading plugin language file: %s" % langfile) self.log.debug("Loading plugin language file: %s" % langfile)
hdf.readFile(langfile) lang_hdf = neo_util.HDF()
lang_hdf.readFile(langfile)
## add the language data below "Lang.Plugins.PLUGINNAME"
hdf.copy("Lang.Plugins." + plname, lang_hdf)
break break
else: else:
self.log.debug("Couldn't find a plugin language file (%s)" % default_langfile) self.log.debug("Couldn't find a plugin language file (%s)" % default_langfile)

View file

@ -18,7 +18,7 @@ class WebInterfaceDataset(dict):
def setPluginState(self, plugins): def setPluginState(self, plugins):
for pl in plugins.allPlugins(): for pl in plugins.allPlugins():
self["Data.Status.Modules." + pl] = plugins.getPlugin(pl).getStatus(self.cbox) self["Data.Status.Plugins." + pl] = plugins.getPlugin(pl).getStatus(self.cbox)
def setCurrentDiskState(self, device): def setCurrentDiskState(self, device):
@ -48,6 +48,7 @@ class WebInterfaceDataset(dict):
self["Settings.Stylesheet"] = self.prefs["WebSettings"]["Stylesheet"] self["Settings.Stylesheet"] = self.prefs["WebSettings"]["Stylesheet"]
self["Settings.Language"] = self.prefs["WebSettings"]["Language"] self["Settings.Language"] = self.prefs["WebSettings"]["Language"]
self["Settings.DocLang"] = self.prefs["WebSettings"]["DocLanguage"] self["Settings.DocLang"] = self.prefs["WebSettings"]["DocLanguage"]
self["Settings.PluginDir"] = self.prefs["Locations"]["PluginDir"]
def __setCryptoBoxState(self): def __setCryptoBoxState(self):

View file

@ -1,9 +1,21 @@
import CryptoBox import CryptoBox
import WebInterfaceDataset import WebInterfaceDataset
import re import re
from Plugins import PluginManager import Plugins
from CryptoBoxExceptions import * from CryptoBoxExceptions import *
class WebInterfacePlugins:
def __init__(self, log, plugins, handler_func):
for plname in plugins.allPlugins():
log.info("Plugin '%s' loaded" % plname)
## this should be the "easiest" way to expose all plugins as URLs
setattr(self, plname, handler_func(plname))
setattr(getattr(self, plname), "exposed", True)
class WebInterfaceSites: class WebInterfaceSites:
''' '''
url2func = {'index':'show_status','doc':'show_doc','logs':'show_log'} url2func = {'index':'show_status','doc':'show_doc','logs':'show_log'}
@ -16,16 +28,9 @@ class WebInterfaceSites:
self.log = logging.getLogger("CryptoBox") self.log = logging.getLogger("CryptoBox")
self.prefs = self.cbox.prefs self.prefs = self.cbox.prefs
self.__resetDataset() self.__resetDataset()
self.plugins = PluginManager(self.prefs["Locations"]["PluginDir"]) self.pluginList = Plugins.PluginManager(self.prefs["Locations"]["PluginDir"])
self.__exposePlugins() self.plugins = WebInterfacePlugins(self.log, self.pluginList, self.return_plugin_action)
self.plugins.index = self.system
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): def __resetDataset(self):
@ -134,8 +139,8 @@ class WebInterfaceSites:
try: try:
container.setName(volume_name) container.setName(volume_name)
# TODO: specify the possible exceptions # TODO: specify the possible exceptions
except Exception: except Exception, errMsg:
self.log.warn("failed to rename the volume '%s' to '%s'" % (device, volume_name)) self.log.warn("failed to rename the volume '%s' to '%s: %s'" % (device, volume_name, errMsg))
self.dataset["Data.Warning"] = "SetVolumeNameFailed" self.dataset["Data.Warning"] = "SetVolumeNameFailed"
else: else:
self.log.info("successfully renamed volume '%s' to '%s'" % (device, volume_name)) self.log.info("successfully renamed volume '%s' to '%s'" % (device, volume_name))
@ -311,7 +316,7 @@ class WebInterfaceSites:
return self.__render("show_volume") return self.__render("show_volume")
def return_module_action(self, module): def return_plugin_action(self, plugin_name):
def handler(**args): def handler(**args):
self.__resetDataset() self.__resetDataset()
try: try:
@ -319,15 +324,9 @@ class WebInterfaceSites:
del args["weblang"] del args["weblang"]
except KeyError: except KeyError:
pass pass
plugin = self.plugins.getPlugin(module) plugin = self.pluginList.getPlugin(plugin_name)
try: nextTemplate = plugin.doAction(self.dataset, self.cbox, **args)
nextTemplate = plugin.doAction(self.cbox, **args) return self.__render(nextTemplate, plugin_name)
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 return handler
@ -418,7 +417,7 @@ class WebInterfaceSites:
return False return False
def __render(self, template, module=None): def __render(self, template, plugin=None):
'''renders from clearsilver templates and returns the resulting html '''renders from clearsilver templates and returns the resulting html
Gets a dictionary with all settings, nessessary for rendering. Gets a dictionary with all settings, nessessary for rendering.
@ -430,16 +429,16 @@ class WebInterfaceSites:
try: try:
import neo_cgi, neo_util, neo_cs import neo_cgi, neo_util, neo_cs
except ImportError: except ImportError:
errorMsg = "Could not import clearsilver modules. Try 'apt-get install python-clearsilver'." errorMsg = "Could not import clearsilver module. Try 'apt-get install python-clearsilver'."
self.log.error(errorMsg) self.log.error(errorMsg)
sys.stderr.write(errorMsg) sys.stderr.write(errorMsg)
raise ImportError, errorMsg raise ImportError, errorMsg
module_cs_file = False plugin_cs_file = False
if module: if plugin:
module_cs_file = self.plugins.getTemplateFileName(module, template) plugin_cs_file = self.pluginList.getTemplateFileName(plugin, template)
default_cs_file = os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs") default_cs_file = os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs")
self.dataset["Data.TemplateFile"] = module_cs_file or default_cs_file self.dataset["Data.TemplateFile"] = plugin_cs_file or default_cs_file
self.log.info("rendering site: " + template) self.log.info("rendering site: " + template)
cs_path = os.path.join(self.prefs["Locations"]["TemplateDir"], "main.cs") cs_path = os.path.join(self.prefs["Locations"]["TemplateDir"], "main.cs")
@ -454,7 +453,7 @@ class WebInterfaceSites:
return "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 ## add the current state of the plugins to the hdf dataset
self.dataset.setPluginState(self.plugins) self.dataset.setPluginState(self.pluginList)
hdf = neo_util.HDF() hdf = neo_util.HDF()
hdf.readFile(hdf_path) hdf.readFile(hdf_path)
@ -462,7 +461,7 @@ class WebInterfaceSites:
for key in self.dataset.keys(): for key in self.dataset.keys():
hdf.setValue(key,str(self.dataset[key])) hdf.setValue(key,str(self.dataset[key]))
## load languaga data of plugins ## load languaga data of plugins
self.plugins.loadLanguageData(hdf, lang=self.dataset["Settings.Language"]) self.pluginList.loadLanguageData(hdf, lang=self.dataset["Settings.Language"])
cs = neo_cs.CS(hdf) cs = neo_cs.CS(hdf)
cs.parseFile(cs_path) cs.parseFile(cs_path)
return cs.render() return cs.render()

View file

@ -1,26 +1,17 @@
from CryptoBoxExceptions import CBPluginActionError
import subprocess import subprocess
import os import os
def prepareForm(hdf, cbox): def doAction(hdf, cbox, store=None, year=0, month=0, day=0, hour=0, minute=0):
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 import datetime
__prepareFormData(hdf, cbox)
if store: if store:
try: try:
year, month, day = int(year), int(month), int(day) year, month, day = int(year), int(month), int(day)
hour, minute = int(hour), int(minute) hour, minute = int(hour), int(minute)
new_date = datetime.datetime(year, month, day, hour, minute) new_date = datetime.datetime(year, month, day, hour, minute)
except ValueError: except ValueError:
raise CBPluginActionError, "InvalidDate" hdf["Data.Warning"] = "Plugins.date.InvalidDate"
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
args = [ args = [
@ -33,7 +24,8 @@ def doAction(cbox, store=None, year=0, month=0, day=0, hour=0, minute=0):
if proc.returncode == 0: if proc.returncode == 0:
return "form_system" return "form_system"
else: else:
raise CBPluginActionError, "InvalidDate" hdf["Data.Warning"] = "Plugins.date.InvalidDate"
return "form_date"
else: else:
return "form_date" return "form_date"
@ -42,6 +34,15 @@ def getStatus(cbox):
return str(__getCurrentDate()) return str(__getCurrentDate())
def __prepareFormData(hdf, cbox):
date = __getCurrentDate()
hdf["Data.Plugins.date.year"] = date.year
hdf["Data.Plugins.date.month"] = date.month
hdf["Data.Plugins.date.day"] = date.day
hdf["Data.Plugins.date.hour"] = date.hour
hdf["Data.Plugins.date.minute"] = date.minute
def __getCurrentDate(): def __getCurrentDate():
import datetime import datetime
return datetime.datetime(2000,1,1).now() return datetime.datetime(2000,1,1).now()

View file

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

View file

@ -1,35 +1,29 @@
Lang { Name = Change date and time
Link = Set date/time
Rank = 10
Title.ConfigDate = Date and time setting Title.ConfigDate = Date and time setting
Button.ConfigDate = Set date and time 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.
}
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
}
WarningMessage.InvalidDate {
Title = Invalid value
Text = An invalid value for date or time was supplied. Please try again.
} }

View file

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

View file

@ -1,11 +1,6 @@
from CryptoBoxExceptions import CBPluginActionError
def doAction(hdf, cbox):
def prepareForm(hdf, cbox): __prepareFormData(hdf,cbox)
hdf["Data.Modules.logs.Content"] = __getLogContent(cbox)
def doAction(cbox):
return "show_log" return "show_log"
@ -16,6 +11,10 @@ def getStatus(cbox):
cbox.prefs["Log"]["Details"]) cbox.prefs["Log"]["Details"])
def __prepareFormData(hdf, cbox):
hdf["Data.Plugins.logs.Content"] = __getLogContent(cbox)
def __getLogContent(cbox, lines=30, maxSize=2000): def __getLogContent(cbox, lines=30, maxSize=2000):
return "<br/>".join(cbox.getLogData(lines, maxSize)) return "<br/>".join(cbox.getLogData(lines, maxSize))

View file

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

View file

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

View file

@ -1,20 +1,24 @@
Lang { Name = Configure network
Link = Configure network
Rank = 30
Title.Network = Network settings Title.Network = Network settings
Button.Network = Update settings Button.Network = Update settings
Text.IP = Network address Text.IP = Network address
Modules.network {
Name = Configure network
Link = Configure network
Rank = 30
}
WarningMessage.InvalidIP { WarningMessage {
InvalidIP {
Title = Invalid value Title = Invalid value
Text = An invalid network address (IP) was supplied. Please try again. Text = An invalid network address (IP) was supplied. Please try again.
} }
}
SuccessMessage {
IPChanged {
Title = Network address changed
Text = The network address has been changed. In a few seconds you will get redirected to the new address.
}
} }

View file

@ -1,19 +1,11 @@
from CryptoBoxExceptions import CBPluginActionError
import re import re
import subprocess import subprocess
import imp import imp
import os import os
def prepareForm(hdf, cbox): def doAction(hdf, cbox, store=None, ip1="", ip2="", ip3="", ip4=""):
(oc1, oc2, oc3, oc4) = __getCurrentIP(cbox) __prepareFormData(hdf, cbox)
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: if store:
try: try:
for ip_in in (ip1, ip2, ip3, ip4): for ip_in in (ip1, ip2, ip3, ip4):
@ -22,11 +14,16 @@ def doAction(cbox, store=None, ip1="", ip2="", ip3="", ip4=""):
raise ValueError raise ValueError
ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4)) ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4))
except ValueError: except ValueError:
raise CBPluginActionError, "InvalidIP" hdf["Data.Warning"] = "Plugins.network.InvalidIP"
return "form_system"
if __setIP(cbox, ip): if __setIP(cbox, ip):
hdf["Data.Success"] = "Plugins.network.IPChanged"
hdf["Data.Redirect.URL"] = ""
hdf["Data.Redirect.Delay"] = 30
return "form_system" return "form_system"
else: else:
raise CBPluginActionError, "InvalidIP" hdf["Data.Warning"] = "Plugins.network.InvalidIP"
return "form_network"
else: else:
return "form_network" return "form_network"
@ -35,14 +32,22 @@ def getStatus(cbox):
return "%d.%d.%d.%d" % __getCurrentIP(cbox) return "%d.%d.%d.%d" % __getCurrentIP(cbox)
def __prepareFormData(hdf, cbox):
(oc1, oc2, oc3, oc4) = __getCurrentIP(cbox)
hdf["Data.Plugins.network.ip.oc1"] = oc1
hdf["Data.Plugins.network.ip.oc2"] = oc2
hdf["Data.Plugins.network.ip.oc3"] = oc3
hdf["Data.Plugins.network.ip.oc4"] = oc4
def __getCurrentIP(cbox): def __getCurrentIP(cbox):
root_action_mod = imp.load_source("root_action", os.path.join(os.path.dirname(__file__), "root_action.py")) root_action_plug = imp.load_source("root_action", os.path.join(os.path.dirname(__file__), "root_action.py"))
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdout = subprocess.PIPE, stdout = subprocess.PIPE,
args = [ args = [
root_action_mod.IFCONFIG_BIN, root_action_plug.IFCONFIG_BIN,
root_action_mod.IFACE]) root_action_plug.IFACE])
(output, error) = proc.communicate() (output, error) = proc.communicate()
if proc.returncode != 0: return (0,0,0,0) if proc.returncode != 0: return (0,0,0,0)
match = re.search(u'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s',output) match = re.search(u'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s',output)

View file

@ -0,0 +1,8 @@
<?cs loop: x = #0, subcount(Data.Plugins.partition.Parts)-1, #1 ?>
<input type="hidden" name="part<?cs var:x ?>_size" value="<?cs var:Data.Plugins.partition.Parts[x].Size ?>" />
<input type="hidden" name="part<?cs var:x ?>_type" value="<?cs var:Data.Plugins.partition.Parts[x].Type ?>" /><?cs
/loop ?>
<input type="hidden" name="block_device" value="<?cs var:html_escape(Data.Plugins.partition.Device) ?>" />

View file

@ -0,0 +1,33 @@
Name = Disk partitioning
Link = Disk partitioning
Rank = 80
Title.Partition = Disk partitions
Button {
SelectDevice = Repartition disk
AddPartition = Add another partition
Back = Back
SavePartitions = Save changes
AbortPartitions = Cancel
}
Text {
FS {
Type = Filesystem type
Fat = FAT (Windows)
Ext2 = Ext2
Ext3 = Ext3
Reiser = Reiser
}
Size = Size (MB)
SelectDevice = Choose a disk for partitioning
NoDevicesAvailable = No suitable disks found - please check your configuration and hardware setup.
WarningMessage {
InvalidInput {
Title = Invalid input
Text = You entered an invalid value.
}
}

View file

@ -0,0 +1,132 @@
import re
import subprocess
import imp
import os
import logging
import CryptoBoxTools
PartTypes = {
"linux" : "L",
"windows" : "0xC"}
logger = logging.getLogger("CryptoBox")
def doAction(hdf, cbox, **args):
try:
step = args["step"]
del args["step"]
except KeyError:
step = "select_device"
if step == "add_partition":
return __actionAddPartition(hdf, cbox, args)
if step == "del_partition":
return __actionDelPartition(hdf, cbox, args)
elif step == "finish":
return __actionFinish(hdf, cbox, args)
else: # for "select_device" and for invalid targets
return __actionSelectDevice(hdf, cbox, args)
def getStatus(cbox):
return "%d.%d.%d.%d" % __getCurrentIP(cbox)
def __isDeviceValid(device, cbox):
if not cbox.isDeviceAllowed(device):
return False
if not device in CryptoBoxTools.getParentBlockDevices():
return False
def __actionSelectDevice(hdf, cbox, args):
block_devices = [e
for e in CryptoBoxTools.getParentBlockDevices()
if cbox.isDeviceAllowed(e)]
counter = 0
for a in block_devices:
hdf["Data.Plugins.partition.BlockDevices.%d" % counter] = a
cbox.log.debug("found a suitable block device: %s" % a)
counter += 1
return "select_device"
def __actionAddPartition(hdf, cbox, args):
try:
device = args["block_device"]
except KeyError:
return __actionSelectDevice(hdf, cbox, args)
#FIXME: the following check should obviuosly get reversed
if __isDeviceValid(device, cbox): return __actionSelectDevice(hdf, cbox, args)
size = __getDeviceSize(device)
hdf["Data.Plugins.partition.Device"] = device
hdf["Data.Plugins.partition.Device.Size"] = size
parts = __getPartitionsFromArgs(args, size)
__setPartitionData(hdf, parts, size)
return "set_partitions"
def __actionDelPartition(hdf, cbox, args):
try:
device = args["block_device"]
except KeyError:
return __actionSelectDevice(hdf, cbox, args)
#FIXME: the following check should obviuosly get reversed
if __isDeviceValid(device, cbox): return __actionSelectDevice(hdf, cbox, args)
size = __getDeviceSize(device)
hdf["Data.Plugins.partition.Device"] = device
hdf["Data.Plugins.partition.Device.Size"] = size
parts = __getPartitionsFromArgs(args, size)
__setPartitionData(hdf, parts[:-1], size)
return "set_partitions"
def __setPartitionData(hdf, parts, size):
availSize = size
i = 0
for part in parts:
logger.debug(part)
hdf["Data.Plugins.partition.Parts.%d.Size" % i] = part["size"]
hdf["Data.Plugins.partition.Parts.%d.Type" % i] = part["type"]
availSize -= part["size"]
i += 1
hdf["Data.Plugins.partition.availSize"] = availSize
for t in PartTypes.keys():
hdf["Data.Plugins.partition.Types.%s" % t] = t
def __getPartitionsFromArgs(args, maxSize):
parts = []
done = False
availSize = maxSize
i = -1
while not done:
i += 1
try:
size = int(args["part%d_size" % i])
partType = args["part%d_type" % i]
if int(size) > availSize: continue
if int(size) <= 0: continue
if not partType in PartTypes.keys(): continue
parts.append({"size":size, "type":partType})
availSize -= size
except TypeError:
pass
except KeyError:
done = True
return parts
def __getDeviceSize(device):
rdev = os.stat(device).st_rdev
minor = os.minor(rdev)
major = os.major(rdev)
for f in file("/proc/partitions"):
try:
elements = f.split()
if len(elements) != 4: continue
if (int(elements[0]) == major) and (int(elements[1]) == minor):
return int(elements[2])
except ValueError:
pass
return 0

View file

@ -0,0 +1,33 @@
#!/usr/bin/env python2.4
#TODO: add netmask and gateway
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
PLUGIN_TYPE = "cryptobox"
import subprocess
import re
import sys
import os
if __name__ == "__main__":
args = sys.argv[1:]
self_bin =sys.argv[0]
if len(args) > 1:
sys.stderr.write("%s: too many arguments (%s)\n" % (self_bin, args))
sys.exit(1)
if len(args) == 0:
sys.stderr.write("%s: no argument supplied\n" % self_bin)
sys.exit(1)
proc = subprocess.Popen(
shell = False,
args = [IFCONFIG_BIN, IFACE, args[0]])
proc.communicate()
sys.exit(proc.returncode)

View file

@ -0,0 +1,27 @@
<?cs # $Id$ ?>
<h1><?cs var:html_escape(Lang.Plugins.partition.Title.Partition) ?></h1>
<?cs if:subcount(Data.Plugins.partition.BlockDevices) > 0 ?>
<?cs call:print_form_header("plugins/partition") ?>
<p><label for="block_device"><?cs var:html_escape(Lang.Plugins.partition.Text.SelectDevice) ?>: </label><br/>
<select name="block_device" id="block_device" size="0">
<?cs each:x = Data.Plugins.partition.BlockDevices
?><option><?cs var:html_escape(x) ?></option>
<?cs /each ?>
</select></p>
<input type="hidden" name="step" value="add_partition" />
<button type="submit"><?cs var:html_escape(Lang.Plugins.partition.Button.SelectDevice) ?></button>
</form>
<?cs else ?>
<p><?cs var:html_escape(Lang.Plugins.partition.Text.NoDevicesAvailable) ?></p>
<?cs /if ?>

View file

@ -0,0 +1,37 @@
<?cs # $Id$ ?>
<h1><?cs var:html_escape(Lang.Plugins.partition.Title.Partition) ?></h1>
<p> <?cs loop: x = #0, subcount(Data.Plugins.partition.Parts)-1, #1 ?>
<p><?cs var:x ?> - <?cs var:Data.Plugins.partition.Parts[x].Size ?> - <?cs var:Data.Plugins.partition.Parts[x].Type ?></p><?cs
/loop ?></p>
<?cs if:Data.Plugins.partition.availSize ?>
<?cs call:print_form_header("plugins/partition") ?>
<?cs include:Settings.PluginDir + "/partition/current_partition_info.cs" ?><?cs
# new partition input if space is available ?><?cs
set: x = subcount(Data.Plugins.partition.Parts) ?>
<p><?cs var:x ?> - <input type="text" name="part<?cs var:x ?>_size" value="<?cs var:Data.Plugins.partition.availSize ?>" /> - <select name="part<?cs var:x ?>_type" size="0"><?cs each: t = Data.Plugins.partition.Types ?><option><?cs var:t ?></option><?cs /each ?></select></p>
<input type="hidden" name="step" value="add_partition" />
<button type="submit"><?cs var:html_escape(Lang.Plugins.partition.Button.AddPartition) ?></button>
</form>
<?cs /if ?>
<?cs if:subcount(Data.Plugins.partition.Parts) > 0 ?>
<?cs call:print_form_header("plugins/partition") ?>
<?cs include:Settings.PluginDir + "/partition/current_partition_info.cs" ?>
<input type="hidden" name="step" value="del_partition" />
<button type="submit"><?cs var:html_escape(Lang.Plugins.partition.Button.Back) ?></button>
</form>
<?cs /if ?>
<?cs if:subcount(Data.Plugins.partition.Parts) > 0 ?>
<?cs call:print_form_header("plugins/partition") ?>
<?cs include:Settings.PluginDir + "/partition/current_partition_info.cs" ?>
<input type="hidden" name="step" value="finish" />
<button type="submit"><?cs var:html_escape(Lang.Plugins.partition.Button.SavePartitions) ?></button>
</form>
<?cs /if ?>

View file

@ -1,36 +1,33 @@
The following directory structure is required: The following directory structure is required:
- python code: plugins/MODULENAME/MODULENAME.py (all lower case is recommended) - python code: plugins/PLUGINNAME/PLUGINNAME.py (all lower case is recommended)
- language files: plugins/MODULENAME/lang/(en|de|??).hdf - language files: plugins/PLUGINNAME/lang/(en|de|??).hdf
- clearsilver templates: plugins/MODULENAME/*.cs - clearsilver templates: plugins/PLUGINNAME/*.cs
Python code interface: Python code interface:
def prepareForm(hdf, cbox): def doAction(hdf, cbox, store=None, ???):
- here you may add some items to the hdf dataset used by the templates - this function will get called whenever this plugins is involved in a request
- 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) - 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) - 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 - if the processing failed for some reason (invalid input, ...), it should manually set the "Data.Warning" (resp. "Data.Error" or "Data.Success") to a value of your choice (preferably you may want to use messages of your namespace (e.g. "Plugins.PLUGINNAME.InvalidInput"))
- 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) - the return value should be the name of the template that should be displayed after processing (a template file in the plugin directory takes precedence over global template files)
def def getStatus(cbox): 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) - returns a string, that described a state connected to this plugin (e.g. the current date and time (for the "date" plugin)
Language file structure: Language file structure:
- the content of the language file will be added to the hdf dataset below "Lang.Plugins.PLUGINNAME" (this avoids namespace conflicts)
- the following values _must_ be defined: - the following values _must_ be defined:
Lang.Modules.MODULENAME.Name (a short description) Name (a short description)
Lang.Modules.MODULENAME.Link (the visible text for links to this module) Link (the visible text for links to this plugin)
Lang.Modules.MODULENAME.Rank (defines the order of the plugins displayed) Rank (defines the order of the plugins displayed (0..100))
- all other elements should follow the usual structure of language files - all warnings, error and success messages should be stored below WarningMessage.??? (resp. ErrorMessage or SuccessMessage)
Clearsilver template: Clearsilver template:
- should start with a "<h1>" tag - should start with a "<h1>" tag
- links to the module (e.g. in form headers) could look like the following: - links to the plugin (e.g. in form headers) could look like the following:
<?cs call:link("module_MODULENAME",'','','','') ?> <?cs call:link("plugins/PLUGINNAME",'','','','') ?>
- a hidden input field called "store" should be used to indicate a form submission - a hidden input field called "store" should be used to indicate a form submission

View file

@ -26,7 +26,7 @@ Data.Status.Config=<?cs var:html_escape(Data.Status.Config) ?>
Data.Status.InitRunning=<?cs var:html_escape(Data.Status.InitRunning) ?> Data.Status.InitRunning=<?cs var:html_escape(Data.Status.InitRunning) ?>
Data.Status.IP=<?cs var:html_escape(Data.Status.IP) ?> Data.Status.IP=<?cs var:html_escape(Data.Status.IP) ?>
Data.Status.Mounted=<?cs var:html_escape(Data.Status.Mounted) ?> Data.Status.Mounted=<?cs var:html_escape(Data.Status.Mounted) ?>
<?cs each:x = Data.Status.Modules ?>Data.Status.Modules.<?cs <?cs each:x = Data.Status.Plugins ?>Data.Status.Plugins.<?cs
var:name(x) ?>=<?cs var: html_escape(x) ?> var:name(x) ?>=<?cs var: html_escape(x) ?>
<?cs /each <?cs /each
?>CBOX-STATUS-end --> ?>CBOX-STATUS-end -->

View file

@ -6,18 +6,18 @@
<?cs # sort the Plugins - using the most stupid way :) ?> <?cs # sort the Plugins - using the most stupid way :) ?>
<?cs loop: order = #0, #100, #1 <?cs loop: order = #0, #100, #1
?><?cs # plugins ?><?cs each:x = Lang.Modules ?><?cs # plugins ?><?cs each:x = Lang.Plugins
?><?cs if:x.Rank == order ?> ?><?cs if:x.Rank == order ?>
<li><a href="<?cs call:link('module_' + name(x),'','','','') ?>" title="<?cs <li><a href="<?cs call:link('plugins/' + name(x),'','','','') ?>" title="<?cs
var:html_escape(x.Link) ?>"><?cs var:html_escape(x.Link) ?></a></li><?cs var:html_escape(x.Link) ?>"><?cs var:html_escape(x.Link) ?></a></li><?cs
/if ?><?cs /if ?><?cs
/each ?><?cs /each ?><?cs
/loop ?> /loop ?>
<?cs # maybe someone forgot to set the rank of a module: we try to catch them ?> <?cs # maybe someone forgot to set the rank of a plugin: we try to catch them ?>
<?cs # plugins ?><?cs each:x = Lang.Modules ?><?cs <?cs # plugins ?><?cs each:x = Lang.Plugins ?><?cs
if:!x.Rank || !(x.Rank >= 0 && x.Rank <= 100) ?> if:!x.Rank || !(x.Rank >= 0 && x.Rank <= 100) ?>
<li><a href="<?cs call:link('module_' + name(x),'','','','') ?>" title="<?cs <li><a href="<?cs call:link('plugins/' + name(x),'','','','') ?>" title="<?cs
var:html_escape(x.Link) ?>"><?cs var:html_escape(x.Link) ?></a></li><?cs var:html_escape(x.Link) ?>"><?cs var:html_escape(x.Link) ?></a></li><?cs
/if ?><?cs /if ?><?cs
/each ?> /each ?>

View file

@ -1,41 +1,45 @@
<?cs # $Id$ ?><?cs <?cs # $Id$ ?><?cs
def:warning(warnname) # the following macro is as ugly as possible - but somehow we have to manage
?><div class="warning"><?cs to use 'normal' and 'plugin' messages in a clean way:
if:?Lang.WarningMessage[warnname].Title Lang.WarningMessage.??? - used by core functions
?> Lang.Plugins.PLUGINNAME.WarningMessage.??? - used by plugins ?><?cs
<h1><?cs var:html_escape(Lang.WarningMessage[warnname].Title) ?></h1> def:message_dispatch(mname, type, category)
<p><?cs var:html_escape(Lang.WarningMessage[warnname].Text) ?></p> ?><?cs # split the message name into a (potentially existing) plugin-name prefix and the suffix (the python equivalent of the following three lines would be:
<?cs else ?> plugPrefix, PlugSuffix = mname[0:mname.find(".",8), mname[mname.find(".",8)+1:]
<h1>unknown warning message</h1> ?><?cs loop:x = #8, #40, #1 ?><?cs if:(string.slice(mname,x,x+1) == ".") && !(?savedX) ?><?cs set:savedX = x ?><?cs /if ?><?cs /loop
<p>could not find warning message: '<?cs var:warnname ?>'</p> ?><?cs set:plugPrefix = string.slice(mname,0,savedX)
?><?cs set:plugSuffix = string.slice(mname,savedX+1,string.length(mname))
?><?cs # preparations are done - now start writing
?><div class="<?cs var:type ?>"><?cs
# check if it is a 'normal' message ?><?cs
if:?Lang[category][mname].Title ?>
<h1><?cs var:html_escape(Lang[category][mname].Title) ?></h1>
<p><?cs var:html_escape(Lang[category][mname].Text) ?></p>
<?cs # check if the mname starts with "Plugins." ... ?><?cs
elif:(string.slice(mname,0,8) == "Plugins.") && ?Lang[plugPrefix][category][plugSuffix].Title ?>
<h1><?cs var:html_escape(Lang[plugPrefix][category][plugSuffix].Title) ?></h1>
<p><?cs var:html_escape(Lang[plugPrefix][category][plugSuffix].Text) ?></p>
<?cs # the message does not seem to exist ... ?><?cs
else ?>
<h1>unknown <?cs var:type ?> message</h1>
<p>could not find <?cs var:type ?> message: '<?cs var:mname ?>'</p>
<?cs /if ?></div><?cs <?cs /if ?></div><?cs
/def ?><?cs /def ?><?cs
def:error(errname) def:warning(mname)
?><div class="error"><?cs ?><?cs call:message_dispatch(mname, "warning", "WarningMessage") ?><?cs
if:?Lang.ErrorMessage[errname].Title
?>
<h1><?cs var:html_escape(Lang.ErrorMessage[errname].Title) ?></h1>
<p><?cs var:html_escape(Lang.ErrorMessage[errname].Text) ?></p>
<?cs else ?>
<h1>unknown error message</h1>
<p>could not find error message: '<?cs var:errname ?>'</p>
<?cs /if ?></div><?cs
/def ?><?cs /def ?><?cs
def:success(succname) def:error(mname)
?><div class="success"><?cs ?><?cs call:message_dispatch(mname, "error", "ErrorMessage") ?><?cs
if:?Lang.SuccessMessage[succname].Title /def ?><?cs
?>
<h1><?cs var:html_escape(Lang.SuccessMessage[succname].Title) ?></h1>
<p><?cs var:html_escape(Lang.SuccessMessage[succname].Text) ?></p> def:success(mname)
<?cs else ?> ?><?cs call:message_dispatch(mname, "success", "SuccessMessage") ?><?cs
<h1>unknown success message</h1>
<p>could not find success message: '<?cs var:succname ?>'</p>
<?cs /if ?></div><?cs
/def ?><?cs /def ?><?cs

View file

@ -1,17 +1,15 @@
<?cs # $Id$ ?> <?cs # $Id$ ?>
<!-- TODO: completely useless for now - do something about it :) --> <?cs # we use "loop" instead of "each" to keep the order of the disks ?>
<?cs loop: index = #0, subcount(Data.Disks)-1, #1 ?>
<?cs each:volume = Data.Disks ?> <a href="<?cs call:link('show_volume','device',Data.Disks[index].device,'','') ?>" title="<?cs
var:Data.Disks[index].name ?>">
<a href="<?cs call:link('show_volume','device',volume.device,'','') ?>" title="<?cs
var:volume.name ?>">
<?cs # the "div" is the container for the background image ?> <?cs # the "div" is the container for the background image ?>
<div class="<?cs if:volume.isActive ?>active<?cs else ?>passive<?cs /if ?><?cs <div class="<?cs if:Data.Disks[index].active ?>active<?cs else ?>passive<?cs /if ?><?cs
if:volume.device == Data.CurrentDisk.device ?> current<?cs /if ?>"> if:Data.Disks[index].device == Data.CurrentDisk.device ?> current<?cs /if ?>">
<p><?cs var:volume.name ?></p> <p><?cs var:Data.Disks[index].name ?></p>
</div> </div>
</a> </a>
<?cs /loop ?>
<?cs /each ?>