def PrepareTestData(self):

        view = self.views[0]

        self.coll = pim.ListCollection("testCollection",
                                       itsView=view,
                                       displayName="Test Collection")

        pacific = view.tzinfo.getInstance('America/Los_Angeles')
        floating = view.tzinfo.floating

        titles = [(u"breakfast", datetime(2007, 3, 1, 10, 30, 0, 0, floating)),
                  (u"dinner", datetime(2007, 3, 1, 18, 30, 0, 0, pacific))]

        self.icalUIDs = {}

        createdOn = datetime(2007, 3, 1, 10, 0, 0, 0, floating)
        for title, dt in titles:
            event = pim.CalendarEvent(itsView=view)
            n = event.itsItem
            n.createdOn = createdOn
            n.displayName = title
            self.icalUIDs[n.itsUUID] = n.displayName
            n.body = u"Here is the body"
            event.startTime = dt
            event.duration = timedelta(hours=1)
            event.anyTime = False
            self.coll.add(n)
Ejemplo n.º 2
0
    def testModifiable(self):

        view = self.view

        # Our test subject
        e1 = pim.CalendarEvent(itsView=view).itsItem

        # We need a currentContact set for isAttributeModifiable to work;
        # normally this is set by the app
        me = pim.Contact(
            itsView=view,
            references=[schema.ns('osaf.pim', view).currentContact])

        # Add the subject to a read-only share:

        share_ro = sharing.Share(itsView=view)
        share_ro.mode = 'get'

        share_ro.addSharedItem(e1)

        # Test modifiability against...

        # ...an attribute which is always shared
        self.assert_(not e1.isAttributeModifiable('displayName'))

        # ...an attribute that is sometimes shared (based on filterAttributes)
        self.assert_(
            not e1.isAttributeModifiable(pim.Remindable.reminders.name))

        ## disabling functionality (and thus tests) for 1.0, bug 9448
        ### ...an attribute which is pretty much never shared
        ##self.assert_(e1.isAttributeModifiable('read'))

        ### Filter out reminderTime, and it should become modifiable:
        ##share_ro.filterAttributes = [pim.Remindable.reminders.name]
        ##self.assert_(e1.isAttributeModifiable(pim.Remindable.reminders.name))

        # Now also add the subject to a read-write share:

        share_rw = sharing.Share(itsView=view)
        share_rw.mode = 'both'

        share_rw.addSharedItem(e1)

        # Test modifiability against...

        ## changed tests to all use not for 1.0, bug 9448
        # ...an attribute which is always shared
        self.assert_(not e1.isAttributeModifiable('displayName'))

        # ...an attribute that is sometimes shared (based on filterAttributes)
        self.assert_(
            not e1.isAttributeModifiable(pim.Remindable.reminders.name))

        # ...an attribute which is pretty much never shared
        self.assert_(not e1.isAttributeModifiable('read'))
Ejemplo n.º 3
0
    def prepareTestData(self):

        # Make sure these are initialized, otherwise they won't be tracking
        # icalUIDs
        schema.ns('osaf.sharing', self.views[0]).uid_map
        schema.ns('osaf.sharing', self.views[1]).uid_map

        view = self.views[0]
        # create a sandbox root
        Item("sandbox", view, None)

        sandbox = view.findPath("//sandbox")
        coll = pim.ListCollection("testCollection",
                                  sandbox,
                                  displayName="Test Collection")

        names = [
            (u"Morgen", u"Sagen", u"*****@*****.**"),
            (u"Ted", u"Leung", u"*****@*****.**"),
            (u"Andi", u"Vajda", u"*****@*****.**"),
        ]

        contacts = []

        for name in names:
            c = pim.Contact(None, sandbox)
            c.contactName = pim.ContactName(None, sandbox)
            c.contactName.firstName = name[0]
            c.contactName.lastName = name[1]
            c.emailAddress = name[2]
            c.displayName = u"%s %s" % (name[0], name[1])
            contacts.append(c)

        events = [
            u"breakfast",
            u"lunch",
            u"dinner",
            u"meeting",
            u"movie",
            u'\u8fd1\u85e4\u6df3\u4e5f\u306e\u65b0\u30cd\u30c3\u30c8\u30b3\u30df\u30e5\u30cb\u30c6\u30a3\u8ad6',
        ]

        self.uuids = {}

        tzinfo = sandbox.itsView.tzinfo.default
        for i in xrange(6):
            c = pim.CalendarEvent(None, sandbox)
            c.summary = events[i % 6]
            c.organizer = contacts[0]
            c.participants = [contacts[1], contacts[2]]
            c.startTime = datetime.datetime(2005, 10, 31, 12, 0, 0, 0, tzinfo)
            c.duration = datetime.timedelta(minutes=60)
            c.anyTime = False
            self.uuids[c.itsItem.itsUUID] = c.summary
            coll.add(c.itsItem)
