<commit_before>#!/usr/bin/python
#
# Basic user-interface stuff
#
import datetime
import re
import sys

from mailpile.util import *
from lxml.html.clean import autolink_html


class NullUI(object):

  WIDTH = 80
  interactive = False
  buffering = False

  def __init__(self):
    self.buffered = []

  def print_key(self, key, config): pass
  def reset_marks(self, quiet=False): pass
  def mark(self, progress): pass

  def clear(self):
    self.buffered = []

  def flush(self):
    while len(self.buffered) > 0:
      self.buffered.pop(0)()

  def block(self):
    self.buffering = True

  def unblock(self):
    self.flush()
    self.buffering = False

  def say(self, text='', newline='\n', fd=sys.stdout):
    if not fd:
      fd = sys.stdout
    def sayit():
      fd.write(text.encode('utf-8')+newline)
      fd.flush()
    self.buffered.append(sayit)
    if not self.buffering:
      self.flush()

  def notify(self, message):
    self.say('%s%s' % (message, ' ' * (self.WIDTH-1-len(message))))
  def warning(self, message):
    self.say('Warning: %s%s' % (message, ' ' * (self.WIDTH-11-len(message))))
  def error(self, message):
    self.say('Error: %s%s' % (message, ' ' * (self.WIDTH-9-len(message))))

  def print_intro(self, help=False, http_worker=None):
    if http_worker:
      http_status = 'on: http://%s:%s/' % http_worker.httpd.sspec
    else:
      http_status = 'disabled.'
    self.say('\n'.join([ABOUT,
                        'The web interface is %s' % http_status,
                        '',
                        'For instructions type `help`, press <CTRL-D> to quit.',
                        '']))

  def print_help(self, commands, tags=None, index=None):
    self.say('Commands:')
    last_rank = None
    cmds = commands.keys()
    cmds.sort(key=lambda k: commands[k][3])
    for c in cmds:
      cmd, args, explanation, rank = commands[c]
      if not rank: continue

      if last_rank and int(rank/10) != last_rank: self.say()
      last_rank = int(rank/10)

      self.say('    %s|%-8.8s %-15.15s %s' % (c[0], cmd.replace('=', ''),
                                              args and ('<%s>' % args) or '',
                                              explanation))
    if tags and index:
      self.say('\nTags:  (use a tag as a command to display tagged messages)',
               '\n  ')
      tkeys = tags.keys()
      tkeys.sort(key=lambda k: tags[k])
      wrap = int(self.WIDTH / 23)
      for i in range(0, len(tkeys)):
        tid = tkeys[i]
        self.say(('%5.5s %-18.18s'
                  ) % ('%s' % (int(index.STATS.get(tid, [0, 0])[1]) or ''),
                       tags[tid]),
                 newline=(i%wrap)==(wrap-1) and '\n  ' or '')
    self.say('\n')

  def print_filters(self, config):
    w = int(self.WIDTH * 23/80)
    ffmt = ' %%3.3s %%-%d.%ds %%-%d.%ds %%s' % (w, w, w-2, w-2)
    self.say(ffmt % ('ID', ' Tags', 'Terms', ''))
    for fid, terms, tags, comment in config.get_filters(filter_on=None):
      self.say(ffmt % (
        fid,
        ' '.join(['%s%s' % (t[0], config['tag'][t[1:]]) for t in tags.split()]),
        ((terms == '*') and '(all new mail)' or
         (terms == '@read') and '(read mail)' or terms or '(none)'),
        comment or '(none)'
      ))

  def display_messages(self, emails,
                       raw=False, sep='', fd=sys.stdout, context=True):
    for email in emails:
      if raw:
        self.display_message(email, None, raw=True, sep=sep, fd=fd)
      else:
        tree = email.get_message_tree()
        if context:
          conversation = [int(m[0], 36) for m in tree['conversation']]
          self.display_results(email.index, conversation or [email.index], [],
                               expand=[email], fd=fd)
        else:
          email.evaluate_pgp(tree)
          self.display_message(email, tree, raw=raw, sep=sep, fd=fd)

  def display_message(self, email, tree, raw=False, sep='', fd=None):
    if raw:
      self.say(sep, fd=fd)
      for line in email.get_file().readlines():
        try:
          line = line.decode('utf-8')
        except UnicodeDecodeError:
          try:
            line = line.decode('iso-8859-1')
          except:
            line = '(MAILPILE DECODING FAILED)\n'
        self.say(line, newline='', fd=fd)<commit_msg>Fix crasher when rendering messages with bogus conversation details<commit_after>#!/usr/bin/python
#
# Basic user-interface stuff
#
import datetime
import re
import sys

from mailpile.util import *
from lxml.html.clean import autolink_html


