def BPFSImageFile(fshandler, location, name=None, img=None, width=-1, height=-1, valign="center", bgcolor=None): """Handles image files If we have to do any conversion on the file then we return PNG data. This used to be a class derived from wx.FSFile, but due to various wxPython bugs it instead returns the parameters to make a wx.FSFile since a new one has to be made every time. """ # if this is a bad or non-existing image file, use the dummy one! if name is None and img is None: name=guihelper.getresourcefile('wallpaper.png') # special fast path if we aren't resizing or converting image if img is None and width<0 and height<0: mime=guihelper.getwxmimetype(name) # wxPython 2.5.3 has a new bug and fails to read bmp files returned as a stream if mime not in (None, "image/x-bmp"): return (open(name, "rb"), location, mime, "", wx.DateTime_Now()) if img is None: img=wx.Image(name) if width>0 and height>0: b=ScaleImageIntoBitmap(img, width, height, bgcolor, valign) else: b=img.ConvertToBitmap() with common.usetempfile('png') as f: if not b.SaveFile(f, wx.BITMAP_TYPE_PNG): raise Exception, "Saving to png failed" data=open(f, "rb").read() return (cStringIO.StringIO(data), location, "image/png", "", wx.DateTime_Now())
def GetSections(self): # work out section and item sizes self.thumbnail=wx.Image(guihelper.getresourcefile('ringer.png')).ConvertToBitmap() dc=wx.MemoryDC() dc.SelectObject(wx.EmptyBitmap(100,100)) # unused bitmap needed to keep wxMac happy h=dc.GetTextExtent("I")[1] itemsize=self.thumbnail.GetWidth()+160, max(self.thumbnail.GetHeight(), h*4+DisplayItem.PADDING)+DisplayItem.PADDING*2 # get all the items items=[DisplayItem(self, key) for key in self._data[self.database_key] if self._data[self.database_key][key].mediadata!=None] self.sections=[] if len(items)==0: return self.sections # get the current sorting type for sectionlabel, items in self.organizeby_Origin(items): self.media_root.AddMediaNode(sectionlabel, self) sh=aggregatedisplay.SectionHeader(sectionlabel) sh.itemsize=itemsize for item in items: item.thumbnailsize=self.thumbnail.GetWidth(), self.thumbnail.GetHeight() # sort items by name items.sort(self.CompareItems) self.sections.append( (sh, items) ) return [sh for sh,items in self.sections]
def getwallpapers(self, result): self.log('Reading wallpaper index') self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media={} media_index=self._get_wallpaper_index() self.charset_ascii() self._wallpaper_mode() res={} self._get_image_index(self.protocolclass.MIN_WALLPAPER_INDEX, self.protocolclass.MAX_WALLPAPER_INDEX, res, 0, 'wallpaper') _dummy_data=file(guihelper.getresourcefile('wallpaper.png'),'rb').read() for e in res.values(): media[e['name']]=_dummy_data self.charset_ascii() self._photo_mode() res={} self._get_image_index(self.protocolclass.MIN_PHOTO_INDEX, self.protocolclass.MAX_PHOTO_INDEX, res, 0, 'camera') for e in res.values(): data=self._get_media_file(e['name']) if data != False: print "get OK" media[e['name']]=data else: print "get failed" media[e['name']]=_dummy_data result['wallpapers']=media result['wallpaper-index']=media_index return result
def GetSections(self): self.thumbnail=wx.Image(guihelper.getresourcefile('ringer.png')).ConvertToBitmap() dc=wx.MemoryDC() dc.SelectObject(wx.EmptyBitmap(100,100)) # unused bitmap needed to keep wxMac happy h=dc.GetTextExtent("I")[1] itemsize=self.thumbnail.GetWidth()+160, max(self.thumbnail.GetHeight(), h*4+DisplayItem.PADDING)+DisplayItem.PADDING*2 items=[DisplayItem(self, key, self.mainwindow.ringerpath) for key in self._data['ringtone-index']] items=[item for item in items if os.path.exists(item.filename)] self.sections=[] if len(items)==0: return self.sections for i in range(len(self.organizetypes)): item=self.organizemenu.FindItemByPosition(i) if self.organizemenu.IsChecked(item.GetId()): for sectionlabel, items in self.organizeinfo[item.GetId()](items): sh=aggregatedisplay.SectionHeader(sectionlabel) sh.itemsize=itemsize for item in items: item.thumbnailsize=self.thumbnail.GetWidth(), self.thumbnail.GetHeight() items=[(item.name.lower(), item) for item in items] items.sort() items=[item for name,item in items] self.sections.append( (sh, items) ) return [sh for sh,items in self.sections] assert False, "Can't get here"
def __init__(self, parent, file, convertinfo): wx.Dialog.__init__(self, parent, title="Convert Audio File", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.MAXIMIZE_BOX) self.file=file self.convertinfo=convertinfo self.afi=None self.temporaryfiles=[] self.wavfile=common.gettempfilename("wav") # full length wav equivalent self.clipwavfile=common.gettempfilename("wav") # used for clips from full length wav self.temporaryfiles.extend([self.wavfile, self.clipwavfile]) getattr(self, self.PARAMETERS[convertinfo.format]['setup'])() vbs=wx.BoxSizer(wx.VERTICAL) self.create_convert_pane(vbs, file, convertinfo) self.create_crop_panel(vbs) vbs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALL|wx.ALIGN_RIGHT, 5) self.SetSizer(vbs) vbs.Fit(self) self.FindWindowById(wx.ID_OK).Enable(False) for i in self.cropids: self.FindWindowById(i).Enable(False) wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk) wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel) wx.EVT_TIMER(self, self.ID_TIMER, self.OnTimer) wx.EVT_BUTTON(self, wx.ID_HELP, lambda _: wx.GetApp().displayhelpid(helpids.ID_DLG_AUDIOCONVERT)) self.sound=None self.timer=wx.Timer(self, self.ID_TIMER) if guihelper.IsMac(): self.zerolenwav=guihelper.getresourcefile("zerolen.wav")
def setuphelp(self): """Does all the nonsense to get help working""" import wx.html from wxPython.htmlhelp import wxHtmlHelpController wx.FileSystem_AddHandler(wx.ZipFSHandler()) self.helpcontroller=wxHtmlHelpController() self.helpcontroller.AddBook(guihelper.getresourcefile("bitpim.htb")) self.helpcontroller.UseConfig(self.config, "help")
def windowsinit(self, iconfile): bitmap=wx.Bitmap(guihelper.getresourcefile(iconfile), wx.BITMAP_TYPE_PNG) icon=wx.EmptyIcon() icon.CopyFromBitmap(bitmap) self.SetIcon(icon, "BitFling") wx.EVT_TASKBAR_RIGHT_UP(self, self.OnRButtonUp) wx.EVT_TASKBAR_LEFT_UP(self, self.OnLButtonUp) wx.EVT_TASKBAR_LEFT_DOWN(self, self.OnLeftDown)
def setuphelp(self): """Does all the nonsense to get help working""" import wx.html # Add the Zip filesystem wx.FileSystem_AddHandler(wx.ZipFSHandler()) # Get the help working self.helpcontroller=wx.html.HtmlHelpController() self.helpcontroller.AddBook(guihelper.getresourcefile("bitpim.htb")) self.helpcontroller.UseConfig(self.config, "help")
def windowsinit(self, iconfile): bitmap=wx.Bitmap(guihelper.getresourcefile(iconfile), wx.BITMAP_TYPE_PNG) icon=wx.EmptyIcon() icon.CopyFromBitmap(bitmap) self.SetIcon(icon, "BitFling") wx.EVT_TASKBAR_RIGHT_UP(self, self.OnRButtonUp) wx.EVT_TASKBAR_LEFT_UP(self, self.OnLButtonUp) #wx.EVT_TASKBAR_MOVE(self, self.OnMouseMotion) wx.EVT_TASKBAR_LEFT_DOWN(self, self.OnLeftDown)
def _gen_print_data(self): if not self._date_changed and \ not self._style_changed and \ self._html is not None: return self._dt_start=self._start_date.GetValue() self._dt_end=self._end_date.GetValue() if not self._dt_start.IsValid() or not self._dt_end.IsValid(): return print_data=( (self._regular_template, self._regular_style, self._get_list_data), (self._monthly_template, self._monthly_style, self._get_monthly_data)) print_style=self._print_style.GetSelection() print_dict=print_data[print_style][2]() if self._xcp is None: self._xcp=xyaptu.xcopier(None) tmpl=file(guihelper.getresourcefile(print_data[print_style][0]), 'rt').read() self._xcp.setupxcopy(tmpl) elif self._style_changed: tmpl=file(guihelper.getresourcefile(print_data[print_style][0]), 'rt').read() self._xcp.setupxcopy(tmpl) if self._dns is None: self._dns={ 'common': __import__('common') } self._dns['guihelper']=__import__('guihelper') self._dns['events']=[] self._dns['events']=print_dict self._dns['date_range']='%s - %s'%\ (self._dt_start.FormatDate(), self._dt_end.FormatDate()) html=self._xcp.xcopywithdns(self._dns.copy()) sd={'styles': {}, '__builtins__': __builtins__ } try: execfile(guihelper.getresourcefile(print_data[print_style][1]), sd, sd) except UnicodeError: common.unicode_execfile(guihelper.getresourcefile(print_data[print_style][1]), sd, sd) try: self._html=bphtml.applyhtmlstyles(html, sd['styles']) except: if __debug__: file('debug.html', 'wt').write(html) raise self._date_changed=self._style_change=False
def GetImageConstructionInformation(self,file): file=os.path.join(imagespath, file) if file.endswith(".mp4") or not os.path.isfile(file): return guihelper.getresourcefile('wallpaper.png'), wx.Image if self.isBCI(file): return file, lambda name: brewcompressedimage.getimage(brewcompressedimage.FileInputStream(file)) fi=fileinfo.identify_imagefile(file) if fi is not None and fi.format=='LGBIT': return file, conversions.convertfilelgbittobmp return file, wx.Image
def genericinit(self, iconfile): self.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) bitmap=wx.Bitmap(guihelper.getresourcefile(iconfile), wx.BITMAP_TYPE_PNG) bit=wx.StaticBitmap(self, -1, bitmap) self.Show(True) wx.EVT_RIGHT_UP(bit, self.OnRButtonUp) wx.EVT_LEFT_UP(bit, self.OnLButtonUp) wx.EVT_MOTION(bit, self.OnMouseMotion) wx.EVT_LEFT_DOWN(bit, self.OnLeftDown) self.bit=bit
def OpenBPImageFile(self, location, name, **kwargs): f = guihelper.getresourcefile(name) if not os.path.isfile(f): print f, "doesn't exist" return None si = statinfo(f) res = self._GetCache(location, si) if res is not None: return res res = BPFSImageFile(self, location, name=f, **kwargs) self._AddCache(location, si, res) return res
def OpenBPImageFile(self, location, name, **kwargs): f=guihelper.getresourcefile(name) if not os.path.isfile(f): print f,"doesn't exist" return None si=statinfo(f) res=self._GetCache(location, si) if res is not None: return res res=BPFSImageFile(self, location, name=f, **kwargs) self._AddCache(location, si, res) return res
def GetImageConstructionInformation(self,file): file=os.path.join(imagespath, file) if file.endswith(".mp4") or not os.path.isfile(file): return guihelper.getresourcefile('wallpaper.png'), wx.Image if self.isBCI(file): return file, lambda name: brewcompressedimage.getimage(brewcompressedimage.FileInputStream(file)) # LG phones may return a proprietary wallpaper media file, LGBIT fi=fileinfo.identify_imagefile(file) if fi is not None and fi.format=='LGBIT': return file, conversions.convertfilelgbittobmp return file, wx.Image
def GetItemThumbnail(self, data, width, height, fileinfo=None): img=self.GetImageFromString(data, fileinfo) if img is None or not img.Ok(): img=wx.Image(guihelper.getresourcefile('wallpaper.png')) if width!=img.GetWidth() or height!=img.GetHeight(): sfactorw=float(width)/img.GetWidth() sfactorh=float(height)/img.GetHeight() sfactor=min(sfactorw,sfactorh) # preserve aspect ratio newwidth=int(img.GetWidth()*sfactor) newheight=int(img.GetHeight()*sfactor) img.Rescale(newwidth, newheight) return img.ConvertToBitmap()
def GetItemThumbnail(self, name, width, height): img,_=self.GetImage(name.encode(guiwidgets.media_codec)) if img is None or not img.Ok(): img=wx.Image(guihelper.getresourcefile('wallpaper.png')) if width!=img.GetWidth() or height!=img.GetHeight(): sfactorw=float(width)/img.GetWidth() sfactorh=float(height)/img.GetHeight() sfactor=min(sfactorw,sfactorh) # preserve aspect ratio newwidth=int(img.GetWidth()*sfactor) newheight=int(img.GetHeight()*sfactor) img.Rescale(newwidth, newheight) bitmap=img.ConvertToBitmap() return bitmap
def getwallpapers(self, result): self.log('Reading wallpaper index') self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media={} media_index=self._get_wallpaper_index() _dummy_data=file(guihelper.getresourcefile('wallpaper.png'),'rb').read() for e in media_index.values(): media[e['name']]=_dummy_data result['wallpapers']=media result['wallpaper-index']=media_index return result
def getwallpapers(self, result): self.log('Reading wallpaper index') self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media = {} media_index = self._get_wallpaper_index() _dummy_data = file(guihelper.getresourcefile('wallpaper.png'), 'rb').read() for e in media_index.values(): media[e['name']] = _dummy_data result['wallpapers'] = media result['wallpaper-index'] = media_index return result
def GetImageConstructionInformation(self, file): """Gets information for constructing an Image from the file @return: (filename to use, function to call that returns wxImage) """ fi=self.GetFileInfo(file) if file.endswith(".mp4") or not os.path.isfile(file): return guihelper.getresourcefile('wallpaper.png'), wx.Image if fi: if fi.format=='AVI': return file, conversions.convertfileavitobmp if fi.format=='LGBIT': return file, conversions.convertfilelgbittobmp if fi.format=='3GPP2': return file, lambda name: None return file, wx.Image
def getwallpapers(self, result): self.log('Reading wallpaper index') self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media = {} media_index = self._get_wallpaper_index() # Set the media type to be pic (wallpaper) self.charset_ascii() self._wallpaper_mode() # and read the list res = {} self._get_image_index(self.protocolclass.MIN_WALLPAPER_INDEX, self.protocolclass.MAX_WALLPAPER_INDEX, res, 0, 'wallpaper') # dummy data for wallpaper _dummy_data = file(guihelper.getresourcefile('wallpaper.png'), 'rb').read() for e in res.values(): media[e['name']] = _dummy_data # Set the media type to be photo self.charset_ascii() self._photo_mode() # and read the list res = {} self._get_image_index(self.protocolclass.MIN_PHOTO_INDEX, self.protocolclass.MAX_PHOTO_INDEX, res, 0, 'camera') # read the files out of the phone for e in res.values(): data = self._get_media_file(e['name']) if data != False: print "get OK" media[e['name']] = data else: print "get failed" media[e['name']] = _dummy_data result['wallpapers'] = media result['wallpaper-index'] = media_index return result
def __init__(self, parent, file, convertinfo): wx.Dialog.__init__(self, parent, title="Convert Audio File", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.MAXIMIZE_BOX) self.file=file self.convertinfo=convertinfo self.afi=None self.temporaryfiles=[] self.wavfile=common.gettempfilename("wav") # full length wav equivalent self.clipwavfile=common.gettempfilename("wav") # used for clips from full length wav self.temporaryfiles.extend([self.wavfile, self.clipwavfile]) getattr(self, self.PARAMETERS[convertinfo.format]['setup'])() vbs=wx.BoxSizer(wx.VERTICAL) # create the covert controls self.create_convert_pane(vbs, file, convertinfo) # and the crop controls self.create_crop_panel(vbs) vbs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALL|wx.ALIGN_RIGHT, 5) self.SetSizer(vbs) vbs.Fit(self) # diable various things self.FindWindowById(wx.ID_OK).Enable(False) for i in self.cropids: self.FindWindowById(i).Enable(False) # Events wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk) wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel) wx.EVT_TIMER(self, self.ID_TIMER, self.OnTimer) wx.EVT_BUTTON(self, wx.ID_HELP, lambda _: wx.GetApp().displayhelpid(helpids.ID_DLG_AUDIOCONVERT)) # timers and sounds self.sound=None self.timer=wx.Timer(self, self.ID_TIMER) # wxPython wrapper on Mac raises NotImplemented for wx.Sound.Stop() so # we hack around that by supplying a zero length wav to play instead if guihelper.IsMac(): self.zerolenwav=guihelper.getresourcefile("zerolen.wav")
def getwallpapers(self, result): self.log("Reading wallpaper index") self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media = {} media_index = self._get_wallpaper_index() # Set the media type to be pic (wallpaper) self.charset_ascii() self._wallpaper_mode() # and read the list res = {} self._get_image_index( self.protocolclass.MIN_WALLPAPER_INDEX, self.protocolclass.MAX_WALLPAPER_INDEX, res, 0, "wallpaper" ) # dummy data for wallpaper _dummy_data = file(guihelper.getresourcefile("wallpaper.png"), "rb").read() for e in res.values(): media[e["name"]] = _dummy_data # Set the media type to be photo self.charset_ascii() self._photo_mode() # and read the list res = {} self._get_image_index(self.protocolclass.MIN_PHOTO_INDEX, self.protocolclass.MAX_PHOTO_INDEX, res, 0, "camera") # read the files out of the phone for e in res.values(): data = self._get_media_file(e["name"]) if data != False: print "get OK" media[e["name"]] = data else: print "get failed" media[e["name"]] = _dummy_data result["wallpapers"] = media result["wallpaper-index"] = media_index return result
def __init__(self, mainwindow, parent, media_root): global thewallpapermanager thewallpapermanager = self self.mainwindow = mainwindow self.usewidth = 10 self.useheight = 10 self._dummy_image_filename = guihelper.getresourcefile('wallpaper.png') wx.FileSystem_AddHandler(BPFSHandler(self)) self._data = {self.database_key: {}} fileview.FileView.__init__(self, mainwindow, parent, media_root, "wallpaper-watermark") self.thedir = self.mainwindow.wallpaperpath self.wildcard="Image files|*.bmp;*.jpg;*.jpeg;*.png;*.gif;*.pnm;*.tiff;*.ico;*.bci;*.bit"\ "|Video files|*.3g2|All files|*.*" ## self.bgmenu.Insert(1,guihelper.ID_FV_PASTE, "Paste") ## wx.EVT_MENU(self.bgmenu, guihelper.ID_FV_PASTE, self.OnPaste) self.modified = False pubsub.subscribe(self.OnListRequest, pubsub.REQUEST_WALLPAPERS) self._raw_image = self._shift_down = False
def __init__(self, mainwindow, parent, media_root): global thewallpapermanager thewallpapermanager=self self.mainwindow=mainwindow self.usewidth=10 self.useheight=10 self._dummy_image_filename=guihelper.getresourcefile('wallpaper.png') wx.FileSystem_AddHandler(BPFSHandler(self)) self._data={self.database_key: {}} fileview.FileView.__init__(self, mainwindow, parent, media_root, "wallpaper-watermark") self.thedir=self.mainwindow.wallpaperpath self.wildcard="Image files|*.bmp;*.jpg;*.jpeg;*.png;*.gif;*.pnm;*.tiff;*.ico;*.bci;*.bit"\ "|Video files|*.3g2|All files|*.*" ## self.bgmenu.Insert(1,guihelper.ID_FV_PASTE, "Paste") ## wx.EVT_MENU(self.bgmenu, guihelper.ID_FV_PASTE, self.OnPaste) self.modified=False pubsub.subscribe(self.OnListRequest, pubsub.REQUEST_WALLPAPERS) self._raw_image=self._shift_down=False
def setuphelp(self): """Does all the nonsense to get help working""" import wx.html from wxPython.htmlhelp import wxHtmlHelpController wx.FileSystem_AddHandler(wx.ZipFSHandler()) self.helpcontroller=wxHtmlHelpController() self.helpcontroller.AddBook(guihelper.getresourcefile("bitpim.htb")) self.helpcontroller.UseConfig(self.config, "help") def IsConnectionAllowed(self, peeraddr, username=None, password=None): """Verifies if a connection is allowed If username and password are supplied (as should be the case if calling this method before executing some code) then they are checked as being from a valid address as well. If username and password are not supplied then this method checks if any of the authentication rules allow a connection from the peeraddr. This form is used immediately after calling accept() on a socket, but before doing anything else.""" v=(peeraddr[0], username, password) if username is not None and password is None: self.Log("%s: No password supplied for user %s" % (peeraddr, `username`)) assert False, "No password supplied" return False print "ica of "+`v` val=self.icacache.get(v, None) if val is not None: allowed, expires = val if allowed: if self._has_expired(expires): msg="Connection from %s no longer allowed due to expiry" % (peeraddr[0],) if username is not None: msg+=". Username "+`username` self.Log(msg) return False return True return False ret_allowed=False ret_expiry=0 for uname, pwd, expires, addresses in self.authinfo.values(): if not self._does_address_match(peeraddr[0], addresses): continue if username is not None: if username!=uname: continue if not self._verify_password(password, pwd): self.Log("Wrong password supplied for user %s from %s" % (`username`, peeraddr[0])) continue ret_expiry=max(ret_expiry, expires) ret_allowed=True if not ret_allowed: if username is not None: self.Log("No valid credentials for user %s from %s" % (username, peeraddr[0])) else: self.Log("No defined users for address "+`peeraddr`) self.icacache[v]=ret_allowed, ret_expiry return self.IsConnectionAllowed(peeraddr, username, password) def _verify_password(self, password, pwd): """Returns True if password matches pwd @param password: password supplied by user @param pwd: password as we store it (salt $ hash)""" salt,hash=pwd.split("$", 1) x="" for i in range(0, len(salt), 2): x+=chr(int(salt[i:i+2], 16)) salt=x str=[] str.extend([ord(x) for x in salt]) str.extend([ord(x) for x in password]) val=sha.new("".join([chr(x) for x in str])) print password, pwd, val.hexdigest(), val.hexdigest()==hash return val.hexdigest()==hash def _does_address_match(self, peeraddr, addresses): """Returns if the peeraddr matches any of the supplied addresses""" for addr in addresses: if peeraddr==addr: return True if '*' in addr or '?' in addr or '[' in addr: if fnmatch.fnmatch(peeraddr, addr): return True ips=[] try: ips=socket.getaddrinfo(addr, None) except: pass for _, _, _, _, ip in ips: if peeraddr==ip[0]: return True return False def _has_expired(self, expires): if expires==0: return False if time.time()>expires: return True return False def CloseRequested(self, evt): if evt.CanVeto(): self.Show(False) evt.Veto() return self.taskwin.GoAway() evt.Skip() sys.excepthook=sys.__excepthook__ def OnXmlServerEvent(self, msg): if msg.cmd=="log": self.Log(msg.data) elif msg.cmd=="logexception": self.LogException(msg.data) else: assert False, "bad message "+`msg` pass def OnExitButton(self, _): self.Close(True) def OnHideButton(self, _): self.Show(False) def OnHelpButton(self, _): import helpids self.helpcontroller.Display(helpids.ID_BITFLING) def Log(self, text): if thread.get_ident()!=guithreadid: wx.PostEvent(self, XmlServerEvent(cmd="log", data=text)) else: self.lw.log(text) def LogException(self, exc): if thread.get_ident()!=guithreadid: wx.PostEvent(self, XmlServerEvent(cmd="log", data="Exception in thread "+threading.currentThread().getName())) wx.PostEvent(self, XmlServerEvent(cmd="logexception", data=exc)) else: self.lw.logexception(exc) def excepthook(self, *args): """Replacement exception handler that sends stuff to our log window""" self.LogException(args) def GetCertificateFilename(self): """Return certificate filename By default $HOME (or My Documents) / .bitfling.key but can be overridden with "certificatefile" config key""" if guihelper.IsMSWindows(): from win32com.shell import shell, shellcon path=shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0) path=os.path.join(path, ".bitfling.key") else: path=os.path.expanduser("~/.bitfling.key") return self.config.Read("certificatefile", path) def StartIfICan(self): certfile=self.GetCertificateFilename() if not os.path.isfile(certfile): wx.BeginBusyCursor(wx.StockCursor(wx.CURSOR_ARROWWAIT)) bi=wx.BusyInfo("Creating BitFling host certificate and keys") try: generate_certificate(certfile) if not os.path.isfile(certfile): certfile=None finally: del bi wx.EndBusyCursor() port=self.config.ReadInt("port", 12652) if port<1 or port>65535: port=None host=self.config.Read("bindaddress", "") if certfile is None or port is None: return self.Log("Starting on port "+`port`) key=paramiko.DSSKey.from_private_key_file(certfile) fp=paramiko.util.hexify(key.get_fingerprint()) self.configpanel.fingerprint.SetValue(fp) self.configpanel.porttext.SetLabel(`port`) self.configpanel.GetSizer().Layout() self.xmlrpcserver=BitFlingService(self, host, port, key) self.xmlrpcserver.setDaemon(True) self.xmlrpcserver.start() def generate_certificate(outfile): key=paramiko.DSSKey.generate() key.write_private_key_file(outfile, None) class XMLRPCService (xmlrpcstuff.Server) : def __init__(self, mainwin, host, port, servercert): self.mainwin=mainwin xmlrpcstuff.Server.__init__(self, host, port, servercert) def OnLog(self, msg): wx.PostEvent(self.mainwin, XmlServerEvent(cmd="log", data=msg)) def OnLogException(self, exc): wx.PostEvent(self.mainwin, XmlServerEvent(cmd="logexception", data=exc)) def OnNewAccept(self, clientaddr): return self.mainwin.IsConnectionAllowed(clientaddr) def OnNewUser(self, clientaddr, username, password): return self.mainwin.IsConnectionAllowed(clientaddr, username, password) def OnMethodDispatch(self, method, params, username, clientaddr): method="exp_"+method if not hasattr(self, method): raise Fault(3, "No such method") context={ 'username': username, 'clientaddr': clientaddr } return getattr(self, method)(*params, **{'context': context}) class BitFlingService (XMLRPCService) : def __init__(self, mainwin, host, port, servercert): XMLRPCService.__init__(self, mainwin, host, port, servercert) self.handles={} def stashhandle(self, context, comm): for i in range(10000): if i not in self.handles: self.handles[i]=[context, comm] return i def gethandle(self, context, num): return self.handles[num][1] def exp_scan(self, context): if usb is None: return comscan.comscan() else: return usbscan.usbscan()+comscan.comscan() def exp_getversion(self, context): return version.description def exp_deviceopen(self, port, baud, timeout, hardwareflow, softwareflow, context): return self.stashhandle(context, commport.CommConnection(None, port, baud, timeout, hardwareflow, softwareflow)) def exp_deviceclose(self, handle, context): comm=self.gethandle(context, handle) comm.close() del self.handles[handle] return True def exp_devicesetbaudrate(self, handle, rate, context): return self.gethandle(context, handle).setbaudrate(rate) def exp_devicesetdtr(self, handle, dtr, context): return self.gethandle(context, handle).setdtr(dtr) def exp_devicesetrts(self, handle, rts, context): return self.gethandle(context, handle).setrts(rts) def exp_devicewrite(self, handle, data, context): self.gethandle(context, handle).write(data.data) return len(data.data) def exp_devicesendatcommand(self, handle, atcommand, ignoreerror, context): "Special handling for empty lists and exceptions" try: res=self.gethandle(context, handle).sendatcommand(atcommand.data, ignoreerror=ignoreerror) if len(res)==0: res=1 except: res=0 return res def exp_devicereaduntil(self, handle, char, numfailures, context): return Binary(self.gethandle(context, handle).readuntil(char.data, numfailures=numfailures)) def exp_deviceread(self, handle, numchars, context): return Binary(self.gethandle(context, handle).read(numchars)) def exp_devicereadsome(self, handle, numchars, context): if numchars==-1: numchars=None return Binary(self.gethandle(context, handle).readsome(log=True,numchars=numchars)) def exp_devicewritethenreaduntil(self, handle, data, char, numfailures, context): return Binary(self.gethandle(context, handle).writethenreaduntil(data.data, False, char.data, False, False, numfailures)) def run(args): theApp=wx.PySimpleApp() menu=wx.Menu() menu.Append(ID_EXIT, "Exit") mw=MainWindow(None, -1, "BitFling") taskwin=MyTaskBarIcon(mw, menu) mw.taskwin=taskwin theApp.MainLoop() if __name__ == '__main__': run() try: import native.usb as usb except ImportError: usb=None if guihelper.IsMSWindows(): parentclass=wx.TaskBarIcon else: parentclass=wx.Frame if __name__ == '__main__': run()
def usbscan(*args, **kwargs): if usb is None: return [] global ids if ids is None: ids=usb_ids.usb_ids() ids.add_data(guihelper.getresourcefile("usb.ids")) ids.add_data(guihelper.getresourcefile("bitpim_usb.ids")) global needdriver if needdriver is None: needdriver=[] for line in open(guihelper.getresourcefile("usb_needdriver.ids"), "rt"): line=line.strip() if line.startswith("#") or len(line)==0: continue prod,vend,iface=[int(x, 16) for x in line.split()] needdriver.append( (prod,vend,iface) ) res=[] usb.UpdateLists() for bus in usb.AllBusses(): for device in bus.devices(): for iface in device.interfaces(): seenin=False seenout=False for ep in iface.endpoints(): if ep.isbulk(): if ep.direction()==ep.IN: seenin=True else: seenout=True if seenin and seenout: # we now have a device/interface that has bidirectional bulk endpoints name="usb::%s::%s::%d" % (bus.name(), device.name(), iface.number()) active=True available=False try: iface.openbulk().close() available=True except: pass v={'name': name, 'active': active, 'available': available, 'libusb': True, 'usb-vendor#': device.vendor(), 'usb-product#': device.product(), 'usb-interface#': iface.number(), 'VID': '0x%04X'%device.vendor(), 'PID': '0x%04X'%device.product() } if ( device.vendor(), device.product(), iface.number() ) in needdriver: v["available"]=False v['driver-required']=True vend,prod,i=ids.lookupdevice(device.vendor(), device.product(), iface.number()) if vend is None: vend="#%04X" % (device.vendor(),) else: v['usb-vendor']=vend if prod is None: prod="#%04X" % (device.product(),) else: v['usb-product']=prod if i is None: i="#%02X" % (iface.number(),) else: v['usb-interface']=i hwinstance="USB Device - Vendor %s, Product %s, (Interface %s)" % \ (vend, prod, i) v['description']=hwinstance prot=" / ".join([val for val in ids.lookupclass(*(iface.classdetails())) if val is not None]) if len(prot): v["protocol"]=prot for n,i in ("usb-vendorstring", device.vendorstring), \ ("usb-productstring", device.productstring), \ ("usb-serialnumber", device.serialnumber): try: x=i() if x is not None: v[n]=x except: pass res.append(v) return res
def getwallpapers(self, result): self.log('Reading wallpaper index') self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media={} media_index=self._get_wallpaper_index() _dummy_data=file(guihelper.getresourcefile('wallpaper.png'),'rb').read() for e in media_index.values(): media[e['name']]=_dummy_data result['wallpapers']=media result['wallpaper-index']=media_index return result def _add_wallpapers(self, names, name_dict, media): self.charset_base64() for n in names: _media_key=name_dict[n] if not self._add_media_file(n, common.stripext(n), 12, media[_media_key].get('data', '')): self.log('Failed to send wallpaper %s'%n) self.charset_ascii() def savewallpapers(self, result, merge): self.log('Saving wallpapers') self.setmode(self.MODEMODEM) self.charset_ascii() self._wallpaper_mode() media=result.get('wallpapers', {}) media_index=result.get('wallpaper-index', {}) media_names=[x['name'] for x in media.values()] index_names=[x['name'] for x in media_index.values()] del_names=[x for x in index_names if x not in media_names] new_names=[x for x in media_names if x not in index_names] self._del_media_files(del_names) names_to_keys={} for k,e in media.items(): names_to_keys[e['name']]=k self._add_wallpapers(new_names, names_to_keys, media) return result def getmemo(self, result): self.log('Reading Memo') self.setmode(self.MODEMODEM) self.charset_ascii() _req=self.protocolclass.memo_read_req() _res=self.sendATcommand(_req, self.protocolclass.memo_read_resp) res={} for e in _res: _memo=memo.MemoEntry() _memo.text=e.text res[_memo.id]=_memo result['memo']=res return res def savememo(self, result, merge): self.log('Writing Memo') self.setmode(self.MODEMODEM) self.charset_ascii() _req=self.protocolclass.memo_del_req() for i in range(self.protocolclass.MEMO_MIN_INDEX, self.protocolclass.MEMO_MAX_INDEX+1): _req.index=i try: self.sendATcommand(_req, None) except: pass _memo_dict=result.get('memo', {}) _keys=_memo_dict.keys() _keys.sort() _req=self.protocolclass.memo_write_req() for k in _keys: _req.text=_memo_dict[k].text try: self.sendATcommand(_req, None) except: self.log('Failed to write memo %s'%_req.text) return _memo_dict def _process_sms(self, _resp, res): for i in range(0, len(_resp), 2): try: _entry=self.protocolclass.sms_msg_list_header() _buf=prototypes.buffer(_resp[i]) _entry.readfrombuffer(_buf) _sms=sms.SMSEntry() if _entry.msg_type==self.protocolclass.SMS_MSG_REC_UNREAD or \ _entry.msg_type==self.protocolclass.SMS_MSG_REC_READ: _sms._from=_entry.address _sms.folder=sms.SMSEntry.Folder_Inbox _sms.read=_entry.msg_type==self.protocolclass.SMS_MSG_REC_READ elif _entry.msg_type==self.protocolclass.SMS_MSG_STO_SENT: _sms.add_recipient(_entry.address) _sms.folder=sms.SMSEntry.Folder_Sent elif _entry.msg_type==self.protocolclass.SMS_MSG_STO_UNSENT: _sms.folder=sms.SMSEntry.Folder_Saved _sms.add_recipient(_entry.address) else: self.log('Unknown message type: %s'%_entry.msg_type) _sms=None if _sms: if _entry.timestamp: _sms.datetime=_entry.timestamp _sms.text=_resp[i+1] res[_sms.id]=_sms except: if __debug__: raise return res def getsms(self, result): self.log('Getting SMS Messages') self.setmode(self.MODEMODEM) self.charset_ascii() res={} _req=self.protocolclass.sms_format_req() self.sendATcommand(_req, None) self.log('Getting SMS messages from the phone memory') _sms_mem=self.protocolclass.sms_memory_select_req() _sms_mem.list_memory=self.protocolclass.SMS_MEMORY_PHONE self.sendATcommand(_sms_mem, None) _list_sms=self.protocolclass.sms_msg_list_req() _resp=self.sendATcommand(_list_sms, None) self._process_sms(_resp, res) self.log('Getting SMS message from the SIM card') _sms_mem.list_memory=self.protocolclass.SMS_MEMORY_SIM self.sendATcommand(_sms_mem, None) _resp=self.sendATcommand(_list_sms, None) self._process_sms(_resp, res) try: self.sendATcommand(_sms_mem, None) except commport.ATError: pass result['sms']=res return result def _get_history_calls(self, log_str, call_type, min_idx, max_idx): self.log(log_str) _sel_mem=self.protocolclass.select_storage_req() _sel_mem.storage=call_type self.sendATcommand(_sel_mem, None) _list_pb=self.protocolclass.read_phonebook_req() _list_pb.start_index=min_idx _list_pb.end_index=max_idx self.sendATcommand(_list_pb, None) def getcallhistory(self, result): self.log('Getting Call History') self.setmode(self.MODEMODEM) self.charset_ascii() res={} for l in self.protocolclass.PB_CALL_HISTORY_INFO: self._get_history_calls(*l) result['call_history']=res return result """ Talk to the LG G4015 Phone""" parent_profile=com_gsm.Profile class Profile (parent_profile) : serialsname=Phone.serialsname WALLPAPER_WIDTH=128 WALLPAPER_HEIGHT=128 MAX_WALLPAPER_BASENAME_LENGTH=19 WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_ ." WALLPAPER_CONVERT_FORMAT="jpg" MAX_RINGTONE_BASENAME_LENGTH=19 RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_ ." RINGTONE_LIMITS= { 'MAXSIZE': 20480 } phone_manufacturer='LGE' phone_model='G4015' usbids=( ( 0x10AB, 0x10C5, 1), ) deviceclasses=("serial",) imageorigins={} imageorigins.update(common.getkv(parent_profile.stockimageorigins, "images")) imagetargets={} imagetargets.update(common.getkv(parent_profile.stockimagetargets, "wallpaper", {'width': 128, 'height': 128, 'format': "JPEG"})) def GetImageOrigins(self): return self.imageorigins def GetTargetsForImageOrigin(self, origin): if origin=='images': return self.imagetargets def __init__(self): parent_profile.__init__(self) _supportedsyncs=( ('phonebook', 'read', None), ('phonebook', 'write', 'OVERWRITE'), ('calendar', 'read', None), ('calendar', 'write', 'OVERWRITE'), ('ringtone', 'read', None), ('ringtone', 'write', 'OVERWRITE'), ('wallpaper', 'read', None), ('wallpaper', 'write', 'OVERWRITE'), ('memo', 'read', None), ('memo', 'write', 'OVERWRITE'), ('sms', 'read', None), ('call_history', 'read', None), ) def convertphonebooktophone(self, helper, data): return data imageorigins.update(common.getkv(parent_profile.stockimageorigins, "images")) imagetargets.update(common.getkv(parent_profile.stockimagetargets, "wallpaper", {'width': 128, 'height': 128, 'format': "JPEG"}))
def GetImageConstructionInformation(self, file): """Gets information for constructing an Image from the file @return: (filename to use, function to call that returns wxImage) """ file=os.path.join(self.mainwindow.wallpaperpath, file) fi=self.GetFileInfo(file) if file.endswith(".mp4") or not os.path.isfile(file): return guihelper.getresourcefile('wallpaper.png'), wx.Image if fi: if fi.format=='AVI': return file, conversions.convertavitobmp if fi.format=='LGBIT': return file, conversions.convertfilelgbittobmp if fi.format=='3GPP2': return file, lambda name: None return file, wx.Image def GetFileInfo(self, filename): return fileinfo.identify_imagefile(filename) def GetImageStatInformation(self, file): """Returns the statinfo for file""" file=os.path.join(self.mainwindow.wallpaperpath, file) return statinfo(file) def updateindex(self, index): if index!=self._data['wallpaper-index']: self._data['wallpaper-index']=index.copy() self.modified=True def populate(self, dict): if self._data['wallpaper-index']!=dict['wallpaper-index']: self._data['wallpaper-index']=dict['wallpaper-index'].copy() self.modified=True self.OnRefresh() def OnPaste(self, evt=None): super(WallpaperView, self).OnPaste(evt) if not wx.TheClipboard.Open(): return if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_BITMAP)): do=wx.BitmapDataObject() success=wx.TheClipboard.GetData(do) else: success=False wx.TheClipboard.Close() if success: self.OnAddImage(wx.ImageFromBitmap(do.GetBitmap()), None) def CanPaste(self): """ Return True if can accept clipboard data, False otherwise """ if not wx.TheClipboard.Open(): return False r=wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_FILENAME)) or\ wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_BITMAP)) wx.TheClipboard.Close() return r def AddToIndex(self, file, origin): for i in self._data['wallpaper-index']: if self._data['wallpaper-index'][i]['name']==file: self._data['wallpaper-index'][i]['origin']=origin return keys=self._data['wallpaper-index'].keys() idx=10000 while idx in keys: idx+=1 self._data['wallpaper-index'][idx]={'name': file, 'origin': origin} self.modified=True def OnAddFiles(self, filenames): for file in filenames: if self._raw_image: decoded_file=self.decodefilename(file) targetfilename=self.getshortenedbasename(decoded_file) open(targetfilename, 'wb').write(open(file, 'rb').read()) self.AddToIndex(str(os.path.basename(targetfilename)).decode(fileview.media_codec), 'images') else: fi=self.GetFileInfo(file) if fi is not None and fi.format=='LGBIT': img=conversions.convertfilelgbittobmp(file) else: img=wx.Image(file) if not img.Ok(): dlg=wx.MessageDialog(self, "Failed to understand the image in '"+file+"'", "Image not understood", style=wx.OK|wx.ICON_ERROR) dlg.ShowModal() continue self.OnAddImage(img,file,refresh=False) self.OnRefresh() def OnAddImage(self, img, file, refresh=True): dlg=ImagePreviewDialog(self, img, file, self.mainwindow.phoneprofile) if dlg.ShowModal()!=wx.ID_OK: dlg.Destroy() return img=dlg.GetResultImage() imgparams=dlg.GetResultParams() origin=dlg.GetResultOrigin() extension={'BMP': 'bmp', 'JPEG': 'jpg', 'PNG': 'png'}[imgparams['format']] decoded_file=self.decodefilename(file) targetfilename=self.getshortenedbasename(decoded_file, extension) res=getattr(self, "saveimage_"+imgparams['format'])( img, targetfilename, imgparams) if not res: try: os.remove(targetfilename) except: pass dlg=wx.MessageDialog(self, "Failed to convert the image in '"+file+"'", "Image not converted", style=wx.OK|wx.ICON_ERROR) dlg.ShowModal() return self.AddToIndex(str(os.path.basename(targetfilename)).decode(fileview.media_codec), origin) if refresh: self.OnRefresh() def saveimage_BMP(self, img, targetfilename, imgparams): if img.ComputeHistogram(wx.ImageHistogram())<=236: img.SetOptionInt(wx.IMAGE_OPTION_BMP_FORMAT, wx.BMP_8BPP) return img.SaveFile(targetfilename, wx.BITMAP_TYPE_BMP) def saveimage_JPEG(self, img, targetfilename, imgparams): img.SetOptionInt("quality", 100) return img.SaveFile(targetfilename, wx.BITMAP_TYPE_JPEG) def saveimage_PNG(self, img, targetfilename, imgparams): return img.SaveFile(targetfilename, wx.BITMAP_TYPE_PNG) def populatefs(self, dict): self.thedir=self.mainwindow.wallpaperpath return self.genericpopulatefs(dict, 'wallpapers', 'wallpaper-index', self.CURRENTFILEVERSION) def getfromfs(self, result): self.thedir=self.mainwindow.wallpaperpath return self.genericgetfromfs(result, None, 'wallpaper-index', self.CURRENTFILEVERSION) def versionupgrade(self, dict, version): """Upgrade old data format read from disk @param dict: The dict that was read in @param version: version number of the data on disk """ if version==0: version=1 if version==1: print "converting to version 2" version=2 d={} input=dict.get('wallpaper-index', {}) for i in input: d[i]={'name': input[i]} dict['wallpaper-index']=d return dict def getdata(self,dict,want=fileview.FileView.NONE): return self.genericgetdata(dict, want, self.mainwindow.wallpaperpath, 'wallpapers', 'wallpaper-index') class WallpaperPreview (wx.PyWindow) : def __init__(self, parent, image=None, id=1, size=wx.DefaultSize, pos=wx.DefaultPosition, style=0): wx.PyWindow.__init__(self, parent, id=id, size=size, pos=pos, style=style|wx.FULL_REPAINT_ON_RESIZE) self.bg=wx.Brush(parent.GetBackgroundColour()) self._bufbmp=None wx.EVT_ERASE_BACKGROUND(self, lambda evt: None) wx.EVT_PAINT(self, self.OnPaint) self.SetImage(image) def SetImage(self, name): if name is None: self.theimage=None else: self.theimage, _=thewallpapermanager.GetImage(name) self.thesizedbitmap=None self.Refresh(False) def OnPaint(self, _): sz=self.GetClientSize() if self._bufbmp is None or sz.width>self._bufbmp.GetWidth() or sz.height>self._bufbmp.GetHeight(): self._bufbmp=wx.EmptyBitmap((sz.width+64)&~8, (sz.height+64)&~8) dc=wx.BufferedPaintDC(self, self._bufbmp, style=wx.BUFFER_VIRTUAL_AREA) dc.SetBackground(self.bg) dc.Clear() if self.theimage is None: return sfactorw=float(sz.width)/self.theimage.GetWidth() sfactorh=float(sz.height)/self.theimage.GetHeight() sfactor=min(sfactorw,sfactorh) newwidth=int(self.theimage.GetWidth()*sfactor) newheight=int(self.theimage.GetHeight()*sfactor) if self.thesizedbitmap is None or self.thesizedbitmap.GetWidth()!=newwidth or \ self.thesizedbitmap.GetHeight()!=newheight: self.thesizedbitmap=self.theimage.Scale(newwidth, newheight).ConvertToBitmap() dc.DrawBitmap(self.thesizedbitmap, sz.width/2-newwidth/2, sz.height/2-newheight/2, True) def ScaleImageIntoBitmap(img, usewidth, useheight, bgcolor=None, valign="center"): """Scales the image and returns a bitmap @param usewidth: the width of the new image @param useheight: the height of the new image @param bgcolor: the background colour as a string ("ff0000" is red etc). If this is none then the background is made transparent""" if bgcolor is None: bitmap=wx.EmptyBitmap(usewidth, useheight, 24) else: bitmap=wx.EmptyBitmap(usewidth, useheight) mdc=wx.MemoryDC() mdc.SelectObject(bitmap) sfactorw=usewidth*1.0/img.GetWidth() sfactorh=useheight*1.0/img.GetHeight() sfactor=min(sfactorw,sfactorh) newwidth=int(img.GetWidth()*sfactor/1.0) newheight=int(img.GetHeight()*sfactor/1.0) img.Rescale(newwidth, newheight) if bgcolor is not None: transparent=None assert len(bgcolor)==6 red=int(bgcolor[0:2],16) green=int(bgcolor[2:4],16) blue=int(bgcolor[4:6],16) mdc.SetBackground(wx.TheBrushList.FindOrCreateBrush(wx.Colour(red,green,blue), wx.SOLID)) else: transparent=wx.Colour(*(img.FindFirstUnusedColour()[1:])) mdc.SetBackground(wx.TheBrushList.FindOrCreateBrush(transparent, wx.SOLID)) mdc.Clear() mdc.SelectObject(bitmap) posx=usewidth-(usewidth+newwidth)/2 if valign in ("top", "clip"): posy=0 elif valign=="center": posy=useheight-(useheight+newheight)/2 else: assert False, "bad valign "+valign posy=0 mdc.DrawBitmap(img.ConvertToBitmap(), posx, posy, True) mdc.SelectObject(wx.NullBitmap) if transparent is not None: mask=wx.Mask(bitmap, transparent) bitmap.SetMask(mask) if valign=="clip" and newheight!=useheight: return bitmap.GetSubBitmap( (0,0,usewidth,newheight) ) return bitmap statinfo=common.statinfo class BPFSHandler (wx.FileSystemHandler) : CACHELOWWATER=80 CACHEHIGHWATER=100 def __init__(self, wallpapermanager): wx.FileSystemHandler.__init__(self) self.wpm=wallpapermanager self.cache={} def _GetCache(self, location, statinfo): """Return the cached item, or None Note that the location value includes the filename and the parameters such as width/height """ if statinfo is None: print "bad location",location return None return self.cache.get( (location, statinfo), None) def _AddCache(self, location, statinfo, value): "Add the item to the cache" if len(self.cache)>=self.CACHEHIGHWATER: print "BPFSHandler cache flush" while len(self.cache)>self.CACHELOWWATER: del self.cache[random.choice(self.cache.keys())] self.cache[(location, statinfo)]=value def CanOpen(self, location): if location.startswith("/"): return False proto=self.GetProtocol(location) if proto=="bpimage" or proto=="bpuserimage": return True return False def OpenFile(self,filesystem,location): try: res=self._OpenFile(filesystem,location) except: res=None print "Exception in getting image file - you can't do that!" print common.formatexception() if res is not None: res[0].seek(0) args=(wx.InputStream(res[0]),)+res[1:] res=wx.FSFile(*args) return res def _OpenFile(self, filesystem, location): proto=self.GetProtocol(location) r=self.GetRightLocation(location) params=r.split(';') r=params[0] params=params[1:] p={} for param in params: x=param.find('=') key=str(param[:x]) value=param[x+1:] if key=='width' or key=='height': p[key]=int(value) else: p[key]=value if proto=="bpimage": return self.OpenBPImageFile(location, r, **p) elif proto=="bpuserimage": return self.OpenBPUserImageFile(location, r, **p) return None def OpenBPUserImageFile(self, location, name, **kwargs): si=self.wpm.GetImageStatInformation(name) res=self._GetCache(location, si) if res is not None: return res file,cons=self.wpm.GetImageConstructionInformation(name) if cons == wx.Image: res=BPFSImageFile(self, location, file, **kwargs) else: res=BPFSImageFile(self, location, img=cons(file), **kwargs) self._AddCache(location, si, res) return res def OpenBPImageFile(self, location, name, **kwargs): f=guihelper.getresourcefile(name) if not os.path.isfile(f): print f,"doesn't exist" return None si=statinfo(f) res=self._GetCache(location, si) if res is not None: return res res=BPFSImageFile(self, location, name=f, **kwargs) self._AddCache(location, si, res) return res def BPFSImageFile(fshandler, location, name=None, img=None, width=-1, height=-1, valign="center", bgcolor=None): """Handles image files If we have to do any conversion on the file then we return PNG data. This used to be a class derived from wx.FSFile, but due to various wxPython bugs it instead returns the parameters to make a wx.FSFile since a new one has to be made every time. """ if img is None and width<0 and height<0: mime=guihelper.getwxmimetype(name) if mime not in (None, "image/x-bmp"): return (open(name, "rb"), location, mime, "", wx.DateTime_Now()) if img is None: img=wx.Image(name) if width>0 and height>0: b=ScaleImageIntoBitmap(img, width, height, bgcolor, valign) else: b=img.ConvertToBitmap() f=common.gettempfilename("png") if not b.SaveFile(f, wx.BITMAP_TYPE_PNG): raise Exception, "Saving to png failed" data=open(f, "rb").read() os.remove(f) return (cStringIO.StringIO(data), location, "image/png", "", wx.DateTime_Now()) class ImageCropSelect (wx.ScrolledWindow) : def __init__(self, parent, image, previewwindow=None, id=1, resultsize=(100,100), size=wx.DefaultSize, pos=wx.DefaultPosition, style=0): wx.ScrolledWindow.__init__(self, parent, id=id, size=size, pos=pos, style=style|wx.FULL_REPAINT_ON_RESIZE) self.previewwindow=previewwindow self.bg=wx.Brush(wx.WHITE) self.parentbg=wx.Brush(parent.GetBackgroundColour()) self._bufbmp=None self.anchors=None wx.EVT_ERASE_BACKGROUND(self, lambda evt: None) wx.EVT_PAINT(self, self.OnPaint) self.image=image self.origimage=image self.setresultsize(resultsize) self.cursors=[wx.StockCursor(c) for c in (wx.CURSOR_ARROW, wx.CURSOR_HAND, wx.CURSOR_SIZING, wx.CURSOR_NO_ENTRY)] self.clickpoint=None wx.EVT_MOTION(self, self.OnMotion) wx.EVT_LEFT_DOWN(self, self.OnLeftDown) wx.EVT_LEFT_UP(self, self.OnLeftUp) def SetPreviewWindow(self, previewwindow): self.previewwindow=previewwindow def OnPaint(self, _): sz=self.thebmp.GetWidth(), self.thebmp.GetHeight() sz2=self.GetClientSize() sz=max(sz[0],sz2[0])+32,max(sz[1],sz2[1])+32 if self._bufbmp is None or self._bufbmp.GetWidth()<sz[0] or self._bufbmp.GetHeight()<sz[1]: self._bufbmp=wx.EmptyBitmap((sz[0]+64)&~8, (sz[1]+64)&~8) dc=wx.BufferedPaintDC(self, self._bufbmp, style=wx.BUFFER_VIRTUAL_AREA) if sz2[0]<sz[0] or sz2[1]<sz[1]: dc.SetBackground(self.parentbg) dc.Clear() dc.DrawBitmap(self.thebmp, 0, 0, False) l,t,r,b=self.anchors points=(l,t), (r,t), (r,b), (l,b) dc.DrawLines( points+(points[0],) ) for x,y in points: dc.DrawRectangle(x-5, y-5, 10, 10) OUTSIDE=0 INSIDE=1 HANDLE_LT=2 HANDLE_RT=3 HANDLE_RB=4 HANDLE_LB=5 def _hittest(self, evt): l,t,r,b=self.anchors within=lambda x,y,l,t,r,b: l<=x<=r and t<=y<=b x,y=self.CalcUnscrolledPosition(evt.GetX(), evt.GetY()) for i,(ptx,pty) in enumerate(((l,t), (r,t), (r,b), (l,b))): if within(x,y,ptx-5, pty-5, ptx+5,pty+5): return self.HANDLE_LT+i if within(x,y,l,t,r,b): return self.INSIDE return self.OUTSIDE def OnMotion(self, evt): if evt.Dragging(): return self.OnMotionDragging(evt) self.UpdateCursor(evt) def UpdateCursor(self, evt): ht=self._hittest(evt) self.SetCursor(self.cursors[min(2,ht)]) def OnMotionDragging(self, evt): if not evt.LeftIsDown() or self.clickpoint is None: self.SetCursor(self.cursors[3]) return xx,yy=self.CalcUnscrolledPosition(evt.GetX(), evt.GetY()) deltax=xx-self.origevtpos[0] deltay=yy-self.origevtpos[1] if self.clickpoint==self.INSIDE: newanchors=self.origanchors[0]+deltax, self.origanchors[1]+deltay, \ self.origanchors[2]+deltax, self.origanchors[3]+deltay iw=self.dimensions[0] ih=self.dimensions[1] if newanchors[0]<0: newanchors=0,newanchors[1], self.origanchors[2]-self.origanchors[0], newanchors[3] if newanchors[1]<0: newanchors=newanchors[0], 0, newanchors[2], self.origanchors[3]-self.origanchors[1] if newanchors[2]>iw: newanchors=iw-(self.origanchors[2]-self.origanchors[0]),newanchors[1],iw, newanchors[3] if newanchors[3]>ih: newanchors=newanchors[0],ih-(self.origanchors[3]-self.origanchors[1]), newanchors[2],ih self.anchors=newanchors self.Refresh(False) self.updatepreview() return if self.clickpoint==self.HANDLE_LT: aa=0,1,-1,-1 elif self.clickpoint==self.HANDLE_RT: aa=2,1,+1,-1 elif self.clickpoint==self.HANDLE_RB: aa=2,3,+1,+1 elif self.clickpoint==self.HANDLE_LB: aa=0,3,-1,+1 else: assert False, "can't get here" na=[self.origanchors[0],self.origanchors[1],self.origanchors[2],self.origanchors[3]] na[aa[0]]=na[aa[0]]+deltax na[aa[1]]=na[aa[1]]+deltay neww=na[2]-na[0] newh=na[3]-na[1] ar=float(neww)/newh if ar<self.aspectratio: na[aa[0]]=na[aa[0]]+(self.aspectratio*newh-neww)*aa[2] elif ar>self.aspectratio: na[aa[1]]=na[aa[1]]+(neww/self.aspectratio-newh)*aa[3] if neww<10 or newh<10: return if na[0]<0: xdiff=-na[0] ydiff=xdiff/self.aspectratio na[0]=0 na[1]+=ydiff if na[1]<0: ydiff=-na[1] xdiff=ydiff*self.aspectratio na[1]=0 na[0]-=xdiff if na[2]>self.dimensions[0]: xdiff=na[2]-self.dimensions[0] ydiff=xdiff/self.aspectratio na[2]=na[2]-xdiff na[3]=na[3]-ydiff if na[3]>self.dimensions[1]: ydiff=na[3]-self.dimensions[1] xdiff=ydiff*self.aspectratio na[2]=na[2]-xdiff na[3]=na[3]-ydiff if na[0]<0 or na[1]<0 or na[2]>self.dimensions[0] or na[3]>self.dimensions[1]: print "offscreen fixup not written yet" return self.anchors=na self.Refresh(False) self.updatepreview() return def OnLeftDown(self, evt): ht=self._hittest(evt) if ht==self.OUTSIDE: self.SetCursor(self.cursors[3]) return self.clickpoint=ht xx,yy=self.CalcUnscrolledPosition(evt.GetX(), evt.GetY()) self.origevtpos=xx,yy self.origanchors=self.anchors def OnLeftUp(self, evt): self.clickpoint=None self.UpdateCursor(evt) def setlbcolour(self, colour): self.bg=wx.Brush(colour) self.remakebitmap() def SetZoom(self, factor): curzoom=float(self.image.GetWidth())/self.origimage.GetWidth() self.anchors=[a*factor/curzoom for a in self.anchors] self.image=self.origimage.Scale(self.origimage.GetWidth()*factor, self.origimage.GetHeight()*factor) self.setresultsize(self.resultsize) def setresultsize(self, (w,h)): self.resultsize=w,h self.aspectratio=ratio=float(w)/h imgratio=float(self.image.GetWidth())/self.image.GetHeight() neww=self.image.GetWidth() newh=self.image.GetHeight() if imgratio<ratio: neww*=ratio/imgratio elif imgratio>ratio: newh*=imgratio/ratio neww=max(neww, 50) newh=max(newh, 50) if self.anchors==None: self.anchors=0.1 * neww, 0.1 * newh, 0.9 * neww, 0.9 * newh l,t,r,b=self.anchors l=min(neww-40, l) r=min(neww-10, r) if r-l<20: r=40 t=min(newh-40, t) b=min(newh-10, b) if b-t<20: b=40 aratio=float(r-l)/(b-t) if aratio<ratio: b=t+(r-l)/ratio elif aratio>ratio: r=l+(b-t)*ratio self.anchors=l,t,r,b self.dimensions=neww,newh self.thebmp=wx.EmptyBitmap(neww, newh) self.remakebitmap() def remakebitmap(self): w,h=self.dimensions dc=wx.MemoryDC() dc.SelectObject(self.thebmp) dc.SetBackground(self.bg) dc.Clear() dc.DrawBitmap(self.image.ConvertToBitmap(), w/2-self.image.GetWidth()/2, h/2-self.image.GetHeight()/2, True) dc.SelectObject(wx.NullBitmap) self.imageofthebmp=None self.SetVirtualSize( (w, h) ) self.SetScrollRate(1,1) self.updatepreview() self.Refresh(False) def updatepreview(self): if self.previewwindow: self.previewwindow.SetUpdated(self.GetPreview) def GetPreview(self): w,h=self.resultsize l,t,r,b=self.anchors scale=max(float(w+0.99999)/(r-l), float(h+0.99999)/(b-t)) if True and scale<1: sub=wx.EmptyBitmap(w,h) mdcsub=wx.MemoryDC() mdcsub.SelectObject(sub) mdcsub.SetUserScale(scale, scale) mdc=wx.MemoryDC() mdc.SelectObject(self.thebmp) mdcsub.Blit(0,0,r-l,b-t,mdc,l,t) mdc.SelectObject(wx.NullBitmap) mdcsub.SelectObject(wx.NullBitmap) return sub sub=self.thebmp.GetSubBitmap( (l,t,(r-l),(b-t)) ) sub=sub.ConvertToImage() sub.Rescale(w,h) return sub.ConvertToBitmap() class ImagePreview (wx.PyWindow) : def __init__(self, parent): wx.PyWindow.__init__(self, parent) wx.EVT_ERASE_BACKGROUND(self, lambda evt: None) wx.EVT_PAINT(self, self.OnPaint) self.bmp=wx.EmptyBitmap(1,1) self.updater=None def SetUpdated(self, updater): self.updater=updater self.Refresh(True) def OnPaint(self, _): if self.updater is not None: self.bmp=self.updater() self.updater=None dc=wx.PaintDC(self) dc.DrawBitmap(self.bmp, 0, 0, False) class ImagePreviewDialog (wx.Dialog) : SCALES=[ (0.25, "1/4"), (0.5, "1/2"), (1, "1"), (2, "2"), (4, "4")] def __init__(self, parent, image, filename, phoneprofile): wx.Dialog.__init__(self, parent, -1, "Image Preview", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX) self.phoneprofile=phoneprofile self.filename=filename self.image=image vbsouter=wx.BoxSizer(wx.VERTICAL) hbs=wx.BoxSizer(wx.HORIZONTAL) self.cropselect=ImageCropSelect(self, image) vbs=wx.BoxSizer(wx.VERTICAL) self.colourselect=wx.lib.colourselect.ColourSelect(self, wx.NewId(), "Background ...", (255,255,255)) vbs.Add(self.colourselect, 0, wx.ALL|wx.EXPAND, 5) wx.lib.colourselect.EVT_COLOURSELECT(self, self.colourselect.GetId(), self.OnBackgroundColour) vbs.Add(wx.StaticText(self, -1, "Origin"), 0, wx.ALL, 5) self.originbox=wx.ListBox(self, size=(-1, 100)) vbs.Add(self.originbox, 0, wx.ALL|wx.EXPAND, 5) vbs.Add(wx.StaticText(self, -1, "Target"), 0, wx.ALL, 5) self.targetbox=wx.ListBox(self, size=(-1,100)) vbs.Add(self.targetbox, 0, wx.EXPAND|wx.ALL, 5) vbs.Add(wx.StaticText(self, -1, "Scale"), 0, wx.ALL, 5) for one,(s,_) in enumerate(self.SCALES): if s==1: break self.slider=wx.Slider(self, -1, one, 0, len(self.SCALES)-1, style=wx.HORIZONTAL|wx.SL_AUTOTICKS) wx.EVT_SCROLL(self, self.SetZoom) vbs.Add(self.slider, 0, wx.ALL|wx.EXPAND, 5) self.zoomlabel=wx.StaticText(self, -1, self.SCALES[one][1]) vbs.Add(self.zoomlabel, 0, wx.ALL|wx.ALIGN_CENTRE_HORIZONTAL, 5) vbs.Add(wx.StaticText(self, -1, "Preview"), 0, wx.ALL, 5) self.imagepreview=ImagePreview(self) self.cropselect.SetPreviewWindow(self.imagepreview) vbs.Add(self.imagepreview, 0, wx.ALL, 5) hbs.Add(vbs, 0, wx.ALL, 5) hbs.Add(self.cropselect, 1, wx.ALL|wx.EXPAND, 5) vbsouter.Add(hbs, 1, wx.EXPAND|wx.ALL, 5) vbsouter.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) vbsouter.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTRE|wx.ALL, 5) wx.EVT_LISTBOX(self, self.originbox.GetId(), self.OnOriginSelect) wx.EVT_LISTBOX_DCLICK(self, self.originbox.GetId(), self.OnOriginSelect) wx.EVT_LISTBOX(self, self.targetbox.GetId(), self.OnTargetSelect) wx.EVT_LISTBOX_DCLICK(self, self.targetbox.GetId(), self.OnTargetSelect) wx.EVT_BUTTON(self, wx.ID_HELP, lambda _: wx.GetApp().displayhelpid(helpids.ID_DLG_IMAGEPREVIEW)) self.originbox.Set(phoneprofile.GetImageOrigins().keys()) self.originbox.SetSelection(0) self.OnOriginSelect(None) self.SetSizer(vbsouter) vbsouter.Fit(self) import guiwidgets guiwidgets.set_size("wallpaperpreview", self, 80, 1.0) def ShowModal(self): res=wx.Dialog.ShowModal(self) import guiwidgets guiwidgets.save_size("wallpaperpreview", self.GetRect()) return res def SetZoom(self, evt): self.cropselect.SetZoom(self.SCALES[evt.GetPosition()][0]) self.zoomlabel.SetLabel(self.SCALES[evt.GetPosition()][1]) return def OnBackgroundColour(self, evt): self.cropselect.setlbcolour(evt.GetValue()) def OnOriginSelect(self, _): v=self.originbox.GetStringSelection() assert v is not None t=self.targetbox.GetStringSelection() self.targets=self.phoneprofile.GetTargetsForImageOrigin(v) keys=self.targets.keys() keys.sort() self.targetbox.Set(keys) if t in keys: self.targetbox.SetSelection(keys.index(t)) else: self.targetbox.SetSelection(0) self.OnTargetSelect(None) def OnTargetSelect(self, _): v=self.targetbox.GetStringSelection() print "target is",v w,h=self.targets[v]['width'],self.targets[v]['height'] self.imagepreview.SetSize( (w,h) ) self.cropselect.setresultsize( (w, h) ) sz=self.GetSizer() if sz is not None: sz.Layout() self.Refresh(True) def GetResultImage(self): return self.imagepreview.bmp.ConvertToImage() def GetResultParams(self): return self.targets[self.targetbox.GetStringSelection()] def GetResultOrigin(self): return self.originbox.GetStringSelection() if __name__=='__main__': if __debug__: def profile(filename, command): import hotshot, hotshot.stats, os file=os.path.abspath(filename) profile=hotshot.Profile(file) profile.run(command) profile.close() del profile howmany=100 stats=hotshot.stats.load(file) stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats(100) stats.sort_stats('cum', 'calls') stats.print_stats(100) stats.sort_stats('calls', 'time') stats.print_stats(100) sys.exit(0) class FakeProfile: def GetImageOrigins(self): return {"images": {'description': 'General images'}, "mms": {'description': 'Multimedia Messages'}, "camera": {'description': 'Camera images'}} def GetTargetsForImageOrigin(self, origin): return {"wallpaper": {'width': 100, 'height': 200, 'description': 'Display as wallpaper'}, "photoid": {'width': 100, 'height': 150, 'description': 'Display as photo id'}, "outsidelcd": {'width': 90, 'height': 80, 'description': 'Display on outside screen'}} def run(): app=wx.PySimpleApp() dlg=ImagePreviewDialog(None, wx.Image("test.jpg"), "foobar.png", FakeProfile()) dlg.ShowModal() if __debug__ and True: profile("wp.prof", "run()") run() import fileview if __name__=='__main__': if __debug__: def profile(filename, command): import hotshot, hotshot.stats, os file=os.path.abspath(filename) profile=hotshot.Profile(file) profile.run(command) profile.close() del profile howmany=100 stats=hotshot.stats.load(file) stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats(100) stats.sort_stats('cum', 'calls') stats.print_stats(100) stats.sort_stats('calls', 'time') stats.print_stats(100) sys.exit(0) class FakeProfile: def GetImageOrigins(self): return {"images": {'description': 'General images'}, "mms": {'description': 'Multimedia Messages'}, "camera": {'description': 'Camera images'}} def GetTargetsForImageOrigin(self, origin): return {"wallpaper": {'width': 100, 'height': 200, 'description': 'Display as wallpaper'}, "photoid": {'width': 100, 'height': 150, 'description': 'Display as photo id'}, "outsidelcd": {'width': 90, 'height': 80, 'description': 'Display on outside screen'}} def run(): app=wx.PySimpleApp() dlg=ImagePreviewDialog(None, wx.Image("test.jpg"), "foobar.png", FakeProfile()) dlg.ShowModal() if __debug__ and True: profile("wp.prof", "run()") run()
def windowsinit(self, iconfile): bitmap=wx.Bitmap(guihelper.getresourcefile(iconfile), wx.BITMAP_TYPE_PNG) icon=wx.EmptyIcon() icon.CopyFromBitmap(bitmap) self.SetIcon(icon, "BitFling") wx.EVT_TASKBAR_RIGHT_UP(self, self.OnRButtonUp) wx.EVT_TASKBAR_LEFT_UP(self, self.OnLButtonUp) wx.EVT_TASKBAR_LEFT_DOWN(self, self.OnLeftDown) def genericinit(self, iconfile): self.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) bitmap=wx.Bitmap(guihelper.getresourcefile(iconfile), wx.BITMAP_TYPE_PNG) bit=wx.StaticBitmap(self, -1, bitmap) self.Show(True) wx.EVT_RIGHT_UP(bit, self.OnRButtonUp) wx.EVT_LEFT_UP(bit, self.OnLButtonUp) wx.EVT_MOTION(bit, self.OnMouseMotion) wx.EVT_LEFT_DOWN(bit, self.OnLeftDown) self.bit=bit class ConfigPanel (wx.Panel, wx.lib.mixins.listctrl.ColumnSorterMixin) : def __init__(self, mw, parent, id=-1): wx.Panel.__init__(self, parent, id) self.mw=mw vbs=wx.BoxSizer(wx.VERTICAL) bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, "General"), wx.HORIZONTAL) bs.Add(wx.StaticText(self, -1, "Fingerprint"), 0, wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) self.fingerprint=wx.TextCtrl(self, -1, "a", style=wx.TE_READONLY, size=(300,-1)) bs.Add(self.fingerprint, 0, wx.EXPAND|wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) bs.Add(wx.StaticText(self, -1, ""), 0, wx.ALL, 5) bs.Add(wx.StaticText(self, -1, "Port"), 0, wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) self.porttext=wx.StaticText(self, -1, "<No Port>") bs.Add(self.porttext, 0, wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) vbs.Add(bs, 0, wx.EXPAND|wx.ALL, 5) bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, "Authorization"), wx.VERTICAL) hbs=wx.BoxSizer(wx.HORIZONTAL) butadd=wx.Button(self, wx.NewId(), "Add ...") hbs.Add(butadd, 0, wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) hbs.Add(wx.StaticText(self, -1, ""), 0, wx.ALL, 5) self.butedit=wx.Button(self, wx.NewId(), "Edit ...") self.butedit.Enable(False) hbs.Add(self.butedit, 0, wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) hbs.Add(wx.StaticText(self, -1, ""), 0, wx.ALL, 5) self.butdelete=wx.Button(self, wx.NewId(), "Delete") self.butdelete.Enable(False) hbs.Add(self.butdelete, 0, wx.ALL|wx.ALIGN_CENTRE_VERTICAL, 5) bs.Add(hbs, 0, wx.EXPAND|wx.ALL, 5) wx.EVT_BUTTON(self, butadd.GetId(), self.OnAddAuth) wx.EVT_BUTTON(self, self.butedit.GetId(), self.OnEditAuth) wx.EVT_BUTTON(self, self.butdelete.GetId(), self.OnDeleteAuth) self.authlist=wx.ListCtrl(self, wx.NewId(), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) self.authlist.InsertColumn(0, "User") self.authlist.InsertColumn(1, "Allowed Addresses") self.authlist.InsertColumn(2, "Expires") self.authlist.SetColumnWidth(0, 300) self.authlist.SetColumnWidth(1, 300) self.authlist.SetColumnWidth(2, 100) bs.Add(self.authlist, 1, wx.EXPAND|wx.ALL, 5) vbs.Add(bs, 1, wx.EXPAND|wx.ALL, 5) self.itemDataMap={} wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self,3) wx.EVT_LIST_ITEM_ACTIVATED(self.authlist, self.authlist.GetId(), self.OnEditAuth) wx.EVT_LIST_ITEM_SELECTED(self.authlist, self.authlist.GetId(), self.OnAuthListItemFondled) wx.EVT_LIST_ITEM_DESELECTED(self.authlist, self.authlist.GetId(), self.OnAuthListItemFondled) wx.EVT_LIST_ITEM_FOCUSED(self.authlist, self.authlist.GetId(), self.OnAuthListItemFondled) bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, "Devices"), wx.VERTICAL) buttoggle=wx.Button(self, wx.NewId(), "Toggle Allowed") bs.Add(buttoggle, 0, wx.ALL, 5) self.devicelist=wx.ListCtrl(self, wx.NewId(), style=wx.LC_REPORT|wx.LC_SINGLE_SEL) self.devicelist.InsertColumn(0, "Allowed") self.devicelist.InsertColumn(1, "Name") self.devicelist.InsertColumn(2, "Available") self.devicelist.InsertColumn(3, "Description") self.devicelist.SetColumnWidth(0, 100) self.devicelist.SetColumnWidth(1, 300) self.devicelist.SetColumnWidth(2, 100) self.devicelist.SetColumnWidth(3, 300) bs.Add(self.devicelist, 1, wx.EXPAND|wx.ALL, 5) vbs.Add(bs, 1, wx.EXPAND|wx.ALL, 5) self.setupauthorization() self.SortListItems() self.SetSizer(vbs) self.SetAutoLayout(True) def _updateauthitemmap(self, itemnum): pos=-1 if itemnum in self.itemDataMap: for i in range(self.authlist.GetItemCount()): if self.authlist.GetItemData(i)==itemnum: pos=i break assert pos!=-1 self.mw.icacache={} v=self.mw.authinfo[itemnum] username=v[0] expires=v[2] addresses=" ".join(v[3]) if pos<0: pos=self.authlist.GetItemCount() self.authlist.InsertStringItem(pos, username) else: self.authlist.SetStringItem(pos, 0, username) self.authlist.SetStringItem(pos, 2, `expires`) self.authlist.SetStringItem(pos, 1, addresses) self.authlist.SetItemData(pos, itemnum) self.itemDataMap[itemnum]=(username, addresses, expires) def GetListCtrl(self): "Used by the ColumnSorter mixin" return self.authlist def setupauthorization(self): dict={} items=[] for i in range(1000): if self.mw.config.HasEntry("user-"+`i`): username,password,expires,addresses=self.mw.config.Read("user-"+`i`).split(":") expires=int(expires) addresses=addresses.split() dict[i]=username,password,expires,addresses items.append(i) self.mw.authinfo=dict for i in items: self._updateauthitemmap(i) def OnAddAuth(self,_): dlg=AuthItemDialog(self, "Add Entry") if dlg.ShowModal()==wx.ID_OK: username,password,expires,addresses=dlg.GetValue() for i in range(1000): if i not in self.mw.authinfo: self.mw.config.Write("user-"+`i`, "%s:%s:%d:%s" % (username, password, expires, " ".join(addresses))) self.mw.config.Flush() self.mw.authinfo[i]=username,password,expires,addresses self._updateauthitemmap(i) self.SortListItems() break dlg.Destroy() def OnDeleteAuth(self, _): item=self._getselectedlistitem(self.authlist) key=self.authlist.GetItemData(item) del self.mw.authinfo[key] self.authlist.DeleteItem(item) self.mw.config.DeleteEntry("user-"+`key`) self.mw.config.Flush() def _getselectedlistitem(self, listctrl): "Finds the selected item in a listctrl since the wx methods don't actually work" i=-1 while True: nexti=listctrl.GetNextItem(i, state=wx.LIST_STATE_SELECTED) if nexti<0: break i=nexti return i return None def OnAuthListItemFondled(self, _): "Called whenever list items are selected, unselectected or similar fondling" selitem=self._getselectedlistitem(self.authlist) self.butedit.Enable(selitem is not None) self.butdelete.Enable(selitem is not None) def OnEditAuth(self, _): "Called to edit the currently selected entry" item=self._getselectedlistitem(self.authlist) key=self.authlist.GetItemData(item) username,password,expires,addresses=self.mw.authinfo[key] dlg=AuthItemDialog(self, "Edit Entry", username=username, password=password, expires=expires, addresses=addresses) if dlg.ShowModal()==wx.ID_OK: username,password,expires,addresses=dlg.GetValue() self.mw.authinfo[key]=username,password,expires,addresses self._updateauthitemmap(key) dlg.Destroy() class AuthItemDialog (wx.Dialog) : _password_sentinel="\x01\x02\x03\x04\x05\x06\x07\x08" def __init__(self, parent, title, username="******", password="", expires=0, addresses=[]): wx.Dialog.__init__(self, parent, -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) p=self gs=wx.FlexGridSizer(4, 2, 5, 5) gs.AddGrowableCol(1) gs.AddGrowableRow(3) gs.Add(wx.StaticText(p, -1, "Username/Email")) self.username=wx.TextCtrl(self, -1, username) gs.Add(self.username,0, wx.EXPAND) gs.Add(wx.StaticText(p, -1, "Password")) self.password=wx.TextCtrl(self, -1, "", style=wx.TE_PASSWORD) self.origpassword=password if len(password): self.password.SetValue(self._password_sentinel) gs.Add(self.password, 0, wx.EXPAND) gs.Add(wx.StaticText(p, -1, "Expires")) self.expires=wx.lib.masked.textctrl.TextCtrl(p, -1, "", autoformat="EUDATETIMEYYYYMMDD.HHMM") gs.Add(self.expires) gs.Add(wx.StaticText(p, -1, "Allowed Addresses")) self.addresses=wx.TextCtrl(self, -1, "\n".join(addresses), style=wx.TE_MULTILINE) gs.Add(self.addresses, 1, wx.EXPAND) vbs=wx.BoxSizer(wx.VERTICAL) vbs.Add(gs,1, wx.EXPAND|wx.ALL, 5) vbs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) vbs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTER|wx.ALL, 5) self.SetSizer(vbs) vbs.Fit(self) def GenPassword(self, string): salt="".join([chr(random.randint(0,127)) for x in range(8)]) saltstr="".join(["%02x" % (ord(x),) for x in salt]) val=sha.new(salt+string) return "$".join([saltstr, val.hexdigest()]) def GetValue(self): if self.password.GetValue()!=self._password_sentinel: password=self.GenPassword(self.password.GetValue()) else: password=self.origpassword return [self.username.GetValue(), password, 0, self.addresses.GetValue().split()] class MainWindow (wx.Frame) : def __init__(self, parent, id, title): self.taskwin=None wx.Frame.__init__(self, parent, id, title, style=wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.CAPTION) sys.excepthook=self.excepthook self.authinfo={} self.icacache={} cfgstr='bitfling' if guihelper.IsMSWindows(): cfgstr="BitFling" self.config=wx.Config(cfgstr, style=wx.CONFIG_USE_LOCAL_FILE) wx.GetApp().SetAppName(cfgstr) wx.GetApp().SetVendorName(cfgstr) self.setuphelp() wx.EVT_CLOSE(self, self.CloseRequested) panel=wx.Panel(self, -1) bs=wx.BoxSizer(wx.VERTICAL) self.nb=wx.Notebook(panel, -1) bs.Add(self.nb, 1, wx.EXPAND|wx.ALL, 5) bs.Add(wx.StaticLine(panel, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) gs=wx.GridSizer(1,4, 5, 5) for name in ("Rescan", "Hide", "Help", "Exit" ): but=wx.Button(panel, wx.NewId(), name) setattr(self, name.lower(), but) gs.Add(but) bs.Add(gs,0,wx.ALIGN_CENTRE|wx.ALL, 5) panel.SetSizer(bs) panel.SetAutoLayout(True) self.configpanel=ConfigPanel(self, self.nb) self.nb.AddPage(self.configpanel, "Configuration") self.lw=guihelper.LogWindow(self.nb) self.nb.AddPage(self.lw, "Log") wx.EVT_BUTTON(self, self.hide.GetId(), self.OnHideButton) wx.EVT_BUTTON(self, self.help.GetId(), self.OnHelpButton) wx.EVT_BUTTON(self, self.exit.GetId(), self.OnExitButton) EVT_XMLSERVER(self, self.OnXmlServerEvent) self.xmlrpcserver=None wx.CallAfter(self.StartIfICan) def setuphelp(self): """Does all the nonsense to get help working""" import wx.html from wxPython.htmlhelp import wxHtmlHelpController wx.FileSystem_AddHandler(wx.ZipFSHandler()) self.helpcontroller=wxHtmlHelpController() self.helpcontroller.AddBook(guihelper.getresourcefile("bitpim.htb")) self.helpcontroller.UseConfig(self.config, "help") def IsConnectionAllowed(self, peeraddr, username=None, password=None): """Verifies if a connection is allowed If username and password are supplied (as should be the case if calling this method before executing some code) then they are checked as being from a valid address as well. If username and password are not supplied then this method checks if any of the authentication rules allow a connection from the peeraddr. This form is used immediately after calling accept() on a socket, but before doing anything else.""" v=(peeraddr[0], username, password) if username is not None and password is None: self.Log("%s: No password supplied for user %s" % (peeraddr, `username`)) assert False, "No password supplied" return False print "ica of "+`v` val=self.icacache.get(v, None) if val is not None: allowed, expires = val if allowed: if self._has_expired(expires): msg="Connection from %s no longer allowed due to expiry" % (peeraddr[0],) if username is not None: msg+=". Username "+`username` self.Log(msg) return False return True return False ret_allowed=False ret_expiry=0 for uname, pwd, expires, addresses in self.authinfo.values(): if not self._does_address_match(peeraddr[0], addresses): continue if username is not None: if username!=uname: continue if not self._verify_password(password, pwd): self.Log("Wrong password supplied for user %s from %s" % (`username`, peeraddr[0])) continue ret_expiry=max(ret_expiry, expires) ret_allowed=True if not ret_allowed: if username is not None: self.Log("No valid credentials for user %s from %s" % (username, peeraddr[0])) else: self.Log("No defined users for address "+`peeraddr`) self.icacache[v]=ret_allowed, ret_expiry return self.IsConnectionAllowed(peeraddr, username, password) def _verify_password(self, password, pwd): """Returns True if password matches pwd @param password: password supplied by user @param pwd: password as we store it (salt $ hash)""" salt,hash=pwd.split("$", 1) x="" for i in range(0, len(salt), 2): x+=chr(int(salt[i:i+2], 16)) salt=x str=[] str.extend([ord(x) for x in salt]) str.extend([ord(x) for x in password]) val=sha.new("".join([chr(x) for x in str])) print password, pwd, val.hexdigest(), val.hexdigest()==hash return val.hexdigest()==hash def _does_address_match(self, peeraddr, addresses): """Returns if the peeraddr matches any of the supplied addresses""" for addr in addresses: if peeraddr==addr: return True if '*' in addr or '?' in addr or '[' in addr: if fnmatch.fnmatch(peeraddr, addr): return True ips=[] try: ips=socket.getaddrinfo(addr, None) except: pass for _, _, _, _, ip in ips: if peeraddr==ip[0]: return True return False def _has_expired(self, expires): if expires==0: return False if time.time()>expires: return True return False def CloseRequested(self, evt): if evt.CanVeto(): self.Show(False) evt.Veto() return self.taskwin.GoAway() evt.Skip() sys.excepthook=sys.__excepthook__ def OnXmlServerEvent(self, msg): if msg.cmd=="log": self.Log(msg.data) elif msg.cmd=="logexception": self.LogException(msg.data) else: assert False, "bad message "+`msg` pass def OnExitButton(self, _): self.Close(True) def OnHideButton(self, _): self.Show(False) def OnHelpButton(self, _): import helpids self.helpcontroller.Display(helpids.ID_BITFLING) def Log(self, text): if thread.get_ident()!=guithreadid: wx.PostEvent(self, XmlServerEvent(cmd="log", data=text)) else: self.lw.log(text) def LogException(self, exc): if thread.get_ident()!=guithreadid: wx.PostEvent(self, XmlServerEvent(cmd="log", data="Exception in thread "+threading.currentThread().getName())) wx.PostEvent(self, XmlServerEvent(cmd="logexception", data=exc)) else: self.lw.logexception(exc) def excepthook(self, *args): """Replacement exception handler that sends stuff to our log window""" self.LogException(args) def GetCertificateFilename(self): """Return certificate filename By default $HOME (or My Documents) / .bitfling.key but can be overridden with "certificatefile" config key""" if guihelper.IsMSWindows(): from win32com.shell import shell, shellcon path=shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0) path=os.path.join(path, ".bitfling.key") else: path=os.path.expanduser("~/.bitfling.key") return self.config.Read("certificatefile", path) def StartIfICan(self): certfile=self.GetCertificateFilename() if not os.path.isfile(certfile): wx.BeginBusyCursor(wx.StockCursor(wx.CURSOR_ARROWWAIT)) bi=wx.BusyInfo("Creating BitFling host certificate and keys") try: generate_certificate(certfile) if not os.path.isfile(certfile): certfile=None finally: del bi wx.EndBusyCursor() port=self.config.ReadInt("port", 12652) if port<1 or port>65535: port=None host=self.config.Read("bindaddress", "") if certfile is None or port is None: return self.Log("Starting on port "+`port`) key=paramiko.DSSKey.from_private_key_file(certfile) fp=paramiko.util.hexify(key.get_fingerprint()) self.configpanel.fingerprint.SetValue(fp) self.configpanel.porttext.SetLabel(`port`) self.configpanel.GetSizer().Layout() self.xmlrpcserver=BitFlingService(self, host, port, key) self.xmlrpcserver.setDaemon(True) self.xmlrpcserver.start() def generate_certificate(outfile): key=paramiko.DSSKey.generate() key.write_private_key_file(outfile, None) class XMLRPCService (xmlrpcstuff.Server) : def __init__(self, mainwin, host, port, servercert): self.mainwin=mainwin xmlrpcstuff.Server.__init__(self, host, port, servercert) def OnLog(self, msg): wx.PostEvent(self.mainwin, XmlServerEvent(cmd="log", data=msg)) def OnLogException(self, exc): wx.PostEvent(self.mainwin, XmlServerEvent(cmd="logexception", data=exc)) def OnNewAccept(self, clientaddr): return self.mainwin.IsConnectionAllowed(clientaddr) def OnNewUser(self, clientaddr, username, password): return self.mainwin.IsConnectionAllowed(clientaddr, username, password) def OnMethodDispatch(self, method, params, username, clientaddr): method="exp_"+method if not hasattr(self, method): raise Fault(3, "No such method") context={ 'username': username, 'clientaddr': clientaddr } return getattr(self, method)(*params, **{'context': context}) class BitFlingService (XMLRPCService) : def __init__(self, mainwin, host, port, servercert): XMLRPCService.__init__(self, mainwin, host, port, servercert) self.handles={} def stashhandle(self, context, comm): for i in range(10000): if i not in self.handles: self.handles[i]=[context, comm] return i def gethandle(self, context, num): return self.handles[num][1] def exp_scan(self, context): if usb is None: return comscan.comscan() else: return usbscan.usbscan()+comscan.comscan() def exp_getversion(self, context): return version.description def exp_deviceopen(self, port, baud, timeout, hardwareflow, softwareflow, context): return self.stashhandle(context, commport.CommConnection(None, port, baud, timeout, hardwareflow, softwareflow)) def exp_deviceclose(self, handle, context): comm=self.gethandle(context, handle) comm.close() del self.handles[handle] return True def exp_devicesetbaudrate(self, handle, rate, context): return self.gethandle(context, handle).setbaudrate(rate) def exp_devicesetdtr(self, handle, dtr, context): return self.gethandle(context, handle).setdtr(dtr) def exp_devicesetrts(self, handle, rts, context): return self.gethandle(context, handle).setrts(rts) def exp_devicewrite(self, handle, data, context): self.gethandle(context, handle).write(data.data) return len(data.data) def exp_devicesendatcommand(self, handle, atcommand, ignoreerror, context): "Special handling for empty lists and exceptions" try: res=self.gethandle(context, handle).sendatcommand(atcommand.data, ignoreerror=ignoreerror) if len(res)==0: res=1 except: res=0 return res def exp_devicereaduntil(self, handle, char, numfailures, context): return Binary(self.gethandle(context, handle).readuntil(char.data, numfailures=numfailures)) def exp_deviceread(self, handle, numchars, context): return Binary(self.gethandle(context, handle).read(numchars)) def exp_devicereadsome(self, handle, numchars, context): if numchars==-1: numchars=None return Binary(self.gethandle(context, handle).readsome(log=True,numchars=numchars)) def exp_devicewritethenreaduntil(self, handle, data, char, numfailures, context): return Binary(self.gethandle(context, handle).writethenreaduntil(data.data, False, char.data, False, False, numfailures)) def run(args): theApp=wx.PySimpleApp() menu=wx.Menu() menu.Append(ID_EXIT, "Exit") mw=MainWindow(None, -1, "BitFling") taskwin=MyTaskBarIcon(mw, menu) mw.taskwin=taskwin theApp.MainLoop() if __name__ == '__main__': run() try: import native.usb as usb except ImportError: usb=None if guihelper.IsMSWindows(): parentclass=wx.TaskBarIcon else: parentclass=wx.Frame if __name__ == '__main__': run()