/**
  * Validate and sanitize our options before saving to the DB.
  *
  * Callback from {@link register_setting()}.
  *
  * @param array $input The submitted values from the form
  * @return array $output The validated values to be inserted into the DB
  */
 public function validate($input)
 {
     $messages = false;
     $output = array();
     $output['mode'] = wp_filter_nohtml_kses($input['mode']);
     // switching from IMAP to inbound email mode
     if ('inbound' == $output['mode'] && 'imap' == bp_rbe_get_setting('mode')) {
         // stop RBE if still connected via IMAP
         if (bp_rbe_is_connected()) {
             bp_rbe_stop_imap();
         }
         bp_rbe_log('- Operating mode switched to inbound -');
     }
     // check if key is alphanumeric
     if (ctype_alnum($input['key'])) {
         $output['key'] = $input['key'];
     }
     /** INBOUND-related ***************************************************/
     $inbound_provider = wp_filter_nohtml_kses($input['inbound-provider']);
     if (!empty($inbound_provider)) {
         $output['inbound-provider'] = $inbound_provider;
     }
     $inbound_domain = isset($input['inbound-domain']) ? wp_filter_nohtml_kses($input['inbound-domain']) : '';
     if (!empty($inbound_domain)) {
         $output['inbound-domain'] = $inbound_domain;
     }
     /** IMAP-related ******************************************************/
     $username = wp_filter_nohtml_kses($input['username']);
     $password = wp_filter_nohtml_kses($input['password']);
     if ($email = is_email($input['email'])) {
         $output['email'] = $email;
         if ($input['gmail'] == 1) {
             $output['username'] = $email;
         }
     }
     if (!empty($username)) {
         $output['username'] = $username;
         if (is_email($username)) {
             $output['email'] = $username;
         }
     }
     if (!empty($password)) {
         $output['password'] = $password;
     }
     // check if port is numeric
     if (is_numeric($input['port'])) {
         $output['port'] = $input['port'];
     }
     // check if address tag is one character
     if (strlen($input['tag']) == 1) {
         $output['tag'] = $input['tag'];
     }
     // override certain settings if "gmail" setting is true
     if (!empty($input['gmail']) && $input['gmail'] == 1) {
         $output['servername'] = 'imap.gmail.com';
         $output['port'] = 993;
         $output['tag'] = '+';
         $output['gmail'] = 1;
         $output['email'] = $username;
         // use alternate server settings as defined by the user
     } else {
         $output['servername'] = wp_filter_nohtml_kses($input['servername']);
         $output['port'] = absint($input['port']);
         $output['tag'] = wp_filter_nohtml_kses($input['tag']);
         $output['gmail'] = 0;
     }
     if (is_numeric($input['keepalive']) && $input['keepalive'] < 30) {
         $output['keepalive'] = $input['keepalive'];
     }
     // keepalive for safe mode will never exceed the execution time
     if (ini_get('safe_mode')) {
         $output['keepalive'] = $input['keepalive'] = bp_rbe_get_execution_time('minutes');
     }
     // automatically reconnect after keep-alive limit
     if (!empty($input['keepaliveauto'])) {
         $output['keepaliveauto'] = 1;
     } else {
         $output['keepaliveauto'] = 0;
     }
     // do a quick imap check if we have valid credentials to check
     if ($output['mode'] == 'imap' && !empty($output['servername']) && !empty($output['port']) && !empty($output['username']) && !empty($output['password'])) {
         if (function_exists('imap_open')) {
             $imap = BP_Reply_By_Email_Connect::init(array('host' => $output['servername'], 'port' => $output['port'], 'username' => $output['username'], 'password' => $output['password']));
             // if connection failed, add an error
             if ($imap === false) {
                 $errors = imap_errors();
                 $messages['connect_error'] = sprintf(__('Error: Unable to connect to inbox - %s', 'bp-rbe'), $errors[0]);
                 $output['connect'] = 0;
                 // connection was successful, now close our temporary connection
             } else {
                 // this tells bp_rbe_is_required_completed() that we're good to go!
                 $output['connect'] = 1;
                 imap_close($imap);
             }
         }
     }
     // encode the password
     if (!empty($password)) {
         $output['password'] = bp_rbe_encode(array('string' => $password, 'key' => wp_salt()));
     }
     /**********************************************************************/
     /* error time! */
     if (strlen($input['tag']) > 1 && !$output['tag']) {
         $messages['tag_error'] = __('Error: <strong>Address tag</strong> must only be one character.', 'bp-rbe');
     }
     if (!empty($input['port']) && !is_numeric($input['port']) && !$output['port']) {
         $messages['port_error'] = __('Error: <strong>Port</strong> must be numeric.', 'bp-rbe');
     }
     if (!empty($input['key']) && !$output['key']) {
         $messages['key_error'] = __('Error: <strong>Key</strong> must only contain letters and / or numbers.', 'bp-rbe');
     }
     if (!empty($input['keepalive']) && !is_numeric($input['keepalive']) && !$output['keepalive']) {
         $messages['keepalive_error'] = __('Error: <strong>Keep Alive Connection</strong> value must be less than 30.', 'bp-rbe');
     }
     if (is_array($messages)) {
         $output['messages'] = $messages;
     }
     // For sites using an external object cache, make sure they get the new value.
     // This is all sorts of ugly! :(
     // I think this is a WP core bug with the WP Settings API...
     wp_cache_delete('alloptions', 'options');
     return $output;
 }
