#!/usr/bin/php -q
<?php


/**
* wp-mail.php
*
* Copyright (c) 2003-2005 The Wordpress Team
* Copyright (c) 2004-2005 - John B. Hewitt - jb@stcpl.com.au
* Copyright (c) 2004 - Dan Cech - dcech@lansmash.com
* Copyright (c) 2005 - Dirk Elmendorf - dirk@economysizegeek.com
* Copyright (c) 2005 - David Luden
* Copyright (c) 2005 - Adrian Heydecker - http://wavestyle.ch
* Copyright (c) 2005 - Jay Talbot - webmaster@jaytalbot.com

*
* Licensed under the GNU GPL. For full terms see the file COPYING.
*
* -= README =-

* This is a drop in replacement modification for the Wordpress 1.2 series that enables
* you to send e-mail's with picture and document attachments.
* Current version can be found at http://www.economysizegeek.com/?cat=13
* This script now has some additional features
* You can include images as part of the text by using the image place holder text. by default this is #img1# #img2# etc
* You can also have your email delay it's publication
*    just add the string delay:XdXhXm  where X is a number d = days , h = hours, m = minutes - you can do any combination
*   so delay:1d1m = 1 day 1 minute
*      delay:15m1h = 1 hour 15 minutes
* You can turn on/off comments by adding
* comments:0 off
* comments:1 on
* comments:2 registered-only
* -=Install=-
* Make sure you have downloaded mimedecode.php (should be available where you got this)
* make two directories in your main wordpress directory wp-filez and wp-photos
* make sure these directories are writable by your web server (chmod 777 or chown to the webserver)
*
*
* -= Requests Pending =-
* Fix appledouble
* Make a 3gp thumbnail automatic.o
* Support draft/private posts
* Some places to look
*    Here are some links for thumbnails of 3gp:
*    www.cdavies.org/code/3gp-thumb.php.txt
*    www.cdavies.org/permalink/watchingbrowserembeddedgpvideosinlinux.php
*    but I think it is requiring mplayer or somesuch.
*
*    and one for embedding it into HTML though I do not know the effect of that with RSS outputs:
*    postneo.com/2003/12/19.html
 * www.bigbold.com/snippets/posts/show/212 

* -= History =-
* Version 0.312.13
* Code clean up - The main loop is finally readable by even non programmers
* FEATURE - You can now post to multiple categories at one time by using the [#],[Category Name], [Cat] in the subject
* FEATURE - You can now select a category by just including the begining characters [G] will select General 
* if you don't have any other categories that start with g
* FEATURE - Jay Talbot - added a new feature so you can have multiple email addresses be allowed in
* Make multi category posting more obvious
* BUG FIX: Timezones of GMT+? should now work properly
* BUG FIX: Able to handle mis-mime typed images as long as they are named with .jpg/.gif/.png

* Version 0.312.12
* Code clean up - slowing shrinking the main to make it easiery to fix things
* FEATURE: Be able to turn on/off allowing comments in an email
* BUG FIX: AppleDouble now mostly supported 
* BUG FIX: MIME handling improved.
* BUG FIX: Fix issue with timing delay
* Version 0.312.11
* FEATURE: Patterns to define where a sig starts are user configurable
* FEATURE: Add filter options for banned file names
* BUG FIX: Made it possible to turn off posting to the db for testing purposes
* Version 0.312.10
* FEATURE: Added in code to diplay the mime type of the file being linked to
* BUG FIX: It now tests for the existance of the directories and makes sure
*           that the web server can write to them
* Version 0.312.9
* FEATURE:Should handle jpg as well as jpeg as the file type
* BUG FIX: Now correctly handles the subject in the message
* BUG FIX: Should handle Text preferences correctly 
* Version 0.312.8
* Some general code tidying. 
* FEATURE: Can now have email from invalid email addresses automatically forwared
*          to the admin's email account. This forward includes all attachments. 
*          Props to David Luden for getting this started.
* Minor change: The system will continue if it runs into a message that doesn't have 
*               any content - it will also continue to process if it gets an email from 
*               someone not in the system. In the past this could result in deleted mail
*               if your cron job didn't run often enough.
* Version 0.312.7
* Confirm the handling of 3gp video for cell phones o
* Added in new directive SUPPORTED_FILE_TYPES -if the mime type is listed here then the system will try to make a link to it without making a thumb nail.
* Version 0.312.6
* Bug Fix: Ok the last bug I fixed - actually caused another bug - man I should set up some unit tests. Now it handles mail from the nokia mail client correctly.
* Version 0.312.5
* Bug Fix : The system was accepting all test/* types. Now you can set a preference (defaults to text/plain)
*   to use as the main text for the post.
* Version 0.312.4 
* Added in sanitize_title call suggested by Jemima
* Added in ability to provide a subject in an mms - by using #Subject#
* Fixed an issue with the time stamp system so it now automatically uses the gmt_offset from WordPress
* Fixed issue with the delay:1d1h tag that prevented it from being removed from the body.
* Fixed issue with the delay tag that caused problems if it was the last thing before an image.

* Version 0.312.3-HEY  (2005-05)
* -> Some changes and Bugfixes by Adrian Heydecker
* -> Not (yet) in main development branch.
* Fixed bug: JPEG-thumbnails had a bigger filesize than full images caused by bad hardcoded compression value.
* Fixed bug: If images and signatures were present but no placeholder tags, the images were deleted together with the signature.
* Fixed bug: Generates valid postnames for users of mod_rewrite. Permalinks to posts should now work even when whitespaces are present in the subject line.
* Added support for Quoted Printable encoded mail.
* Added ability to encode Wordpress-posts in charset ISO-8859-1 instead of UTF-8.
* Added ability to choose JPEG-compression value for thumbnails.
* Added ability to add class="" and style="" to images.
* Added ability to use a different mailadress (eg. mobile) without setting up a new Wordpress-account.
*
* Version 0.312.2
* BUGFIX: It now removes the delay tag from the message
* Version 0.312.1
* Added modification for placeholder support for images (David Luden)
* Added in support to automatically scale down big images (Dirk Elmendorf)
* Fixed bug with multiple emails all getting the contents of the first image tag (Dirk Elmendorf)
* Added option to allow HTML in the body and subject of the email (Dirk Elmendorf)
* Switch config options to defines to reduce the number of global variables (Dirk Elmendorf)
* Added tests to make sure there is a trailing slash on the DIR definitions (Dirk Elmendorf)
* Add tests to see if they have gd installed (Dirk Elmendorf)
* Seperate the scaling out to a function for easier usage (Dirk Elmendorf)
* Add delay feature for future posting. (Dirk Elmendorf)
* Added in ability to use strtotime if it is available (Dirk ELmendorf)
*
* Todo
*   Have option to have the email that is rejected forwarded on to another address.
* Fix bug that id still diplays the delay tag in the body 
* Version 0.312 - 2005-03
* - CHANGE FOR DEFAULT E-mail Categories, instead of [General] Subject you can now use General: Subject in the subject line.  Less typing, and there must be a space after the colon. 
* - Fixed bugs with no default posting for categories and user 
* Version 0.311 - 2005-01
* - eep, major bug for pop3 server. Next time I test my code more before I released, fixed so that pop3 now works.`
* Version 0.31 - 2004-12 & 2005-01
* (Has it been this long, best get back into the swing of things... did most of this coding on my holiday as I didn't have a machine to play WoW on :)
* - moved the deletion of pop3 emails into a check so that e-mails aren't deleted without proper checking.
* - added HTML 'decoding' (basic support for Thunderbird & Outlook) 
* - updated the Category search so that it matches words as well as numbers (i.e. [General] Subjectname will work instead of just [1] Subjectname)
* - Changed time function from time to strtotime (as per Senior Pez's suggestion), but found out that strtotime isn't in default php distro so removed...
*
* Vesion 0.3 - 2004-09
* - Added UBB decoding support
* - Added default title (when there is no subject assigned)
* - Started doing a little code cleanup, been reading Advanced PHP Book :)

* Version 0.2 - 2004-08
* - Stopped using pear body decoding in favour of own decoding (may be slower but more modifiable) because of enriched text decoding
* - Added base64_decode checking (may help mobile phone users)
* - Fixed Subject line for non-english users (htmlentities instead of just trim)
* - Fixed error in some pop hanging -> more graceful exit on event on no emails in inbox ($pop3->quit)
* - Added work around for email addresses with exta <> in field (ie: <blade@lansmash.com> instead of blade@lasmash.com
* - Added some ===basic=== enriched text support
* - Updated readme file for easier install
* - Easy modify of globals (such as PHOTOSDIR and FILESDIR)
* - Cleaned up some pear stuff in install

* Version 0.1 - 2004-06
* First release

-= Begin Program =-
**/
    //Load up some usefull libraries
    
