Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managesieve plugin: option to append original subject in out-of-office auto-replies #8570

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ function save()
$interval_types = rcube_utils::get_input_value('_action_interval_type', rcube_utils::INPUT_POST);
$from = rcube_utils::get_input_value('_action_from', rcube_utils::INPUT_POST, true);
$subject = rcube_utils::get_input_value('_action_subject', rcube_utils::INPUT_POST, true);
$subject_append_original = rcube_utils::get_input_value('_action_subject_append_original', rcube_utils::INPUT_POST);
$flags = rcube_utils::get_input_value('_action_flags', rcube_utils::INPUT_POST);
$varnames = rcube_utils::get_input_value('_action_varname', rcube_utils::INPUT_POST);
$varvalues = rcube_utils::get_input_value('_action_varvalue', rcube_utils::INPUT_POST);
Expand Down Expand Up @@ -1155,6 +1156,7 @@ function save()
$this->form['actions'][$i]['reason'] = str_replace("\r\n", "\n", $reason);
$this->form['actions'][$i]['from'] = $from[$idx];
$this->form['actions'][$i]['subject'] = $subject[$idx];
$this->form['actions'][$i]['subject_append_original'] = $subject_append_original[$idx];
$this->form['actions'][$i]['addresses'] = $addresses[$idx];
$this->form['actions'][$i][$interval_type] = $intervals[$idx];

