Experimental: send user unknown

pull/194/head
M66B 4 years ago
parent aabfc099b3
commit be7d139f5d

@ -2863,6 +2863,10 @@ Please see [this FAQ](#user-content-faq163) for details.
Since this is an experimental feature, my advice is to start with just one folder. Since this is an experimental feature, my advice is to start with just one folder.
*Send user unknown (version 1.1477+)*
Send a [Delivery Status Notification](https://tools.ietf.org/html/rfc3464) *User unknown* via the answer menu.
<br /> <br />
<a name="faq126"></a> <a name="faq126"></a>

@ -3349,7 +3349,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private void onReceipt(TupleMessageEx message) { private void onReceipt(TupleMessageEx message) {
Intent reply = new Intent(context, ActivityCompose.class) Intent reply = new Intent(context, ActivityCompose.class)
.putExtra("action", "receipt") .putExtra("action", "dsn")
.putExtra("dsn", EntityMessage.DSN_RECEIPT)
.putExtra("reference", message.id); .putExtra("reference", message.id);
context.startActivity(reply); context.startActivity(reply);
} }

@ -407,6 +407,9 @@ public class ApplicationEx extends Application
} else if (version < 1463) { } else if (version < 1463) {
if (!prefs.contains("autoscroll")) if (!prefs.contains("autoscroll"))
editor.putBoolean("autoscroll", true); editor.putBoolean("autoscroll", true);
} else if (version < 1477) {
if (!BuildConfig.DEBUG)
editor.remove("experiments");
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !BuildConfig.DEBUG) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !BuildConfig.DEBUG)