/**
 * Should we enable SSL for the IMAP connection??
 *
 * Check to see if both the OpenSSL and IMAP modules are loaded.  Next, see if
 * the port is explictly 993.
 *
 * @since 1.0-beta
 *
 * @param int $port The port number for the IMAP server
 * @return bool
 */
function bp_rbe_is_imap_ssl($port = 0)
{
    if (empty($port)) {
        $port = bp_rbe_get_setting('port');
    }
    return BP_Reply_By_Email_Connect::is_ssl((int) $port);
}
 /**
  * Constructor.
  *
  * @param array $args {
  *     An array of arguments.
  *
  *     @type string $host The server name. (eg. imap.gmail.com)
  *     @type int $port The port number used by the server name.
  *     @type string $username The username used to login to the server.
  *     @type string $password The password used to login to the server.
  *     @type bool $validatecert Whether to validate certificates from TLS/
  *                              SSL server. Defaults to true.
  *     @type string $mailbox The mailbox to open. Defaults to 'INBOX'.
  *     @type int $retries How many times to try reconnection on failure.
  *                        Defaults to 1.
  *     @type bool $reconnect Are we attempting a reconnection? Defaults to false.
  * }
  * @param resource $connection The IMAP resource if attempting a reconnection.
  * @return resource|bool The IMAP resource on success. Boolean false on failure.
  */
 public function __construct($args = array(), $connection = false)
 {
     $this->args = wp_parse_args($args, array('host' => bp_rbe_get_setting('servername'), 'port' => bp_rbe_get_setting('port'), 'username' => bp_rbe_get_setting('username'), 'password' => bp_rbe_get_setting('password') ? bp_rbe_decode(array('string' => bp_rbe_get_setting('password'), 'key' => wp_salt())) : false, 'validatecert' => true, 'mailbox' => 'INBOX', 'retries' => 1, 'reconnect' => false));
     $this->connection = $connection;
 }
 /**
  * Returns the querystring from an email address.
  *
  * In IMAP mode:
  *   test+THEQUERYSTRING@gmail.com> -> THEQUERYSTRING
  *
  * In Inbound mode:
  *   THEQUERYSTRING@reply.mydomain.com -> THEQUERYSTRING
  *
  * The querystring is encoded by default.
  *
  * @param string $address The email address containing the address tag
  * @return mixed Either the address tag on success or false on failure
  */
 public static function get_querystring($address = '')
 {
     if (empty($address)) {
         return false;
     }
     $at = strpos($address, '@');
     if ($at === false) {
         return false;
     }
     // inbound mode uses subdomain addressing
     if (bp_rbe_is_inbound()) {
         $qs = substr($address, 0, $at);
         // imap mode uses address tags
     } else {
         $tag = strpos($address, bp_rbe_get_setting('tag'));
         if ($tag === false) {
             $qs = false;
         } else {
             $qs = substr($address, ++$tag, $at - $tag);
         }
     }
     /**
      * Filter the querystring from an email address.
      *
      * @since 1.0-RC4
      *
      * @param string|false $qs      Current querystring.
      * @param string       $address Full 'to' email address.
      */
     return apply_filters('bp_rbe_get_querystring', $qs, $address);
 }
 /**
  * The main method we use to parse an IMAP inbox.
  */
 public function run()
 {
     // $instance must be initialized before we go on!
     if (self::$instance === false) {
         return false;
     }
     // If safe mode isn't on, then let's set the execution time to unlimited
     if (!ini_get('safe_mode')) {
         set_time_limit(0);
     }
     // Try to connect
     $connect = $this->connect();
     if (!$connect) {
         return false;
     }
     // Total duration we should keep the IMAP stream alive for in seconds
     $duration = bp_rbe_get_execution_time();
     bp_rbe_log('--- Keep alive for ' . $duration / 60 . ' minutes ---');
     bp_rbe_remove_imap_lock();
     // Mark the current timestamp, mark the future time when we should close the IMAP connection;
     // Do our parsing until $future > $now; re-mark the timestamp at end of loop... rinse and repeat!
     for ($now = time(), $future = time() + $duration; $future > $now; $now = time()) {
         // Get number of messages
         $message_count = imap_num_msg($this->connection);
         // If there are messages in the inbox, let's start parsing!
         if ($message_count != 0) {
             // According to this:
             // http://www.php.net/manual/pl/function.imap-headerinfo.php#95012
             // This speeds up rendering the email headers... could be wrong
             imap_headers($this->connection);
             bp_rbe_log('- Checking inbox -');
             // Loop through each email message
             for ($i = 1; $i <= $message_count; ++$i) {
                 // flush object cache if necessary
                 //
                 // we only flush the cache if the default object cache is in use
                 // why? b/c the default object cache is only meant for single page loads and
                 // since RBE runs in the background, we need to flush the object cache so WP
                 // will do a direct DB query for the next data fetch
                 if (!wp_using_ext_object_cache()) {
                     wp_cache_flush();
                 }
                 self::$html = false;
                 $content = self::body_parser($this->connection, $i);
                 $headers = $this->get_mail_headers($this->connection, $i);
                 $data = array('headers' => $headers, 'to_email' => BP_Reply_By_Email_Parser::get_header($headers, 'To'), 'from_email' => BP_Reply_By_Email_Parser::get_header($headers, 'From'), 'content' => $content, 'is_html' => self::$html, 'subject' => imap_utf8(BP_Reply_By_Email_Parser::get_header($headers, 'Subject')));
                 $parser = BP_Reply_By_Email_Parser::init($data, $i);
                 if (is_wp_error($parser)) {
                     //do_action( 'bp_rbe_imap_no_match', $this->connection, $i, $headers, $parser->get_error_code() );
                     do_action('bp_rbe_no_match', $parser, $data, $i, $this->connection);
                 }
                 // do something during the loop
                 // we mark the message for deletion here via this hook
                 do_action('bp_rbe_imap_loop', $this->connection, $i);
                 // unset some variables at the end of the loop
                 unset($content, $headers, $data, $parser);
             }
             // do something after the loop
             do_action('bp_rbe_imap_after_loop', $this->connection);
         }
         // stop the loop if necessary
         if (bp_rbe_should_stop()) {
             if ($this->close()) {
                 bp_rbe_log('--- Manual termination of connection confirmed! Kaching! ---');
             } else {
                 bp_rbe_log('--- Error - invalid connection during manual termination ---');
             }
             remove_action('shutdown', 'bp_rbe_spawn_inbox_check');
             exit;
         }
         // Give IMAP server a break
         sleep(10);
         // If the IMAP connection is down, reconnect
         if (!imap_ping($this->connection)) {
             bp_rbe_log('-- IMAP connection is down, attempting to reconnect... --');
             if (bp_rbe_is_connecting(array('clearcache' => true))) {
                 bp_rbe_log('--- RBE is already attempting to connect - stopping connection attempt ---');
                 continue;
             }
             // add lock marker before connecting
             bp_rbe_add_imap_lock();
             // attempt to reconnect
             $reopen = BP_Reply_By_Email_Connect::init(array('reconnect' => true), $this->connection);
             if ($reopen) {
                 bp_rbe_log('-- Reconnection successful! --');
             } else {
                 bp_rbe_log('-- Reconnection failed! :( --');
                 bp_rbe_log('Cannot connect: ' . imap_last_error());
                 // cleanup RBE after failure
                 bp_rbe_cleanup();
                 remove_action('shutdown', 'bp_rbe_spawn_inbox_check');
                 exit;
             }
         }
         // Unset some variables to clear some memory
         unset($message_count);
     }
     if ($this->close()) {
         bp_rbe_log('--- Closing current connection automatically ---');
     } else {
         bp_rbe_log('--- Invalid connection during close time ---');
     }
     // autoconnect is off
     if (1 !== (int) bp_rbe_get_setting('keepaliveauto', array('refetch' => true))) {
         remove_action('shutdown', 'bp_rbe_spawn_inbox_check');
         // sleep a bit before autoconnecting again
     } else {
         sleep(5);
     }
     exit;
 }
 /**
  * Load inbound provider.
  *
  * @since 1.0-RC3
  */
 public function load_inbound_provider()
 {
     $selected = bp_rbe_get_setting('inbound-provider');
     $providers = self::get_inbound_providers();
     if (isset($providers[$selected]) && class_exists($providers[$selected])) {
         $this->inbound_provider = new $providers[$selected]();
         // Default to SendGrid if no provider is valid.
     } else {
         $this->inbound_provider = new $providers['sendgrid']();
     }
 }