# -*- coding: ISO-8859-1 -*-
""" capellaScript
>>> Script Download

    Mit diesem Skript werden Capellaskript Dateien von diversen Homepages heruntergeladen
    und im Capella Skript-Verzeichnis im Ordner Scriptdownload abgelegt.
    Alle Dateien werden mit dem Zeitstempel vom Server versehen.
<<<


  File:     Scriptdownload.py
  Author:   Paul Villiger
  e-mail:   villpaul(a)bluewin.ch
  Created:  20.10.2004
  Modified: 04.12.2010

  Purpose:  Mit diesem Skript werden Capellaskript Dateien von diversen Homepages heruntergeladen
            und im Capella Skript-Verzeichnis in einzelne oder mehrere Ordner abgelegt.
            Alle Dateien werden mit dem Zeitstempel vom Server versehen.

  Remark:   - Anwendung auf eigene Gefahr
            - Bestehende Skripts im Zielverzeichnis werden überschrieben
            - Skript kann auch ohne Capella aufgerufen werden, dann werden alle Plugins geladen

  Config:   - Die URL-Liste kann beliebig erweitert werden.
            - Zu jeder URL muss ein Zielverzeichnis definiert werden.

  History   20.10.04 Erstausgabe
            21.10.04 Dialog
            22.10.04 Proxywerte unter Optionen speichern
            12.11.04 - nur geänderte oder neue Dateien übertragen
                     - Externer Aufruf: Option -p <proxy>
            16.11.04 - Fehler mit win32traceutil
            24.04.05 - Download der Plugins von der capella-software Homepage
            30.06.05 - Neue HP von Stefan Thierfeldt
            21.02.06 - Download von ZIP-Dateien, Link zu Klaus Meglitsch
            01.03.06 - Download von CHM-Dateien
            18.03.06 - Icons werden aus Symbole.zip extrahiert
            19.03.06 - Alle Verzeichnisse werden wieder abgefragt
            01.01.07 - Neue Domain http://freenet-homepage.de/peter.becker/
            25.06.07 - Plugins von Hans H. Lampe
            04.07.07 - neue Domain sins942.ch
            13.10.07 - Behandlung für capella 2008
            13.10.07 - Proxy Behandlung entfernt
            27.10.07 - Korrektur
            11.11.07 - Neue Downloadstruktur
            26.11.07 - Download von plugins*.dat
            10.11.08 - Fehler bei Einzelauswahl
            29.03.09 - capella new website
            02.03.10 - Peter Becker neue Website
            08.04.10 - Plugin Symbols bei notensatz-fischer
            11.09.10 - Für capella7 nur Verzeichnis ScriptDownload
                     - Homepage von Stefan Thierfeld unf HH Lampe entfernt, neu bei capella-software
                     - Für capella7 Behandlung von plugins.dat und plugins-1.bmp
                     - Download Skripthandbuch entfernt
                     - Für capella 7 keine Icon-Behandlung
            12.09.10 - Symbole.zip nur bei capella 2008
            13.09.10 - Externer Aufruf unterdrückt
                     - Korrekturen bei plugins.dat
                     - deutsche Fehlertexte
            14.09.10 - plugins.dat Behandlung optimiert
            22.09.10 - Erste Gruppe ohne Namen --> neuer Name: "Plugin Symbolleiste"
            26.09.10 - Logfile wird erstellt, Endemeldung wird angezeigt
            04.12.10 - Neue Homepage Peter Becker
                     

"""

import urllib2, sys, zipfile
import htmllib, formatter, string, time
import urllib, urlparse, os.path, os, shutil, _winreg

def latin1(u):
    return u.decode('Latin-1')
def latin1e(u):
    return u.encode('Latin-1')

ok = True # wird bei einem Fehler auf "False" gesetzt

