Example #1
0
def _interval_restriction(proptag, start, end):
    start = datetime_to_filetime(start)
    end = datetime_to_filetime(end)

    return SAndRestriction([
        SPropertyRestriction(RELOP_GE, proptag, SPropValue(proptag, start)),
        SPropertyRestriction(RELOP_LT, proptag, SPropValue(proptag, end))
    ])
Example #2
0
def GetUserList(session, companyname=None, flags=0):
    restriction = SAndRestriction([
        SPropertyRestriction(RELOP_EQ, PR_OBJECT_TYPE,
                             SPropValue(PR_OBJECT_TYPE, MAPI_MAILUSER)),
        SPropertyRestriction(RELOP_NE, PR_DISPLAY_TYPE,
                             SPropValue(PR_DISPLAY_TYPE, DT_REMOTE_MAILUSER))
    ])
    return GetAbObjectList(session, restriction, companyname, flags)
Example #3
0
    def occurrences(self, start=None, end=None):
        if start and end:
            startstamp = time.mktime(start.timetuple())
            endstamp = time.mktime(end.timetuple())

            # XXX use shortcuts and default type (database) to avoid MAPI snake wrestling
            NAMED_PROPS = [
                MAPINAMEID(PSETID_Appointment, MNID_ID, x)
                for x in (33293, 33294, 33315)
            ]
            ids = self.mapiobj.GetIDsFromNames(NAMED_PROPS, 0)
            startdate = ids[0] | PT_SYSTIME
            enddate = ids[1] | PT_SYSTIME
            recurring = ids[2] | PT_BOOLEAN

            # only look at non-recurring items which overlap and all recurring items
            restriction = SOrRestriction([
                SAndRestriction([
                    SPropertyRestriction(
                        RELOP_GT, enddate,
                        SPropValue(enddate, unixtime(startstamp))),
                    SPropertyRestriction(
                        RELOP_LT, startdate,
                        SPropValue(startdate, unixtime(endstamp))),
                ]),
                SAndRestriction([
                    SPropertyRestriction(RELOP_EQ, recurring,
                                         SPropValue(recurring, True))
                ])
            ])

            table = Table(
                self.server,
                self.mapiobj,
                self.mapiobj.GetContentsTable(MAPI_DEFERRED_ERRORS),
                PR_CONTAINER_CONTENTS,
                columns=[PR_ENTRYID],
            )
            table.mapitable.Restrict(restriction, 0)
            for row in table.rows():
                entryid = _benc(row[0].value)
                for occurrence in self.item(entryid).occurrences(start, end):
                    yield occurrence

        else:
            for item in self:
                for occurrence in item.occurrences(start, end):
                    yield occurrence
Example #4
0
    def create_calendar(
        self,
        name,
        color = "",
        allow_online_meeting_providers = ["unknown"],
        default_online_meeting_provider = "unknown"
    ):
        """Create a new calendar.

        Args:
            name (str): calendar name.
            color (str): calendar color name. Defaults to an empty string.
            allow_online_meeting_providers (list): allow online meeting providers
                like "skypeForBusiness", "skypeForCustomer", and etc. Defaults to ["unknown"].
            default_online_meeting_provider (str): default online meeting providers.
                Defaults to "unknown".

        Returns:
            Folder: the created calendar.

        Todo:
            "allow_online_meeting_providers" needs be to supported.
        """
        restriction = Restriction(SPropertyRestriction(
            RELOP_EQ, PR_CONTAINER_CLASS_W,
            SPropValue(PR_CONTAINER_CLASS_W, 'IPF.Appointment')
        ))
        folder = self.create_folder(
            name=name,
            restriction=restriction,
            container_class="IPF.Appointment",
            color=color,
            default_online_meeting_provider=default_online_meeting_provider
        )
        return folder
Example #5
0
    def favorites(self):
        """Returns all favorite folders"""

        table = self.common_views.mapiobj.GetContentsTable(MAPI_ASSOCIATED)
        table.SetColumns([
            PR_MESSAGE_CLASS, PR_SUBJECT, PR_WLINK_ENTRYID, PR_WLINK_FLAGS,
            PR_WLINK_ORDINAL, PR_WLINK_STORE_ENTRYID, PR_WLINK_TYPE
        ], 0)
        table.Restrict(
            SPropertyRestriction(
                RELOP_EQ, PR_MESSAGE_CLASS,
                SPropValue(PR_MESSAGE_CLASS, "IPM.Microsoft.WunderBar.Link")),
            TBL_BATCH)

        for row in table.QueryRows(-1, 0):
            store_entryid = bin2hex(row[5].Value)

            try:
                if store_entryid == self.entryid:  # XXX: Handle favorites from public stores
                    yield self.folder(entryid=bin2hex(row[2].Value))
                else:
                    store = Store(entryid=store_entryid, server=self.server)
                    yield store.folder(entryid=bin2hex(row[2].Value))
            except NotFoundError:
                pass
Example #6
0
    def favorites(self):
        """Returns all favorite :class:`folders <Folder>`."""
        restriction = Restriction(
            SPropertyRestriction(
                RELOP_EQ, PR_MESSAGE_CLASS_W,
                SPropValue(PR_MESSAGE_CLASS_W,
                           'IPM.Microsoft.WunderBar.Link')))

        table = Table(
            self.server,
            self.mapiobj,
            self.common_views.mapiobj.GetContentsTable(MAPI_ASSOCIATED),
            restriction=restriction,
            columns=[PR_WLINK_ENTRYID, PR_WLINK_STORE_ENTRYID],
        )
        for entryid, store_entryid in table:
            try:
                # TODO: Handle favorites from public stores
                if store_entryid == self.entryid:
                    yield self.folder(entryid=_benc(entryid.value))
                else:
                    store = Store(entryid=_benc(store_entryid.value),
                                  server=self.server)
                    yield store.folder(entryid=_benc(entryid.value))
            except NotFoundError:
                pass
Example #7
0
    def searches(self):
        """Return all permanent search folders."""
        findroot = self.root.folder('FINDER_ROOT')  # TODO

        # extract special type of guid from search folder
        # PR_EXTENDED_FOLDER_FLAGS to match against
        guid_folder = {}
        for folder in findroot.folders():
            try:
                prop = folder.prop(PR_EXTENDED_FOLDER_FLAGS)
                subprops = self._subprops(prop.value)
                guid_folder[subprops[2]] = folder
            except NotFoundError:
                pass

        # match common_views SFInfo records against these guids
        table = self.common_views.mapiobj.GetContentsTable(MAPI_ASSOCIATED)

        table.SetColumns([PR_MESSAGE_CLASS_W, PR_WB_SF_ID], MAPI_UNICODE)
        table.Restrict(
            SPropertyRestriction(
                RELOP_EQ, PR_MESSAGE_CLASS_W,
                SPropValue(PR_MESSAGE_CLASS_W,
                           'IPM.Microsoft.WunderBar.SFInfo')), TBL_BATCH)

        for row in table.QueryRows(-1, 0):
            try:
                yield guid_folder[row[1].Value]
            except KeyError:
                pass
Example #8
0
    def item(self, entryid=None, sourcekey=None):
        """ Return :class:`Item` with given entryid or sourcekey

        :param entryid: item entryid
        :param sourcekey: item sourcekey
        """

        # resolve sourcekey to entryid
        if sourcekey is not None:
            restriction = SPropertyRestriction(RELOP_EQ, PR_SOURCE_KEY, SPropValue(PR_SOURCE_KEY, _bdec(sourcekey)))
            table = self.mapiobj.GetContentsTable(MAPI_DEFERRED_ERRORS)
            table.SetColumns([PR_ENTRYID, PR_SOURCE_KEY], 0)
            table.Restrict(restriction, 0)
            rows = list(table.QueryRows(-1, 0))
            if not rows:
                raise NotFoundError("no item with sourcekey '%s'" % sourcekey)
            entryid = _benc(rows[0][0].Value)

        # open message with entryid
        try:
            mapiobj = _utils.openentry_raw(self.store.mapiobj, _bdec(entryid), self.content_flag)
        except MAPIErrorNotFound:
            raise NotFoundError("no item with entryid '%s'" % entryid)

        item = _item.Item(self, mapiobj=mapiobj)
        return item
Example #9
0
    def restriction(self, type_, store):
        if self.field:
            # determine proptag for term, eg 'subject'
            proptag = TYPE_KEYWORD_PROPMAP[type_][self.field]
            flag = None
            subobj = None
            recipient_type = None

            # property in sub-object (attachments/recipient): use sub-restriction
            if isinstance(proptag, tuple):
                if(proptag[0]) == PR_MESSAGE_ATTACHMENTS:
                    subobj, proptag = proptag
                elif(proptag[0]) == PR_MESSAGE_RECIPIENTS:
                    subobj, proptag, recipient_type = proptag
                elif len(proptag) == 2:
                    proptag, flag = proptag

                # named property: resolve local proptag
                elif len(proptag) == 4:
                    proptag = store._name_id(proptag[:3]) | proptag[3]

            # make restriction on proptag(s)
            if isinstance(proptag, list):
                restr = SOrRestriction([
                    self.prop_restriction(proptag, flag) for proptag in proptag
                ])
            else:
                restr = self.prop_restriction(proptag, flag)

            # turn restriction into sub-restriction
            if subobj:
                if recipient_type is not None:
                    restr = SAndRestriction([
                        restr,
                        SPropertyRestriction(
                                RELOP_EQ,
                                PR_RECIPIENT_TYPE,
                                SPropValue(PR_RECIPIENT_TYPE, recipient_type)
                        )
                    ])
                restr = SSubRestriction(subobj, restr)

        else:
            defaults = [(store._name_id(proptag[:3]) | proptag[3])
                           if isinstance(proptag, tuple) else proptag
                               for proptag in DEFAULT_PROPTAGS[type_]]

            restr = SOrRestriction([
                       SContentRestriction(
                           FL_SUBSTRING | FL_IGNORECASE,
                           p,
                           SPropValue(p, self.value)
                       ) for p in defaults
                   ])

        if self.sign == '-':
            restr = SNotRestriction(restr)

        return restr
