Welcome To Our Shell

Mister Spy & Souheyl Bypass Shell

Current Path : /home/ift/51_iftlib/data/

Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
Upload File :
Current File : //home/ift/51_iftlib/data/template.py

#  coding: utf-8

import os,re,sys,time,random,glob


class Template (object):

    def __init__ (self):
    
        self.compiled_text_pattern = {}
        self.entry_cache           = {}
        self.DYNFIELD              = True
        self.sorted_fields         = []
        
#****************************************************************************

    def ff_file (self,text,entry=False):   #  Filename normalisieren

        text1 = text
        text1 = re.sub(r"(^|\/|\\)x","\\1-x",text)
#        text1 = re.sub(r"^--","-","-"+text1)
        text2 = re.sub(r"(-)(x?)(\d*[A-Z][A-Za-z0-9]*?|x)(\d*)-","",text1,99999999)
        text1 = self.ff(text1,entry)
        text1 = re.sub(r"[\;\: \?\!]","_",text1,99999999)
        text1 = re.sub("ü","ue",text1,99999999)
        text1 = re.sub("ö","oe",text1,99999999)
        text1 = re.sub("ä","ae",text1,99999999)
        text1 = re.sub("Ü","Ue",text1,99999999)
        text1 = re.sub("Ä","Ae",text1,99999999)
        text1 = re.sub("Ö","Oe",text1,99999999)
        text1 = re.sub("ß","ss",text1,99999999)
        text1 = re.sub(r"___","/",text1,99999999)
        text1 = re.sub(r"^-","",text1)
        text1 = re.sub(r"\+","-",text1)
        text1 = re.sub(r"\/","_",text1)
        if text2.lower() == text2 and not "-" in text2:
            text1 = text1.lower()

        return(text1)
        
#****************************************************************************

    def ff (self,text,entry=False):
    
        """
        Replaces in the string variable all occurrences of  -KEYNAME- by
        the value of entry.KEYNAME  (KEYNAME stands for  alphanumeric key notators)
        
        A special 'keyname' is: REST. It produces a printout of all 'remaining'
        key-value pairs.
        """

#        text = re.sub(r'\\',r'\\\\',text,99999999,flags=re.DOTALL)
#        text = re.sub(r'\[','@a@',text,99999999,flags=re.DOTALL)
#        text = re.sub(r'\]','@b@',text,99999999,flags=re.DOTALL)
#        text = re.sub(r'\\','@c@',text,99999999,flags=re.DOTALL)
#        print text

#        while re.search(r"\.",text):   #   Das Template kann auch eine Funktion aus einem Modul sein
#            m = re.search(r"^(.*)\.(.*)$",text)
#            try:
#                exec "import " + m.group(1)
#            except:
#                break
#            exec "erg =  " + text + "(entry)"
#            return(erg)

        if text in self.compiled_text_pattern:
            text1 = self.compiled_text_pattern[text]
        else:
            text1 =  re.sub(r"(-)(x?)(\d*[A-Za-z\_0-9\.]+?|x)(\d*)-","@SEPARATOR@"+"\\2,\\3,\\4"+"@SEPARATOR@",
                           text,99999999,flags=re.DOTALL)
#            text1 =  ( "u\'\'\'" + re.sub(r"(-)(x?)(\d*[A-Za-z\_0-9\.]+?|x)(\d*)-",
#                          "\'\'\'+unicode(self.valfield(entry,\"\\2\",\"\\3\",\"\\4\"))+u\'\'\'",
#                          text,99999999,flags=re.DOTALL) + "\'\'\'" )
            text2     = text1.split("@SEPARATOR@")
            text1     = ""
            translate = False
            for textpattern in text2:
                if translate:
                    textpattern1 = textpattern.split(",")
                    textpattern1 = self.valfield(entry,textpattern1[0],textpattern1[1],textpattern1[2])
                    text1        = text1 + textpattern1
                else:
                    text1        = text1 + textpattern
                translate = not translate

            self.compiled_text_pattern[text] = text1


        while (0 == 0):  #  substitution of include files
            break
            m = re.search(r"^(.*?)\[(\S+?)\](.*)$",text1,re.DOTALL)
            if not m:
                break
            file9 = ""
            if os.path.isfile(m.group(2)):
                file9 = m.group(2)
            elif os.path.isfile(self.ff_file(m.group(2))):
                file9 = self.ff_file(m.group(2))
            if file9:
                text1 = m.group(1) + open(file9,'r').read() + m.group(3)
            else:
                text1 = m.group(1) + "[-x-x-]" + m.group(2) + "[-y-y-]" + m.group(3)
        text1 = re.sub(r"\[-x-x-\]","[",text1,99999999)
        text1 = re.sub(r"\[-y-y-\]","]",text1,99999999)
        erg   = text1

#        print("\n\n----",erg,entry)

        return(erg)
        

#**************************************************************************

    def ff_content (self,text,entry=False):   #  Filename normalisieren

        text1 = self.ff(text,entry)
#        text1 = self.ff(text1,entry)
#        m = re.search(r"PERSONALIZE: +(.+?),(.+?),(.+?),(.+?),(.+?),(.*?),(.*?),(.*?),(.+?),(.+?),",text1)
#        if m:
#            self.entry_cache['TOADR']      = m.group(3)
#            self.entry_cache['TONAME']     = m.group(4)
#            self.entry_cache['TOANREDE']   = m.group(5)
#            self.entry_cache['TOAMODE']    = m.group(6)
#            self.entry_cache['TOBMODE']    = m.group(7)
#            self.entry_cache['TOCMODE']    = m.group(8)
#            self.entry_cache['TOGRUSS']    = m.group(9)
#            self.entry_cache['TOABSENDER'] = m.group(10)
#            text1 = self.ff(text,entry)
#            text1 = re.sub(r"DELTEXT.*?DELTEXT",text1,99999999,flags=re.DOTALL)

        return(text1)

#*************************************************************************

    def xxvalfield (self,entry,delflag,field,nr=""):
    
        erg0 = None
        erg  = self.valfield1(entry,delflag,field,nr)
        return(self.ff(erg,entry))
#        return(erg)
#        while (0 == 0):
#            print erg, erg0
#            if erg0 and erg0 == erg:
#                return(erg)
#            erg0 = erg
#            print erg, erg0
#            time.sleep(1)
#            erg  = self.ff(erg,entry)