Expand Down Expand Up @@ -2440,6 +2442,14 @@ function action_div($fid, $id, $div = true)
'size' => 35,
'class' => $this->error_class($id, 'action', 'subject', 'action_subject'),
]);
$out .= '<br>' . html::label('action_subject_append_original' . $id,
html::tag('input', array(
'type' => 'checkbox',
'name' => '_action_subject_append_original[' . $id . ']',
'id' => 'action_subject_append_original' . $id,
'value' => 1,
'checked' => isset($action['subject_append_original']) && $action['subject_append_original'] == 1,
)) . ' ' . rcube::Q($this->plugin->gettext('vacation.subjectappendoriginal')));
$out .= '<br><span class="label">' .rcube::Q($this->plugin->gettext('vacationfrom')) . '</span><br>';
$out .= html::tag('input', [
'type' => 'text',
Expand Down
86 changes: 85 additions & 1 deletion plugins/managesieve/lib/Roundcube/rcube_sieve_script.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class rcube_sieve_script
// @TODO: virustest, mailbox
];

private $vacation_subject_var = 'subject';
private $vacation_subject_suffix = '${subject}';

/**
* Object constructor
*
Expand Down Expand Up @@ -209,6 +212,12 @@ public function as_text()
$exts = [];
$idx = 0;

$add_vacation_subject_rule = $this->should_generate_vacation_subject_rule();
if ($add_vacation_subject_rule) {
$this->set_var($this->vacation_subject_var, '');
}


if (!empty($this->vars)) {
if (in_array('variables', (array)$this->supported)) {
$has_vars = true;
Expand All @@ -232,6 +241,12 @@ public function as_text()
$imapflags = in_array('imap4flags', $this->supported) ? 'imap4flags' : 'imapflags';
$notify = in_array('enotify', $this->supported) ? 'enotify' : 'notify';

if ($add_vacation_subject_rule) {
$output .= 'if header :matches "subject" "*" {' . "\r\n" .
"\t" . 'set "' . $this->vacation_subject_var . '" "${1}";' . "\r\n" .
"}\r\n";
}

// rules
foreach ($this->content as $rule) {
$script = '';
Expand Down Expand Up @@ -567,7 +582,11 @@ public function as_text()
$action_script .= " :addresses " . self::escape_string($action['addresses']);
}
if (!empty($action['subject'])) {
$action_script .= " :subject " . self::escape_string($action['subject']);
$subject = trim($action['subject']);
if (isset($action['subject_append_original']) && $action['subject_append_original'] == 1) {
$subject .= ($this->ends_with($subject, ':') ? ' ' : ': ') . $this->vacation_subject_suffix;
}
$action_script .= " :subject " . self::escape_string($subject);
}
if (!empty($action['handle'])) {
$action_script .= " :handle " . self::escape_string($action['handle']);
Expand Down Expand Up @@ -712,6 +731,13 @@ private function _parse_text($script)
}
}

// Skip the rule if it is a internal vacation rule (see more at is_vacation_subject_rule function)
if (!empty($rule)) {
if ($this->is_vacation_subject_rule($rule)) {
unset($rule);
}
}

if (!empty($rule)) {
$this->content[] = $rule;
}
Expand Down Expand Up @@ -978,6 +1004,12 @@ private function _parse_actions($content, &$position, $end = '}')
$vargs = ['seconds', 'days', 'addresses', 'subject', 'handle', 'from'];
$action += $this->action_arguments($tokens, $args, $vargs);

$subject = isset($action['subject']) ? $action['subject'] : '';
if (!empty($subject) && $this->ends_with($subject, ': ' . $this->vacation_subject_suffix)) {
$action['subject_append_original'] = 1;
$action['subject'] = trim(substr($subject, 0, -(strlen($this->vacation_subject_suffix) + 2)));
}

$result[] = $action;
break;

Expand Down Expand Up @@ -1483,6 +1515,58 @@ static function ltrim_position($content, $position, $br = true)
return $position;
}

/**
* Checks if the following unnamed rule is found:
*
* if header :matches "subject" "*" {
* set "subject" "${1}";
* }
*
* This is used by Sieverules and a commonly recommended solution to append the original subject to the vacation's subject
* This rule is usually preceeded by setting a global variable to empty, like this:
*
* set "subject" "";
* if header :matches "subject" "*" { ...
*/
private function is_vacation_subject_rule($rule) {
$name = isset($rule['name']) ? $rule['name'] : '';
$type = isset($rule['type']) ? $rule['type'] : '';
if (!empty($name) || $type != "if" || count($rule['tests']) != 1 || count($rule['actions']) != 1) {
return false;
}

$test = $rule['tests'][0];
$action = $rule['actions'][0];

return $test['test'] == 'header' && $test['type'] == 'matches' && $test['arg1'] == 'subject' && $test['arg2'] == '*'
&& $action['type'] == 'set' && $action['name'] == 'subject' && $action['value'] == '${1}';
}

/**
* Checks if there is any vacation rule that wants to append original subject to the vacation's subject
*/
private function should_generate_vacation_subject_rule() {
foreach ($this->content as $rule) {
foreach ($rule['actions'] as $action) {
if ($action['type'] == 'vacation' && isset($action['subject_append_original']) && $action['subject_append_original'] == 1) {
return true;
}
}
}
return false;
}

private function ends_with($haystack, $needle) {
if ('' === $needle) {
return true;
}
if ('' === $haystack && '' !== $needle) {
return false;
}
$length = strlen($needle);
return strlen($haystack) >= $length && 0 === substr_compare($haystack, $needle, -$length, $length);
}

/**
* Converts disabled Sieverules serialized rules into Managesieve format
*
Expand Down
6 changes: 6 additions & 0 deletions plugins/managesieve/lib/Roundcube/rcube_sieve_vacation.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ protected function vacation_post()
$status = rcube_utils::get_input_string('vacation_status', rcube_utils::INPUT_POST);
$from = rcube_utils::get_input_string('vacation_from', rcube_utils::INPUT_POST, true);
$subject = rcube_utils::get_input_string('vacation_subject', rcube_utils::INPUT_POST, true);
$subject_append_original = rcube_utils::get_input_value('vacation_subject_append_original', rcube_utils::INPUT_POST);
$reason = rcube_utils::get_input_string('vacation_reason', rcube_utils::INPUT_POST, true);
$addresses = rcube_utils::get_input_value('vacation_addresses', rcube_utils::INPUT_POST, true);
$interval = rcube_utils::get_input_string('vacation_interval', rcube_utils::INPUT_POST);
Expand All @@ -204,6 +205,7 @@ protected function vacation_post()
$vacation_action['type'] = 'vacation';
$vacation_action['reason'] = $this->strip_value(str_replace("\r\n", "\n", $reason), true);
$vacation_action['subject'] = trim($subject);
$vacation_action['subject_append_original'] = $subject_append_original == 1 ? 1 : NULL;
$vacation_action['from'] = trim($from);
$vacation_action['addresses'] = $addresses;
$vacation_action[$interval_type] = $interval;
Expand Down Expand Up @@ -393,6 +395,7 @@ public function vacation_form($attrib)
// form elements
$from = new html_inputfield(['name' => 'vacation_from', 'id' => 'vacation_from', 'size' => 50, 'class' => 'form-control']);
$subject = new html_inputfield(['name' => 'vacation_subject', 'id' => 'vacation_subject', 'size' => 50, 'class' => 'form-control']);
$subject_append_original = new html_inputfield(['name' => 'vacation_subject_append_original', 'id' => 'vacation_subject_append_original', 'type' => 'checkbox', 'class' => 'form-control']);
$reason = new html_textarea(['name' => 'vacation_reason', 'id' => 'vacation_reason', 'cols' => 60, 'rows' => 8]);
$interval = new html_inputfield(['name' => 'vacation_interval', 'id' => 'vacation_interval', 'size' => 5, 'class' => 'form-control']);
$addresses = '<textarea name="vacation_addresses" id="vacation_addresses" data-type="list" data-size="30" style="display: none">'
Expand Down Expand Up @@ -524,6 +527,9 @@ public function vacation_form($attrib)

$table->add('title', html::label('vacation_subject', $this->plugin->gettext('vacation.subject')));
$table->add(null, $subject->show(!empty($this->vacation['subject']) ? $this->vacation['subject'] : null));
$table->add('title', '');
$table->add(null, $subject_append_original->show('1', ['checked' => isset($this->vacation['subject_append_original']) && $this->vacation['subject_append_original'] == 1 ? 'checked' : ''])
. html::label('vacation_subject_append_original', $this->plugin->gettext('vacation.subjectappendoriginal')));
$table->add('title', html::label('vacation_reason', $this->plugin->gettext('vacation.body')));
$table->add(null, $reason->show(!empty($this->vacation['reason']) ? $this->vacation['reason'] : null));

Expand Down
1 change: 1 addition & 0 deletions plugins/managesieve/localization/de_DE.inc
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ $labels['vacation.reply'] = 'Antwort';
$labels['vacation.advanced'] = 'Erweiterte Einstellungen';
$labels['vacation.from'] = 'Antwort E-Mail-Adresse:';
$labels['vacation.subject'] = 'Betreff';
$labels['vacation.subjectappendoriginal'] = 'Anhängen des ursprünglichen Betreffs an die Antwort';
$labels['vacation.body'] = 'Nachricht';
$labels['vacation.start'] = 'Beginn der Abwesenheit';
$labels['vacation.end'] = 'Ende der Abwesenheit';
Expand Down
1 change: 1 addition & 0 deletions plugins/managesieve/localization/en_GB.inc
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ $labels['vacation.reply'] = 'Reply message';
$labels['vacation.advanced'] = 'Advanced settings';
$labels['vacation.from'] = 'Reply sender address';
$labels['vacation.subject'] = 'Subject';
$labels['vacation.subjectappendoriginal'] = 'Append original subject to the reply';
$labels['vacation.body'] = 'Body';
$labels['vacation.start'] = 'Start time';
$labels['vacation.end'] = 'End time';
Expand Down
1 change: 1 addition & 0 deletions plugins/managesieve/localization/en_US.inc
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ $labels['vacation.reply'] = 'Reply message';
$labels['vacation.advanced'] = 'Advanced settings';
$labels['vacation.from'] = 'Reply sender address';
$labels['vacation.subject'] = 'Subject';
$labels['vacation.subjectappendoriginal'] = 'Append original subject to the reply';
$labels['vacation.body'] = 'Body';
$labels['vacation.start'] = 'Start time';
$labels['vacation.end'] = 'End time';
Expand Down
1 change: 1 addition & 0 deletions plugins/managesieve/localization/hu_HU.inc
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ $labels['vacation.reply'] = 'Válasz az üzenetre';
$labels['vacation.advanced'] = 'Haladó beállítások';
$labels['vacation.from'] = 'Válasz küldőjének címe:';
$labels['vacation.subject'] = 'Tárgy';
$labels['vacation.subjectappendoriginal'] = 'Eredeti tárgy hozzáfűzése a válaszhoz';
$labels['vacation.body'] = 'Törzs';
$labels['vacation.start'] = 'Kezdő időpontja';
$labels['vacation.end'] = 'Befejezés időpontja';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require ["vacation","variables"];
set "subject" "";
if header :matches "subject" "*" {
set "subject" "${1}";
}
# rule:[Out of Office]
if true
{
vacation :days 3 :subject "Out of office: ${subject}" "Went for holiday";
}