define("ROOTDIR",dirname(__FILE__)); //area where wordpress is, i.e. /var/www/wordpress - should work from the command line
    //define("ROOTDIR",$_SERVER["DOCUMENT_ROOT"]); //better if running thru apace
    
require(ROOTDIR '/wp-config.php');
    require_once (
ROOTDIR '/mimedecode.php');
    
/* USER VARIABLES */
    //vars you can change, but dont unless you know what you're doing. :)
    
$AUTHORIZED_ADDRESSES = array();
    
//If you would like to authorize emails for posting in the script just add lines below
    //It supports as many addresses as you want
    // $AUTHORIZED_ADDRESSES[] = "sample@example.com";
    // $AUTHORIZED_ADDRESSES[] = "sample2@example.com";
    // $AUTHORIZED_ADDRESSES[] = "sample3@example.com";

    
    //Usefull for e.g. for MMS if you have an adress like yournumber@yourprivider.com. You can allow posting under this adress, too.
    
define("PHOTOSDIR","/wp-photos/");  //relative directory, must include extra slashes
    
define("FILESDIR","/wp-filez/");  //relative directory, must include extra slashes
    
define("PREFER_TEXT_TYPE","plain"); //This setting controls if it prefers the text/plain or text/html part of the mail
    
define("SUPPORTED_FILE_TYPES","video,application"); //This is a comma seperated list of mime types to allow as attachments
    
