mirror of https://github.com/M66B/FairEmail.git
Added rule forward with attachments (untested)
This commit is contained in:
parent
f1d2ef324a
commit
bcf65b7f71
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue