import email.policy
import html
import mailbox
+from urllib.parse import parse_qs
# for diff preparation:
# normalize whitespace sequences to single space, for when people reply from
if last_line.lstrip().startswith('On ') and last_line.rstrip().endswith(':'):
# Check if next block is quote
check_pos = self.start_pos_orig + self.length_orig
- print('######## LOOKS LIKE QUOTE: <<'+last_line+'>>')
+ #print('######## LOOKS LIKE QUOTE: <<'+last_line+'>>')
while check_pos < len(self.message.lines.lines):
if self.message.lines.lines[check_pos].real_quote:
# is real quote, strip last line
self.length_orig -= 1
- print(' IS QUOTE!')
+ #print(' IS QUOTE!')
break
if not self.message.lines.lines[check_pos].empty:
break
self.ranges.append(r)
def import_rangeset(self, other_ranges):
- print('import_rangeset()')
- print(' own ranges:')
- for r in self.ranges:
- print(' '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+' '+('quote' if r.is_quote else 'new'))
- print(' import ranges:')
- for r in other_ranges:
- print(' '+str(r.pos_parent))
+ #print('import_rangeset()')
+ #print(' own ranges:')
+ #for r in self.ranges:
+ # print(' '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+' '+('quote' if r.is_quote else 'new'))
+ #print(' import ranges:')
+ #for r in other_ranges:
+ # print(' '+str(r.pos_parent))
own_i = 0
for other_range in other_ranges:
- print('importing element with pos_parent='+str(other_range.pos_parent))
+ #print('importing element with pos_parent='+str(other_range.pos_parent))
while own_i != len(self.ranges) and other_range.pos_parent >= self.ranges[own_i].end_pos_child():
own_i += 1
if other_range.pos_parent == -1:
other_range.move_up_after(self.ranges[own_i-1])
self.ranges.insert(own_i, other_range)
- print(' own ranges after:')
- for r in self.ranges:
- print(' '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+' '+('quote' if r.is_quote else 'new')+' '+r.meta_origin_str())
+ #print(' own ranges after:')
+ #for r in self.ranges:
+ # print(' '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+' '+('quote' if r.is_quote else 'new')+' '+r.meta_origin_str())
def drop_quotes(self):
self.ranges = list(filter(lambda r: not r.is_quote, self.ranges))
child.dump_tree(level+1, topic_only)
def init_diff_recursively(self):
- print('init_diff_recursively')
+ #print('init_diff_recursively')
if self.is_diff_root():
self.blocks = TextBlockRangeset()
self.blocks.append(TextBlockRange(self, 0, len(self.lines.lines), -1, False))
for block in child.blocks.ranges:
all_child_blocks.append(block)
all_child_blocks.sort(key=lambda block:block.pos_parent)
- print('importing for '+self.id+' from '+self.from_hdr)
+ #print('importing for '+self.id+' from '+self.from_hdr)
self.blocks.import_rangeset(all_child_blocks)
self.blocks.drop_quotes()
# only do this for diff roots, at the end
self.blocks.trim_blocks()
-mbox = mailbox.mbox('t.mbox', factory=lambda x: email.message_from_binary_file(x, policy=email.policy.default))
-root_message = None
-messages_by_id = {}
-all_messages = []
-all_topic_roots = []
-message_index = 0
-for msg in mbox:
- tmsg = ThreadMessage(msg, message_index)
- message_index += 1
- messages_by_id[tmsg.id] = tmsg
- #print('have message "'+tmsg.id+'"')
- all_messages.append(tmsg)
- if tmsg.parent_id == None:
- if root_message != None:
- raise Exception('more than one root message')
- root_message = tmsg
- if tmsg.parent_id == None or tmsg.is_patch:
- all_topic_roots.append(tmsg)
-
-if root_message == None:
- raise Exception('no root message')
-
-for tmsg in all_messages:
- #print('looking up message "'+tmsg.parent_id+'"')
- if not tmsg.parent_id:
- continue
- if not tmsg.parent_id in messages_by_id:
- raise Exception('missing intermediate message')
- parent_tmsg = messages_by_id[tmsg.parent_id]
- tmsg.parent = parent_tmsg
- parent_tmsg.children.append(tmsg)
+def parse_mbox():
+ mbox = mailbox.mbox('t.mbox', factory=lambda x: email.message_from_binary_file(x, policy=email.policy.default))
+ root_message = None
+ messages_by_id = {}
+ all_messages = []
+ all_topic_roots = []
+ message_index = 0
+ for msg in mbox:
+ tmsg = ThreadMessage(msg, message_index)
+ message_index += 1
+ messages_by_id[tmsg.id] = tmsg
+ #print('have message "'+tmsg.id+'"')
+ all_messages.append(tmsg)
+ if tmsg.parent_id == None:
+ if root_message != None:
+ raise Exception('more than one root message')
+ root_message = tmsg
+ if tmsg.parent_id == None or tmsg.is_patch:
+ all_topic_roots.append(tmsg)
+
+ if root_message == None:
+ raise Exception('no root message')
+
+ for tmsg in all_messages:
+ #print('looking up message "'+tmsg.parent_id+'"')
+ if not tmsg.parent_id:
+ continue
+ if not tmsg.parent_id in messages_by_id:
+ raise Exception('missing intermediate message')
+ parent_tmsg = messages_by_id[tmsg.parent_id]
+ tmsg.parent = parent_tmsg
+ parent_tmsg.children.append(tmsg)
+
+ root_message.init_diff_recursively()
+ return all_topic_roots
# note: theoretically we can have loops in the "tree" at this point, but they'd
# have to be unreachable from the root, so, meh, whatever
#root_message.dump_tree(0, False)
-root_message.init_diff_recursively()
#messages_by_id['<20240827143852.163123189@linuxfoundation.org>'].init_diff_recursively()
#for topic in all_topic_roots:
# print('TOPIC: '+topic.msg.get('subject', ''))
# print('')
-print('<<<<<<')
+#print('<<<<<<')
#print(messages_by_id['<20240827143852.163123189@linuxfoundation.org>'].blocks.get_formatted())
-print(root_message.blocks.get_formatted())
-print('>>>>>>')
+#print(root_message.blocks.get_formatted())
+#print('>>>>>>')
#messages_by_id['<20240827143852.163123189@linuxfoundation.org>'].blocks.dump_meta()
-root_message.blocks.dump_meta()
-
-
-with open('/tmp/lkml-out.html', 'wt') as outfile:
- outfile.write('<!DOCTYPE html>\n')
- outfile.write('<html>\n')
- outfile.write(' <head>\n')
- outfile.write(' <title>Mehlbrei</title>\n')
- outfile.write(' <style>\n')
- outfile.write(' html {height: 100%;width:100%;margin:0px;}\n')
- outfile.write(' body {display: flex;height: 100%;width:100%;margin:0px;}\n')
- outfile.write(' #topic_panel {height: 100%; overflow:scroll;flex-shrink:0;}\n')
- outfile.write(' #main_panel {height: 100%; overflow:scroll;flex-grow:2;}\n')
- outfile.write(' .topic_link {display:block;}\n')
- outfile.write(' .empty-topic {opacity: 0.5;}\n')
- outfile.write(' .alt-content {display:none;}\n')
- outfile.write(' :target.alt-content {display:block;}\n')
- outfile.write(' .message-block-container {border: 1px solid black;}\n')
- outfile.write(' .message-block-meta {font-style: italic; font-weight: bolder;}\n')
- outfile.write(' .message-block-content {white-space: pre;}\n')
- outfile.write(' </style>\n')
- outfile.write(' </head>\n')
- outfile.write(' <body>\n')
- outfile.write(' <div id="topic_panel">\n')
- outfile.write(' <h1>Topics</h1>\n')
+#root_message.blocks.dump_meta()
+
+def app(environ, start_response):
+ out = []
+ query = parse_qs(environ.get('QUERY_STRING', ''))
+ msgid = query.get('msgid', None)
+
+ all_topic_roots = parse_mbox()
+
+ out.append('<!DOCTYPE html>')
+ out.append('<html>')
+ out.append(' <head>')
+ out.append(' <title>Mehlbrei</title>')
+ out.append(' <style>')
+ out.append(' html {height: 100%;width:100%;margin:0px;}')
+ out.append(' body {display: flex;height: 100%;width:100%;margin:0px;}')
+ out.append(' #topic_panel {height: 100%; overflow:scroll;flex-shrink:0;}')
+ out.append(' #main_panel {height: 100%; overflow:scroll;flex-grow:2;}')
+ out.append(' .topic_link {display:block;}')
+ out.append(' .empty-topic {opacity: 0.5;}')
+ out.append(' .alt-content {display:none;}')
+ out.append(' :target.alt-content {display:block;}')
+ out.append(' .message-block-container {border: 1px solid black;}')
+ out.append(' .message-block-meta {font-style: italic; font-weight: bolder;}')
+ out.append(' .message-block-content {white-space: pre;}')
+ out.append(' </style>')
+ out.append(' </head>')
+ out.append(' <body>')
+ out.append(' <div id="topic_panel">')
+ out.append(' <h1>Topics</h1>')
for topic_root in all_topic_roots:
- outfile.write(' <span class="topic_link'+(' empty-topic' if topic_root.non_diff_root_descendants == 0 else '')+'"><a href="#topic-'+str(topic_root.index)+'">'+html.escape(topic_root.msg.get('subject', '<no subject>'), quote=False)+'</a> ('+str(topic_root.non_diff_root_descendants)+' replies)</span>\n')
- outfile.write(' </div>\n')
- outfile.write(' <div id="main_panel">\n')
+ out.append(' <span class="topic_link'+(' empty-topic' if topic_root.non_diff_root_descendants == 0 else '')+'"><a href="#topic-'+str(topic_root.index)+'">'+html.escape(topic_root.msg.get('subject', '<no subject>'), quote=False)+'</a> ('+str(topic_root.non_diff_root_descendants)+' replies)</span>')
+ out.append(' </div>')
+ out.append(' <div id="main_panel">')
for topic_root in all_topic_roots:
- outfile.write(' <div class="alt-content" id="topic-'+str(topic_root.index)+'">\n')
+ out.append(' <div class="alt-content" id="topic-'+str(topic_root.index)+'">')
printed_top_header = False
printed_threads_header = False
for block in topic_root.blocks.ranges:
if block.start_pos_child < 0 and not printed_top_header:
- outfile.write(' <h1>Top-posted messages (sorry this section looks like a mess)</h1>\n')
+ out.append(' <h1>Top-posted messages (sorry this section looks like a mess)</h1>')
printed_top_header = True
if block.start_pos_child >= 0 and not printed_threads_header:
- outfile.write(' <h1>Actual thread</h1>\n')
+ out.append(' <h1>Actual thread</h1>')
printed_threads_header = True
- outfile.write(' <div class="message-block-container" style="margin-left:'+str(block.message.depth*4)+'em">\n')
- outfile.write(' <div class="message-block-meta">'+html.escape(block.message.from_hdr, quote=False)+'</div>\n')
- outfile.write(' <div class="message-block-content">'+html.escape(block.get_text(), quote=False)+'</div>\n')
- outfile.write(' </div>\n')
- outfile.write(' </div>\n')
- outfile.write(' </div>\n')
- outfile.write(' </body>\n')
- outfile.write('</html>\n')
+ out.append(' <div class="message-block-container" style="margin-left:'+str(block.message.depth*4)+'em">')
+ out.append(' <div class="message-block-meta">'+html.escape(block.message.from_hdr, quote=False)+'</div>')
+ out.append(' <div class="message-block-content">'+html.escape(block.get_text(), quote=False)+'</div>')
+ out.append(' </div>')
+ out.append(' </div>')
+ out.append(' </div>')
+ out.append(' </body>')
+ out.append('</html>')
+
+ out = bytes('\n'.join(out), 'utf-8')
+ start_response("200 OK", [
+ ("Content-Type", "text/html; charset=utf-8"),
+ ("Content-Length", str(len(out)))
+ ])
+
+ return iter([out])