define("RESIZE_LARGE_IMAGES",true); // true/false - if on it will automatically make thumbnails if you have gd installed
    //If the image is bigger than this a scaled version will be made
    
define("MAX_IMAGE_WIDTH",400);
    
//Set to true if you want to turn on parsing the subject in the message 
    // as well - Put #Subject# - the first # must be the first character
    
define("ALLOW_SUBJECT_IN_MAIL",true);
    
//if you don't want to add a subject in the email then you assign a default
    
define("DEFAULT_TITLE",'Live from the field');
    
//What protocol are we using? Just leave it default if you don't know
    
define("INPUT_PROTOCOL","pop3"); //pop3/smtp
    //Default Category to use if non-selected
#define("DEFAULT_CATEGORY",get_settings('default_category')); //Set if you want the standard default - use this if you are not using WordPress 1.5
    
define("DEFAULT_POST_CATEGORY",get_settings('default_email_category')); //if you want to use the one set by the email preferences in 1.5
    
define("TIME_OFFSET"get_settings('gmt_offset'));//This should be set in WordPress
    //You may not need this
    //drop Sigature, Everything after -- is deleted in the text msg.
    
define("DROP_SIGNATURE",true);
    
//Controls if rejected mail should be forwarded to the admin
    
define("FORWARD_REJECTED_MAIL",true);
    
//Controls if HTML is allowed in the subject of an email
    
define("ALLOW_HTML_IN_SUBJECT",true);
    
//Controls if HTML is allowed in the body of an email
    
define("ALLOW_HTML_IN_BODY",true);
    
define("IMAGE_PLACEHOLDER",'#img%#'); // % - The percent sign is used to represent the number of the image.
    
define("START_IMAGE_COUNT_AT_ZERO",false); // Where to start placeholders.
    //true means the first image is 0
    //false means the first is 1
    //For example, #img0# or #img1# (Every occurence of a particular placeholder should show that image.)
    