#*************************************************************************

    def valfield (self,entry,delflag,field,nr=""):
    

        if field == "x" and delflag == "":
            delflag = "x"
            field   = ""

        erg = ""

        while (0 == 0):
            try:
                erg = self.entry_cache[field]
                break
            except:
                pass
                
            if not field == "DELETE":
                try:
                    erg = entry[field]
                except:
                    try:
                        erg = entry[field]
                    except:
                        try:
                            erg = entry[field+nr] ##  check!!! @@@@
                        except:
                            pass

            if erg == "" and not nr == "" and 'INDEXX' in entry:
                if re.search((field+nr),(" " + entry['INDEXX'] + " ")):
                   field = field+nr
                   nr    = ""
                   continue

            if not nr == "" and (field+nr) in entry:
                   field = field+nr
                   nr    = ""

            if type(erg) == type(None):
                erg = ""
            if not nr == "":
                try:
                    erg = (erg.split(","))[int(nr)-1]
                except:
                    pass
                    
            m = re.search(r"^([MW])(\d)([A-Z]+)$",field)  # personalized data
            if m:
                if re.search("^"+m.group(1).lowercase()+".* "+m.group(3).lowercase+mgroup(2),self.valfield(entry,"SEX")):
                    erg = "1"
                    break                

            if field == "COUNT":
                erg = str(self.entries_count)

            elif re.search(r"^REST",field):
                exclude_columns = field.split("_")
                field = "REST"
                erg   = ""
                ee    = list(entry.keys())
                ee.sort()
                for k in self.sorted_fields + ee:
                    if not k in entry:
                        continue
                    if not k in self.entry_cache and type(entry[k]) != type(None):
                        self.entry_cache[k] = str(entry[k])
                        if k == "MD5KEY" and not delflag == "":
                            continue
                        if k in exclude_columns:
                            continue
                        if k[0] == "_":
                            continue
#                        if field == "REST":
#                            erg = erg + "\n" + k + ": " + self.valfield(entry,"",k) + "\",\""
                        o   = str(entry[k]) 
                        if re.search(r"\n",o,re.DOTALL):
                            o = "\n" + o + "\n"
                        erg = erg + "\n" + ("%-15s" % (k + ": ")) + o + "\",\""
                erg = "\"" + erg + "\n\""
            self.entry_cache[field+nr] = erg
            break        

        if erg == "":
            m = re.search(r"^(.*)FROM(.*)",field)
            if m:
                erg = self.valfield(entry,delflag,m.group(1),nr)

        if erg == "" and field[0:2] == "TO" and not re.search(r"^(TOOLS?|TODO)$",field):
#            print field
            return(delflag+field[2:])
        if erg == "" and delflag == "":
            erg = "-" + field + nr + "-"
            

        if delflag == "x":   #  put it in double quotes if necessary
            try:
                erg = re.sub(r"^\"(.*)\"$","\\1",erg,flags=re.DOTALL)
                if re.search(r"[\"\,\n]",erg):
                    erg = '"' + erg + '"'
            except:
                pass

        try:
            erg = str(erg)
        except:
            pass

        if not re.search(r"^-[^-]*-$",erg):
            erg = self.ff(erg,entry)

        return(erg)

#*************************************************************************

    def export (self,tpl,entry,no_output_header=False):
    
        self.compiled_text_pattern = {}
        self.entry_cache           = {}

        tpl_file     = ""
        outputfile   = ""
        outputheader = ""
        
        if os.path.isfile(tpl):
        
            tpl_file   = tpl
            tpl        = open(tpl_file).read()
            outputfile = self.ff_file(tpl_file,entry)
            if outputfile == tpl_file:
                return("ERROR. Template and output file are identical")
            no_output_header = False

        output_header  = ""
        m = re.search(r"^\s*([^\n]+?)\s*$",tpl,flags=re.DOTALL)    #  wenn das Template nur aus einer einzigen
        if m:                                                      #  Zeile besteht, dann daraus einen
            output_header = re.sub(r"-x?","",m.group(1),99999999)  #  template header machen

        output_text = self.ff(tpl,entry)
        if output_header and not no_output_header:
            if not os.path.isfile(outputfile):
                output_text = output_header + "\n" + (len(output_header) * "-") + "\n\n" + output_text

        if outputfile:
            if "\n" in output_text:
                open(outputfile,"w").write(output_text)
            else:
                open(outputfile,"a").write(output_text)
            output_text = outputfile

        return(output_text)

#**********************************************************************************

    def csvimport (self,csvname,make_objid=False):  #  ,tmp_entry_list=[]):

        resultlist = []

        """
        This function upserts a bulk of key-value pairs from a csv-list
        into the database table  entries .
     
        The name of the resp. csv-file is in csvname
     
        The column names will be taken from the first valid line
        (comments starting with      , empty lines und and underlining lines consisting
        only from  ----  will be skipped)
        If column names are missing, they will be created on the fly with
        with names MISC01, MISC02, ....
     
        Each cell can overwrite the static column name under which it comes:
        By denoting   <key>:  <value>   the <value> goes into the row's
        key-value pairs with the key  <key>  and the value  <value> .
        (but only if the column does not end with _ and self.DYNFIELD = True)
        """

        text = self.read_excel_file(csvname)
  
        if not text:
            text = open(csvname,'r').read()
