Beispiel #1
0
    def _index_addresses(self, cfg, terms, vcard_addresses):
        existing = dict([(k['address'].lower(), k) for k in vcard_addresses])
        index = self._idx()

        # Figure out which tags are invisible so we can skip messages marked
        # with those tags.
        invisible = set([t._key for t in cfg.get_tags(flag_hides=True)])

        # 1st, go through the last 1000 or so messages in the index and search
        # for matching senders or recipients, give medium priority.
        matches = {}
        addresses = []
        for msg_idx in xrange(max(0,
                                  len(index.INDEX) - 2500), len(index.INDEX)):
            msg_info = index.get_msg_at_idx_pos(msg_idx)
            tags = set(msg_info[index.MSG_TAGS].split(','))
            frm = msg_info[index.MSG_FROM]
            match = not (tags & invisible)
            if match:
                for term in terms:
                    if term not in frm.lower():
                        match = False
            if match:
                matches[frm] = matches.get(frm, 0) + 1
            if len(matches) > 1000:
                break

        # FIXME: 2nd, search the social graph for matches, give low priority.
        for frm in index.EMAILS:
            match = True
            for term in terms:
                if term not in frm.lower():
                    match = False
            if match:
                matches[frm] = matches.get(frm, 0) + 1

        # Assign info & scores!
        for frm in matches:
            email, fn = ExtractEmailAndName(frm)

            boost = min(10, matches[frm])
            for term in terms:
                boost += self._boost_rank(term, fn, email)

            if not email or '@' not in email:
                # FIXME: This may not be the right thing for alternate
                #        message transports.
                pass
            elif email.lower() in existing:
                existing[email.lower()]['rank'] += min(20, boost)
            else:
                info = AddressInfo(email, fn)
                existing[email.lower()] = info
                addresses.append(info)

        return addresses
Beispiel #2
0
    def _index_addresses(self, cfg, terms, vcard_addresses):
        existing = dict([(k['address'].lower(), k) for k in vcard_addresses])
        index = self._idx()

        # Figure out which tags are invisible so we can skip messages marked
        # with those tags.
        invisible = set([t._key for t in cfg.get_tags(flag_hides=True)])

        # 1st, go through the last 1000 or so messages in the index and search
        # for matching senders or recipients, give medium priority.
        matches = {}
        addresses = []
        for msg_idx in xrange(max(0, len(index.INDEX)-2500), len(index.INDEX)):
            msg_info = index.get_msg_at_idx_pos(msg_idx)
            tags = set(msg_info[index.MSG_TAGS].split(','))
            frm = msg_info[index.MSG_FROM]
            match = not (tags & invisible)
            if match:
                for term in terms:
                    if term not in frm.lower():
                        match = False
            if match:
                matches[frm] = matches.get(frm, 0) + 1
            if len(matches) > 1000:
                break

        # FIXME: 2nd, search the social graph for matches, give low priority.
        for frm in index.EMAILS:
            match = True
            for term in terms:
                if term not in frm.lower():
                    match = False
            if match:
                matches[frm] = matches.get(frm, 0) + 1

        # Assign info & scores!
        for frm in matches:
            email, fn = ExtractEmailAndName(frm)

            boost = min(10, matches[frm])
            for term in terms:
                boost += self._boost_rank(term, fn, email)

            if not email or '@' not in email:
                # FIXME: This may not be the right thing for alternate
                #        message transports.
                pass
            elif email.lower() in existing:
                existing[email.lower()]['rank'] += min(20, boost)
            else:
                info = AddressInfo(email, fn)
                existing[email.lower()] = info
                addresses.append(info)

        return addresses
Beispiel #3
0
    def _msg_addresses(self,
                       msg_info=None,
                       addresses=[],
                       no_from=False,
                       no_to=False,
                       no_cc=False):
        cids = set()

        for ai in addresses:
            eid = self.idx.EMAIL_IDS.get(ai.address.lower())
            cids.add(b36(self.idx._add_email(ai.address, name=ai.fn, eid=eid)))

        if msg_info:
            if not no_to:
                to = [t for t in msg_info[MailIndex.MSG_TO].split(',') if t]
                cids |= set(to)
            if not no_cc:
                cc = [t for t in msg_info[MailIndex.MSG_CC].split(',') if t]
                cids |= set(cc)
            if not no_from:
                fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
                if fe:
                    eid = self.idx.EMAIL_IDS.get(fe.lower())
                    cids.add(b36(self.idx._add_email(fe, name=fn, eid=eid)))

        return sorted(list(cids))
Beispiel #4
0
    def _metadata(self, msg_info):
        import mailpile.urlmap
        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)
        um = mailpile.urlmap.UrlMap(self.session)
        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        expl = {
            'mid': msg_info[MailIndex.MSG_MID],
            'id': msg_info[MailIndex.MSG_ID],
            'from': {
                'name': fn,
                'email': fe,
            },
            'urls': {
                'thread': um.url_thread(msg_info[MailIndex.MSG_MID]),
            },
            'timestamp': msg_ts,
            'tag_tids': self._msg_tags(msg_info),
            'to_eids': self._msg_people(msg_info, no_from=True),
            'thread_mid': msg_info[MailIndex.MSG_CONV_MID],
            'subject': msg_info[MailIndex.MSG_SUBJECT],
            'body': {
                'snippet': msg_info[MailIndex.MSG_SNIPPET],
            },
            'flags': {
            }
        }

        # Support rich snippets
        if expl['body']['snippet'].startswith('{'):
            try:
                expl['body'] = json.loads(expl['body']['snippet'])
            except ValueError:
                pass

        # Misc flags
        if [e for e in self.idx.config.profiles
                    if e.email.lower() == fe.lower()]:
            expl['flags']['from_me'] = True;
        tag_types = [self.idx.config.get_tag(t).type for t in expl['tag_tids']]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl['flags'][self.TAG_TYPE_FLAG_MAP[t]] = True;

        # FIXME: Is message signed or encrypted?

        # Extra behavior for editable messages
        if 'draft' in expl['flags']:
            if self.idx.config.is_editable_message(msg_info):
                expl['urls']['editing'] = um.url_edit(expl['mid'])
            else:
                del expl['flags']['draft']

        return expl
Beispiel #5
0
    def _metadata(self, msg_info):
        import mailpile.urlmap

        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)
        um = mailpile.urlmap.UrlMap(self.session)
        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        fvcard = self.session.config.vcards.get_vcard(fe)
        expl = {
            "mid": msg_info[MailIndex.MSG_MID],
            "id": msg_info[MailIndex.MSG_ID],
            "from": AddressInfo(fe, fn, vcard=fvcard),
            "urls": {"thread": um.url_thread(msg_info[MailIndex.MSG_MID])},
            "timestamp": msg_ts,
            "tag_tids": self._msg_tags(msg_info),
            "to_eids": self._msg_people(msg_info, no_from=True),
            "thread_mid": msg_info[MailIndex.MSG_CONV_MID],
            "subject": msg_info[MailIndex.MSG_SUBJECT],
            "body": {"snippet": msg_info[MailIndex.MSG_SNIPPET]},
            "flags": {},
        }

        # Support rich snippets
        if expl["body"]["snippet"].startswith("{"):
            try:
                expl["body"] = json.loads(expl["body"]["snippet"])
            except ValueError:
                pass

        # Misc flags
        if [e for e in self.idx.config.profiles if e.email.lower() == fe.lower()]:
            expl["flags"]["from_me"] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl["tag_tids"]]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl["flags"][self.TAG_TYPE_FLAG_MAP[t]] = True

        # FIXME: Is message signed or encrypted?

        # Extra behavior for editable messages
        if "draft" in expl["flags"]:
            if self.idx.config.is_editable_message(msg_info):
                expl["urls"]["editing"] = um.url_edit(expl["mid"])
            else:
                del expl["flags"]["draft"]

        return expl
Beispiel #6
0
 def _msg_addresses(self, msg_info, no_from=False, no_to=False, no_cc=False):
     if no_to:
         cids = set()
     else:
         to = [t for t in msg_info[MailIndex.MSG_TO].split(",") if t]
         cids = set(to)
     if not no_cc:
         cc = [t for t in msg_info[MailIndex.MSG_CC].split(",") if t]
         cids |= set(cc)
     if not no_from:
         fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
         if fe:
             try:
                 cids.add(b36(self.idx.EMAIL_IDS[fe.lower()]))
             except KeyError:
                 cids.add(b36(self.idx._add_email(fe, name=fn)))
     return sorted(list(cids))
Beispiel #7
0
 def _msg_addresses(self, msg_info,
                    no_from=False, no_to=False, no_cc=False):
     if no_to:
         cids = set()
     else:
         to = [t for t in msg_info[MailIndex.MSG_TO].split(',') if t]
         cids = set(to)
     if not no_cc:
         cc = [t for t in msg_info[MailIndex.MSG_CC].split(',') if t]
         cids |= set(cc)
     if not no_from:
         fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
         if fe:
             try:
                 cids.add(b36(self.idx.EMAIL_IDS[fe.lower()]))
             except KeyError:
                 cids.add(b36(self.idx._add_email(fe, name=fn)))
     return sorted(list(cids))
Beispiel #8
0
    def _msg_addresses(self, msg_info=None, addresses=[], no_from=False, no_to=False, no_cc=False):
        cids = set()

        for ai in addresses:
            eid = self.idx.EMAIL_IDS.get(ai.address.lower())
            cids.add(b36(self.idx._add_email(ai.address, name=ai.fn, eid=eid)))

        if msg_info:
            if not no_to:
                to = [t for t in msg_info[MailIndex.MSG_TO].split(",") if t]
                cids |= set(to)
            if not no_cc:
                cc = [t for t in msg_info[MailIndex.MSG_CC].split(",") if t]
                cids |= set(cc)
            if not no_from:
                fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
                if fe:
                    eid = self.idx.EMAIL_IDS.get(fe.lower())
                    cids.add(b36(self.idx._add_email(fe, name=fn, eid=eid)))

        return sorted(list(cids))
Beispiel #9
0
    def _metadata(self, msg_info):
        msg_mid = msg_info[MailIndex.MSG_MID]
        if '-' in msg_mid:
            # Ephemeral...
            msg_idx = None
        else:
            msg_idx = int(msg_mid, 36)
            cache = self.idx.CACHE.get(msg_idx, {})
            if 'metadata' in cache:
                return cache['metadata']

        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)

        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        f_info = self._address(e=fe, n=fn)
        f_info['aid'] = (self._msg_addresses(msg_info, no_to=True, no_cc=True)
                         or [''])[0]
        thread_mid = parent_mid = msg_info[MailIndex.MSG_THREAD_MID]
        if '/' in thread_mid:
            thread_mid, parent_mid = thread_mid.split('/')
        expl = {
            'mid': msg_mid,
            'id': msg_info[MailIndex.MSG_ID],
            'timestamp': msg_ts,
            'from': f_info,
            'to_aids': self._msg_addresses(msg_info, no_from=True, no_cc=True),
            'cc_aids': self._msg_addresses(msg_info, no_from=True, no_to=True),
            'msg_kb': int(msg_info[MailIndex.MSG_KB], 36),
            'tag_tids': sorted(self._msg_tags(msg_info)),
            'thread_mid': thread_mid,
            'parent_mid': parent_mid,
            'subject': msg_info[MailIndex.MSG_SUBJECT],
            'body': MailIndex.get_body(msg_info),
            'flags': {},
            'crypto': {}
        }

        # Ephemeral messages do not have URLs
        if '-' in msg_info[MailIndex.MSG_MID]:
            expl['flags'].update({
                'ephemeral': True,
                'draft': True,
            })
        else:
            expl['urls'] = {
                'thread': self.urlmap.url_thread(msg_info[MailIndex.MSG_MID]),
                'source': self.urlmap.url_source(msg_info[MailIndex.MSG_MID]),
            }

        # Support rich snippets
        if expl['body']['snippet'].startswith('{'):
            try:
                expl['body'] = json.loads(expl['body']['snippet'])
            except ValueError:
                pass

        # Misc flags
        sender_vcard = self.idx.config.vcards.get_vcard(fe.lower())
        if sender_vcard:
            if sender_vcard.kind == 'profile':
                expl['flags']['from_me'] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl['tag_tids']]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl['flags'][self.TAG_TYPE_FLAG_MAP[t]] = True

        # Check tags for signs of encryption or signatures
        tag_slugs = [self.idx.config.get_tag(t).slug for t in expl['tag_tids']]
        for t in tag_slugs:
            if t.startswith('mp_sig'):
                expl['crypto']['signature'] = t[7:]
            elif t.startswith('mp_enc'):
                expl['crypto']['encryption'] = t[7:]

        # Extra behavior for editable messages
        if 'draft' in expl['flags']:
            if 'ephemeral' in expl['flags']:
                pass
            elif self.idx.config.is_editable_message(msg_info):
                expl['urls']['editing'] = self.urlmap.url_edit(expl['mid'])
            else:
                del expl['flags']['draft']

        if msg_idx is not None:
            cache['metadata'] = expl
            self.idx.CACHE[msg_idx] = cache
        return expl
Beispiel #10
0
    def _index_addresses(self, cfg, terms, vcard_addresses, count, deadline):
        existing = dict([(k['address'].lower(), k) for k in vcard_addresses])
        index = self._idx()

        # Figure out which tags are invisible so we can skip messages marked
        # with those tags.
        invisible = set([t._key for t in cfg.get_tags(flag_hides=True)])
        matches = {}
        addresses = []

        # 1st, search the social graph for matches, give low priority.
        for frm in index.EMAILS:
            frm_lower = frm.lower()
            match = True
            for term in terms:
                if term not in frm_lower:
                    match = False
                    break
            if match:
                matches[frm] = matches.get(frm, 0) + 3
                if len(matches) > (count * 10):
                    break
            elif len(matches) and time.time() > deadline:
                break

        # 2nd, go through at most the last 5000 messages in the index and
        # search for matching senders or recipients, give medium priority.
        # Note: This is more CPU intensive, so we do this last.
        if len(matches) < (count * 5):
            for msg_idx in xrange(max(0, len(index.INDEX)-5000),
                                  len(index.INDEX)):
                msg_info = index.get_msg_at_idx_pos(msg_idx)
                tags = set(msg_info[index.MSG_TAGS].split(','))
                match = not (tags & invisible)
                if match:
                    frm = msg_info[index.MSG_FROM]
                    search = (frm + ' ' + msg_info[index.MSG_SUBJECT]).lower()
                    for term in terms:
                        if term not in search:
                            match = False
                            break
                    if match:
                        matches[frm] = matches.get(frm, 0) + 1
                        if len(matches) > (count * 5):
                            break
                    if len(matches) and time.time() > deadline:
                        break

        # Assign info & scores!
        for frm in matches:
            email, fn = ExtractEmailAndName(frm)
            boost = min(10, matches[frm])
            for term in terms:
                boost += self._boost_rank(term, fn, email)

            if not email or '@' not in email:
                # FIXME: This may not be the right thing for alternate
                #        message transports.
                pass
            elif email.lower() in existing:
                existing[email.lower()]['rank'] += min(20, boost)
            else:
                info = AddressInfo(email, fn)
                existing[email.lower()] = info
                addresses.append(info)

        return addresses