excludeFilter = ['Handbuch.zip', 'Update.zip']
downloadManual = False
copyPluginsDat = False
singleDownloadDir = True
scriptFileList = []
downloadDir = 'ScriptDownload'
symbolFile = 'Symbole.zip'  # Diese Datei enthält die Symbole
symbolDir = 'symbols'       # In dieses Verzeichnis werden die Symbole extrahiert


# Testen ob intern (Capella) oder extern (ohne Capella
try:
    # interner Aufruf
    if activeScore():
        internal = True
    options = ScriptOptions()
    opt = options.get()
    options.set(opt)

except:
    # externer Aufruf
    internal = False
    print 'Scriptdownload: Externer Aufruf wird (momentan) nicht unterstützt'
    ok = False

# Liste der zu untersuchenden URL's. Die Liste kann beliebig erweitert werden.
# Beide Listen müssen identische URLs haben
#            URL                                                            Verzeichnis             Autor
urlList_1 = [('http://www.peter-becker-cap.de/scripts_meine.htm',           downloadDir,            'Peter Becker'),
             ('http://www.peter-becker-cap.de/scripts_salis.htm',           downloadDir,            'Radolf von Salis'),
             ('http://www.peter-becker-cap.de/scripts_lampe.htm',           downloadDir,            'H.H. Lampe'),
             ('http://www.peter-becker-cap.de/scripts_capella.htm',         downloadDir,            'capella'),
             ('http://www.sins942.ch/scripts_pv.html',                        downloadDir,            'Paul Villiger'),
             ('http://www.sins942.ch/scripts_ah.html',                        downloadDir,            'Andreas Herzog'),
             ('http://www.sins942.ch/scripts_lh.html',                        downloadDir,            'Lutz Haas'),
             ('http://www.sins942.ch/scripts_hl.html',                        downloadDir,            'Hartmut Lemmel'),
             ('http://www.capella.de/Plugins.cfm',                            downloadDir,            'Capella Software'),
             ('http://www.notensatz-s-fischer.de/capella_Dokumente/html/capella_zubehoer.htm',        downloadDir,          'Plugin Svmbols')
             ]

# Liste der zu untersuchenden URL's. Die Liste kann beliebig erweitert werden.
#            URL                                                             Verzeichnis                Autor
urlList_2 = [('http://www.peter-becker-cap.de/scripts_meine.htm',           'Plugins_Becker',            'Peter Becker'),
             ('http://www.peter-becker-cap.de/scripts_salis.htm',           'Plugins_Becker',            'Radolf von Salis'),
             ('http://www.peter-becker-cap.de/scripts_lampe.htm',           'Plugins_Becker',            'H.H. Lampe'),
             ('http://www.peter-becker-cap.de/scripts_capella.htm',         'Plugins_Becker',            'capella'),
           ('http://www.sins942.ch/scripts_pv.html',                        'Plugins_Villiger',         'Paul Villiger'),
           ('http://www.sins942.ch/scripts_ah.html',                        'Plugins_Villiger',         'Andreas Herzog'),
           ('http://www.sins942.ch/scripts_lh.html',                        'Plugins_Villiger',         'Lutz Haas'),
           ('http://www.sins942.ch/scripts_hl.html',                        'Plugins_Villiger',         'Hartmut Lemmel'),
           ('http://www.capella.de/Plugins.cfm',                            'Plugins_Capella_Software', 'Capella Software'),
           ('http://www.notensatz-s-fischer.de/capella_Dokumente/html/capella_zubehoer.htm',             'Plugins_Symbols',          'Plugin Svmbols')
             ]