Example #10
0
def GetGab(session):
    ab = session.OpenAddressBook(0, None, 0)
    root = ab.OpenEntry(None, None, 0)
    table = root.GetHierarchyTable(0)
    table.SetColumns([PR_ENTRYID], TBL_BATCH)
    restriction = SOrRestriction([
        SPropertyRestriction(RELOP_EQ, PR_DISPLAY_TYPE,
                             SPropValue(PR_DISPLAY_TYPE, DT_GLOBAL)),
        SAndRestriction([
            SExistRestriction(PR_EMS_AB_CONTAINERID),
            SPropertyRestriction(RELOP_EQ, PR_EMS_AB_CONTAINERID,
                                 SPropValue(PR_EMS_AB_CONTAINERID, 0))
        ])
    ])
    table.FindRow(restriction, BOOKMARK_BEGINNING, 0)
    eid = table.QueryRows(1, 0)[0][0].Value
    return ab.OpenEntry(eid, None, 0)
Example #11
0
    def _save_rule(store, userids, deletion):
        # remove existing rule # XXX update
        for rule in store.inbox.rules():
            if rule.mapirow[PR_RULE_PROVIDER_W] == u'Schedule+ EMS Interface' and \
               PR_RULE_ID in rule.mapirow:
                pr_rule_id = rule.mapirow[PR_RULE_ID]

                rulerows = [
                    ROWENTRY(ROW_REMOVE, [SPropValue(PR_RULE_ID, pr_rule_id)])
                ]
                table = store.inbox.mapiobj.OpenProperty(
                    PR_RULES_TABLE, IID_IExchangeModifyTable, 0, 0)
                table.ModifyTable(0, rulerows)

        # create new rule
        row = [
            SPropValue(PR_RULE_LEVEL, 0),
            SPropValue(PR_RULE_NAME_W, u"Delegate Meetingrequest service"),
            SPropValue(PR_RULE_PROVIDER_W, u"Schedule+ EMS Interface"),
            SPropValue(PR_RULE_SEQUENCE, 0),
            SPropValue(PR_RULE_STATE, 1),
            SPropValue(PR_RULE_PROVIDER_DATA, b''),
        ]

        actions = []
        userprops = []
        for userid in userids:
            user = store.server.gab.OpenEntry(userid, None, MAPI_BEST_ACCESS)
            props = user.GetProps(USERPROPS, MAPI_UNICODE)
            # Hardcode recipient type to TO
            props.append(SPropValue(PR_RECIPIENT_TYPE, MAPI_TO))
            userprops.append(props)

        actions.append(
            ACTION(ACTTYPE.OP_DELEGATE, 0, None, None, 0,
                   actFwdDelegate(userprops)))
        if deletion:
            actions.append(ACTION(ACTTYPE.OP_DELETE, 0, None, None, 0, None))
        row.append(SPropValue(PR_RULE_ACTIONS, ACTIONS(1, actions)))

        cond = SAndRestriction([
            SContentRestriction(
                FL_PREFIX, PR_MESSAGE_CLASS_W,
                SPropValue(PR_MESSAGE_CLASS_W, u"IPM.Schedule.Meeting")),
            SNotRestriction(SExistRestriction(PR_DELEGATED_BY_RULE)),
            SOrRestriction([
                SNotRestriction(SExistRestriction(PR_SENSITIVITY)),
                SPropertyRestriction(RELOP_NE, PR_SENSITIVITY,
                                     SPropValue(PR_SENSITIVITY, 2))
            ])
        ])
        row.append(SPropValue(PR_RULE_CONDITION, cond))
        rulerows = [ROWENTRY(ROW_ADD, row)]
        table = store.inbox.mapiobj.OpenProperty(PR_RULES_TABLE,
                                                 IID_IExchangeModifyTable, 0,
                                                 0)
        table.ModifyTable(0, rulerows)
Example #12
0
def gab_user(gab):
    username = os.getenv('KOPANO_TEST_USER')
    table = gab.GetContentsTable(0)
    table.FindRow(
        SPropertyRestriction(RELOP_EQ, PR_ACCOUNT_W,
                             SPropValue(PR_ACCOUNT_W, username)),
        BOOKMARK_BEGINNING, 0)
    row = table.QueryRows(1, 0)
    return row
Example #13
0
def test_subject(item):
    item.subject = 'test'
    mapiobj = SPropertyRestriction(RELOP_EQ, PR_SUBJECT,
                                   SPropValue(PR_SUBJECT, b'test'))
    restriction = Restriction(mapiobj=mapiobj)

    assert restriction.match(item)

    item.subject = 'henk'
    assert not restriction.match(item)
def test_deletedontimestamp(root, message):
    eid = message.GetProps([PR_ENTRYID], 0)[0]
    root.DeleteMessages([eid.Value], 0, None, 0)

    table = root.GetContentsTable(SHOW_SOFT_DELETES)
    table.SetColumns([PR_SUBJECT, PR_ENTRYID, PR_DELETED_ON], 0)
    table.FindRow(SPropertyRestriction(RELOP_EQ, PR_ENTRYID, eid), 0, 0)
    rows = table.QueryRows(1, 0)

    assert PpropFindProp(rows[0], PR_DELETED_ON)