Ejemplo n.º 4
0
def installParcel(parcel, oldVersion=None):

    pim_ns = schema.ns('osaf.pim', parcel)
    sharing_ns = schema.ns('osaf.sharing', parcel)

    ClientIdentifier.update(parcel, 'clientID')

    ApplicationPrefs.update(parcel, 'prefs')

    AutoRestorePrefs.update(parcel, "autoRestorePrefs")

    message = _(u'User')

    me = pim.Contact.update(
        parcel,
        'me',
        # L10N: The word 'Me' is used to represent the
        #       current Chandler user.
        displayName=_(u'Me'),
        contactName=pim.ContactName.update(
            parcel,
            'meName',
            firstName=u'Chandler',
            #XXX Since the notion of 'me' may be going away
            #    there is no current need to refactor the
            #    last name attribute to the LocalizableString type.
            #    Thus for now will convert the c{Message} object
            #    returned from the c{ChandlerMessageFactory}
            #    to Unicode. This decision will be revisited later.
            lastName=unicode(message),
        ),
        references=[pim_ns.currentContact])

    # The Sidebar collection
    sidebarListCollection = pim.ListCollection.update(
        parcel,
        'sidebarCollection',
        inclusions=[
            pim_ns.allCollection, pim_ns.inCollection, pim_ns.outCollection,
            pim_ns.trashCollection
        ])

    testReply = pim.mail.EmailAddress.update(parcel, 'TestReplyAddress')

    # [i18n] Test Accounts are not displayed to the user and
    # do not require localization
    testSmtp = pim.mail.SMTPAccount.update(parcel,
                                           'TestSMTPAccount',
                                           displayName=u'Test SMTP Account',
                                           password=password.Password.update(
                                               parcel,
                                               'TestSMTPAccountPassword'),
                                           isActive=False)

    pim.mail.IMAPAccount.update(parcel,
                                'TestIMAPAccount',
                                displayName=u'Test IMAP mail',
                                replyToAddress=testReply,
                                password=password.Password.update(
                                    parcel, 'TestIMAPAccountPassword'),
                                isActive=False)

    pim.mail.POPAccount.update(parcel,
                               'TestPOPAccount',
                               displayName=u'Test POP mail',
                               replyToAddress=testReply,
                               defaultSMTPAccount=testSmtp,
                               password=password.Password.update(
                                   parcel, 'TestPOPAccountPassword'),
                               isActive=False)

    osafDev = pim.Contact.update(parcel,
                                 'OSAFContact',
                                 emailAddress=u'*****@*****.**',
                                 contactName=pim.ContactName.update(
                                     parcel,
                                     'OSAFContactName',
                                     firstName=u'OSAF',
                                     lastName=u'Development'))

    # OOTB collections and items (bugs 6545, 11772)
    # http://chandlerproject.org/bin/view/Journal/PreviewOOTBChandlerExperience
    #
    # (1) Don't create these in //parcels, or they won't get dumped
    # (2) Don't create these if reloading, or else there will be endless
    #     duplication of items/events
    # (3) We do want new UUIDs, so different users can share these
    #     collections/items to the same morsecode server
    # (4) The Welcome Event should be created regardless of whether
    #     we're reloading, because summaryblocks references it.
    #     (Maybe there's a better way to have it selected in the
    #      detail view?) -- Grant
    # (5) We create

    triageWhenValues = [datetime.datetime.now(parcel.itsView.tzinfo.default)]

    def changeTriage(itemOrStamp, triageValue):
        triageWhen = triageWhenValues.pop()
        item = getattr(itemOrStamp, 'itsItem', itemOrStamp)
        item.setTriageStatus(triageValue, triageWhen)
        triageWhenValues.append(triageWhen - datetime.timedelta(seconds=5))

    # OOTB item: Welcome Event
    noonToday = datetime.datetime.combine(
        datetime.date.today(),
        datetime.time(12, tzinfo=parcel.itsView.tzinfo.floating))

    WelcomeEvent = pim.EventStamp.update(
        parcel,
        'WelcomeEvent',
        # L10N: The Trademark symbol "TM" is represented in Unicode as U+2122
        displayName=_(u'Welcome to Chandler\u2122'),
        startTime=noonToday,
        duration=datetime.timedelta(minutes=60),
        anyTime=False,
        read=False,
        creator=osafDev,
        location=pim.Location.update(
            parcel,
            "OSAFLocation",
            displayName="Open Source Applications Foundation",
        ),
    )

    # L10N: The Trademark symbol "TM" is represented in Unicode as U+2122
    body = _(
        u"""Welcome to Chandler\u2122 %(version)s. Here is a list of resources to help you get started:

1. Get a tour of Chandler
(http://chandlerproject.org/tour).

2. Learn how to import calendars and set up Chandler to back up and share
(http://chandlerproject.org/getstarted).

3. Back up your data and Share by signing up for a Chandler Hub account
(http://hub.chandlerproject.org/signup).

4. Ask for help by sending mail to mailto:[email protected].

5. Learn more about the project on our wiki
(http://chandlerproject.org/wikihome).

6. Get involved and contribute to the project
(http://chandlerproject.org/getinvolved).

Thank you for trying Chandler!

The Chandler Team""") % {
            'version': version.version
        }

    WelcomeEvent.body = body
    WelcomeEvent.changeEditState(pim.Modification.created)
    changeTriage(WelcomeEvent, pim.TriageEnum.now)
    pim.TaskStamp(WelcomeEvent).add()

    if Globals.options.reload:
        schema.ns('osaf.pim', parcel.itsView).allCollection.add(WelcomeEvent)
    else:
        # OOTB user defined collections: collections should be in mine
        mine = schema.ns("osaf.pim", parcel.itsView).mine

        def makeCollection(name, checked, color):
            collection = pim.SmartCollection(itsView=parcel.itsView,
                                             displayName=name)
            # include collection in overlays, as spec'ed
            UserCollection(collection).checked = checked
            # set the collection color as spec'ed
            UserCollection(collection).setColor(color)

            sidebarListCollection.add(collection)
            mine.addSource(collection)

            return collection

        # OOTB user defined collections: Work, Home and Fun
        work = makeCollection(_(u"Work"), True, u'Blue')
        home = makeCollection(_(u"Home"), True, u'Red')
        fun = makeCollection(_(u"Fun"), False, u'Plum')

        # OOTB shared collection: U.S. Holidays
        holidays = makeCollection(_(u"U.S. Holidays"), True, u'Green')

        holidaysPath = pkg_resources.resource_filename(__name__,
                                                       "us_holidays.ics")
        sharing.importFile(parcel.itsView, holidaysPath, collection=holidays)

        dashboard = schema.ns("osaf.pim", parcel.itsView).allCollection

        # Add Welcome item to OOTB collections
        home.add(WelcomeEvent)
        work.add(WelcomeEvent)

        thisWeek = CalendarUtility.getCalendarRange(noonToday.date())

        def getDayInThisWeek(weekday):

            res = thisWeek[0]
            while res.weekday() != weekday:
                res += datetime.timedelta(days=1)
            return res

        # OOTB item 1: Next dentist appointment?
        event1 = pim.CalendarEvent(
            itsView=parcel.itsView,
            displayName=_(u"Next dentist appointment?"),
            startTime=noonToday.replace(hour=9),
            anyTime=True,
            collections=[home],
            read=True,
        )
        event1.itsItem.changeEditState(pim.Modification.created,
                                       when=noonToday.replace(hour=8))
        changeTriage(event1, pim.TriageEnum.now)

        # OOTB item #2: Tell a friend about Chandler
        item2 = pim.Note(
            itsView=parcel.itsView,
            displayName=_(u"Tell a friend about Chandler"),
            read=True,
            body=_(
                u"""Try sharing a collection with family, friends or colleagues.

Sign up for a Chandler Hub account to get started: http://hub.chandlerproject.org
"""),
        )

        schema.ns("osaf.pim", parcel.itsView).allCollection.add(item2)
        item2.changeEditState(pim.Modification.created,
                              when=noonToday.replace(hour=8))
        changeTriage(item2, pim.TriageEnum.now)

        # OOTB item #3: Write-up
        task3 = pim.Task(
            itsView=parcel.itsView,
            displayName=_(u"Write-up..."),
            collections=[work],
            read=True,
            body=
            _(u"""Start jotting down ideas for that big write-up you should really have started last week!

.
.
.
"""),
        )
        task3.itsItem.changeEditState(pim.Modification.created)
        changeTriage(task3, pim.TriageEnum.now)

        # OOTB item #4: Follow up
        task4 = pim.Task(
            itsView=parcel.itsView,
            displayName=_(u"Follow up with...on..."),
            read=True,
            body=
            _(u"""Maintain a list of things you need to discuss with a colleague:
.
.
.

(Click on the clock icon to add this note to the calendar for the next time you're going to meet with them.)
"""),
        )
        dashboard.add(task4.itsItem)
        task4.itsItem.changeEditState(pim.Modification.created)
        changeTriage(task4, pim.TriageEnum.now)

        # OOTB item #5: Start planning vacation
        task5 = pim.Task(
            itsView=parcel.itsView,
            displayName=_(u"Start planning vacation"),
            read=True,
            collections=[home],
            body=_("""Places you could go?
.
.
.

Activities you'd like to try?
.
.
.

Interesting travel articles?
.
.
.
"""),
        )

        changeTriage(task5, pim.TriageEnum.now)
        task5.itsItem.changeEditState(pim.Modification.created)

        # OOTB item #6: Bi-Weekly Status Report
        event5 = pim.CalendarEvent(
            itsView=parcel.itsView,
            displayName=_(u"Bi-Weekly Status Report"),
            startTime=noonToday,
            anyTime=True,
            read=True,
            collections=[work],
            body=_("""What have you been up to the last couple of weeks?
.
.
.
"""),
        )

        def makeRecurring(event, **kw):
            rule = pim.calendar.Recurrence.RecurrenceRule(
                itsView=parcel.itsView, **kw)

            event.rruleset = pim.calendar.Recurrence.RecurrenceRuleSet(
                itsView=parcel.itsView, rrules=[rule])
            for item in event.modifications:
                changeTriage(item, item._triageStatus)

        pim.TaskStamp(event5).add()
        event5.itsItem.changeEditState(pim.Modification.created)

        makeRecurring(event5, freq='weekly', interval=2)

        # OOTB item #6: Office supplies order
        startTime6 = datetime.datetime.combine(getDayInThisWeek(4),
                                               noonToday.timetz())

        event6 = pim.CalendarEvent(
            itsView=parcel.itsView,
            displayName=_(u"Office supplies order"),
            startTime=startTime6,
            anyTime=True,
            read=True,
            collections=[work],
            body=_(u"""Maintain a list of supplies you need to get every month:
.
.
.

(Share it with others so you can all maintain the list together!)
"""))
        changeTriage(event6, pim.TriageEnum.done)
        event6.itsItem.changeEditState(pim.Modification.created)
        makeRecurring(event6, freq='monthly')

        # OOTB item #7: Salsa class
        startTime7 = noonToday.replace(hour=14, minute=30)
        delta = 14 + startTime7.date().weekday() - 6
        startTime7 -= datetime.timedelta(days=delta)
        until7 = startTime7 + datetime.timedelta(days=28)
        event7 = pim.CalendarEvent(itsView=parcel.itsView,
                                   displayName=_(u"Salsa Class"),
                                   startTime=startTime7,
                                   duration=datetime.timedelta(hours=1),
                                   anyTime=False,
                                   read=True,
                                   collections=[home, fun],
                                   body=_(u"""Assignment for this week:
.
.
.

Remember to bring:
.
.
.
"""))
        event7.itsItem.changeEditState(pim.Modification.created,
                                       when=startTime7)
        changeTriage(event7, pim.TriageEnum.done)
        makeRecurring(event7, freq='weekly', until=until7)

        # A hack to get this occurrence to appear in the dashboard
        event7.getFirstOccurrence().getNextOccurrence().changeThis()
        for m in sorted(event7.modifications,
                        key=lambda o: pim.EventStamp(o).startTime):
            changeTriage(m, m._triageStatus)

        # OOTB item #8: Brunch potluck...
        startTime8 = datetime.datetime.combine(
            getDayInThisWeek(6), datetime.time(11, 0, tzinfo=noonToday.tzinfo))

        event8 = pim.CalendarEvent(
            itsView=parcel.itsView,
            displayName=_(u"Brunch potluck..."),
            startTime=startTime8,
            duration=datetime.timedelta(hours=2),
            anyTime=False,
            read=True,
            collections=[home, fun],
            body=_(u"""Directions
.
.
.

Ideas for games to bring...
.
.
.

Sign up to bring food...
.
.
.
"""),
        )
        changeTriage(event8, event8.autoTriage())
        event8.itsItem.changeEditState(pim.Modification.created)

        # OOTB Item #9: Ideas for presents
        item9 = pim.Note(
            itsView=parcel.itsView,
            displayName=_(u"Ideas for presents"),
            read=True,
            collections=[home],
            body=
            _(u"""Maintain a list of possible presents for family, friends and colleagues so you're never short on ideas!
.
.
.
"""),
        )
        changeTriage(item9, pim.TriageEnum.later)
        item9.changeEditState(pim.Modification.edited)

        # OOTB Item #10: Thank you notes
        item10 = pim.Note(
            itsView=parcel.itsView,
            displayName=_(u"Thank you notes"),
            read=True,
            collections=[home],
            body=
            _(u"""Who do you need to write thank you notes to? and for what reason?
.
.
.


"""),
        )

        changeTriage(item10, pim.TriageEnum.later)
        item10.changeEditState(pim.Modification.created)

        # OOTB Item #11: Movie list
        item11 = pim.Note(
            itsView=parcel.itsView,
            displayName=_(u"Movie list"),
            read=True,
            collections=[fun, home],
            body=_(u"""Movies you want to see:

.
.
.
"""),
        )

        changeTriage(item11, pim.TriageEnum.later)
        item11.changeEditState(pim.Modification.created)

        # OOTB Item #12: Book list
        item12 = pim.Note(
            itsView=parcel.itsView,
            displayName=_(u"Book list"),
            read=True,
            collections=[fun, home],
            body=_(
                u"""Book recommendations you've been meaning to follow up on:

.
.
.
"""),
        )

        changeTriage(item12, pim.TriageEnum.later)
        item12.changeEditState(pim.Modification.created)

        # OOTB Item #13: File taxes
        startTime13 = noonToday.replace(month=4, day=15)
        alarmTime13 = startTime13.replace(day=1)
        if alarmTime13 < noonToday:
            alarmTime13 = alarmTime13.replace(year=alarmTime13.year + 1)
            startTime13 = startTime13.replace(year=startTime13.year + 1)

        event13 = pim.CalendarEvent(
            itsView=parcel.itsView,
            startTime=startTime13,
            displayName=_(u"File taxes!"),
            read=True,
            collections=[home],
            body=_(u"""What forms do you have in hand?
.
.
.

What are you missing?
.
.
.

Questions for your accountant?
.
.
.
"""),
        )

        pim.TaskStamp(event13).add()
        event13.itsItem.changeEditState(pim.Modification.created)
        changeTriage(event13, pim.TriageEnum.later)
        event13.itsItem.userReminderTime = alarmTime13

        # OOTB Item #14: Class Trip: Exhibit on Sound!
        location14 = pim.Location.update(
            parcel,
            "Exploratorium",
            displayName="Exploratorium",
        )

        startTime14 = datetime.datetime.combine(
            getDayInThisWeek(6), datetime.time(15, tzinfo=noonToday.tzinfo))

        event14 = pim.CalendarEvent(
            itsView=parcel.itsView,
            startTime=startTime14,
            displayName=_(u"Class Trip: Exhibit on Sound!"),
            read=True,
            location=location14,
            collections=[fun],
            body=_(u"""Directions...
.
.
.
"""),
        )
        event14.itsItem.changeEditState(pim.Modification.edited,
                                        when=startTime14)
        changeTriage(event14, pim.TriageEnum.done)

        # OOTB Item #15: Download Chandler!
        note15 = pim.Note(
            itsView=parcel.itsView,
            displayName=_(u"Download Chandler!"),
            read=True,
        )
        dashboard.add(note15)
        done15 = datetime.datetime.now(parcel.itsView.tzinfo.default)
        done15 -= datetime.timedelta(minutes=5)
        done15 = done15.replace(second=0, microsecond=0)
        changeTriage(note15, pim.TriageEnum.done)
        note15.changeEditState(pim.Modification.edited, when=done15)

        # Set up sharing for holidays
        share = sharing.Share(itsView=parcel.itsView,
                              mode='get',
                              contents=holidays,
                              established=True)
        filters = set([
            'cid:[email protected]', 'cid:[email protected]',
            'cid:[email protected]', 'cid:[email protected]',
            'cid:[email protected]'
        ])
        share.conduit = sharing.WebDAVMonolithicRecordSetConduit(
            itsParent=share,
            host=u'hub.chandlerproject.org',
            port=443,
            sharePath=u'webcal/collection',
            shareName=u'7febe2f4-324c-11dd-d9e4-0016cbca6aed?ticket=01q75n1sy0',
            useSSL=True,
            filters=filters,
            translator=sharing.SharingTranslator,
            serializer=sharing.ICSSerializer)
        share.conduit.ticketReadOnly = share.conduit.ticket
        sharing.SharedItem(share.contents).add()
        sharing.SharedItem(share.contents).shares.append(share)

    # Set up the main web server
    from osaf import webserver

    startup.Startup.update(parcel,
                           "startServers",
                           invoke="osaf.webserver.start_servers")

    webserver.Server.update(
        parcel,
        "mainServer",
        # Port to listen on.  1888 was the year Raymond Chandler was born.
        port=1888,

        # This path specifies the "doc root" of this web server, and is
        # relative to webserver/servers, but you may also put in an
        # absolute path if you wish.
        #
        path=unicode(os.path.join("parcels", "osaf", "app", "webhome")),
        resources=[
            webserver.Resource.update(
                parcel,
                "lobsResource",
                displayName=u"Lob Server",
                location=u"lobs",
                resourceClass=schema.importString(
                    "osaf.servlets.lobviewer.LobViewerResource"),
            ),
            webserver.Resource.update(
                parcel,
                "photoResource",
                displayName=u"Photo Viewer",
                location=u"photos",
                resourceClass=schema.importString(
                    "osaf.servlets.photo.PhotosResource"),
            ),
            webserver.Resource.update(parcel,
                                      "repoResource",
                                      displayName=u"Repository Viewer",
                                      location=u"repo",
                                      resourceClass=schema.importString(
                                          "osaf.servlets.repo.RepoResource"),
                                      autoView=False),
            webserver.Resource.update(parcel,
                                      "prefResource",
                                      displayName=u'Preference Editor',
                                      location=u"prefs",
                                      resourceClass=schema.importString(
                                          "osaf.servlets.prefs.PrefResource"),
                                      autoView=False),
            webserver.Resource.update(
                parcel,
                "xmlrpcResource",
                displayName=u'XML-RPC Service',
                location=u"xmlrpc",
                resourceClass=schema.importString(
                    "osaf.servlets.xmlrpc.XmlRpcResource"),
                autoView=False),
        ])

    from osaf.app import updates

    # Subtract 15 minutes from lastRun so that in a week's
    # time we don't conflict with the "compact" trask.
    updates.UpdateCheckTask.update(parcel,
                                   'updateCheckTask',
                                   interval=datetime.timedelta(days=1),
                                   lastRun=datetime.datetime.now() -
                                   datetime.timedelta(minutes=15))

    # Compact task should come last
    from osaf.app import compact
    compact.CompactTask.update(parcel, 'compactTask')
