Index: SrvTxtUtils.py
===================================================================
--- SrvTxtUtils.py	(revision 585)
+++ SrvTxtUtils.py	(revision 613)
@@ -8,9 +8,47 @@
 import stat
 import urllib
-import urllib2
 import logging
-
-
-srvTxtUtilsVersion = "1.6"
+import time
+import re
+import string
+import datetime
+try:
+    import httplib2
+    httplib = 'httplib2'
+except:
+    logging.warn("Unable to import httplib2! Falling back to urllib2!")
+    import urllib2
+    httplib = 'urllib2'
+
+import xml.etree.ElementTree as ET
+
+srvTxtUtilsVersion = "1.12.1"
+
+map_months = {'en': [u"",
+               u"January",
+               u"February",
+               u"March",
+               u"April",
+               u"May",
+               u"June",
+               u"July",
+               u"August",
+               u"September",
+               u"October",
+               u"November",
+               u"December"],
+              'de': [u"",
+               u"Januar",
+               u"Februar",
+               u"M\u00e4rz",
+               u"April",
+               u"Mai",
+               u"Juni",
+               u"Juli",
+               u"August",
+               u"September",
+               u"Oktober",
+               u"November",
+               u"Dezember"]}
 
 def getInt(number, default=0):
@@ -38,5 +76,5 @@
             return s.decode('latin-1')
     else:
-        return unicode(s)
+        return s
 
 def utf8ify(s):
@@ -45,11 +83,11 @@
     if not s:
         return ""
-    if isinstance(s, unicode):
+    if isinstance(s, str):
+        return s
+    else:
         return s.encode('utf-8')
-    else:
-        return str(s)
 
 def getText(node, recursive=0):
-    """returns all text content of a node and its subnodes"""
+    """returns all text content of a (etree) node and its subnodes"""
     if node is None:
         return ''
@@ -75,6 +113,72 @@
 
 
-
-def getHttpData(url, data=None, num_tries=3, timeout=10, noExceptions=False):
+def serialize(node):
+    """returns a string containing an XML snippet of (etree) node"""
+    s = ET.tostring(node, 'UTF-8')
+    # snip off XML declaration
+    if s.startswith('<?xml'):
+        i = s.find('?>')
+        return s[i+3:]
+
+    return s
+
+
+def getMonthName(mon, lang):
+    """returns the name of the month mon in the language lang"""
+    return map_months[lang][mon]
+
+
+def getDateString(date=None, lang='en', withYear=True, monthNames=True, abbrev=False):
+    """Return formatted date string."""
+    if date is None:
+        return None
+    
+    ds = None
+    if callable(date.day):
+        # callable members
+        day = date.day()
+        month = date.month()
+        year = date.year()
+    else:
+        # data members
+        day = date.day
+        month = date.month
+        year = date.year
+        
+    if lang.lower() == 'en':
+        ds = "%s %s"%(getMonthName(month, lang), day)
+        if withYear:
+            ds += ", %s"%year
+            
+    elif lang.lower() == 'de':
+        ds = "%s. %s"%(day, getMonthName(month, lang))
+        if withYear:
+            ds += " %s"%year
+
+    elif lang.lower() == 'iso':
+        ds = date.isoformat()
+            
+    return ds
+        
+
+def getDate(date):
+    """return date object from date or datetime date."""
+    if isinstance(date, datetime.datetime):
+        # strip time
+        return date.date()
+    
+    return date
+
+
+def getDatetime(date):
+    """return datetime object from date or datetime date."""
+    if isinstance(date, datetime.date):
+        # add time 0:00
+        return datetime.datetime.combine(date, datetime.time())
+    
+    return date
+
+
+def getHttpData(url, data=None, num_tries=3, timeout=10, username=None, password=None, cache=None, insecure=False, noExceptions=False):
     """returns result from url+data HTTP request"""
     # we do GET (by appending data to url)