class NullUI(object):

  WIDTH = 80
  interactive = False
  buffering = False

  def __init__(self):
    self.buffered = []

  def print_key(self, key, config): pass
  def reset_marks(self, quiet=False): pass
  def mark(self, progress): pass

  def clear(self):
    self.buffered = []

  def flush(self):
    while len(self.buffered) > 0:
      self.buffered.pop(0)()

  def block(self):
    self.buffering = True

  def unblock(self):
    self.flush()
    self.buffering = False

  def say(self, text='', newline='\n', fd=sys.stdout):
    if not fd:
      fd = sys.stdout
    def sayit():
      fd.write(text.encode('utf-8')+newline)
      fd.flush()
    self.buffered.append(sayit)
    if not self.buffering:
      self.flush()

  def notify(self, message):
    self.say('%s%s' % (message, ' ' * (self.WIDTH-1-len(message))))
  def warning(self, message):
    self.say('Warning: %s%s' % (message, ' ' * (self.WIDTH-11-len(message))))
  def error(self, message):
    self.say('Error: %s%s' % (message, ' ' * (self.WIDTH-9-len(message))))

  def print_intro(self, help=False, http_worker=None):
    if http_worker:
      http_status = 'on: http://%s:%s/' % http_worker.httpd.sspec
    else:
      http_status = 'disabled.'
    self.say('\n'.join([ABOUT,
                        'The web interface is %s' % http_status,
                        '',
                        'For instructions type `help`, press <CTRL-D> to quit.',
                        '']))

  def print_help(self, commands, tags=None, index=None):
    self.say('Commands:')
    last_rank = None
    cmds = commands.keys()
    cmds.sort(key=lambda k: commands[k][3])
    for c in cmds:
      cmd, args, explanation, rank = commands[c]
      if not rank: continue

      if last_rank and int(rank/10) != last_rank: self.say()
      last_rank = int(rank/10)

      self.say('    %s|%-8.8s %-15.15s %s' % (c[0], cmd.replace('=', ''),
                                              args and ('<%s>' % args) or '',
                                              explanation))
    if tags and index:
      self.say('\nTags:  (use a tag as a command to display tagged messages)',
               '\n  ')
      tkeys = tags.keys()
      tkeys.sort(key=lambda k: tags[k])
      wrap = int(self.WIDTH / 23)
      for i in range(0, len(tkeys)):
        tid = tkeys[i]
        self.say(('%5.5s %-18.18s'
                  ) % ('%s' % (int(index.STATS.get(tid, [0, 0])[1]) or ''),
                       tags[tid]),
                 newline=(i%wrap)==(wrap-1) and '\n  ' or '')
    self.say('\n')

  def print_filters(self, config):
    w = int(self.WIDTH * 23/80)
    ffmt = ' %%3.3s %%-%d.%ds %%-%d.%ds %%s' % (w, w, w-2, w-2)
    self.say(ffmt % ('ID', ' Tags', 'Terms', ''))
    for fid, terms, tags, comment in config.get_filters(filter_on=None):
      self.say(ffmt % (
        fid,
        ' '.join(['%s%s' % (t[0], config['tag'][t[1:]]) for t in tags.split()]),
        ((terms == '*') and '(all new mail)' or
         (terms == '@read') and '(read mail)' or terms or '(none)'),
        comment or '(none)'
      ))

  def display_messages(self, emails,
                       raw=False, sep='', fd=sys.stdout, context=True):
    for email in emails:
      if raw:
        self.display_message(email, None, raw=True, sep=sep, fd=fd)
      else:
        tree = email.get_message_tree()
        if context:
          try:
            try:
              conversation = [int(m[0], 36) for m in tree['conversation']]
            except TypeError:
              conversation = [email.msg_idx]
            self.display_results(email.index,  conversation, [],
                                 expand=[email], fd=fd)
          except TypeError:
            self.warning('No conversation, bad ID: %s' % email.msg_idx)
        else:
          email.evaluate_pgp(tree)
          self.display_message(email, tree, raw=raw, sep=sep, fd=fd)

  def display_message(self, email, tree, raw=False, sep='', fd=None):
    if raw:
      self.say(sep, fd=fd)
      for line in email.get_file().readlines():
        try:
          line = line.decode('utf-8')
        except UnicodeDecodeError:
          try:
            line = line.decode('iso-8859-1')
          except:
            line = '(MAILPILE DECODING FAILED)\n'
        self.say(line, newline='', fd=fd)
{'fraction_non_alphanumeric': 0.1632491220120086, 'fraction_numerical': 0.012008609946754277, 'mean_word_length': 2.108450704225352, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7609063', 'n_tokens_mistral': 3039, 'n_tokens_neox': 2923, 'n_words': 705}