Ejemplo n.º 5
0
class BackgroundSyncHandler:
    def __init__(self, item):
        global running_status

        def shutdownCallback():
            # This gets called before twisted starts shutting down, since we
            # register this callback a few lines down

            # Return a Deferred that we can return to twisted -- twisted will
            # wait for the Deferred to be called-back when shutting down; if
            # no current sync activity, then return None
            global shutdown_deferred

            if running_status == IDLE:
                # Returning None since we're not running
                return None

            shutdown_deferred = twisted.internet.defer.Deferred()
            return shutdown_deferred

        # Register a callback for when twisted is being shutdown
        twisted.internet.reactor.addSystemEventTrigger('before', 'shutdown',
                                                       shutdownCallback)

        # Store the repository view provided to us
        self.rv = item.itsView

        running_status = IDLE

    def run(self, *args, **kwds):

        # This method must return True -- no raising exceptions!

        global interrupt_flag, running_status, current_activity

        if running_status != IDLE:
            # busy
            return True

        stats = []
        running_status = RUNNING

        try:  # ensuring we always return True {

            modeOverride = kwds.get('modeOverride', None)
            forceUpdate = kwds.get('forceUpdate', None)

            self.rv.refresh(notify=False)
            tz = self.rv.tzinfo.default

            if not (schema.ns('osaf.app', self.rv).prefs.isOnline
                    and isOnline(self.rv)):
                # app and sharing layer must both be online to perform a sync
                running_status = IDLE
                return True

            shares = []

            if 'collection' in kwds:
                uuid = kwds['collection']
                collection = self.rv.findUUID(uuid)
            else:
                collection = None

                # TODO: someday replace this with an endpoint
                for account in CosmoAccount.iterAccounts(self.rv):
                    if account.isSetUp():

                        if interrupt_flag != PROCEED:  # interruption
                            raise ActivityAborted(_(u"Cancelled by user"))

                        try:
                            msg = _(u"Examining collections for %(account)s") \
                                % {'account' : account.displayName}
                            activity = Activity(msg)
                            activity.started()
                            current_activity = activity
                            info = account.getPublishedShares(blocking=True)
                            current_activity = None
                            activity.completed()

                            for uuid in account.unsubscribed:
                                if (uuid not in account.ignored
                                        and uuid not in account.requested):
                                    callCallbacks(UNSUBSCRIBEDCOLLECTIONS)

                        except ActivityAborted:
                            raise

                        except Exception, e:
                            logger.exception("Collection restore error")
                            activity.failed(e)
                            current_activity = None

            shares = getSyncableShares(self.rv, collection)

            for share in shares:

                if interrupt_flag != PROCEED:  # interruption
                    raise ActivityAborted(_(u"Cancelled by user"))

                callCallbacks(UPDATE,
                              msg="Syncing collection '%s'" %
                              share.contents.displayName)

                try:
                    activity = Activity("Sync: %s" %
                                        share.contents.displayName)
                    activity.started()
                    altView = viewpool.getView(self.rv.repository)
                    altShare = altView.findUUID(share.itsUUID)
                    current_activity = activity
                    stats.extend(
                        altShare.sync(modeOverride=modeOverride,
                                      activity=activity,
                                      forceUpdate=forceUpdate))
                    altView.commit(mergeFunction)
                    viewpool.releaseView(altView)
                    current_activity = None
                    activity.completed()

                except ActivityAborted:
                    logger.exception("Syncing cancelled")
                    altView.cancel()
                    viewpool.releaseView(altView)
                    raise

                except Exception, e:
                    logger.exception("Error syncing collection")
                    altView.cancel()
                    viewpool.releaseView(altView)
                    share.error, share.errorDetails = errors.formatException(e)
                    share.lastAttempt = datetime.datetime.now(tz)
                    stats.extend([{
                        'collection': share.contents.itsUUID,
                        'error': str(e)
                    }])
                    activity.failed(e)
                    current_activity = None

            try:
                log = schema.ns('osaf.sharing', self.rv).activityLog
            except AttributeError:
                log = None

            if log is not None:
                reportEvent = pim.CalendarEvent(
                    itsView=self.rv,
                    displayName="Sync",
                    startTime=datetime.datetime.now(self.rv.tzinfo.default),
                    duration=datetime.timedelta(minutes=60),
                    anyTime=False,
                    transparency='fyi',
                    body=stats2str(self.rv, stats))
                log.add(reportEvent.itsItem)

            self.rv.commit(mergeFunction)

            callCallbacks(UPDATE, msg='')