define ("IMAGECLASS",'wp-mailimage');
    
// CSS-Class of inserted Images. You can set .wp-mailimage{border: 1px solid black} for example in your CSS-File.
    
define ("IMAGESTYLE",'border: none;');
    
//If you dont want to change your CSS-File, you can insert values directly. This replaces IMAGESTYLE in <img style="IMAGESTYLE"> with your favorite CSS-value.
    
define ("JPEGQUALITY",80);
    
//Compression Value for resized JPEG-Images
    //Choose Value between 0 (high Compression - ugly) and 100 (almost no Compression - pretty).
    //75 is a good compromise between filesize and look, 85 looks good. Higher values are too much in most cases.
    
define("ISO_8859_1",false);
    
// Is your blog encoded in ISO-8859-1 ?
    
$SIG_PATTERN_LIST = array('--','- --',"\?--");
    
//Only modify this is you need a new starter for the signature line
    
$BANNED_FILES_LIST = array(); 
    
//put values in this array if there are files tacked on by
    //your provider that you would prefer to not have 
    //example
    //Tmobile
    /*
    $BANNED_FILES_LIST = array('dottedLine_350.gif',
                            'dottedLine_600.gif',
                            'masthead.jpg',
                            'spacer.gif');
    */

    //These should only be modified if you are testing
    
define("DELETE_MAIL_AFTER_PROCESSING",true);
    
define("POST_TO_DB",true); //Only turn off if debugging
    
define("TEST_EMAIL",false);
    
define("TEST_EMAIL_ACCOUNT","blog.test");
    
define("TEST_EMAIL_PASSWORD","");


/* END OF USER VARIABLES */
//some variables
error_reporting(2037);
TestWPMailInstallation();

