Added rule forward with attachments (untested)

This commit is contained in:
M66B 2020-08-31 11:53:48 +02:00
parent f1d2ef324a
commit bcf65b7f71
5 changed files with 125 additions and 33 deletions

View File

@ -1802,7 +1802,7 @@ class Core {
}
}
private static void onRule(Context context, JSONArray jargs, EntityMessage message) throws JSONException, IOException {
private static void onRule(Context context, JSONArray jargs, EntityMessage message) throws JSONException, IOException, AddressException {
// Download message body
DB db = DB.getInstance(context);

View File

@ -57,6 +57,7 @@ import javax.mail.Address;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import static androidx.room.ForeignKey.CASCADE;
@ -294,7 +295,7 @@ public class EntityRule {
return matched;
}
boolean execute(Context context, EntityMessage message) throws JSONException, IOException {
boolean execute(Context context, EntityMessage message) throws JSONException, IOException, AddressException {
boolean executed = _execute(context, message);
if (id != null && executed) {
DB db = DB.getInstance(context);
@ -303,7 +304,7 @@ public class EntityRule {
return executed;
}
private boolean _execute(Context context, EntityMessage message) throws JSONException, IOException {
private boolean _execute(Context context, EntityMessage message) throws JSONException, IOException, AddressException {
JSONObject jaction = new JSONObject(action);
int type = jaction.getInt("type");
Log.i("Executing rule=" + type + ":" + name + " message=" + message.id);
@ -408,18 +409,30 @@ public class EntityRule {
return true;
}
private boolean onActionAnswer(Context context, EntityMessage message, JSONObject jargs) throws JSONException, IOException {
if (!message.content) {
EntityOperation.queue(context, message, EntityOperation.BODY);
EntityOperation.queue(context, message, EntityOperation.RULE, this.id);
return true;
}
private boolean onActionAnswer(Context context, EntityMessage message, JSONObject jargs) throws JSONException, IOException, AddressException {
DB db = DB.getInstance(context);
long iid = jargs.getLong("identity");
long aid = jargs.getLong("answer");
boolean cc = (jargs.has("cc") && jargs.getBoolean("cc"));
String to = jargs.optString("to");
boolean cc = jargs.optBoolean("cc");
boolean attachments = jargs.optBoolean("attachments");
DB db = DB.getInstance(context);
if (!message.content)
EntityOperation.queue(context, message, EntityOperation.BODY);
boolean complete = true;
if (attachments)
for (EntityAttachment attachment : db.attachment().getAttachments(message.id))
if (!attachment.available) {
complete = false;
EntityOperation.queue(context, message, EntityOperation.ATTACHMENT, attachment.id);
}
if (!message.content || !complete) {
EntityOperation.queue(context, message, EntityOperation.RULE, this.id);
return true;
}
EntityIdentity identity = db.identity().getIdentity(iid);
if (identity == null)
@ -448,15 +461,25 @@ public class EntityRule {
reply.folder = db.folder().getOutbox().id;
reply.identity = identity.id;
reply.msgid = EntityMessage.generateMessageId();
if (TextUtils.isEmpty(to)) {
reply.references = (message.references == null ? "" : message.references + " ") + message.msgid;
reply.inreplyto = message.msgid;
reply.thread = message.thread;
reply.to = (message.reply == null || message.reply.length == 0 ? message.from : message.reply);
} else {
reply.wasforwardedfrom = message.msgid;
reply.thread = reply.msgid; // new thread
reply.to = InternetAddress.parseHeader(to, false);
}
reply.from = from;
if (cc)
reply.cc = message.cc;
reply.unsubscribe = "mailto:" + identity.email;
reply.subject = context.getString(R.string.title_subject_reply, message.subject == null ? "" : message.subject);
reply.subject = context.getString(
TextUtils.isEmpty(to) ? R.string.title_subject_reply : R.string.title_subject_forward,
message.subject == null ? "" : message.subject);
reply.received = new Date().getTime();
reply.sender = MessageHelper.getSortKey(reply.from);
@ -468,6 +491,7 @@ public class EntityRule {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean extended_reply = prefs.getBoolean("extended_reply", false);
boolean quote_reply = prefs.getBoolean("quote_reply", true);
boolean quote = (quote_reply && TextUtils.isEmpty(to));
String body = answer.getText(message.from);
Document msg = JsoupEx.parse(body);
@ -478,7 +502,7 @@ public class EntityRule {
div.appendChild(p);
Document answering = JsoupEx.parse(message.getFile(context));
div.appendChild(answering.body().tagName(quote_reply ? "blockquote" : "p"));
div.appendChild(answering.body().tagName(quote ? "blockquote" : "p"));
msg.body().appendChild(div);
@ -493,6 +517,9 @@ public class EntityRule {
HtmlHelper.getPreview(body),
null);
if (attachments)
EntityAttachment.copy(context, message.id, reply.id);
EntityOperation.queue(context, reply, EntityOperation.SEND);
// Batch send operations, wait until after commit

View File

@ -43,7 +43,7 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ImageButton;
import android.widget.NumberPicker;
import android.widget.ScrollView;
import android.widget.Spinner;
@ -88,12 +88,12 @@ public class FragmentRule extends FragmentBase {
private EditText etSender;
private CheckBox cbSender;
private ImageView ibSender;
private ImageButton ibSender;
private CheckBox cbKnownSender;
private EditText etRecipient;
private CheckBox cbRecipient;
private ImageView ibRecipient;
private ImageButton ibRecipient;
private EditText etSubject;
private CheckBox cbSubject;
@ -129,7 +129,10 @@ public class FragmentRule extends FragmentBase {
private Spinner spIdent;
private Spinner spAnswer;
private EditText etTo;
private ImageButton ibTo;
private CheckBox cbCc;
private CheckBox cbWithAttachments;
private Button btnTtsSetup;
private Button btnTtsData;
@ -170,8 +173,9 @@ public class FragmentRule extends FragmentBase {
private final static int REQUEST_DELETE = 4;
private final static int REQUEST_SCHEDULE_START = 5;
private final static int REQUEST_SCHEDULE_END = 6;
private final static int REQUEST_TTS_CHECK = 7;
private final static int REQUEST_TTS_DATA = 8;
private static final int REQUEST_TO = 7;
private final static int REQUEST_TTS_CHECK = 8;
private final static int REQUEST_TTS_DATA = 9;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -249,7 +253,10 @@ public class FragmentRule extends FragmentBase {
spIdent = view.findViewById(R.id.spIdent);
spAnswer = view.findViewById(R.id.spAnswer);
etTo = view.findViewById(R.id.etTo);
ibTo = view.findViewById(R.id.ibTo);
cbCc = view.findViewById(R.id.cbCc);
cbWithAttachments = view.findViewById(R.id.cbWithAttachments);
btnTtsSetup = view.findViewById(R.id.btnTtsSetup);
btnTtsData = view.findViewById(R.id.btnTtsData);
@ -452,6 +459,14 @@ public class FragmentRule extends FragmentBase {
spIdent.setOnItemSelectedListener(onItemSelectedListener);
spAnswer.setOnItemSelectedListener(onItemSelectedListener);
ibTo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent pick = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Email.CONTENT_URI);
startActivityForResult(Helper.getChooser(getContext(), pick), REQUEST_TO);
}
});
btnTtsSetup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -623,11 +638,11 @@ public class FragmentRule extends FragmentBase {
switch (requestCode) {
case REQUEST_SENDER:
if (resultCode == RESULT_OK && data != null)
onPickContact(data, true);
onPickContact(data, etSender);
break;
case REQUEST_RECIPIENT:
if (resultCode == RESULT_OK && data != null)
onPickContact(data, true);
onPickContact(data, etRecipient);
break;
case REQUEST_COLOR:
if (resultCode == RESULT_OK && data != null) {
@ -652,6 +667,10 @@ public class FragmentRule extends FragmentBase {
if (resultCode == RESULT_OK)
onScheduleEnd(data.getBundleExtra("args"));
break;
case REQUEST_TO:
if (resultCode == RESULT_OK && data != null)
onPickContact(data, etTo);
break;
case REQUEST_TTS_CHECK:
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
ToastEx.makeText(getContext(), R.string.title_rule_tts_ok, Toast.LENGTH_LONG).show();
@ -669,7 +688,7 @@ public class FragmentRule extends FragmentBase {
}
}
private void onPickContact(Intent data, boolean sender) {
private void onPickContact(Intent data, final EditText et) {
Uri uri = data.getData();
if (uri == null) return;
try (Cursor cursor = getContext().getContentResolver().query(uri,
@ -678,10 +697,7 @@ public class FragmentRule extends FragmentBase {
},
null, null, null)) {
if (cursor != null && cursor.moveToFirst())
if (sender)
etSender.setText(cursor.getString(0));
else
etRecipient.setText(cursor.getString(0));
et.setText(cursor.getString(0));
} catch (Throwable ex) {
Log.e(ex);
Log.unexpectedError(getParentFragmentManager(), ex);
@ -871,7 +887,9 @@ public class FragmentRule extends FragmentBase {
break;
}
etTo.setText(jaction.optString("to"));
cbCc.setChecked(jaction.optBoolean("cc"));
cbWithAttachments.setChecked(jaction.optBoolean("attachments"));
break;
}
@ -1173,7 +1191,9 @@ public class FragmentRule extends FragmentBase {
EntityAnswer answer = (EntityAnswer) spAnswer.getSelectedItem();
jaction.put("identity", identity == null ? -1 : identity.id);
jaction.put("answer", answer == null ? -1 : answer.id);
jaction.put("to", etTo.getText().toString().trim());
jaction.put("cc", cbCc.isChecked());
jaction.put("attachments", cbWithAttachments.isChecked());
break;
}
}

View File

@ -669,6 +669,40 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvAnswerTemplate" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:hint="@string/title_optional"
android:text="@string/title_rule_forward_to"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spAnswer" />
<eu.faircode.email.EditTextPlain
android:id="@+id/etTo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="text"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/ibTo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTo" />
<ImageButton
android:id="@+id/ibTo"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/title_legend_pick"
app:layout_constraintBottom_toBottomOf="@id/etTo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/etTo"
app:srcCompat="@drawable/baseline_person_add_24" />
<CheckBox
android:id="@+id/cbCc"
android:layout_width="wrap_content"
@ -676,7 +710,16 @@
android:layout_marginTop="12dp"
android:text="@string/title_rule_cc"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spAnswer" />
app:layout_constraintTop_toBottomOf="@id/etTo" />
<CheckBox
android:id="@+id/cbWithAttachments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_rule_with_attachments"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbCc" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvAnswerRemark"
@ -687,7 +730,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbCc" />
app:layout_constraintTop_toBottomOf="@id/cbWithAttachments" />
<Button
android:id="@+id/btnTtsSetup"
@ -773,7 +816,7 @@
android:id="@+id/grpAnswer"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tvAnswerIdentity,spIdent,tvAnswerTemplate,spAnswer,cbCc,tvAnswerRemark" />
app:constraint_referenced_ids="tvAnswerIdentity,spIdent,tvAnswerTemplate,spAnswer,tvTo,etTo,ibTo,cbCc,cbWithAttachments,tvAnswerRemark" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpTts"

View File

@ -1103,7 +1103,7 @@
<string name="title_rule_keyword">Add keyword</string>
<string name="title_rule_move">Move</string>
<string name="title_rule_copy">Copy (label)</string>
<string name="title_rule_answer">Reply</string>
<string name="title_rule_answer">Reply/forward</string>
<string name="title_rule_tts">Text to speech</string>
<string name="title_rule_automation">Automation</string>
@ -1131,7 +1131,9 @@
<string name="title_rule_thread">All messages in same conversation and folder</string>
<string name="title_rule_identity">Identity</string>
<string name="title_rule_template">Reply template</string>
<string name="title_rule_forward_to">Forward to</string>
<string name="title_rule_cc">Reply to CC addresses</string>
<string name="title_rule_with_attachments">With attachments</string>
<string name="title_rule_answer_remark">Only one reply will be sent for any conversation, to avoid reply loops</string>
<string name="title_rule_name_missing">Rule name missing</string>
<string name="title_rule_condition_missing">Condition missing</string>