def handlePluginsDat(new, orig):

    import xml.dom.minidom

    origChanged = False

    if not os.path.isfile(new):
        return
    if not os.path.isfile(orig):
        return

    fileOrig = open(orig, 'r')
    textOrig = fileOrig.read()
    fileOrig.close()

    fileNew = open(new, 'r')
    textNew = fileNew.read()
    fileNew.close()


    if '<?xml' not in textOrig:
        textOrig = '<?xml version="1.0" encoding="ISO-8859-1"?>\n\r' + textOrig

    if '<?xml' not in textNew:
        textNew = '<?xml version="1.0" encoding="ISO-8859-1"?>\n\r' + textNew
        
    try:
        domOrig = xml.dom.minidom.parseString(textOrig)
        domNew  = xml.dom.minidom.parseString(textNew)
    except:
        return

    groupOrig = None
    for group in domOrig.getElementsByTagName('group'):
        itemCount = len(group.getElementsByTagName('item'))
        if 12 <= itemCount < 30:
            groupOrig = group
            break
        if itemCount < 12:
            break
    
    if groupOrig:
        if not groupOrig.hasAttribute("name"):
            groupOrig.setAttribute("name", "Plugin Symbolleiste")

        # replace items without symbol attributes
        for itemOrig in groupOrig.getElementsByTagName('item'):
            path, itemFile = os.path.split(itemOrig.getAttribute('file'))

            for itemNew in domNew.getElementsByTagName('item'):
                path, fil = os.path.split(itemNew.getAttribute('file'))
                if itemFile == fil:
                    itemOrig.parentNode.replaceChild(itemNew.cloneNode(True), itemOrig)
                    break

        # replace original script group with entries from original file
        for group in domNew.getElementsByTagName('group'):
            itemCount = len(group.getElementsByTagName('item'))
            if 12 <= itemCount < 30:
                group.parentNode.replaceChild(groupOrig, group)
                origChanged = True
                break
            if itemCount < 12:
                break

    if origChanged:
        fileOut = open(new, 'w')
        # fileOut.write( domOrig.toprettyxml(' ','','ISO-8859-1') )
        fileOut.write( domNew.toprettyxml(' ','','ISO-8859-1') )
        fileOut.flush()
        fileOut.close()
    
def errorMsg(text):
    if internal:
        messageBox('',text,img=4)
    else:
        print text

def writeLogFile(log, init=False):
    if init:
        logFile = open(logFileName, 'w')
    else:
        logFile = open(logFileName, 'a')
    logFile.write(log)
    logFile.flush()
    logFile.close()

# Capella Verzeichnis aus der Registry auslesen
try:
    r = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders')
    homePath, x = _winreg.QueryValueEx(r, 'Personal')
    _winreg.CloseKey(r)
    scriptPath = os.path.join(homePath,'capella', 'scripts')
    configPath = os.path.join(homePath,'capella', 'config','data')

    version6 = False
    version7 = False
    if internal:
        if (6, 0, 0) <= capVersion():
            version6 = True
        if (7, 0, 0) <= capVersion():
            version7 = True
        
    elif os.path.exists(scriptPath):
        version6 = True
        if not internal:
            print 'Download for capella 6.'
        
        
    if not version6:
        r = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\capella-software\capella\5.0')
        capPath = os.path.split(_winreg.QueryValueEx(r, 'ExePath')[0])[0]
        _winreg.CloseKey(r)

        scriptPath = os.path.join(capPath, 'scripts')
        configPath = os.path.join(capPath, 'config','data')
        if not internal:
            print 'Download for capella 5.'
except:
    errorMsg('FEHLER beim Lesen der capella Registry')
    ok = False

logFileName = os.path.join(scriptPath, 'Scriptdownload.log')    

# Wenn Download Verzeichnis besteht, dann Voreinstellung auf Einzelverzeichnis aendern 
if os.path.isdir(os.path.join(scriptPath, downloadDir)):
    singleDownloadDir = True
else:
    singleDownloadDir = True
    