Example #15
0
 def calendar_item(self):
     """Global calendar item :class:`item <Item>`
     (possibly in delegator store)."""
     goid = self.item.get_prop(PidLidCleanGlobalObjectId)
     if goid is not None:
         restriction = Restriction(SPropertyRestriction(
             RELOP_EQ, goid.proptag,
             SPropValue(goid.proptag, goid.mapiobj.Value))
         )
         return next(self.calendar.items(restriction), None)
Example #16
0
    def folder(self, path=None, entryid=None, recurse=False, create=False):
        """ Return :class:`Folder` with given path or entryid

            :param key: name, path or entryid
        """

        if entryid is not None:
            try:
                return Folder(self.store, entryid)
            except (MAPIErrorInvalidEntryid, MAPIErrorNotFound, TypeError):
                raise NotFoundError('no folder with entryid "%s"' % entryid)
        elif path is None:
            raise ArgumentError('missing argument to identify folder')

        if path is None:
            raise ArgumentError('no path or entryid specified')

        if '/' in path.replace(
                '\\/', ''
        ):  # XXX MAPI folders may contain '/' (and '\') in their names..
            subfolder = self
            for name in UNESCAPED_SLASH_RE.split(path):
                subfolder = subfolder.folder(name,
                                             create=create,
                                             recurse=False)
            return subfolder

        if self == self.store.subtree and path in ENGLISH_FOLDER_MAP:  # XXX depth==0?
            f = getattr(self.store, ENGLISH_FOLDER_MAP[path], None)
            if f:
                path = f.name

        if create:
            name = path.replace('\\/', '/')
            try:
                mapifolder = self.mapiobj.CreateFolder(FOLDER_GENERIC,
                                                       _unicode(name), u'',
                                                       None, MAPI_UNICODE)
                return Folder(
                    self.store,
                    _benc(HrGetOneProp(mapifolder, PR_ENTRYID).Value))
            except MAPIErrorCollision:
                pass

        name = path.replace('\\/', '/')
        restriction = Restriction(
            SPropertyRestriction(RELOP_EQ, PR_DISPLAY_NAME_W,
                                 SPropValue(PR_DISPLAY_NAME_W,
                                            _unicode(name))))

        folders = list(self.folders(recurse=recurse, restriction=restriction))
        if len(folders) == 0:
            raise NotFoundError("no such folder: '%s'" % path)

        return folders[0]
Example #17
0
    def get_all(cls, req, resp, store, server, userid):
        restriction = None
        if cls.needs_restriction:
            restriction = Restriction(
                SPropertyRestriction(
                    RELOP_EQ, PR_CONTAINER_CLASS_W,
                    SPropValue(PR_CONTAINER_CLASS_W, cls.container_class)))

        data = cls.generator(req, cls.default_folders_list(store), 0,
                             restriction)
        cls.respond(req, resp, data, cls.fields)
Example #18
0
    def calendar_item(
        self
    ):  # TODO ambiguous: split in two (match exact GOID or parent recurrence?)
        """ Global calendar item :class:`item <Item>` (possibly in delegator store) """

        goid = self.item.get_prop(PidLidCleanGlobalObjectId)
        if goid is not None:
            restriction = Restriction(
                SPropertyRestriction(
                    RELOP_EQ, goid.proptag,
                    SPropValue(goid.proptag, goid.mapiobj.Value)))
            return next(self.calendar.items(restriction), None)
Example #19
0
 def type_(self):
     """Store type (*private*, *public*, *archive*)."""
     table = self.server.sa.OpenUserStoresTable(MAPI_UNICODE)
     table.Restrict(SPropertyRestriction(RELOP_EQ, PR_EC_STOREGUID,
         SPropValue(PR_EC_STOREGUID, _bdec(self.guid))), TBL_BATCH)
     for row in table.QueryRows(1, 0):
         storetype = PpropFindProp(row, PR_EC_STORETYPE)
         if storetype:
             return {
                 ECSTORE_TYPE_PRIVATE: 'private',
                 ECSTORE_TYPE_ARCHIVE: 'archive',
                 ECSTORE_TYPE_PUBLIC: 'public',
             }[storetype.Value]
Example #20
0
 def _store(self, guid):
     if len(guid) != 32:
         raise Error("invalid store id: '%s'" % guid)
     try:
         storeid = _bdec(guid)
     except:
         raise Error("invalid store id: '%s'" % guid)
     table = self.ems.GetMailboxTable(None, 0) # XXX merge with Store.__init__
     table.SetColumns([PR_ENTRYID], 0)
     table.Restrict(SPropertyRestriction(RELOP_EQ, PR_STORE_RECORD_KEY, SPropValue(PR_STORE_RECORD_KEY, storeid)), TBL_BATCH)
     for row in table.QueryRows(-1, 0):
         return self._store2(row[0].Value)
     raise NotFoundError("no such store: '%s'" % guid)