#            text = re.sub(r"\n([A-Z][A-Z]):","\n\\1_:",text,99999999)
#            text = text.replace('\r\n', '\n')
            cells = re.split(r'\"|$',text,99999999,flags=re.DOTALL)   #    make a list of all text patterns separated by "
            text  = re.sub(r"\"(.*?)\"","---FIELD---",text,99999999,re.DOTALL)  # replace all "..." cells with ---FIELD---
            m     = re.search(r"^(.*?---FIELD---)[^,\n]",text)
            if m:
                print("Error in csv-File" + m.group(1))
                return(0)
            text  = text.splitlines()
        
        cells_count        = -2
        entry0             = {}
        column_descriptors = []
        anzahl_importierte_datensaetze = 0
        
        for zeile in text:
            try:
               zeile_sum = zeile
               zeile     = zeile.split(",")
            except:
               zeile_sum = "".join(zeile)

            if re.search(r"^(#|\\-+ *$|-+ *$| *$|alter *table)",zeile_sum):   #  skip comments, empty lines,  underlining ---------
                continue

            m = re.search(r"^ *[qQ]\: *([^\n]*)$",zeile_sum)
            if m:
                self.import_query = m.group(1)
                continue

            if cells_count == -2:
                column_descriptors = zeile
                cells_count = -1
                continue
        
            entry   = {}
            zaehler = -1
            miscnr  = 0
            for cell in zeile:
                zaehler = zaehler + 1
                cell    = cell.strip()
                if cell == "---FIELD---":
                    cells_count = cells_count + 2
                    cell        = cells[cells_count].strip()

                while (0 == 0):
                    try:
                        if str(column_descriptors[zaehler]) == str(""):
                            miscnr = miscnr + 1
                            column_descriptors[zaehler] = str("MISC" + ("%02u" % miscnr))
                        break
                    except:
                        miscnr = miscnr + 1
                        column_descriptors.append(str("MISC" + ("%02u" % miscnr)))
                if re.search(r"^\s*$",cell,re.DOTALL):
                    continue
                field = column_descriptors[zaehler]

                if self.DYNFIELD and not field[-1] == "_":
                    m = re.search(r"^\s*([A-Za-z0-9\_]+)\: *(.*)$",cell,re.DOTALL)
                    if m:
                        field = m.group(1)
                        cell  = m.group(2)

                cell = re.sub(r"^\-\-\> *","",cell)
                cell = re.sub(r"\r","",cell,99999999)
                cell = re.sub(r"\t","    ",cell,99999999)
                cell = re.sub(r"\"","\'",cell,99999999)
                cell = cell.strip()
                if   field[0:3] == "XXX":
                    continue
                if   field == "":
                    continue
                if re.search(r"^\s*$",cell):
                    continue
                if   field == "MDEL":
                    entry['DELETE'] = cell
                elif field == "DEL":
                    if cell == "X":
                        entry['DELETE'] = cell
                elif field == "MD5KEY":
                    entry[field] = cell
                elif not re.search(r"^MISC\d+$",field):
                    entry[field] = cell
                if not '_FILE' in entry and not '_DIR' in entry:
                    filename = csvname
                    dirname  = "."
                    m = re.search(r"^(.*)[\\\/](.*)$",csvname)
                    if m:
                        dirname  = re.sub(r"[\\\/]","___",m.group(1),99999999)
                        filename = m.group(2)
                    entry['_FILE'] = filename
                    entry['_DIR']  = dirname
                if make_objid and not 'OBJID' in entry:
                    entry['OBJID'] = "%03u" % random.randint(110,990)

            if 'DELETE' in entry and entry['DELETE'] == "M":   #  2 WAY MERGE !
                entry1 = dict(entry0)
                for k in entry:
                    if k == "DELETE":
                        continue
                    if not k in entry1 or entry1[k] == "":
                        entry1[k] = entry[k]
                    elif not entry1[k] == entry[k]:
                        if re.search(r"^(INFO|INDEX+)$",k):
                            entry1[k] = entry1[k] + "\n" + entry[k]
#                        if re.search(r"^VDATE$",k):
#                            entry1[k] = entry[k]
                        else:
                            del entry1
                            break

            if 'entry1' in vars():
#                print "XXX: 1 -----------------------------------------------"
#                time.sleep(5)
                entry0 = entry1   #  entry1 is a merge result which could be merged again
            else:                 #  and therefore put in entry0
                entry1 = entry0
                entry0 = entry    #  No merge possible. So upsert the entry0 and make the
                entry  = entry1   #  entry to the new entry0. Roll back...
                del entry1
                
            delete_mode = 0
            if 'DELETE' in entry0 and entry0['DELETE'] == "X":
                delete_mode = 1
            else:
                anzahl_importierte_datensaetze = anzahl_importierte_datensaetze + 1
#            erg = self.db.upsert_extend(entry0)
            resultlist.append(entry0)

#            if erg:
#                entry0['MD5KEY'] = erg
#                tmp_entry_list.append(entry0)
#        print self.import_query

        self.column_descriptors = column_descriptors
        return(resultlist)                

#*************************************************************************

    def read_excel_file (self,xlsname):

        m = re.search(r"^(.*)\,(.*)$",xlsname)
        if m:
            xlsname = m.group(2)
        try:
            wb = xlrd.open_workbook(xlsname)
        except:
            return(None)
            
        sheets = wb.sheet_names()
        sheet  = sheets[0]
        if m:
            sheet = m.group(1)
        try:
            sheet  = wb.sheet_by_name(sheet)
        except:
            print("Sheets in the file " + m.group(2) + ":\n" + str(sheets))
            return(0)
        text   = []

#        xrows  = sheet.row(4)
        crows = 0
        while (0 == 0): 
            if crows == sheet.nrows:
                break
            ccols = 0
            text.append([])
            while (0 == 0):
                if ccols == sheet.ncols:
                    break
                cell_content = sheet.cell_value(crows,ccols)
                try:
                    if cell_content == int(cell_content):
                       cell_content = str(int(cell_content))
                except:
                    pass
                text[-1].append(str(cell_content))
                ccols = ccols + 1
            crows = crows + 1
            
#        print text
        return(text)

#*************************************************************************


class Xlsmanager (object):

    def __init__(self,db):

        try:
            self.db = sqlite3.connect(db)
        except:
            self.db = db


        cursor = self.dbh.cursor()
        try:
            cursor.execute("create table entries ("
                                 + "MD5KEY CHAR(25) UNIQUE,"
                                 + "OBJID VARCHAR(50) UNIQUE,"  
                                 + "OBJCLASS TEXT)"
                       )
        except:
            pass

        try:
            cursor.execute("create index md5keyidx on entries (MD5KEY)")
        except:
            pass

        try:
            cursor.execute("create index objididx on entries (OBJID)")
        except:
            pass

        self.dbh.commit()
        self.compiled_text_pattern = {}

        self.index_fields = {
              'DATUM'      : 1,
              'NAME'       : 1,
              'PLZ'        : 1,
              'STADT'      : 1,
              'TEL'        : 1,
              'KTOA'       : 1,
              'KTOB'       : 1,
            }

        self.sorted_fields = ('OBJCLASS NAME VORNAME STRASSE PLZ STADT TEL FAX MOBIL MAIL SEX INDEXX INFO ' +
                              'K KTO BANK BLZ STIMM END MD5KEY').split(" ")

