diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index c3a785a987..e5ee577dbd 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -274,6 +274,7 @@ public class FragmentCompose extends FragmentBase { private boolean monospaced = false; private String compose_font; + private boolean dsn = true; private Integer encrypt = null; private boolean media = true; private boolean compact = false; @@ -1586,8 +1587,8 @@ public class FragmentCompose extends FragmentBase { ImageButton ib = v.findViewById(R.id.button); TextView tv = v.findViewById(R.id.text); - v.setAlpha(state == State.LOADED ? 1f : Helper.LOW_LIGHT); - ib.setEnabled(state == State.LOADED); + v.setAlpha(state == State.LOADED && !dsn ? 1f : Helper.LOW_LIGHT); + ib.setEnabled(state == State.LOADED && !dsn); if (EntityMessage.PGP_SIGNONLY.equals(encrypt) || EntityMessage.SMIME_SIGNONLY.equals(encrypt)) { ib.setImageResource(R.drawable.twotone_gesture_24); @@ -4267,21 +4268,23 @@ public class FragmentCompose extends FragmentBase { EntityLog.log(context, "Selected=" + selected.email); - if (plain_only && - !"resend".equals(action) && - !"editasnew".equals(action)) - data.draft.plain_only = true; + if (!"dsn".equals(action)) { + if (plain_only && + !"resend".equals(action) && + !"editasnew".equals(action)) + data.draft.plain_only = true; - if (encrypt_default || selected.encrypt_default) - if (selected.encrypt == 0) - data.draft.ui_encrypt = EntityMessage.PGP_SIGNENCRYPT; - else - data.draft.ui_encrypt = EntityMessage.SMIME_SIGNENCRYPT; - else if (sign_default || selected.sign_default) - if (selected.encrypt == 0) - data.draft.ui_encrypt = EntityMessage.PGP_SIGNONLY; - else - data.draft.ui_encrypt = EntityMessage.SMIME_SIGNONLY; + if (encrypt_default || selected.encrypt_default) + if (selected.encrypt == 0) + data.draft.ui_encrypt = EntityMessage.PGP_SIGNENCRYPT; + else + data.draft.ui_encrypt = EntityMessage.SMIME_SIGNENCRYPT; + else if (sign_default || selected.sign_default) + if (selected.encrypt == 0) + data.draft.ui_encrypt = EntityMessage.PGP_SIGNONLY; + else + data.draft.ui_encrypt = EntityMessage.SMIME_SIGNONLY; + } if (receipt_default) data.draft.receipt_request = true; @@ -4519,34 +4522,36 @@ public class FragmentCompose extends FragmentBase { } else if ("participation".equals(action)) data.draft.subject = status + ": " + ref.subject; - // Sensitivity - data.draft.sensitivity = ref.sensitivity; + if (!"dsn".equals(action)) { + // Sensitivity + data.draft.sensitivity = ref.sensitivity; - // Plain-only - if (ref.plain_only != null && ref.plain_only) - data.draft.plain_only = true; + // Plain-only + if (ref.plain_only != null && ref.plain_only) + data.draft.plain_only = true; - // Encryption - List
recipients = new ArrayList<>(); - if (data.draft.to != null) - recipients.addAll(Arrays.asList(data.draft.to)); - if (data.draft.cc != null) - recipients.addAll(Arrays.asList(data.draft.cc)); - if (data.draft.bcc != null) - recipients.addAll(Arrays.asList(data.draft.bcc)); - - if (EntityMessage.PGP_SIGNONLY.equals(ref.ui_encrypt) || - EntityMessage.PGP_SIGNENCRYPT.equals(ref.ui_encrypt)) { - if (Helper.isOpenKeychainInstalled(context) && - selected.sign_key != null && - hasPgpKey(context, recipients)) - data.draft.ui_encrypt = ref.ui_encrypt; - } else if (EntityMessage.SMIME_SIGNONLY.equals(ref.ui_encrypt) || - EntityMessage.SMIME_SIGNENCRYPT.equals(ref.ui_encrypt)) { - if (ActivityBilling.isPro(context) && - selected.sign_key_alias != null && - hasSmimeKey(context, recipients)) - data.draft.ui_encrypt = ref.ui_encrypt; + // Encryption + List
recipients = new ArrayList<>(); + if (data.draft.to != null) + recipients.addAll(Arrays.asList(data.draft.to)); + if (data.draft.cc != null) + recipients.addAll(Arrays.asList(data.draft.cc)); + if (data.draft.bcc != null) + recipients.addAll(Arrays.asList(data.draft.bcc)); + + if (EntityMessage.PGP_SIGNONLY.equals(ref.ui_encrypt) || + EntityMessage.PGP_SIGNENCRYPT.equals(ref.ui_encrypt)) { + if (Helper.isOpenKeychainInstalled(context) && + selected.sign_key != null && + hasPgpKey(context, recipients)) + data.draft.ui_encrypt = ref.ui_encrypt; + } else if (EntityMessage.SMIME_SIGNONLY.equals(ref.ui_encrypt) || + EntityMessage.SMIME_SIGNENCRYPT.equals(ref.ui_encrypt)) { + if (ActivityBilling.isPro(context) && + selected.sign_key_alias != null && + hasSmimeKey(context, recipients)) + data.draft.ui_encrypt = ref.ui_encrypt; + } } // Reply template @@ -4970,6 +4975,7 @@ public class FragmentCompose extends FragmentBase { } working = data.draft.id; + dsn = (data.draft.dsn != null && !EntityMessage.DSN_NONE.equals(data.draft.dsn)); encrypt = data.draft.ui_encrypt; invalidateOptionsMenu(); @@ -5767,8 +5773,10 @@ public class FragmentCompose extends FragmentBase { args.putBoolean("remind_external", external); } - if (draft.ui_encrypt == null || - EntityMessage.ENCRYPT_NONE.equals(draft.ui_encrypt)) { + if ((draft.dsn == null || + EntityMessage.DSN_NONE.equals(draft.dsn)) && + (draft.ui_encrypt == null || + EntityMessage.ENCRYPT_NONE.equals(draft.ui_encrypt))) { args.putBoolean("remind_pgp", hasPgpKey(context, recipients)); args.putBoolean("remind_smime", hasSmimeKey(context, recipients)); } @@ -6866,7 +6874,6 @@ public class FragmentCompose extends FragmentBase { final Spinner spEncrypt = dview.findViewById(R.id.spEncrypt); final ImageButton ibEncryption = dview.findViewById(R.id.ibEncryption); final Spinner spPriority = dview.findViewById(R.id.spPriority); - final ImageButton ibPriority = dview.findViewById(R.id.ibPriority); final Spinner spSensitivity = dview.findViewById(R.id.spSensitivity); final ImageButton ibSensitivity = dview.findViewById(R.id.ibSensitivity); final TextView tvSendAt = dview.findViewById(R.id.tvSendAt); @@ -7131,13 +7138,6 @@ public class FragmentCompose extends FragmentBase { } }); - ibPriority.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // Invisible - } - }); - spSensitivity.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java index 57efd0f397..5b853141ac 100644 --- a/app/src/main/java/eu/faircode/email/MessageHelper.java +++ b/app/src/main/java/eu/faircode/email/MessageHelper.java @@ -489,226 +489,228 @@ public class MessageHelper { List attachments = db.attachment().getAttachments(message.id); - if (message.from != null && message.from.length > 0) - for (EntityAttachment attachment : attachments) - if (EntityAttachment.PGP_KEY.equals(attachment.encryption)) { - InternetAddress from = (InternetAddress) message.from[0]; + if (message.dsn == null || EntityMessage.DSN_NONE.equals(message.dsn)) { + if (message.from != null && message.from.length > 0) + for (EntityAttachment attachment : attachments) + if (EntityAttachment.PGP_KEY.equals(attachment.encryption)) { + InternetAddress from = (InternetAddress) message.from[0]; + + if (autocrypt) { + String mode = (mutual ? "mutual" : "nopreference"); + + StringBuilder sb = new StringBuilder(); + File file = attachment.getFile(context); + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line = br.readLine(); + while (line != null) { + String data = null; + if (line.length() > 0 && + !line.startsWith("-----BEGIN ") && + !line.startsWith("-----END ")) + data = line; + + line = br.readLine(); + + // https://www.w3.org/Protocols/rfc822/3_Lexical.html#z0 + if (data != null && + line != null && !line.startsWith("-----END ")) + sb.append("\r\n ").append(data); + } + } - if (autocrypt) { - String mode = (mutual ? "mutual" : "nopreference"); + // https://autocrypt.org/level1.html#the-autocrypt-header + imessage.addHeader("Autocrypt", + "addr=" + from.getAddress() + ";" + + " prefer-encrypt=" + mode + ";" + + " keydata=" + sb.toString()); + } + } - StringBuilder sb = new StringBuilder(); - File file = attachment.getFile(context); - try (BufferedReader br = new BufferedReader(new FileReader(file))) { - String line = br.readLine(); - while (line != null) { - String data = null; - if (line.length() > 0 && - !line.startsWith("-----BEGIN ") && - !line.startsWith("-----END ")) - data = line; - - line = br.readLine(); - - // https://www.w3.org/Protocols/rfc822/3_Lexical.html#z0 - if (data != null && - line != null && !line.startsWith("-----END ")) - sb.append("\r\n ").append(data); + // PGP: https://tools.ietf.org/html/rfc3156 + // S/MIME: https://tools.ietf.org/html/rfc8551 + for (final EntityAttachment attachment : attachments) + if (EntityAttachment.PGP_SIGNATURE.equals(attachment.encryption)) { + Log.i("Sending PGP signed message"); + + for (final EntityAttachment content : attachments) + if (EntityAttachment.PGP_CONTENT.equals(content.encryption)) { + BodyPart bpContent = new MimeBodyPart(new FileInputStream(content.getFile(context))); + + final ContentType cts = new ContentType(attachment.type); + String micalg = cts.getParameter("micalg"); + if (TextUtils.isEmpty(micalg)) { + // Some providers strip parameters + // https://tools.ietf.org/html/rfc3156#section-5 + Log.w("PGP micalg missing type=" + attachment.type); } - } + ParameterList params = cts.getParameterList(); + if (params != null) + params.remove("micalg"); + cts.setParameterList(params); + + // Build signature + BodyPart bpSignature = new MimeBodyPart(); + bpSignature.setFileName(attachment.name); + FileDataSource dsSignature = new FileDataSource(attachment.getFile(context)); + dsSignature.setFileTypeMap(new FileTypeMap() { + @Override + public String getContentType(File file) { + return cts.toString(); + } - // https://autocrypt.org/level1.html#the-autocrypt-header - imessage.addHeader("Autocrypt", - "addr=" + from.getAddress() + ";" + - " prefer-encrypt=" + mode + ";" + - " keydata=" + sb.toString()); - } - } + @Override + public String getContentType(String filename) { + return cts.toString(); + } + }); + bpSignature.setDataHandler(new DataHandler(dsSignature)); + bpSignature.setDisposition(Part.INLINE); + + // Build message + ContentType ct = new ContentType("multipart/signed"); + if (micalg != null) + ct.setParameter("micalg", micalg); + ct.setParameter("protocol", "application/pgp-signature"); + String ctx = ct.toString(); + int slash = ctx.indexOf("/"); + Multipart multipart = new MimeMultipart(ctx.substring(slash + 1)); + multipart.addBodyPart(bpContent); + multipart.addBodyPart(bpSignature); + imessage.setContent(multipart); + + return imessage; + } + throw new IllegalStateException("PGP content not found"); + } else if (EntityAttachment.PGP_MESSAGE.equals(attachment.encryption)) { + Log.i("Sending PGP encrypted message"); + + // Build header + // https://tools.ietf.org/html/rfc3156 + BodyPart bpHeader = new MimeBodyPart(); + bpHeader.setContent("Version: 1\n", "application/pgp-encrypted"); + + // Build content + BodyPart bpContent = new MimeBodyPart(); + bpContent.setFileName(attachment.name); + FileDataSource dsContent = new FileDataSource(attachment.getFile(context)); + dsContent.setFileTypeMap(new FileTypeMap() { + @Override + public String getContentType(File file) { + return attachment.type; + } - // PGP: https://tools.ietf.org/html/rfc3156 - // S/MIME: https://tools.ietf.org/html/rfc8551 - for (final EntityAttachment attachment : attachments) - if (EntityAttachment.PGP_SIGNATURE.equals(attachment.encryption)) { - Log.i("Sending PGP signed message"); - - for (final EntityAttachment content : attachments) - if (EntityAttachment.PGP_CONTENT.equals(content.encryption)) { - BodyPart bpContent = new MimeBodyPart(new FileInputStream(content.getFile(context))); - - final ContentType cts = new ContentType(attachment.type); - String micalg = cts.getParameter("micalg"); - if (TextUtils.isEmpty(micalg)) { - // Some providers strip parameters - // https://tools.ietf.org/html/rfc3156#section-5 - Log.w("PGP micalg missing type=" + attachment.type); + @Override + public String getContentType(String filename) { + return attachment.type; } - ParameterList params = cts.getParameterList(); - if (params != null) - params.remove("micalg"); - cts.setParameterList(params); - - // Build signature - BodyPart bpSignature = new MimeBodyPart(); - bpSignature.setFileName(attachment.name); - FileDataSource dsSignature = new FileDataSource(attachment.getFile(context)); - dsSignature.setFileTypeMap(new FileTypeMap() { - @Override - public String getContentType(File file) { - return cts.toString(); + }); + bpContent.setDataHandler(new DataHandler(dsContent)); + bpContent.setDisposition(Part.INLINE); + + // Build message + ContentType ct = new ContentType("multipart/encrypted"); + ct.setParameter("protocol", "application/pgp-encrypted"); + String ctx = ct.toString(); + int slash = ctx.indexOf("/"); + Multipart multipart = new MimeMultipart(ctx.substring(slash + 1)); + multipart.addBodyPart(bpHeader); + multipart.addBodyPart(bpContent); + imessage.setContent(multipart); + + if (encrypt_subject) + imessage.setSubject("..."); + + return imessage; + } else if (EntityAttachment.SMIME_SIGNATURE.equals(attachment.encryption)) { + Log.i("Sending S/MIME signed message"); + + for (final EntityAttachment content : attachments) + if (EntityAttachment.SMIME_CONTENT.equals(content.encryption)) { + BodyPart bpContent = new MimeBodyPart(new FileInputStream(content.getFile(context))); + + final ContentType cts = new ContentType(attachment.type); + String micalg = cts.getParameter("micalg"); + if (TextUtils.isEmpty(micalg)) { + // Some providers strip parameters + Log.w("S/MIME micalg missing type=" + attachment.type); + micalg = "sha-256"; } + ParameterList params = cts.getParameterList(); + if (params != null) + params.remove("micalg"); + cts.setParameterList(params); + + // Build signature + BodyPart bpSignature = new MimeBodyPart(); + bpSignature.setFileName(attachment.name); + FileDataSource dsSignature = new FileDataSource(attachment.getFile(context)); + dsSignature.setFileTypeMap(new FileTypeMap() { + @Override + public String getContentType(File file) { + return cts.toString(); + } - @Override - public String getContentType(String filename) { - return cts.toString(); - } - }); - bpSignature.setDataHandler(new DataHandler(dsSignature)); - bpSignature.setDisposition(Part.INLINE); + @Override + public String getContentType(String filename) { + return cts.toString(); + } + }); + bpSignature.setDataHandler(new DataHandler(dsSignature)); + bpSignature.setDisposition(Part.INLINE); - // Build message - ContentType ct = new ContentType("multipart/signed"); - if (micalg != null) + // Build message + ContentType ct = new ContentType("multipart/signed"); ct.setParameter("micalg", micalg); - ct.setParameter("protocol", "application/pgp-signature"); - String ctx = ct.toString(); - int slash = ctx.indexOf("/"); - Multipart multipart = new MimeMultipart(ctx.substring(slash + 1)); - multipart.addBodyPart(bpContent); - multipart.addBodyPart(bpSignature); - imessage.setContent(multipart); - - return imessage; - } - throw new IllegalStateException("PGP content not found"); - } else if (EntityAttachment.PGP_MESSAGE.equals(attachment.encryption)) { - Log.i("Sending PGP encrypted message"); - - // Build header - // https://tools.ietf.org/html/rfc3156 - BodyPart bpHeader = new MimeBodyPart(); - bpHeader.setContent("Version: 1\n", "application/pgp-encrypted"); - - // Build content - BodyPart bpContent = new MimeBodyPart(); - bpContent.setFileName(attachment.name); - FileDataSource dsContent = new FileDataSource(attachment.getFile(context)); - dsContent.setFileTypeMap(new FileTypeMap() { - @Override - public String getContentType(File file) { - return attachment.type; - } + ct.setParameter("protocol", "application/pkcs7-signature"); + ct.setParameter("smime-type", "signed-data"); + String ctx = ct.toString(); + int slash = ctx.indexOf("/"); + Multipart multipart = new MimeMultipart(ctx.substring(slash + 1)); + multipart.addBodyPart(bpContent); + multipart.addBodyPart(bpSignature); + imessage.setContent(multipart); + + return imessage; + } + throw new IllegalStateException("S/MIME content not found"); + } else if (EntityAttachment.SMIME_MESSAGE.equals(attachment.encryption)) { + Log.i("Sending S/MIME encrypted message"); - @Override - public String getContentType(String filename) { - return attachment.type; - } - }); - bpContent.setDataHandler(new DataHandler(dsContent)); - bpContent.setDisposition(Part.INLINE); - - // Build message - ContentType ct = new ContentType("multipart/encrypted"); - ct.setParameter("protocol", "application/pgp-encrypted"); - String ctx = ct.toString(); - int slash = ctx.indexOf("/"); - Multipart multipart = new MimeMultipart(ctx.substring(slash + 1)); - multipart.addBodyPart(bpHeader); - multipart.addBodyPart(bpContent); - imessage.setContent(multipart); - - if (encrypt_subject) - imessage.setSubject("..."); - - return imessage; - } else if (EntityAttachment.SMIME_SIGNATURE.equals(attachment.encryption)) { - Log.i("Sending S/MIME signed message"); - - for (final EntityAttachment content : attachments) - if (EntityAttachment.SMIME_CONTENT.equals(content.encryption)) { - BodyPart bpContent = new MimeBodyPart(new FileInputStream(content.getFile(context))); - - final ContentType cts = new ContentType(attachment.type); - String micalg = cts.getParameter("micalg"); - if (TextUtils.isEmpty(micalg)) { - // Some providers strip parameters - Log.w("S/MIME micalg missing type=" + attachment.type); - micalg = "sha-256"; + // Build message + imessage.setDisposition(Part.ATTACHMENT); + imessage.setFileName(attachment.name); + imessage.setDescription("S/MIME Encrypted Message"); + + ContentType ct = new ContentType("application/pkcs7-mime"); + ct.setParameter("name", attachment.name); + ct.setParameter("smime-type", "enveloped-data"); + + File file = attachment.getFile(context); + FileDataSource dataSource = new FileDataSource(file); + dataSource.setFileTypeMap(new FileTypeMap() { + @Override + public String getContentType(File file) { + return ct.toString(); } - ParameterList params = cts.getParameterList(); - if (params != null) - params.remove("micalg"); - cts.setParameterList(params); - - // Build signature - BodyPart bpSignature = new MimeBodyPart(); - bpSignature.setFileName(attachment.name); - FileDataSource dsSignature = new FileDataSource(attachment.getFile(context)); - dsSignature.setFileTypeMap(new FileTypeMap() { - @Override - public String getContentType(File file) { - return cts.toString(); - } - @Override - public String getContentType(String filename) { - return cts.toString(); - } - }); - bpSignature.setDataHandler(new DataHandler(dsSignature)); - bpSignature.setDisposition(Part.INLINE); - - // Build message - ContentType ct = new ContentType("multipart/signed"); - ct.setParameter("micalg", micalg); - ct.setParameter("protocol", "application/pkcs7-signature"); - ct.setParameter("smime-type", "signed-data"); - String ctx = ct.toString(); - int slash = ctx.indexOf("/"); - Multipart multipart = new MimeMultipart(ctx.substring(slash + 1)); - multipart.addBodyPart(bpContent); - multipart.addBodyPart(bpSignature); - imessage.setContent(multipart); - - return imessage; - } - throw new IllegalStateException("S/MIME content not found"); - } else if (EntityAttachment.SMIME_MESSAGE.equals(attachment.encryption)) { - Log.i("Sending S/MIME encrypted message"); - - // Build message - imessage.setDisposition(Part.ATTACHMENT); - imessage.setFileName(attachment.name); - imessage.setDescription("S/MIME Encrypted Message"); - - ContentType ct = new ContentType("application/pkcs7-mime"); - ct.setParameter("name", attachment.name); - ct.setParameter("smime-type", "enveloped-data"); - - File file = attachment.getFile(context); - FileDataSource dataSource = new FileDataSource(file); - dataSource.setFileTypeMap(new FileTypeMap() { - @Override - public String getContentType(File file) { - return ct.toString(); - } + @Override + public String getContentType(String filename) { + return ct.toString(); + } + }); - @Override - public String getContentType(String filename) { - return ct.toString(); - } - }); + imessage.setDataHandler(new DataHandler(dataSource)); - imessage.setDataHandler(new DataHandler(dataSource)); + return imessage; + } - return imessage; + if (EntityMessage.PGP_SIGNENCRYPT.equals(message.ui_encrypt) || + EntityMessage.SMIME_SIGNENCRYPT.equals(message.ui_encrypt)) { + String msg = "Storing unencrypted message" + + " encrypt=" + message.encrypt + "/" + message.ui_encrypt; + Log.w(msg); + throw new IllegalArgumentException(msg); } - - if (EntityMessage.PGP_SIGNENCRYPT.equals(message.ui_encrypt) || - EntityMessage.SMIME_SIGNENCRYPT.equals(message.ui_encrypt)) { - String msg = "Storing unencrypted message" + - " encrypt=" + message.encrypt + "/" + message.ui_encrypt; - Log.w(msg); - throw new IllegalArgumentException(msg); } build(context, message, attachments, identity, send, imessage); diff --git a/app/src/main/res/layout/dialog_send.xml b/app/src/main/res/layout/dialog_send.xml index 3a07c76f26..6336ded07a 100644 --- a/app/src/main/res/layout/dialog_send.xml +++ b/app/src/main/res/layout/dialog_send.xml @@ -387,25 +387,10 @@ android:layout_height="wrap_content" android:layout_marginEnd="12dp" android:entries="@array/priorityNames" - app:layout_constraintEnd_toStartOf="@id/ibPriority" + app:layout_constraintEnd_toStartOf="@id/ibSensitivity" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvPriority" /> - - + tvEncrypt,spEncrypt,ibEncryption, + tvPriority,spPriority, + tvSensitivity,spSensitivity,ibSensitivity" /> \ No newline at end of file