@@ -85,35 +189,53 @@
         # urlencode
         url = "%s?%s"%(url,urllib.urlencode(data))
-    
-    response = None
+
     errmsg = None
-    for cnt in range(num_tries):
-        try:
-            logging.debug("getHttpData(#%s %ss) url=%s"%(cnt+1,timeout,url))
-            if sys.version_info < (2, 6):
-                # set timeout on socket -- ugly :-(
-                import socket
-                socket.setdefaulttimeout(float(timeout))
-                response = urllib2.urlopen(url)
-            else:
-                # timeout as parameter
-                response = urllib2.urlopen(url,timeout=float(timeout))
-            # check result?
-            break
-        except urllib2.HTTPError, e:
-            logging.error("getHttpData: HTTP error(%s): %s"%(e.code,e))
-            errmsg = str(e)
-            # stop trying
-            break
-        except urllib2.URLError, e:
-            logging.error("getHttpData: URLLIB error(%s): %s"%(e.reason,e))
-            errmsg = str(e)
-            # stop trying
-            #break
-
-    if response is not None:
-        data = response.read()
-        response.close()
-        return data
+    if httplib == 'httplib2':
+        # use httplib2
+        for cnt in range(num_tries):
+            try:
+                logging.debug("getHttp(lib2)Data(#%s %ss) url=%s"%(cnt+1,timeout,url))
+                h = httplib2.Http(cache=cache, timeout=float(timeout), disable_ssl_certificate_validation=insecure)
+                if username:
+                    h.add_credentials(username, password)
+                    
+                resp, data = h.request(url)
+                return data
+            
+            except httplib2.HttpLib2Error, e:
+                logging.error("getHttp(lib2)Data: HTTP error(%s): %s"%(e.code,e))
+                errmsg = str(e)
+                # stop trying
+                break
+    
+    else:
+        # use urllib2 
+        response = None
+        for cnt in range(num_tries):
+            try:
+                logging.debug("getHttpData(#%s %ss) url=%s"%(cnt+1,timeout,url))
+                if sys.version_info < (2, 6):
+                    # set timeout on socket -- ugly :-(
+                    import socket
+                    socket.setdefaulttimeout(float(timeout))
+                    response = urllib2.urlopen(url)
+                else:
+                    # timeout as parameter
+                    response = urllib2.urlopen(url,timeout=float(timeout))
+                # check result?
+                data = response.read()
+                response.close()
+                return data
+
+            except urllib2.HTTPError, e:
+                logging.error("getHttpData: HTTP error(%s): %s"%(e.code,e))
+                errmsg = str(e)
+                # stop trying
+                break
+            except urllib2.URLError, e:
+                logging.error("getHttpData: URLLIB error(%s): %s"%(e.reason,e))
+                errmsg = str(e)
+                # stop trying
+                #break
     
     if noExceptions:
@@ -134,6 +256,34 @@
 
 
+def shortenString(s, l, ellipsis='...'):
+    """returns a string of length l (or l-1) by omitting characters in the middle of s, replacing with ellipsis."""
+    if len(s) <= l:
+        return s
+    
+    l1 = int((l - len(ellipsis)) / 2)
+    return "%s%s%s"%(s[:l1],ellipsis,s[-l1:])
+
+
+def sqlName(s, lc=True, more=''):
+    """returns restricted ASCII-only version of string"""
+    if s is None:
+        return ""
+    
+    if not isinstance(s, basestring):
+        # make string object
+        s = str(s)
+        
+    # remove '
+    s = s.replace("'","")
+    # all else -> "_"
+    s = re.sub('[^A-Za-z0-9_'+more+']','_',s)
+    if lc:
+        return s.lower()
+    
+    return s
+
+
 def getBrowserType(self):
-    """check the browsers request to find out the browser type"""
+    """(legacy) check the browsers request to find out the browser type"""
     bt = {}
     ua = self.REQUEST.get_header("HTTP_USER_AGENT")
@@ -161,3 +311,2 @@
     return bt
 
-
