diff --git a/res/layout/registration_welcome_activity.xml b/res/layout/registration_welcome_activity.xml
index 69cb628f33..d08003387a 100644
--- a/res/layout/registration_welcome_activity.xml
+++ b/res/layout/registration_welcome_activity.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:background="@color/loki_darkest_gray"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
@@ -26,7 +26,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/textView"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/welcome_terms_button"
+        app:layout_constraintBottom_toTopOf="@id/beta_terms_label"
         android:orientation="vertical"
         android:gravity="center">
 
@@ -37,6 +37,21 @@
 
     </LinearLayout>
 
+    <TextView
+        android:id="@+id/beta_terms_label"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="32dp"
+        android:layout_marginEnd="32dp"
+        android:layout_marginBottom="24dp"
+        style="@style/Signal.Text.Body"
+        android:text="@string/activity_landing_beta_terms"
+        android:textColor="@color/white"
+        android:textAlignment="center"
+        app:layout_constraintBottom_toTopOf="@+id/welcome_terms_button"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
     <TextView
         android:id="@+id/welcome_terms_button"
         android:layout_width="wrap_content"
@@ -45,6 +60,7 @@
         style="@style/Signal.Text.Body"
         android:text="@string/activity_landing_privacy_policy_button_title"
         android:textColor="@color/signal_primary"
+        android:textAlignment="center"
         app:layout_constraintBottom_toTopOf="@+id/welcome_continue_button"
         app:layout_constraintEnd_toEndOf="@+id/welcome_continue_button"
         app:layout_constraintStart_toStartOf="@+id/welcome_continue_button" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6488c933b5..10f66eeca1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1547,6 +1547,7 @@
     <!-- Landing activity -->
     <string name="activity_landing_title">Loki Messenger</string>
     <string name="activity_landing_permission_dialog_message">Some features of Loki Messenger (such as automatic message backup) require storage access to work.</string>
+    <string name="activity_landing_beta_terms">"Loki Messenger is currently in beta. For development purposes the beta version collects basic usage statistics and crash logs. In addition, the beta version doesn't provide full privacy and shouldn\'t be used to transmit sensitive information."</string>
     <string name="activity_landing_privacy_policy_button_title">Privacy Policy</string>
     <!-- Account details activity -->
     <string name="activity_account_details_title">Create Your Loki Messenger Account</string>
diff --git a/src/org/thoughtcrime/securesms/components/QuoteView.java b/src/org/thoughtcrime/securesms/components/QuoteView.java
index 63f66cfa7b..ef9dccff24 100644
--- a/src/org/thoughtcrime/securesms/components/QuoteView.java
+++ b/src/org/thoughtcrime/securesms/components/QuoteView.java
@@ -20,8 +20,8 @@ import android.widget.TextView;
 import com.annimon.stream.Stream;
 import com.bumptech.glide.load.engine.DiskCacheStrategy;
 
-import network.loki.messenger.R;
 import org.thoughtcrime.securesms.attachments.Attachment;
+import org.thoughtcrime.securesms.database.DatabaseFactory;
 import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
 import org.thoughtcrime.securesms.mms.GlideRequests;
 import org.thoughtcrime.securesms.mms.Slide;
@@ -30,9 +30,12 @@ import org.thoughtcrime.securesms.recipients.Recipient;
 import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
 import org.thoughtcrime.securesms.util.ThemeUtil;
 import org.thoughtcrime.securesms.util.Util;
+import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI;
 
 import java.util.List;
 