#**********************************************************

    def oa (self,*pars):

        result_file = self.export_data(list(pars))
        print(result_file)
        if result_file and os.path.isfile(result_file):
            self.db.commit()
            print(("joe " + result_file))
            os.system("joe " + result_file)
            try:
                text = open(result_file,'r').read() 
                open(result_file,'w').write(text)
            except:
                pass
            self.export_data([result_file,"xyxyxyxyxyxyxyx","--"])
            self.db.commit()

#*************************************************************************

    def export_data (self,pars,print_to_console=True):
    
        """
        This function reads out data from the database in a rendered form.
      
        A parameter which is a .csv or .adr file is taken as a data source
        and its entries are upserted by the csvimport function.
      
        The other parameters are read in in the database in the order:
      
        First parameter (filter):     The sql-filter expression against the table  entries
                                      ( or the short form  <pattern1>,<pattern2>,...~<pattern3>, ....)
        Second parameter (template):  The text template. Each occurences of -<KEY>- will be
                                      replaced by the respective value of the actual entry.
                                      -x<KEY>- works at the same but replaced by "" if no
                                      such key exists.
                                      If the text template is a name of an existing file,
                                      then the contents will be written in files where
                                      the placeholders in the filename also are replaced,
                                      so that the can be as a result many files. The
                                      placeholders in the contents of the file wille be also
                                      replaced.
        Third parameter (sort1):      Sorts the entries to a pattern given by the template  sort1
                                      Each entries with the same sort1-Value will be given
                                      to the merge function which returns a merged list
                                      of entries.
        Fourth paramater (filter_template):  Filters  filter , but on the
                                      pattern given by filter_template, and only if the
                                      form  <pattern1>,<pattern2>,...~<pattern3>, ....
                                      for filter is used
        """

        pars1 = []   #   Aufloesung von Wildcards, ggfs aus der Windows-Shell
        for par in pars:
            par = re.sub(r"'","",par,9999)
            if re.search(r"\*",par):
                pars1 = pars1 + glob.glob(par)
            else:
                pars1.append(par)
        pars = pars1


#   1.   Preparation of parameters   ------------------------------------


        def sort_e (x):
            if 'VDATE' in x:
                erg = x['VDATE']
            else:
                erg = 99999999
            return(erg)
                
        self.output_text    = ""
        self.import_query   = ""
        obj_to_change_entry = None

        if "__MERGE__" in pars:
            self.merge_files = []

        for par in pars:

            par = par.strip()  #  .decode(self.local_enc)       #  hier wird erstmal getestet, ob ein Parameter ein File ist
            m = re.search(r"^(.*),(.*)$",par)
            if m:
                parfile = m.group(2)
            else:
                parfile = par
#            print("import " + re.sub(r"^(.*)\.(.*)$","\\1",par))
            try:    #   hier versuchen, den Paraeter als entry-changing Objekt zu laden
                exec("import " + re.sub(r"^(.*)\.(.*)$","\\1",par))
                exec("obj_to_change_entry = " + par + "()")
                continue
            except Exception as e:
                pass

            if not 'filter' in vars():
                if (os.path.isfile(parfile)):
                    if 'merge_files' in vars(self):  #  nur der Ancestor muss sich von den anderen Eintraegen unterscheiden                    
                        anzahl_importierte_datensaetze = self.csvimport(par,len(self.merge_files)==0)   #  ,tmp_entry_list)
                        self.merge_files.append(par)
                    else:
                        anzahl_importierte_datensaetze = self.csvimport(par)  #  ,tmp_entry_list)
                else:
                    if 'merge_files' in vars(self):
                        if par == "__MERGE__":
                            filter = '~'
                    else:
                        filter = par 
            elif not 'template' in vars():
                template        = par
            elif not 'sort1'    in vars():
                sort1           = par
            elif not 'filter_template' in vars():
                filter_template = par

#        print self.merge_files

        if self.db.upsert_hold_backs():  #  Read in hold back entries which have an OBJID field with value:
#            tmp_entry_list.append(self.db.hold_back)
#            anzahl_importierte_datensaetze = anzahl_importierte_datensaetze + len(self.db.hold_back)
#            self.db.hold_back = []
            self.db.commit()             #  \D*9+\D*, to get new OBJID computation

        if not 'filter' in vars():
            filter = "~" 
        if not 'template' in vars():
#            template = "-MD5KEY-,-REST-"
            template = "-REST_MD5KEY-"

        output_file_template = ""         #  define an output file
        if 'merge_files' in vars(self):    #  __MERGE__
            output_file_template = re.sub(r"\.xlsx?$",".csv","x-" + self.merge_files[1])  #  write back the 3way result in %A-file for git
            print(output_file_template)
            os.unlink(self.merge_files[1])
        if os.path.isfile(template):       #  wenn das Template ein File ist, dieses einlesen
            output_file_template = template
            text = self.read_excel_file(output_file_template)   #  erstmal versuchen, als Excel-File einzulesen
            if text:
                template = ""
                for xls_row in text:
                    zeile = ",".join(xls_row)
                    template = template + zeile + "\n"
            else:
                template = open(output_file_template,'r').read()
            if re.search(r"(csv|xlsx?)$",output_file_template):
                template = re.sub(r"\r?\n","",template,99999999)
            template = template.strip()

#        template = re.sub(r"\\n","\n",template,99999999,flags=re.DOTALL) # keine Ahnung mehr, wozu diese Zeile gut sein sollte

        convert_to_xls = False
        output_header  = ""
        m = re.search(r"^\s*([^\n]+?)\s*$",template,flags=re.DOTALL)  #  wenn das Template nur aus einer einzigen
        if m:
            output_header = re.sub(r"-x?","",m.group(1),99999999)     #  Zeile besteht, dann daraus einen template header
            if re.search(r"\{.*\}",output_header):                    #  erzeugen
                convert_to_xls = True   #  wenn xls-Formatierungen vorgefunden werden, in Excel-Tabelle schreiben
                m = re.search(r"^(\{.*?\})(.*)$",output_header,flags=re.DOTALL)
                if m:
                    output_header = re.sub(r"\{.*?\}","",m.group(2),99999999)
                    output_header = re.sub(r"($|,)",m.group(1)+"\\1",output_header,99999999)
                    template      = re.sub(r"^\{(.*?)\}(.*)$","\\2",template)
        
