svn.filsa.org wordpress_dev

Rev

Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
/*
*/


/** Make sure that the WordPress bootstrap has run before continuing. */
require(dirname(__FILE__) . '/../../../wp-load.php');
include_once( ABSPATH . 'wp-admin/includes/admin.php' );

/** Get the POP3 class with which to access the mailbox. */
require_once( ABSPATH . WPINC . '/class-pop3.php' );
/** Include mimeparser lib from Manuel Lemos. */
require_once('lib/rfc822_addresses.php');
require_once('lib/mime_parser.php');


class mail2wp {

        var $run_id; // unique path
        var $image_id = 1;
        var $upload_dir;
        var $blog_gmt_offset;
        var $options;
       
        var $set_meta_image = false;
        var $meta_image = '';
       
        /**
        * Process one mail message, and execute the post-by-mail.
        * - handle attachments correctly.
        - parse with mime_parser.
        - get headers.
        - process body (including attachments)
          - move attachments to upload folder
          - concatenate body text and insert <img? tags to attachment files
        - create new post
        - delete message
        @param $msg_text - full text of the rfc822 message
        @param $result - array that will be returned as the result
        @return True if successful, False if not.
        */

        function process_message($msg_text, $result) {
                //$this->log("process_message: start.");
                $this->meta_image = '';

                $parser = new mime_parser_class;
                $parseparams = array ('Data'=>$msg_text);
                //$parseparams['SaveBody'] = 'temp/';
                //$parseparams['SkipBody'] = '1';
                //var_dump($parseparams);
                $result['status'] = 'INCOMPLETE';
                // --------------------- PARSE with mime_parser ----------------------------
                if(!$parser->Decode($parseparams, $decoded)) {
                        $result['error'] =  'MIME message decoding error: '.$mime->error.' at position '.$mime->error_position. 'Aborting this message.' . "\n";
                        $this->log($result['error'], 'ERR');
                return False;
                }
                $msgparse = $decoded[0];

                if(!$parser->Analyze($msgparse, $analyzed)) {
                        $result['error'] =  'MIME message analyzing error: '.$mime->error.' at position '.$mime->error_position. 'Aborting this message.' . "\n";
                        $this->log($result['error'], 'ERR');
                        return False;
                }
                $this->log(' - Parsing data from message titled: ' . $analyzed['Subject']);
                // ------- DO AUTH CHECK -- at this point we have enough info to figure this out
                //var_dump($analyzed);
               
                $authorized = false;
                $auth_emails = split(',', $this->options['auth_approved_senders']);
               
                $this->log('==> Email Auth Check', 'INFO');
                //var_dump($analyzed['From']);
                //var_dump($auth_emails);
                //$this->log('admin settings: auth_approved_senders:' . $this->options['auth_approved_senders']);
               
                foreach($analyzed['From'] as $sender) {
                        $this->log('== Checking Sender: ' . $sender['address']);
                        if ( in_array($sender['address'], $auth_emails)) {
                                $authorized = true;
                        }
                }
                if ( ! $authorized) {
                        $this->log('No valid email found.', 'WARN');
                        return false;
                }
                //---- END AUTHORIZATION ----
               
                //get headers
                // 'post_content','post_title','post_date','post_date_gmt','post_author','post_category', 'post_status'
                $post_author   = $this->_get_post_author($msgparse);
                $post_category = array(get_option('default_email_category'));
                $post_date     = $this->_parse_rfc822date($analyzed['Date']);
                $post_date_gmt = $this->_parse_rfc822date($analyzed['Date'], True);
                //$post_title    = $this->_decode_text($msgparse['Headers']['subject:']); // using decoded
                $post_title = $this->_decode_text($analyzed['Subject']);
                $post_content  = $analyzed['Data'];; // content, unprocessed, for now.
                $post_status   = 'draft';
               
                if (empty($post_author)) {
                        $post_author=1; // dumb but easy assumption that user 1, admin, will always exist.                     
                }
               
                // prep post
                $post_data = compact('post_content','post_title','post_date','post_date_gmt','post_author','post_category', 'post_status');
                //var_dump($post_data);
                $post_data = add_magic_quotes($post_data);
                // send post to WP
                $post_ID = wp_insert_post($post_data);
                if ( is_wp_error( $post_ID ) ) {
                        $this->log(' WP Post failed. '. $post_ID->get_error_message(), 'ERR');
                        return False;
                        }
                // We couldn't post, for whatever reason. Better move forward to the next email.
                if ( empty( $post_ID ) )
                        return False;

                // process mail body into post content
                $post_content = $this->process_analyzed_body($analyzed, $post_ID); // process via analyzed
                $post_content = apply_filters('phone_content', $post_content);// WP filter hook
                $post_content = str_replace('Sent from my iPhone','', $post_content); // clean sigs

                if (function_exists('mb_convert_encoding') &&
                        $analyzed['Encoding'] == 'iso-2022-jp') {
                        $this->log(' ! Detected iso-2022-jp encoding. Making adjustments.');
                        $post_title = mb_convert_encoding($post_title, "UTF-8", "ISO-2022-JP");
                        $post_content = mb_convert_encoding($post_content, "UTF-8", "ISO-2022-JP");
                }
                $user = new WP_User($post_author);
                $post_status = ( $user->has_cap('publish_posts') ) ? 'publish' : 'pending';
               
                // update post content and title
                $update = compact('post_content','post_title', 'post_status');
                $update['ID'] = $post_ID;
                $update_post_id = wp_update_post($update);
               
                // add "image" meta tag to post. to support image templates in the mailcanvas theme.
                if ($this->set_meta_image && !empty($this->meta_image))
                        add_post_meta($post_ID, 'image', $this->meta_image);
               
                if ( 0 == $update_post_id ) {
                        $this->log(' WP Post failed  after content update. Check for a new draft with no content.');
                        return False;
                        }
                       
                do_action('publish_phone', $post_ID); // WP hook
                $this->log(" * Posted title: $post_title, Author id: $post_author, status: $post_status.");
                //var_dump($post_data);
                //echo 'POST_CONTENT:<br/>' . $post_content . '<br />';
                return true;
               
        }
       
