From b352044f920ebd423fbdd22ee4fe73fab9b9f026 Mon Sep 17 00:00:00 2001 From: Cas Cremers Date: Mon, 25 Aug 2008 14:59:42 +0200 Subject: [PATCH] BUGFIX: PIL is tested at the start of the program. Previously, one would get one void verification result before Scyther detected PIL was not working. Now nothing is wasted. --- gui/Gui/Attackwindow.py | 5 +- gui/Gui/Mainwindow.py | 6 ++ gui/Gui/Makeimage.py | 173 +++++++++++++++++++++++++++++++++++++++ gui/Gui/Preference.py | 43 ++++++++-- gui/Gui/Scytherthread.py | 106 +----------------------- 5 files changed, 223 insertions(+), 110 deletions(-) create mode 100644 gui/Gui/Makeimage.py diff --git a/gui/Gui/Attackwindow.py b/gui/Gui/Attackwindow.py index 5a4b3ce..fb24da7 100644 --- a/gui/Gui/Attackwindow.py +++ b/gui/Gui/Attackwindow.py @@ -33,8 +33,11 @@ import Preference import Error #--------------------------------------------------------------------------- -if Preference.usePIL(): +try: import Image +except ImportError: + pass + #--------------------------------------------------------------------------- class AttackDisplay(wx.ScrolledWindow): diff --git a/gui/Gui/Mainwindow.py b/gui/Gui/Mainwindow.py index b89e20c..7c1b09e 100644 --- a/gui/Gui/Mainwindow.py +++ b/gui/Gui/Mainwindow.py @@ -33,6 +33,7 @@ import Scytherthread import Icon import About import Editor +import Preference #--------------------------------------------------------------------------- @@ -44,6 +45,9 @@ ID_CHECK = 103 #--------------------------------------------------------------------------- +def MainInitOnce(): + result = Preference.usePIL() # Makes sure PIL is tested. + class MainWindow(wx.Frame): def __init__(self, opts, args): @@ -54,6 +58,8 @@ class MainWindow(wx.Frame): self.dirname = os.path.abspath('.') + MainInitOnce() + self.filename = 'noname.spdl' self.load = False diff --git a/gui/Gui/Makeimage.py b/gui/Gui/Makeimage.py new file mode 100644 index 0000000..ba4c174 --- /dev/null +++ b/gui/Gui/Makeimage.py @@ -0,0 +1,173 @@ +#!/usr/bin/python +""" + Scyther : An automatic verifier for security protocols. + Copyright (C) 2007 Cas Cremers + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +""" + + +#--------------------------------------------------------------------------- + +""" Import externals """ +import wx +import os +import sys +import re +import threading +import StringIO + +#--------------------------------------------------------------------------- + +""" Import scyther components """ + +""" Import scyther-gui components """ +import Tempfile +import Preference + +#--------------------------------------------------------------------------- +try: + import Image +except ImportError: + pass +#--------------------------------------------------------------------------- + + +def writeGraph(attackthread,txt,fp): + + EDGE = 0 + NODE = 1 + DEFAULT = 2 + ALL = 3 + + def graphLine(txt): + fp.write("\t%s;\n" % (txt)) + + def setAttr(atxt,EdgeNodeDefAll=ALL): + if EdgeNodeDefAll == ALL: + setAttr(atxt,EDGE) + setAttr(atxt,NODE) + setAttr(atxt,DEFAULT) + else: + if EdgeNodeDefAll == EDGE: + edge = "edge" + elif EdgeNodeDefAll == NODE: + edge = "node" + else: + graphLine("%s" % atxt) + return + graphLine("%s [%s]" % (edge,atxt)) + + if sys.platform.startswith("darwin"): + attackthread.fontname = "Helvetica" + elif sys.platform.startswith("win"): + attackthread.fontname = "Courier" + else: + #font = wx.Font(9,wx.SWISS,wx.NORMAL,wx.NORMAL) + #attackthread.fontname = font.GetFaceName() + attackthread.fontname = "\"Helvetica\"" + + # write all graph lines but add layout modifiers + for l in txt.splitlines(): + fp.write(l) + if l.startswith("digraph"): + # Write additional stuff for this graph + # + # [CC][x] This dpi setting messed up quite a bit + #graphLine("dpi=96") + graphLine("rankdir=TB") + #graphLine("nodesep=0.1") + #graphLine("ranksep=0.001") + #graphLine("mindist=0.1") + + # Set fontname + if attackthread.fontname: + fontstring = "fontname=%s" % (attackthread.fontname) + setAttr(fontstring) + + # Stupid Mac <> Graphviz bug fix + if (sys.platform.startswith("mac")) or (sys.platform.startswith("darwin")): + # Note that dot on Mac cannot find the fonts by default, + # and we have to set them accordingly. + os.environ["DOTFONTPATH"]="~/Library/Fonts:/Library/Fonts:/System/Library/Fonts" + + # Select font size + if attackthread.parent and attackthread.parent.mainwin: + fontsize = attackthread.parent.mainwin.settings.fontsize + setAttr("fontsize=%s" % fontsize) + #setAttr("height=\"0.1\"",NODE) + #setAttr("width=\"1.0\"",NODE) + #setAttr("margin=\"0.3,0.03\"",NODE) + + +def makeImageDot(dotdata,attackthread=None): + """ create image for this particular dot data """ + + if Preference.usePIL(): + # If we have the PIL library, we can do postscript! great + # stuff. + type = "ps" + ext = ".ps" + else: + # Ye olde pnge file + type = "png" + ext = ".png" + + # command to write to temporary file + (fd2,fpname2) = Tempfile.tempcleaned(ext) + f = os.fdopen(fd2,'w') + + cmd = "dot -T%s" % (type) + + # execute command + cin,cout = os.popen2(cmd,'b') + + if attackthread: + writeGraph(attackthread,dotdata,cin) + else: + cin.write(dotdata) + + cin.close() + + for l in cout.read(): + f.write(l) + + cout.close() + f.flush() + f.close() + + return (fpname2, type) + + +def makeImage(attack,attackthread=None): + """ create image for this particular attack """ + + """ This should clearly be a method of 'attack' """ + + (name,type) = makeImageDot(attack.scytherDot,attackthread) + # if this is done, store and report + attack.file = name + attack.filetype = type + + +def testImage(): + """ + We generate a postscript file from a dot file, and see what happens. + """ + + dotdata = "digraph X {\nA->B;\n}\n" + (filename,filetype) = makeImageDot(dotdata) + testimage = Image.open(filename) + diff --git a/gui/Gui/Preference.py b/gui/Gui/Preference.py index daede86..dd5b9bc 100644 --- a/gui/Gui/Preference.py +++ b/gui/Gui/Preference.py @@ -49,13 +49,14 @@ from time import localtime,strftime #--------------------------------------------------------------------------- """ Import scyther-gui components """ +import Makeimage #--------------------------------------------------------------------------- """ Globals """ # Do we have the Python Imaging library? havePIL = True -#havePIL = False # For now, override (bounding box bug on Feisty?) +testPILOkay = None try: import Image except ImportError: @@ -71,14 +72,23 @@ def usePIL(): """ Determine whether or not we should use the PIL library """ - global havePIL + global havePIL, testPILOkay + + if not havePIL: + return False # Only if we have it, and it is windows. - if havePIL: - if sys.platform.startswith("lin"): - return True + if not sys.platform.startswith("lin"): + return False - return False + # Seems fine. But did we already test it? + if testPILOkay != None: + return testPILOkay + + # Test the usage + testPILOkay = True + testPILOkay = testPIL() + return testPILOkay def doNotUsePIL(): """ @@ -88,6 +98,27 @@ def doNotUsePIL(): havePIL = False + +def testPIL(): + """ + Test whether PIL works as we want it. + + We generate a postscript file from a dot file, and see what happens. + """ + + # depends on PIL lib + okay = True + try: + Makeimage.testImage() + # PIL seems fine + except: + # PIL broke + doNotUsePIL() + okay = False + + return okay + + #--------------------------------------------------------------------------- class Preferences(dict): diff --git a/gui/Gui/Scytherthread.py b/gui/Gui/Scytherthread.py index 0ba4d90..dff63f3 100644 --- a/gui/Gui/Scytherthread.py +++ b/gui/Gui/Scytherthread.py @@ -42,9 +42,10 @@ import Preference import Attackwindow import Icon import Error +import Makeimage #--------------------------------------------------------------------------- -if Preference.usePIL(): +if Preference.havePIL: import Image #--------------------------------------------------------------------------- @@ -148,7 +149,7 @@ class AttackThread(threading.Thread): done = 0 for cl in self.parent.claims: for attack in cl.attacks: - self.makeImage(attack) + Makeimage.makeImage(attack,self) done += 1 if self.callbackattack: wx.CallAfter(self.callbackattack,attack,self.totalattacks,done) @@ -157,107 +158,6 @@ class AttackThread(threading.Thread): if self.callbackdone: wx.CallAfter(self.callbackdone) - def writeGraph(self,txt,fp): - - EDGE = 0 - NODE = 1 - DEFAULT = 2 - ALL = 3 - - def graphLine(txt): - fp.write("\t%s;\n" % (txt)) - - def setAttr(atxt,EdgeNodeDefAll=ALL): - if EdgeNodeDefAll == ALL: - setAttr(atxt,EDGE) - setAttr(atxt,NODE) - setAttr(atxt,DEFAULT) - else: - if EdgeNodeDefAll == EDGE: - edge = "edge" - elif EdgeNodeDefAll == NODE: - edge = "node" - else: - graphLine("%s" % atxt) - return - graphLine("%s [%s]" % (edge,atxt)) - - if sys.platform.startswith("darwin"): - self.fontname = "Helvetica" - elif sys.platform.startswith("win"): - self.fontname = "Courier" - else: - #font = wx.Font(9,wx.SWISS,wx.NORMAL,wx.NORMAL) - #self.fontname = font.GetFaceName() - self.fontname = "\"Helvetica\"" - - # write all graph lines but add layout modifiers - for l in txt.splitlines(): - fp.write(l) - if l.startswith("digraph"): - # Write additional stuff for this graph - # - # [CC][x] This dpi setting messed up quite a bit - #graphLine("dpi=96") - graphLine("rankdir=TB") - #graphLine("nodesep=0.1") - #graphLine("ranksep=0.001") - #graphLine("mindist=0.1") - - # Set fontname - if self.fontname: - fontstring = "fontname=%s" % (self.fontname) - setAttr(fontstring) - - # Stupid Mac <> Graphviz bug fix - if (sys.platform.startswith("mac")) or (sys.platform.startswith("darwin")): - # Note that dot on Mac cannot find the fonts by default, - # and we have to set them accordingly. - os.environ["DOTFONTPATH"]="~/Library/Fonts:/Library/Fonts:/System/Library/Fonts" - - # Select font size - if self.parent and self.parent.mainwin: - fontsize = self.parent.mainwin.settings.fontsize - setAttr("fontsize=%s" % fontsize) - #setAttr("height=\"0.1\"",NODE) - #setAttr("width=\"1.0\"",NODE) - #setAttr("margin=\"0.3,0.03\"",NODE) - - def makeImage(self,attack): - """ create image for this particular attack """ - - if Preference.usePIL(): - # If we have the PIL library, we can do postscript! great - # stuff. - type = "ps" - ext = ".ps" - else: - # Ye olde pnge file - type = "png" - ext = ".png" - - # command to write to temporary file - (fd2,fpname2) = Tempfile.tempcleaned(ext) - f = os.fdopen(fd2,'w') - - cmd = "dot -T%s" % (type) - - # execute command - cin,cout = os.popen2(cmd,'b') - - self.writeGraph(attack.scytherDot,cin) - cin.close() - - for l in cout.read(): - f.write(l) - - cout.close() - f.flush() - f.close() - - # if this is done, store and report - attack.filetype = type - attack.file = fpname2 # this is where the file name is stored #---------------------------------------------------------------------------