#   2.   Pre-Filter  ------------------------------------

        cursor = self.db.query_data(filter)

        if 'filter_template' in vars():
            filter_conditions = []
            for pattern in filter.split("~"):
                filter_conditions.append(pattern.split(","))
            entries = []
            while (0 == 0):
                self.entry_cache           = {}
                self.compiled_text_pattern = {}
                entry = self.db.next_obj(cursor,obj_to_change_entry)
                if not entry:
                    break
                filter_str = self.ff(filter_template,entry)
                for p1 in filter_conditions:
                    bed = True
                    for p2 in p1:
                        if re.search(p2,filter_str):
                            continue
                        bed = False
                        break
                    if bed:
                        break
                if bed:
                    entries.append(entry) 
                    
#   3.   Post-Sort by Sort-Pattern  ------------------------------------
                    
        if 'sort1' in vars():
            entries_by_sort = {}
            zaehler         = 0
            while (0 == 0):
                self.entry_cache           = {}
                self.compiled_text_pattern = {}
                if 'filter_template' in vars():
                    try:
                        entry  = entries[zaehler]
                    except:
                        break
                    zaehler = zaehler + 1
                else:
                    entry = self.db.next_obj(cursor,obj_to_change_entry)
                    if not entry:
                        break
                sort_text  = self.ff(sort1,entry)
                if sort_text in entries_by_sort:
                    entry['DEL'] = "M"
                if not sort_text in entries_by_sort:
                    entries_by_sort[sort_text] = []
                entries_by_sort[sort_text].append(entry)
            sorting_of_entries = list(entries_by_sort.keys())
            sorting_of_entries.sort()
            entries = []
            for sort_text in sorting_of_entries:   #   sort the grouped entries
                entries1 = []
                for e in entries_by_sort[sort_text]:
                    entries1.append(e)
                entries1.sort(key=sort_e)
                entries1.reverse()
                if 'merge_files' in vars(self):
                    entries1 = self.merge_23way(entries1)
                if not 'VDATE' in entries1[0] and 'DEL' in entries1[0]:  #  VDATE can be a date to which the entry is vaiid
                    del entries1[0]['DEL']
                entries = entries + entries1
                
#    4. ------------------  Main loop   -------------------------------

        zaehler            = 0
        self.entries_count = 0
        touched_files      = {}

        while (0 == 0):
            self.entry_cache           = {}
            self.compiled_text_pattern = {}
            if 'entries' in vars():
                try:
                    entry = entries[zaehler]
                except:
                    break
                zaehler = zaehler + 1
            else:
                entry = self.db.next_obj(cursor,obj_to_change_entry)
                if not entry:
                    break
            output_file    = self.ff_file(output_file_template,entry)
            if output_file == output_file_template:
                output_file = ""    #  to prevent from overwriting template-file
            output_content = self.ff_content(template,entry)
            
            m = re.search(r"^(.*)\/(.*)$",output_file)
            if m:
                try:
                    os.makedirs(m.group(1))
                except:
                    pass
                    
            if not output_file in touched_files:
                touched_files[output_file] = 1
                if output_file == "":
                    if print_to_console:
                        print(output_header)
                        print(re.sub(r".","-",output_header))
                    else:
                        self.output_text = self.output_text + output_header
                        self.output_text = self.output_text + re.sub(r".","-",
                               re.sub(r"\{[a-z0-9]+\}","",output_header,9999))
                else:
                    open(output_file,'w').write(output_header+"\n")
                    if print_to_console:
                        print(output_file) # .encode(self.local_enc)
                    else:
                        self.output_text = self.output_text + output_file
                    open(output_file,'a').write(re.sub(r".","-",
                           re.sub(r"\{[a-z0-9]+\}","",output_header,9999))+"\n")
            cr = ""
            text = self.ff_content(template,entry)
            if re.search("\n",text):
                cr = "\n"
            if output_file == "":
                if print_to_console:
                    print((cr+text+cr))  #  .encode(self.local_enc))
                else:
                    self.output_text = self.output_text + cr + text + cr
            else:
                if os.path.isfile(output_file):
                    open(output_file,'a').write(cr+text+cr+"\n")
                else:
                    open(output_file,'a').write(text+cr+"\n")

#    5.   ------ Conversion of files to xls

        if convert_to_xls:
    
            for file in touched_files:

                template_content1 = open(file,'r').read()
#                print template_content1
                if re.search(r"NOXLS",template_content1) and len(touched_files) > 1:
                    open(file,"w").write(re.sub(r"\{[a-z0-9]+\}","",template_content1,99999999))
                    continue
                os.unlink(file)
                template_content1 = re.sub(r"\n\"[\n ]+\n","\n\"\n",template_content1,99999999)
                template_content1 = re.sub(r"\n-+\n","\n",template_content1,99999999)
                template_content1 = re.sub(r"\n *\n","\n",template_content1,99999999)
                template_content1 = re.sub(r"\n *\n","\n",template_content1,99999999)
                template_content1 = re.sub(r"\n\"[\n ]+\n","\n\"\n",template_content1,99999999)
                template_content1 = re.sub(",\"\s*([A-Za-z\_0-9]+)\: *",",\"\\1: ",template_content1,99999999)
                template_content1 = re.sub(",\"\n\"","",template_content1,99999999)
                template_content1 = re.sub(r"\\\"","",template_content1,99999999)
                cells             = re.split(r"\"|$",template_content1,99999999,flags=re.DOTALL)
                cells_count       = -1
                template_content1 = re.sub(r"\"(.*?)\"","---FIELD---",template_content1,99999999,flags=re.DOTALL)
                m = re.search(r"^(.*)\.(.*)$",file)
                if not m:
                    continue
                sheet_name = m.group(2)
                if not m.group(1) == "":
                    file = m.group(1) + ".xls"

#   ----------------------------------

                try:
                    wb0 = xlrd.open_workbook(file,formatting_info=True)
                except:
                    wb0 = None
                    
                if wb0:
                    wb1 = xlutils.copy.copy(wb0)
                else:
                    wb1 = xlwt.Workbook(encoding=self.local_enc)   #  open the new excel-workbook