Example #21
0
 def stores(self):
     """Return all company :class:`stores <Store>`."""
     if self.server.multitenant:
         table = self.server.sa.OpenUserStoresTable(MAPI_UNICODE)
         restriction = SPropertyRestriction(RELOP_EQ, PR_EC_COMPANY_NAME_W,
             SPropValue(PR_EC_COMPANY_NAME_W, self.name))
         table.Restrict(restriction, TBL_BATCH)
         for row in table.QueryRows(-1, 0):
             prop = PpropFindProp(row, PR_EC_STOREGUID)
             if prop:
                 yield _store.Store(_hex(prop.Value), self.server)
     else:
         for store in self.server.stores():
             yield store
Example #22
0
def test_deletedontimestamp(root, message):
    message.SetProps([SPropValue(PR_SUBJECT, b'Test')])
    message.SaveChanges(KEEP_OPEN_READWRITE)
    eid = message.GetProps([PR_ENTRYID], 0)[0]
    root.DeleteMessages([eid.Value], 0, None, 0)

    table = root.GetContentsTable(SHOW_SOFT_DELETES)
    table.SetColumns([PR_SUBJECT, PR_ENTRYID, PR_DELETED_ON], 0)
    table.FindRow(SPropertyRestriction(RELOP_EQ, PR_ENTRYID, eid), 0, 0)
    rows = table.QueryRows(1, 0)

    assert PpropFindProp(rows[0], PR_DELETED_ON)

    # Clean up message
    root.DeleteMessages([rows[0][1].Value], 0, None, 0)
Example #23
0
    def config_item(self, name):
        """Retrieve the config item for the given name.

        :param name: The config item name
        """
        table = self.subtree.mapiobj.GetContentsTable(MAPI_DEFERRED_ERRORS | MAPI_ASSOCIATED)
        table.Restrict(SPropertyRestriction(RELOP_EQ, PR_SUBJECT, SPropValue(PR_SUBJECT, name)), 0)
        rows = table.QueryRows(1,0)
        # No config item found, create new message
        if len(rows) == 0:
            item = self.subtree.associated.create_item(message_class='IPM.Zarafa.Configuration', subject=name)
        else:
            mapiobj = self.subtree.mapiobj.OpenEntry(rows[0][0].Value, None, MAPI_MODIFY)
            item = _item.Item(mapiobj=mapiobj)
        return item
Example #24
0
 def company(self):
     """Store :class:`company <Company>`."""
     if self.server.multitenant:
         table = self.server.sa.OpenUserStoresTable(MAPI_UNICODE)
         table.Restrict(SPropertyRestriction(RELOP_EQ, PR_EC_STOREGUID, SPropValue(PR_EC_STOREGUID, _bdec(self.guid))), TBL_BATCH)
         for row in table.QueryRows(1, 0):
             storetype = PpropFindProp(row, PR_EC_STORETYPE)
             if storetype.Value == ECSTORE_TYPE_PUBLIC:
                 companyname = PpropFindProp(row, PR_EC_USERNAME_W) # XXX bug in ECUserStoreTable.cpp?
                 if not companyname:
                     companyname = PpropFindProp(row, PR_EC_COMPANY_NAME_W) # XXX
             else:
                 companyname = PpropFindProp(row, PR_EC_COMPANY_NAME_W)
             return self.server.company(companyname.Value)
     else:
         return next(self.server.companies())
Example #25
0
 def mail_folders(self, **kwargs):
     # Mail folders are a fixed set of folders which all can contain mail
     # items, plus any other customly created folder of container class
     # IPF.Note.
     static = {}
     for n in ('inbox', 'outbox', 'sentmail', 'wastebasket', 'drafts',
               'junk'):
         f = getattr(self, n)
         if f is not None:
             static[f.entryid] = True
             yield f
     # Find additional folders using a restrictions.
     restriction = Restriction(
         SPropertyRestriction(RELOP_EQ, PR_CONTAINER_CLASS_W,
                              SPropValue(PR_CONTAINER_CLASS_W, 'IPF.Note')))
     for folder in self.folders(restriction=restriction, **kwargs):
         # Yield additional folders, filtering by the fixed ones.
         if folder.entryid not in static:
             yield folder
Example #26
0
    def item(self, entryid=None, sourcekey=None):
        """ Return :class:`Item` with given entryid or sourcekey

        :param entryid: item entryid
        :param sourcekey: item sourcekey
        """

        if entryid is not None:
            eid = _utils._bdec_eid(entryid)

        elif sourcekey is not None:  # TODO this is horribly slow with nothing cached.. 1 SQL per row!?
            try:
                restriction = SPropertyRestriction(
                    RELOP_EQ, PR_SOURCE_KEY,
                    SPropValue(PR_SOURCE_KEY, _bdec(sourcekey)))
            except:
                raise ArgumentError("invalid sourcekey: %r" % sourcekey)
            table = self.mapiobj.GetContentsTable(MAPI_DEFERRED_ERRORS)
            table.SetColumns([PR_ENTRYID, PR_SOURCE_KEY], 0)
            table.Restrict(restriction, 0)
            rows = list(table.QueryRows(-1, 0))
            if not rows:
                raise NotFoundError("no item with sourcekey '%s'" % sourcekey)
            eid = rows[0][0].Value

        else:
            raise ArgumentError("no entryid or sourcekey specified")

        # open message with entryid
        try:
            mapiobj = _utils.openentry_raw(self.store.mapiobj, eid,
                                           self.content_flag)
        except MAPIErrorNotFound:
            if sourcekey is not None:
                raise NotFoundError("no item with sourcekey '%s'" % sourcekey)
            else:
                raise NotFoundError("no item with entryid '%s'" % entryid)
        except MAPIErrorInvalidEntryid:
            raise ArgumentError("invalid entryid: %r" % entryid)

        item = _item.Item(self, mapiobj=mapiobj)
        return item