//Retreive emails 
$emails FetchMail();
//loop through messages
foreach ($emails as $email) {
    
$IMAGES = array();
    
//sanity check to see if there is any info in the message
    
if ($email == NULL ) { print 'Dang, message is empty!'; continue; }
    
    
$mimeDecodedEmail DecodeMimeMail($email);

    
//Check poster to see if a valid person
    
$poster ValidatePoster($mimeDecodedEmail);
    if (!empty(
$poster)) {
        
PostEmail($poster,$mimeDecodedEmail);
    }
    else {
        print(
"<p>Ignoring email - not authorized.\n");
    }
// end looping over messages
    
/* END PROGRAM */

/** FUNCTIONS **/
/**
  * This function handles determining the protocol and fetching the mail
  * @return array
  */ 
function FetchMail() {
    
$emails = array();
    switch ( 
strtolower(INPUT_PROTOCOL) ) {
        case 
'smtp'//direct 
            
$fd fopen("php://stdin""r");
            
$input "";
            while (!
feof($fd)) {
                
$input .= fread($fd1024);
            }
            
fclose($fd);
            
$emails[0] = $input;
            break;
        case 
'pop3':
        default: 
            if (
TEST_EMAIL) {
                
$emails TestPOP3MessageFetch();
            }
            else {
                
$emails POP3MessageFetch();
            }
        }
    return(
$emails);
}
/**
  * Determines if it is a writable directory
  */
function IsWritableDirectory($directory) {
    if (!
is_dir($directory)) {
        die (
"Sorry but ".$directory." is not a valid directory.");
    }
    if (!
is_writable($directory)) {
        die(
"The web server cannot write to ".$directory." please correct the permissions");
    }

}
/**
  * This function handles putting the actual entry into the database
  * @param array - categories to be posted to
  * @param array - details of the post
  */
function PostToDB($details) {
    global 
$tablepost2cat;
    global 
$wpdb,$tableposts;

    if (
POST_TO_DB) {
        
//generate sql for insertion    
        
$post_categories $details["post_categories"];
        unset(
$details["post_categories"]);
        
$sql 'INSERT INTO '.$tableposts.' ('implode(',',array_keys($details)) .') VALUES (\''implode('\',\'',array_map('addslashes',$details)) . '\')';

        
$result $wpdb->query($sql);
        
$post_ID $wpdb->insert_id;

        
do_action('publish_post'$post_ID);
        
do_action('publish_phone'$post_ID);
        
pingback($content$post_ID);

        foreach (
$post_categories as $post_category) {
            
$post_category intval($post_category);

            
// Double check it's not there already
            
$exists $wpdb->get_row("SELECT * FROM $tablepost2cat WHERE post_id = $post_ID AND category_id = $post_category");

            if (!
$exists && $result) { 
                
$wpdb->query("
                INSERT INTO $tablepost2cat
                (post_id, category_id)
                VALUES
                ($post_ID, $post_category)
                "
);
            }
        }
    }
}

function 
TestPOP3MessageFetch ( ) {            
    require_once(
ABSPATH.WPINC.'/class-pop3.php');
    
$pop3 = new POP3();
    if (!
$pop3->connect(get_settings('mailserver_url'), get_settings('mailserver_port'))) {
        die(
"Ooops $pop3->ERROR <br />\n");
    }

    
//Check to see if there is any mail, if not die
    
$msg_count $pop3->login(TEST_EMAIL_ACCOUNT,TEST_EMAIL_PASSWORD);
    if (!
$msg_count) {
        
$pop3->quit();
        die(
'There does not seem to be any new mail.');
    }

    
// loop through messages 
    
for ($i=1$i <= $msg_count$i++) {
        
$emails[$i] = implode ('',$pop3->get($i));
        if ( 
DELETE_MAIL_AFTER_PROCESSING) {
            if( !
$pop3->delete($i) ) {
                echo 
'<p>Oops '.$pop3->ERROR.'</p></div>';
                
$pop3->reset();
                exit;
            } else {
                echo 
"Mission complete, message <strong>$i</strong> deleted.";
            }
        }
    }
    
//clean up
    
$pop3->quit();    
    return 
$emails;
}
//retrieve POP3 mail
function POP3MessageFetch ( ) {            
    require_once(
ABSPATH.WPINC.'/class-pop3.php');
    
$pop3 = new POP3();
    if (!
$pop3->connect(get_settings('mailserver_url'), get_settings('mailserver_port'))) {
        die(
"Ooops $pop3->ERROR <br />\n");
    }

    
//Check to see if there is any mail, if not die
    
$msg_count $pop3->login(get_settings('mailserver_login'), get_settings('mailserver_pass'));
    if (!
$msg_count) {
        
$pop3->quit();
        die(
'There does not seem to be any new mail.');
    }

    
// loop through messages 
    
for ($i=1$i <= $msg_count$i++) {
        
$emails[$i] = implode ('',$pop3->get($i));
        if ( 
DELETE_MAIL_AFTER_PROCESSING) {
            if( !
$pop3->delete($i) ) {
                echo 
'<p>Oops '.$pop3->ERROR.'</p></div>';
                
$pop3->reset();
                exit;
            } else {
                echo 
"Mission complete, message <strong>$i</strong> deleted.";
            }
        }
    }
    
//clean up
    
$pop3->quit();    
    return 
$emails;
}
/**
  * This function determines if the mime attachment is on the BANNED_FILE_LIST
  * @param string
  * @return boolean
  */
function BannedFileName($filename) {
    global 
$BANNED_FILES_LIST;
    if (
in_array($filename,$BANNED_FILES_LIST)) {
        print(
"<p>Ignoreing $filename - it is on the \$BANNED_FILES_LIST");
        return(
true);
    }
    return(
false);
}

//tear apart the meta part for useful information
function GetContent ($part,&$IMAGES) {
    
$meta_return NULL;    
    
//fixes
    // Hint by Hey:
    // I think this should not be done if we have plain text and want to keep it in utf-8.
    // Leaving it anyway 'cause I don't use utf-8 and can not test it.
    
HandleUTF8Decode($part);

    
DecodeBase64Part($part);
    if (
BannedFileName($part->ctype_parameters['name'])
            || 
BannedFileName($part->ctype_parameters['name'])) {
        return(
NULL);
    }
    
    if (
$part->ctype_primary == "application"
            
&& $part->ctype_secondary == "octet-stream") {
        if (
$part->disposition == "attachment") {
            
$image_endings = array("jpg","png","gif","jpeg");
            foreach (
$image_endings as $type) {
                if (
eregi(".$type\$",$part->d_parameters["filename"])) {
                    
$part->ctype_primary "image";
                    
$part->ctype_secondary $type;
                    break;
                }
            }
        }
        else {
            
$mimeDecodedEmail DecodeMIMEMail($part->body);
            
FilterTextParts($mimeDecodedEmail);
            foreach(
$mimeDecodedEmail->parts as $section) {
                
$meta_return .= GetContent($section,$IMAGES);
            }
        }
    }
    if (
$part->ctype_primary == "multipart"
            
&& $part->ctype_secondary == "appledouble") {
        
$mimeDecodedEmail DecodeMIMEMail("Content-Type: multipart/mixed; boundary=".$part->ctype_parameters["boundary"]."\n".$part->body);
       
FilterTextParts($mimeDecodedEmail);
       
FilterAppleFile($mimeDecodedEmail);
       foreach(
$mimeDecodedEmail->parts as $section) {
        
$meta_return .= GetContent($section,$IMAGES);
       }
    }
    else { 
        switch ( 
strtolower($part->ctype_primary) ) {
            case 
'multipart':
                
$meta_return '';
                
FilterTextParts($part);
                foreach (
$part->parts as $section) {
                    
$meta_return .= GetContent($section,$IMAGES);
                }
                break;
            case 
'text':
                
HandleQuotedPrintable($part);
                
HandleISO($part);

                
//go through each sub-section
                
if ($part->ctype_secondary=='enriched') {
                    
//convert enriched text to HTML
                    
$meta_return etf2HTML($part->body ) . "\n";
                } elseif (
$part->ctype_secondary=='html') {
                    
//strip excess HTML
                    
$meta_return HTML2HTML($part->body ) . "\n";
                } else {
                    
//regular text, so just strip the pgp signature
                    
if (ALLOW_HTML_IN_BODY) {
                        
$meta_return $part->body  "\n";
                    }
                    else {
                        
$meta_return htmlentities$part->body ) . "\n";
                    }
                    
$meta_return StripPGP($meta_return);
                }
                break;

            case 
'image':
                
$file GenerateImageFileName(REALPHOTOSDIR$part->ctype_secondary);
                
//This makes sure there is no collision
                
$ctr 0;
                while(
file_exists($file) && $ctr 1000) {
                    
$file GenerateImageFileName(REALPHOTOSDIR$part->ctype_secondary);
                    
$ctr++;
                }
                if (
$ctr >= 1000) {
                    die(
"Unable to find a name for images that does not collide\n");
                }
                
$fileName basename($file);
                
$fp fopen($file'w');
                
fwrite($fp$part->body);
                
fclose($fp);
                @
exec ('chmod 755 ' $file);
                
$mimeTag '<!--Mime Type of File is '.$part->ctype_primary."/".$part->ctype_secondary.' -->';
                if (
RESIZE_LARGE_IMAGES) {
                    list(
$thumbImage$fullImage) = ResizeImage($file,$part->ctype_secondary);
                    if (
$thumbImage) {
                        
$IMAGES[] .= $mimeTag.'<a href="' URLPHOTOSDIR $fullImage '"><img src="' URLPHOTOSDIR $thumbImage '" alt="' $part->ctype_parameters['name'] . '" style="'.IMAGESTYLE.'" class="'.IMAGECLASS.'" /></a>' "\n";
                    }
                    else {
                        
$IMAGES[] .= $mimeTag.'<img src="' URLPHOTOSDIR $fullImage '" alt="' $part->ctype_parameters['name'] . '"  style="'.IMAGESTYLE.'" class="'.IMAGECLASS.'" />' "\n";
                    }
                }
                else {
                    
$IMAGES[] .= $mimeTag.'<img src="' URLPHOTOSDIR $fileName '" alt="' $part->ctype_parameters['name'] . '" style="'.IMAGESTYLE.'" class="'.IMAGECLASS.'"  />' "\n";
                }

                break;
            default:
                
$types explode(",",SUPPORTED_FILE_TYPES);
                if (
in_array(strtolower($part->ctype_primary),$types)) {
                    
//pgp signature - then forget it
                    
if ( $part->ctype_secondary == 'pgp-signature' ) {break;}
                    
//other attachments save to FILESDIR
                    
$filename =  $part->ctype_parameters['name'];
                    
$file REALFILESDIR $filename;
                    
$fp fopen($file'w');
                    
fwrite($fp$part->body );
                    
fclose($fp);
                    @
exec ('chmod 755 ' $file);
                    
$meta_return .= '<!--Mime Type of File is '.$part->ctype_primary."/".$part->ctype_secondary.' --><a href="' URLFILESDIR $filename '">' $part->ctype_parameters['name'] . '</a>' "\n";
                }
                break;
        }        
    }
    return 
$meta_return;
}

