>From 61c2b1c18f3b0dd17a289b96e99b1ed3cb5293f8 Mon Sep 17 00:00:00 2001
From: Amir <amir@localhost.localdomain>
Date: Tue, 6 Oct 2015 11:42:57 +0300
Subject: [PATCH 1/2] Implement 'mail me a copy'

---
 .../mailarchives/templates/email_message.html      |  2 +
 .../archives/mailarchives/templates/message.html   | 16 +++++++-
 django/archives/mailarchives/views.py              | 46 +++++++++++++++++++++-
 django/archives/mailqueue/__init__.py              |  0
 django/archives/mailqueue/admin.py                 |  5 +++
 django/archives/mailqueue/models.py                | 14 +++++++
 django/archives/mailqueue/util.py                  | 39 ++++++++++++++++++
 django/archives/settings.py                        |  4 +-
 django/archives/urls.py                            |  3 ++
 9 files changed, 126 insertions(+), 3 deletions(-)
 create mode 100644 django/archives/mailarchives/templates/email_message.html
 create mode 100644 django/archives/mailqueue/__init__.py
 create mode 100644 django/archives/mailqueue/admin.py
 create mode 100644 django/archives/mailqueue/models.py
 create mode 100644 django/archives/mailqueue/util.py

diff --git a/django/archives/mailarchives/templates/email_message.html b/django/archives/mailarchives/templates/email_message.html
new file mode 100644
index 0000000..1af66b0
--- /dev/null
+++ b/django/archives/mailarchives/templates/email_message.html
@@ -0,0 +1,2 @@
+<META http-equiv="refresh" content="3;URL={{return_url}}">
+    You should receive the email shortly. Returning you to message in a few seconds...
diff --git a/django/archives/mailarchives/templates/message.html b/django/archives/mailarchives/templates/message.html
index 1d09e24..ae2e6c5 100644
--- a/django/archives/mailarchives/templates/message.html
+++ b/django/archives/mailarchives/templates/message.html
@@ -7,6 +7,11 @@ function onThreadSelect() {
    document.location.href = '/message-id/' + document.getElementById('thread_select').value;
 }
 
