226 lines
8.0 KiB
Python
226 lines
8.0 KiB
Python
# -*- mode: python -*-
|
|
"""capisuite.config
|
|
|
|
Handling of configuration and job description files.
|
|
|
|
This file contains CSConfigParser, a configuration parser derived from the
|
|
default Python parsers, but adapted to the needs of CapiSuite.
|
|
|
|
Additionally, the class JobDescription is defined, which allows to read and
|
|
write special text files used to store meta data about incoming and outgoing
|
|
voice and fax jobs/calls.
|
|
"""
|
|
|
|
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
|
__copyright__ = "Copyright (c) 2004 by Hartmut Goebel"
|
|
__version__ = "$Revision: 0.0 $"
|
|
__credits__ = "This is part of www.capisuite.de; thanks to Gernot Hillier"
|
|
__license__ = """
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
"""
|
|
|
|
import os.path, types, string
|
|
|
|
# the name of the config file read by the scripts; see there for
|
|
# options and descriptions
|
|
pkgsysconfdir = "@pkgsysconfdir@"
|
|
|
|
configfile_fax = os.path.join(pkgsysconfdir, "fax.conf")
|
|
configfile_voice = os.path.join(pkgsysconfdir, "answering_machine.conf")
|
|
|
|
__all__ = ['configfile_fax', 'configfile_voice',
|
|
'CSConfigParser', 'JobDescription',
|
|
'readGlobalConfig', 'readDescription', 'createDescriptionFor',
|
|
'NoOptionError', 'NoGlobalSectionError']
|
|
|
|
# try to use RawConfigParser if available
|
|
try:
|
|
from ConfigParser import RawConfigParser as ConfigParser
|
|
except:
|
|
from ConfigParser import ConfigParser as ConfigParser
|
|
|
|
# capisuite stuff
|
|
import consts
|
|
from exceptions import NoGlobalSectionError, NoOptionError
|
|
|
|
#--- spezialied ConfigParser --#
|
|
|
|
class CSConfigParser(ConfigParser):
|
|
"""
|
|
Specialized version of Python ConfigParser:
|
|
- if no filenames are given, read the default config files
|
|
- values are automatically quoted on setting (if required) und
|
|
unquoted on reading
|
|
"""
|
|
|
|
def read(self, filenames):
|
|
"""Read configuration files given as filenames. If no names are given,
|
|
the default fax and voice files are read.
|
|
"""
|
|
if not filenames:
|
|
ConfigParser.read(self, configfile_fax)
|
|
ConfigParser.read(self, configfile_voice)
|
|
else:
|
|
ConfigParser.read(self, filenames)
|
|
|
|
def get(self, section, option):
|
|
"""Get the value of the option from the given section (w/o quot. marks)."""
|
|
value = ConfigParser.get(self, section, option)
|
|
if len(value) > 1 and value[0] == '"':
|
|
value = value[1:-1]
|
|
self.set(section, option, value)
|
|
return value
|
|
|
|
def getList(self, section, option):
|
|
"""Return the value of the option from the given section as a list.
|
|
Commas are used as separators and leading and trailing whitespaces are
|
|
removed from all items."""
|
|
return map(string.strip, self.get(section, option).split(','))
|
|
|
|
def getUser(self, user, option, default=None, fail=0):
|
|
"""Get an option from the user or global section.
|
|
|
|
The option is searched in the user's section and if not found
|
|
in the global section.
|
|
|
|
'config' the ConfigParser object containing the values
|
|
'user' user section to use, if empty only global section is read
|
|
'option' the name of the option to search for
|
|
|
|
Returns the value for this option or None if it's not found
|
|
"""
|
|
retval = None
|
|
if self.has_option(user, option):
|
|
retval = self.get(user, option)
|
|
elif self.has_option('GLOBAL', option):
|
|
retval = self.get('GLOBAL', option)
|
|
elif fail:
|
|
raise NoOptionError(user, option)
|
|
# don't return empty values
|
|
if not retval is None:
|
|
return retval
|
|
return default
|
|
|
|
def listUsers(self):
|
|
ul = [ u
|
|
for u in self.sections()
|
|
if u not in consts.__known_sections__ ]
|
|
return ul
|
|
|
|
def items(self, section):
|
|
"""
|
|
Return a dictionary (name, value) for each option in the section.
|
|
|
|
NB: This differs from ConfigParser.items() which returns a list of
|
|
tuples!
|
|
"""
|
|
items = {}
|
|
for key, value in ConfigParser.items(self, section):
|
|
if len(value) > 1 and value[0] == '"':
|
|
value = value[1:-1]
|
|
items[key] = value
|
|
return items
|
|
|
|
def set(self, section, option, value):
|
|
if isinstance(value, types.StringTypes):
|
|
if not value or value[0].isspace() or value[-1].isspace():
|
|
value = '"%s"' % value
|
|
ConfigParser.set(self, section, option, value)
|
|
|
|
|
|
class JobDescription:
|
|
def __init__(self, filename=None, defaults=None):
|
|
self._config = config = CSConfigParser(defaults)
|
|
config.add_section('GLOBAL')
|
|
if filename:
|
|
config.read(filename)
|
|
|
|
def add_section(self, section):
|
|
if 1: # PyChecker should _not_ take this a an abstract method
|
|
raise NotImplementedError
|
|
remove_section = add_section
|
|
|
|
def options(self): return self._config.options('GLOBAL')
|
|
def items(self): return self._config.items('GLOBAL')
|
|
def get(self, option): return self._config.get('GLOBAL', option)
|
|
def getint(self, option): return self._config.getint('GLOBAL', option)
|
|
def getfloat(self, option): return self._config.getfloat('GLOBAL', option)
|
|
def getboolean(self, option): return self._config.getboolean('GLOBAL', option)
|
|
def has_option(self, option): return self._config.has_option('GLOBAL', option)
|
|
def set(self, option, value): return self._config.set('GLOBAL', option, value)
|
|
def remove_option(self, option): return self._config.remove_option('GLOBAL',option)
|
|
def read(self, filenames): return self._config.read(filenames)
|
|
def readfp(self, fp, filename=None): return self._config.read(fp, filename)
|
|
|
|
def writefp(self, fp):
|
|
print >> fp, "# Description file for", self.get('filename')
|
|
print >> fp, "# This if for internal use of CapiSuite."
|
|
print >> fp, "# Only change if you know what you do!"
|
|
self._config.write(fp)
|
|
|
|
def write(self, filename):
|
|
self.writefp(open(filename, 'w'))
|
|
|
|
def x__getattr__(self, attr):
|
|
return getattr(self._config, attr)
|
|
def x__setattr__(self, attr, value):
|
|
setattr(self._config, attr, value)
|
|
|
|
###--- utility functions ---###
|
|
|
|
|
|
def readGlobalConfig(file=None):
|
|
"""read configuration file and return a ConfigParser object
|
|
|
|
The configfile is read from the path given above and the
|
|
surrounding quotation marks from the values are removed.
|
|
|
|
Returns the constructed CSConfigParser object
|
|
"""
|
|
config = CSConfigParser()
|
|
config.read(file)
|
|
if not config.has_section('GLOBAL'):
|
|
raise NoGlobalSectionError()
|
|
return config
|
|
|
|
def readDescription(jobfilename):
|
|
"""read (job) description file for received fax or voice
|
|
|
|
This function reads an INI-style description file which has prior
|
|
been written by writeDesc() .
|
|
|
|
jobfilename the job' filename (with extension .txt)
|
|
|
|
Returns the filename the data filename (with extension) and
|
|
content the description as a dictionary
|
|
"""
|
|
control = JobDescription()
|
|
control.read(jobfilename)
|
|
filename = control.get('filename')
|
|
description = control.items()
|
|
return filename, description
|
|
|
|
|
|
def createDescriptionFor(filename, **description):
|
|
"""write (job) description file for received fax or voice
|
|
|
|
This function writes an INI-style description file for the given
|
|
data file which can later on be read by the CSConfigParser
|
|
instance. The data file name is used, the extension stripped and
|
|
replaced by .txt
|
|
|
|
filename the data filename (with extension),
|
|
content the description as a dictionary
|
|
"""
|
|
assert isinstance(description, dict)
|
|
descrname = os.path.splitext(filename)[0] + '.txt'
|
|
control = JobDescription()
|
|
control.set('filename', filename)
|
|
for key, value in description.items():
|
|
control.set(key, value)
|
|
control.write(descrname)
|
|
return descrname
|