...
 
Commits (277)
buildscript {
ext {
buildConfig = [
'compileSdk' : 28,
'compileSdk' : 29,
'targetSdk' : 28,
'minSdk' : 21,
'versionCode' : 42,
'pEpEngineRevision' : 4465,
'pEpJNIAdapterRevision': 653,
'versionName' : '1.0.233',
'versionCode' : 43,
'pEpEngineRevision' : 4499,
'pEpJNIAdapterRevision': 660,
'versionName' : '1.0.234',
'libpEpAdapterRevision': 158
]
......
......@@ -13,6 +13,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -34,6 +35,9 @@ import com.fsck.k9.mail.internet.MimeHeader;
import com.fsck.k9.mail.internet.MimeMessageHelper;
import com.fsck.k9.mail.internet.MimeMultipart;
import com.fsck.k9.mail.internet.MimeUtility;
import org.jetbrains.annotations.NotNull;
import timber.log.Timber;
import static com.fsck.k9.mail.store.imap.ImapUtility.getLastResponse;
......@@ -46,6 +50,13 @@ class ImapFolder extends Folder<ImapMessage> {
return new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
}
};
private static final ThreadLocal<SimpleDateFormat> RFC2822_DATE = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US);
}
};
private static final int MORE_MESSAGES_WINDOW_SIZE = 500;
private static final int FETCH_WINDOW_SIZE = 100;
......@@ -1155,8 +1166,7 @@ class ImapFolder extends Folder<ImapMessage> {
String encodeFolderName = folderNameCodec.encode(getPrefixedName());
String escapedFolderName = ImapUtility.encodeString(encodeFolderName);
String command = String.format(Locale.US, "APPEND %s (%s) {%d}", escapedFolderName,
combineFlags(message.getFlags()), messageSize);
String command = generateAppendCommand(message, messageSize, escapedFolderName);
connection.sendCommand(command, false);
ImapResponse response;
......@@ -1225,6 +1235,19 @@ class ImapFolder extends Folder<ImapMessage> {
}
}
@NotNull
private String generateAppendCommand(Message message, long messageSize, String escapedFolderName) {
if (message.getInternalDate() == null) {
return String.format(Locale.US, "APPEND %s (%s) {%d}", escapedFolderName,
combineFlags(message.getFlags()), messageSize);
} else {
String internalDate = Objects.requireNonNull(RFC2822_DATE.get()).format(message.getInternalDate());
String escapedInternalDate = ImapUtility.encodeString(internalDate);
return String.format(Locale.US, "APPEND %s (%s) %s {%d}", escapedFolderName,
combineFlags(message.getFlags()), escapedInternalDate, messageSize);
}
}
@NonNull
private List<Message> filterAppendingMessages(List<? extends Message> messages) {
List<Message> filteredMessages = new ArrayList<>();
......
......@@ -3,7 +3,6 @@ package com.fsck.k9;
import android.app.Activity;
import android.app.Application;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
......@@ -48,7 +47,7 @@ import com.fsck.k9.pEp.infrastructure.Poller;
import com.fsck.k9.pEp.infrastructure.components.ApplicationComponent;
import com.fsck.k9.pEp.infrastructure.components.DaggerApplicationComponent;
import com.fsck.k9.pEp.infrastructure.modules.ApplicationModule;
import com.fsck.k9.pEp.ui.keysync.PEpAddDevice;
import com.fsck.k9.pEp.manualsync.ImportWizardFrompEp;
import com.fsck.k9.power.DeviceIdleManager;
import com.fsck.k9.preferences.Storage;
import com.fsck.k9.preferences.StorageEditor;
......@@ -332,7 +331,7 @@ public class K9 extends MultiDexApplication {
private static String pEpExtraAccounts = "";
//private static boolean pEpUseKeyserver = false;
private static boolean pEpPassiveMode = false;
private static boolean pEpSubjectUnprotected = false;
private static boolean pEpSubjectProtection = true;
private static boolean pEpForwardWarningEnabled = false;
private static boolean pEpSyncEnabled = BuildConfig.WITH_KEY_SYNC;
private static boolean shallRequestPermissions = true;
......@@ -604,7 +603,7 @@ public class K9 extends MultiDexApplication {
editor.putString("pEpExtraAccounts", pEpExtraAccounts);
//editor.putBoolean("pEpUseKeyserver", pEpUseKeyserver);
editor.putBoolean("pEpPassiveMode", pEpPassiveMode);
editor.putBoolean("pEpSubjectUnprotected", pEpSubjectUnprotected);
editor.putBoolean("pEpSubjectProtection", pEpSubjectProtection);
editor.putBoolean("pEpForwardWarningEnabled", pEpForwardWarningEnabled);
editor.putBoolean("pEpEnableSync", pEpSyncEnabled);
editor.putBoolean("shallRequestPermissions", shallRequestPermissions);
......@@ -785,8 +784,11 @@ public class K9 extends MultiDexApplication {
}
public PEpProvider getpEpSyncProvider() {
if (pEpSyncEnabled) return pEpSyncProvider;
else return pEpProvider;
if (pEpSyncEnabled) {
return pEpSyncProvider;
} else {
return pEpProvider;
}
}
private void initSync() {
......@@ -807,19 +809,17 @@ public class K9 extends MultiDexApplication {
}
});
// if (Preferences.getPreferences(this).getAccounts().size() > 0) {
if (!pEpSyncProvider.isSyncRunning()) {
if (!pEpSyncProvider.isSyncRunning()) {
pEpSyncProvider.startSync();
}
// }
}
private void goToAddDevice(Identity myself, Identity partner, SyncHandshakeSignal signal, String explanation) {
private void goToAddDevice(Identity myself, Identity partner, SyncHandshakeSignal signal, boolean formingGroup) {
Timber.i("PEPJNI", "showHandshake: " + signal.name() + " " + myself.toString() + "\n::\n" + partner.toString());
language = Locale.getDefault().getLanguage();
String trust = pEpSyncProvider.trustwords(myself, partner, language, true);
Context context = K9.this.getApplicationContext();
Intent syncTrustowordsActivity = PEpAddDevice.getActionRequestHandshake(context, trust, myself, partner, explanation, false);
Intent syncTrustowordsActivity = ImportWizardFrompEp.createActionStartKeySyncIntent(context, myself, partner, signal, formingGroup);
syncTrustowordsActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(syncTrustowordsActivity);
}
......@@ -963,7 +963,7 @@ public class K9 extends MultiDexApplication {
pEpExtraAccounts = storage.getString("pEpExtraAccounts", null);
//pEpUseKeyserver = storage.getBoolean("pEpUseKeyserver", false);
pEpPassiveMode = storage.getBoolean("pEpPassiveMode", false);
pEpSubjectUnprotected = storage.getBoolean("pEpSubjectUnprotected", false);
pEpSubjectProtection = getValuePEpSubjectProtection(storage);
pEpForwardWarningEnabled = storage.getBoolean("pEpForwardWarningEnabled", false);
pEpSyncEnabled = storage.getBoolean("pEpEnableSync", BuildConfig.WITH_KEY_SYNC);
......@@ -1013,6 +1013,10 @@ public class K9 extends MultiDexApplication {
K9.setUseFixedMessageViewTheme(storage.getBoolean("fixedMessageViewTheme", true));
}
private static boolean getValuePEpSubjectProtection(Storage storage) {
return storage.getBoolean("pEpSubjectProtection", !storage.getBoolean("pEpSubjectUnprotected", false));
}
/**
* Mutually excluyent setter for the behavior after a message is deleted.
*
......@@ -1070,6 +1074,10 @@ public class K9 extends MultiDexApplication {
return language;
}
public static String getK9CurrentLanguage() {
return language.isEmpty() ? Locale.getDefault().getLanguage() : language;
}
public static void setK9Language(String nlanguage) {
language = nlanguage;
}
......@@ -1750,14 +1758,14 @@ public class K9 extends MultiDexApplication {
}
public static boolean ispEpSubjectUnprotected() {
return pEpSubjectUnprotected;
public static boolean ispEpSubjectProtection() {
return pEpSubjectProtection;
}
public void setpEpSubjectUnprotected(boolean pEpSubjectUnprotected) {
K9.pEpSubjectUnprotected = pEpSubjectUnprotected;
pEpProvider.setSubjectUnprotected(pEpSubjectUnprotected);
MessagingController.getInstance(this).setSubjectUnprotected(pEpSubjectUnprotected);
public void setpEpSubjectProtection(boolean pEpSubjectProtection) {
K9.pEpSubjectProtection = pEpSubjectProtection;
pEpProvider.setSubjectProtection(pEpSubjectProtection);
MessagingController.getInstance(this).setSubjectProtected(pEpSubjectProtection);
}
......@@ -1824,6 +1832,7 @@ public class K9 extends MultiDexApplication {
} else {
shutdownSync();
}
forceSaveAppSettings();
}
public boolean needsFastPoll() {
......@@ -1842,42 +1851,41 @@ public class K9 extends MultiDexApplication {
@Override
public void notifyHandshake(Identity myself, Identity partner, SyncHandshakeSignal signal) {
System.out.println("pEpSync" + "notifyHandshakeCallFromC: " + notifyHandshakeCallback + " :: " + signal.name());
new Handler(Looper.getMainLooper()).post(()
-> Toast.makeText(K9.this, signal.name(), Toast.LENGTH_SHORT).show());
Log.e("pEpEngine", String.format("pEp notifyHandshake: %s", signal.name()));
// Before starting a new "event" we dismiss the current one.
Intent broadcastIntent = new Intent("KEYSYNC_DISMISS");
K9.this.sendOrderedBroadcast(broadcastIntent, null);
// Intent broadcastIntent = new Intent("KEYSYNC_DISMISS");
// K9.this.sendOrderedBroadcast(broadcastIntent, null);
switch (signal) {
case SyncNotifyUndefined:
break;
case SyncNotifyInitAddOurDevice:
case SyncNotifyInitAddOtherDevice:
ImportWizardFrompEp.actionStartKeySync(getApplicationContext(), myself, partner, signal, false);
break;
case SyncNotifyInitFormGroup:
ImportWizardFrompEp.actionStartKeySync(getApplicationContext(), myself, partner, signal, true);
needsFastPoll = true;
goToAddDevice(myself, partner, signal, getString(R.string.pep_add_device_ask_trustwords));
break;
case SyncNotifyTimeout:
//Close handshake
new Handler(Looper.getMainLooper()).post(()
-> Toast.makeText(K9.this, R.string.pep_keysync_timeout, Toast.LENGTH_SHORT).show());
ImportWizardFrompEp.notifyNewSignal(getApplicationContext(), signal);
needsFastPoll = false;
break;
case SyncNotifyAcceptedDeviceAdded:
case SyncNotifyAcceptedGroupCreated:
needsFastPoll = false;
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(K9.this, R.string.pep_device_group, Toast.LENGTH_LONG).show());
break;
case SyncNotifySole:
needsFastPoll = false;
grouped = false;
ImportWizardFrompEp.notifyNewSignal(getApplicationContext(), signal);
break;
case SyncNotifyInGroup:
needsFastPoll = false;
grouped = true;
pEpSyncEnabled = true;
ImportWizardFrompEp.notifyNewSignal(getApplicationContext(), signal);
break;
}
......@@ -1912,5 +1920,12 @@ public class K9 extends MultiDexApplication {
pEpSyncEnabled = false;
}
private void forceSaveAppSettings() {
StorageEditor editor = Preferences.getPreferences(this).getStorage().edit();
save(editor);
editor.commit();
}
}
......@@ -32,6 +32,8 @@ import butterknife.OnClick;
import butterknife.OnEditorAction;
import butterknife.OnTextChanged;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
public abstract class K9Activity extends AppCompatActivity implements K9ActivityMagic {
......@@ -47,6 +49,12 @@ public abstract class K9Activity extends AppCompatActivity implements K9Activity
@Override
public void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getWindow().getDecorView().setSystemUiVisibility(
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
);
}
mBase = K9ActivityCommon.newInstance(this);
super.onCreate(savedInstanceState);
// ((K9) getApplication()).pEpSyncProvider.setSyncHandshakeCallback(this);
......
......@@ -30,6 +30,7 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
......@@ -445,6 +446,23 @@ public class MessageList extends PepActivity implements MessageListFragmentListe
setupNavigationFoldersList();
createFoldersMenu();
setNavigationViewInsets();
}
private void setNavigationViewInsets() {
ViewCompat.setOnApplyWindowInsetsListener(
navigationView,
(v, insets) -> {
View view = navigationView.findViewById(R.id.menu_header);
view.setPadding(
view.getPaddingLeft(),
insets.getSystemWindowInsetTop(),
view.getPaddingRight(),
view.getPaddingBottom()
);
return insets.consumeSystemWindowInsets();
});
}
private void setupNavigationFoldersList() {
......@@ -2352,7 +2370,13 @@ public class MessageList extends PepActivity implements MessageListFragmentListe
@Override
public void goBack() {
if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) {
if (mDisplayMode == DisplayMode.MESSAGE_VIEW && mMessageListWasDisplayed) {
if(!isThreadDisplayed) {
updateToolbarColorToOriginal();
}
showMessageList();
}
else if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) {
if(isBackstackClear()) {
if (mAccount != null) {
Router.onOpenAccount(this, mAccount);
......@@ -2363,11 +2387,6 @@ public class MessageList extends PepActivity implements MessageListFragmentListe
finish();
}
} else if (mDisplayMode == DisplayMode.MESSAGE_VIEW && mMessageListWasDisplayed) {
if(!isThreadDisplayed) {
updateToolbarColorToOriginal();
}
showMessageList();
} else if (isThreadDisplayed) {
actionDisplaySearch(this, mSearch, false, false);
} else if (getIntent().getBooleanExtra(EXTRA_FOLDER, false)) {
......
......@@ -338,7 +338,7 @@ class SettingsActivity : PEpImporterActivity(), PreferenceFragmentCompat.OnPrefe
TOP, MIDDLE, BOTTOM
}
private fun accountLocation(account: BaseAccount): EnumSet<ACCOUNT_LOCATION> {
private fun accountLocation(account: BaseAccount?): EnumSet<ACCOUNT_LOCATION> {
val accountLocation = EnumSet.of(ACCOUNT_LOCATION.MIDDLE)
if (accounts.size > 0) {
if (accounts[0] == account) {
......
......@@ -19,11 +19,15 @@ import timber.log.Timber;
class TrustedMessageController {
boolean shouldDownloadMessageInTrustedServer(PEpProvider.DecryptResult result, MimeMessage decryptedMessage, Account account) {
boolean shouldReuploadMessageInTrustedServer(PEpProvider.DecryptResult result,
MimeMessage decryptedMessage,
Account account,
boolean alreadyDecrypted) {
return account.ispEpPrivacyProtected()
&& !account.isUntrustedSever()
&& result.flags == -1
&& !decryptedMessage.isSet(Flag.X_PEP_NEVER_UNSECURE);
&& !decryptedMessage.isSet(Flag.X_PEP_NEVER_UNSECURE)
&& !alreadyDecrypted;
}
<T extends Message> boolean shouldAppendMessageInTrustedServer(T message, Account account) {
......@@ -58,6 +62,7 @@ class TrustedMessageController {
localMessage.getFlags().contains(Flag.X_PEP_NEVER_UNSECURE)) { //Untrusted server
encryptedMessage = encryptUntrustedMessage(context, pEpProvider, account, localMessage);
} else { // Trusted
localMessage.setInternalDate(localMessage.getSentDate());
return localMessage;
}
return encryptedMessage;
......
package com.fsck.k9.message.quote;
import java.io.Serializable;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* <p>Represents an HTML document with an insertion point for placing a reply. The quoted
......@@ -12,8 +15,8 @@ import java.io.Serializable;
*
* TODO: This container should also have a text part, along with its insertion point. Or maybe a generic InsertableContent and maintain one each for Html and Text?
*/
public class InsertableHtmlContent implements Serializable {
private static final long serialVersionUID = 2397327034L;
public class InsertableHtmlContent implements Parcelable {
// Default to a headerInsertionPoint at the beginning of the message.
private int headerInsertionPoint = 0;
private int footerInsertionPoint = 0;
......@@ -24,6 +27,8 @@ public class InsertableHtmlContent implements Serializable {
// Where to insert the content. Default to top posting.
private InsertionLocation insertionLocation = InsertionLocation.BEFORE_QUOTE;
public InsertableHtmlContent() { }
/**
* Defines where user content should be inserted, either before or after quoted content.
*/
......@@ -167,4 +172,43 @@ public class InsertableHtmlContent implements Serializable {
", compiledResult=" + toString() +
'}';
}
/*
Parcelable implementation
*/
private InsertableHtmlContent(Parcel in) {
headerInsertionPoint = in.readInt();
footerInsertionPoint = in.readInt();
// TODO: 2020-03-23 Check if it is really needed to store the Strings.
quotedContent = new StringBuilder(Objects.requireNonNull(in.readString()));
userContent = new StringBuilder(Objects.requireNonNull(in.readString()));
}
public static final Creator<InsertableHtmlContent> CREATOR = new Creator<InsertableHtmlContent>() {
@Override
public InsertableHtmlContent createFromParcel(Parcel in) {
return new InsertableHtmlContent(in);
}
@Override
public InsertableHtmlContent[] newArray(int size) {
return new InsertableHtmlContent[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(headerInsertionPoint);
dest.writeInt(footerInsertionPoint);
// TODO: 2020-03-23 Check if it is really needed to store the Strings.
dest.writeString(quotedContent.toString());
dest.writeString(userContent.toString());
}
}
......@@ -65,12 +65,12 @@ class PEpMessageBuilder {
// - plain text body if html above
// - many attachments (of type binarymemoryblob (hopefully ;-)).
Body b = mm.getBody();
Vector<Blob> attachments = new Vector<Blob>();
Vector<Blob> attachments = new Vector<>();
if(!(b instanceof MimeMultipart)) { //FIXME: Don't do this assumption (if not Multipart then plain or html text)
String disposition = MimeUtility.unfoldAndDecode(mm.getDisposition());
if (("attachment".equalsIgnoreCase(MessageExtractor.getContentDisposition(mm)))) {
if ((isAnAttachment(mm))) {
Log.i("PEpMessageBuilder", "addBody 1 " + disposition);
String filename = MimeUtility.getHeaderParameter(disposition, "filename");
addAttachment(attachments, mm.getContentType(), filename, PEpUtils.extractBodyContent(b));
......@@ -78,13 +78,7 @@ class PEpMessageBuilder {
// return;
}
String charset = MimeUtility.getHeaderParameter(mm.getContentType(), "charset");
if (charset == null || !Charset.isSupported(charset)) {
// failback when the header doesn't have charset parameter or it is invalid, defaults to UTF-8
// FIXME: charset, trate non text bod4y types like application/pgp-keys
charset = Charset.defaultCharset().name();
}
String charset = getMessageCharset();
String text = new String(PEpUtils.extractBodyContent(b), charset);
if(mm.isMimeType("text/html")) {
pEpMsg.setLongmsgFormatted(text);
......@@ -100,6 +94,17 @@ class PEpMessageBuilder {
pEpMsg.setAttachments(attachments);
}
private String getMessageCharset() {
String charset = MimeUtility.getHeaderParameter(mm.getContentType(), "charset");
if (charset == null || !Charset.isSupported(charset)) {
// failback when the header doesn't have charset parameter or it is invalid, defaults to UTF-8
// FIXME: charset, treat non text body types like application/pgp-keys
charset = Charset.defaultCharset().name();
}
return charset;
}
private void handleMultipart(Message pEpMsg, MimeMultipart mmp, Vector<Blob> attachments) throws MessagingException, IOException, UnsupportedEncodingException {
int nrOfParts = mmp.getBodyParts().size();
for (int part = 0; part < nrOfParts; part++) {
......@@ -117,14 +122,10 @@ class PEpMessageBuilder {
//FIXME> Deal with non text and non multipart message and non attachments
boolean plain = mbp.isMimeType("text/plain");
if (plain || mbp.isMimeType("text/html")) {
String charset = MimeUtility.getHeaderParameter(mbp.getContentType(), "charset");
String text;
if (charset != null) {
text = new String(PEpUtils.extractBodyContent(mbp_body), charset);
} else {
text = new String(PEpUtils.extractBodyContent(mbp_body));
}
if (!isAnAttachment(mbp) && (plain || mbp.isMimeType("text/html"))) {
String charset = getMessageCharset();
String text = new String(PEpUtils.extractBodyContent(mbp_body), charset);
if (plain) {
String longmsg = pEpMsg.getLongmsg();
if (longmsg != null) {
......@@ -231,7 +232,7 @@ class PEpMessageBuilder {
}
private Vector<String> createMessageReferences(String[] references) {
Vector<String> rv = new Vector<String>();
Vector<String> rv = new Vector<>();
if(references != null)
for(String s : references)
rv.add(s);
......@@ -243,7 +244,7 @@ class PEpMessageBuilder {
if (part.getMimeType().equalsIgnoreCase("message/rfc822")) return "ForwardedMessage.eml";
if (filename == null) {
String disposition = MimeUtility.unfoldAndDecode(part.getDisposition());
if (("attachment".equalsIgnoreCase(MessageExtractor.getContentDisposition(part)))) {
if (isAnAttachment(part)) {
Log.i("PEpMessageBuilder", "addBody 1 " + disposition);
filename = MimeUtility.getHeaderParameter(disposition, "filename");
}
......@@ -252,4 +253,8 @@ class PEpMessageBuilder {
return filename != null ? filename : DEFAULT_FILENAME;
}
private boolean isAnAttachment(Part part) {
return "attachment".equalsIgnoreCase(MessageExtractor.getContentDisposition(part));
}
}
......@@ -176,7 +176,7 @@ public interface PEpProvider extends AutoCloseable {
KeyDetail getOwnKeyDetails(Message message);
void setSubjectUnprotected(boolean enabled);
void setSubjectProtection(boolean enabled);
List<KeyListItem> getBlacklistInfo();
......@@ -188,11 +188,11 @@ public interface PEpProvider extends AutoCloseable {
//com.fsck.k9.mail.Message getMimeMessage(Message message);
void acceptHandshake(Identity identity);
void acceptSync();
void rejectHandshake(Identity identity);
void rejectSync();
void cancelHandshake(Identity identity);
void cancelSync();
void loadMessageRatingAfterResetTrust(MimeMessage message, boolean isIncoming, Identity id, ResultCallback<Rating> loadedCallback);
......@@ -269,13 +269,11 @@ public interface PEpProvider extends AutoCloseable {
}
class DecryptResult {
public final KeyDetail keyDetails;
public int flags = -1;
public DecryptResult(MimeMessage msg, Rating rating, KeyDetail keyDetails, int flags) {
public DecryptResult(MimeMessage msg, Rating rating, int flags) {
this.msg = msg;
this.rating = rating;
this.keyDetails = keyDetails;
this.flags = flags;
}
......
......@@ -103,7 +103,7 @@ public class PEpProviderImpl implements PEpProvider {
private void initEngineConfig(Engine engine) {
engine.config_passive_mode(K9.getPEpPassiveMode());
configKeyServerLockup(K9.getPEpUseKeyserver());
engine.config_unencrypted_subject(K9.ispEpSubjectUnprotected());
engine.config_unencrypted_subject(!K9.ispEpSubjectProtection());
engine.setMessageToSendCallback(MessagingController.getInstance(context));
engine.setNotifyHandshakeCallback(((K9) context.getApplicationContext()).getNotifyHandshakeCallback());
}
......@@ -228,21 +228,12 @@ public class PEpProviderImpl implements PEpProvider {
decMsg.setFlag(Flag.X_PEP_NEVER_UNSECURE, neverUnprotected);
extractpEpImportHeaderFromReplyTo(decMsg);
// TODO: 2020-02-20 Seem like this flgs currently are not used on the engine, this needs to be reviewed and probably removed
DecryptResult flaggedResult = processKeyImportSyncMessages(decReturn, decMsg);
if (flaggedResult != null) return flaggedResult;
if (isUsablePrivateKey(decReturn)) {
if (decMsg.getHeaderNames().contains(MimeHeader.HEADER_PEP_KEY_IMPORT)
|| decMsg.getHeaderNames().contains(MimeHeader.HEADER_PEP_KEY_IMPORT_LEGACY)) {
Log.d(TAG, "pEpdecryptMessage() after decrypt has usable pEp key (import)");
return new DecryptResult(decMsg, decReturn.rating, new KeyDetail("", null), decReturn.flags);
} else if (!PEpUtils.isAutoConsumeMessage(decMsg)) {
Log.d(TAG, "pEpdecryptMessage() after decrypt has usable PGP key (import)");
return new DecryptResult(decMsg, decReturn.rating, getOwnKeyDetails(srcMsg), decReturn.flags);
} else return new DecryptResult(decMsg, decReturn.rating, null, 0x2);
}
else return new DecryptResult(decMsg, decReturn.rating, null, -1);
}catch (Throwable t) {
return new DecryptResult(decMsg, decReturn.rating, -1);
} catch (Throwable t) {
Log.e(TAG, "while decrypting message: " + source.getSubject()
+ "\n" + source.getFrom()[0]
+ "\n" + source.getSentDate().toString()
......@@ -266,17 +257,16 @@ public class PEpProviderImpl implements PEpProvider {
if (lastValidDate.after(decryptedMimeMessage.getSentDate())) {
flags = DecryptFlags.pEpDecryptFlagConsumed.value;
return new DecryptResult(decryptedMimeMessage, decReturn.rating, null, flags);
return new DecryptResult(decryptedMimeMessage, decReturn.rating, flags);
}
}
else if (PEpUtils.isAutoConsumeMessage(decryptedMimeMessage)) {
if (lastValidDate.after(decryptedMimeMessage.getSentDate())) {
flags = DecryptFlags.pEpDecryptFlagConsumed.value;
return new DecryptResult(decryptedMimeMessage, decReturn.rating, null, flags);
} else {
flags = DecryptFlags.pEpDecryptFlagIgnored.value;
return new DecryptResult(decryptedMimeMessage, decReturn.rating, null, flags);
}
return new DecryptResult(decryptedMimeMessage, decReturn.rating, flags);
}
return null;
}
......@@ -323,16 +313,9 @@ public class PEpProviderImpl implements PEpProvider {
Message message = decReturn.dst;
MimeMessage decMsg = getMimeMessage(source, message);
if (isUsablePrivateKey(decReturn)) {
notifyLoaded(new DecryptResult(decMsg, decReturn.rating, getOwnKeyDetails(srcMsg), -1), callback);
}
else notifyLoaded(new DecryptResult(decMsg, decReturn.rating, null, decReturn.flags), callback);
// } catch (pEpMessageConsume | pEpMessageIgnore pe) {
// // TODO: 15/11/16 deal with it as flag not exception
notifyLoaded(new DecryptResult(decMsg, decReturn.rating, decReturn.flags), callback);
// // throw pe;
// return null;
}catch (Throwable t) {
} catch (Throwable t) {
Log.e(TAG, "while decrypting message:", t);
notifyError(new AppCannotDecryptException("Could not decrypt", t), callback);
} finally {
......@@ -802,7 +785,11 @@ public class PEpProviderImpl implements PEpProvider {
engine.stopKeyserverLookup();
}
/**
* @deprecated private key detection is not supported anymore, alternatives are pEp sync and import from FS
*/
@Override
@Deprecated
public synchronized KeyDetail getOwnKeyDetails(Message message) {
Identity id;
try {
......@@ -847,9 +834,9 @@ public class PEpProviderImpl implements PEpProvider {
// }
@Override
public synchronized void setSubjectUnprotected (boolean isUnprotected) {
public synchronized void setSubjectProtection(boolean isProtected) {
createEngineInstanceIfNeeded();
engine.config_unencrypted_subject(isUnprotected);
engine.config_unencrypted_subject(!isProtected);
}
@Override
......@@ -942,17 +929,17 @@ public class PEpProviderImpl implements PEpProvider {
//FIXME: Implement sync use lists.
@Override
public synchronized void acceptHandshake(Identity identity) {
public synchronized void acceptSync() {
engine.deliverHandshakeResult(SyncHandshakeResult.SyncHandshakeAccepted, new Vector<>());
}
@Override
public synchronized void rejectHandshake(Identity identity) {
public synchronized void rejectSync() {
engine.deliverHandshakeResult(SyncHandshakeResult.SyncHandshakeRejected, new Vector<>());
}
@Override
public synchronized void cancelHandshake(Identity identity) {
public synchronized void cancelSync() {
engine.deliverHandshakeResult(SyncHandshakeResult.SyncHandshakeCancel, new Vector<>());
}
......@@ -1194,7 +1181,8 @@ public class PEpProviderImpl implements PEpProvider {
public void keyResetIdentity(Identity ident, String fpr) {
createEngineInstanceIfNeeded();
ident = updateIdentity(ident);
engine.key_reset_identity(ident, fpr);
engine.key_reset_identity(ident,
fpr);
}
@Override
......
......@@ -58,7 +58,7 @@ public class PEpUtils {
private static final String TRUSTWORDS_SEPARATOR = " ";
private static final int CHUNK_SIZE = 4;
private static final CharSequence[] pEpLanguages = {"ca", "de", "es", "fr", "tr", "en"};
private static final CharSequence[] pEpLanguages = {"ca", "de", "es", "fr", "tr", "en", "nl"};
public static CharSequence[] getPEpLocales() {
return pEpLanguages;
......@@ -472,6 +472,10 @@ public class PEpUtils {
|| message.getFolder().getName().equals(account.getOutboxFolderName());
}
public static boolean shouldUseOutgoingRating(Message message, Account account, Rating rating) {
return isMessageOnOutgoingFolder(message, account) && !isRatingUnsecure(rating);
}
public static Message generateKeyImportRequest(Context context, PEpProvider pEp, Account account,
boolean ispEp, boolean encrypted) throws MessagingException {
foundation.pEp.jniadapter.Message result;
......@@ -561,5 +565,9 @@ public class PEpUtils {
public static boolean isPepStatusClickable(ArrayList<Identity> recipients ,Rating rating) {
return recipients.size() > 0 && rating.value >= Rating.pEpRatingReliable.value;
}
public static boolean isRatingUnsecure(Rating rating){
return rating.value != Rating.pEpRatingMistrust.value && rating.value < Rating.pEpRatingReliable.value;
}
}
......@@ -10,8 +10,6 @@ import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.pEp.PEpProvider;
import com.fsck.k9.pEp.manualsync.ImportKeyController;
import com.fsck.k9.pEp.manualsync.ImportKeyControllerFactory;
import com.fsck.k9.pEp.ui.SimpleMessageLoaderHelper;
import com.fsck.k9.pEp.ui.fragments.PEpSettingsCheck;
import com.fsck.k9.pEp.ui.fragments.PEpSettingsChecker;
......@@ -22,8 +20,6 @@ import dagger.Module;
import dagger.Provides;
import security.pEp.permissions.PermissionChecker;
import security.pEp.ui.permissions.PEpPermissionChecker;
import security.pEp.ui.resources.PEpResourcesProvider;
import security.pEp.ui.resources.ResourcesProvider;
@Module
public class PEpModule {
......@@ -69,11 +65,6 @@ public class PEpModule {
return MessagingController.getInstance(context);
}
@Provides
public ImportKeyController provideImportkeyController(@Named("Background") PEpProvider pEp) {
return ImportKeyControllerFactory.getInstance().getImportKeyController(context, pEp);
}
@Provides
public Preferences providePreferences() {
return Preferences.getPreferences(context);
......
package com.fsck.k9.pEp.manualsync;
import android.content.Context;
import com.fsck.k9.K9;
import com.fsck.k9.pEp.PEpProvider;
public class ImportKeyControllerFactory {
private static ImportKeyControllerFactory INSTANCE = null;
private ImportKeyController importKeyController = null;
private ImportKeyControllerFactory() {
}
public static ImportKeyControllerFactory getInstance() {
if (INSTANCE == null) {
synchronized (ImportKeyControllerFactory.class) {
INSTANCE = new ImportKeyControllerFactory();
}
}
return INSTANCE;
}
public ImportKeyController getImportKeyController(Context context, PEpProvider pEp) {
if (importKeyController == null) {
synchronized (ImportKeyControllerFactory.class) {
importKeyController = new ImportKeyController(((K9) context.getApplicationContext()), pEp);
}
}
return importKeyController;
}
}
package com.fsck.k9.pEp.manualsync;
interface ImportWizardFromPGPView {
void showDescription(String description);
void renderpEpCreateDeviceGroupRequest();
void setImportTitle(String type);
void renderpEpInitialScreen();
void renderPGPInitialScreen();
void renderWaitingForHandshake();
void renderWaitingForPGPHandshake();
void renderpEpSecondlScreen();
void notifyAcceptedHandshakeAndWaitingForPrivateKey();
void notifyKeySent();
void finishImportSuccefully();
void renderpEpAddToExistingDeviceGroupRequest();
void close();
void cancel();
void setDialogEnabled();
void showHandshake(String trustwords);
void showWaitingForSync();
void showGroupCreated();
void notifyAcceptedHandshakeAndWaitingForPGPPrivateKey();
void showJoinedGroup();
void starSendKeyImportRequest();
void showSomethingWentWrong();
void finishSendingKeyImport();
void disableSync();
void showSendError();
void showLongTrustwordsIndicator();
void notifySendingOwnKey();
void hideLongTrustwordsIndicator();
void renderPgpSendHandshakeFirstStep();
void prepareGroupCreationLoading();
void renderPgpSendHandshakeSecondStep();
void prepareGroupJoiningLoading();
}
......@@ -223,18 +223,18 @@ public class AddDevicePresenter implements Presenter {
@Override
void acceptHandshake(Identity partner) {
Log.e("pEpEngine", String.format("acceptHandshake: myself(%s), partner(%s)", pEpProvider.myself(partner), partner) );
pEpProvider.acceptHandshake(pEpProvider.myself(partner));
Log.e("pEpEngine", String.format("acceptSync: myself(%s), partner(%s)", pEpProvider.myself(partner), partner) );
pEpProvider.acceptSync();
}
@Override
void rejectHandshake(Identity partner) {
pEpProvider.rejectHandshake(partner);
pEpProvider.rejectSync();
}
@Override
void cancelHandshake(Identity partner) {
pEpProvider.cancelHandshake(partner);
pEpProvider.cancelSync();
}
}
}
......@@ -448,7 +448,7 @@ public class PEpAddDevice extends WizardActivity implements AddDeviceView {
@OnClick(R.id.add_device_background)
public void onClickOutside() {
//presenter.cancelHandshake();
//presenter.cancelSync();
}
@OnClick(R.id.show_long_trustwords)
......
......@@ -294,21 +294,23 @@ public class GlobalSettings {
s.put("pEpPassiveMode", Settings.versions(
new V(43, new BooleanSetting(true))
));
s.put("pEpSubjectUnprotected", Settings.versions(
new V(46, new BooleanSetting(true))
));
s.put("pEpForwardWarningEnabled", Settings.versions(
new V(47, new BooleanSetting(false))
));
s.put("pEpEnableSync", Settings.versions(
new V(49, new BooleanSetting(true))
));
s.put("pEpSubjectProtection", Settings.versions(
new V(50, new BooleanSetting(true))
));
SETTINGS = Collections.unmodifiableMap(s);
Map<Integer, SettingsUpgrader> u = new HashMap<>();
u.put(12, new SettingsUpgraderV12());
u.put(24, new SettingsUpgraderV24());
u.put(31, new SettingsUpgraderV31());
u.put(50, new SettingsUpgraderV50());
UPGRADERS = Collections.unmodifiableMap(u);
}
......@@ -422,6 +424,27 @@ public class GlobalSettings {
}
}
/**
* Upgrades the settings from version 49 to 50.
*
* <p>
* Convert value from <em>pEpSubjectUnprotected</em> to
* <em>pEpSubjectProtection</em>.
* </p>
*/
public static class SettingsUpgraderV50 implements SettingsUpgrader {
@Override
public Set<String> upgrade(Map<String, Object> settings) {
boolean oldValue = (Boolean) settings.get("pEpSubjectUnprotected");
settings.put("pEpSubjectProtection", !oldValue);
return new HashSet<>(Collections.singletonList("pEpSubjectUnprotected"));
}
}
private static class LanguageSetting extends PseudoEnumSetting<String> {
private final Map<String, String> mapping;
......
......@@ -153,13 +153,13 @@ public class QuotedMessagePresenter {
public void onSaveInstanceState(Bundle outState) {
outState.putSerializable(STATE_KEY_QUOTED_TEXT_MODE, quotedTextMode);
outState.putSerializable(STATE_KEY_HTML_QUOTE, quotedHtmlContent);
outState.putParcelable(STATE_KEY_HTML_QUOTE, quotedHtmlContent);
outState.putSerializable(STATE_KEY_QUOTED_TEXT_FORMAT, quotedTextFormat);
outState.putBoolean(STATE_KEY_FORCE_PLAIN_TEXT, forcePlainText);
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
quotedHtmlContent = (InsertableHtmlContent) savedInstanceState.getSerializable(STATE_KEY_HTML_QUOTE);
quotedHtmlContent = savedInstanceState.getParcelable(STATE_KEY_HTML_QUOTE);
if (quotedHtmlContent != null && quotedHtmlContent.getQuotedContent() != null) {
// we don't have the part here, but inline-displayed images are cached by the webview
view.setQuotedHtml(quotedHtmlContent.getQuotedContent(), null);
......
......@@ -2,30 +2,32 @@ package com.fsck.k9.ui.messageview;
import android.content.Context;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.helper.SizeFormatter;
import com.fsck.k9.mailstore.AttachmentViewInfo;
import timber.log.Timber;
public class AttachmentView extends FrameLayout implements OnClickListener, OnLongClickListener {
public class AttachmentView extends ConstraintLayout {
private AttachmentViewInfo attachment;
private AttachmentViewCallback callback;
private Button viewButton;
private ImageView downloadButton;
private View attachmentContainer;
public AttachmentView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
......@@ -39,46 +41,42 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
super(context);
}
private void init() {
downloadButton = findViewById(R.id.download);
}
public AttachmentViewInfo getAttachment() {
return attachment;
}
public void setAttachment(AttachmentViewInfo attachment) {
this.attachment = attachment;
displayAttachmentInformation();
}
public void enableButtons() {
viewButton.setEnabled(true);
downloadButton.setEnabled(true);
}
public void disableButtons() {
viewButton.setEnabled(false);
downloadButton.setEnabled(false);
}
public void setAttachment(AttachmentViewInfo attachment) {
this.attachment = attachment;
displayAttachmentInformation();
}
private void displayAttachmentInformation() {
attachmentContainer = findViewById(R.id.attachment_container);
viewButton = (Button) findViewById(R.id.view);
downloadButton = (ImageView) findViewById(R.id.download);
init();
if (attachment.size > K9.MAX_ATTACHMENT_DOWNLOAD_SIZE) {
viewButton.setVisibility(View.GONE);
downloadButton.setVisibility(View.GONE);
}
attachmentContainer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onViewClick();
}
setOnClickListener(v -> onViewClick());
downloadButton.setOnClickListener(v -> onSaveButtonClick());
downloadButton.setOnLongClickListener(v -> {
onSaveButtonLongClick();
return true;
});
downloadButton.setOnClickListener(this);
downloadButton.setOnLongClickListener(this);
TextView attachmentName = (TextView) findViewById(R.id.attachment_name);
TextView attachmentName = findViewById(R.id.attachment_name);
attachmentName.setText(attachment.displayName);
setAttachmentSize(attachment.size);
......@@ -87,7 +85,7 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
}
private void setAttachmentSize(long size) {
TextView attachmentSize = (TextView) findViewById(R.id.attachment_info);
TextView attachmentSize = findViewById(R.id.attachment_info);
if (size == AttachmentViewInfo.UNKNOWN_SIZE) {
attachmentSize.setText("");
} else {
......@@ -96,26 +94,6 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.download: {
onSaveButtonClick();
break;
}
}
}
@Override
public boolean onLongClick(View view) {
if (view.getId() == R.id.download) {
onSaveButtonLongClick();
return true;
}
return false;
}
private void onViewClick() {
callback.onViewAttachment(attachment);
}
......@@ -133,11 +111,25 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
}
public void refreshThumbnail() {
ImageView thumbnailView = (ImageView) findViewById(R.id.attachment_icon);
ImageView thumbnailView = findViewById(R.id.attachment_icon);
Glide.with(getContext())
.load(attachment.internalUri)
.placeholder(R.drawable.attached_image_placeholder)
.placeholder(ContextCompat.getDrawable(getContext(), R.drawable.ic_file_light))
.centerCrop()
.into(thumbnailView);
.listener(new RequestListener<Uri, GlideDrawable>() {
@Override
public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) {
Timber.e(e);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
thumbnailView.setPadding(0, 0, 0, 0);
return false;
}
})
.into(thumbnailView)
;
}
}
......@@ -2,6 +2,7 @@ package com.fsck.k9.ui.settings.account
import android.app.AlertDialog
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Toast
......@@ -63,6 +64,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
initializeCryptoSettings(account)
initializeFolderSettings(account)
initializeAccountpEpKeyReset(account)
initializeNewRingtoneOptions()
if (!BuildConfig.WITH_KEY_SYNC) {
hideKeySyncOptions()
......@@ -174,6 +176,12 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
findPreference(PREFERENCE_PEP_ENABLE_SYNC_ACCOUNT)?.remove()
}
private fun initializeNewRingtoneOptions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
findPreference(PREFERENCE_RINGTONE)?.remove()
}
}
private fun dopEpKeyReset(account: Account) {
disableKeyResetClickListener()
loading?.visibility = View.VISIBLE
......@@ -289,6 +297,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
private const val PREFERENCE_SENT_FOLDER = "sent_folder"
private const val PREFERENCE_SPAM_FOLDER = "spam_folder"
private const val PREFERENCE_TRASH_FOLDER = "trash_folder"
private const val PREFERENCE_RINGTONE = "account_ringtone"
private const val PREFERENCE_PEP_ACCOUNT_KEY_RESET = "pep_key_reset_account"
private const val PREFERENCE_PEP_ENABLE_SYNC_ACCOUNT = "pep_enable_sync_account"
......
......@@ -45,7 +45,7 @@ class GeneralSettingsDataStore(
"sensitive_logging" -> K9.DEBUG_SENSITIVE
"pep_use_keyserver" -> K9.getPEpUseKeyserver()
"pep_passive_mode" -> K9.getPEpPassiveMode()
"pep_subject_unprotected" -> K9.ispEpSubjectUnprotected()
"pep_subject_protection" -> K9.ispEpSubjectProtection()
"pep_forward_warning" -> K9.ispEpForwardWarningEnabled()
"pep_enable_sync" -> K9.ispEpSyncEnabled()
else -> defValue
......@@ -84,7 +84,7 @@ class GeneralSettingsDataStore(
"sensitive_logging" -> K9.DEBUG_SENSITIVE = value
"pep_use_keyserver" -> app.setPEpUseKeyserver(value)
"pep_passive_mode" -> app.setPEpPassiveMode(value)
"pep_subject_unprotected" -> app.setpEpSubjectUnprotected(value)
"pep_subject_protection" -> app.setpEpSubjectProtection(value)
"pep_forward_warning" -> app.setpEpForwardWarningEnabled(value)
"pep_enable_sync" -> app.setpEpSyncEnabled(value) //TODO: CHECK
else -> return
......
package security.pEp.sync
import foundation.pEp.jniadapter.SyncHandshakeSignal
//TODO: Rewrite the wizard.
abstract class SyncAction
class Cancel: SyncAction()
class Next: SyncAction()
class Reject: SyncAction()
class confirm: SyncAction()
class leave: SyncAction()
class retry: SyncAction()
enum class DeviceGroupStatus {
SOLE, GROUPED, ADDING
}
interface KeySyncWizardView {
fun showHandshake()
}
interface KeySyncWizard {
//fun getText(): String
fun getCurrentState(): SyncState
fun notify(signal: SyncHandshakeSignal) {
when (signal) {
SyncHandshakeSignal.SyncNotifySole -> TODO()
SyncHandshakeSignal.SyncNotifyUndefined -> TODO()
SyncHandshakeSignal.SyncNotifyInitAddOurDevice -> TODO()
SyncHandshakeSignal.SyncNotifyInitAddOtherDevice -> TODO()
SyncHandshakeSignal.SyncNotifyInitFormGroup -> TODO()
SyncHandshakeSignal.SyncNotifyTimeout -> TODO()
SyncHandshakeSignal.SyncNotifyAcceptedDeviceAdded -> TODO()
SyncHandshakeSignal.SyncNotifyAcceptedGroupCreated -> TODO()
SyncHandshakeSignal.SyncNotifyAcceptedDeviceAccepted -> TODO()
SyncHandshakeSignal.SyncNotifyInGroup -> TODO()
}
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
class KeySyncAppWizard(var state: SyncState = SyncState.INITIAL) : KeySyncWizard {
init {
state.next()
}
override fun getCurrentState(): SyncState {
return state
}
}
enum class SyncState {
INITIAL {