Beispiel #11
0
    def _index_addresses(self, cfg, terms, vcard_addresses, count, deadline):
        existing = dict([(k['address'].lower(), k) for k in vcard_addresses])
        index = self._idx()

        # Figure out which tags are invisible so we can skip messages marked
        # with those tags.
        invisible = set([t._key for t in cfg.get_tags(flag_hides=True)])
        matches = {}
        addresses = []

        # 1st, search the social graph for matches, give low priority.
        for frm in index.EMAILS:
            frm_lower = frm.lower()
            match = True
            for term in terms:
                if term not in frm_lower:
                    match = False
                    break
            if match:
                matches[frm] = matches.get(frm, 0) + 3
                if len(matches) > (count * 10):
                    break
            elif len(matches) and time.time() > deadline:
                break

        # 2nd, go through at most the last 5000 messages in the index and
        # search for matching senders or recipients, give medium priority.
        # Note: This is more CPU intensive, so we do this last.
        if len(matches) < (count * 5):
            for msg_idx in xrange(max(0,
                                      len(index.INDEX) - 5000),
                                  len(index.INDEX)):
                msg_info = index.get_msg_at_idx_pos(msg_idx)
                tags = set(msg_info[index.MSG_TAGS].split(','))
                match = not (tags & invisible)
                if match:
                    frm = msg_info[index.MSG_FROM]
                    search = (frm + ' ' + msg_info[index.MSG_SUBJECT]).lower()
                    for term in terms:
                        if term not in search:
                            match = False
                            break
                    if match:
                        matches[frm] = matches.get(frm, 0) + 1
                        if len(matches) > (count * 5):
                            break
                    if len(matches) and time.time() > deadline:
                        break

        # Assign info & scores!
        for frm in matches:
            email, fn = ExtractEmailAndName(frm)
            boost = min(10, matches[frm])
            for term in terms:
                boost += self._boost_rank(term, fn, email)

            if not email or '@' not in email:
                # FIXME: This may not be the right thing for alternate
                #        message transports.
                pass
            elif email.lower() in existing:
                existing[email.lower()]['rank'] += min(20, boost)
            else:
                info = AddressInfo(email, fn)
                existing[email.lower()] = info
                addresses.append(info)

        return addresses
Beispiel #12
0
    def _metadata(self, msg_info):
        import mailpile.urlmap

        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)
        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        expl = {
            "mid": msg_info[MailIndex.MSG_MID],
            "id": msg_info[MailIndex.MSG_ID],
            "timestamp": msg_ts,
            "from": {"email": fe, "fn": fn, "aid": (self._msg_addresses(msg_info, no_to=True, no_cc=True) or [""])[0]},
            "to_aids": self._msg_addresses(msg_info, no_from=True, no_cc=True),
            "cc_aids": self._msg_addresses(msg_info, no_from=True, no_to=True),
            "msg_kb": int(msg_info[MailIndex.MSG_KB], 36),
            "tag_tids": self._msg_tags(msg_info),
            "thread_mid": msg_info[MailIndex.MSG_THREAD_MID],
            "subject": msg_info[MailIndex.MSG_SUBJECT],
            "body": {"snippet": msg_info[MailIndex.MSG_BODY]},
            "flags": {},
            "crypto": {},
        }

        # Ephemeral messages do not have URLs
        if ":" not in msg_info[MailIndex.MSG_MID]:
            expl["urls"] = {
                "thread": self.urlmap.url_thread(msg_info[MailIndex.MSG_MID]),
                "source": self.urlmap.url_source(msg_info[MailIndex.MSG_MID]),
            }
        else:
            expl["flags"]["ephemeral"] = True

        # Support rich snippets
        if expl["body"]["snippet"].startswith("{"):
            try:
                expl["body"] = json.loads(expl["body"]["snippet"])
            except ValueError:
                pass

        # Misc flags
        if [e for e in self.idx.config.profiles if (e.email.lower() == fe.lower())]:
            expl["flags"]["from_me"] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl["tag_tids"]]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl["flags"][self.TAG_TYPE_FLAG_MAP[t]] = True

        # Check tags for signs of encryption or signatures
        tag_slugs = [self.idx.config.get_tag(t).slug for t in expl["tag_tids"]]
        for t in tag_slugs:
            if t.startswith("mp_sig"):
                expl["crypto"]["signature"] = t[7:]
            elif t.startswith("mp_enc"):
                expl["crypto"]["encryption"] = t[7:]

        # Extra behavior for editable messages
        if "draft" in expl["flags"]:
            if self.idx.config.is_editable_message(msg_info):
                expl["urls"]["editing"] = self.urlmap.url_edit(expl["mid"])
            else:
                del expl["flags"]["draft"]

        return expl
