|
|
@ -20,6 +20,7 @@ package eu.faircode.email; |
|
|
|
*/ |
|
|
|
|
|
|
|
import android.Manifest; |
|
|
|
import android.app.PendingIntent; |
|
|
|
import android.content.Context; |
|
|
|
import android.content.Intent; |
|
|
|
import android.content.pm.PackageManager; |
|
|
@ -54,7 +55,13 @@ import android.widget.Toast; |
|
|
|
import com.google.android.material.bottomnavigation.BottomNavigationView; |
|
|
|
import com.google.android.material.snackbar.Snackbar; |
|
|
|
|
|
|
|
import org.openintents.openpgp.OpenPgpError; |
|
|
|
import org.openintents.openpgp.util.OpenPgpApi; |
|
|
|
import org.openintents.openpgp.util.OpenPgpServiceConnection; |
|
|
|
|
|
|
|
import java.io.BufferedOutputStream; |
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
import java.io.File; |
|
|
|
import java.io.FileOutputStream; |
|
|
|
import java.io.IOException; |
|
|
@ -110,8 +117,27 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
private boolean addresses; |
|
|
|
private boolean autosave = true; |
|
|
|
|
|
|
|
private String encrypted = null; |
|
|
|
private OpenPgpServiceConnection openPgpConnection = null; |
|
|
|
|
|
|
|
private static final int ATTACHMENT_BUFFER_SIZE = 8192; // bytes |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onCreate(Bundle savedInstanceState) { |
|
|
|
super.onCreate(savedInstanceState); |
|
|
|
openPgpConnection = new OpenPgpServiceConnection(getContext(), "org.sufficientlysecure.keychain"); |
|
|
|
openPgpConnection.bindToService(); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onDestroy() { |
|
|
|
super.onDestroy(); |
|
|
|
if (openPgpConnection != null) { |
|
|
|
openPgpConnection.unbindFromService(); |
|
|
|
openPgpConnection = null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@Nullable |
|
|
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
|
|
@ -317,6 +343,7 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
public void onSaveInstanceState(Bundle outState) { |
|
|
|
super.onSaveInstanceState(outState); |
|
|
|
outState.putLong("working", working); |
|
|
|
outState.putString("encrypted", encrypted); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
@ -337,6 +364,8 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
args.putParcelableArrayList("attachments", getArguments().getParcelableArrayList("attachments")); |
|
|
|
draftLoader.load(this, args); |
|
|
|
} else { |
|
|
|
encrypted = savedInstanceState.getString("encrypted"); |
|
|
|
|
|
|
|
Bundle args = new Bundle(); |
|
|
|
args.putString("action", "edit"); |
|
|
|
args.putLong("id", savedInstanceState.getLong("working")); |
|
|
@ -365,6 +394,7 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
menu.findItem(R.id.menu_attachment).setVisible(!free && working >= 0); |
|
|
|
menu.findItem(R.id.menu_attachment).setEnabled(etBody.isEnabled()); |
|
|
|
menu.findItem(R.id.menu_addresses).setVisible(!free && working >= 0); |
|
|
|
menu.findItem(R.id.menu_encrypt).setVisible(encrypted == null); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
@ -376,6 +406,9 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
case R.id.menu_addresses: |
|
|
|
onMenuAddresses(); |
|
|
|
return true; |
|
|
|
case R.id.menu_encrypt: |
|
|
|
onMenuEncrypt(); |
|
|
|
return true; |
|
|
|
default: |
|
|
|
return super.onOptionsItemSelected(item); |
|
|
|
} |
|
|
@ -392,12 +425,77 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
grpAddresses.setVisibility(grpAddresses.getVisibility() == View.GONE ? View.VISIBLE : View.GONE); |
|
|
|
} |
|
|
|
|
|
|
|
private void onMenuEncrypt() { |
|
|
|
Log.i(Helper.TAG, "On encrypt"); |
|
|
|
try { |
|
|
|
if (openPgpConnection == null) |
|
|
|
throw new IllegalArgumentException(); |
|
|
|
if (!openPgpConnection.isBound()) |
|
|
|
throw new IllegalArgumentException("OpenPgp not available"); |
|
|
|
|
|
|
|
EntityIdentity identity = (EntityIdentity) spFrom.getSelectedItem(); |
|
|
|
if (identity == null) |
|
|
|
throw new IllegalArgumentException("No identity selected"); |
|
|
|
|
|
|
|
Intent data = new Intent(); |
|
|
|
data.setAction(OpenPgpApi.ACTION_ENCRYPT); |
|
|
|
data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{identity.email}); |
|
|
|
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); |
|
|
|
|
|
|
|
String plain = etBody.getText().toString(); |
|
|
|
final InputStream is = new ByteArrayInputStream(plain.getBytes("UTF-8")); |
|
|
|
final ByteArrayOutputStream os = new ByteArrayOutputStream(); |
|
|
|
|
|
|
|
OpenPgpApi api = new OpenPgpApi(getContext(), openPgpConnection.getService()); |
|
|
|
api.executeApiAsync(data, is, os, new OpenPgpApi.IOpenPgpCallback() { |
|
|
|
@Override |
|
|
|
public void onReturn(Intent result) { |
|
|
|
try { |
|
|
|
int code = result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); |
|
|
|
switch (code) { |
|
|
|
case OpenPgpApi.RESULT_CODE_SUCCESS: { |
|
|
|
Log.i(Helper.TAG, "Encrypted"); |
|
|
|
FragmentCompose.this.encrypted = os.toString("UTF-8"); |
|
|
|
getActivity().invalidateOptionsMenu(); |
|
|
|
etBody.setText(FragmentCompose.this.encrypted); |
|
|
|
break; |
|
|
|
} |
|
|
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: { |
|
|
|
Log.i(Helper.TAG, "User interaction"); |
|
|
|
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT); |
|
|
|
getActivity().startIntentSenderForResult( |
|
|
|
pi.getIntentSender(), |
|
|
|
ActivityCompose.REQUEST_OPENPGP, |
|
|
|
null, 0, 0, 0); |
|
|
|
break; |
|
|
|
} |
|
|
|
case OpenPgpApi.RESULT_CODE_ERROR: { |
|
|
|
OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); |
|
|
|
Log.e(Helper.TAG, error.getMessage()); |
|
|
|
Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_LONG).show(); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (Throwable ex) { |
|
|
|
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); |
|
|
|
Toast.makeText(getContext(), ex.toString(), Toast.LENGTH_LONG).show(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} catch (Throwable ex) { |
|
|
|
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); |
|
|
|
Toast.makeText(getContext(), ex.toString(), Toast.LENGTH_LONG).show(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onActivityResult(int requestCode, int resultCode, Intent data) { |
|
|
|
if (resultCode == RESULT_OK) { |
|
|
|
if (requestCode == ActivityCompose.REQUEST_ATTACHMENT) { |
|
|
|
if (data != null) |
|
|
|
handleAddAttachment(data); |
|
|
|
} else if (requestCode == ActivityCompose.REQUEST_OPENPGP) { |
|
|
|
Log.i(Helper.TAG, "User interacted"); |
|
|
|
onMenuEncrypt(); |
|
|
|
} else |
|
|
|
handlePickContact(requestCode, data); |
|
|
|
} |
|
|
@ -531,7 +629,6 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
if (attachment.type == null) |
|
|
|
attachment.type = "application/octet-stream"; |
|
|
|
|
|
|
|
|
|
|
|
attachment.size = (s == null ? null : Integer.parseInt(s)); |
|
|
|
attachment.progress = 0; |
|
|
|
|
|
|
@ -903,7 +1000,11 @@ public class FragmentCompose extends FragmentEx { |
|
|
|
draft.subject = subject; |
|
|
|
draft.received = new Date().getTime(); |
|
|
|
|
|
|
|
String pbody = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>"; |
|
|
|
String pbody; |
|
|
|
if (encrypted == null) |
|
|
|
pbody = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>"; |
|
|
|
else |
|
|
|
pbody = encrypted; |
|
|
|
|
|
|
|
// Execute action |
|
|
|
if (action == R.id.action_trash) { |
|
|
|