# Benutzerdialog starten
if ok and internal:
    selList = ['Alle Plugins']
    for (url, pluginDir, author) in urlList_1:
        selList.append('Plugins von '+author)
    cpPluginsDat = CheckBox('', value = copyPluginsDat)
    dirSelect = CheckBox('', value = singleDownloadDir)

    selPlugin = Radio(selList,value=0)

    if version7:
        dlg = Dialog('Plugin Download',
                     VBox([selPlugin,
                           Label(' '),
                           HBox([cpPluginsDat, Label('plugins.dat kopieren')]),
     #                     HBox([dirSelect, Label('Verzeichnis '+downloadDir +' verwenden?')]),
                           Label(' '),
                           Label('Die Plugins werden im Skript-Verzeichnis', width = 40),
                           Label(downloadDir + ' abgelegt'),
                           ], text='Auswahl')
                     )

    else:   # not Version 7
        dlg = Dialog('Plugin Download',
                     VBox([selPlugin,
                           Label(' '),
     #                     HBox([cpPluginsDat, Label('plugins.dat kopieren')]),
                           HBox([dirSelect, Label('Verzeichnis '+downloadDir +' verwenden?')]),
                           Label(' '),
                           Label('Die Plugins werden im Skript-Verzeichnis', width = 40),
                           Label('unter "Plugins_<Autor>" gespeichert'),
                           Label('oder im Verzeichnis  '+ downloadDir),
                           ], text='Auswahl')
                     )

    if dlg.run():
        sel = selPlugin.value()
        if sel > 0:
            urlList_1 = [urlList_1[sel-1]]
            urlList_2 = [urlList_2[sel-1]]
        options.set(opt)
        copyPluginsDat = cpPluginsDat.value()

        if version7:
            copyPluginsDat = cpPluginsDat.value()
            singleDownloadDir = True
        else:
            singleDownloadDir = dirSelect.value()
            copyPluginsDat = False

    else:
        ok = False

if singleDownloadDir:
    urlList = urlList_1
else:
    urlList = urlList_2
    

