Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Abstract class describing Inbound Message Handlers.
  19   *
  20   * @package    core_message
  21   * @copyright  2014 Andrew Nicols
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  namespace core\message\inbound;
  25  
  26  /**
  27   * Abstract class describing Inbound Message Handlers.
  28   *
  29   * @copyright  2014 Andrew NIcols
  30   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   *
  32   * @property-read int $id The ID of the handler in the database
  33   * @property-read string $component The component of this handler
  34   * @property-read int $defaultexpiration Default expiration of new addresses for this handler
  35   * @property-read string $description The description of this handler
  36   * @property-read string $name The name of this handler
  37   * @property-read bool $validateaddress Whether the address validation is a requiredment
  38   * @property-read bool $enabled Whether this handler is currently enabled
  39   * @property-read string $classname The name of handler class
  40   */
  41  abstract class handler {
  42  
  43      /**
  44       * @var int $id The id of the handler in the database.
  45       */
  46      private $id = null;
  47  
  48      /**
  49       * @var string $component The component to which this handler belongs.
  50       */
  51      private $component = '';
  52  
  53      /**
  54       * @var int $defaultexpiration The default expiration time to use when created a new key.
  55       */
  56      private $defaultexpiration = WEEKSECS;
  57  
  58      /**
  59       * @var bool $validateaddress Whether to validate the sender address when processing this handler.
  60       */
  61      private $validateaddress = true;
  62  
  63      /**
  64       * @var bool $enabled Whether this handler is currently enabled.
  65       */
  66      private $enabled = false;
  67  
  68      /**
  69       * @var $accessibleproperties A list of the properties which can be read.
  70       */
  71      private $accessibleproperties = array(
  72          'id' => true,
  73          'component' => true,
  74          'defaultexpiration' => true,
  75          'validateaddress' => true,
  76          'enabled' => true,
  77      );
  78  
  79      /**
  80       * Magic getter to fetch the specified key.
  81       *
  82       * @param string $key The name of the key to retrieve
  83       */
  84      public function __get($key) {
  85          // Some properties have logic behind them.
  86          $getter = 'get_' . $key;
  87          if (method_exists($this, $getter)) {
  88              return $this->$getter();
  89          }
  90  
  91          // Check for a commonly accessibly property.
  92          if (isset($this->accessibleproperties[$key])) {
  93              return $this->$key;
  94          }
  95  
  96          // Unknown property - bail.
  97          throw new \coding_exception('unknown_property ' . $key);
  98      }
  99  
 100      /**
 101       * Set the id name.
 102       *
 103       * @param int $id The id to set
 104       * @return int The newly set id
 105       */
 106      public function set_id($id) {
 107          return $this->id = $id;
 108      }
 109  
 110      /**
 111       * Set the component name.
 112       *
 113       * @param string $component The component to set
 114       * @return string The newly set component
 115       */
 116      public function set_component($component) {
 117          return $this->component = $component;
 118      }
 119  
 120      /**
 121       * Whether the current handler allows changes to the address validation
 122       * setting.
 123       *
 124       * By default this will return true, but for some handlers it may be
 125       * necessary to disallow such changes.
 126       *
 127       * @return boolean
 128       */
 129      public function can_change_validateaddress() {
 130          return true;
 131      }
 132  
 133      /**
 134       * Set whether validation of the address is required.
 135       *
 136       * @param bool $validateaddress The new state of validateaddress
 137       * @return bool
 138       */
 139      public function set_validateaddress($validateaddress) {
 140          return $this->validateaddress = $validateaddress;
 141      }
 142  
 143      /**
 144       * Whether the current handler allows changes to expiry of the generated email address.
 145       *
 146       * By default this will return true, but for some handlers it may be
 147       * necessary to disallow such changes.
 148       *
 149       * @return boolean
 150       */
 151      public function can_change_defaultexpiration() {
 152          return true;
 153      }
 154  
 155      /**
 156       * Whether this handler can be disabled (or enabled).
 157       *
 158       * By default this will return true, but for some handlers it may be
 159       * necessary to disallow such changes. For example, a core handler to
 160       * handle rejected mail validation should not be disabled.
 161       *
 162       * @return boolean
 163       */
 164      public function can_change_enabled() {
 165          return true;
 166      }
 167  
 168      /**
 169       * Set the enabled name.
 170       *
 171       * @param bool $enabled The new state of enabled
 172       * @return bool
 173       */
 174      public function set_enabled($enabled) {
 175          return $this->enabled = $enabled;
 176      }
 177  
 178      /**
 179       * Set the default validity for new keys.
 180       *
 181       * @param int $period The time in seconds before a key expires
 182       * @return int
 183       */
 184      public function set_defaultexpiration($period) {
 185          return $this->defaultexpiration = $period;
 186      }
 187  
 188      /**
 189       * Get the non-namespaced name of the current class.
 190       *
 191       * @return string The classname
 192       */
 193      private function get_classname() {
 194          $classname = get_class($this);
 195          if (strpos($classname, '\\') !== 0) {
 196              $classname = '\\' . $classname;
 197          }
 198  
 199          return $classname;
 200      }
 201  
 202      /**
 203       * Return a description for the current handler.
 204       *
 205       * @return string
 206       */
 207      protected abstract function get_description();
 208  
 209      /**
 210       * Return a name for the current handler.
 211       * This appears in the admin pages as a human-readable name.
 212       *
 213       * @return string
 214       */
 215      protected abstract function get_name();
 216  
 217      /**
 218       * Process the message against the current handler.
 219       *
 220       * @param \stdClass $record The Inbound Message Handler record
 221       * @param \stdClass $messagedata The message data
 222       */
 223      public abstract function process_message(\stdClass $record, \stdClass $messagedata);
 224  
 225      /**
 226       * Return the content of any success notification to be sent.
 227       * Both an HTML and Plain Text variant must be provided.
 228       *
 229       * If this handler does not need to send a success notification, then
 230       * it should return a falsey value.
 231       *
 232       * @param \stdClass $messagedata The message data.
 233       * @param \stdClass $handlerresult The record for the newly created post.
 234       * @return \stdClass with keys `html` and `plain`.
 235       */
 236      public function get_success_message(\stdClass $messagedata, $handlerresult) {
 237          return false;
 238      }
 239  
 240      /**
 241       * Remove quoted message string from the text (NOT HTML) message.
 242       *
 243       * @param \stdClass $messagedata The Inbound Message record
 244       *
 245       * @return array message and message format to use.
 246       */
 247      protected static function remove_quoted_text($messagedata) {
 248          if (!empty($messagedata->plain)) {
 249              $text = $messagedata->plain;
 250          } else {
 251              $text = html_to_text($messagedata->html);
 252          }
 253          $messageformat = FORMAT_PLAIN;
 254  
 255          $splitted = preg_split("/\n|\r/", $text);
 256          if (empty($splitted)) {
 257              return array($text, $messageformat);
 258          }
 259  
 260          $i = 0;
 261          $flag = false;
 262          foreach ($splitted as $i => $element) {
 263              if (stripos($element, ">") === 0) {
 264                  // Quoted text found.
 265                  $flag = true;
 266                  // Remove 2 non empty line before this.
 267                  for ($j = $i - 1; ($j >= 0); $j--) {
 268                      $element = $splitted[$j];
 269                      if (!empty($element)) {
 270                          unset($splitted[$j]);
 271                          break;
 272                      }
 273                  }
 274                  break;
 275              }
 276          }
 277          if ($flag) {
 278              // Quoted text was found.
 279              // Retrieve everything from the start until the line before the quoted text.
 280              $splitted = array_slice($splitted, 0, $i-1);
 281  
 282              // Strip out empty lines towards the end, since a lot of clients add a huge chunk of empty lines.
 283              $reverse = array_reverse($splitted);
 284              foreach ($reverse as $i => $line) {
 285                  if (empty($line)) {
 286                      unset($reverse[$i]);
 287                  } else {
 288                      // Non empty line found.
 289                      break;
 290                  }
 291              }
 292  
 293              $replaced = implode(PHP_EOL, array_reverse($reverse));
 294              $message = trim($replaced);
 295          } else {
 296              // No quoted text, fallback to original text.
 297              if (!empty($messagedata->html)) {
 298                  $message = $messagedata->html;
 299                  $messageformat = FORMAT_HTML;
 300              } else {
 301                  $message = $messagedata->plain;
 302              }
 303          }
 304          return array($message, $messageformat);
 305      }
 306  }