b2evolution PHP Cross Reference Blogging Systems

Source: /inc/cron/model/_decode_returned_emails.funcs.php - 916 lines - 24975 bytes - Summary - Text - Print

Description: This file implements the decode the returned emails support functions. b2evolution - {@link http://b2evolution.net/} Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}

   1  <?php
   2  /**

   3   * This file implements the decode the returned emails support functions.

   4   *

   5   * b2evolution - {@link http://b2evolution.net/}

   6   * Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}

   7   *

   8   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}

   9   *

  10   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}

  11   * @author fplanque: Francois PLANQUE

  12   *

  13   * @package admin

  14   *

  15   * @version $Id: _decode_returned_emails.funcs.php 815 2012-02-11 08:25:32Z yura $

  16   */
  17  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  18  
  19  /**

  20   * Print out a debugging message with optional HTML color added

  21   *

  22   * @param string Message

  23   * @param string

  24   */
  25  function dre_msg( $message, $cron = false )
  26  {
  27      global $is_web, $result_message, $dre_messages;
  28  
  29      // Log all messages to $dre_messages no matter if we are in cron mode or not

  30      // We may use this report later, display or send to the blog owner

  31      $dre_messages[] = $message;
  32  
  33      if( $cron )
  34      {    // We are in cron mode, log the message
  35          if( $is_web )
  36              $message .= '<br />';
  37  
  38          $result_message .= $message."\n";
  39      }
  40  }
  41  
  42  /**

  43   * Connect to a mail server

  44   *

  45   * @param string Message

  46   * @return resource $mbox

  47   */
  48  function dre_connect()
  49  {
  50      if( !extension_loaded( 'imap' ) )
  51      {    // Exit here if imap extension is not loaded
  52          dre_msg('<b class="red">IMAP extension is NOT loaded!</b>');
  53          return false;
  54      }
  55  
  56      global $Settings;
  57  
  58      $host = $Settings->get('repath_server_host').':'.$Settings->get('repath_server_port');
  59      $mailserver = '{'.$host;
  60  
  61      dre_msg('Connecting and authenticating to mail server <b>'.$host.'</b>');
  62  
  63      switch( $Settings->get('repath_encrypt') )
  64      {
  65          case 'ssl':
  66              $mailserver .= '/ssl';
  67              break;
  68  
  69          case 'tls':
  70              $mailserver .= '/tls';
  71              break;
  72  
  73          case 'none':
  74          default:
  75              $mailserver .= '/notls';
  76              break;
  77      }
  78  
  79      switch( $Settings->get('repath_method') )
  80      {
  81          case 'pop3':
  82          case 'pop3a':
  83              $mailserver .= '/pop3';
  84              break;
  85  
  86          case 'imap':
  87          default:
  88              // imap needs no additional options

  89              break;
  90      }
  91  
  92      if( $Settings->get('repath_novalidatecert') )
  93      {
  94          $mailserver .= '/novalidate-cert';
  95      }
  96  
  97      $mailserver .= '}INBOX';
  98  
  99      // Connect to mail server (one retry)

 100      $mbox = @imap_open( $mailserver, $Settings->get('repath_username'), $Settings->get('repath_password'), NULL, 1 );
 101  
 102      if( is_null(@get_resource_type($mbox)) )
 103      {    // Not a resource
 104          $error = imap_errors();
 105          if( is_array($error) )
 106          {
 107              $error = implode( "<br />\n", $error );
 108          }
 109  
 110          dre_msg( sprintf( /* TRANS: %s is the error message */ T_('Connection failed: %s'), $error), true );
 111          return false;
 112      }
 113      dre_msg('<b class="green">Successfully connected!</b>');
 114  
 115      @imap_errors();
 116  
 117      return $mbox;
 118  }
 119  
 120  
 121  /**

 122   * Read messages from server and save returned emails into DB

 123   *

 124   * @param resource $mbox created by dre_connect() (by reference)

 125   * @param integer the number of messages to process

 126   * @return boolean true on success

 127   */
 128  function dre_process_messages( & $mbox, $limit )
 129  {
 130      //return; // Exit, in development...

 131  
 132  
 133      global $Settings;
 134      global $dre_messages, $dre_emails, $email_cntr, $del_cntr, $is_cron_mode;
 135  
 136      // No execution time limit

 137      set_max_execution_time(0);
 138  
 139      $email_cntr = 0;
 140      $del_cntr = 0;
 141      for( $index = 1; $index <= $limit; $index++ )
 142      {
 143          dre_msg('<hr /><h3>Processing message #'.$index.':</h3>');
 144  
 145          $strbody = '';
 146          $hasAttachment = false;
 147          $hasRelated = false;
 148  
 149          // Save email to hard drive, otherwise attachments may take a lot of RAM

 150          if( ! ($tmpMIME = tempnam( sys_get_temp_dir(), 'b2evoMail' )) )
 151          {
 152              dre_msg( T_('Could not create temporary file.'), true );
 153              continue;
 154          }
 155          imap_savebody( $mbox, $tmpMIME, $index );
 156  
 157          // Create random temp directory for message parts

 158          $tmpDirMIME = dre_tempdir( sys_get_temp_dir(), 'b2evo_' );
 159  
 160          $mimeParser = new mime_parser_class;
 161          $mimeParser->mbox = 0;                // Set to 0 for parsing a single message file

 162          $mimeParser->decode_headers = 1;
 163          $mimeParser->ignore_syntax_errors = 1;
 164          $mimeParser->extract_addresses = 0;
 165  
 166          $MIMEparameters = array(
 167                  'File' => $tmpMIME,
 168                  'SaveBody' => $tmpDirMIME,    // Save message body parts to a directory
 169                  'SkipBody' => 1,            // Do not retrieve or save message body parts
 170              );
 171  
 172          if( !$mimeParser->Decode( $MIMEparameters, $decodedMIME ) )
 173          {
 174              dre_msg( sprintf( 'MIME message decoding error: %s at position %d.', $mimeParser->error, $mimeParser->error_position), true );
 175              rmdir_r( $tmpDirMIME );
 176              unlink( $tmpMIME );
 177              continue;
 178          }
 179          else
 180          {
 181              dre_msg('MIME message decoding successful');
 182  
 183              if( ! $mimeParser->Analyze( $decodedMIME[0], $parsedMIME ) )
 184              {
 185                  dre_msg( sprintf( 'MIME message analyse error: %s', $mimeParser->error), true );
 186                  rmdir_r( $tmpDirMIME );
 187                  unlink( $tmpMIME );
 188                  continue;
 189              }
 190  
 191              // Get message $subject and $post_date from headers (by reference)

 192              if( ! dre_process_header( $parsedMIME, $subject, $post_date ) )
 193              {    // Couldn't process message headers
 194                  rmdir_r( $tmpDirMIME );
 195                  unlink($tmpMIME);
 196                  continue;
 197              }
 198  
 199              // TODO: handle type == "message" recursively

 200              // sam2kb> For some reason imap_qprint() demages HTML text... needs more testing

 201  
 202              if( $parsedMIME['Type'] == 'html' )
 203              {    // Mail is HTML
 204                  dre_msg( 'HTML message part saved as '.$parsedMIME['DataFile'] );
 205                  $html_body = file_get_contents($parsedMIME['DataFile']);
 206  
 207                  foreach( $parsedMIME['Alternative'] as $alternative )
 208                  {    // First try to get HTML alternative (when possible)
 209                      if( $alternative['Type'] == 'html' )
 210                      {    // HTML text
 211                          dre_msg('HTML alternative message part saved as '.$alternative['DataFile']);
 212                          // sam2kb> TODO: we may need to use $html_body here instead

 213                          $strbody = file_get_contents($alternative['DataFile']);
 214                          break; // stop after first alternative

 215                      }
 216                      elseif( $alternative['Type'] == 'text' )
 217                      {    // Plain text
 218                          dre_msg('Text alternative message part saved as '.$alternative['DataFile']);
 219                          $strbody = imap_qprint( file_get_contents($alternative['DataFile']) );
 220                          break; // stop after first alternative

 221                      }
 222                  }
 223              }
 224              elseif( $parsedMIME['Type'] == 'text' )
 225              {    // Mail is plain text
 226                  dre_msg('Plain-text message part saved as '.$parsedMIME['DataFile']);
 227                  $strbody = imap_qprint( file_get_contents($parsedMIME['DataFile']) );
 228              }
 229              elseif( $parsedMIME['Type'] == 'delivery-status' )
 230              {    // Mail is delivery-status
 231                  $strbody = '';
 232                  foreach( $decodedMIME[0]['Parts'] as $part )
 233                  {
 234                      $strbody .= imap_qprint( file_get_contents( $part['BodyFile'] ) );
 235                  }
 236              }
 237  
 238              if( count($mimeParser->warnings) > 0 )
 239              {
 240                  dre_msg( sprintf('<h4>%d warnings during decode:</h4>', count($mimeParser->warnings)) );
 241                  foreach( $mimeParser->warnings as $k => $v )
 242                  {
 243                      dre_msg('Warning: '.$v.' at position '.$k);
 244                  }
 245              }
 246          }
 247          unlink( $tmpMIME );
 248  
 249          if( empty($html_body) )
 250          {    // Plain text message
 251              dre_msg('Message type: TEXT');
 252              dre_msg('Message body: <pre style="font-size:10px">'.htmlspecialchars($strbody).'</pre>');
 253  
 254              // Process body. First fix different line-endings (dos, mac, unix), remove double newlines

 255              $content = str_replace( array("\r", "\n\n"), "\n", trim($strbody) );
 256          }
 257          else
 258          {    // HTML message
 259              dre_msg('Message type: HTML');
 260  
 261              if( ($parsed_message = dre_prepare_html_message( $html_body )) === false )
 262              {    // No 'auth' tag provided, skip to the next message
 263                  rmdir_r( $tmpDirMIME );
 264                  continue;
 265              }
 266              list($auth, $content) = $parsed_message;
 267          }
 268  
 269          dre_msg('<b class="green">Success</b>');
 270  
 271          $message_text = $content;
 272  
 273          // Remove content after terminators

 274          $content = dre_limit_by_terminators( $content );
 275  
 276          global $Messages;
 277          if( $Messages->has_errors() )
 278          {
 279              // Make it easier for user to find and correct the errors

 280              dre_msg( "\n".sprintf( T_('Processing message: %s'), $post_title ), true );
 281              dre_msg( $Messages->get_string( T_('Cannot post, please correct these errors:'), 'error' ), true );
 282  
 283              $Messages->clear();
 284              rmdir_r( $tmpDirMIME );
 285              continue;
 286          }
 287  
 288          global $dre_emails, $DB, $localtimenow;
 289  
 290          dre_msg( sprintf('<h4>Saving the returned email in the database</h4>' ) );
 291  
 292          // Insert a returned email's data into DB

 293          if( $returned_email = dre_insert_returned_email( $content, $message_text, dre_get_headers( $decodedMIME ) ) )
 294          {
 295              dre_msg( 'Error Type: '.dre_decode_error_type( $returned_email['errtype'] ) );
 296              dre_msg( 'Error Message: '.$returned_email['errormsg'] );
 297  
 298              ++$email_cntr;
 299          }
 300  
 301          // Delete temporary directory

 302          rmdir_r( $tmpDirMIME );
 303  
 304          if( $Settings->get('repath_delete_emails') )
 305          {
 306              dre_msg( 'Marking message for deletion from inbox: '.$index );
 307              imap_delete( $mbox, $index );
 308              ++$del_cntr;
 309          }
 310      }
 311  
 312      // Expunge messages market for deletion

 313      imap_expunge( $mbox );
 314  
 315      return true;
 316  }
 317  
 318  
 319  /**

 320   * Simulate a message processing and save email into DB

 321   *

 322   * @param string Message text

 323   * @return boolean true on success

 324   */
 325  function dre_simulate_message( $message_text )
 326  {
 327      global $Settings;
 328      global $dre_messages, $is_cron_mode, $DB, $localtimenow;
 329  
 330      $content = $message_text;
 331  
 332      dre_msg('<hr /><h3>Processing message:</h3>');
 333  
 334      dre_msg('Message body: <pre style="font-size:10px">'.htmlspecialchars( $content ).'</pre>');
 335  
 336      dre_msg('<b class="green">Success</b>');
 337  
 338      // Remove content after terminators

 339      $content = dre_limit_by_terminators( $content );
 340  
 341      dre_msg( sprintf('<h4>Saving the returned email in the database</h4>' ) );
 342  
 343      // Insert a returned email's data into DB

 344      if( $returned_email = dre_insert_returned_email( $content, $message_text, 'Empty headers' ) )
 345      {
 346          dre_msg( 'Error Type: '.dre_decode_error_type( $returned_email['errtype'] ) );
 347          dre_msg( 'Error Message: '.$returned_email['errormsg'] );
 348          return true;
 349      }
 350      else
 351      {
 352          return false;
 353      }
 354  }
 355  
 356  
 357  /**

 358   * Create a new directory with unique name

 359   * This creates a new directory below the given path with the given prefix and a random number

 360   *

 361   * @param  string $dir base path to new directory

 362   * @param  string $prefix prefix random number with this

 363   * @param  integer $mode permissions to use

 364   * @return string path to created directory

 365   */
 366  function dre_tempdir( $dir, $prefix = 'tmp', $mode = 0700 )
 367  {
 368      // Add trailing slash

 369      $dir = trailing_slash($dir);
 370  
 371      do { $path = $dir.$prefix.mt_rand(); } while( ! evo_mkdir( $path, $mode ) );
 372  
 373      return $path;
 374  }
 375  
 376  
 377  /**

 378   * Process Header information like subject and date of a mail.

 379   *

 380   * @param array $header header as set by mime_parser_class::Analyze()

 381   * @param string message subject by reference

 382   * @param string message date by reference

 383   * @return bool true if valid subject prefix is detected

 384   */
 385  function dre_process_header( $header, & $subject, & $post_date )
 386  {
 387      global $Settings;
 388  
 389      $subject = $header['Subject'];
 390      $ddate = $header['Date'];
 391  
 392      dre_msg('Subject: '.$subject);
 393  
 394      // Check subject to match in titles to identify return path emails

 395      $subject_is_correct = false;
 396      $repath_subjects = explode( "\n", str_replace( array( '\r\n', '\n\n' ), '\n', $Settings->get( 'repath_subject' ) ) );
 397      foreach( $repath_subjects as $repath_subject )
 398      {
 399          if( strpos( $subject, $repath_subject ) !== false )
 400          {
 401              $subject_is_correct = true;
 402              break;
 403          }
 404      }
 405  
 406      if( !$subject_is_correct )
 407      {    // Subject is not match to identify return email
 408          dre_msg( 'Subject prefix is not  "'.implode( '", "', $repath_subjects ).'", skip this email' );
 409          return false;
 410      }
 411  
 412      // Parse Date

 413      if( !preg_match('#^(.{3}, )?(\d{2}) (.{3}) (\d{4}) (\d{2}):(\d{2}):(\d{2})#', $ddate, $match) )
 414      {
 415          $ddate_U = @strtotime($ddate);
 416          if( empty($ddate_U) || strlen($ddate_U) < 2 )
 417          {
 418              dre_msg( sprintf( T_('Could not parse date header "%s"'), $ddate ), true );
 419              return false;
 420          }
 421      }
 422  
 423      if( empty($ddate_U) )
 424      {
 425          $dmonths = array(
 426              'Jan' => 1,
 427              'Feb' => 2,
 428              'Mar' => 3,
 429              'Apr' => 4,
 430              'May' => 5,
 431              'Jun' => 6,
 432              'Jul' => 7,
 433              'Aug' => 8,
 434              'Sep' => 9,
 435              'Oct' => 10,
 436              'Nov' => 11,
 437              'Dec' => 12,
 438          );
 439  
 440          $ddate_H = $match[5];
 441          $ddate_i = $match[6];
 442          $ddate_s = $match[7];
 443  
 444          if( ! isset( $dmonths[$match[3]] ) )
 445          {
 446              dre_msg( T_('Invalid month name in message date string.'), true );
 447              return false;
 448          }
 449          $ddate_m = $dmonths[$match[3]];
 450          $ddate_d = $match[2];
 451          $ddate_Y = $match[4];
 452  
 453          $ddate_U = mktime( $ddate_H, $ddate_i, $ddate_s, $ddate_m, $ddate_d, $ddate_Y );
 454      }
 455  
 456      $post_date = date( 'Y-m-d H:i:s', $ddate_U );
 457  
 458      return true;
 459  }
 460  
 461  
 462  /**

 463   * Extract emails from a message body

 464   *

 465   * @param string Message body

 466   * @param integer Max count emails

 467   * @param string Delimeter between emails

 468   * @return string Emails separated by delimeter

 469   */
 470  function dre_get_emails( $content, $max_count = 1, $delimeter = ', ' )
 471  {
 472      if( preg_match_all( '/([a-z0-9&\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+)/is', $content, $emails ) )
 473      {    // Get the returned emails
 474          global $Settings;
 475  
 476          $emails = array_unique( $emails[1] );
 477          foreach( $emails as $e => $email )
 478          {
 479              if( in_array( $email, array( $Settings->get( 'notification_sender_email' ), $Settings->get( 'notification_return_path' ) ) ) )
 480              {    // Exclude Sender email & Return path
 481                  unset( $emails[$e] );
 482              }
 483          }
 484          // Limit by max count emails

 485          $emails = array_slice( $emails, 0, $max_count );
 486  
 487          return implode( $delimeter, $emails );
 488      }
 489  
 490      return '';
 491  }
 492  
 493  
 494  /**

 495   * Prepare html message

 496   *

 497   * @param string Message

 498   * @return string Content

 499   */
 500  function dre_prepare_html_message( $message )
 501  {
 502      dre_msg('Message body (original): <pre style="font-size:10px">'.htmlspecialchars($message).'</pre>');
 503  
 504      $marker = 0;
 505      if( preg_match( '~<body[^>]*>(.*?)</body>~is', $message, $result ) )
 506      {    // First see if we can get contents of <body> tag
 507          $content = $result[1];
 508          $marker = 1;
 509      }
 510      elseif( preg_match( '~<html[^>]*>(.*?)</html>~is', $message, $result ) )
 511      {    // <body> was not found, use <html> contents and delete <head> section from it
 512          $content = preg_replace( '~<head[^>]*>(.*?)</head>~is', '', $result[1] );
 513          $marker = 1;
 514      }
 515  
 516      if( empty($marker) )
 517      {    // None of the above methods worked, just use the original message body
 518          $content = $message;
 519      }
 520  
 521      // First fix different line-endings (dos, mac, unix), remove double newlines

 522      $content = str_replace( array("\r", "\n\n"), "\n", trim($content) );
 523  
 524      // Decode 'category', 'title' and 'auth' tags

 525      $content = preg_replace( '~&lt;(/)?(category|title|auth)&gt;~i', '<\\1\\2>', $content );
 526  
 527      // Balance tags

 528      $content = balance_tags($content);
 529  
 530      // Remove markup that cause validator errors

 531      $patterns = array(
 532          '~ moz-do-not-send="true"~',            // Thunderbird inline image with absolute "src"
 533          '~ class="moz-signature" cols="\d+"~',    // Thunderbird signature in HTML message
 534          '~ goomoji="[^"]+"~',                    // Gmail smilies
 535      );
 536      $content = preg_replace( $patterns, '', $content );
 537  
 538      dre_msg('Message body (processed): <pre style="font-size:10px">'.htmlspecialchars($content).'</pre>');
 539  
 540      return $content;
 541  }
 542  
 543  
 544  /**

 545   * Get Headers from Decoded MIME Data

 546   *

 547   * @param array Decoded MIME Data

 548   * @return string Headers

 549   */
 550  function dre_get_headers( $decodedMIME )
 551  {
 552      $headers = array();
 553      foreach( $decodedMIME[0]['Headers'] as $field => $value )
 554      {
 555          if( is_array( $value ) )
 556          {
 557              $value = implode( "\r\n", $value );
 558          }
 559          $headers[] = ucfirst( $field ).' '.$value;
 560      }
 561  
 562      return implode( "\r\n", $headers );
 563  }
 564  
 565  
 566  /**

 567   * Get content after email and before terminator line

 568   *

 569   * @param mixed $message

 570   * @param mixed $emails

 571   * @return string Content

 572   */
 573  function dre_get_processing_content( $content, $emails )
 574  {
 575      $error_text = '';
 576  
 577      $emails = explode( ', ', $emails );
 578      if( count( $emails ) > 0 )
 579      {    // If emails exist
 580          // Get last email

 581          $email = $emails[ count( $emails ) - 1 ];
 582          if( !empty( $email ) )
 583          {    // Get error text after last email address
 584              $error_text = trim( evo_substr( $content, evo_strpos( $content, $email ) + evo_strlen( $email ) ) );
 585          }
 586          if( empty( $error_text ) )
 587          {    // If error text is empty we should get all content before email OR full content if no email address in content
 588              $error_text = empty( $email ) ? $content : trim( evo_substr( $content, 0, evo_strpos( $content, $email ) ) );
 589          }
 590      }
 591      else
 592      {    // If no emails - get full content as error text
 593          $error_text = $content;
 594      }
 595  
 596      if( !empty( $error_text ) )
 597      {    // Replace all new line sumbols with space symbol
 598          $error_text = str_replace( array( "\r\n\r\n", "\r\n", "\n\n", "\n" ), " ", $error_text );
 599      }
 600  
 601      return $error_text;
 602  }
 603  
 604  /**

 605   * Get Error from Message

 606   *

 607   * @param string Message

 608   * @return string Error text

 609   */
 610  function dre_get_error_message( $message )
 611  {
 612      $error_text = '';
 613  
 614      if( preg_match( '#[\s;]{1}(5[0-9][0-9][\s\d\.\-]+([^\n]+))#i', $message, $errors ) )
 615      {    // Get first found error
 616          $error_text = trim( $errors[1] );
 617      }
 618      else
 619      {    // If no errors - use full content(between email and body terminator)
 620          $error_text = $message;
 621      }
 622  
 623      // Return error text limited by DB field length

 624      return evo_substr( $error_text, 0, 255 );
 625  }
 626  
 627  
 628  /**

 629   * Get Error from Message by defined patterns ($Settings->get( 'repath_errtype' ))

 630   *

 631   * @param string Content

 632   * @return array ( 'Error Type', 'Error Mask' )

 633   */
 634  function dre_get_error_by_pattern( $content )
 635  {
 636      global $Settings;
 637  
 638      $error_types = trim( $Settings->get( 'repath_errtype' ) );
 639  
 640      if( empty( $error_types ) )
 641      {    // Error types are not defined
 642          return false;
 643      }
 644  
 645      $error_types = explode( "\n", str_replace( array( "\r", "\n\n" ), "\n", $error_types ) );
 646  
 647      foreach( $error_types as $error_type )
 648      {
 649          list( $error_type, $error_mask ) = explode( ' ', $error_type, 2 );
 650          if( preg_match( '#'.$error_mask.'#i', $content ) )
 651          {
 652              return array( $error_type, $error_mask );
 653          }
 654      }
 655  
 656      // Not found error

 657      return false;
 658  }
 659  
 660  
 661  /**

 662   * Get Error info

 663   *

 664   * @param string Content

 665   * @return array Error info:

 666   *              'text' => Error text

 667   *              'type' => Error type code

 668   */
 669  function dre_get_error_info( $content )
 670  {
 671      $error_info = array();
 672  
 673      // Get error by patterns from the Setting 'repath_errtype'

 674      $error_pattern = dre_get_error_by_pattern( $content );
 675  
 676      // Get full error message from content

 677      $error_full_text = dre_get_error_message( $content );
 678  
 679      if( !empty( $error_pattern ) )
 680      {
 681          if( preg_match( '#'.$error_pattern[1].'#i', $error_full_text ) )
 682          {    // If error pattern is contained in the full error text
 683              $error_info['text'] = $error_full_text;
 684              $error_info['type'] = $error_pattern[0];
 685          }
 686      }
 687  
 688      if( empty( $error_info ) )
 689      {    // Set error info from full error text If error info is not defined by some reason yet
 690          $error_info['text'] = $error_full_text;
 691          $error_info['type'] = dre_get_error_type( $error_full_text );
 692      }
 693  
 694      return $error_info;
 695  }
 696  
 697  
 698  /**

 699   * Get Error type

 700   *

 701   * @param string Error

 702   * @return string Error type

 703   */
 704  function dre_get_error_type( $error )
 705  {
 706      global $Settings;
 707  
 708      $error_types = trim( $Settings->get( 'repath_errtype' ) );
 709  
 710      if( empty( $error_types ) )
 711      {    // Error types are not defined
 712          return 'U';
 713      }
 714  
 715      $error_types = explode( "\n", str_replace( array( "\r", "\n\n" ), "\n", $error_types ) );
 716  
 717      foreach( $error_types as $error_type )
 718      {
 719          list( $error_type, $error_mask ) = explode( ' ', $error_type, 2 );
 720          if( preg_match( '#'.$error_mask.'#i', $error ) )
 721          {
 722              return $error_type;
 723          }
 724      }
 725  
 726      // Not found error type

 727      return 'U';
 728  }
 729  
 730  
 731  /**

 732   * Decode error type to error title

 733   *

 734   * @param string Error type

 735   * @return string Error title

 736   */
 737  function dre_decode_error_type( $error_type )
 738  {
 739      $titles = array(
 740          ''  => T_('Unknown error'),
 741          'S' => T_('Spam suspicion'),
 742          'P' => T_('Permament error'),
 743          'T' => T_('Temporary error'),
 744          'C' => T_('Configuration error')
 745      );
 746  
 747      if( isset( $titles[ $error_type ] ) )
 748      {
 749          return $titles[ $error_type ];
 750      }
 751      else
 752      {    // Unknown error
 753          return $titles[ '' ];
 754      }
 755  }
 756  
 757  
 758  /**

 759   * Remove content after body terminators

 760   *

 761   * @param string Source content

 762   * @retrun string Limited content

 763   */
 764  function dre_limit_by_terminators( $content )
 765  {
 766      global $Settings;
 767  
 768      $repath_terminators = $Settings->get('repath_body_terminator');
 769      if( !empty( $repath_terminators ) )
 770      {
 771          $repath_terminators = explode( "\n", str_replace( array( "\r", "\n\n" ), "\n", $repath_terminators ) );
 772          foreach( $repath_terminators as $repath_terminator )
 773          {    // Limit by each terminator
 774              $repath_terminator = trim( $repath_terminator );
 775              if( empty( $repath_terminator ) )
 776              {    // Skip empty string
 777                  continue;
 778              }
 779              if( !empty( $repath_terminator ) && ($os_terminator = evo_strpos( $content, $repath_terminator )) !== false )
 780              {    // Remove text after terminator string
 781                  $content = evo_substr( $content, 0, $os_terminator );
 782              }
 783          }
 784      }
 785  
 786      return $content;
 787  }
 788  
 789  
 790  /**

 791   * Insert a returned email's data into DB

 792   *

 793   * @param string Prepared message text (without text after body terminator)

 794   * @param string Full message text

 795   * @param string Headers

 796   * @return array|boolean Data of returned email| False

 797   */
 798  function dre_insert_returned_email( $content, $message_text, $headers )
 799  {
 800      global $DB, $dre_emails;
 801  
 802      // Extract emails from content

 803      $emails = dre_get_emails( $content );
 804  
 805      // Get content between email and body terminator

 806      $content = dre_get_processing_content( $content, $emails );
 807  
 808      // Get Error info

 809      $error_info = dre_get_error_info( $content );
 810  
 811      $email_returned = array(
 812              'address'  => $emails,
 813              'errormsg' => $error_info['text'],
 814              'message'  => $message_text,
 815              'headers'  => $headers,
 816              'errtype'  => $error_info['type']
 817          );
 818  
 819      // INSERT RETURNED DATA INTO DB

 820      $DB->query( 'INSERT INTO T_email__returns ( emret_address, emret_errormsg, emret_message, emret_headers, emret_errtype )
 821          VALUES ( '.$DB->quote( $email_returned ).' )' );
 822  
 823      if( $DB->insert_id > 0 )
 824      {
 825          // Save a blocked email's data

 826          dre_save_blocked_email( $email_returned );
 827  
 828          // Save saved emails for reports

 829          $dre_emails[] = $email_returned;
 830  
 831          return $email_returned;
 832      }
 833      else
 834      {
 835          return false;
 836      }
 837  }
 838  
 839  /**

 840   * Insert/Update a blocked email's data into DB

 841   *

 842   * @param array Data of returned email:

 843   *               'address'

 844   *               'errormsg'

 845   *               'message'

 846   *               'headers'

 847   *               'errtype'

 848   */
 849  function dre_save_blocked_email( $email_returned )
 850  {
 851      global $DB;
 852  
 853      if( empty( $email_returned['address'] ) )
 854      {    // No emails, Exit here
 855          return;
 856      }
 857  
 858      load_class( 'tools/model/_emailblocked.class.php', 'EmailBlocked' );
 859  
 860      $EmailBlockedCache = & get_EmailBlockedCache();
 861      // Get an existing email address to update if it exist

 862      $EmailBlocked = & $EmailBlockedCache->get_by_name( $email_returned['address'], false );
 863      if( !$EmailBlocked )
 864      {    // Insert new email address
 865          $EmailBlocked = new EmailBlocked();
 866          $EmailBlocked->set( 'address', $email_returned['address'] );
 867      }
 868  
 869      switch( $email_returned['errtype'] )
 870      {    // Error type of the returned email:
 871          case 'P':    // Permanent error
 872              $EmailBlocked->increase_counter( 'prmerror' );
 873              // Update only the adresses with NOT spammer statuses

 874              $EmailBlocked->set_status( 'prmerror' );
 875              break;
 876  
 877          case 'T':    // Temporary error
 878              if( in_array( $EmailBlocked->get( 'status' ), array( 'suspicious1', 'suspicious2', 'suspicious3' ) ) )
 879              {    // If current status alredy is defined as 'suspicious1', 'suspicious2' or 'suspicious3'
 880                  if( $EmailBlocked->get( 'sent_last_returnerror' ) <= 1 )
 881                  {
 882                      if( $EmailBlocked->get( 'status' ) == 'suspicious1' )
 883                      {    // Increase status from suspicious1 to suspicious2
 884                          $EmailBlocked->set( 'status', 'suspicious2' );
 885                      }
 886                      elseif( $EmailBlocked->get( 'status' ) == 'suspicious2' )
 887                      {    // Increase status from suspicious2 to suspicious3
 888                          $EmailBlocked->set( 'status', 'suspicious3' );
 889                      }
 890                  }
 891              }
 892              else
 893              {    // Update only the email addresses with level status less then Suspicious 1
 894                  $EmailBlocked->set_status( 'suspicious1' );
 895              }
 896              $EmailBlocked->increase_counter( 'tmperror' );
 897              break;
 898  
 899          case 'S':    // Spam suspicion
 900              $EmailBlocked->increase_counter( 'spamerror' );
 901              // Update only the email addresses with 'unknown' status

 902              $EmailBlocked->set_status( 'warning' );
 903              break;
 904  
 905          default:    // Other errors
 906              $EmailBlocked->increase_counter( 'othererror' );
 907              // Update only the email addresses with 'unknown' status

 908              $EmailBlocked->set_status( 'warning' );
 909              break;
 910      }
 911  
 912      // Insert/Update an email address

 913      $EmailBlocked->dbsave();
 914  }
 915  
 916  ?>

title

Description

title

Description

title

Description

title

title

Body