Beispiel #13
0
    def _metadata(self, msg_info):
        import mailpile.urlmap
        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)
        um = mailpile.urlmap.UrlMap(self.session)
        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        expl = {
            'mid': msg_info[MailIndex.MSG_MID],
            'id': msg_info[MailIndex.MSG_ID],
            'timestamp': msg_ts,
            'from': {
                'email': fe,
                'fn': fn,
                'aid': (self._msg_addresses(msg_info, no_to=True, no_cc=True)
                        or [''])[0],
            },
            'to_aids': self._msg_addresses(msg_info, no_from=True, no_cc=True),
            'cc_aids': self._msg_addresses(msg_info, no_from=True, no_to=True),
            'msg_kb': int(msg_info[MailIndex.MSG_KB], 36),
            'tag_tids': self._msg_tags(msg_info),
            'thread_mid': msg_info[MailIndex.MSG_THREAD_MID],
            'subject': msg_info[MailIndex.MSG_SUBJECT],
            'body': {
                'snippet': msg_info[MailIndex.MSG_BODY],
            },
            'flags': {
            },
            'crypto': {
            }
        }

        # Ephemeral messages do not have URLs
        if ':' not in msg_info[MailIndex.MSG_MID]:
            expl['urls'] = {
                'thread': um.url_thread(msg_info[MailIndex.MSG_MID]),
                'source': um.url_source(msg_info[MailIndex.MSG_MID]),
            }
        else:
            expl['flags']['ephemeral'] = True

        # Support rich snippets
        if expl['body']['snippet'].startswith('{'):
            try:
                expl['body'] = json.loads(expl['body']['snippet'])
            except ValueError:
                pass

        # Misc flags
        if [e for e in self.idx.config.profiles if (e.email.lower()
                                                    == fe.lower())]:
            expl['flags']['from_me'] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl['tag_tids']]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl['flags'][self.TAG_TYPE_FLAG_MAP[t]] = True

        # Check tags for signs of encryption or signatures
        tag_slugs = [self.idx.config.get_tag(t).slug for t in expl['tag_tids']]
        for t in tag_slugs:
            if t.startswith('mp_sig'):
                expl['crypto']['signature'] = t[7:]
            elif t.startswith('mp_enc'):
                expl['crypto']['encryption'] = t[7:]

        # Extra behavior for editable messages
        if 'draft' in expl['flags']:
            if self.idx.config.is_editable_message(msg_info):
                expl['urls']['editing'] = um.url_edit(expl['mid'])
            else:
                del expl['flags']['draft']

        return expl
