Utils.py
上传用户:lswyart
上传日期:2008-06-12
资源大小:3441k
文件大小:31k
源码类别:

杀毒

开发平台:

Visual C++

  1. #-----------------------------------------------------------------------------
  2. # Name:        Utils.py
  3. # Product:     ClamWin Free Antivirus
  4. #
  5. # Author:      alch [alch at users dot sourceforge dot net]
  6. #
  7. # Created:     2004/22/04
  8. # Copyright:   Copyright alch (c) 2004
  9. # Licence:     
  10. #   This program is free software; you can redistribute it and/or modify
  11. #   it under the terms of the GNU General Public License as published by
  12. #   the Free Software Foundation; either version 2 of the License, or
  13. #   (at your option) any later version.
  14. #   This program is distributed in the hope that it will be useful,
  15. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. #   GNU General Public License for more details.
  18. #   You should have received a copy of the GNU General Public License
  19. #   along with this program; if not, write to the Free Software
  20. #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. #-----------------------------------------------------------------------------
  22. import os, sys, time, tempfile, shutil, locale
  23. import Config, ConfigParser
  24. import re, fnmatch, urllib2
  25. import win32api, win32con, win32gui, win32event, win32con, pywintypes
  26. from win32com.shell import shell, shellcon
  27. if win32api.GetVersionEx()[3] != win32con.VER_PLATFORM_WIN32_WINDOWS:
  28.     import win32security
  29.         
  30.     
  31. EM_AUTOURLDETECT=1115
  32. EM_HIDESELECTION=1087
  33. CONFIG_EVENT='ClamWinConfigUpdateEvent01'
  34. _FRESHCLAM_CONF_GENERAL = """
  35. DNSDatabaseInfo current.cvd.clamav.net
  36. DatabaseMirror %s
  37. MaxAttempts 3
  38. """
  39. _FRESHCLAM_CONF_PROXY = """
  40. HTTPProxyServer %s
  41. HTTPProxyPort %s
  42. """
  43. _FRESHCLAM_CONF_PROXY_USER = """
  44. HTTPProxyUsername %s
  45. HTTPProxyPassword %s
  46. """
  47. def _ShowOwnBalloon(title, text, icon, hwnd, timeout):    
  48.     import BalloonTip   
  49.     hwnd = win32gui.FindWindow("Shell_TrayWnd", "")
  50.     hwnd = win32gui.FindWindowEx(hwnd, 0, "TrayNotifyWnd", "")     
  51.     rect = win32gui.GetWindowRect(hwnd)
  52.     flags = BalloonTip.SHOW_CLOSE_BUTTON|BalloonTip.SHOW_INNER_SHADOW|
  53.             BalloonTip.SHOW_TOPMOST|BalloonTip.CLOSE_ON_KEYPRESS|
  54.             BalloonTip.CLOSE_ON_LBUTTON_DOWN|
  55.             BalloonTip.CLOSE_ON_MBUTTON_DOWN|
  56.             BalloonTip.CLOSE_ON_RBUTTON_DOWN
  57.     # find and close existing notification
  58.     hExistingWnd = None
  59.     wnd_classes = (BalloonTip.SHADOWED_CLASS, BalloonTip.SHADOWLESS_CLASS)
  60.     for wnd_class in wnd_classes:
  61.         try:
  62.             hExistingWnd = win32gui.FindWindow(wnd_class, None)
  63.             break
  64.         except Exception, e:        
  65.             pass
  66.     if hExistingWnd is not None:       
  67.         win32api.SendMessage(hExistingWnd, win32con.WM_CLOSE, 0, 0) 
  68.         
  69.     #display balloon tooltip                       
  70.     BalloonTip.ShowBalloonTip(title, text, (rect[0], rect[1]), icon,         
  71.                             flags, hwnd, '', timeout)
  72. # balloon_info tuple contains 2 tuples for error and success notifications
  73. # each tuple has (HeaderMessage, Expected Retcode, ICON_ID, Timeout)                         
  74. def ShowBalloon(ret_code, balloon_info, hwnd = None):        
  75.     if sys.platform.startswith("win"):   
  76.         # no hwnd supplied - find it
  77.         if hwnd is None:
  78.             try:
  79.                 hwnd = win32gui.FindWindow('ClamWinTrayWindow', 'ClamWin')                        
  80.             except:
  81.                 return                        
  82.         try:
  83.             if balloon_info[0] is None:
  84.                 tuple = balloon_info[1]
  85.             elif balloon_info[1] is None:
  86.                 tuple = balloon_info[0]              
  87.             elif ret_code == balloon_info[0][1]:
  88.                 tuple = balloon_info[0]                    
  89.             elif ret_code != balloon_info[1][1]:
  90.                 tuple = balloon_info[1]                    
  91.             else:
  92.                 return 
  93.             
  94.             title = 'ClamWin Free Antivirus' 
  95.             txt = tuple[0]
  96.             icon = tuple[2]
  97.             timeout = tuple[3]                       
  98.                 
  99.             # there is not balloon tips on windows 95/98/NT
  100.             # (windows ME with balloons implemented has version 4.9)
  101.             # need to display custom notification            
  102.             version = win32api.GetVersionEx()                        
  103.             if version[0] == 4 and version[1] < 90:                
  104.                 if icon == win32gui.NIIF_INFO:
  105.                     icon = win32con.IDI_INFORMATION
  106.                 elif icon == win32gui.NIIF_WARNING:
  107.                     icon = win32con.IDI_WARNING
  108.                 elif icon == win32gui.NIIF_ERROR:
  109.                     icon = win32con.IDI_ERROR
  110.                 elif icon == win32gui.NIIF_NONE:
  111.                     icon = 0    
  112.                 _ShowOwnBalloon(title, txt, icon, hwnd, timeout)                
  113.             else:                
  114.                 nid = (hwnd, 0, win32gui.NIF_INFO, 0, 0, "", txt, timeout, title, icon)
  115.                 win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY, nid)
  116.         except Exception, e:
  117.             print 'Could not display notification. Error: %s' % str(e)
  118.     
  119. def GetCurrentDir(bUnicode):    
  120.     if sys.platform.startswith("win") and hasattr(sys, "frozen"):
  121.         # get current dir where the file was executed form
  122.         if sys.frozen == "dll":            
  123.             this_filename = win32api.GetModuleFileName(sys.frozendllhandle)
  124.         else:
  125.             this_filename = sys.executable
  126.         currentDir = os.path.split(this_filename)[0]
  127.                
  128.         # attempt to read the config from the working folder
  129.         conf = Config.Settings(os.path.join(currentDir, 'ClamWin.conf'))        
  130.         
  131.         # not a standalone version
  132.         if not conf.Read() or conf.Get('UI', 'Standalone') != '1':                    
  133.             try:
  134.                 # try HKCU first and then HKLM keys 
  135.                 # (this is to enable non admin user to install and use clamwin)
  136.                 try:
  137.                     key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, 'Software\ClamWin')
  138.                 except win32api.error:
  139.                     key = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'Software\ClamWin')
  140.                 currentDir = SafeExpandEnvironmentStrings(win32api.RegQueryValueEx(key, 'Path')[0])            
  141.             except win32api.error:                      
  142.                 pass       
  143.     else:
  144.         try:
  145.             currentDir = os.path.split(os.path.abspath(__file__))[0]
  146.         except NameError: # No __file__ attribute (in boa debugger)
  147.             currentDir = os.path.split(os.path.abspath(sys.argv[0]))[0]            
  148.     if bUnicode and sys.platform.startswith("win"):                        
  149.         # change encoding to proper unicode 
  150.         currentDir = pywintypes.Unicode(currentDir)
  151.     return currentDir
  152.     
  153. def GetProfileDir(bUnicode):
  154.     try:
  155.         if sys.platform.startswith("win"):                        
  156.             # read template config file
  157.             conf = Config.Settings(os.path.join(GetCurrentDir(bUnicode), 'ClamWin.conf'))        
  158.             if conf.Read() and conf.Get('UI', 'Standalone') == '1':        
  159.                 profileDir = GetCurrentDir(bUnicode)
  160.             else:            
  161.                 profileDir = shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_APPDATA, True)
  162.                 profileDir = os.path.join(profileDir, '.clamwin')
  163.                 # change encoding to proper unicode 
  164.                 if bUnicode:
  165.                     profileDir = pywintypes.Unicode(profileDir)    
  166.         else:
  167.             profileDir = os.path.join(os.path.expanduser('~'), '.clamwin')       
  168.     except Exception, e:
  169.         print 'Could not get the profile folder. Error: %s' % str(e)
  170.         profileDir = GetCurrentDir(bUnicode)
  171.     return profileDir
  172. def CopyFile(src, dst, overwrite = False):
  173.     copied = False
  174.     if overwrite or 
  175.         (not os.path.isfile(dst) and os.path.isfile(src)):
  176.         try:
  177.             shutil.copyfile(src, dst)               
  178.             copied = True
  179.         except Exception, e:
  180.             print 'Could not copy %s to %s. Error: %s' % (src, dst, str(e))
  181.     return copied
  182.                 
  183. # since ver 0.34 config files are stored in user's home directory
  184. # but installer puts the template version to the program folder    
  185. # which an admin can preconfigure for all new users
  186. # then confing and scheduler info files are copied 
  187. # at runtime to user's home dir 
  188. # only if these files are not yet present in the home dir
  189. def CreateProfile():        
  190.     curDir = GetCurrentDir(True)    
  191.     profileDir = GetProfileDir(True)   
  192.     
  193.     # read template config file
  194.     conf = Config.Settings(os.path.join(curDir, 'ClamWin.conf'))        
  195.     if not conf.Read():
  196.         return   
  197.      
  198.     # check for standalone flag and exit (don't copy anything)            
  199.     if conf.Get('UI', 'Standalone') == '1':
  200.         return
  201.     
  202.     # create profile dir
  203.     try:
  204.         if not os.path.isdir(profileDir):
  205.             os.makedirs(profileDir)      
  206.     except Exception, e:
  207.         print 'Could not create profile directory %s. Error: %s' % (profileDir, str(e))                         
  208.     # copy configuration file                
  209.     copied = CopyFile(os.path.join(curDir, 'ClamWin.conf'),
  210.                      os.path.join(profileDir, 'ClamWin.conf'))                                    
  211.     if copied:                                   
  212.         # copy scheduled scans info
  213.         shelvePath = conf.Get('Schedule', 'Path')            
  214.         # no [Schedule]-Path in conf file, copy schedule info across
  215.         if not shelvePath:                                             
  216.             CopyFile(os.path.join(curDir, 'ScheduledScans'),
  217.                     os.path.join(profileDir, 'ScheduledScans'))                                                                 
  218.                                             
  219. def GetScheduleShelvePath(config):
  220.     # In some rare cases (clamwin plugin to BartPE <http://oss.netfarm.it/winpe/>)
  221.     # path to Shelve may be not in the current dir            
  222.     shelvePath = config.Get('Schedule', 'Path')
  223.     if not len(shelvePath):
  224.         shelvePath = GetProfileDir(True)
  225.     else:
  226.         if sys.platform.startswith("win"):    
  227.             shelvePath = pywintypes.Unicode(shelvePath)
  228.             shelvePath = SafeExpandEnvironmentStrings(shelvePath)                    
  229.     return shelvePath
  230.                         
  231. # we want to be user-friendly and determine should
  232. # we use 24 or 12 hour clock
  233. # on Win32 this is a bit of a hack because GetTimeFormat() is
  234. # not available and time.strftime('%X', t) tends to return
  235. # 24 hr format regardless the regional settings
  236. # therefore we use repr(pywintypes.Time()) that calls
  237. # GetTimeFormat() internally. This should work unless
  238. # pywintypes.Time().repr() changes
  239. def IsTime24():
  240.     # set C locale, otherwise python and wxpython complain
  241.     locale.setlocale(locale.LC_ALL, 'C')            
  242.     t = time.localtime()                
  243.     if sys.platform.startswith("win"):    
  244.         import pywintypes
  245.         timestr = repr(pywintypes.Time(t))
  246.     else:
  247.         timestr = time.strftime('%X', t)
  248.     return not time.strftime('%p', t) in timestr
  249.     
  250. # use secure mkstemp() in python 2.3 and less secure mktemp/open combination in 2.2
  251. def SafeTempFile():
  252.     fd = -1
  253.     name = ''                            
  254.     try:            
  255.         if sys.version_info[0] < 2 or sys.version_info[1] < 3:            
  256.             name = tempfile.mktemp()                
  257.             fd = os.open(name, os.O_WRONLY|os.O_CREAT)
  258.         else:
  259.             fd, name = tempfile.mkstemp(text=True)                            
  260.     except Exception, e:            
  261.         print 'cannot create temp file. Error: ' + str(e)    
  262.     return (fd, name)
  263.     
  264. def SaveFreshClamConf(config):
  265.         data = _FRESHCLAM_CONF_GENERAL % config.Get('Updates', 'DBMirror')
  266.         if len(config.Get('Proxy', 'Host')):
  267.             data += _FRESHCLAM_CONF_PROXY % 
  268.                     (config.Get('Proxy', 'Host'), config.Get('Proxy', 'Port'))
  269.         if len(config.Get('Proxy', 'User')):        
  270.             data += _FRESHCLAM_CONF_PROXY_USER % 
  271.                 (config.Get('Proxy', 'User'), config.Get('Proxy', 'Password'))
  272.                             
  273.         fd, name = SafeTempFile()                                    
  274.         try:                        
  275.             os.write(fd, data)                    
  276.         finally:            
  277.             if fd != -1:
  278.                 os.close(fd)                                                
  279.         return name
  280.                                     
  281. def GetExcludeSysLockedFiles():
  282.     configDir = os.path.join(win32api.GetSystemDirectory(), 'config')
  283.     regFiles = ('default', 'SAM', 'SECURITY', 
  284.              'software', 'software.alt', 'system', 
  285.              'system.alt')
  286.     ret = ''
  287.     for regFile in regFiles:
  288.         ret += ' --exclude="%s"' % os.path.join(configDir, regFile).replace('\', '/')   
  289.     return ret
  290.                                     
  291. def GetScanCmd(config, path, scanlog):
  292.     # 2006-03-18 alch moving to native win32 clamav binaries
  293.     # remove all /cygdrive/ referneces and slash conversions
  294.     
  295.     # append / to a DRIVE letter as our regexep relacer needs that
  296.     # i.e C: will become C:/
  297.     
  298.     path = re.sub('([A-Za-z]):("|$)', r'1:/2', path)
  299.     print "Scanning: %s" % path
  300.         
  301.     cmd = '--tempdir "%s"' % tempfile.gettempdir().replace('\', '/').rstrip('/')
  302.     if config.Get('ClamAV', 'Debug') == '1':
  303.         cmd += ' --debug'
  304.     #this disables oversized zip checking
  305.     cmd += ' --max-ratio=0'
  306.     if config.Get('ClamAV', 'ScanRecursive') == '1':
  307.         cmd += ' --recursive'
  308.     if config.Get('ClamAV', 'RemoveInfected') == '1':
  309.         cmd += ' --remove'
  310.     elif config.Get('ClamAV', 'MoveInfected') == '1':
  311.         quarantinedir = config.Get('ClamAV', 'QuarantineDir')
  312.         # create quarantine folder before scanning
  313.         if quarantinedir and not os.path.exists(quarantinedir):
  314.             try:
  315.                 os.makedirs(quarantinedir)
  316.             except:
  317.                 pass
  318.         cmd += ' --move="%s"' % quarantinedir
  319.     if config.Get('ClamAV', 'EnableMbox') != '1':
  320.         cmd += ' --no-mail'
  321.     if config.Get('ClamAV', 'ScanOle2') != '1':
  322.         cmd += ' --no-ole2'            
  323.     if config.Get('ClamAV', 'DetectBroken') == '1':
  324.         cmd += ' --detect-broken'
  325.     if config.Get('ClamAV', 'ClamScanParams') != '':
  326.         cmd += ' ' + config.Get('ClamAV', 'ClamScanParams')
  327.     if config.Get('ClamAV', 'InfectedOnly') == '1':
  328.         cmd += ' --infected'    
  329.     if config.Get('ClamAV', 'ScanArchives') == '1':
  330.         cmd += ' --max-files=%i --max-space=%i --max-recursion=%i' % 
  331.             (int(config.Get('ClamAV', 'MaxFiles')), 
  332.             int(config.Get('ClamAV', 'MaxSize'))*1024, 
  333.             int(config.Get('ClamAV', 'MaxRecursion')))
  334.     else:
  335.         cmd += ' --no-archive' 
  336.               
  337.     cmd += ' --show-progress --stdout --database="%s" --log="%s" %s' % 
  338.             (config.Get('ClamAV', 'Database'), 
  339.             scanlog, path)          
  340.                                 
  341.     if sys.platform.startswith('win'):
  342.         # replace windows path with cygwin-like one        
  343.         cmd = cmd.replace('\', '/')
  344.         
  345.     # add --exlude=win386.swp to fix the bug 939877
  346.     # see http://sourceforge.net/tracker/index.php?func=detail&aid=939877&group_id=105508&atid=641462
  347.     if sys.platform.startswith('win'):
  348.         # Win 98/ME
  349.         if win32api.GetVersionEx()[3] == win32con.VER_PLATFORM_WIN32_WINDOWS:
  350.             cmd += ' --exclude=win386.swp --exclude=pagefile.sys'
  351.     # add annoying registry files to exclude as they're locked by OS
  352.     cmd += GetExcludeSysLockedFiles()
  353.            
  354.     # add include and exclude patterns    
  355.     for patterns in (['--include', config.Get('ClamAV', 'IncludePatterns')],
  356.                     ['--exclude', config.Get('ClamAV', 'ExcludePatterns')]):
  357.         patterns[1] = patterns[1].replace('\', '/')            
  358.         for pat in patterns[1].split(Config.REGEX_SEPARATOR):
  359.             if len(pat):            
  360.                 # proper regular expressions are started with ':'
  361.                 if pat.startswith('<') and pat.endswith('>'):
  362.                     pat = pat[1:len(pat)-1].replace('//', '/')
  363.                 else:
  364.                     # not a regular expression
  365.                     # translate glob style to regex
  366.                     pat = fnmatch.translate(pat)
  367.                     
  368.                     # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which
  369.                     # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix,
  370.                     # and by extension they shouldn't match such "special characters" under
  371.                     # any OS.  So change all non-escaped dots in the RE to match any
  372.                     # character except the special characters.
  373.                     # XXX currently the "special characters" are just slash -- i.e. this is
  374.                     # Unix-only.
  375.                     pat = re.sub(r'(^|[^\]).', r'1[^/]', pat)
  376.                     
  377.                 cmd += ' %s="%s"' % (patterns[0], pat)
  378.    
  379.     cmd = '"%s" %s' % (config.Get('ClamAV', 'ClamScan'), cmd)
  380.     return cmd
  381.         
  382. def AppendLogFile(logfile, appendfile, maxsize):    
  383.     try:
  384.         # create logs folder before appending     
  385.         if logfile:
  386.             logsdir = os.path.split(logfile)[0]
  387.             if logsdir and not os.path.exists(logsdir):
  388.                 os.makedirs(logsdir)                
  389.                 
  390.         # we need to synchronise log file access here
  391.         # to avoid race conditions        
  392.         if sys.platform.startswith("win"):            
  393.             name = 'ClamWinLogFileUpdate-' + os.path.split(logfile)[1]
  394.             try:
  395.                 # try to acquire our logupdate mutex       
  396.                 hMutex = win32event.OpenMutex(win32con.SYNCHRONIZE, False, name)                    
  397.                 # wait until it is released
  398.                 win32event.WaitForSingleObject(hMutex, win32event.INFINITE)
  399.                 win32api.CloseHandle(hMutex)                    
  400.             except win32api.error:
  401.                 pass
  402.             # create and own the mutex now to prevent others from modifying the log file
  403.             # whilst we append to it
  404.             hMutex = None
  405.             try:
  406.                 hMutex = win32event.CreateMutex(None, True, name)            
  407.             except win32api.error, e:
  408.                 print('Could not create mutex %s. Error: %s' % (name, str(e)))  
  409.         
  410.         ftemp = file(appendfile, 'rt')
  411.                
  412.         # check if the file is larger then maxsize and read last maxsize bytes
  413.         # go to end of file
  414.         ftemp.seek(0, 2)        
  415.         tempsize = ftemp.tell()
  416.         if tempsize > maxsize:
  417.             ftemp.seek(-maxsize, 2)
  418.         else: 
  419.             # read from the beginning
  420.             ftemp.seek(0, 0) 
  421.         # open main file for appending        
  422.         f = file(logfile, 'a+t')
  423.         # get the file size
  424.         f.seek(0, 2)        
  425.         # empty the file if longer than log size limit 
  426.         # shall implement rotation here, when have time
  427.         if f.tell() > maxsize - tempsize:            
  428.             f.truncate(0)             
  429.         # copy data in using 64Kb buffer
  430.         bufsize = 65535
  431.         pos = 0
  432.         while pos < tempsize:                     
  433.             # read text from our temporary log file
  434.             text = ftemp.read(min(bufsize, tempsize - pos)).replace('rn', 'n')
  435.             f.write(text)
  436.             pos = pos + bufsize        
  437.     except IOError, e:
  438.         print('Could not write to the log file %s. Error: %s' % (logfile, str(e)))        
  439.     
  440.     # release our synchronisation mutex
  441.     if sys.platform.startswith("win") and hMutex is not None:
  442.         try:
  443.             win32event.ReleaseMutex(hMutex)            
  444.         except win32api.error, e:
  445.             print('Could not release mutex %s Error: %s' % (name, str(e)))
  446.                         
  447. def GetDBInfo(filename):    
  448.     try:
  449.         # first 100 bytes of the file are definitely text
  450.         f = file(filename, 'rt')
  451.         # read first 100 bytes        
  452.         data = f.read(100)        
  453.         data = data.split(':')
  454.         updatestr, ver, numv = data[1:4]                                         
  455.         
  456.         # set C locale, otherwise python and wxpython complain
  457.         locale.setlocale(locale.LC_ALL, 'C')            
  458.         
  459.         # parse datestr to local time
  460.         # time is in following format '12 May 2004 15-55 +0200' or
  461.         # '%d %b %Y %H-%M %z', since strptime on windows has no %z flag,
  462.         # we need to process it separately
  463.         sep = updatestr.rfind(' ')
  464.         # get the time differnece relative to GMT 
  465.         tzhour = time.strptime(updatestr[sep + 2:], '%H%M').tm_hour
  466.         
  467.         # deduct or add tzhour to the time based on timezone
  468.         if updatestr[sep + 1] == '-':
  469.             tzhour = -tzhour
  470.             
  471.         updatestr = updatestr[:sep]
  472.         # set default C locale, as *.cvd timestring uses that
  473.         loc = locale.setlocale(locale.LC_TIME, 'C')
  474.         update_tm = time.strptime(updatestr, '%d %b %Y %H-%M %Z')
  475.         # restore the locale
  476.         locale.setlocale(locale.LC_TIME, loc)       
  477.         #get the final update time and add the UTC difference
  478.         updated = time.mktime(update_tm) - tzhour*3600.0 - time.altzone
  479.         return int(ver), int(numv), updated
  480.     except Exception, e:
  481.         print 'Unable to retrieve %s version. Error: %s' % (filename, str(e))
  482.         return None, None, None    
  483. def GetHostName():    
  484.     hostname = ''
  485.     if sys.platform.startswith('win'):            
  486.         # ignore errors retrieving domain name
  487.         try:                        
  488.             try:
  489.                 # there is no win32api.GetDomainName()
  490.                 # on 9x, therefore try: except: block
  491.                 dom_name = win32api.GetDomainName()
  492.             except:
  493.                 dom_name = None
  494.             comp_name = win32api.GetComputerName()
  495.             # on computers that are not members of domain 
  496.             # GetDomainName returns computer name
  497.             # we don't want to duplicate it
  498.             hostname = comp_name
  499.             if (dom_name is not None) and (dom_name != comp_name):
  500.                     hostname = dom_name + '\' + hostname
  501.         except:                
  502.             hostname = 'Unknown'
  503.     else:
  504.         import socket
  505.         try:
  506.             hostname = socket.gethostbyaddr(socket.gethostbyname(socket.gethostname()))[0]
  507.         except:        
  508.             hostname = 'Unknown'                      
  509.     return hostname
  510. def SpawnPyOrExe(filename, *params):    
  511.     if not hasattr(sys, 'frozen') and sys.platform.startswith('win'):
  512.         win32api.ShellExecute(0, 'open', 'pythonw.exe', 
  513.                     filename + '.py ' + ' '.join(params),
  514.                     None, win32con.SW_SHOWNORMAL)     
  515.     else:        
  516.         os.spawnl(os.P_NOWAIT, filename + '.exe', *params)            
  517.                         
  518. def SetDbFilesPermissions(dbdir):
  519.     if sys.platform.startswith('win'):            
  520.         # cygwin creates database files writable for a user
  521.         # who downloaded the database only
  522.         # this is a problem in the multiuser environment
  523.         # we need to reset file permissions to match
  524.         # those of the parent folder
  525.         
  526.         # don't do anything on Windows 9x or Me
  527.         isWin9x = win32api.GetVersionEx()[3] == win32con.VER_PLATFORM_WIN32_WINDOWS
  528.         if isWin9x:
  529.             return
  530.         # inherit securiy from parent                    
  531.         try:
  532.             sdParent = win32security.GetFileSecurity(dbdir, win32security.DACL_SECURITY_INFORMATION);
  533.             fname = os.path.join(dbdir, 'main.cvd')
  534.             win32security.SetFileSecurity(fname,
  535.                 win32security.DACL_SECURITY_INFORMATION,
  536.                 sdParent)
  537.         except Exception, e:
  538.             print 'An error occured whilst setting database permissions on %s. Error: %s' % (fname, str(e))
  539.             
  540.         try:
  541.             fname = os.path.join(dbdir, 'daily.cvd')
  542.             win32security.SetFileSecurity(fname,
  543.                 win32security.DACL_SECURITY_INFORMATION,
  544.                 sdParent)
  545.         except Exception, e:
  546.             print 'An error occured whilst setting database permissions on %s. Error: %s' % (fname, str(e))
  547.     else:
  548.          pass
  549. def SafeExpandEnvironmentStrings(s):
  550.     if sys.platform.startswith('win'):
  551.         try:
  552.             s = win32api.ExpandEnvironmentStrings(s)        
  553.         except Exception,e:
  554.             print "An Error occured in ExpandEnvironmentStrings: %s" % str(e) 
  555.     return s    
  556. def IsCygwinInstalled():
  557.     if sys.platform.startswith('win'):
  558.         # look for  / (root) mount point for cygwin and return yes if found
  559.         try:
  560.             win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE,
  561.                      r'SOFTWARECygnus SolutionsCygwinmounts v2/', 0, 
  562.                      win32con.KEY_READ);
  563.             return True
  564.         except:
  565.             return False
  566.     else:
  567.         return False
  568.         
  569. def SetCygwinTemp():
  570.     # if we have full cygwin install let's not worry
  571.     # about setting /tmp mount point
  572.     if IsCygwinInstalled():
  573.         return    
  574.         
  575.     # get user's temp folder    
  576.     temp = win32api.GetTempPath().rstrip('\');        
  577.     # set necessary cygwin registries
  578.     try:
  579.         # set magic flags and /cygdrive prefix
  580.         key = win32api.RegCreateKey(win32con.HKEY_CURRENT_USER,
  581.                  r'SOFTWARECygnus SolutionsCygwinmounts v2');
  582.         win32api.RegSetValueEx(key, 'cygdrive prefix', 0, win32con.REG_SZ, '/cygdrive')
  583.         win32api.RegSetValueEx(key, 'cygdrive flags', 0, win32con.REG_DWORD, 34)
  584.         # add tmp mount point   
  585.         key = win32api.RegCreateKey(win32con.HKEY_CURRENT_USER,
  586.                  r'SOFTWARECygnus SolutionsCygwinmounts v2/tmp');
  587.         win32api.RegSetValueEx(key, 'native', 0, win32con.REG_SZ, temp)
  588.         win32api.RegSetValueEx(key, 'flags', 0, win32con.REG_DWORD, 10)        
  589.     except Exception, e:
  590.         raise Exception("An Error occured whilst configuring Temporary Folder. Error:  %s" % str(e))
  591. def ReformatLog(data, rtf):
  592.     data = ReplaceClamAVWarnings(data.replace('rn', 'n'))
  593.     # retrieve the pure report strings
  594.     rex = re.compile('(.*)(-- summary --.*)(Infected files: d*?n)(.*)', re.M|re.S)
  595.     #rex = re.compile('(.*)(----------- SCAN SUMMARY -----------.*)(Infected files: d*?n)(.*)', re.M|re.S)    
  596.     r = rex.search(data)
  597.     if r is not None:                
  598.         found = ''
  599.         other = ''
  600.         lines = r.group(1).splitlines()   
  601.         # get all infections first
  602.         for line in lines:
  603.             if line.endswith('FOUND'):            
  604.                 if rtf:
  605.                     found += '\cf1\b %s\cf0\b0n' % line.replace('\', '\\')
  606.                 else:
  607.                     found += line + 'n'
  608.             elif not line.endswith('OK'):                 
  609.                 if rtf:
  610.                     other += line.replace('\', '\\') + 'n'
  611.                 else:
  612.                     other += line + 'n'
  613.                       
  614.         data = '%s%s' + r.group(2) + "%s" + r.group(4)         
  615.         # line with number of infected files
  616.         infected = r.group(3)                                     
  617.         if rtf:
  618.             num = re.match('.*?(d*?)$', infected)
  619.             if num is not None and int(num.group(1)) > 0:            
  620.                 # print in red
  621.                 infected = '\cf1\b %s\cf0\b0n' % infected
  622.             else:
  623.                 # print in green
  624.                 infected = '\cf2\b %s\cf0\b0n' % infected
  625.             data = data.replace('\', '\\')
  626.         data %= (other, found, infected)
  627.         if rtf:
  628.             data = r'{rtf1{colortbl ;red128green0blue0;;red0green128blue0;}%s}' % data.replace('n', '\parrn')
  629.     return data    
  630. # replaces clamav warnings with ours
  631. def ReplaceClamAVWarnings(data):
  632.     # reformat database update warnings to our FAQ
  633.     data = data.replace('Please check if ClamAV tools are linked against proper version of libclamavn', '')
  634.     data = data.replace(r'http:\www.clamav.netfaq.html', 'http://www.clamwin.com/content/view/10/27/')
  635.     
  636.     # remove XXX: Excluded lines
  637.     data = re.sub('.*: Excludedn', '', data)
  638.     
  639.     return data
  640. # returns tuple (version, url, changelog)
  641. # exception on error
  642. def GetOnlineVersion(config):
  643.      tmpfile = None
  644.      url = config.Get('Updates', 'CheckVersionURL')
  645.      try:
  646.          # add proxy info
  647.          if config.Get('Proxy', 'Host') != '':
  648.              proxy_info = {
  649.                  'user' : config.Get('Proxy', 'User'),
  650.                  'pass' : config.Get('Proxy', 'Password'),
  651.                  'host' : config.Get('Proxy', 'Host'),
  652.                  'port' : config.Get('Proxy', 'Port')
  653.                  }
  654.              if proxy_info['user'] != '':
  655.                  proxy_url = "http://%(user)s:%(pass)s@%(host)s:%(port)s"
  656.              else: 
  657.                  proxy_url = "http://%(host)s:%(port)s"
  658.                  
  659.              proxy_url = proxy_url % proxy_info    
  660.              proxy_support = urllib2.ProxyHandler({"http": proxy_url})
  661.              opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler())
  662.              urllib2.install_opener(opener)
  663.          f = urllib2.urlopen(url)    
  664.          verinfo = f.read()
  665.          #write to a temp file
  666.          tmpfile = tempfile.mktemp()
  667.          file(tmpfile, 'wt').write(verinfo)
  668.          
  669.          # read ini file
  670.          conf = ConfigParser.ConfigParser()
  671.          conf.read(tmpfile) 
  672.          os.unlink(tmpfile)
  673.          tmpfile = None
  674.          
  675.          # get our data           
  676.          version = conf.get('VERSION', 'VER') 
  677.          if conf.has_option('CHANGELOG', 'HTML'):
  678.              changelog = conf.get('CHANGELOG', 'HTML')
  679.          elif conf.has_option('CHANGELOG', 'TEXT'):
  680.              changelog = conf.get('CHANGELOG', 'TEXT')
  681.          else:
  682.              changelog = None    
  683.          changelog = changelog.replace('\n', 'n')
  684.          
  685.          url = conf.get('DOWNLOAD', 'WEB')                                      
  686.      except Exception, e:
  687.          if tmpfile is not None:
  688.              try:                    
  689.                  os.unlink(tmpfile)
  690.              except:
  691.                  pass
  692.          raise e
  693.      return (version, url, changelog)
  694. def CheckDatabase(config):
  695.     path = config.Get('ClamAV', 'Database')
  696.     if path == '':
  697.         return False
  698.     return os.path.isfile(os.path.join(path, 'main.cvd')) and 
  699.            os.path.isfile(os.path.join(path, 'daily.cvd'))
  700.                                        
  701. if __name__ == '__main__':
  702.     f = file('c:\2.txt', 'rt')
  703.     file('c:\3.rtf', 'wt').write(ReformatLog(f.read(), True))
  704.     #AppendLogFile('c:\1.txt',  'C:\MSDE2kLog.txt', 30000)
  705.     #currentDir = GetCurrentDir(True)
  706.     #os.chdir(currentDir)        
  707.     #CreateProfile()
  708.     config_file = os.path.join(GetProfileDir(True),'ClamWin.conf')                          
  709.     config = Config.Settings(config_file)    
  710.     b = config.Read()
  711.     print GetOnlineVersion(config)
  712.     print CheckDatabase(config)