Example #27
0
    def favorites(self):
        """Returns all favorite folders"""

        table = Table(
            self.server,
            self.common_views.mapiobj.GetContentsTable(MAPI_ASSOCIATED),
            columns=[PR_WLINK_ENTRYID, PR_WLINK_STORE_ENTRYID],
            restriction=Restriction(
                SPropertyRestriction(
                    RELOP_EQ, PR_MESSAGE_CLASS,
                    SPropValue(PR_MESSAGE_CLASS,
                               b"IPM.Microsoft.WunderBar.Link"))))
        for entryid, store_entryid in table:
            try:
                if store_entryid == self.entryid:  # XXX: Handle favorites from public stores
                    yield self.folder(entryid=_hex(entryid.value))
                else:
                    store = Store(entryid=_hex(store_entryid.value),
                                  server=self.server)
                    yield store.folder(entryid=_hex(entryid.value))
            except NotFoundError:
                pass
Example #28
0
    def _recipients(self, reciptype, addrs):
        """Sets the recipient table according to the type and given addresses.

        Since the recipienttable contains to, cc and bcc addresses, and item.to
        = [] should only set the to recipients (not append), the to recipients
        are first removed and then added again. This approach works but seems
        suboptimal, since it queries the MAPI_TO items, removes them and adds
        the new entries while leaving the other recipients intact.

        :param reciptype: MAPI_TO, MAPI_CC or MAPI_BCC
        :param addrs: list of addresses to set.
        """

        restriction = Restriction(SPropertyRestriction(RELOP_EQ,
                                                       PR_RECIPIENT_TYPE,
                                                       SPropValue(PR_RECIPIENT_TYPE, reciptype)))
        table = self.table(PR_MESSAGE_RECIPIENTS, columns=[PR_ROWID], restriction=restriction)
        rows = [[SPropValue(PR_ROWID, row[PR_ROWID])] for row in table.dict_rows()]
        if rows:
            self.mapiobj.ModifyRecipients(MODRECIP_REMOVE, rows)

        if _is_str(addrs):
            addrs = [x.strip() for x in _unicode(addrs).split(';')]
        elif isinstance(addrs, _user.User):
            addrs = [addrs]
        names = []
        for addr in addrs:
            pr_addrtype, pr_dispname, pr_email, pr_entryid = self._addr_props(addr)
            names.append([
                SPropValue(PR_RECIPIENT_TYPE, reciptype),
                SPropValue(PR_DISPLAY_NAME_W, pr_dispname),
                SPropValue(PR_ADDRTYPE_W, _unicode(pr_addrtype)),
                SPropValue(PR_EMAIL_ADDRESS_W, _unicode(pr_email)),
                SPropValue(PR_ENTRYID, pr_entryid),
            ])
        self.mapiobj.ModifyRecipients(MODRECIP_ADD, names)
        _utils._save(self.mapiobj) # XXX needed?