#                oldsheets = []
#                opennew = False
#                zaehler = 0
#                sheets_idx = {}
#                for sheet in wb1._Workbook__worksheets:
#                    print sheet.name
#                    if sheet.name == sheet_name:                      TODO!!!
#                        opennew   = True
#                    else:
#                        oldsheets.append(sheet)
#                        sheets_idx[sheet.name] = zaehler
#                        zaehler = zaehler + 1
#                if opennew:
#                    wb1._Workbook__worksheets = oldsheets
#                    wb1._Workbook__worksheet_idx_from_name = sheets_idx
#                    wb1.save(file)
#                    wb  = xlrd.open_workbook(file,formatting_info=True)
#                else:
#                    wb = wb1

                wb = wb1

                wb.set_colour_RGB(51, 200, 255, 200)  #  green         0x51,
                xlwt.Style.add_palette_colour("ga",51)
                wb.set_colour_RGB(52, 100, 204, 100)  #                0x52,
                xlwt.Style.add_palette_colour("gb",52)
                wb.set_colour_RGB(53,  51, 153,  51)  #                0x53,
                xlwt.Style.add_palette_colour("gc",53)

                wb.set_colour_RGB(55, 255, 255, 200)  #  yellow        0x55,
                xlwt.Style.add_palette_colour("ya",55)
                wb.set_colour_RGB(56, 255, 255, 130)  #                0x56,
                xlwt.Style.add_palette_colour("yb",56)
                wb.set_colour_RGB(57, 255, 255,   0)  #                0x57,
                xlwt.Style.add_palette_colour("yc",57)

                wb.set_colour_RGB(60, 255, 200, 200)  #  red           0x60,
                xlwt.Style.add_palette_colour("ra",60)
                wb.set_colour_RGB(61, 255, 120, 120)  #                0x61,
                xlwt.Style.add_palette_colour("rb",61)
                wb.set_colour_RGB(62, 255,   0,   0)  #                0x62,
                xlwt.Style.add_palette_colour("rc",62)

                wb.set_colour_RGB(45, 200, 200, 250)  #  blue          0x45,
                xlwt.Style.add_palette_colour("ba",45)
                wb.set_colour_RGB(46, 100, 100, 200)  #                0x46,
                xlwt.Style.add_palette_colour("bb",46)
                wb.set_colour_RGB(47,  90,  90, 150)  #                0x47,
                xlwt.Style.add_palette_colour("bc",47)

                wb.set_colour_RGB(48, 220, 220, 220)  #  grey          0x48,
                xlwt.Style.add_palette_colour("ea",48)
                wb.set_colour_RGB(49, 180, 180, 180)  #                0x49,
                xlwt.Style.add_palette_colour("eb",49)
                wb.set_colour_RGB(50,   0,   0,   0)  #                0x50,
                xlwt.Style.add_palette_colour("ec",50)

                nr = None
#                print wb.__active_sheet
                if sheet_name in wb._Workbook__worksheet_idx_from_name:
                    nr = wb._Workbook__worksheet_idx_from_name[sheet_name]
                    del wb._Workbook__worksheet_idx_from_name[sheet_name]
                    wb._Workbook__worksheets[nr] = None
                newsheet = wb.add_sheet(sheet_name)
                if not nr == None:
                    wb._Workbook__worksheets[nr] = wb._Workbook__worksheets[-1]
                    wb._Workbook__worksheets     = wb._Workbook__worksheets[:-1]

                crows = 0
                for zeile in template_content1.split("\n"):
                    if re.search(r"^\s*$",zeile ):
                        break
                    ccols = 0
                    for cell_content in zeile.split(","):
                        while (0 == 0):
                            m = re.search(r"^(.*)(\{(.*)\})\{(.*)\}$",cell_content,re.DOTALL)
                            if not m:
                                break
                            cell_content = m.group(1) + m.group(2)
                        m = re.search(r"^(\-\-\-FIELD\-\-\-)(.*)$",cell_content,flags=re.DOTALL)
                        if m:
                            cells_count  = cells_count + 2
                            cell_content = cells[cells_count].strip() + m.group(2)
                        cellstyle = self.style_wb("")
                        m         = re.search(r"^(.*)\{(.*)\}$",cell_content,flags=re.DOTALL)
                        if not m:
                            m1 = re.search(r"^(.*)(\{.*\})$",zeile,flags=re.DOTALL)
                            if m1:
                                cell_content = cell_content + m1.group(2)
                                m = re.search(r"^(.*)\{(.*)\}$",cell_content,flags=re.DOTALL)
                        if m:
                            cellstyle    = self.style_wb(m.group(2))
                            cell_content = m.group(1)
                        newsheet.write(crows,ccols,cell_content,cellstyle)
                        if crows == 1:
                            m1 = re.search(r"^(\d+)",m.group(2))
                            if m1:
                                newsheet.col(ccols).width = 256*int(m1.group(1))
                        ccols = ccols + 1
                    crows = crows + 1

                wb.save(file)


        if not len(touched_files) == 1:
            return("")
            
        if not re.search(r"(^|,)REST($|,)",output_header):
            return("")
            
        if convert_to_xls:
            return("")

        return(list(touched_files.keys())[0])


#*************************************************************************


    def style_wb (self,style_marker):
       
       style_color = "w"
       style_size  = 12
       style_ftype = "n"
       style_pos   = "l"
       m = re.search(r"^(\d*)(c?)(.*?)(\d+)(\D?)$",style_marker)
       if m:
           style_pos    = m.group(2)
           style_color  = m.group(3)
           style_size   = m.group(4)
           style_ftype  = m.group(5)
           
       if re.search(r"^()$",style_ftype):
           style_ftype = "n"
       if re.search(r"^()$",style_pos):
           style_pos = "l"
       if style_color == "w":
           style_color = "white"
           
       style =  (
                  "font: bold " + {"b":"1","n":"0"}[style_ftype] + ", height " + str(int(style_size)*16) + "; " +
                  "pattern: pattern solid, fore_color " + style_color + "; " +
                  "borders: left thin, top thin, right thin, bottom thin; " +
                  "align: horiz " + {"c":"center","l":"left"}[style_pos] + ", vert center, wrap 1"
                )
                
       xlwt.easyxf(style)
       if not 'wbstyles' in vars(self):
           self.wbstyles = {}
       if not style in self.wbstyles:
           self.wbstyles[style] = xlwt.easyxf(style)
       return(self.wbstyles[style])