function 
ubb2HTML(&$text) {
    
// Array of tags with opening and closing
    
$tagArray['img'] = array('open'=>'<img src="','close'=>'">');
    
$tagArray['b'] = array('open'=>'<b>','close'=>'</b>');
    
$tagArray['i'] = array('open'=>'<i>','close'=>'</i>');
    
$tagArray['u'] = array('open'=>'<u>','close'=>'</u>');
    
$tagArray['url'] = array('open'=>'<a href="','close'=>'">\\1</a>');
    
$tagArray['email'] = array('open'=>'<a href="mailto:','close'=>'">\\1</a>');
    
$tagArray['url=(.*)'] = array('open'=>'<a href="','close'=>'">\\2</a>');
    
$tagArray['email=(.*)'] = array('open'=>'<a href="mailto:','close'=>'">\\2</a>');
    
$tagArray['color=(.*)'] = array('open'=>'<font color="','close'=>'">\\2</font>');
    
$tagArray['size=(.*)'] = array('open'=>'<font size="','close'=>'">\\2</font>');
    
$tagArray['font=(.*)'] = array('open'=>'<font face="','close'=>'">\\2</font>');
    
// Array of tags with only one part
    
$sTagArray['br'] = array('tag'=>'<br>');
    
$sTagArray['hr'] = array('tag'=>'<hr>');
    
    foreach(
$tagArray as $tagName=>$replace) {
        
$tagEnd preg_replace('/\W/Ui','',$tagName);
        
$text preg_replace("|\[$tagName\](.*)\[/$tagEnd\]|Ui","$replace[open]\\1$replace[close]",$text);
    }
    foreach(
$sTagArray as $tagName=>$replace) {
        
$text preg_replace("|\[$tagName\]|Ui","$replace[tag]",$text);
    }
    return 
$text;
}


