示例#1
0
 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)
示例#2
0
 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()
示例#4
0
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(
                '<', '&lt;').replace('>', '&gt;')
            escaped = re.escape('&lt;%s&gt;' % attachment)
            escaped = escaped.replace(r'\ ', r'(?: |\&nbsp;)')
            escaped = escaped.replace(r'\:', '[:_]')
            matchnames.append(escaped)
        matches = "|".join(matchnames)
        html = re.sub(matches, '', html)
        htmlroot.setInnerHTML_(html)
示例#5
0
 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)
示例#6
0
 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)
示例#7
0
    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())
示例#8
0
    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())
示例#9
0
    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)
示例#10
0
    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)
示例#11
0
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('&', '&amp;').replace(
                '<', '&lt;').replace('>', '&gt;')
            escaped = re.escape('&lt;%s&gt;' % attachment)
            escaped = escaped.replace(r'\ ', r'(?: |\&nbsp;)')
            escaped = escaped.replace(r'\:', '[:_]')
            matchnames.append(escaped)
        matches = "|".join(matchnames)
        html = re.sub(matches, '', html)
        htmlroot.setInnerHTML_(html)
示例#12
0
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('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
            escaped     = re.escape('&lt;%s&gt;' % attachment)
            escaped     = escaped.replace(r'\ ', r'(?: |\&nbsp;)')
            escaped     = escaped.replace(r'\:', '[:_]')
            matchnames.append(escaped)
        matches = "|".join(matchnames)
        html    = re.sub(matches, '', html)
        htmlroot.setInnerHTML_(html)
示例#13
0
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('&', '&amp;').replace(
                '<', '&lt;').replace('>', '&gt;')
            escaped = re.escape('&lt;%s&gt;' % attachment)
            escaped = escaped.replace(r'\ ', r'(?: |\&nbsp;)')
            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
示例#15
0
    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
                )
示例#16
0
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)
示例#17
0
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
            )
示例#18
0
    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
示例#20
0
 def injectPreferencesModule(cls, prefs):
     titles = objc.getInstanceVariable(prefs, '_preferenceTitles')
     if 'QuoteFix' not in titles:
         prefs.addPreferenceNamed_owner_(
             "QuoteFix", QuoteFixPreferencesModule.sharedInstance())
示例#21
0
 def injectPreferencesModule(cls, prefs):
     titles = objc.getInstanceVariable(prefs, '_preferenceTitles')
     if 'QuoteFix' not in titles:
         prefs.addPreferenceNamed_owner_("QuoteFix", QuoteFixPreferencesModule.sharedInstance())
示例#22
0
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)
示例#23
0
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)
示例#24
0
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)
示例#25
0
    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)