Beispiel #14
0
    def _metadata(self, msg_info):
        msg_mid = msg_info[MailIndex.MSG_MID]
        if "-" in msg_mid:
            # Ephemeral...
            msg_idx = None
        else:
            msg_idx = int(msg_mid, 36)
            cache = self.idx.CACHE.get(msg_idx, {})
            if "metadata" in cache:
                return cache["metadata"]

        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)

        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        f_info = self._address(e=fe, n=fn)
        f_info["aid"] = (self._msg_addresses(msg_info, no_to=True, no_cc=True) or [""])[0]
        thread_mid = parent_mid = msg_info[MailIndex.MSG_THREAD_MID]
        if "/" in thread_mid:
            thread_mid, parent_mid = thread_mid.split("/")
        expl = {
            "mid": msg_mid,
            "id": msg_info[MailIndex.MSG_ID],
            "timestamp": msg_ts,
            "from": f_info,
            "to_aids": self._msg_addresses(msg_info, no_from=True, no_cc=True),
            "cc_aids": self._msg_addresses(msg_info, no_from=True, no_to=True),
            "msg_kb": int(msg_info[MailIndex.MSG_KB], 36),
            "tag_tids": sorted(self._msg_tags(msg_info)),
            "thread_mid": thread_mid,
            "parent_mid": parent_mid,
            "subject": msg_info[MailIndex.MSG_SUBJECT],
            "body": MailIndex.get_body(msg_info),
            "flags": {},
            "crypto": {},
        }

        # Ephemeral messages do not have URLs
        if "-" in msg_info[MailIndex.MSG_MID]:
            expl["flags"].update({"ephemeral": True, "draft": True})
        else:
            expl["urls"] = {
                "thread": self.urlmap.url_thread(msg_info[MailIndex.MSG_MID]),
                "source": self.urlmap.url_source(msg_info[MailIndex.MSG_MID]),
            }

        # Support rich snippets
        if expl["body"]["snippet"].startswith("{"):
            try:
                expl["body"] = json.loads(expl["body"]["snippet"])
            except ValueError:
                pass

        # Misc flags
        sender_vcard = self.idx.config.vcards.get_vcard(fe.lower())
        if sender_vcard:
            if sender_vcard.kind == "profile":
                expl["flags"]["from_me"] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl["tag_tids"]]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl["flags"][self.TAG_TYPE_FLAG_MAP[t]] = True

        # Check tags for signs of encryption or signatures
        tag_slugs = [self.idx.config.get_tag(t).slug for t in expl["tag_tids"]]
        for t in tag_slugs:
            if t.startswith("mp_sig"):
                expl["crypto"]["signature"] = t[7:]
            elif t.startswith("mp_enc"):
                expl["crypto"]["encryption"] = t[7:]

        # Extra behavior for editable messages
        if "draft" in expl["flags"]:
            if "ephemeral" in expl["flags"]:
                pass
            elif self.idx.config.is_editable_message(msg_info):
                expl["urls"]["editing"] = self.urlmap.url_edit(expl["mid"])
            else:
                del expl["flags"]["draft"]

        if msg_idx is not None:
            cache["metadata"] = expl
            self.idx.CACHE[msg_idx] = cache
        return expl
Beispiel #15
0
    def _metadata(self, msg_info):
        import mailpile.urlmap
        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)
        um = mailpile.urlmap.UrlMap(self.session)
        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        expl = {
            'mid': msg_info[MailIndex.MSG_MID],
            'id': msg_info[MailIndex.MSG_ID],
            'timestamp': msg_ts,
            'from': {
                'email':
                fe,
                'fn':
                fn,
                'aid': (self._msg_addresses(msg_info, no_to=True, no_cc=True)
                        or [''])[0],
            },
            'to_aids': self._msg_addresses(msg_info, no_from=True, no_cc=True),
            'cc_aids': self._msg_addresses(msg_info, no_from=True, no_to=True),
            'msg_kb': int(msg_info[MailIndex.MSG_KB], 36),
            'tag_tids': self._msg_tags(msg_info),
            'thread_mid': msg_info[MailIndex.MSG_THREAD_MID],
            'subject': msg_info[MailIndex.MSG_SUBJECT],
            'body': {
                'snippet': msg_info[MailIndex.MSG_BODY],
            },
            'flags': {},
            'crypto': {}
        }

        # Ephemeral messages do not have URLs
        if ':' not in msg_info[MailIndex.MSG_MID]:
            expl['urls'] = {
                'thread': um.url_thread(msg_info[MailIndex.MSG_MID]),
                'source': um.url_source(msg_info[MailIndex.MSG_MID]),
            }
        else:
            expl['flags']['ephemeral'] = True

        # Support rich snippets
        if expl['body']['snippet'].startswith('{'):
            try:
                expl['body'] = json.loads(expl['body']['snippet'])
            except ValueError:
                pass

        # Misc flags
        if [
                e for e in self.idx.config.profiles
                if (e.email.lower() == fe.lower())
        ]:
            expl['flags']['from_me'] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl['tag_tids']]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl['flags'][self.TAG_TYPE_FLAG_MAP[t]] = True

        # Check tags for signs of encryption or signatures
        tag_slugs = [self.idx.config.get_tag(t).slug for t in expl['tag_tids']]
        for t in tag_slugs:
            if t.startswith('mp_sig'):
                expl['crypto']['signature'] = t[7:]
            elif t.startswith('mp_enc'):
                expl['crypto']['encryption'] = t[7:]

        # Extra behavior for editable messages
        if 'draft' in expl['flags']:
            if self.idx.config.is_editable_message(msg_info):
                expl['urls']['editing'] = um.url_edit(expl['mid'])
            else:
                del expl['flags']['draft']

        return expl