        /**
        Returns a string containing the body of a mail message.
        The body is modified based on the attachments or related fileparts that are included with the message.
        @param $mail is an array returned from the $mime_parser_class->Analyze() function.
        */

        function process_analyzed_body($mail, $post_id) {
                $result = '';
                $attach_text = '';
                if ($mail['Type'] == 'text') $result = $this->_decode_text($mail['Data']);

                //handle Type=html and Related
                // Related images are already in the $result text.
                if ($mail['Type'] == 'html') {
                        $this->log (' - HTML message type.');
                        $result = $mail['Data'];
                        if (!empty($mail['Related'])) {
                        $this->log(' - Processing related items.');                                    
                                foreach ($mail['Related'] as $attachment) {
                                        if (! 'image' == $attachment['Type']) continue; //skip non-images for now
                                        $fname = $this->_get_safe_filename($attachment['FileName'], $attachment['SubType']);
                                        if ($this->_save_file($fname, $attachment['Data'])) {
                                                $mimetype = $attachment['Type'] . '/' . $attachment['SubType'];
                                                $attachname = $this->_insert_attachment($fname, $post_id, $mimetype, false);

                                                $urlpath = $this->upload_dir['url'] . '/' . $attachname['file'];
                                                $cid = 'cid:' . $attachment['ContentID'];
                                                $result = str_replace($cid, $urlpath, $result);
                                        }
                                }
                        }
                }
               
                // handle attachments
                if (!empty($mail['Attachments'])) {
                        $this->log(' - Processing attachments.');
                        $attach_text .= "\n<div class='attachments'>\n";
                        foreach ($mail['Attachments'] as $attachment) {
                                if ( 'image' != $attachment['Type']) continue; //skip non-images for now
                                $fname = $this->_get_safe_filename($attachment['FileName'], $attachment['SubType']);
                                if ($this->_save_file($fname, $attachment['Data'])) {
                                        $mimetype = $attachment['Type'] . '/' . $attachment['SubType'];        
                                        $attachname = $this->_insert_attachment($fname, $post_id, $mimetype);
                                        $urlpath = $this->upload_dir['url'] . '/' . $attachname['file'];
                                       
                                        if (!$this->set_meta_image)
                                                $attach_text .= '<img src="' . $urlpath .'" class="photomail attachments"/>'. "\n";
                                }
                        }
                        $attach_text .= "\n</div>\n";
               
                $result = $attach_text . $result;
                }
                return $result;
        }
       
        /*******
         * registers image as an attachment, so it shows in media browser and is associated with the post
         * creates thumbnails and other images sizes
         *  @param $filename - name of the file (from $this->_get_safe_filename() )
         *  @param $parent_post_id - the post id of the mail message
         *  @param $resize - resize the image to no larger than the configured size. defaults to true.
         *  @returns An array with keys "file, height,width"
        */