#*************************************************************************

    def merge_23way (self,entries1):      #   2 or 3 way merge
    
        entries2 = {}
        
        origin = None
        if len(self.merge_files) == 3:   #  if we have 3 input files, then it is a 3 way merge with an common ancestor
            origins = []
            for entry in entries1:
#                print entry
                if entry['_FILE'] == self.merge_files[0]:
                    origins.append(entry)
            for origin in origins:
                entries1.remove(origin)
            if len(origins) > 1:
                return(entries1)
            if len(origins) == 1:
                origin = origins[0]

#        print self.merge_files
#        print origin
#        print len(entries1)

        allkeys      = {}
        for entry in entries1:
            for key in entry:
                allkeys[key] = 1
                
        merged_entry = {}
        for key in allkeys:
            for entry in entries1:
#                print entry['_FILE']
                if key in entry:
                    if not key in merged_entry or key[0] == "_" or key in ("MD5KEY","OBJID"):
                        merged_entry[key] = entry[key]         #  no problem to decide. key is not occupied yet
                        continue
                    if merged_entry[key] == entry[key]:
                        continue
                    if origin and key in origin:               #  another chance to decide by common ancestor
#                        print origin[key]
#                        print merged_entry[key]
#                        print entry[key]
                        if origin[key] == merged_entry[key]:  #  we take the change
                            merged_entry[key] = entry[key]
#                            print 123
                        elif origin[key] == entry[key]:  #  we take the change
                            pass
#                            print 124
                        else:
#                            print "NOT MERGED"
                            return(entries1)
                    else:
                        return(entries1)   #  merge not possible

        return([merged_entry])
                                
#*************************************************************************


    def mark_for_merge (self,entries):
    
        '''Rules out whether there are candidates for doublettes
        '''


        if len(entries) == 1:
            return(entries)

        diff_entry = {}

        for entry in entries:
            for k in entry:
                if k == "MD5KEY":
                    continue
                if k == "DEL":
                    continue
                if k in diff_entry:
                    if not diff_entry[k] == entry[k]:
                        diff_entry[k] = entry[k]
                        entry[k]      = "-->" + str(entry[k])
                    else:
                        diff_entry[k] = entry[k]
                else:
                    diff_entry[k] = entry[k]
        
#        entries.insert(-1,diff_entry)
#        print entries
        
        return(entries)
        
#*************************************************************************

    def xxtrack_tasks (self,pars):


        taskdir  = re.sub(r"\s","",os.popen('git config tasks.taskdir').read(),        99999999,flags=re.DOTALL)
        smtphost = re.sub(r"\s","",os.popen('git config tasks.smtphost').read(),       99999999,flags=re.DOTALL)
        sender   = re.sub(r"\s","",os.popen('git config tasks.sender').read(),         99999999,flags=re.DOTALL)
        cclist   = re.sub(r"\s","",os.popen('git config tasks.cclist').read(),         99999999,flags=re.DOTALL)
        gitroot  = re.sub(r"\s","",os.popen('git rev-parse --show-toplevel').read(),   99999999,flags=re.DOTALL)
        cwd      = os.getcwd()
        taskdir  = re.sub(r"^"+gitroot,"",cwd)
        
        try:
            name_of_tracker = pars[0]
        except:
            name_of_tracker = "ProcPy"

        self.output_text = ""


#  1.  Execute a query for all tasks where its _DIR differs from ASSIGN field (all moved tasks)

        
        changed_tasks = self.export_data(os.popen("ls */*.csv").readlines() +
                       ['not __DIR=ASSIGN','-_DIR-,-ASSIGN-,-_DIR-/-_FILE-,-OBJID-,x'],False)
        open("x--_DIR-___-_FILE-","w").write("-_DIR-,-xREST_ASSIGN\n")

        for zeile in changed_tasks.split("\n"):

            m = re.search(r"^(.*),(.*),(.*),(.*)$",zeile)
            if not m:
                continue
            newowner = m.group(1)
            oldowner = m.group(2)
            taskfile = m.group(3)
            taskid   = m.group(4)
            

#  2.  Add assigning informations to task text

            try:
                text = open(taskfile).read()
            except:
                continue
            text = re.sub(r"(HISTORY\:)(.*?)\"","\\1\\2\n" +
                          "assigned from " + oldowner + " to " + newowner +
                          " at " + time.asctime() + "\n\"",text,flags=re.DOTALL)
            open(taskfile,"w").write(text)
            

#  3.  Rename task file name if it has not yet OBJID information
            
            newfilename = re.sub(r"(.*)(^|[\\\/])(.*)$","\\1\\2"+taskid+"_\\3",zeile1[2])
            newfilename = re.sub(r"(^|[\\\/])"+taskid+"_"+taskid,"\\1"+zeile1[3],newfilename)
            if not newfilename == zeile1[2]:   #   wenn Umbenennung des Tasks noetig ist
                os.popen("mv " + zeile1[2] + " " + newfilename)
                print(("mv " + zeile1[2] + " " + newfilename))


#  4.  Check whether a notification should be sent

            try:
                toaddr = re.sub(r"\s","",open(newowner+"/.notification.txt").read(),   99999999,flags=re.DOTALL)
            except:
                print("No mail notification sent to " + newowner)
                continue
                

#  5.  Create the mailsender object if not yet done

            if not 'mailsender' in vars():
                import smtplib
                import email.mime.text
                mailsender = smtplib.SMTP()
                mailsender.connect(smtphost)


#  6.  Create the mail message
            
            mailmsg = email.mime.text.MIMEText("""
Hello """ + newowner + """,

The task """ + taskdir + "/" + newowner + "/" + newfilename + """
has been assigned to you by """ + oldowner + """

Please work on it via editing the HISTORY Section, and re-assign it to another person's folder in

          """ + taskdir + """
                    
The content of the task is:

---------------------------------------------------------------------
""" + text + """

---------------------------------------------------------------------
The """ + name_of_tracker + """ Tracker, """ + time.asctime() + """

Do not answer to this mail.
""")
            mailmsg['Subject'] = "Task Assignment " + newfilename
            mailmsg['Cc']      = cclist
            if not name_of_tracker.lower() == "dryrun":
                mailsender.sendmail(sender,[toaddr],mailmsg.as_string())
            print("Mail sent to " + toaddr + " for task " + newfilename)
                                          

