def injectPreferencesModule(cls, prefs): titles = objc.getInstanceVariable(prefs, '_preferenceTitles') if 'QuoteFix' not in titles: prefs.addPreferenceNamed_owner_("QuoteFix", QuoteFixPreferencesModule.sharedInstance()) toolbar = objc.getInstanceVariable(prefs, '_preferencesPanel').toolbar() numitems = len( toolbar.items() ) toolbar.insertItemWithItemIdentifier_atIndex_("QuoteFix", numitems)
def injectPreferencesModule(cls, prefs): titles = objc.getInstanceVariable(prefs, '_preferenceTitles') if 'MailTrack' not in titles: prefs.addPreferenceNamed_owner_("MailTrack", MailTrackPreferencesModule.sharedInstance()) toolbar = objc.getInstanceVariable(prefs, '_preferencesPanel').toolbar() numitems = len( toolbar.items() ) toolbar.insertItemWithItemIdentifier_atIndex_("MailTrack", numitems)
def recipientsDidChange(self, original, sender): NSLog('[AFP] recipientsDidChange') original(self, sender) try: objc.getInstanceVariable(self, '_documentEditor').checkRecipients() except: objc.getInstanceVariable(self, 'documentEditor').checkRecipients()
def remove_attachment_placeholders(self, backend, htmlroot): messages = objc.getInstanceVariable(backend, '_originalMessages') if not messages: NSLog('unable to retrieve _originalMessages') return for original in messages: try: # ElCap and older messagebody = original.messageBody() attachments = messagebody.attachmentFilenames() except: # Sierra message = original.parsedMessage() attachments = [ v.filename() for k, v in message.attachmentsByURL().iteritems() ] NSLog('attachments: %@', attachments) if not attachments: return html = htmlroot.innerHTML() matchnames = [] for attachment in attachments: attachment = attachment.replace('&', '&').replace( '<', '<').replace('>', '>') escaped = re.escape('<%s>' % attachment) escaped = escaped.replace(r'\ ', r'(?: |\ )') escaped = escaped.replace(r'\:', '[:_]') matchnames.append(escaped) matches = "|".join(matchnames) html = re.sub(matches, '', html) htmlroot.setInnerHTML_(html)
def updateAlert_finishedWithChoice_(self, alert, choice): if choice == SUInstallUpdateChoice: app.config.set(SUSkippedVersionPref, '') elif choice == SURemindMeLaterChoice: app.config.set(SUSkippedVersionPref, '') elif choice == SUSkipThisVersionChoice: suItem = objc.getInstanceVariable(self, 'updateItem') app.config.set(SUSkippedVersionPref, suItem.versionString()) # Do whatever it is the superclass has to do. SUUIBasedUpdateDriver.updateAlert_finishedWithChoice_(self, alert, choice)
def updateAlert_finishedWithChoice_(self, alert, choice): if choice == SUInstallUpdateChoice: app.config.set(SUSkippedVersionPref, '') elif choice == SURemindMeLaterChoice: app.config.set(SUSkippedVersionPref, '') elif choice == SUSkipThisVersionChoice: suItem = objc.getInstanceVariable(self, 'updateItem') app.config.set(SUSkippedVersionPref, suItem.versionString()) # Do whatever it is the superclass has to do. SUUIBasedUpdateDriver.updateAlert_finishedWithChoice_( self, alert, choice)
def updateAlert_finishedWithChoice_(self, alert, choice): alert.release() if choice == 0: # SUInstallUpdateChoice app.config.set(SUSkippedVersionPref, '') self.beginDownload() elif choice == 1: # SURemindMeLaterChoice objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True) app.config.set(SUSkippedVersionPref, '') self.scheduleCheckWithInterval_(30 * 60) elif choice == 2: # SUSkipThisVersionChoice objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True) suItem = objc.getInstanceVariable(updater, 'updateItem') app.config.set(SUSkippedVersionPref, suItem.fileVersion())
def updateAlert_finishedWithChoice_(self, alert, choice): global alerter # release our kept reference alerter = None if choice == 0: # SUInstallUpdateChoice app.config.set(SUSkippedVersionPref, '') self.beginDownload() elif choice == 1: # SURemindMeLaterChoice objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True) app.config.set(SUSkippedVersionPref, '') self.scheduleCheckWithInterval_(30 * 60) elif choice == 2: # SUSkipThisVersionChoice objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True) suItem = objc.getInstanceVariable(updater, 'updateItem') app.config.set(SUSkippedVersionPref, suItem.fileVersion())
def downloadDidFinish_(self, d): url = d.request().URL() temp_url = NSURL.alloc().initWithScheme_host_path_('https', url.host(), url.path()) appcast_url = objc.getInstanceVariable(self, 'appcastURL') temp_appcast_url = NSURL.alloc().initWithScheme_host_path_('https', appcast_url.host(), appcast_url.path()) request = NSURLRequest.requestWithURL_(temp_url) fake_d = DummyURLDownload.alloc().initWithRequest_(request) objc.setInstanceVariable(self, 'appcastURL', temp_appcast_url, objc.YES) # Back to your regular scheduled programming .. SUUIBasedUpdateDriver.downloadDidFinish_(self, fake_d) # Restoring values to what they were previously. objc.setInstanceVariable(self, 'appcastURL', appcast_url, objc.YES)
def downloadDidFinish_(self, d): url = d.request().URL() temp_url = NSURL.alloc().initWithScheme_host_path_( 'https', url.host(), url.path()) appcast_url = objc.getInstanceVariable(self, 'appcastURL') temp_appcast_url = NSURL.alloc().initWithScheme_host_path_( 'https', appcast_url.host(), appcast_url.path()) request = NSURLRequest.requestWithURL_(temp_url) fake_d = DummyURLDownload.alloc().initWithRequest_(request) objc.setInstanceVariable(self, 'appcastURL', temp_appcast_url, objc.YES) # Back to your regular scheduled programming .. SUUIBasedUpdateDriver.downloadDidFinish_(self, fake_d) # Restoring values to what they were previously. objc.setInstanceVariable(self, 'appcastURL', appcast_url, objc.YES)
def remove_attachment_placeholders(self, backend, htmlroot): messages = objc.getInstanceVariable(backend, '_originalMessages') if not messages: NSLog('unable to retrieve _originalMessages') return for original in messages: if original.respondsToSelector_('parsedMessage'): # Sierra message = original.parsedMessage() attachments = [ v.filename() for k, v in message.attachmentsByURL().iteritems() ] elif original.respondsToSelector_('messageBody'): messagebody = original.messageBody() if not messagebody: # High Sierra NSLog( 'unable to retrieve message body to remove attachment placeholders' ) continue else: # ElCap and older attachments = messagebody.attachmentFilenames() else: NSLog("unable to retrieve list of attachments") continue if not attachments: return html = htmlroot.innerHTML() matchnames = [] for attachment in attachments: attachment = attachment.replace('&', '&').replace( '<', '<').replace('>', '>') escaped = re.escape('<%s>' % attachment) escaped = escaped.replace(r'\ ', r'(?: |\ )') escaped = escaped.replace(r'\:', '[:_]') matchnames.append(escaped) matches = "|".join(matchnames) html = re.sub(matches, '', html) htmlroot.setInnerHTML_(html)
def remove_attachment_placeholders(self, backend, htmlroot): messages = objc.getInstanceVariable(backend, '_originalMessages') for original in messages: messagebody = original.messageBody() if not messagebody: return attachments = messagebody.attachmentFilenames() if not attachments: return html = htmlroot.innerHTML() matchnames = [] for attachment in attachments: attachment = attachment.replace('&', '&').replace('<', '<').replace('>', '>') escaped = re.escape('<%s>' % attachment) escaped = escaped.replace(r'\ ', r'(?: |\ )') escaped = escaped.replace(r'\:', '[:_]') matchnames.append(escaped) matches = "|".join(matchnames) html = re.sub(matches, '', html) htmlroot.setInnerHTML_(html)
def remove_attachment_placeholders(self, backend, htmlroot): messages = objc.getInstanceVariable(backend, '_originalMessages') for original in messages: messagebody = original.messageBody() if not messagebody: return attachments = messagebody.attachmentFilenames() if not attachments: return html = htmlroot.innerHTML() matchnames = [] for attachment in attachments: attachment = attachment.replace('&', '&').replace( '<', '<').replace('>', '>') escaped = re.escape('<%s>' % attachment) escaped = escaped.replace(r'\ ', r'(?: |\ )') escaped = escaped.replace(r'\:', '[:_]') matchnames.append(escaped) matches = "|".join(matchnames) html = re.sub(matches, '', html) htmlroot.setInnerHTML_(html)
controller = SUSoftwareUpdateController.alloc( ).initWithDelegate_localizedProductName_(ControllerDelegate, "SU Predicate") if controller.countOfCachedProductsMatchingPredicate_(predicate) == 0: raise Exception("No products found for %s" % sys.argv[1]) md = controller.metadataOfCachedProductsMatchingPredicate_(predicate) #print md # get matching product keys mdcache = SUMetadataCache.alloc().init() productkeys = mdcache.cachedProductKeysMatchingPredicate_(predicate) #print productkeys conn = objc.getInstanceVariable(controller, '_connection') serviceclient = conn.remoteObjectProxy() serviceclient.dumpServiceDebugInfo() controller.startUpdateInBackgroundWithPredicate_(predicate) startedInstall = False while True: # _runningUpdate is the only thing that ever changes. currentState is always zero. # unfortunately getting a struct from PyObjC always logs a warning runningUpdate = objc.getInstanceVariable(controller, '_runningUpdate') if not startedInstall and runningUpdate != None: startedInstall = True elif startedInstall and runningUpdate == None: break
def finishLoadingEditor(self, original): logger.debug('DocumentEditor finishLoadingEditor') # execute original finishLoadingEditor() original(self) try: # if toggle key is active, temporarily switch the active state is_active = self.app.toggle_key_active ^ self.app.is_active # check if we can proceed if not is_active: logger.debug("MailTrack is not active, so no MailTracking for you!") return # grab composeView instance (this is the WebView which contains the # message editor) and check for the right conditions try: view = objc.getInstanceVariable(self, 'composeWebView') except: # was renamed in Lion view = objc.getInstanceVariable(self, '_composeWebView') # grab some other variables we need to perform our business backend = self.backEnd() htmldom = view.mainFrame().DOMDocument() htmlroot = htmldom.documentElement() messageType = self.messageType() # XXX: hack alert! if message type is DRAFT, but we can determine this # is actually a Send Again action, adjust the message type. origmsg = backend.originalMessage() if origmsg and messageType == DRAFT: # get the message viewer for this message viewer = MessageViewer.existingViewerShowingMessage_(origmsg) if not viewer: # XXX: this happens with conversation view active, not sure if this is stable enough though messageType = SENDAGAIN elif viewer: # get the mailbox for the viewer mailboxes = viewer.selectedMailboxes() # get the Drafts mailbox draftmailbox = viewer.draftsMailbox() # check if they're the same; if not, it's a Send-Again if draftmailbox not in mailboxes: messageType = SENDAGAIN # send original HTML to menu for debugging self.app.html = htmlroot.innerHTML() if not self.app.is_mailtracking: logger.debug('mailtracking turned off in preferences, skipping that part') elif messageType not in self.app.message_types_to_track: logger.debug('message type "%s" not in %s, not tracking' % ( messageType, self.app.message_types_to_track )) else: # move cursor to end of document view.moveToEndOfDocument_(self) # perform some general cleanups logger.debug('calling cleanup_layout()') if self.cleanup_layout(htmlroot, backend): backend.setHasChanges_(False) # move cursor to end of document if self.app.move_cursor_to_top: view.moveToBeginningOfDocument_(self) # move to beginning of line logger.debug('calling view.moveToBeginningOfLine()') view.moveToBeginningOfLine_(self) # done logger.debug('MailTracking done') except Exception: logger.critical(traceback.format_exc()) if self.app.is_debugging: NSRunAlertPanel( 'MailTrack caught an exception', 'The MailTrack plug-in caught an exception:\n\n' + traceback.format_exc() + '\nPlease contact the developer quoting the contents of this alert.', None, None, None )
def handleNewUpdate(latest): """A new update has been found, the Sparkle framework will now take control and perform user interaction and automatic update on our behalf. Since the appcast has already been fetched and parsed by the crossplatform code, Sparkle is actually not used in *full* automatic mode so we have to short-circuit some of its code and manually call the parts we are interested in. This includes: - manually building a clean dictionary containing the RSS item corresponding to the latest version of the software and then creating an SUAppcastItem with this dictionary. - manually allocating and initializing a driver for the updater. The driver determines the policy for doing updates (e.g. auto updates, UI, etc). We use our own driver based on the SUUIBasedUpdateDriver, which has overrides for a couple of functions to bypass functionality which we don't implement yet, or if we have extra work that needs to be done (possibly by calling portable code). - manually setting ivar updateItem, host, appcastURL into the driver, which would normally be done by Sparkle internally. Set the driver to be an ivar of the updater object, which was created at startup. We ask the bridge to retain these for us, as they would be if they were done by Sparkle internally. A bit hackish but it is the only way to make the Sparkle guts happy since we are creating things manually. - manually creating and calling an SUUpdateAlert object (which we must retain to prevent it to be automatically released by the Python garbage collector and therefore cause bad crashes). - Set the delegate of the alerter to be the driver - which will handle callbacks in response to state changes in the alerter. """ if not _host_supported(latest): logging.warn("Update available but host system not supported.") return # If already running don't bother. global updater if updater.updateInProgress(): # Update currently in progress. return dictionary = dict() _transfer(latest, 'title', dictionary) _transfer(latest, 'pubdate', dictionary, 'pubDate') _transfer(latest, 'description', dictionary) _transfer(latest, 'releasenoteslink', dictionary, 'sparkle:releaseNotesLink') enclosure = latest['enclosures'][0] suEnclosure = dict() _transfer(enclosure, 'sparkle:dsaSignature', suEnclosure) _transfer(enclosure, 'sparkle:md5Sum', suEnclosure) _transfer(enclosure, 'sparkle:version', suEnclosure) _transfer(enclosure, 'sparkle:shortVersionString', suEnclosure) _transfer(enclosure, 'url', suEnclosure) dictionary['enclosure'] = suEnclosure suItem = SUAppcastItem.alloc().initWithDictionary_(dictionary) skipped_version = app.config.get(SUSkippedVersionPref) if suItem.versionString() == skipped_version: logging.debug("Skipping update by user request") else: host = objc.getInstanceVariable(updater, 'host') global alerter # keep a reference around final = app.config.get(prefs.APP_FINAL_RELEASE) pref = prefs.AUTOUPDATE_URL if final else prefs.AUTOUPDATE_BETA_URL appcast_url = NSURL.alloc().initWithString_(app.config.get(pref)) alerter = SUUpdateAlert.alloc().initWithAppcastItem_host_(suItem, host) driver = MiroUpdateDriver.alloc().initWithUpdater_(updater) objc.setInstanceVariable(driver, 'updateItem', suItem, True) objc.setInstanceVariable(driver, 'host', host, True) objc.setInstanceVariable(driver, 'appcastURL', appcast_url, True) objc.setInstanceVariable(updater, 'driver', driver, True) alerter.setDelegate_(driver) alerter.showWindow_(updater)
def fix(self): try: # if toggle key is active, temporarily switch the active state is_active = self.app.toggle_key_active ^ self.app.is_active # check if we can proceed if not is_active: logger.debug("QuoteFix is not active, so no QuoteFixing for you!") return # Grab some variables we need to perform our business view = self.composeWebView() # contains the message editor backend = self.backEnd() htmldom = view.mainFrame().DOMDocument() htmlroot = htmldom.documentElement() messageType = self.messageType() # XXX: hack alert! if message type is DRAFT, but we can determine this # is actually a Send Again action, adjust the message type. origmsg = backend.originalMessage() if origmsg and messageType == DRAFT and origmsg.type() == 0: messageType = SENDAGAIN # send original HTML to menu for debugging self.app.html = htmlroot.innerHTML() # provide custom attribution? attributor = None if self.app.use_custom_reply_attribution and messageType in [ REPLY, REPLY_ALL, REPLY_AS ]: logger.debug("calling customize_attribution() for reply{-all,-as}") attributor = CustomizedAttribution.customize_reply elif self.app.use_custom_sendagain_attribution and messageType in [ SENDAGAIN ]: logger.debug("calling customize_attribution() for Send Again") attributor = CustomizedAttribution.customize_sendagain elif self.app.use_custom_forwarding_attribution and messageType == FORWARD: logger.debug("calling customize_attribution() for forwarding") attributor = CustomizedAttribution.customize_forward if attributor: # play nice with Attachment Tamer try: message = backend.draftMessage() except: try: copy = backend.copyOfContentsForDraft_shouldBePlainText_isOkayToForceRichText_(True, False, True) except: # Yosemite copy = backend.copyOfContentsForDraft_shouldBePlainText_isOkayToForceRichText_isMailDropPlaceholderMessage_(True, False, True, False) message = backend._makeMessageWithContents_isDraft_shouldSign_shouldEncrypt_shouldSkipSignature_shouldBePlainText_( copy, True, False, False, False, False ) try: for original in objc.getInstanceVariable(backend, '_originalMessages'): attributor( app = self.app, editor = self, dom = htmldom, reply = message, inreplyto = original, ) backend.setHasChanges_(False) except: # ignore when not debugging if self.app.is_debugging: raise # should we be quotefixing? if not self.app.is_quotefixing: logger.debug('quotefixing turned off in preferences, skipping that part') elif messageType not in self.app.message_types_to_quotefix: logger.debug('message type "%s" not in %s, not quotefixing' % ( messageType, self.app.message_types_to_quotefix )) else: # remove attachment placeholders? if self.app.remove_attachment_placeholders: self.remove_attachment_placeholders(backend, htmlroot) # move cursor to end of document view.moveToEndOfDocument_(self) # remove quotes? if self.app.remove_quotes: logger.debug('calling remove_quotes()') self.remove_quotes(htmldom, self.app.remove_quotes_level) # make quotes selectable? if self.app.selectable_quotes: logger.debug('calling make_selectable_quotes()') self.make_selectable_quotes(view, htmldom) # remove signature from sender if not self.app.keep_sender_signature: logger.debug('calling remove_old_signature()') self.remove_old_signature(htmldom, view) # place cursor above own signature (if any) logger.debug('calling move_above_new_signature()') if self.move_above_new_signature(htmldom, view): # insert a paragraph break? if not self.app.no_whitespace_below_quote: view.insertParagraphSeparator_(self) else: view.insertNewline_(self) # perform some general cleanups logger.debug('calling cleanup_layout()') self.cleanup_layout(htmlroot, backend) # move cursor to top of document if self.app.move_cursor_to_top: view.moveToBeginningOfDocument_(self) # move to beginning of line logger.debug('calling view.moveToBeginningOfLine()') view.moveToBeginningOfLine_(self) # done logger.debug('QuoteFixing done') except Exception: logger.critical(traceback.format_exc()) if self.app.is_debugging: NSRunAlertPanel( 'QuoteFix caught an exception', 'The QuoteFix plug-in caught an exception:\n\n' + traceback.format_exc() + '\nPlease contact the developer quoting the contents of this alert.', None, None, None )
def finishLoadingEditor(self, original): logger.debug('DocumentEditor finishLoadingEditor') # execute original finishLoadingEditor() original(self) try: # if toggle key is active, temporarily switch the active state is_active = self.app.toggle_key_active ^ self.app.is_active # check if we can proceed if not is_active: logger.debug("QuoteFix is not active, so no QuoteFixing for you!") return # grab composeView instance (this is the WebView which contains the # message editor) and check for the right conditions try: view = objc.getInstanceVariable(self, 'composeWebView') except: # was renamed in Lion view = objc.getInstanceVariable(self, '_composeWebView') # grab some other variables we need to perform our business backend = self.backEnd() htmldom = view.mainFrame().DOMDocument() htmlroot = htmldom.documentElement() messageType = self.messageType() # XXX: hack alert! if message type is DRAFT, but we can determine this # is actually a Send Again action, adjust the message type. origmsg = backend.originalMessage() if origmsg and messageType == DRAFT: # get the message viewer for this message viewer = MessageViewer.existingViewerShowingMessage_(origmsg) if not viewer: # XXX: this happens with conversation view active, not sure if this is stable enough though messageType = SENDAGAIN elif viewer: # get the mailbox for the viewer mailboxes = viewer.selectedMailboxes() # get the Drafts mailbox draftmailbox = viewer.draftsMailbox() # check if they're the same; if not, it's a Send-Again if draftmailbox not in mailboxes: messageType = SENDAGAIN # send original HTML to menu for debugging self.app.html = htmlroot.innerHTML() # should we be quotefixing? if not self.app.is_quotefixing: logger.debug('quotefixing turned off in preferences, skipping that part') elif messageType not in self.app.message_types_to_quotefix: logger.debug('message type "%s" not in %s, not quotefixing' % ( messageType, self.app.message_types_to_quotefix )) else: # remove attachment placeholders? if self.app.remove_attachment_placeholders: self.remove_attachment_placeholders(backend, htmlroot) backend.setHasChanges_(False) # move cursor to end of document view.moveToEndOfDocument_(self) # remove quotes? if self.app.remove_quotes: logger.debug('calling remove_quotes()') self.remove_quotes(htmldom, self.app.remove_quotes_level) backend.setHasChanges_(False) # make quotes selectable? if self.app.selectable_quotes: logger.debug('calling make_selectable_quotes()') self.make_selectable_quotes(view, htmldom) backend.setHasChanges_(False) # remove signature from sender if not self.app.keep_sender_signature: logger.debug('calling remove_old_signature()') if self.remove_old_signature(htmldom, view): backend.setHasChanges_(False) # place cursor above own signature (if any) logger.debug('calling move_above_new_signature()') if self.move_above_new_signature(htmldom, view): backend.setHasChanges_(False) else: view.insertNewline_(self) # perform some general cleanups logger.debug('calling cleanup_layout()') if self.cleanup_layout(htmlroot, backend): backend.setHasChanges_(False) # move cursor to end of document if self.app.move_cursor_to_top: view.moveToBeginningOfDocument_(self) # provide custom attribution? attributor = None if self.app.use_custom_reply_attribution and messageType in [ REPLY, REPLY_ALL, REPLY_AS ]: logger.debug("calling customize_attribution() for reply{-all,-as}") attributor = CustomizedAttribution.customize_reply elif self.app.use_custom_sendagain_attribution and messageType in [ SENDAGAIN ]: logger.debug("calling customize_attribution() for Send Again") attributor = CustomizedAttribution.customize_sendagain elif self.app.use_custom_forwarding_attribution and messageType == FORWARD: logger.debug("calling customize_attribution() for forwarding") attributor = CustomizedAttribution.customize_forward if attributor: # play nice with Attachment Tamer try: message = backend.draftMessage() except: message = backend._makeMessageWithContents_isDraft_shouldSign_shouldEncrypt_shouldSkipSignature_shouldBePlainText_( backend.copyOfContentsForDraft_shouldBePlainText_isOkayToForceRichText_(True, False, True), True, False, False, False, False ) try: for original in objc.getInstanceVariable(backend, '_originalMessages'): attributor( app = self.app, editor = self, dom = htmldom, reply = message, inreplyto = original, ) backend.setHasChanges_(False) except: # ignore when not debugging if self.app.is_debugging: raise # move to beginning of line logger.debug('calling view.moveToBeginningOfLine()') view.moveToBeginningOfLine_(self) # done logger.debug('QuoteFixing done') except Exception: logger.critical(traceback.format_exc()) if self.app.is_debugging: NSRunAlertPanel( 'QuoteFix caught an exception', 'The QuoteFix plug-in caught an exception:\n\n' + traceback.format_exc() + '\nPlease contact the developer quoting the contents of this alert.', None, None, None )
return True return method controller = SUSoftwareUpdateController.alloc().initWithDelegate_localizedProductName_(ControllerDelegate, "SU Predicate") if controller.countOfCachedProductsMatchingPredicate_(predicate) == 0: raise Exception("No products found for %s" % sys.argv[1]) md = controller.metadataOfCachedProductsMatchingPredicate_(predicate) #print md # get matching product keys mdcache = SUMetadataCache.alloc().init() productkeys = mdcache.cachedProductKeysMatchingPredicate_(predicate) #print productkeys conn = objc.getInstanceVariable(controller, '_connection') serviceclient = conn.remoteObjectProxy() serviceclient.dumpServiceDebugInfo() controller.startUpdateInBackgroundWithPredicate_(predicate) startedInstall = False while True: # _runningUpdate is the only thing that ever changes. currentState is always zero. # unfortunately getting a struct from PyObjC always logs a warning runningUpdate = objc.getInstanceVariable(controller, '_runningUpdate') if not startedInstall and runningUpdate != None: startedInstall = True elif startedInstall and runningUpdate == None: break
def injectPreferencesModule(cls, prefs): titles = objc.getInstanceVariable(prefs, '_preferenceTitles') if 'QuoteFix' not in titles: prefs.addPreferenceNamed_owner_( "QuoteFix", QuoteFixPreferencesModule.sharedInstance())
def injectPreferencesModule(cls, prefs): titles = objc.getInstanceVariable(prefs, '_preferenceTitles') if 'QuoteFix' not in titles: prefs.addPreferenceNamed_owner_("QuoteFix", QuoteFixPreferencesModule.sharedInstance())
def isLoaded(self, original): global isQuoteFixed # call superclass method first isloaded = original(self) if not isloaded or not App.isActive(): return isloaded # check if this message was already quotefixed if self in isQuoteFixed: return isloaded try: # check for the right kind of message: # messagetype == 1 -> reply (will be fixed) # messagetype == 2 -> reply to all (will be fixed) # messagetype == 3 -> forward (will be fixed) # messagetype == 4 -> is draft (won't be fixed) # messagetype == 5 -> new message (won't be fixed) if self.messageType() not in [1, 2, 3]: return isloaded # grab composeView instance (this is the WebView which contains the # message editor) and check for the right conditions composeView = objc.getInstanceVariable(self, 'composeWebView') if not composeView or composeView.isLoading() or not composeView.isEditable(): return isloaded # move cursor to end of document and signal that this view was # 'fixed', since this method gets called repeatedly (can't use # a new instance variable for this since the Obj-C backend doesn't # appreciate that) composeView.moveToEndOfDocument_(self) isQuoteFixed[self] = True # perform some more modifications backend = self.backEnd() message = backend.message() is_rich = backend.containsRichText() frame = composeView.mainFrame() dom = frame.DOMDocument() root = dom.documentElement() # send original HTML to menu for debugging App.setHTML(root.innerHTML()) # start cleaning up if removeOldSignature(self, root, composeView): # if we changed anything, reset the 'changed' state of the # compose backend self.backEnd().setHasChanges_(False) # place cursor above own signature (if any) if moveAboveNewSignature(self, dom, composeView): self.backEnd().setHasChanges_(False) else: composeView.insertNewline_(self) # perform some general cleanups if cleanupLayout(self, dom, root): self.backEnd().setHasChanges_(False) # move to beginning of line composeView.moveToBeginningOfLine_(self) except Exception, e: if App.isDebugging(): QFAlert.showException(self)
def fix(self): try: # if toggle key is active, temporarily switch the active state is_active = self.app.toggle_key_active ^ self.app.is_active # check if we can proceed if not is_active: logger.debug("QuoteFix is not active, so no QuoteFixing for you!") return # Grab some variables we need to perform our business view = self.composeWebView() # contains the message editor backend = self.backEnd() htmldom = view.mainFrame().DOMDocument() htmlroot = htmldom.documentElement() messageType = self.messageType() # XXX: hack alert! if message type is DRAFT, but we can determine this # is actually a Send Again action, adjust the message type. origmsg = backend.originalMessage() if origmsg and messageType == DRAFT and origmsg.type() == 0: messageType = SENDAGAIN # send original HTML to menu for debugging self.app.html = htmlroot.innerHTML() # provide custom attribution? attributor = None if self.app.use_custom_reply_attribution and messageType in [ REPLY, REPLY_ALL, REPLY_AS ]: logger.debug("calling customize_attribution() for reply{-all,-as}") attributor = CustomizedAttribution.customize_reply elif self.app.use_custom_sendagain_attribution and messageType in [ SENDAGAIN ]: logger.debug("calling customize_attribution() for Send Again") attributor = CustomizedAttribution.customize_sendagain elif self.app.use_custom_forwarding_attribution and messageType == FORWARD: logger.debug("calling customize_attribution() for forwarding") attributor = CustomizedAttribution.customize_forward if attributor: try: for original in objc.getInstanceVariable( backend, '_originalMessages'): attributor( app=self.app, editor=self, dom=htmldom, reply=backend.message(), inreplyto=original, ) backend.setHasChanges_(False) except: # ignore when not debugging if self.app.is_debugging: raise # should we be quotefixing? if not self.app.is_quotefixing: logger.debug( 'quotefixing turned off in preferences, skipping that part') elif messageType not in self.app.message_types_to_quotefix: logger.debug('message type "%s" not in %s, not quotefixing' % (messageType, self.app.message_types_to_quotefix)) else: # remove attachment placeholders? if self.app.remove_attachment_placeholders: logger.debug('calling remove_attachment_placeholders()') self.remove_attachment_placeholders(backend, htmlroot) # move cursor to end of document view.moveToEndOfDocument_(self) # remove quotes? if self.app.remove_quotes: logger.debug('calling remove_quotes()') self.remove_quotes(htmldom, self.app.remove_quotes_level) # make quotes selectable? if self.app.selectable_quotes: logger.debug('calling make_selectable_quotes()') self.make_selectable_quotes(view, htmldom) # remove signature from sender if not self.app.keep_sender_signature: logger.debug('calling remove_old_signature()') self.remove_old_signature(htmldom, view) # place cursor above own signature (if any) logger.debug('calling move_above_new_signature()') if self.move_above_new_signature(htmldom, view): # insert a paragraph break? if not self.app.no_whitespace_below_quote: view.insertParagraphSeparator_(self) else: view.insertNewline_(self) # perform some general cleanups logger.debug('calling cleanup_layout()') self.cleanup_layout(htmlroot, backend) # move cursor to top of document if self.app.move_cursor_to_top: view.moveToBeginningOfDocument_(self) # move to beginning of line logger.debug('calling view.moveToBeginningOfLine()') view.moveToBeginningOfLine_(self) # done logger.debug('QuoteFixing done') except Exception: logger.critical(traceback.format_exc()) if self.app.is_debugging: NSRunAlertPanel( 'QuoteFix caught an exception', 'The QuoteFix plug-in caught an exception:\n\n' + traceback.format_exc() + '\nPlease contact the developer quoting the contents of this alert.', None, None, None)
def finishLoadingEditor(self, original): logger.debug('DocumentEditor finishLoadingEditor') # execute original finishLoadingEditor() original(self) try: # if toggle key is active, temporarily switch the active state is_active = self.app.toggle_key_active ^ self.app.is_active # check if we can proceed if not is_active: logger.debug( "MailTrack is not active, so no MailTracking for you!") return # grab composeView instance (this is the WebView which contains the # message editor) and check for the right conditions try: view = objc.getInstanceVariable(self, 'composeWebView') except: # was renamed in Lion view = objc.getInstanceVariable(self, '_composeWebView') # grab some other variables we need to perform our business backend = self.backEnd() htmldom = view.mainFrame().DOMDocument() htmlroot = htmldom.documentElement() messageType = self.messageType() # XXX: hack alert! if message type is DRAFT, but we can determine this # is actually a Send Again action, adjust the message type. origmsg = backend.originalMessage() if origmsg and messageType == DRAFT: # get the message viewer for this message viewer = MessageViewer.existingViewerShowingMessage_(origmsg) if not viewer: # XXX: this happens with conversation view active, not sure if this is stable enough though messageType = SENDAGAIN elif viewer: # get the mailbox for the viewer mailboxes = viewer.selectedMailboxes() # get the Drafts mailbox draftmailbox = viewer.draftsMailbox() # check if they're the same; if not, it's a Send-Again if draftmailbox not in mailboxes: messageType = SENDAGAIN # send original HTML to menu for debugging self.app.html = htmlroot.innerHTML() if not self.app.is_mailtracking: logger.debug( 'mailtracking turned off in preferences, skipping that part' ) elif messageType not in self.app.message_types_to_track: logger.debug('message type "%s" not in %s, not tracking' % (messageType, self.app.message_types_to_track)) else: # move cursor to end of document view.moveToEndOfDocument_(self) # perform some general cleanups logger.debug('calling cleanup_layout()') if self.cleanup_layout(htmlroot, backend): backend.setHasChanges_(False) # move cursor to end of document if self.app.move_cursor_to_top: view.moveToBeginningOfDocument_(self) # move to beginning of line logger.debug('calling view.moveToBeginningOfLine()') view.moveToBeginningOfLine_(self) # done logger.debug('MailTracking done') except Exception: logger.critical(traceback.format_exc()) if self.app.is_debugging: NSRunAlertPanel( 'MailTrack caught an exception', 'The MailTrack plug-in caught an exception:\n\n' + traceback.format_exc() + '\nPlease contact the developer quoting the contents of this alert.', None, None, None)