if ok:
    writeLogFile('-- Scriptdowload Logfile --\r\n\r\n', True)
    
    fileCount = 0
    for (url, pluginDir, author) in urlList:
        if os.path.isdir(scriptPath):
            pDir = os.path.join(scriptPath,pluginDir)
            if not os.path.isdir(pDir):
                os.mkdir(pDir)   # Plugin Directory erzeugen wenn noch nicht vorhanden

            # URL lesen
            try:
                f = urllib2.urlopen(url)
                lines = f.read()
                f.close()
            except:
                errorMsg('FEHLER: Url "%s" nicht gefunden' % (url))
                continue     # Goto next URL

            # URL Inhalt nach Links durchsuchen -> anchorlist
            try:
                parser = htmllib.HTMLParser(formatter.NullFormatter(), verbose=1)
                parser.feed(lines)
                parser.close()
            except:
                errorMsg('FEHLER beim Uebersetzen von "%s"' % (url))
                continue     # Goto next URL

            for l in parser.anchorlist:

                (addressing_scheme, network_location, path, parameters, query, fragment_identifier) = urlparse.urlparse(l)
                root, tail = os.path.split(path)
                head, ext =os.path.splitext(tail)
                if ext == '.py' and head[-3:] <> '_tr':
                    scriptFileList.append(head)

            for l in parser.anchorlist:
                
                downloadUnconditional = False

                (addressing_scheme, network_location, path, parameters, query, fragment_identifier) = urlparse.urlparse(l)
                root, tail = os.path.split(path)
                head, ext = os.path.splitext(tail)
                
                if ext in ['.py']:
                    pass                            # alle Python Files zulassen
                elif ext in ['.zip']:
                    if version7:
                        continue
                    else:
                        if 'Symbole' in head:
                            pass
                        else:
                            continue
                elif ext in ['.chm', '.info','.html']:
                    found = False
                    for s in scriptFileList:        # prüfen, ob Datei zu einem Pythonscript gehört
                        if s in head:
                            found = True
                    if not found:
                        continue    # Datei überspringen
                elif ext in ['.dat', '.bmp']:
                    if 'plugins' not in head:     # nur bestimmte dat Dateien zulassen
                        continue    # Datei überspringen
                    else:
                        if copyPluginsDat:
                            downloadUnconditional = True
                else:
                    continue    # Datei überspringen

                if addressing_scheme <> '' :
                    # Absoluter Link
                    u = l
                else:
                    # Relativer Link
                    u = urlparse.urljoin(url, path)

                # Dateinamen aus Link bestimmen
                tail = latin1(tail)
                pluginFile = os.path.join(pDir,tail)
                if os.path.isfile(pluginFile):
                    modTime = os.stat(pluginFile)[8]
                else:
                    modTime = 0.0

                # Link in Datei speichern
                # if True:
                try:
                    f = urllib2.urlopen(u)
                    # Speicherdatum des Links bestimmen und Dateidatum setzen                
                    t = time.time()    # default actual time
                    try:
                        infoLines = str(f.info()).splitlines()
                        for l in infoLines:
                            if 'Last-Modified: ' == l[0:15]:
                                t = time.mktime(time.strptime(l[15:],'%a, %d %b %Y %H:%M:%S GMT'))
                                break
                    except:
                        errorMsg('FEHLER beim setzen der Zeit von "%s"' % (pluginFile))

                    if modTime < t:
                        log = 'Datei uebertragen: %s\r\n' % pluginFile
                    elif downloadUnconditional:
                        log = 'Datei uebertragen unbedingt %s\r\n' % pluginFile
                    else:
                        log = 'Datei ist aktuell: %s\r\n' % pluginFile
                    writeLogFile(log)
                    
                    
                    # Datei nur übertragen wenn neuere Datei auf Server vorhanden
                    #  oder sich die Zeit auf dem Server nicht bestimmen lässt
                    if modTime < t or downloadUnconditional:
                        pf = file(pluginFile,'wb')
                        data = f.read(-1)
                        pf.write(data)
                        pf.flush()
                        pf.close()
                        os.utime(pluginFile,(t,t))

                        fileCount += 1
                        
                        if not internal:
                            print 'File transfered: ' + pluginFile

                        if not version7:
                            try:
                                # ZIP-Dateien extrahieren
                                if symbolFile in pluginFile and zipfile.is_zipfile(pluginFile):
                                    print 'Icons werden aus %s extrahiert' % (symbolFile)

                                    symbolDirectory = os.path.join(scriptPath, symbolDir)
                                    if not os.path.isdir(symbolDirectory):
                                        os.mkdir(symbolDirectory)
                                    zip = zipfile.ZipFile(pluginFile,'r')
                                    for zf in zip.infolist():
                                        h, e = os.path.splitext(zf.filename)
                                        if e == '.gif':
                                            try:
                                                outFileName = os.path.join(symbolDirectory, latin1(zf.filename))
                                                outFile = file(outFileName, 'wb')
                                                outFile.write(zip.read(zf.filename))
                                                outFile.close()
                                                print 'Icon gespeichert: ' , latin1e(outFileName)
                                            except:
                                                print 'Icon nicht gespeichert: ' , latin1e(outFileName)

                                    zip.close()
                            except:
                                errorMsg('FEHLER beim Entkomprimieren von "%s", "%s" ' % (symbolFile, outFileName))
                                zip.close()

                        if internal and copyPluginsDat and tail == 'plugins.dat':
                            pluginsDatFile = os.path.join(configPath, tail)
                            if not os.path.isdir(configPath):
                                os.mkdir(configPath)
                            """
                            # bestehende plugins.dat sichern
                            if modTime > 0.0:
                                pHead,pExt = os.path.splitext(pluginsDatFile)
                                tString = str(datetime.date.fromtimestamp(modTime))
                                saveFile = os.path.join(pHead + '_' + tString, ext)
                                os.rename(pluginsDatFile, saveFile)
                            """
                            
                            handlePluginsDat(pluginFile, pluginsDatFile)
                            
                            shutil.copyfile(pluginFile, pluginsDatFile)
                        

                        if internal and copyPluginsDat and string.lower(tail) == 'plugins-1.bmp':
                            pluginsDatFile = os.path.join(configPath, 'toolbars', tail)
                            if not os.path.isdir(os.path.join(configPath, 'toolbars')):
                                os.mkdir(os.path.join(configPath, 'toolbars'))
                            """
                            # bestehende Plugins-1.bmp sichern
                            if modTime > 0.0:
                                pHead,pExt = os.path.splitext(pluginsDatFile)
                                tString = str(datetime.date.fromtimestamp(modTime))
                                saveFile = os.path.join(pHead + '_' + tString, ext)
                                os.rename(pluginsDatFile, saveFile)
                            """

                            shutil.copyfile(pluginFile, pluginsDatFile)

                except:
                # else:
                    errorMsg('FEHLER beim Herunterladen von "%s"' % (u))
                    continue     # Goto next file

    # Zentrales Scriptverzeichnis updaten
    scriptList = os.listdir(scriptPath)
    for (url, pluginDir, author) in urlList:                # Symbole in alle Autorenverzeichnisse verteilen
        for sc in scriptList:
            sf = os.path.join(scriptPath,sc)
            df = os.path.join(scriptPath,pluginDir,sc)
            if os.path.isfile(sf) and os.path.isfile(df):   # wenn Datei in beiden Verzeichnissen vorkommt
                if os.stat(df)[8] > os.stat(sf)[8]:         # und Downloadfile neuer ist,
                    try:
                        shutil.copyfile(df,sf)                         #   dann kopieren
                        t = os.stat(df)[8]
                        os.utime(sf, (t,t))                     # Dateidatum setzen
                    except:
                        pass
        if singleDownloadDir:
            break
                
    if not version7:
        # Symbol.zip Datei ins symbol-Verzeichnis kopieren
        for (url, pluginDir, author) in urlList:                # Symbole in alle Autorenverzeichnisse verteilen
            pluginPath = os.path.join(scriptPath, pluginDir)
            if symbolFile in os.listdir(pluginPath):
                shutil.copyfile(os.path.join(pluginPath, symbolFile), os.path.join(scriptPath, symbolDir, symbolFile))
                break
    
    if not version7:
        # Symbole verteilen, nur PNG und nur ab Version 6
        symbolZip = os.path.join(scriptPath, symbolDir, symbolFile)
        if version6 and os.path.isfile(symbolZip) and zipfile.is_zipfile(symbolZip):
            zip = zipfile.ZipFile(symbolZip,'r')
            symbolFiles = zip.namelist()
            zip.close()

            symbolPath = os.path.join(scriptPath,symbolDir)

            def copySymbols(destDir):                           # destDir ist Unterverzeichnis von scriptPath
                destPath = os.path.join(scriptPath, destDir)
                scriptList = os.listdir(destPath)
                for sc in scriptList:
                    sHead, sExt = os.path.splitext(sc)
                    if sExt == '.py':
                        sy = sHead + '.png'
                        df = os.path.join(destPath, sy)
                        if sy in symbolFiles:
                            zip = zipfile.ZipFile(symbolZip,'r')
                            try:                # wenn capella geöffnet ist kann Datei nicht geschrieben werden
                                outFile = file(df, 'wb')
                                outFile.write(zip.read(sy))
                                outFile.close()
                            except:
                                pass
                            zip.close()
                    
            pluginDirList = []
            for (url, pluginDir, author) in urlList:                # Symbole in alle Autorenverzeichnisse verteilen
                if pluginDir not in pluginDirList:                  
                    copySymbols(pluginDir)
                    pluginDirList.append(pluginDir)                 
            
            copySymbols('')                                         # Symbole ins zentralen Scriptverzeichnis kopieren

    if internal:
        text = 'Es wurden %s Dateien übertragen.\r\n\r\nDas Logfile %s wurde erstellt.' % (str(fileCount), latin1e(logFileName))
        messageBox('-- Info --', text)
    else:
        print 'INFO: Es wurden %s Dateien übertragen.\r\n\r\nDas Logfile %s wurde erstellt.' % (str(fileCount), latin1e(logFileName))

    writeLogFile('\r\n\r\nEs wurden %s Dateien übertragen' % str(fileCount))