        function _insert_attachment($fname, $parent_post_id, $mimetype, $resize=true ) {
                $result = array('file'=>$fname);
                $fpath = $this->upload_dir['path'] . '/'. $fname;
                $att_params = array();
                $att_params['post_title'] = $fname;
                $att_params['post_status'] = 'inherit';
                $att_params['post_content'] = '';
                $att_params['post_mime_type'] = $mimetype;
                $att_params['guid'] = $this->upload_dir['url'] . '/'. $fname;
               
               
                $this->log(' - _insert_attachment: ' . $fname .',path:'.$fpath.', postid:'. $parent_post_id);
                $attach_id = wp_insert_attachment( $att_params, $fpath, $parent_post_id );
                $this->log(' - got attachment_id=' . $attach_id);
                $attach_data = wp_generate_attachment_metadata( $attach_id, $fpath );
               
                //var_dump($attach_data);
                wp_update_attachment_metadata( $attach_id,  $attach_data );
                $result['height'] = $attach_data['height'];
                $result['width'] = $attach_data['width'];
               
                // return a resized image filename if the attachment image is larger than a $good_size image.
                // @@TODO - make this a config option.
                $good_size = 'medium';
                $this->log(' - _insert_attachment: h=' . $attach_data['height'] .', w='.$attach_data['width'] );

                if ($resize) {
                        if ( ($attach_data['width']  > get_option("{$good_size}_size_w")) ||
                                 ($attach_data['height'] > get_option("{$good_size}_size_h"))  ) {
                                 if (isset($attach_data['sizes'][$good_size])) {
                                        $this->log(' - _insert_attachment inside resize: good-size=' . $good_size);
                                        //var_dump($attach_data['sizes'][$good_size]);
                                        $result = $attach_data['sizes'][$good_size];
                                }
                        }
                }
                $this->log(' - _insert_attachment is done, returning:' . $result['file']);

                if ($this->set_meta_image) $this->meta_image = $this->upload_dir['url'] . '/' .$result['file'];

                return $result;
       
        }
        /**
        Returns a string, that represents a safe filename.
        - safe filename is not encoded in a weird way
        - safe filename is unique and is not a
        */

        function _get_safe_filename($f, $subtype){
                $fext = array('jpeg'=>'.jpg', 'gif'=>'.gif', 'png'=>'.png');
                // fix encoded filenames - just generate a safe name.
                if ($f != $this->_decode_text($f)) {   
                        $f = 'pic_'.$this->run_id . '-' . $this->image_id++ . $fext[$subtype];
                        $f = $this->_decode_text($f);
                }
                $f = str_replace(' ', '_', $f); // change spaces to underscores.
                $filechar = 65;
                $fpath = $this->upload_dir['path'] . '/' . $f;
                // makes sure file doesnt already exist.
                while (file_exists($fpath)) {
                        $fparts = explode('.', $f);
                        $f = $fparts[0];
                        if (substr($f, -2, 1) == '-') {
                                $f = substr($f, 0, strlen($f)-2);
                        }
                        $f = $f . '-' . chr($filechar++) . '.' . $fparts[1];
                        $fpath = $this->upload_dir['path'] . '/' . $f; 
                }
               
                return $f;
        }
        /*
       
        */

        function _save_file($fname, $data) {
                $result = true;
                $fpath = $this->upload_dir['path'] . '/' . $fname;
               
                if ($fh = fopen($fpath, 'w')) {
                        fwrite($fh, $data);
                        $this->log(' - File saved: ' . $fpath);
                } else {
                        $this->log("Attachment not written: $fname.", 'ERR' );
                        $result = false;
                }
                fclose($fh);
               
                return $result;
        }
       
        /**
        *Easy logging
        * @@TODO: log to a file, implement log levels that work.
        */

        function log($s, $level='INFO') {
                $t = date('Y-m-d H:i:s');
                echo "$t [$level] $s" . "<br/>\n";
        }
        /**
        * Loop through messages on pop3 server.
        * @param $msg_count - # of message on the server.
        * @param $pop3 - variable that holds reference to an active POP3 instance.
        */

        function process_messages($msg_count, $pop3) {
                $this->startup();
                // loop through messages
                // if message process is True, then delete from pop3.
                for ( $i = 1; $i <= $msg_count; $i++ ) {
                        // get message
                        $this->log("Processing message #$i.");

                        $message = $pop3->get($i);
                        $msg_text = implode ('',  $message); // convert message array to string
                        // process message
                        $msg_status = $this->process_message($msg_text, $msg_result);
                        // delete message if message process was successful.
                        if ($msg_status) {
                                $this->log ("Message #$i OK. Attempting POP3 server delete...");

                                if(!$pop3->delete($i)) {
                                        $this->log( 'Message delete failure: ' . wp_specialchars($pop3->ERROR), 'ERR');
                                        $pop3->reset();
                                        exit;
                                } else {
                                        $this->log ("Message <strong>$i</strong> deleted.");
                                }      
                        } else {
                                $this->log ("process message $i failed: " . $result['error'], "ERR");
                        }
               
                }
                $pop3->quit(); // comment out to prevent deletion of messages.
                $this->shutdown();

        }
        function startup() {           
                $this->run_id = dechex(time());
                $this->upload_dir = wp_upload_dir(date('Y/m'));
                $this->blog_gmt_offset = absint(get_option('gmt_offset')) * 3600;
                $this->options = get_option( 'm2wp_options' );
                var_dump($this->options);
        }
       
