Author: Michael Slusarz (slusarz@horde.org)
Inheritance: extends Ingo_Rule_Addresses, implements Ingo_Rule_System
Example #1
0
 /**
  * Constructs a new procmail recipe.
  *
  * @param array $params        Array of parameters.
  *                               REQUIRED FIELDS:
  *                                'action'
  *                               OPTIONAL FIELDS:
  *                                'action-value' (only used if the
  *                                'action' requires it)
  *                                'disable'
  * @param array $scriptparams  Array of parameters passed to
  *                             Ingo_Script_Procmail.
  */
 public function __construct($params = array(), $scriptparams = array())
 {
     $this->_disable = !empty($params['disable']);
     $this->_params = array_merge($this->_params, $scriptparams);
     $delivery = '| ';
     if (isset($this->_params['delivery_agent'])) {
         $delivery .= $this->_params['delivery_agent'] . ' ';
     }
     if (isset($this->_params['delivery_mailbox_prefix'])) {
         $delivery .= ' ' . $this->_params['delivery_mailbox_prefix'];
     }
     switch ($params['action']) {
         case 'Ingo_Rule_User_Keep':
             // Note: you may have to set the DEFAULT variable in your
             // backend configuration.
             $this->_action[] = $delivery .= '$DEFAULT';
             break;
         case 'Ingo_Rule_User_Move':
             $this->_action[] = $delivery .= $this->procmailPath($params['action-value']);
             break;
         case 'Ingo_Rule_User_Discard':
             $this->_action[] = '/dev/null';
             break;
         case 'Ingo_Rule_User_Redirect':
             $this->_action[] = '! ' . $params['action-value'];
             break;
         case 'Ingo_Rule_User_RedirectKeep':
             $this->_action[] = '{';
             $this->_action[] = '  :0 c';
             $this->_action[] = '  ! ' . $params['action-value'];
             if (strpos($this->_flags, 'c') === false) {
                 $this->_action[] = '';
                 $this->_action[] = '  :0' . (isset($this->_params['delivery_agent']) ? ' w' : '');
                 $this->_action[] = '  ' . $delivery . '$DEFAULT';
             }
             $this->_action[] = '}';
             break;
         case 'Ingo_Rule_User_Reject':
             $this->_action[] = '{';
             $this->_action[] = '  :0 h';
             $this->_action[] = '  SUBJECT=| formail -xSubject:';
             $this->_action[] = '';
             $this->_action[] = '  :0 h';
             $this->_action[] = '  SENDER=| formail -zxFrom:';
             $this->_action[] = '';
             $this->_action[] = '  :0 Wh';
             $this->_action[] = '  * !^FROM_DAEMON';
             $this->_action[] = '  * !^X-Loop: $SENDER';
             $this->_action[] = '  | (formail -rA"X-Loop: $SENDER" \\';
             $reason = $params['action-value'];
             if (Horde_Mime::is8bit($reason)) {
                 $this->_action[] = '    -i"Subject: Re: $SUBJECT" \\';
                 $this->_action[] = '    -i"Content-Transfer-Encoding: quoted-printable" \\';
                 $this->_action[] = '    -i"Content-Type: text/plain; charset=UTF-8" ; \\';
                 $reason = Horde_Mime_QuotedPrintable::encode($reason);
             } else {
                 $this->_action[] = '    -i"Subject: Re: $SUBJECT" ; \\';
             }
             $reason = addcslashes($reason, "\\\n\r\t\"`");
             $this->_action[] = '    ' . $this->_params['echo'] . ' -e "' . $reason . '" \\';
             $this->_action[] = '  ) | $SENDMAIL -oi -t';
             $this->_action[] = '}';
             break;
         case 'Ingo_Rule_System_Vacation':
             $days = $params['action-value']['days'];
             $timed = !empty($params['action-value']['start']) && !empty($params['action-value']['end']);
             $this->_action[] = '{';
             foreach ($params['action-value']['addresses'] as $address) {
                 if (empty($address)) {
                     continue;
                 }
                 $this->_action[] = '  :0';
                 $this->_action[] = '  * ^TO_' . $address;
                 $this->_action[] = '  {';
                 $this->_action[] = '    FILEDATE=`test -f ${VACATION_DIR:-.}/\'.vacation.' . $address . '\' && ' . $this->_params['ls'] . ' -lcn --time-style=+%s ${VACATION_DIR:-.}/\'.vacation.' . $address . '\' | ' . 'awk \'{ print $6 + (' . $days * 86400 . ') }\'`';
                 $this->_action[] = '    DATE=`' . $this->_params['date'] . ' +%s`';
                 $this->_action[] = '    DUMMY=`test -f ${VACATION_DIR:-.}/\'.vacation.' . $address . '\' && ' . 'test $FILEDATE -le $DATE && ' . 'rm ${VACATION_DIR:-.}/\'.vacation.' . $address . '\'`';
                 if ($timed) {
                     $this->_action[] = '    START=' . $params['action-value']['start'];
                     $this->_action[] = '    END=' . $params['action-value']['end'];
                 }
                 $this->_action[] = '';
                 $this->_action[] = '    :0 h';
                 $this->_action[] = '    SUBJECT=| formail -xSubject:';
                 $this->_action[] = '';
                 $this->_action[] = '    :0 Whc: ${VACATION_DIR:-.}/vacation.lock';
                 if ($timed) {
                     $this->_action[] = '    * ? test $DATE -gt $START && test $END -gt $DATE';
                 }
                 $this->_action[] = '    {';
                 $this->_action[] = '      :0 Wh';
                 $this->_action[] = '      * ^TO_' . $address;
                 $this->_action[] = '      * !^X-Loop: ' . $address;
                 $this->_action[] = '      * !^X-Spam-Flag: YES';
                 if (count($params['action-value']['excludes']) > 0) {
                     foreach ($params['action-value']['excludes'] as $exclude) {
                         if (!empty($exclude)) {
                             $this->_action[] = '      * !^From.*' . $exclude;
                         }
                     }
                 }
                 if ($params['action-value']['ignorelist']) {
                     $this->_action[] = '      * !^FROM_DAEMON';
                 }
                 $this->_action[] = '      | formail -rD 8192 ${VACATION_DIR:-.}/.vacation.' . $address;
                 $this->_action[] = '      :0 eh';
                 $this->_action[] = '      | (formail -rI"Precedence: junk" \\';
                 $this->_action[] = '       -a"From: <' . $address . '>" \\';
                 $this->_action[] = '       -A"X-Loop: ' . $address . '" \\';
                 $reason = Ingo_Rule_System_Vacation::vacationReason($params['action-value']['reason'], $params['action-value']['start'], $params['action-value']['end']);
                 if (Horde_Mime::is8bit($reason)) {
                     $this->_action[] = '       -i"Subject: ' . Horde_Mime::encode($params['action-value']['subject'] . ' (Re: $SUBJECT)') . '" \\';
                     $this->_action[] = '       -i"Content-Transfer-Encoding: quoted-printable" \\';
                     $this->_action[] = '       -i"Content-Type: text/plain; charset=UTF-8" ; \\';
                     $reason = Horde_Mime_QuotedPrintable::encode($reason);
                 } else {
                     $this->_action[] = '       -i"Subject: ' . Horde_Mime::encode($params['action-value']['subject'] . ' (Re: $SUBJECT)') . '" ; \\';
                 }
                 $reason = addcslashes($reason, "\\\n\r\t\"`");
                 $this->_action[] = '       ' . $this->_params['echo'] . ' -e "' . $reason . '" \\';
                 $this->_action[] = '      ) | $SENDMAIL -f' . $address . ' -oi -t';
                 $this->_action[] = '    }';
                 $this->_action[] = '  }';
             }
             $this->_action[] = '}';
             break;
         case 'Ingo_Rule_System_Forward':
             /* Make sure that we prevent mail loops using 3 methods.
              *
              * First, we call sendmail -f to set the envelope sender to be the
              * same as the original sender, so bounces will go to the original
              * sender rather than to us.  This unfortunately triggers lots of
              * Authentication-Warning: messages in sendmail's logs.
              *
              * Second, add an X-Loop header, to handle the case where the
              * address we forward to forwards back to us.
              *
              * Third, don't forward mailer daemon messages (i.e., bounces).
              * Method 1 above should make this redundant, unless we're sending
              * mail from this account and have a bad forward-to account.
              *
              * Get the from address, saving a call to formail if possible.
              * The procmail code for doing this is borrowed from the
              * Procmail Library Project, http://pm-lib.sourceforge.net/.
              * The Ingo project has the permission to use Procmail Library code
              * under Apache licence v 1.x or any later version.
              * Permission obtained 2006-04-04 from Author Jari Aalto. */
             $this->_action[] = '{';
             $this->_action[] = '  :0 ';
             $this->_action[] = '  *$ ! ^From *\\/[^  ]+';
             $this->_action[] = '  *$ ! ^Sender: *\\/[^   ]+';
             $this->_action[] = '  *$ ! ^From: *\\/[^     ]+';
             $this->_action[] = '  *$ ! ^Reply-to: *\\/[^     ]+';
             $this->_action[] = '  {';
             $this->_action[] = '    OUTPUT = `formail -zxFrom:`';
             $this->_action[] = '  }';
             $this->_action[] = '  :0 E';
             $this->_action[] = '  {';
             $this->_action[] = '    OUTPUT = $MATCH';
             $this->_action[] = '  }';
             $this->_action[] = '';
             /* Forward to each address on our list. */
             foreach ($params['action-value'] as $address) {
                 if (!empty($address)) {
                     $this->_action[] = '  :0 c';
                     $this->_action[] = '  * !^FROM_MAILER';
                     $this->_action[] = '  * !^X-Loop: to-' . $address;
                     $this->_action[] = '  | formail -A"X-Loop: to-' . $address . '" | $SENDMAIL -oi -f $OUTPUT ' . $address;
                 }
             }
             /* In case of mail loop or bounce, store a copy locally.  Note
              * that if we forward to more than one address, only a mail loop
              * on the last address will cause a local copy to be saved.  TODO:
              * The next two lines are redundant (and create an extra copy of
              * the message) if "Keep a copy of messages in this account" is
              * checked. */
             $this->_action[] = '  :0 E' . (isset($this->_params['delivery_agent']) ? 'w' : '');
             $this->_action[] = '  ' . $delivery . '$DEFAULT';
             $this->_action[] = '  :0 ';
             $this->_action[] = '  /dev/null';
             $this->_action[] = '}';
             break;
         default:
             $this->_valid = false;
             break;
     }
 }