Example #29
0
    def restriction(self, type_, store):
        if self.field:
            # determine proptag for term, eg 'subject'
            proptag = TYPE_KEYWORD_PROPMAP[type_][self.field]
            flag = None
            subobj = None
            recipient_type = None

            # property in sub-object (attachments/recipient): use sub-restriction
            if isinstance(proptag, tuple) and len(proptag) == 2:
                if(proptag[0]) == PR_MESSAGE_ATTACHMENTS:
                    subobj, proptag = proptag
                elif(proptag[0]) == PR_MESSAGE_RECIPIENTS:
                    subobj, recipient_type = proptag
                    proptag = PR_DISPLAY_NAME_W # TODO email
                else:
                    proptag, flag = proptag

            # named property: resolve local proptag
            elif isinstance(proptag, tuple) and len(proptag) == 4:
                proptag = store._name_id(proptag[:3]) | proptag[3]

            # comparison operator
            if self.op in ('<', '>', '>=', '<=', '<>'):
                if PROP_TYPE(proptag) == PT_SYSTIME:
                    d = dateutil.parser.parse(self.value, dayfirst=True)
                    d = datetime_to_filetime(d)
                    restr = SPropertyRestriction(
                                OP_RELOP[self.op],
                                proptag,
                                SPropValue(proptag, d)
                            )
                else:
                    value = self.value
                    unit = ''
                    if [x for x in ('KB', 'MB', 'GB') if value.endswith(x)]:
                        value, unit = value[:-2], value[-2:]

                    if PROP_TYPE(proptag) in (PT_FLOAT, PT_DOUBLE):
                        value = float(value)
                    else:
                        value = int(value)

                    if unit == 'KB':
                        value *= 1024
                    elif unit == 'MB':
                        value *= 1024**2
                    elif unit == 'GB':
                        value *= 1024**3

                    restr = SPropertyRestriction(
                                OP_RELOP[self.op],
                                proptag,
                                SPropValue(proptag, value)
                            )

            # contains/equals operator
            elif self.op in (':', '='):
                if PROP_TYPE(proptag) == PT_UNICODE:
                    restr = SContentRestriction(
                                FL_SUBSTRING | FL_IGNORECASE,
                                proptag,
                                SPropValue(proptag, self.value)
                            )

                elif flag or PROP_TYPE(proptag) == PT_BOOLEAN:
                    if flag:
                        restr = SBitMaskRestriction(
                                    BMR_NEZ if self.value in ('yes', 'true') else BMR_EQZ,
                                    proptag,
                                    flag
                                )
                    else:
                        restr = SPropertyRestriction(
                                    RELOP_EQ,
                                    proptag,
                                    SPropValue(proptag, self.value in ('yes', 'true'))
                                )

                elif PROP_TYPE(proptag) == PT_MV_UNICODE:
                    proptag2 = (proptag ^ PT_MV_UNICODE) | PT_UNICODE # funky!
                    restr = SContentRestriction(
                                FL_SUBSTRING | FL_IGNORECASE,
                                proptag,
                                SPropValue(proptag2, self.value)
                            )

                elif PROP_TYPE(proptag) in (PT_SHORT, PT_LONG, PT_LONGLONG, PT_FLOAT, PT_DOUBLE):
                    conv = float if PROP_TYPE(proptag) in (PT_FLOAT, PT_DOUBLE) else int
                    if '..' in self.value:
                        val1, val2 = self.value.split('..')
                        restr = SAndRestriction([
                            SPropertyRestriction(
                                RELOP_GE,
                                proptag,
                                SPropValue(proptag, conv(val1))
                            ),
                            SPropertyRestriction(
                                RELOP_LT,
                                proptag,
                                SPropValue(proptag, conv(val2))
                            )
                        ])
                    else:
                        restr = SPropertyRestriction(
                                    RELOP_EQ,
                                    proptag,
                                    SPropValue(proptag, conv(self.value))
                                )

                elif PROP_TYPE(proptag) == PT_SYSTIME:
                    if self.value == 'today':
                        d = datetime.datetime.now().date()
                        d2 = d + datetime.timedelta(days=1)
                        restr = _interval_restriction(proptag, d, d2)

                    elif self.value == 'yesterday':
                        d2 = datetime.datetime.now().date()
                        d = d2 - datetime.timedelta(days=1)
                        restr = _interval_restriction(proptag, d, d2)

                    elif self.value == 'this week':
                        d2 = datetime.datetime.now()
                        d = d2.date() - datetime.timedelta(days=d2.weekday())
                        restr = _interval_restriction(proptag, d, d2)

                    elif self.value == 'this month':
                        d2 = datetime.datetime.now()
                        d = d2.date() - datetime.timedelta(days=d2.day-1)
                        restr = _interval_restriction(proptag, d, d2)

                    elif self.value == 'last month':
                        now = datetime.datetime.now()
                        d2 = now.date() - datetime.timedelta(days=now.day-1)
                        d = (d2 - datetime.timedelta(days=1)).replace(day=1)
                        restr = _interval_restriction(proptag, d, d2)

                    elif self.value == 'this year':
                        d2 = datetime.datetime.now()
                        d = datetime.datetime(d2.year, 1, 1)
                        restr = _interval_restriction(proptag, d, d2)

                    elif self.value == 'last year':
                        now = datetime.datetime.now()
                        d2 = datetime.datetime(now.year, 1, 1)
                        d = datetime.datetime(d2.year-1, 1, 1)
                        restr = _interval_restriction(proptag, d, d2)

                    elif '..' in self.value:
                        date1, date2 = self.value.split('..') # TODO hours etc
                        d = dateutil.parser.parse(date1, dayfirst=True)
                        d2 = dateutil.parser.parse(date2, dayfirst=True)
                        restr = _interval_restriction(proptag, d, d2)

                    else:
                        d = dateutil.parser.parse(self.value, dayfirst=True) # TODO hours etc
                        d2 = d + datetime.timedelta(days=1)
                        restr = _interval_restriction(proptag, d, d2)

            # turn restriction into sub-restriction
            if subobj:
                if recipient_type is not None:
                    restr = SAndRestriction([
                        restr,
                        SPropertyRestriction(
                                RELOP_EQ,
                                PR_RECIPIENT_TYPE,
                                SPropValue(PR_RECIPIENT_TYPE, recipient_type)
                        )
                    ])
                restr = SSubRestriction(subobj, restr)

        else:
            defaults = [(store._name_id(proptag[:3]) | proptag[3])
                           if isinstance(proptag, tuple) else proptag
                               for proptag in DEFAULT_PROPTAGS[type_]]
            restr = SOrRestriction([
                       SContentRestriction(
                           FL_SUBSTRING | FL_IGNORECASE,
                           p,
                           SPropValue(p, self.value)
                       ) for p in defaults
                   ])

        if self.sign == '-':
            restr = SNotRestriction(restr)

        return restr