        function shutdown() {
        }
       

        /*-- PRIVATE FUNCTIONS --*/
        /**
        Converts a rfc822date to a php and db friendly format.
        From - Thu, 1 Jan 2009 23:33:40 +0900
        To - 2009-01-01 22:33:40
       
        @param dataheader - string that reflects rfc822date
        @param gmt - returns a GMT date. default is false.
        */

        function _parse_rfc822date($dateheader, $gmt=False) {
                $dmonths = array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
               
                $ddate = trim($dateheader);
                if (strpos($ddate, ',')) {
                        $ddate = trim(substr($ddate, strpos($ddate, ',') + 1, strlen($ddate)));
                }
                $date_arr = explode(' ', $ddate);
                $date_time = explode(':', $date_arr[3]);

                $ddate_H = $date_time[0];
                $ddate_i = $date_time[1];
                $ddate_s = $date_time[2];

                $ddate_m = $date_arr[1];
                $ddate_d = $date_arr[0];
                $ddate_Y = $date_arr[2];
                for ( $j = 0; $j < 12; $j++ ) {
                        if ( $ddate_m == $dmonths[$j] ) {
                                $ddate_m = $j+1;
                        }
                }

                $time_zn = intval($date_arr[4]) * 36;
                $ddate_U = gmmktime($ddate_H, $ddate_i, $ddate_s, $ddate_m, $ddate_d, $ddate_Y);
                if ($gmt) {$ddate_U = $ddate_U - $time_zn;}
                return gmdate('Y-m-d H:i:s', $ddate_U); //post_date_gmt
        }
        function _rfc822date($dateheader, $gmt=False) {
                $epoch_secs = strtotime(trim($dateheader));
               
        }
        /**
        Converts subject text to match blog settings using iconv
        */
     
        function _decode_text($text) {
                // Captures any text in the subject before $phone_delim as the subject
                if ( function_exists('iconv_mime_decode') ) {
                        $result = iconv_mime_decode($text, 2, get_option('blog_charset'));
                } else {
                        $result = wp_iso_descrambler($text);
                }
                return $result;
        }
        /**
        * Collects email addresses from mail headers, then attempts to identify a WP author with that email address.
        */

        function _get_post_author($msgparse) {
                //Find $post_author based on from: (and reply-to)headers, set $author_found
                $authors = array();
                $result = NULL;
                $addr_fields = array('from:','reply-to:','return-path:');

                foreach ($addr_fields as $field){ // collect emails
                        if (! empty($msgparse['ExtractedAddresses'][$field])) {
                        foreach ($msgparse['ExtractedAddresses'][$field] as $email) {
                                $authors[] = $email['address'];
                                }
                        }
                }
                foreach ($authors as $author) { // find authors based on email
                        if ( is_email($author) ) {
                                $userdata = get_user_by_email($author);
                                if ( ! empty($userdata) ) {
                                        $result = $userdata->ID;
                                        break;
                                }
                        }
                }
                return $result;
        }
}


function do_photomail() {
        // fetch mail via POP3
        $mail_server = new POP3();
        $photomail = new mail2wp();

        $is_active = get_option('m2wp_enabled');
        if (false /*! $is_active*/) { // this doesnt seem to be working.
                $photomail->log("Deactivated. Activate the mail2wordpress plugin to start processing emails.");
                return true;
        }
        ;
       
        if ( ! $mail_server->connect(get_option('mailserver_url'), get_option('mailserver_port') ) ||
                ! $mail_server->user(get_option('mailserver_login')) ||
                ( ! $msg_count = $mail_server->pass(get_option('mailserver_pass')) ) ) {
                        $mail_server->quit();
                        wp_die( ( 0 === $msg_count ) ? __("There doesn't seem to be any new mail.") : wp_specialchars($mail_server->ERROR) );
        }
        // loop through mail.
       
        $photomail->log("Connected to POP3 server: There are $msg_count message(s).");
        $photomail->process_messages($msg_count, $mail_server);
}

do_photomail();



?>