Example #2
0
    public function testVacationEnabled()
    {
        $vacation = new Ingo_Rule_System_Vacation();
        $vacation->addAddresses('*****@*****.**');
        $vacation->disable = false;
        $vacation->subject = 'Subject';
        $vacation->reason = "Because I don't like working!";
        $this->storage->updateRule($vacation);
        $this->_assertScript(':0
{
:0
* ^TO_from@example.com
{
FILEDATE=`test -f ${VACATION_DIR:-.}/\'.vacation.from@example.com\' && ls -lcn --time-style=+%s ${VACATION_DIR:-.}/\'.vacation.from@example.com\' | awk \'{ print $6 + (604800) }\'`
DATE=`date +%s`
DUMMY=`test -f ${VACATION_DIR:-.}/\'.vacation.from@example.com\' && test $FILEDATE -le $DATE && rm ${VACATION_DIR:-.}/\'.vacation.from@example.com\'`
:0 h
SUBJECT=| formail -xSubject:
:0 Whc: ${VACATION_DIR:-.}/vacation.lock
{
:0 Wh
* ^TO_from@example.com
* !^X-Loop: from@example.com
* !^X-Spam-Flag: YES
* !^FROM_DAEMON
| formail -rD 8192 ${VACATION_DIR:-.}/.vacation.from@example.com
:0 eh
| (formail -rI"Precedence: junk" \\
-a"From: <*****@*****.**>" \\
-A"X-Loop: from@example.com" \\
-i"Subject: Subject (Re: $SUBJECT)" ; \\
echo -e "Because I don\'t like working!" \\
) | $SENDMAIL -ffrom@example.com -oi -t
}
}
}');
    }
Example #3
0
 /**
  * Generates the maildrop script to handle vacation messages.
  *
  * @param Ingo_Rule $rule  Rule object.
  */
 protected function _generateVacation(Ingo_Rule $rule)
 {
     if (!count($rule)) {
         return;
     }
     $this->_addItem(Ingo::RULE_VACATION, new Ingo_Script_Maildrop_Comment(_("Vacation"), $disable, true));
     $recipe = new Ingo_Script_Maildrop_Recipe(array('action' => 'Ingo_Rule_System_Vacation', 'action-value' => array('addresses' => $rule->addresses, 'subject' => $rule->subject, 'days' => $rule->days, 'ignorelist' => $rule->ignore_list, 'excludes' => $rule->exclude, 'start' => $rule->start, 'end' => $rule->end), 'disable' => $disable), $this->_params);
     $this->_addItem(Ingo::RULE_VACATION, $recipe);
     $this->_addItem(Ingo::RULE_VACATION, new Ingo_Script_String(Ingo_Rule_System_Vacation::vacationReason($rule->reason, $rule->start, $rule->end)), 'vacation.msg');
 }
Example #4
0
 /**
  * Set vacation
  *
  * @param array $info        Vacation details.
  *   - addresses: (mixed)    Address list to enable vacation for.
  *   - days: (integer)       Number of days between vacation replies.
  *   - excludes: (mixed)     Address list to exclude from vacation replies.
  *   - ignorelist: (boolean) If set, ignore mailing lists.
  *   - reason: (string)      Vacation message.
  *   - subject: (string)     Vacation email subject.
  *   - start: (integer)      Timestamp of vacation starttime.
  *   - end: (integer)        Timestamp of vacation endtime.
  * @param boolean $enable  Enable the filter?
  *
  * @throws Ingo_Exception
  */
 public function setVacation($info, $enable = true)
 {
     global $injector, $registry;
     if (empty($info)) {
         return true;
     }
     /* Get vacation filter. */
     $ingo_storage = $injector->getInstance('Ingo_Factory_Storage')->create();
     $vacation = new Ingo_Rule_System_Vacation();
     /* Make sure we have at least one address. */
     if (empty($info['addresses'])) {
         $identity = $injector->getInstance('Horde_Core_Factory_Identity')->create();
         /* Remove empty lines. */
         $info['addresses'] = preg_replace('/\\n{2,}/', "\n", implode("\n", $identity->getAll('from_addr')));
         if (empty($info['addresses'])) {
             $info['addresses'] = $registry->getAuth();
         }
     }
     $vacation->addresses($info['addresses']);
     if (isset($info['days'])) {
         $vacation->days = $info['days'];
     }
     if (isset($info['excludes'])) {
         $vacation->exclude = $info['excludes'];
     }
     if (isset($info['ignorelist'])) {
         $vacation->ignore_list = $info['ignorelist'] == 'on';
     }
     if (isset($info['reason'])) {
         $vacation->reason = $info['reason'];
     }
     if (isset($info['subject'])) {
         $vacation->subject = $info['subject'];
     }
     if (isset($info['start'])) {
         $vacation->start = $info['start'];
     }
     if (isset($info['end'])) {
         $vacation->end = $info['end'];
     }
     $vacation->enable = $enable;
     $ingo_storage->updateRule($vacation);
     $injector->getInstance('Ingo_Factory_Script')->activateAll();
 }
Example #5
0
    public function testVacationEnabled()
    {
        $vacation = new Ingo_Rule_System_Vacation();
        $vacation->addAddresses('*****@*****.**');
        $vacation->disable = false;
        $vacation->subject = 'Subject';
        $vacation->reason = "Because I don't like working!";
        $this->storage->updateRule($vacation);
        $this->_assertScript('require ["vacation", "regex"];
if allof ( not exists "list-help", not exists "list-unsubscribe", not exists "list-subscribe", not exists "list-owner", not exists "list-post", not exists "list-archive", not exists "list-id", not exists "Mailing-List", not header :comparator "i;ascii-casemap" :is "Precedence" ["list", "bulk", "junk"], not header :comparator "i;ascii-casemap" :matches "To" "Multiple recipients of*" ) {
vacation :days 7 :addresses "*****@*****.**" :subject "Subject" "Because I don\'t like working!";
}');
    }
Example #6
0
 /**
  */
 protected function _vacationCode()
 {
     $code = 'vacation ';
     if (!empty($this->_vars['days'])) {
         $code .= ':days ' . $this->_vars['days'] . ' ';
     }
     $addresses = $this->_vars['addresses'];
     $stringlist = '';
     if (count($addresses) > 1) {
         foreach ($addresses as $address) {
             $address = trim($address);
             if (!empty($address)) {
                 $stringlist .= empty($stringlist) ? '"' : ', "';
                 $stringlist .= Ingo_Script_Sieve::escapeString($address) . '"';
             }
         }
         $stringlist = "[" . $stringlist . "] ";
     } elseif (count($addresses) == 1) {
         $stringlist = '"' . Ingo_Script_Sieve::escapeString($addresses[0]) . '" ';
     }
     if (!empty($stringlist)) {
         $code .= ':addresses ' . $stringlist;
     }
     if (!empty($this->_vars['subject'])) {
         $code .= ':subject "' . Horde_Mime::encode(Ingo_Script_Sieve::escapeString($this->_vars['subject'])) . '" ';
     }
     return $code . '"' . Ingo_Script_Sieve::escapeString(Ingo_Rule_System_Vacation::vacationReason($this->_vars['reason'], $this->_vars['start'], $this->_vars['end'])) . '";';
 }