@ -104,6 +104,7 @@ public class EntityMessage implements Serializable {
static final Integer DSN_NONE = 0; static final Integer DSN_NONE = 0;
static final Integer DSN_RECEIPT = 1; static final Integer DSN_RECEIPT = 1;
static final Integer DSN_USER_UNKNOWN = 2;
static final Long SWIPE_ACTION_ASK = -1L; static final Long SWIPE_ACTION_ASK = -1L;
static final Long SWIPE_ACTION_SEEN = -2L; static final Long SWIPE_ACTION_SEEN = -2L;

@ -1184,6 +1184,7 @@ public class FragmentCompose extends FragmentBase {
args.putLong("account", a.getLong("account", -1)); args.putLong("account", a.getLong("account", -1));
args.putLong("identity", a.getLong("identity", -1)); args.putLong("identity", a.getLong("identity", -1));
args.putLong("reference", a.getLong("reference", -1)); args.putLong("reference", a.getLong("reference", -1));
args.putInt("dsn", a.getInt("dsn", -1));
args.putSerializable("ics", a.getSerializable("ics")); args.putSerializable("ics", a.getSerializable("ics"));
args.putString("status", a.getString("status")); args.putString("status", a.getString("status"));
args.putBoolean("raw", a.getBoolean("raw", false)); args.putBoolean("raw", a.getBoolean("raw", false));
@ -3388,6 +3389,7 @@ public class FragmentCompose extends FragmentBase {
String action = args.getString("action"); String action = args.getString("action");
long id = args.getLong("id", -1); long id = args.getLong("id", -1);
long reference = args.getLong("reference", -1); long reference = args.getLong("reference", -1);
int dsn = args.getInt("dsn", EntityMessage.DSN_RECEIPT);
File ics = (File) args.getSerializable("ics"); File ics = (File) args.getSerializable("ics");
String status = args.getString("status"); String status = args.getString("status");
long answer = args.getLong("answer", -1); long answer = args.getLong("answer", -1);
@ -3609,7 +3611,7 @@ public class FragmentCompose extends FragmentBase {
// References // References
if ("reply".equals(action) || "reply_all".equals(action) || if ("reply".equals(action) || "reply_all".equals(action) ||
"list".equals(action) || "list".equals(action) ||
"receipt".equals(action) || "dsn".equals(action) ||
"participation".equals(action)) { "participation".equals(action)) {
data.draft.references = (ref.references == null ? "" : ref.references + " ") + ref.msgid; data.draft.references = (ref.references == null ? "" : ref.references + " ") + ref.msgid;
data.draft.inreplyto = ref.msgid; data.draft.inreplyto = ref.msgid;
@ -3617,7 +3619,7 @@ public class FragmentCompose extends FragmentBase {
if ("list".equals(action) && ref.list_post != null) if ("list".equals(action) && ref.list_post != null)
data.draft.to = ref.list_post; data.draft.to = ref.list_post;
else if ("receipt".equals(action) && ref.receipt_to != null) else if ("dsn".equals(action) && ref.receipt_to != null)
data.draft.to = ref.receipt_to; data.draft.to = ref.receipt_to;
else { else {
// Prevent replying to self // Prevent replying to self
@ -3667,8 +3669,8 @@ public class FragmentCompose extends FragmentBase {
if ("reply_all".equals(action)) if ("reply_all".equals(action))
data.draft.cc = ref.getAllRecipients(data.identities, ref.account); data.draft.cc = ref.getAllRecipients(data.identities, ref.account);
else if ("receipt".equals(action)) { else if ("dsn".equals(action)) {
data.draft.dsn = EntityMessage.DSN_RECEIPT; data.draft.dsn = dsn;
data.draft.receipt_request = false; data.draft.receipt_request = false;
} }
@ -3727,10 +3729,17 @@ public class FragmentCompose extends FragmentBase {
} }
} else if ("list".equals(action)) { } else if ("list".equals(action)) {
data.draft.subject = ref.subject; data.draft.subject = ref.subject;
} else if ("receipt".equals(action)) { } else if ("dsn".equals(action)) {
data.draft.subject = context.getString(R.string.title_receipt_subject, subject); if (EntityMessage.DSN_USER_UNKNOWN.equals(dsn))
data.draft.subject = context.getString(R.string.title_user_unknown_subject);
else
data.draft.subject = context.getString(R.string.title_receipt_subject, subject);
String[] texts = Helper.getStrings(context, ref.language, R.string.title_receipt_text); String[] texts;
if (EntityMessage.DSN_USER_UNKNOWN.equals(dsn))
texts = new String[]{context.getString(R.string.title_user_unknown_text)};
else
texts = Helper.getStrings(context, ref.language, R.string.title_receipt_text);
for (int i = 0; i < texts.length; i++) { for (int i = 0; i < texts.length; i++) {
if (i > 0) if (i > 0)
document.body() document.body()
@ -3782,7 +3791,7 @@ public class FragmentCompose extends FragmentBase {
if (ref.content && if (ref.content &&
!"editasnew".equals(action) && !"editasnew".equals(action) &&
!("list".equals(action) && TextUtils.isEmpty(s)) && !("list".equals(action) && TextUtils.isEmpty(s)) &&
!"receipt".equals(action)) { !"dsn".equals(action)) {
// Reply/forward // Reply/forward
Element reply = document.createElement("div"); Element reply = document.createElement("div");
reply.attr("fairemail", "reference"); reply.attr("fairemail", "reference");

@ -2410,6 +2410,10 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
if (data.identities == null) if (data.identities == null)
data.identities = new ArrayList<>(); data.identities = new ArrayList<>();
final Context context = getContext();
if (context == null)
return;
final Address[] to = final Address[] to =
message.replySelf(data.identities, message.account) message.replySelf(data.identities, message.account)
? message.to ? message.to
@ -2419,13 +2423,17 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
int answers = args.getInt("answers"); int answers = args.getInt("answers");
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), anchor); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean experiments = prefs.getBoolean("experiments", false);
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, getViewLifecycleOwner(), anchor);
popupMenu.inflate(R.menu.popup_reply); popupMenu.inflate(R.menu.popup_reply);
popupMenu.getMenu().findItem(R.id.menu_reply_to_all).setVisible(recipients.length > 0); popupMenu.getMenu().findItem(R.id.menu_reply_to_all).setVisible(recipients.length > 0);
popupMenu.getMenu().findItem(R.id.menu_reply_list).setVisible(message.list_post != null); popupMenu.getMenu().findItem(R.id.menu_reply_list).setVisible(message.list_post != null);
popupMenu.getMenu().findItem(R.id.menu_reply_receipt).setVisible(message.receipt_to != null); popupMenu.getMenu().findItem(R.id.menu_reply_receipt).setVisible(message.receipt_to != null);
popupMenu.getMenu().findItem(R.id.menu_reply_user_unknown).setVisible(experiments);
popupMenu.getMenu().findItem(R.id.menu_new_message).setVisible(to != null && to.length > 0); popupMenu.getMenu().findItem(R.id.menu_new_message).setVisible(to != null && to.length > 0);
popupMenu.getMenu().findItem(R.id.menu_reply_answer).setVisible(answers != 0 || !ActivityBilling.isPro(getContext())); popupMenu.getMenu().findItem(R.id.menu_reply_answer).setVisible(answers != 0 || !ActivityBilling.isPro(context));
popupMenu.getMenu().findItem(R.id.menu_reply_to_sender).setEnabled(message.content); popupMenu.getMenu().findItem(R.id.menu_reply_to_sender).setEnabled(message.content);
popupMenu.getMenu().findItem(R.id.menu_reply_to_all).setEnabled(message.content); popupMenu.getMenu().findItem(R.id.menu_reply_to_all).setEnabled(message.content);
@ -2446,7 +2454,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
@Override @Override
public boolean onMenuItemClick(MenuItem target) { public boolean onMenuItemClick(MenuItem target) {
if (target.getGroupId() == 1) { if (target.getGroupId() == 1) {
startActivity(new Intent(getContext(), ActivityCompose.class) startActivity(new Intent(context, ActivityCompose.class)
.putExtra("action", "reply") .putExtra("action", "reply")
.putExtra("reference", message.id) .putExtra("reference", message.id)
.putExtra("answer", target.getIntent().getLongExtra("id", -1))); .putExtra("answer", target.getIntent().getLongExtra("id", -1)));
@ -2465,7 +2473,10 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
onMenuReply(message, "list", selected); onMenuReply(message, "list", selected);
return true; return true;
case R.id.menu_reply_receipt: case R.id.menu_reply_receipt:
onMenuReply(message, "receipt"); onMenuDsn(message, EntityMessage.DSN_RECEIPT);
return true;
case R.id.menu_reply_user_unknown:
onMenuDsn(message, EntityMessage.DSN_USER_UNKNOWN);
return true; return true;
case R.id.menu_forward: case R.id.menu_forward:
onMenuReply(message, "forward"); onMenuReply(message, "forward");
@ -2506,6 +2517,14 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
startActivity(reply); startActivity(reply);
} }
private void onMenuDsn(TupleMessageEx message, int type) {
Intent reply = new Intent(getContext(), ActivityCompose.class)
.putExtra("action", "dsn")
.putExtra("reference", message.id)
.putExtra("dsn", type);
startActivity(reply);
}
private void onMenuNew(TupleMessageEx message, Address[] to) { private void onMenuNew(TupleMessageEx message, Address[] to) {
Intent reply = new Intent(getContext(), ActivityCompose.class) Intent reply = new Intent(getContext(), ActivityCompose.class)
.putExtra("action", "new") .putExtra("action", "new")

@ -573,6 +573,43 @@ public class MessageHelper {
//headersPart.setDisposition(Part.INLINE); //headersPart.setDisposition(Part.INLINE);
//report.addBodyPart(headersPart); //report.addBodyPart(headersPart);
imessage.setContent(report);
return;
} else if (EntityMessage.DSN_USER_UNKNOWN.equals(message.dsn)) {
// https://tools.ietf.org/html/rfc3464
Multipart report = new MimeMultipart("report; report-type=delivery-status");
String html = Helper.readText(message.getFile(context));
String plainContent = HtmlHelper.getText(context, html);
BodyPart plainPart = new MimeBodyPart();
plainPart.setContent(plainContent, "text/plain; charset=" + Charset.defaultCharset().name());
report.addBodyPart(plainPart);
String from = null;
if (message.from != null && message.from.length > 0)
from = ((InternetAddress) message.from[0]).getAddress();
StringBuilder sb = new StringBuilder();
sb.append("Reporting-MTA: dns;").append("dummy.faircode.eu").append("\r\n");
sb.append("\r\n");
if (from != null)
sb.append("Final-Recipient: rfc822;").append(from).append("\r\n");
sb.append("Action: failed").append("\r\n");
sb.append("Status: 5.1.1").append("\r\n"); // https://tools.ietf.org/html/rfc3463
sb.append("Diagnostic-Code: smtp; 550 user unknown").append("\r\n");
MailDateFormat mdf = new MailDateFormat();
mdf.setTimeZone(TimeZone.getTimeZone("UTC"));
sb.append("Last-Attempt-Date: ").append(mdf.format(message.received)).append("\r\n");
BodyPart dnsPart = new MimeBodyPart();
dnsPart.setContent(sb.toString(), "message/delivery-status");
dnsPart.setDisposition(Part.INLINE);
report.addBodyPart(dnsPart);
imessage.setContent(report); imessage.setContent(report);
return; return;
} }

@ -16,6 +16,10 @@
android:id="@+id/menu_reply_receipt" android:id="@+id/menu_reply_receipt"
android:title="@string/title_reply_receipt" /> android:title="@string/title_reply_receipt" />
<item
android:id="@+id/menu_reply_user_unknown"
android:title="@string/title_reply_user_unknown" />
<item <item
android:id="@+id/menu_forward" android:id="@+id/menu_forward"
android:title="@string/title_forward" /> android:title="@string/title_forward" />

@ -887,11 +887,15 @@
<string name="title_reply_to_all">Reply to all</string> <string name="title_reply_to_all">Reply to all</string>
<string name="title_reply_list">Reply to list</string> <string name="title_reply_list">Reply to list</string>
<string name="title_reply_receipt">Send read receipt</string> <string name="title_reply_receipt">Send read receipt</string>
<string name="title_reply_user_unknown" translatable="false">Send user unknown</string>
<string name="title_reply_template">Reply with template</string> <string name="title_reply_template">Reply with template</string>
<string name="title_move_undo">Moving to %1$s (%2$d)</string> <string name="title_move_undo">Moving to %1$s (%2$d)</string>
<string name="title_open_with">Open with</string> <string name="title_open_with">Open with</string>
<string name="title_authentication_failed">%1$s authentication failed</string> <string name="title_authentication_failed">%1$s authentication failed</string>
<string name="title_user_unknown_subject" translatable="false">Delivery Status Notification (Failure)</string>
<string name="title_user_unknown_text" translatable="false">Your message wasn\'t delivered because the address couldn\'t be found.</string>
<string name="title_receipt_subject">Read receipt: %1$s</string> <string name="title_receipt_subject">Read receipt: %1$s</string>
<string name="title_receipt_text">This read receipt only acknowledges that the message was displayed. There is no guarantee that the recipient has read the message contents.</string> <string name="title_receipt_text">This read receipt only acknowledges that the message was displayed. There is no guarantee that the recipient has read the message contents.</string>

Loading…
Cancel
Save