Example #30
0
    def accept(self, tentative=False, response=True, add_bcc=False, subject_prefix='Accepted'):
        """Accept meeting request.

        :param tentative: accept tentatively (default False)
        :param response: send response message (default True)
        """
        if not self.is_request:
            raise Error('item is not a meeting request')
        if self._check_processed():
            self.log.warning('meeting request already processed')
            return

        calendar = self.calendar
        cal_item = self.calendar_item
        basedate = self.basedate

        # do nothing for invitation to self
        # (esp. don't try to add organizer/BCC)
        if self.item.store.user.email == self.item.from_.email:
            return

        self.item.mapiobj.SetReadFlag(SUPPRESS_RECEIPT)
        merge = False

        if basedate:
            # update existing recurrence
            if cal_item and cal_item.recurring:
                recurrence = cal_item.recurrence
                if recurrence._is_exception(basedate):
                    recurrence._modify_exception(basedate, self.item)
                else:
                    recurrence._create_exception(basedate, self.item)

            # otherwise replace calendar item
            else:
                if cal_item and cal_item[PidLidGlobalObjectId] == \
                        self.item[PidLidGlobalObjectId]:
                    calendar.delete(cal_item)
                cal_item = self.item.copy(calendar)
                self._init_calitem(cal_item, tentative)

        else:
            # preserve categories # TODO preserve everything unrelated?
            categories = cal_item.categories if cal_item else []

            # remove existing recurrence
            if cal_item and cal_item.recurring:
                mr_counter = self.update_counter
                cal_counter = cal_item.meetingrequest.update_counter
                if mr_counter is not None and cal_counter is not None and \
                   mr_counter <= cal_counter:
                    raise Error('trying to accept out-of-date meeting request')
                calendar.delete(cal_item)

            # determine existing exceptions
            goid = self.item.get_prop(PidLidCleanGlobalObjectId)
            if goid is not None:
                restriction = Restriction(SPropertyRestriction(
                    RELOP_EQ, goid.proptag,
                    SPropValue(goid.proptag, goid.mapiobj.Value))
                )
                existing_items = list(calendar.items(restriction))
                # TODO check php
                existing_items.sort(
                    key=lambda i: i.get(PidLidAppointmentStartWhole))
            else:
                existing_items = []

            # create new recurrence
            cal_item = self.item.copy(calendar)
            if categories:
                cal_item.categories = categories

            # merge existing exceptions
            if cal_item.recurring and existing_items:
                merge = True
                rec = cal_item.recurrence
                for item in existing_items:
                    if not rec._is_exception(item.meetingrequest.basedate):
                        rec._create_exception(
                            item.meetingrequest.basedate, item, merge=True)
                    # TODO else update..?

            calendar.delete(existing_items)

            self._init_calitem(cal_item, tentative, merge)

            # TODO why filter recipients?
            if merge or not add_bcc:
                table = cal_item.mapiobj.OpenProperty(
                    PR_MESSAGE_RECIPIENTS, IID_IMAPITable, MAPI_UNICODE, 0)
                table.SetColumns(RECIP_PROPS, 0)
                rows = table.QueryRows(2147483647, 0)
                cal_item.mapiobj.ModifyRecipients(MODRECIP_MODIFY, rows)
                _utils._save(cal_item.mapiobj)

        # add self as BCC for ZCP-9901 TODO still relevant?
        proptags = [
            PR_ACCOUNT_W,
            PR_ADDRTYPE_W,
            PR_DISPLAY_NAME_W,
            PR_DISPLAY_TYPE,
            PR_DISPLAY_TYPE_EX,
            PR_EMAIL_ADDRESS_W,
            PR_ENTRYID,
            PR_OBJECT_TYPE,
            PR_SEARCH_KEY,
            PR_SMTP_ADDRESS_W,
        ]
        user = self.item.store.user
        props = user.mapiobj.GetProps(proptags, 0)
        props.extend([
            SPropValue(PR_RECIPIENT_ENTRYID, props[6].Value),
            SPropValue(PR_RECIPIENT_FLAGS, (recipOriginal | recipSendable)),
            SPropValue(PR_RECIPIENT_TRACKSTATUS, 0),
            SPropValue(PR_RECIPIENT_TYPE, MAPI_BCC),
        ])
        if add_bcc and not merge:
            cal_item.mapiobj.ModifyRecipients(MODRECIP_ADD, [props])
            _utils._save(cal_item.mapiobj)

        # send response
        if response:
            if tentative:
                message_class = 'IPM.Schedule.Meeting.Resp.Tent'
            else:
                message_class = 'IPM.Schedule.Meeting.Resp.Pos'
            self._respond(subject_prefix, message_class)