Automatically migrated from Gitolite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
6.9 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. #!/usr/bin/python
  2. import os, argparse, hashlib, sqlite3, time, shutil, cgi, re, math
  3. from datetime import datetime
  4. parser = argparse.ArgumentParser(description='Renders static HTML pages and indexes from an SQLite database of emails and an attachment folder.')
  5. parser.add_argument('-o', dest='output_dir', action='store', default='rendered_files',
  6. help='path of the directory where rendered files should be stored')
  7. parser.add_argument('-t', dest='template_dir', action='store', default='templates',
  8. help='path where the template files are')
  9. parser.add_argument('-i', dest='title', action='store', default='Inbox',
  10. help='title for the rendered pages')
  11. parser.add_argument('-d', dest='database', action='store', default='emails.db',
  12. help='path of the database that should be used to render the e-mail files')
  13. parser.add_argument('-a', dest='attachment_dir', action='store', default='attachments',
  14. help='path where attachments are stored')
  15. parser.add_argument('-n', dest='per_page', action='store', default='20',
  16. help='amount of entries per page')
  17. args = parser.parse_args()
  18. options = vars(args)
  19. def format_size(num):
  20. for unit in [' bytes','KB','MB','GB']:
  21. if num < 1024.0:
  22. return "%3.1f%s" % (num, unit)
  23. num /= 1024.0
  24. return "%3.1f%s" % (num, 'TB')
  25. def chunk(iterable, chunksize, fillvalue=None):
  26. result = []
  27. num_chunks = int(math.ceil(len(iterable) / (chunksize * 1.0)))
  28. for i in xrange(0, num_chunks):
  29. start = (chunksize * i)
  30. if (chunksize * (i + 1)) > len(iterable):
  31. end = len(iterable)
  32. else:
  33. end = (chunksize * (i + 1))
  34. result.append((iterable[start:end]))
  35. return result
  36. def render_index(email_list, title, identifier):
  37. email_list = chunk(email_list, int(options['per_page']))
  38. current_page = 0
  39. for list_chunk in email_list:
  40. variables = {
  41. 'page': title,
  42. 'pagenum': "Page %d of %d" % (current_page + 1, len(email_list)),
  43. 'title': options['title'],
  44. 'index': "../index.html",
  45. 'items': "".join('<tr><td>%s...</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>' % (message[0][:8], message[3], message[4], message[5], message[6], message[7]) for message in list_chunk)
  46. }
  47. filename = "%s/index_%s_%d.html" % (options['output_dir'], identifier, current_page)
  48. generated = template_index % variables
  49. open(filename, 'w').write(generated.encode('UTF-8'))
  50. print "Wrote page %d for %s." % (current_page, identifier)
  51. current_page += 1
  52. if os.path.isfile(options['database']) == False:
  53. print "Database file not found. Use the -d switch to specify a custom database path."
  54. exit(1)
  55. # Connect to database
  56. database = sqlite3.connect(options['database'])
  57. cursor = database.cursor()
  58. # Load templates
  59. template_message = open('%s/message.html' % options['template_dir']).read()
  60. template_index = open('%s/index.html' % options['template_dir']).read()
  61. # Create output directory if necessary
  62. try:
  63. os.makedirs("%s/messages" % options['output_dir'])
  64. except OSError:
  65. pass
  66. email_list = []
  67. for message_id, sender, recipient, subject, unixtime, textbody, htmlbody, sha1_hash in cursor.execute("SELECT * FROM emails"):
  68. sender = cgi.escape(sender, True)
  69. recipient = cgi.escape(recipient, True)
  70. subject = cgi.escape(subject, True)
  71. message_id = cgi.escape(message_id, True)
  72. timestamp = datetime.fromtimestamp(unixtime).strftime("%A %B %e, %Y %H:%M:%S")
  73. attachment_list = []
  74. attachment_cursor = database.cursor()
  75. for attachment_hash, attachment_filename, attachment_type, message_hash, attachment_size in attachment_cursor.execute("SELECT * FROM attachments WHERE `message_hash` = ?", (sha1_hash,)):
  76. attachment_extension = os.path.splitext(attachment_filename)[1][1:]
  77. attachment_file = "%s.%s" % (attachment_hash, attachment_extension)
  78. attachment_list.append('<a href="../attachments/%s" class="attachment">%s (%s, %s)</a>' % (attachment_file, attachment_filename, attachment_type, format_size(attachment_size)))
  79. if len(attachment_list) > 0:
  80. attachments = "".join(attachment_list)
  81. print "ATTACHMENTS %s" % sha1_hash
  82. else:
  83. attachments = '<div class="attachment light">No attachments.</div>'
  84. versions = {}
  85. if textbody != "":
  86. available_text = True
  87. versions['Plaintext'] = '%s_text.html' % sha1_hash
  88. else:
  89. available_text = False
  90. if htmlbody != "":
  91. available_html = True
  92. versions['HTML'] = '%s_html.html' % sha1_hash
  93. else:
  94. available_html = False
  95. version_list = "".join('<a href="%s" class="version">%s</a>' % (value, key) for key, value in versions.viewitems())
  96. if available_text == True:
  97. # Text version
  98. variables = {
  99. 'subject': subject,
  100. 'date': timestamp,
  101. 'from': sender,
  102. 'to': recipient,
  103. 'body': "<pre>%s</pre>" % textbody,
  104. 'title': options['title'],
  105. 'version': "Plaintext version",
  106. 'index': "../index.html",
  107. 'versions': version_list,
  108. 'attachments': attachments
  109. }
  110. generated = template_message % variables
  111. open('%s/messages/%s_text.html' % (options['output_dir'], sha1_hash), 'w').write(generated.encode('UTF-8'))
  112. print "Successfully generated plaintext version of %s." % sha1_hash
  113. if available_html == True:
  114. # HTML version
  115. variables = {
  116. 'subject': subject,
  117. 'date': timestamp,
  118. 'from': sender,
  119. 'to': recipient,
  120. 'body': htmlbody,
  121. 'title': options['title'],
  122. 'version': "HTML version",
  123. 'index': "../index.html",
  124. 'versions': version_list,
  125. 'attachments': attachments
  126. }
  127. generated = template_message % variables
  128. open('%s/messages/%s_html.html' % (options['output_dir'], sha1_hash), 'w').write(generated.encode('UTF-8'))
  129. print "Successfully generated HTML version of %s." % sha1_hash
  130. try:
  131. snippet = "%s..." % re.search("^(.{0,200})\\b", textbody, re.DOTALL).group(1)
  132. except AttributeError:
  133. snippet = ""
  134. email_list.append((sha1_hash, available_text, available_html, sender, recipient, subject, timestamp, len(attachment_list), snippet, unixtime))
  135. # Sort by timestamp, ascending
  136. sorted_list = sorted(email_list, key=lambda email: email[9])
  137. render_index(sorted_list, "Sorted from old to new", "date_asc")
  138. # Sort by timestamp, descending
  139. sorted_list.reverse()
  140. render_index(sorted_list, "Sorted from new to old", "date_desc")
  141. # Sort by sender, ascending
  142. sorted_list = sorted(email_list, key=lambda email: email[3].lower())
  143. # Sort by sender, descending
  144. sorted_list.reverse()
  145. # Sort by recipient, ascending
  146. sorted_list = sorted(email_list, key=lambda email: email[4].lower())
  147. # Sort by recipient, descending
  148. sorted_list.reverse()
  149. # Sort by hash, ascending
  150. sorted_list = sorted(email_list, key=lambda email: email[0].lower())
  151. # Sort by hash, descending
  152. sorted_list.reverse()
  153. # Sort by subject, ascending
  154. sorted_list = sorted(email_list, key=lambda email: email[5].lower())
  155. # Sort by subject, descending
  156. sorted_list.reverse()
  157. shutil.copy('%s/style.css' % options['template_dir'], '%s/style.css' % options['output_dir'])