// This function turns Enriched Text into something similar to HTML
// Very basic at the moment, only supports some functionality and dumps the rest
// FIXME: fix colours: <color><param>FFFF,C2FE,0374</param>some text </color>
function etf2HTML $content ) {

    
$search = array(
        
'/<bold>/',
        
'/<\/bold>/',
        
'/<underline>/',
        
'/<\/underline>/',
        
'/<italic>/',
        
'/<\/italic>/',
        
'/<fontfamily><param>.*<\/param>/',
        
'/<\/fontfamily>/',
        
'/<x-tad-bigger>/',
        
'/<\/x-tad-bigger>/',
        
'/<bigger>/',
        
'</bigger>/',
        
'/<color>/',
        
'/<\/color>/',    
        
'/<param>.+<\/param>/'
    
);
    
    
$replace = array (
        
'<b>',
        
'</b>',
        
'<u>',
        
'</u>',
        
'<i>',
        
'</i>',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
''
    
);
        
// strip extra line breaks
        
$content preg_replace($search,$replace,$content);
        return 
trim($content);
}


// This function cleans up HTML in the e-mail
function HTML2HTML $content ) {
    
$search = array(
        
'/<html>/',
        
'/<\/html>/',
        
'/<title>/',
        
'/<\/title>/',
        
'/<body.*>/',
        
'/<\/body>/',
        
'/<head>/',
        
'/<\/head>/',
        
'/<meta content=.*>/',
        
'/<!DOCTYPE.*>/',
        
'/<img src=".*>/'
//        '/<img src="cid:(.*)" .*>/'
    
);
    
    
$replace = array (
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
'',
        
''
    
);
        
// strip extra line breaks
        
$content preg_replace($search,$replace,trim($content));
        return (
$content);
}