Beispiel #16
0
    def _metadata(self, msg_info):
        msg_mid = msg_info[MailIndex.MSG_MID]
        if '-' in msg_mid:
            # Ephemeral...
            msg_idx = None
        else:
            msg_idx = int(msg_mid, 36)
            cache = self.idx.CACHE.get(msg_idx, {})
            if 'metadata' in cache:
                return cache['metadata']

        nz = lambda l: [v for v in l if v]
        msg_ts = long(msg_info[MailIndex.MSG_DATE], 36)
        msg_date = datetime.datetime.fromtimestamp(msg_ts)

        fe, fn = ExtractEmailAndName(msg_info[MailIndex.MSG_FROM])
        f_info = self._address(e=fe, n=fn)
        f_info['aid'] = (self._msg_addresses(msg_info, no_to=True, no_cc=True)
                         or [''])[0]
        thread_mid = parent_mid = msg_info[MailIndex.MSG_THREAD_MID]
        if '/' in thread_mid:
            thread_mid, parent_mid = thread_mid.split('/')
        expl = {
            'mid': msg_mid,
            'id': msg_info[MailIndex.MSG_ID],
            'timestamp': msg_ts,
            'from': f_info,
            'to_aids': self._msg_addresses(msg_info, no_from=True, no_cc=True),
            'cc_aids': self._msg_addresses(msg_info, no_from=True, no_to=True),
            'msg_kb': int(msg_info[MailIndex.MSG_KB], 36),
            'tag_tids': sorted(self._msg_tags(msg_info)),
            'thread_mid': thread_mid,
            'parent_mid': parent_mid,
            'subject': msg_info[MailIndex.MSG_SUBJECT],
            'body': MailIndex.get_body(msg_info),
            'flags': {
            },
            'crypto': {
            }
        }

        # Ephemeral messages do not have URLs
        if '-' in msg_info[MailIndex.MSG_MID]:
            expl['flags'].update({
                'ephemeral': True,
                'draft': True,
            })
        else:
            expl['urls'] = {
                'thread': self.urlmap.url_thread(msg_info[MailIndex.MSG_MID]),
                'source': self.urlmap.url_source(msg_info[MailIndex.MSG_MID]),
            }

        # Support rich snippets
        if expl['body']['snippet'].startswith('{'):
            try:
                expl['body'] = json.loads(expl['body']['snippet'])
            except ValueError:
                pass

        # Misc flags
        sender_vcard = self.idx.config.vcards.get_vcard(fe.lower())
        if sender_vcard:
            if sender_vcard.kind == 'profile':
                expl['flags']['from_me'] = True
        tag_types = [self.idx.config.get_tag(t).type for t in expl['tag_tids']]
        for t in self.TAG_TYPE_FLAG_MAP:
            if t in tag_types:
                expl['flags'][self.TAG_TYPE_FLAG_MAP[t]] = True

        # Check tags for signs of encryption or signatures
        tag_slugs = [self.idx.config.get_tag(t).slug for t in expl['tag_tids']]
        for t in tag_slugs:
            if t.startswith('mp_sig'):
                expl['crypto']['signature'] = t[7:]
            elif t.startswith('mp_enc'):
                expl['crypto']['encryption'] = t[7:]

        # Extra behavior for editable messages
        if 'draft' in expl['flags']:
            if 'ephemeral' in expl['flags']:
                pass
            elif self.idx.config.is_editable_message(msg_info):
                expl['urls']['editing'] = self.urlmap.url_edit(expl['mid'])
            else:
                del expl['flags']['draft']

        if msg_idx is not None:
            cache['metadata'] = expl
            self.idx.CACHE[msg_idx] = cache
        return expl