+import network.loki.messenger.R;
+
 public class QuoteView extends FrameLayout implements RecipientModifiedListener {
 
   private static final String TAG = QuoteView.class.getSimpleName();
@@ -186,8 +189,11 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
     boolean outgoing    = messageType != MESSAGE_TYPE_INCOMING;
     boolean isOwnNumber = Util.isOwnNumber(getContext(), author.getAddress());
 
-    authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you)
-                                   : author.toShortString());
+    String quoteeDisplayName = author.toShortString();
+    if (quoteeDisplayName.equals(author.getAddress().toString())) {
+      quoteeDisplayName = DatabaseFactory.getLokiUserDatabase(getContext()).getServerDisplayName(LokiGroupChatAPI.getPublicChatServer() + "." + LokiGroupChatAPI.getPublicChatServerID(), author.getAddress().toString());
+    }
+    authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you) : quoteeDisplayName);
 
     // We use the raw color resource because Android 4.x was struggling with tints here
     quoteBarView.setImageResource(author.getColor().toQuoteBarColorResource(getContext(), outgoing));
diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java
index 585dc5b01d..074ac80b89 100644
--- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java
+++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java
@@ -408,10 +408,10 @@ public class ConversationFragment extends Fragment
     boolean isGroupChat = recipient.isGroupRecipient();
 
     if (isGroupChat) {
-      menu.findItem(R.id.menu_context_reply).setVisible(false);
-      LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext());
-      boolean isLokiPublicChat = recipient.getName().equals("Loki Public Chat");
+      boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat");
       int selectedMessageCount = messageRecords.size();
+      menu.findItem(R.id.menu_context_reply).setVisible(isLokiPublicChat && selectedMessageCount == 1);
+      LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext());
       boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing();
       boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer());
       boolean isDeleteOptionVisible = isLokiPublicChat && selectedMessageCount == 1 && (isSentByUser || userCanModerate);
diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
index 687ba2a604..25be4d87d9 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
@@ -305,7 +305,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
         if      (message.isEndSession())        handleEndSessionMessage(content, smsMessageId);
         else if (message.isGroupUpdate())       handleGroupMessage(content, message, smsMessageId);
         else if (message.isExpirationUpdate())  handleExpirationUpdate(content, message, smsMessageId);
-        else if (isMediaMessage)                handleMediaMessage(content, message, smsMessageId);
+        else if (isMediaMessage)                handleMediaMessage(content, message, smsMessageId, Optional.absent());
         else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId, Optional.absent());
 
         if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) {
@@ -733,9 +733,10 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
     MessageNotifier.updateNotification(context);
   }
 
-  private void handleMediaMessage(@NonNull SignalServiceContent content,
-                                  @NonNull SignalServiceDataMessage message,
-                                  @NonNull Optional<Long> smsMessageId)
+  public void handleMediaMessage(@NonNull SignalServiceContent content,
+                                 @NonNull SignalServiceDataMessage message,
+                                 @NonNull Optional<Long> smsMessageId,
+                                 @NonNull Optional<Long> messageServerIDOrNull)
       throws StorageFailedException
   {
     notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice());
@@ -764,7 +765,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
               }
               if (c == linkPreviewCount) {
                 try {
-                  handleMediaMessage(content, mediaMessage, smsMessageId);
+                  handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
                 } catch (Exception e) {
                   // TODO: Handle
                 }
@@ -772,17 +773,13 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
             }));
           }
         } else {
-          handleMediaMessage(content, mediaMessage, smsMessageId);
+          handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
         }
       } else {
-        handleMediaMessage(content, mediaMessage, smsMessageId);
+        handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
       }
   }
 
-  private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID) throws StorageFailedException {
-    handleMediaMessage(content, mediaMessage, smsMessageID, null);
-  }
-
   private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID, @Nullable Optional<Long> messageServerIDOrNull) throws StorageFailedException {
     MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
     database.beginTransaction();
@@ -927,7 +924,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
   public void handleTextMessage(@NonNull SignalServiceContent content,
                                 @NonNull SignalServiceDataMessage message,
                                 @NonNull Optional<Long> smsMessageId,
-                                @Nullable Optional<Long> messageServerIDOrNull)
+                                @NonNull Optional<Long> messageServerIDOrNull)
       throws StorageFailedException
   {
     SmsDatabase database  = DatabaseFactory.getSmsDatabase(context);
@@ -996,7 +993,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
     }
   }
 