/**
  * Determines if the sender is a valid user.
  * @return integer|NULL
  */
function ValidatePoster( &$mimeDecodedEmail ) {
    global 
$wpdb,$tableusers;

    
$from RemoveExtraCharactersInEmailAddress(trim($mimeDecodedEmail->headers["from"]));

    if ( empty(
$from) ) { 
        echo 
'<h1> Invalid Sender - Emtpy! </h1>';
        return;
    }

    
//See if the email address is one of the special authorized ones
    
if (CheckEmailAddress($from)) {
        print(
"<p>$from is authorized to post as the administrator <br />\n");
        
$from get_settings("admin_email");
    }
    
$sql 'SELECT id FROM '$tableusers.' WHERE user_email=\'' addslashes($from) . '\'';
    
$poster $wpdb->get_var($sql);
    if (!
$poster) {
        echo 
'<h1>Invalid sender: ' htmlentities($from) . " !</h1><h2>Not adding email!</h2><br />\n";
        if (
FORWARD_REJECTED_MAIL) {
            if (
ForwardRejectedMailToAdmin($mimeDecodedEmail)) { 
                echo 
"A copy of the message has been forwarded to the administrator.\n"
            } else {
                echo 
"The message was unable to be forwarded to the adminstrator.\n";
            }
        }
        return;
    } 
    return 
$poster;
}

/**
  * Looks at the content for the start of the signature and removes all text
  * after that point
  * @param string
  * @param array - a list of patterns to determine if it is a sig block
  */
function RemoveSignature$content,$filterList = array('--','- --' )) {
    
$arrcontent explode("\n"$content);
    
$i 0;
    for (
$i 0$i<=count($arrcontent); $i++) {
        
$line $arrcontent[$i];
        
$nextline $arrcontent[$i+1];
        foreach (
$filterList as $pattern) {
            if (
preg_match("/^$pattern/",trim($line))) {
                print(
"<p>Found in $line");
                break 
2;
            }
        } 
        
$strcontent .= $line ."\n";
    }
    return 
$strcontent;
}

//filter content for new lines
function FilterNewLines ( &$content ) {
        
$search = array (
            
'/ (\n|\r\n|\r)/',
            
'/(\n|\r\n|\r)/'
        
);
        
$replace = array (
            
' ',
            
"\n"
        
);
        
// strip extra line breaks
        
$return preg_replace($search,$replace,$content);
        
$content $return;
}

//strip pgp stuff
function StripPGP $content ) {
        
$search = array (
            
'/-----BEGIN PGP SIGNED MESSAGE-----/',
            
'/Hash: SHA1/'
        
);
        
$replace = array (
            
' ',
            
''
        
);
        
// strip extra line breaks
        
$return preg_replace($search,$replace,$content);
        return 
$return;
}

/**
 * Added by Hey
 * This function converts to ISO-8859-1 if desired by the user.
 *
 * Hint: It should only be applied to type="text/*" Other types are already converted
 * by the initial HandleUTF8Decode()-call and will be broken if converted twice.
 *
 * Hint: Do conversion only if text was encoded in Base64 or Quoted-Printable.
 * -> Plain texts are coverted by the initial HandleUTF8Decode().
 * This could be a bug for utf-8 users but it doesn't bother me because I want ISO anyway :-)
*/
function HandleISO( &$part ) {
    
$charset $part->ctype_parameters['charset'];
    if( (
ISO_8859_1 == true) && ($charset != 'iso-8859-1')) {
        
$transenc strtolower$part->headers['content-transfer-encoding'] );
        if( 
$transenc == 'base64' || $transenc == 'quoted-printable' ) {
            
$part->body utf8_decode($part->body);
        }
    }
}

/**
  * This function handles decoding base64 if needed
  */
function