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
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
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))
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
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
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))
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))
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))
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
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
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
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
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
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
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
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