+function submitEmailRequestform()
+{
+  document.emailMessageForm.submit();
+}
+
 $(function(){
    $('select#thread_select').selectmenu({
       style:'dropdown',
@@ -17,6 +22,14 @@ $(function(){
    });
 });
 </script>
+
+<!-- Hidden forms -->
+
+<!-- request an email copy -->
+<form name="emailMessageForm" action="/message-id/email/" method="post">
+<input type='hidden' name='msgid' value="{{msg.messageid}}" />
+</form>
+
 {%endblock%}
 {%block contents%}
 <h2>{{msg.subject}}</h2>
@@ -45,7 +58,8 @@ $(function(){
  </tr>
  <tr>
   <th>Message-ID:</th>
-  <td><a href="/message-id/{{msg.messageid}}">{{msg.messageid}}</a> (view <a href="/message-id/raw/{{msg.messageid}}">raw</a> or <a href="/message-id/flat/{{msg.messageid}}">whole thread</a>)</td>
+  <td><a href="/message-id/{{msg.messageid}}">{{msg.messageid}}</a> (view <a href="/message-id/raw/{{msg.messageid}}">raw</a> or <a href="/message-id/flat/{{msg.messageid}}">whole thread</a> or <a href="javascript:void(0)" onclick="submitEmailRequestform()">via email</a>)</td>
+
  </tr>
  <tr>
   <th>Thread:</th>
diff --git a/django/archives/mailarchives/views.py b/django/archives/mailarchives/views.py
index e011827..40d0e52 100644
--- a/django/archives/mailarchives/views.py
+++ b/django/archives/mailarchives/views.py
@@ -1,12 +1,15 @@
 from django.template import RequestContext
 from django.http import HttpResponse, HttpResponseForbidden, Http404
-from django.http import HttpResponsePermanentRedirect, HttpResponseNotModified
+from django.http import HttpResponsePermanentRedirect, HttpResponseNotModified, HttpResponseRedirect
 from django.shortcuts import render_to_response, get_object_or_404
+from django.core.urlresolvers import reverse
 from django.utils.http import http_date, parse_http_date_safe
 from django.db import connection
 from django.db.models import Q
 from django.conf import settings
 
+from archives.mailqueue.util import send_mail
+
 import urllib
 import re
 import os
@@ -390,6 +393,47 @@ def message_raw(request, msgid):
 	response['WWW-Authenticate'] = 'Basic realm="Please authenticate with user archives and password antispam"'
 	return response
 
+# TODO: archives app isn't hooked into community login, requires the pg web team.
+# @ssl_required
+# @login_required
+@nocache
+def email_message(request):
+    # user_email = request.user.email
+    user_email = "user1@localhost"
+
+    if not (request.method == 'POST'):
+        raise Http404('I only respond to POST')
+
+    if (not request.POST.has_key('msgid') or len(str(request.POST['msgid']))==0):
+        raise Http404('No msgid specified')
+
+    msgid = str(request.POST['msgid'])
+
+    curs = connection.cursor()
+    curs.execute("SELECT threadid, hiddenstatus, rawtxt FROM messages WHERE messageid=%(messageid)s", {
+        'messageid': msgid,
+        })
+
+    row = curs.fetchall()
+    if len(row) != 1:
+        raise Http404('Message does not exist')
+
+    threadid, hiddenstatus, rawtxt = row[0]
+
+    if hiddenstatus:
+        return HttpResponseForbidden('This message has been hidden.', content_type='text/plain')
+
+    try:
+        send_mail(settings.ARCHIVE_COPY_EMAIL_FROM, user_email,  rawtxt)
+    except:
+        # log error
+        return Http404("An error has occured.")
+
+    response = render_to_response('email_message.html',
+                                  {'return_url' :  reverse(message,args=[msgid]) })
+
+    return response
+
 def testview(request, seqid):
 	m = Message.objects.get(pk=seqid)
 	try:
diff --git a/django/archives/mailqueue/__init__.py b/django/archives/mailqueue/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/django/archives/mailqueue/admin.py b/django/archives/mailqueue/admin.py
new file mode 100644
index 0000000..ccabb81
--- /dev/null
+++ b/django/archives/mailqueue/admin.py
@@ -0,0 +1,5 @@
+from django.contrib import admin
+
+from models import QueuedMail
+
+admin.site.register(QueuedMail)
diff --git a/django/archives/mailqueue/models.py b/django/archives/mailqueue/models.py
new file mode 100644
index 0000000..36d73ee
--- /dev/null
+++ b/django/archives/mailqueue/models.py
@@ -0,0 +1,14 @@
+from django.db import models
+
+class QueuedMail(models.Model):
+	sender = models.EmailField(max_length=100, null=False, blank=False)
+	receiver = models.EmailField(max_length=100, null=False, blank=False)
+	# We store the raw MIME message, so if there are any attachments or
+	# anything, we just push them right in there!
+	fullmsg = models.TextField(null=False, blank=False)
+	# Flag if the message is "user generated", so we can treat those
+	# separately from an antispam and delivery perspective.
+	usergenerated = models.BooleanField(null=False, blank=False, default=False)
+
+	def __unicode__(self):
+		return "%s: %s -> %s" % (self.pk, self.sender, self.receiver)
diff --git a/django/archives/mailqueue/util.py b/django/archives/mailqueue/util.py
new file mode 100644
index 0000000..3a35c41
--- /dev/null
+++ b/django/archives/mailqueue/util.py
@@ -0,0 +1,39 @@
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.mime.nonmultipart import MIMENonMultipart
+from email.Utils import formatdate
+from email.Utils import make_msgid
+from email import encoders
+
+from models import QueuedMail
+
+def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, usergenerated=False):
+	# attachment format, each is a tuple of (name, mimetype,contents)
+	# content should be *binary* and not base64 encoded, since we need to
+	# use the base64 routines from the email library to get a properly
+	# formatted output message
+	msg = MIMEMultipart()
+	msg['Subject'] = subject
+	msg['To'] = receiver
+	msg['From'] = sender
+	msg['Date'] = formatdate(localtime=True)
+	msg['Message-ID'] = make_msgid()
+
+	msg.attach(MIMEText(msgtxt, _charset='utf-8'))
+
+	if attachments:
+		for filename, contenttype, content in attachments:
+			main,sub = contenttype.split('/')
+			part = MIMENonMultipart(main,sub)
+			part.set_payload(content)
+			part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename)
+			encoders.encode_base64(part)
+			msg.attach(part)
+
+
+	# Just write it to the queue, so it will be transactionally rolled back
+	QueuedMail(sender=sender, receiver=receiver, fullmsg=msg.as_string(), usergenerated=usergenerated).save()
+
+def send_mail(sender, receiver, fullmsg, usergenerated=False):
+	# Send an email, prepared as the full MIME encoded mail already
+	QueuedMail(sender=sender, receiver=receiver, fullmsg=fullmsg, usergenerated=False).save()
diff --git a/django/archives/settings.py b/django/archives/settings.py
index 0a01c3b..a680c3a 100644
--- a/django/archives/settings.py
+++ b/django/archives/settings.py
@@ -119,7 +119,8 @@ INSTALLED_APPS = (
     # 'django.contrib.admin',
     # Uncomment the next line to enable admin documentation:
     # 'django.contrib.admindocs',
-	'archives.mailarchives',
+    'archives.mailarchives',
+    'archives.mailqueue',
 )
 
 # A sample logging configuration. The only tangible logging
@@ -154,6 +155,7 @@ FORCE_SCRIPT_NAME=""
 MBOX_ARCHIVES_ROOT="/dev/null"
 SEARCH_CLIENTS = ('127.0.0.1',)
 API_CLIENTS = ('127.0.0.1',)
+ARCHIVE_COPY_EMAIL_FROM = "someone@example.com" # bounce address for emails sent by app
 
 try:
 	from settings_local import *
diff --git a/django/archives/urls.py b/django/archives/urls.py
index 16fc718..4214243 100644
--- a/django/archives/urls.py
+++ b/django/archives/urls.py
@@ -28,6 +28,9 @@ urlpatterns = patterns('',
     (r'^message-id/flat/([^/]+)$', 'archives.mailarchives.views.message_flat'),
     (r'^message-id/raw/([^/]+)$', 'archives.mailarchives.views.message_raw'),
 
+    # POST endpoint for reuesting a message copy by email
+    (r'^message-id/email/$', 'archives.mailarchives.views.email_message'),
+
     # Search
     (r'^archives-search/', 'archives.mailarchives.views.search'),
 
-- 
2.4.3