-  private void updatePublicChatMessageWithServerID(@Nullable  Optional<Long> messageServerIDOrNull, Optional<InsertResult> databaseInsert) {
+  private void updatePublicChatMessageWithServerID(Optional<Long> messageServerIDOrNull, Optional<InsertResult> databaseInsert) {
     if (messageServerIDOrNull == null) { return; }
     if (databaseInsert.isPresent() && messageServerIDOrNull.isPresent()) {
       long messageID = databaseInsert.get().getMessageId();
diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt
index 4b6afca3fc..b1bb313f94 100644
--- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt
+++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt
@@ -3,19 +3,15 @@ package org.thoughtcrime.securesms.loki
 import android.content.Context
 import android.os.Handler
 import android.util.Log
-import org.thoughtcrime.securesms.attachments.Attachment
-import org.thoughtcrime.securesms.contactshare.Contact
 import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
 import org.thoughtcrime.securesms.database.Address
 import org.thoughtcrime.securesms.database.DatabaseFactory
 import org.thoughtcrime.securesms.database.ThreadDatabase
-import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch
-import org.thoughtcrime.securesms.database.documents.NetworkFailure
 import org.thoughtcrime.securesms.jobs.PushDecryptJob
-import org.thoughtcrime.securesms.linkpreview.LinkPreview
 import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
 import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
 import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
+import org.thoughtcrime.securesms.mms.QuoteModel
 import org.thoughtcrime.securesms.recipients.Recipient
 import org.thoughtcrime.securesms.util.GroupUtil
 import org.thoughtcrime.securesms.util.TextSecurePreferences
@@ -28,7 +24,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress
 import org.whispersystems.signalservice.loki.api.LokiGroupChat
 import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
 import org.whispersystems.signalservice.loki.api.LokiGroupMessage
-import java.util.*
 
 class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) {
     private val handler = Handler()
@@ -102,11 +97,21 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG
         fun processIncomingMessage(message: LokiGroupMessage) {
             val id = group.id.toByteArray()
             val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null)
-            val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body)
+            val quote: SignalServiceDataMessage.Quote?
+            if (message.quote != null) {
+                quote = SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf())
+            } else {
+                quote = null
+            }
+            val x2 = SignalServiceDataMessage(message.timestamp, x1, listOf(), message.body, false, 0, false, null, false, quote, null, null, null)
             val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false)
             val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})"
             DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName)
-            PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID))
+            if (quote != null) {
+                PushDecryptJob(context).handleMediaMessage(x3, x2, Optional.absent(), Optional.of(message.serverID))
+            } else {
+                PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID))
+            }
         }
         fun processOutgoingMessage(message: LokiGroupMessage) {
             val messageServerID = message.serverID ?: return
@@ -116,8 +121,14 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG
             val id = group.id.toByteArray()
             val mmsDatabase = DatabaseFactory.getMmsDatabase(context)
             val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false)
-            val signalMessage = OutgoingMediaMessage(recipient, message.body, ArrayList<Attachment>(), message.timestamp, 0, 0, ThreadDatabase.DistributionTypes.DEFAULT,
-               null, ArrayList<Contact>(), ArrayList<LinkPreview>(), ArrayList<NetworkFailure>(), ArrayList<IdentityKeyMismatch>())
+            val quote: QuoteModel?
+            if (message.quote != null) {
+                quote = QuoteModel(message.quote!!.quotedMessageTimestamp, Address.fromSerialized(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, false, listOf())
+            } else {
+                quote = null
+            }
+            val signalMessage = OutgoingMediaMessage(recipient, message.body, listOf(), message.timestamp, 0, 0,
+               ThreadDatabase.DistributionTypes.DEFAULT, quote, listOf(), listOf(), listOf(), listOf())
             val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
             fun finalize() {
                 val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null)