#   7.. Finishing of the changed tasks: new column headers

        for zeile in self.export_data(os.popen("ls */*.csv").readlines()+['not __DIR=ASSIGN','x--_DIR-___-_FILE-'],False):
            taskfile = zeile.strip()
            try:
                text = open(taskfile).read()
            except:
                continue
            text = re.sub(r"_DIR,REST_ASSIGN","ASSIGN,REST",text)  #  <--- new column headers
            open(taskfile,"w").write(text)
            print(taskfile + " rewritten ...")

        os.unlink("x--_DIR-___-_FILE-")

#*************************************************************************

    def xxpostcommand (self,text):

        m = re.search(r"^(reassigntask|columnheaderstask),(.*)$",text)
        if m:
            exec("self."+m.group(1)+"("+m.group(2)+")")

#*************************************************************************
        
    def xxreassigntask (self,text):


        if not 'taskdir' in self:

            self.taskdir  = re.sub(r"\s","",os.popen('git config tasks.taskdir').read(),        99999999,flags=re.DOTALL)
            self.smtphost = re.sub(r"\s","",os.popen('git config tasks.smtphost').read(),       99999999,flags=re.DOTALL)  
            self.sender   = re.sub(r"\s","",os.popen('git config tasks.sender').read(),         99999999,flags=re.DOTALL)
            self.cclist   = re.sub(r"\s","",os.popen('git config tasks.cclist').read(),         99999999,flags=re.DOTALL)
            self.gitroot  = re.sub(r"\s","",os.popen('git rev-parse --show-toplevel').read(),   99999999,flags=re.DOTALL)
            self.cwd      = os.getcwd()
            self.taskdir  = re.sub(r"^"+gitroot,"",cwd)
        
        m = re.search(r"^(.*),(.*),(.*),(.*),(.*)$",text)
        newowner        = m.group(1)
        oldowner        = m.group(2)
        taskfile        = m.group(3)
        taskid          = m.group(4)
        name_of_tracker = m.group(5)
            

#  2.  Add assigning informations to task text

        try:
            text = open(taskfile).read()
        except:
            return()
        text = re.sub(r"(HISTORY\:)(.*?)\"","\\1\\2\n" +
                      "assigned from " + oldowner + " to " + newowner +
                      " at " + time.asctime() + "\n\"",text,flags=re.DOTALL)
        open(taskfile,"w").write(text)
            

#  3.  Rename task file name if it has not yet OBJID information
            
        newfilename = re.sub(r"(.*)(^|[\\\/])(.*)$","\\1\\2"+taskid+"_\\3",zeile1[2])
        newfilename = re.sub(r"(^|[\\\/])"+taskid+"_"+taskid,"\\1"+zeile1[3],newfilename)
        if not newfilename == zeile1[2]:   #   wenn Umbenennung des Tasks noetig ist
            os.popen("mv " + zeile1[2] + " " + newfilename)
            print(("mv " + zeile1[2] + " " + newfilename))


#  4.  Check whether a notification should be sent

        try:
            toaddr = re.sub(r"\s","",open(newowner+"/.notification.txt").read(),   99999999,flags=re.DOTALL)
        except:
            print("No mail notification sent to " + newowner)
            return()
                

#  5.  Create the mailsender object if not yet done

        if not 'mailsender' in self:
            import smtplib
            import email.mime.text
            self.mailsender = smtplib.SMTP()
            self.mailsender.connect(smtphost)


#  6.  Create the mail message
            
        mailmsg = email.mime.text.MIMEText("""
Hello """ + newowner + """,

The task """ + taskdir + "/" + newowner + "/" + newfilename + """
has been assigned to you by """ + oldowner + """

Please work on it via editing the HISTORY Section, and re-assign it to another person's folder in

          """ + taskdir + """
                    
The content of the task is:

---------------------------------------------------------------------
""" + text + """

---------------------------------------------------------------------
The """ + name_of_tracker + """ Tracker, """ + time.asctime() + """

Do not answer to this mail.
""")
        mailmsg['Subject'] = "Task Assignment " + newfilename
        mailmsg['Cc']      = cclist
        if not name_of_tracker.lower() == "dryrun":
            self.mailsender.sendmail(sender,[toaddr],mailmsg.as_string())
        print("Mail sent to " + toaddr + " for task " + newfilename)
                                          
#*************************************************************************

#   7.  Finishing of the changed tasks: new column headers

        for zeile in self.export_data(os.popen("ls */*.csv").readlines()+['not __DIR=ASSIGN','x--_DIR-___-_FILE-'],False):
            taskfile = zeile.strip()
            try:
                text = open(taskfile).read()
            except:
                continue
            text = re.sub(r"_DIR,REST_ASSIGN","ASSIGN,REST",text)  #  <--- new column headers
            open(taskfile,"w").write(text)
            print(taskfile + " rewritten ...")

        os.unlink("x--_DIR-___-_FILE-")

#*************************************************************************


class UnitTest (object):

    def test01 (self,pars):
    
        dateiname  = pars[0]
        try:
            tpl = eval(pars[1])
        except:
            tpl = {"NAME":"ABC"}
        print(dateiname)
        t          = Template()
        dateiname1 = t.ff_file(dateiname,tpl)
        
        print(dateiname1)

    def test02 (self,pars):
    
        dateiname  = pars[0]
        print(dateiname)
        t          = Template()
        dateiname1 = t.export(dateiname,{"NAME":"ABC"})
        
        print(dateiname1)

    def test03 (self,pars):
    
        dateiname  = pars[0]
        print(dateiname)
        t          = Template()
        result     = t.csvimport(dateiname)
        
        print(result)

    def test04 (self,pars):
    
        dateiname  = pars[0]
        tpl        = pars[1]
        t          = Template()
        result     = t.csvimportl(dateiname)

        no_output_header = False
        print("")
        for r in result:
            if "'aktuell'" in str(r):
                output           = t.export(tpl,r,no_output_header)
                no_output_header = True
                print(output)
        print("")

#*************************************************************************


if __name__ == "__main__":
    UnitTest.__dict__[sys.argv[1]](UnitTest(),sys.argv[2:])


bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped)
Email: contact@elmoujehidin.net bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped) Email: contact@elmoujehidin.net