svn.filsa.org wordpress_dev

Compare Revisions

Ignore whitespace Rev 9 → Rev 10

/trunk/plugins/mail2wordpress/mail2wp.php
0,0 → 1,369
<?php
/*
 
 
 
*/
 
/** Make sure that the WordPress bootstrap has run before continuing. */
require(dirname(__FILE__) . '/../../../wp-load.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;
/**
* 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.");
 
$parser = new mime_parser_class;
$parseparams = array ('Data'=>$msg_text);
//$parseparams['SaveBody'] = 'temp/';
//$parseparams['SkipBody'] = '1';
//var_dump($parseparams);
$result['status'] = 'INCOMPLETE';
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']);
//var_dump($analyzed);
//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_status = 'pending';
if (empty($post_author)) {
$post_author=1; // dumb but easy assumption that user 1, admin, will always exist.
} else {
$user = new WP_User($post_author);
$post_status = ( $user->has_cap('publish_posts') ) ? 'publish' : 'pending';
}
// process body
$post_content = $this->process_analyzed_body($analyzed); // process via analyzed
$post_content = apply_filters('phone_content', $post_content);// WP filter hook
 
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");
}
// prep post
$post_data = compact('post_content','post_title','post_date','post_date_gmt','post_author','post_category', 'post_status');
$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;
 
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) {
$result = '';
if ($mail['Type'] == 'text') $result = $this->_decode_text($mail['Data']);
 
//handle Type=html and Related
if ($mail['Type'] == 'html') {
$this->log (' - HTML message type.');
$result = $this->_decode_text($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'])) {
$urlpath = $this->upload_dir['url'] . '/' . $fname;
$cid = 'cid:' . $attachment['ContentID'];
$result = str_replace($cid, $urlpath, $result);
}
}
}
}
// handle attachments
if (!empty($mail['Attachments'])) {
$this->log(' - Processing attachments.');
$result .= "\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'])) {
$urlpath = $this->upload_dir['url'] . '/' . $fname;
$result .= '<img src="' . $urlpath .'" class="photomail attachments"/>'. "\n";
}
}
$result .= "\n</div>\n";
 
}
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 = $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
*/
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();
$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;
}
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();
 
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();
 
 
 
?>
 
 
 
 
/trunk/plugins/mail2wordpress/TODO.txt
0,0 → 1,38
 
DONE
 
 
Version: 0.1
 
Support for Email Image attachments.
 
 
TODO
 
Version: Future.
 
Admin interface for configuration:
- Enable/disable mail2wp job.
 
Authorization based on:
- restrict to certain email addresses.
 
Advanced Image Handling:
- add to media library.
- create thumbnails if larger than a certain size.
- Limit size of image attachments to process?
- if image size is > 2meg, build thumbnails?
 
 
 
Feature Ideas:
 
Authorize/Restrict emails that can post.
- via secret word
> http://wordpress.org/extend/ideas/topic.php?id=965
> http://wordpress.org/extend/ideas/topic.php?id=316#post-1218
 
POP3 over SSL support (Gmail)
>http://wordpress.org/extend/ideas/topic.php?id=845
 
 
/trunk/plugins/mail2wordpress/lib/mime_parser.php
0,0 → 1,2257
<?php
/*
* mime_parser.php
*
* @(#) $Id: mime_parser.php,v 1.60 2008/07/17 00:54:24 mlemos Exp $
*
*/
 
define('MIME_PARSER_START', 1);
define('MIME_PARSER_HEADER', 2);
define('MIME_PARSER_HEADER_VALUE', 3);
define('MIME_PARSER_BODY', 4);
define('MIME_PARSER_BODY_START', 5);
define('MIME_PARSER_BODY_DATA', 6);
define('MIME_PARSER_BODY_DONE', 7);
define('MIME_PARSER_END', 8);
 
define('MIME_MESSAGE_START', 1);
define('MIME_MESSAGE_GET_HEADER_NAME', 2);
define('MIME_MESSAGE_GET_HEADER_VALUE', 3);
define('MIME_MESSAGE_GET_BODY', 4);
define('MIME_MESSAGE_GET_BODY_PART', 5);
 
define('MIME_ADDRESS_START', 1);
define('MIME_ADDRESS_FIRST', 2);
 
/*
{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
<class>
 
<package>net.manuellemos.mimeparser</package>
 
<version>@(#) $Id: mime_parser.php,v 1.60 2008/07/17 00:54:24 mlemos Exp $</version>
<copyright>Copyright © (C) Manuel Lemos 2006 - 2008</copyright>
<title>MIME parser</title>
<author>Manuel Lemos</author>
<authoraddress>mlemos-at-acm.org</authoraddress>
 
<documentation>
<idiom>en</idiom>
<purpose>Parse MIME encapsulated e-mail message data compliant with
the RFC 2822 or aggregated in mbox format.</purpose>
<usage>Use the function <functionlink>Decode</functionlink> function
to retrieve the structure of the messages to be parsed. Adjust its
parameters to tell how to return the decoded body data.
Use the <tt>SaveBody</tt> parameter to make the body parts be saved
to files when the message is larger than the available memory. Use
the <tt>SkipBody</tt> parameter to just retrieve the message
structure without returning the body data.<paragraphbreak />
If the message data is an archive that may contain multiple messages
aggregated in the mbox format, set the variable
<variablelink>mbox</variablelink> to <booleanvalue>1</booleanvalue>.</usage>
</documentation>
 
{/metadocument}
*/
 
class mime_parser_class
{
/*
{metadocument}
<variable>
<name>error</name>
<type>STRING</type>
<value></value>
<documentation>
<purpose>Store the message that is returned when an error
occurs.</purpose>
<usage>Check this variable to understand what happened when a call to
any of the class functions has failed.<paragraphbreak />
This class uses cumulative error handling. This means that if one
class functions that may fail is called and this variable was
already set to an error message due to a failure in a previous call
to the same or other function, the function will also fail and does
not do anything.<paragraphbreak />
This allows programs using this class to safely call several
functions that may fail and only check the failure condition after
the last function call.<paragraphbreak />
Just set this variable to an empty string to clear the error
condition.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error='';
 
/*
{metadocument}
<variable>
<name>error_position</name>
<type>INTEGER</type>
<value>-1</value>
<documentation>
<purpose>Point to the position of the message data or file that
refers to the last error that occurred.</purpose>
<usage>Check this variable to determine the relevant position of the
message when a parsing error occurs.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error_position = -1;
 
/*
{metadocument}
<variable>
<name>mbox</name>
<type>BOOLEAN</type>
<value>0</value>
<documentation>
<purpose>Specify whether the message data to parse is a single RFC
2822 message or it is an archive that contain multiple messages in
the mbox format.</purpose>
<usage>Set this variable to <booleanvalue>1</booleanvalue> if it is
it is intended to parse an mbox message archive.<br />
mbox archives may contain multiple messages. Each message starts
with the header <tt>From</tt>. Since all valid RFC 2822 headers
must with a colon, the class will fail to parse a mbox archive if
this variable is set to <booleanvalue>0</booleanvalue>.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $mbox = 0;
 
/*
{metadocument}
<variable>
<name>decode_headers</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Specify whether the message headers should be decoded.</purpose>
<usage>Set this variable to <booleanvalue>1</booleanvalue> if it is
necessary to decode message headers that may have non-ASCII
characters and use other character set encodings.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $decode_headers = 1;
 
/*
{metadocument}
<variable>
<name>decode_bodies</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Specify whether the message body parts should be decoded.</purpose>
<usage>Set this variable to <booleanvalue>1</booleanvalue> if it is
necessary to parse the message bodies and extract its part
structure.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $decode_bodies = 1;
 
/*
{metadocument}
<variable>
<name>extract_addresses</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Specify whether the message headers that usually contain
e-mail addresses should be parsed and the addresses should be
extracted by the <functionlink>Decode</functionlink> function.</purpose>
<usage>Set this variable to <booleanvalue>1</booleanvalue> if it is
necessary to extract the e-mail addresses contained in certain
message headers.<paragraphbreak />
The headers to be parsed are defined by the
<variablelink>address_headers</variablelink> variable.<paragraphbreak />
The parsed addresses are returned by the
<tt>ExtractedAddresses</tt> entry of the <argumentlink>
<function>Decode</function>
<argument>decoded</argument>
</argumentlink> argument of the
<functionlink>Decode</functionlink> function.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $extract_addresses = 1;
 
/*
{metadocument}
<variable>
<name>address_headers</name>
<type>HASH</type>
<value></value>
<documentation>
<purpose>Specify which headers contain addresses that should be
parsed and extracted.</purpose>
<usage>Change this variable if you need to extract e-mail addresses
from a different list of message headers.<paragraphbreak />
It must be set to an associative array with keys set to the names
of the headers to be parsed including the colon. The array values
must be set to a boolean flag to tell whether the headers with the
respective name should be parsed. The header names must be in lower
case.<paragraphbreak />
By default the class addresses from the headers:
<stringvalue>from:</stringvalue>, <stringvalue>to:</stringvalue>,
<stringvalue>cc:</stringvalue>, <stringvalue>bcc:</stringvalue>,
<stringvalue>return-path:</stringvalue>,
<stringvalue>reply-to:</stringvalue> and
<stringvalue>disposition-notification-to:</stringvalue>.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $address_headers = array(
'from:' => 1,
'to:' => 1,
'cc:' => 1,
'bcc:' => 1,
'return-path:'=>1,
'reply-to:'=>1,
'disposition-notification-to:'=>1
);
 
/*
{metadocument}
<variable>
<name>message_buffer_length</name>
<type>INTEGER</type>
<value>8000</value>
<documentation>
<purpose>Maximum length of the chunks of message data that the class
parse at one time.</purpose>
<usage>Adjust this value according to the available memory.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $message_buffer_length = 8000;
 
/*
{metadocument}
<variable>
<name>ignore_syntax_errors</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Specify whether the class should ignore syntax errors in
malformed messages.</purpose>
<usage>Set this variable to <booleanvalue>0</booleanvalue> if it is
necessary to verify whether message data may be corrupted due to
to eventual bugs in the program that generated the
message.<paragraphbreak />
Currently the class only ignores some types of syntax errors.
Other syntax errors may still cause the
<functionlink>Decode</functionlink> to fail.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $ignore_syntax_errors=1;
 
/*
{metadocument}
<variable>
<name>warnings</name>
<type>HASH</type>
<value></value>
<documentation>
<purpose>Return a list of positions of the original message that
contain syntax errors.</purpose>
<usage>Check this variable to retrieve eventual message syntax
errors that were ignored when the
<variablelink>ignore_syntax_errors</variablelink> is set to
<booleanvalue>1</booleanvalue>.<paragraphbreak />
The indexes of this array are the positions of the errors. The
array values are the corresponding syntax error messages.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $warnings=array();
 
/* Private variables */
var $state = MIME_PARSER_START;
var $buffer = '';
var $buffer_position = 0;
var $offset = 0;
var $parts = array();
var $part_position = 0;
var $headers = array();
var $body_parser;
var $body_parser_state = MIME_PARSER_BODY_DONE;
var $body_buffer = '';
var $body_buffer_position = 0;
var $body_offset = 0;
var $current_header = '';
var $file;
var $body_file;
var $position = 0;
var $body_part_number = 1;
var $next_token = '';
 
/* Private functions */
 
Function SetError($error)
{
$this->error = $error;
return(0);
}
 
Function SetErrorWithContact($error)
{
return($this->SetError($error.'. Please contact the author Manuel Lemos <mlemos@acm.org> and send a copy of this message to let him add support for this kind of messages'));
}
 
Function SetPositionedError($error, $position)
{
$this->error_position = $position;
return($this->SetError($error));
}
 
Function SetPositionedWarning($error, $position)
{
if(!$this->ignore_syntax_errors)
return($this->SetPositionedError($error, $position));
$this->warnings[$position]=$error;
return(1);
}
 
Function SetPHPError($error, &$php_error_message)
{
if(IsSet($php_error_message)
&& strlen($php_error_message))
$error .= ': '.$php_error_message;
return($this->SetError($error));
}
 
Function ResetParserState()
{
$this->error='';
$this->error_position = -1;
$this->state = MIME_PARSER_START;
$this->buffer = '';
$this->buffer_position = 0;
$this->offset = 0;
$this->parts = array();
$this->part_position = 0;
$this->headers = array();
$this->body_parser_state = MIME_PARSER_BODY_DONE;
$this->body_buffer = '';
$this->body_buffer_position = 0;
$this->body_offset = 0;
$this->current_header = '';
$this->position = 0;
$this->body_part_number = 1;
$this->next_token = '';
}
 
Function Tokenize($string,$separator="")
{
if(!strcmp($separator,""))
{
$separator=$string;
$string=$this->next_token;
}
for($character=0;$character<strlen($separator);$character++)
{
if(GetType($position=strpos($string,$separator[$character]))=='integer')
$found=(IsSet($found) ? min($found,$position) : $position);
}
if(IsSet($found))
{
$this->next_token=substr($string,$found+1);
return(substr($string,0,$found));
}
else
{
$this->next_token='';
return($string);
}
}
 
Function ParseStructuredHeader($value, &$type, &$parameters, &$character_sets, &$languages)
{
$type = strtolower(trim($this->Tokenize($value, ';')));
$p = trim($this->Tokenize(''));
$parameters = $character_sets = $languages = array();
while(strlen($p))
{
$parameter = trim(strtolower($this->Tokenize($p, '=')));
$remaining = trim($this->Tokenize(''));
if(!strcmp($remaining[0], '"')
&& (GetType($quote = strpos($remaining, '"', 1)) == 'integer'))
{
$value = substr($remaining, 1, $quote - 1);
$p = trim(substr($remaining, $quote + 1));
if(strlen($p) > 0
&& !strcmp($p[0], ';'))
$p = substr($p, 1);
}
else
{
$value = trim($this->Tokenize($remaining, ';'));
$p = trim($this->Tokenize(''));
}
if(($l=strlen($parameter))
&& !strcmp($parameter[$l - 1],'*'))
{
$parameter=$this->Tokenize($parameter, '*');
if(IsSet($parameters[$parameter])
&& IsSet($character_sets[$parameter]))
$value = $parameters[$parameter] . UrlDecode($value);
else
{
$character_sets[$parameter] = strtolower($this->Tokenize($value, '\''));
$languages[$parameter] = $this->Tokenize('\'');
$value = UrlDecode($this->Tokenize(''));
}
}
$parameters[$parameter] = $value;
}
}
 
Function FindStringLineBreak($string, $position, &$break, &$line_break)
{
if(GetType($line_break=strpos($string, $break="\n", $position))=='integer')
{
if(GetType($new_line_break=strpos($string, "\n", $position))=='integer')
{
if($new_line_break < $line_break)
{
$break = "\n";
$line_break = $new_line_break;
return(1);
}
}
if($line_break>$position
&& $string[$line_break-1]=="\r")
{
$line_break--;
$break="\r\n";
}
return(1);
}
return(GetType($line_break=strpos($string, $break="\r", $position))=='integer');
}
 
Function FindLineBreak($position, &$break, &$line_break)
{
if(GetType($line_break=strpos($this->buffer, $break="\r", $position))=='integer')
{
if(GetType($new_line_break=strpos($this->buffer, "\n", $position))=='integer')
{
if($new_line_break < $line_break)
{
$break = "\n";
$line_break = $new_line_break;
return(1);
}
}
if(($n = $line_break + 1) < strlen($this->buffer)
&& $this->buffer[$n]=="\n")
$break="\r\n";
return(1);
}
return(GetType($line_break=strpos($this->buffer, $break="\n", $position))=='integer');
}
 
Function FindBodyLineBreak($position, &$break, &$line_break)
{
if(GetType($line_break=strpos($this->body_buffer, $break="\r", $position))=='integer')
{
if(GetType($new_line_break=strpos($this->body_buffer, "\n", $position))=='integer')
{
if($new_line_break < $line_break)
{
$break = "\n";
$line_break = $new_line_break;
return(1);
}
}
if(($n = $line_break + 1) < strlen($this->body_buffer)
&& $this->body_buffer[$n]=="\n")
$break="\r\n";
return(1);
}
return(GetType($line_break=strpos($this->body_buffer, $break="\n", $position))=='integer');
}
 
Function ParseHeaderString($body, &$position, &$headers)
{
$l = strlen($body);
$headers = array();
for(;$position < $l;)
{
if($this->FindStringLineBreak($body, $position, $break, $line_break))
{
$line = substr($body, $position, $line_break - $position);
$position = $line_break + strlen($break);
}
else
{
$line = substr($body, $position);
$position = $l;
}
if(strlen($line)==0)
break;
$h = strtolower(strtok($line,':'));
$headers[$h] = trim(strtok(''));
}
}
 
Function ParsePart($end, &$part, &$need_more_data)
{
$need_more_data = 0;
switch($this->state)
{
case MIME_PARSER_START:
$part=array(
'Type'=>'MessageStart',
'Position'=>$this->offset + $this->buffer_position
);
$this->state = MIME_PARSER_HEADER;
break;
case MIME_PARSER_HEADER:
if($this->FindLineBreak($this->buffer_position, $break, $line_break))
{
$next = $line_break + strlen($break);
if(!strcmp($break,"\r")
&& strlen($this->buffer) == $next
&& !$end)
{
$need_more_data = 1;
break;
}
if($line_break==$this->buffer_position)
{
$part=array(
'Type'=>'BodyStart',
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = $next;
$this->state = MIME_PARSER_BODY;
break;
}
}
if(GetType($colon=strpos($this->buffer, ':', $this->buffer_position))=='integer')
{
if(GetType($space=strpos(substr($this->buffer, $this->buffer_position, $colon - $this->buffer_position), ' '))=='integer')
{
if((!$this->mbox
|| strcmp(strtolower(substr($this->buffer, $this->buffer_position, $space)), 'from'))
&& !$this->SetPositionedWarning('invalid header name line', $this->buffer_position))
return(0);
$next = $this->buffer_position + $space + 1;
}
else
$next = $colon+1;
}
else
{
$need_more_data = 1;
break;
}
$part=array(
'Type'=>'HeaderName',
'Name'=>substr($this->buffer, $this->buffer_position, $next - $this->buffer_position),
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = $next;
$this->state = MIME_PARSER_HEADER_VALUE;
break;
case MIME_PARSER_HEADER_VALUE:
$position = $this->buffer_position;
$value = '';
for(;;)
{
if($this->FindLineBreak($position, $break, $line_break))
{
$next = $line_break + strlen($break);
$line = substr($this->buffer, $position, $line_break - $position);
if(strlen($this->buffer) == $next)
{
if(!$end)
{
$need_more_data = 1;
break 2;
}
$value .= $line;
$part=array(
'Type'=>'HeaderValue',
'Value'=>$value,
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = $next;
$this->state = MIME_PARSER_END;
break ;
}
else
{
$character = $this->buffer[$next];
if(!strcmp($character, ' ')
|| !strcmp($character, "\t"))
{
$value .= $line;
$position = $next + 1;
}
else
{
$value .= $line;
$part=array(
'Type'=>'HeaderValue',
'Value'=>$value,
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = $next;
$this->state = MIME_PARSER_HEADER;
break 2;
}
}
}
else
{
if(!$end)
{
$need_more_data = 1;
break;
}
else
{
$value .= substr($this->buffer, $position);
$part=array(
'Type'=>'HeaderValue',
'Value'=>$value,
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = strlen($this->buffer);
$this->state = MIME_PARSER_END;
break;
}
}
}
break;
case MIME_PARSER_BODY:
if($this->mbox)
{
$add = 0;
$append='';
if($this->FindLineBreak($this->buffer_position, $break, $line_break))
{
$next = $line_break + strlen($break);
$following = $next + strlen($break);
if($following >= strlen($this->buffer)
|| GetType($line=strpos($this->buffer, $break, $following))!='integer')
{
if(!$end)
{
$need_more_data = 1;
break;
}
}
$start = strtolower(substr($this->buffer, $next, strlen($break.'from ')));
if(!strcmp($break.'from ', $start))
{
if($line_break == $this->buffer_position)
{
$part=array(
'Type'=>'MessageEnd',
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = $following;
$this->state = MIME_PARSER_START;
break;
}
else
$add = strlen($break);
$next = $line_break;
}
else
{
$start = strtolower(substr($this->buffer, $next, strlen('>from ')));
if(!strcmp('>from ', $start))
{
$part=array(
'Type'=>'BodyData',
'Data'=>substr($this->buffer, $this->buffer_position, $next - $this->buffer_position),
'Position'=>$this->offset + $this->buffer_position
);
$this->buffer_position = $next + 1;
break;
}
}
}
else
{
if(!$end)
{
$need_more_data = 1;
break;
}
$next = strlen($this->buffer);
$append="\r\n";
}
if($next > $this->buffer_position)
{
$part=array(
'Type'=>'BodyData',
'Data'=>substr($this->buffer, $this->buffer_position, $next + $add - $this->buffer_position).$append,
'Position'=>$this->offset + $this->buffer_position
);
}
elseif($end)
{
$part=array(
'Type'=>'MessageEnd',
'Position'=>$this->offset + $this->buffer_position
);
$this->state = MIME_PARSER_END;
}
$this->buffer_position = $next;
}
else
{
if(strlen($this->buffer)-$this->buffer_position)
{
$data=substr($this->buffer, $this->buffer_position, strlen($this->buffer) - $this->buffer_position);
$end_line = (!strcmp(substr($data,-1),"\n") || !strcmp(substr($data,-1),"\r"));
if($end
&& !$end_line)
{
$data.="\n";
$end_line = 1;
}
$offset = $this->offset + $this->buffer_position;
$this->buffer_position = strlen($this->buffer);
$need_more_data = !$end;
if(!$end_line)
{
if(GetType($line_break=strrpos($data, "\n"))=='integer'
|| GetType($line_break=strrpos($data, "\r"))=='integer')
{
$line_break++;
$this->buffer_position -= strlen($data) - $line_break;
$data = substr($data, 0, $line_break);
}
}
$part=array(
'Type'=>'BodyData',
'Data'=>$data,
'Position'=>$offset
);
}
else
{
if($end)
{
$part=array(
'Type'=>'MessageEnd',
'Position'=>$this->offset + $this->buffer_position
);
$this->state = MIME_PARSER_END;
}
else
$need_more_data = 1;
}
}
break;
default:
return($this->SetPositionedError($this->state.' is not a valid parser state', $this->buffer_position));
}
return(1);
}
 
Function QueueBodyParts()
{
for(;;)
{
if(!$this->body_parser->GetPart($part,$end))
return($this->SetError($this->body_parser->error));
if($end)
return(1);
if(!IsSet($part['Part']))
$part['Part']=$this->headers['Boundary'];
$this->parts[]=$part;
}
}
 
Function ParseParameters($value, &$first, &$parameters, $return)
{
$first = strtolower(trim(strtok($value, ';')));
$values = trim(strtok(''));
$parameters = array();
$return_value = '';
while(strlen($values))
{
$parameter = trim(strtolower(strtok($values, '=')));
$value = trim(strtok(';'));
$l = strlen($value);
if($l > 1
&& !strcmp($value[0], '"')
&& !strcmp($value[$l - 1], '"'))
$value = substr($value, 1, $l - 2);
$parameters[$parameter] = $value;
if(!strcmp($parameter, $return))
$return_value = $value;
$values = trim(strtok(''));
}
return($return_value);
}
 
Function DecodePart($part)
{
switch($part['Type'])
{
case 'MessageStart':
$this->headers=array();
break;
case 'HeaderName':
if($this->decode_bodies)
$this->current_header = strtolower($part['Name']);
break;
case 'HeaderValue':
if($this->decode_headers)
{
$value = $part['Value'];
$error = '';
for($decoded_header = array(), $position = 0; $position<strlen($value); )
{
if(GetType($encoded=strpos($value,'=?', $position))!='integer')
{
if($position<strlen($value))
{
if(count($decoded_header))
$decoded_header[count($decoded_header)-1]['Value'].=substr($value, $position);
else
{
$decoded_header[]=array(
'Value'=>substr($value, $position),
'Encoding'=>'ASCII'
);
}
}
break;
}
$set = $encoded + 2;
if(GetType($method=strpos($value,'?', $set))!='integer')
{
$error = 'invalid header encoding syntax '.$part['Value'];
$error_position = $part['Position'] + $set;
break;
}
$encoding=strtoupper(substr($value, $set, $method - $set));
$method += 1;
if(GetType($data=strpos($value,'?', $method))!='integer')
{
$error = 'invalid header encoding syntax '.$part['Value'];
$error_position = $part['Position'] + $set;
break;
}
$start = $data + 1;
if(GetType($end=strpos($value,'?=', $start))!='integer')
{
$error = 'invalid header encoding syntax '.$part['Value'];
$error_position = $part['Position'] + $start;
break;
}
if($encoded > $position)
{
if(count($decoded_header))
$decoded_header[count($decoded_header)-1]['Value'].=substr($value, $position, $encoded - $position);
else
{
$decoded_header[]=array(
'Value'=>substr($value, $position, $encoded - $position),
'Encoding'=>'ASCII'
);
}
}
switch(strtolower(substr($value, $method, $data - $method)))
{
case 'q':
if($end>$start)
{
for($decoded = '', $position = $start; $position < $end ; )
{
switch($value[$position])
{
case '=':
$h = HexDec($hex = strtolower(substr($value, $position+1, 2)));
if($end - $position < 3
|| strcmp(sprintf('%02x', $h), $hex))
{
$warning = 'the header specified an invalid encoded character';
$warning_position = $part['Position'] + $position + 1;
if($this->ignore_syntax_errors)
{
$this->SetPositionedWarning($warning, $warning_position);
$decoded .= '=';
$position ++;
}
else
{
$error = $warning;
$error_position = $warning_position;
break 4;
}
}
else
{
$decoded .= Chr($h);
$position += 3;
}
break;
case '_':
$decoded .= ' ';
$position++;
break;
default:
$decoded .= $value[$position];
$position++;
break;
}
}
if(count($decoded_header)
&& (!strcmp($decoded_header[$last = count($decoded_header)-1]['Encoding'], 'ASCII'))
|| !strcmp($decoded_header[$last]['Encoding'], $encoding))
{
$decoded_header[$last]['Value'].= $decoded;
$decoded_header[$last]['Encoding']= $encoding;
}
else
{
$decoded_header[]=array(
'Value'=>$decoded,
'Encoding'=>$encoding
);
}
}
break;
case 'b':
$decoded=base64_decode(substr($value, $start, $end - $start));
if($end <= $start
|| GetType($decoded) != 'string'
|| strlen($decoded) == 0)
{
$warning = 'the header specified an invalid base64 encoded text';
$warning_position = $part['Position'] + $start;
if($this->ignore_syntax_errors)
$this->SetPositionedWarning($warning, $warning_position);
else
{
$error = $warning;
$error_position = $warning_position;
break 2;
}
}
if(count($decoded_header)
&& (!strcmp($decoded_header[$last = count($decoded_header)-1]['Encoding'], 'ASCII'))
|| !strcmp($decoded_header[$last]['Encoding'], $encoding))
{
$decoded_header[$last]['Value'].= $decoded;
$decoded_header[$last]['Encoding']= $encoding;
}
else
{
$decoded_header[]=array(
'Value'=>$decoded,
'Encoding'=>$encoding
);
}
break;
default:
$error = 'the header specified an unsupported encoding method';
$error_position = $part['Position'] + $method;
break 2;
}
$position = $end + 2;
}
if(strlen($error)==0
&& count($decoded_header))
$part['Decoded']=$decoded_header;
}
if($this->decode_bodies
|| $this->decode_headers)
{
switch($this->current_header)
{
case 'content-type:':
$boundary = $this->ParseParameters($part['Value'], $type, $parameters, 'boundary');
$this->headers['Type'] = $type;
if($this->decode_headers)
{
$part['MainValue'] = $type;
$part['Parameters'] = $parameters;
}
if(!strcmp(strtok($type, '/'), 'multipart'))
{
$this->headers['Multipart'] = 1;
if(strlen($boundary))
$this->headers['Boundary'] = $boundary;
else
return($this->SetPositionedError('multipart content-type header does not specify the boundary parameter', $part['Position']));
}
break;
case 'content-transfer-encoding:':
switch($this->headers['Encoding']=strtolower(trim($part['Value'])))
{
case 'quoted-printable':
$this->headers['QuotedPrintable'] = 1;
break;
case '7 bit':
case '8 bit':
if(!$this->SetPositionedWarning('"'.$this->headers['Encoding'].'" is an incorrect content transfer encoding type', $part['Position']))
return(0);
case '7bit':
case '8bit':
case 'binary':
break;
case 'base64':
$this->headers['Base64']=1;
break;
default:
if(!$this->SetPositionedWarning('decoding '.$this->headers['Encoding'].' encoded bodies is not yet supported', $part['Position']))
return(0);
}
break;
}
}
break;
case 'BodyStart':
if($this->decode_bodies
&& IsSet($this->headers['Multipart']))
{
$this->body_parser_state = MIME_PARSER_BODY_START;
$this->body_buffer = '';
$this->body_buffer_position = 0;
}
break;
case 'MessageEnd':
if($this->decode_bodies
&& IsSet($this->headers['Multipart'])
&& $this->body_parser_state != MIME_PARSER_BODY_DONE)
{
if($this->body_parser_state != MIME_PARSER_BODY_DATA)
return($this->SetPositionedError('incomplete message body part', $part['Position']));
if(!$this->SetPositionedWarning('truncated message body part', $part['Position']))
return(0);
}
break;
case 'BodyData':
if($this->decode_bodies)
{
if(strlen($this->body_buffer)==0)
{
$this->body_buffer = $part['Data'];
$this->body_offset = $part['Position'];
}
else
$this->body_buffer .= $part['Data'];
if(IsSet($this->headers['Multipart']))
{
$boundary = '--'.$this->headers['Boundary'];
switch($this->body_parser_state)
{
case MIME_PARSER_BODY_START:
for($position = $this->body_buffer_position; ;)
{
if(!$this->FindBodyLineBreak($position, $break, $line_break))
return(1);
$next = $line_break + strlen($break);
if(!strcmp(rtrim(substr($this->body_buffer, $position, $line_break - $position)), $boundary))
{
$part=array(
'Type'=>'StartPart',
'Part'=>$this->headers['Boundary'],
'Position'=>$this->body_offset + $next
);
$this->parts[]=$part;
UnSet($this->body_parser);
$this->body_parser = new mime_parser_class;
$this->body_parser->decode_bodies = 1;
$this->body_parser->decode_headers = $this->decode_headers;
$this->body_parser->mbox = 0;
$this->body_parser_state = MIME_PARSER_BODY_DATA;
$this->body_buffer = substr($this->body_buffer, $next);
$this->body_offset += $next;
$this->body_buffer_position = 0;
break;
}
else
$position = $next;
}
case MIME_PARSER_BODY_DATA:
for($position = $this->body_buffer_position; ;)
{
if(!$this->FindBodyLineBreak($position, $break, $line_break))
{
if($position > 0)
{
if(!$this->body_parser->Parse(substr($this->body_buffer, 0, $position), 0))
return($this->SetError($this->body_parser->error));
if(!$this->QueueBodyParts())
return(0);
}
$this->body_buffer = substr($this->body_buffer, $position);
$this->body_buffer_position = 0;
$this->body_offset += $position;
return(1);
}
$next = $line_break + strlen($break);
$line = substr($this->body_buffer, $position, $line_break - $position);
if(!strcmp(rtrim($line), $boundary))
{
if(!$this->body_parser->Parse(substr($this->body_buffer, 0, $position), 1))
return($this->SetError($this->body_parser->error));
if(!$this->QueueBodyParts())
return(0);
$part=array(
'Type'=>'EndPart',
'Part'=>$this->headers['Boundary'],
'Position'=>$this->body_offset + $position
);
$this->parts[] = $part;
$part=array(
'Type'=>'StartPart',
'Part'=>$this->headers['Boundary'],
'Position'=>$this->body_offset + $next
);
$this->parts[] = $part;
UnSet($this->body_parser);
$this->body_parser = new mime_parser_class;
$this->body_parser->decode_bodies = 1;
$this->body_parser->decode_headers = $this->decode_headers;
$this->body_parser->mbox = 0;
$this->body_buffer = substr($this->body_buffer, $next);
$this->body_buffer_position = 0;
$this->body_offset += $next;
$position=0;
continue;
}
elseif(!strcmp($r = rtrim($line), $boundary.'--'))
{
if(!$this->body_parser->Parse(substr($this->body_buffer, 0, $position), 1))
return($this->SetError($this->body_parser->error));
if(!$this->QueueBodyParts())
return(0);
$part=array(
'Type'=>'EndPart',
'Part'=>$this->headers['Boundary'],
'Position'=>$this->body_offset + $position
);
$this->body_buffer = substr($this->body_buffer, $next);
$this->body_buffer_position = 0;
$this->body_offset += $next;
$this->body_parser_state = MIME_PARSER_BODY_DONE;
break 2;
}
$position = $next;
}
break;
case MIME_PARSER_BODY_DONE:
return(1);
default:
return($this->SetPositionedError($this->state.' is not a valid body parser state', $this->body_buffer_position));
}
}
elseif(IsSet($this->headers['QuotedPrintable']))
{
for($end = strlen($this->body_buffer), $decoded = '', $position = $this->body_buffer_position; $position < $end; )
{
if(GetType($equal = strpos($this->body_buffer, '=', $position))!='integer')
{
$decoded .= substr($this->body_buffer, $position);
$position = $end;
break;
}
$next = $equal + 1;
switch($end - $equal)
{
case 1:
$decoded .= substr($this->body_buffer, $position, $equal - $position);
$position = $equal;
break 2;
case 2:
$decoded .= substr($this->body_buffer, $position, $equal - $position);
if(!strcmp($this->body_buffer[$next],"\n"))
$position = $end;
else
$position = $equal;
break 2;
}
if(!strcmp(substr($this->body_buffer, $next, 2), $break="\r\n")
|| !strcmp($this->body_buffer[$next], $break="\n")
|| !strcmp($this->body_buffer[$next], $break="\r"))
{
$decoded .= substr($this->body_buffer, $position, $equal - $position);
$position = $next + strlen($break);
continue;
}
$decoded .= substr($this->body_buffer, $position, $equal - $position);
$h = HexDec($hex=strtolower(substr($this->body_buffer, $next, 2)));
if(strcmp(sprintf('%02x', $h), $hex))
{
if(!$this->SetPositionedWarning('the body specified an invalid quoted-printable encoded character', $this->body_offset + $next))
return(0);
$decoded.='=';
$position=$next;
}
else
{
$decoded .= Chr($h);
$position = $equal + 3;
}
}
if(strlen($decoded)==0)
{
$this->body_buffer_position = $position;
return(1);
}
$part['Data'] = $decoded;
$this->body_buffer = substr($this->body_buffer, $position);
$this->body_buffer_position = 0;
$this->body_offset += $position;
}
elseif(IsSet($this->headers['Base64']))
{
$part['Data'] = base64_decode($this->body_buffer_position ? substr($this->body_buffer,$this->body_buffer_position) : $this->body_buffer);
$this->body_offset += strlen($this->body_buffer) - $this->body_buffer_position;
$this->body_buffer_position = 0;
$this->body_buffer = '';
}
else
{
$part['Data'] = substr($this->body_buffer, $this->body_buffer_position);
$this->body_buffer_position = 0;
$this->body_buffer = '';
}
}
break;
}
$this->parts[]=$part;
return(1);
}
 
Function DecodeStream($parameters, &$end_of_message, &$decoded)
{
$end_of_message = 1;
$state = MIME_MESSAGE_START;
for(;;)
{
if(!$this->GetPart($part, $end))
return(0);
if($end)
{
if(IsSet($parameters['File']))
{
$end_of_data = feof($this->file);
if($end_of_data)
break;
$data = @fread($this->file, $this->message_buffer_length);
if(GetType($data)!='string')
return($this->SetPHPError('could not read the message file', $php_errormsg));
$end_of_data = feof($this->file);
}
else
{
$end_of_data=($this->position>=strlen($parameters['Data']));
if($end_of_data)
break;
$data = substr($parameters['Data'], $this->position, $this->message_buffer_length);
$this->position += strlen($data);
$end_of_data = ($this->position >= strlen($parameters['Data']));
}
if(!$this->Parse($data, $end_of_data))
return(0);
continue;
}
$type = $part['Type'];
switch($state)
{
case MIME_MESSAGE_START:
switch($type)
{
case 'MessageStart':
$decoded=array(
'Headers'=>array(),
'Parts'=>array()
);
$end_of_message = 0;
$state = MIME_MESSAGE_GET_HEADER_NAME;
continue 3;
}
break;
 
case MIME_MESSAGE_GET_HEADER_NAME:
switch($type)
{
case 'HeaderName':
$header = strtolower($part['Name']);
$state = MIME_MESSAGE_GET_HEADER_VALUE;
continue 3;
case 'BodyStart':
$state = MIME_MESSAGE_GET_BODY;
$part_number = 0;
continue 3;
}
break;
 
case MIME_MESSAGE_GET_HEADER_VALUE:
switch($type)
{
case 'HeaderValue':
$value = trim($part['Value']);
if(!IsSet($decoded['Headers'][$header]))
{
$h = 0;
$decoded['Headers'][$header]=$value;
if($this->extract_addresses
&& IsSet($this->address_headers[$header]))
$decoded['HeaderPositions'][$header] = $part['Position'];
}
elseif(GetType($decoded['Headers'][$header])=='string')
{
$h = 1;
$decoded['Headers'][$header]=array($decoded['Headers'][$header], $value);
}
else
{
$h = count($decoded['Headers'][$header]);
$decoded['Headers'][$header][]=$value;
}
if(IsSet($part['Decoded'])
&& (count($part['Decoded'])>1
|| strcmp($part['Decoded'][0]['Encoding'],'ASCII')
|| strcmp($value, trim($part['Decoded'][0]['Value']))))
{
$p=$part['Decoded'];
$p[0]['Value']=ltrim($p[0]['Value']);
$last=count($p)-1;
$p[$last]['Value']=rtrim($p[$last]['Value']);
$decoded['DecodedHeaders'][$header][$h]=$p;
}
switch($header)
{
case 'content-disposition:':
$filename='filename';
break;
case 'content-type:':
if(!IsSet($decoded['FileName']))
{
$filename='name';
break;
}
default:
$filename='';
break;
}
if(strlen($filename))
{
$this->ParseStructuredHeader($value, $type, $header_parameters, $character_sets, $languages);
if(IsSet($header_parameters[$filename]))
{
$decoded['FileName']=$header_parameters[$filename];
if(IsSet($character_sets[$filename])
&& strlen($character_sets[$filename]))
$decoded['FileNameCharacterSet']=$character_sets[$filename];
if(IsSet($character_sets['language'])
&& strlen($character_sets['language']))
$decoded['FileNameCharacterSet']=$character_sets[$filename];
if(!strcmp($header, 'content-disposition:'))
$decoded['FileDisposition']=$type;
}
}
$state = MIME_MESSAGE_GET_HEADER_NAME;
continue 3;
}
break;
 
case MIME_MESSAGE_GET_BODY:
switch($type)
{
case 'BodyData':
if(IsSet($parameters['SaveBody']))
{
if(!IsSet($decoded['BodyFile']))
{
$directory_separator=(defined('DIRECTORY_SEPARATOR') ? DIRECTORY_SEPARATOR : '/');
$path = (strlen($parameters['SaveBody']) ? ($parameters['SaveBody'].(strcmp($parameters['SaveBody'][strlen($parameters['SaveBody'])-1], $directory_separator) ? $directory_separator : '')) : '').strval($this->body_part_number);
if(!($this->body_file = fopen($path, 'wb')))
return($this->SetPHPError('could not create file '.$path.' to save the message body part', $php_errormsg));
$decoded['BodyFile'] = $path;
$decoded['BodyPart'] = $this->body_part_number;
$decoded['BodyLength'] = 0;
$this->body_part_number++;
}
if(strlen($part['Data'])
&& !fwrite($this->body_file, $part['Data']))
{
$this->SetPHPError('could not save the message body part to file '.$decoded['BodyFile'], $php_errormsg);
fclose($this->body_file);
@unlink($decoded['BodyFile']);
return(0);
}
}
elseif(IsSet($parameters['SkipBody']))
{
if(!IsSet($decoded['BodyPart']))
{
$decoded['BodyPart'] = $this->body_part_number;
$decoded['BodyLength'] = 0;
$this->body_part_number++;
}
}
else
{
if(IsSet($decoded['Body']))
$decoded['Body'].=$part['Data'];
else
{
$decoded['Body']=$part['Data'];
$decoded['BodyPart'] = $this->body_part_number;
$decoded['BodyLength'] = 0;
$this->body_part_number++;
}
}
$decoded['BodyLength'] += strlen($part['Data']);
continue 3;
case 'StartPart':
if(!$this->DecodeStream($parameters, $end_of_part, $decoded_part))
return(0);
$decoded['Parts'][$part_number]=$decoded_part;
$part_number++;
$state = MIME_MESSAGE_GET_BODY_PART;
continue 3;
case 'MessageEnd':
if(IsSet($decoded['BodyFile']))
fclose($this->body_file);
return(1);
}
break;
 
case MIME_MESSAGE_GET_BODY_PART:
switch($type)
{
case 'EndPart':
$state = MIME_MESSAGE_GET_BODY;
continue 3;
}
break;
}
return($this->SetError('unexpected decoded message part type '.$type.' in state '.$state));
}
return(1);
}
 
/* Public functions */
 
Function Parse($data, $end)
{
if(strlen($this->error))
return(0);
if($this->state==MIME_PARSER_END)
return($this->SetError('the parser already reached the end'));
$this->buffer .= $data;
do
{
Unset($part);
if(!$this->ParsePart($end, $part, $need_more_data))
return(0);
if(IsSet($part)
&& !$this->DecodePart($part))
return(0);
}
while(!$need_more_data
&& $this->state!=MIME_PARSER_END);
if($end
&& $this->state!=MIME_PARSER_END)
return($this->SetError('reached a premature end of data'));
if($this->buffer_position>0)
{
$this->offset += $this->buffer_position;
$this->buffer = substr($this->buffer, $this->buffer_position);
$this->buffer_position = 0;
}
return(1);
}
 
Function ParseFile($file)
{
if(strlen($this->error))
return(0);
if(!($stream = @fopen($file, 'r')))
return($this->SetPHPError('Could not open the file '.$file, $php_errormsg));
for($end = 0;!$end;)
{
if(!($data = @fread($stream, $this->message_buffer_length)))
{
$this->SetPHPError('Could not open the file '.$file, $php_errormsg);
fclose($stream);
return(0);
}
$end=feof($stream);
if(!$this->Parse($data, $end))
{
fclose($stream);
return(0);
}
}
fclose($stream);
return(1);
}
 
Function GetPart(&$part, &$end)
{
$end = ($this->part_position >= count($this->parts));
if($end)
{
if($this->part_position)
{
$this->part_position = 0;
$this->parts = array();
}
}
else
{
$part = $this->parts[$this->part_position];
$this->part_position ++;
}
return(1);
}
 
/*
{metadocument}
<function>
<name>Decode</name>
<type>BOOLEAN</type>
<documentation>
<purpose>Parse and decode message data and retrieve its structure.</purpose>
<usage>Pass an array to the <argumentlink>
<function>Decode</function>
<argument>parameters</argument>
</argumentlink>
parameter to define whether the message data should be read and
parsed from a file or a data string, as well additional parsing
options. The <argumentlink>
<function>Decode</function>
<argument>decoded</argument>
</argumentlink> returns the
data structure of the parsed messages.</usage>
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
the specified message data is parsed successfully. Otherwise,
check the variables <variablelink>error</variablelink> and
<variablelink>error_position</variablelink> to determine what
error occurred and the relevant message position.</returnvalue>
</documentation>
<argument>
<name>parameters</name>
<type>HASH</type>
<documentation>
<purpose>Associative array to specify parameters for the message
data parsing and decoding operation. Here follows the list of
supported parameters that should be used as indexes of the
array:<paragraphbreak />
<tt>File</tt><paragraphbreak />
Name of the file from which the message data will be read. It
may be the name of a file stream or a remote URL, as long as
your PHP installation is configured to allow accessing remote
files with the <tt>fopen()</tt> function.<paragraphbreak />
<tt>Data</tt><paragraphbreak />
String that specifies the message data. This should be used
as alternative data source for passing data available in memory,
like for instance messages stored in a database that was queried
dynamically and the message data was fetched into a string
variable.<paragraphbreak />
<tt>SaveBody</tt><paragraphbreak />
If this parameter is specified, the message body parts are saved
to files. The path of the directory where the files are saved is
defined by this parameter value. The information about the
message body part structure is returned by the <argumentlink>
<function>Decode</function>
<argument>decoded</argument>
</argumentlink> argument, but it just returns the body data part
file name instead of the actual body data. It is recommended for
retrieving messages larger than the available memory. The names
of the body part files are numbers starting from
<stringvalue>1</stringvalue>.<paragraphbreak />
<tt>SkipBody</tt><paragraphbreak />
If this parameter is specified, the message body parts are
skipped. This means the information about the message body part
structure is returned by the <argumentlink>
<function>Decode</function>
<argument>decoded</argument>
</argumentlink> but it does not return any body data. It is
recommended just for parsing messages without the need to
retrieve the message body part data.</purpose>
</documentation>
</argument>
<argument>
<name>decoded</name>
<type>ARRAY</type>
<out />
<documentation>
<purpose>Retrieve the structure of the parsed message headers and
body data.<paragraphbreak />
The argument is used to return by reference an array of message
structure definitions. Each array entry refers to the structure
of each message that is found and parsed successfully.<paragraphbreak />
Each message entry consists of an associative array with several
entries that describe the message structure. Here follows the
list of message structure entries names and the meaning of the
respective values:<paragraphbreak />
<tt>Headers</tt><paragraphbreak />
Associative array that returns the list of all the message
headers. The array entries are the header names mapped to
lower case, including the end colon. The array values are the
respective header raw values without any start or trailing white
spaces. Long header values split between multiple message lines
are gathered in single string without line breaks. If an header
with the same name appears more than once in the message, the
respective value is an array with the values of all of the
header occurrences.<paragraphbreak />
<tt>DecodedHeaders</tt><paragraphbreak />
Associative array that returns the list of all the encoded
message headers when the
<variablelink>decode_headers</variablelink> variable is set. The
array entries are the header names mapped to lower case,
including the end colon. The array values are also arrays that
list only the occurrences of the header that originally were
encoded. Each entry of the decoded header array contains more
associative arrays that describe each part of the decoded
header. Each of those associative arrays have an entry named
<tt>Value</tt> that contains the decoded header part value, and
another entry named <tt>Encoding</tt> that specifies the
character set encoding of the value in upper case.<paragraphbreak />
<tt>ExtractedAddresses</tt><paragraphbreak />
If the <variablelink>extract_addresses</variablelink> variable
is set to <booleanvalue>1</booleanvalue>, this entry is set to an
associative array with the addresses found in the headers
specified by the <variablelink>address_headers</variablelink>
variable.<paragraphbreak />
The parsed addresses found on each header are returned as an
array with the format of the <link>
<data>addresses</data>
<url>rfc822_addresses_class.html#argument_ParseAddressList_addresses</url>
</link> argument of the <link>
<data>ParseAddressList</data>
<url>rfc822_addresses_class.html#function_ParseAddressList</url>
</link> function of the <link>
<data>RFC 822 addresses</data>
<url>rfc822_addresses_class.html</url>
</link> class.<paragraphbreak />
<tt>Parts</tt><paragraphbreak />
If this message content type is multipart, this entry is an
array that describes each of the parts contained in the message
body. Each message part is described by an associative array
with the same structure of a complete message
definition.<paragraphbreak />
<tt>Body</tt><paragraphbreak />
String with the decoded data contained in the message body. If
the <tt>SaveBody</tt> or <tt>SkipBody</tt> parameters are
defined, the <tt>Body</tt> entry is not set.<paragraphbreak />
<tt>BodyFile</tt><paragraphbreak />
Name of the file to which the message body data was saved when
the <tt>SaveBody</tt> parameter is defined.<paragraphbreak />
<tt>BodyLength</tt><paragraphbreak />
Length of the current decoded body part.<paragraphbreak />
<tt>BodyPart</tt><paragraphbreak />
Number of the current message body part.<paragraphbreak />
<tt>FileName</tt><paragraphbreak />
Name of the file for body parts composed from
files.<paragraphbreak />
<tt>FileNameCharacterSet</tt><paragraphbreak />
Character set encoding for file parts with names that may
include non-ASCII characters.<paragraphbreak />
<tt>FileNameLanguage</tt><paragraphbreak />
Language of file parts with names that may include non-ASCII
characters.<paragraphbreak />
<tt>FileDisposition</tt><paragraphbreak />
Disposition of parts that files. It may be either
<tt><stringvalue>inline</stringvalue></tt> for file parts to be
displayed with the message, or
<tt><stringvalue>attachment</stringvalue></tt> otherwise.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function Decode($parameters, &$decoded)
{
if(IsSet($parameters['File']))
{
if(!($this->file = @fopen($parameters['File'], 'r')))
return($this->SetPHPError('could not open the message file to decode '.$parameters['File'], $php_errormsg));
}
elseif(IsSet($parameters['Data']))
$this->position = 0;
else
return($this->SetError('it was not specified a valid message to decode'));
$this->warnings = $decoded = array();
$this->ResetParserState();
$addresses = new rfc822_addresses_class;
$addresses->ignore_syntax_errors = $this->ignore_syntax_errors;
for($message = 0; ($success = $this->DecodeStream($parameters, $end_of_message, $decoded_message)) && !$end_of_message; $message++)
{
if($this->extract_addresses)
{
$headers = $decoded_message['Headers'];
$positions = $decoded_message['HeaderPositions'];
$th = count($headers);
for(Reset($headers), $h = 0; $h<$th; Next($headers), ++$h)
{
$header = Key($headers);
if(IsSet($this->address_headers[$header])
&& $this->address_headers[$header])
{
$values = (GetType($headers[$header]) == 'array' ? $headers[$header] : array($headers[$header]));
$p = (GetType($positions[$header]) == 'array' ? $positions[$header] : array($positions[$header]));
$tv = count($values);
for($v = 0; $v<$tv; ++$v)
{
if($addresses->ParseAddressList($values[$v], $a))
{
if($v==0)
$decoded_message['ExtractedAddresses'][$header] = $a;
else
{
$tl = count($a);
for($l = 0; $l<$tl; ++$l)
$decoded_message['ExtractedAddresses'][$header][] = $a[$l];
}
$tw = count($addresses->warnings);
for($w = 0, Reset($addresses->warnings); $w < $tw; Next($addresses->warnings), $w++)
{
$warning = Key($addresses->warnings);
if(!$this->SetPositionedWarning('Address extraction warning from header '.$header.' '.$addresses->warnings[$warning], $warning + $p[$v]))
return(0);
}
}
elseif(!$this->SetPositionedWarning('Address extraction error from header '.$header.' '.$addresses->error, $addresses->error_position + $p[$v]))
return(0);
}
}
}
UnSet($decoded_message['HeaderPositions']);
}
$decoded[$message]=$decoded_message;
}
if(IsSet($parameters['File']))
fclose($this->file);
return($success);
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
 
Function CopyAddresses($message, &$results, $header)
{
if(!IsSet($message['Headers'][$header]))
return;
if(!IsSet($message['ExtractedAddresses'][$header]))
{
$parser = new rfc822_addresses_class;
$parser->ignore_syntax_errors = $this->ignore_syntax_errors;
$values = (GetType($message['Headers'][$header]) == 'array' ? $message['Headers'][$header] : array($message['Headers'][$header]));
$tv = count($values);
$addresses = array();
for($v = 0; $v<$tv; ++$v)
{
if($parser->ParseAddressList($values[$v], $a))
{
if($v==0)
$addresses = $a;
else
{
$tl = count($a);
for($l = 0; $l<$tl; ++$l)
$addresses[] = $a[$l];
}
}
}
}
else
$addresses = $message['ExtractedAddresses'][$header];
if(count($addresses))
$results[ucfirst(substr($header, 0, strlen($header) -1))] = $addresses;
}
 
Function ReadMessageBody($message, &$body, $prefix)
{
if(IsSet($message[$prefix]))
$body = $message[$prefix];
elseif(IsSet($message[$prefix.'File']))
{
$path = $message[$prefix.'File'];
if(!($file = @fopen($path, 'rb')))
return($this->SetPHPError('could not open the message body file '.$path, $php_errormsg));
for($body = '', $end = 0;!$end;)
{
if(!($data = @fread($file, $this->message_buffer_length)))
{
$this->SetPHPError('Could not open the message body file '.$path, $php_errormsg);
fclose($stream);
return(0);
}
$end=feof($file);
$body.=$data;
}
fclose($file);
}
else
$body = '';
return(1);
}
/*
{metadocument}
<function>
<name>Analyze</name>
<type>BOOLEAN</type>
<documentation>
<purpose>Analyze a parsed message to describe its contents.</purpose>
<usage>Pass an array to the <argumentlink>
<function>Analyze</function>
<argument>message</argument>
</argumentlink>
parameter with the decoded message array structure returned by the
<functionlink>Decode</functionlink> function. The <argumentlink>
<function>Analyze</function>
<argument>results</argument>
</argumentlink> returns details about the type of message that was
analyzed and its contents.</usage>
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
the specified message is analyzed successfully. Otherwise,
check the variables <variablelink>error</variablelink> and
<variablelink>error_position</variablelink> to determine what
error occurred.</returnvalue>
</documentation>
<argument>
<name>message</name>
<type>HASH</type>
<documentation>
<purpose>Pass an associative array with the definition of an
individual message returned by the <argumentlink>
<function>Decode</function>
<argument>decoded</argument>
</argumentlink> argument of the
<functionlink>Decode</functionlink> function..</purpose>
</documentation>
</argument>
<argument>
<name>results</name>
<type>HASH</type>
<out />
<documentation>
<purpose>Returns an associative array with the results of the
analysis. Some types of entries are returned for all types of
analyzed messages. Other entries are specific to each type of
message.<paragraphbreak />
<tt>Type</tt><paragraphbreak />
Type of message that was analyzed. Currently it supports the
types: <tt>binary</tt>, <tt>text</tt>, <tt>html</tt>,
<tt>video</tt>, <tt>image</tt>, <tt>audio</tt>, <tt>zip</tt>,
<tt>pdf</tt>, <tt>postscript</tt>, <tt>ms-word</tt>,
<tt>ms-excel</tt>, <tt>ms-powerpoint</tt>, <tt>ms-tnef</tt>,
<tt>odf-writer</tt>, <tt>signature</tt>, <tt>report-type</tt>,
<tt>delivery-status</tt> and <tt>message</tt>.<paragraphbreak />
<tt>SubType</tt><paragraphbreak />
Name of the variant of the message type format.<paragraphbreak />
<tt>Description</tt><paragraphbreak />
Human readable description in English of the message type.<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<b>From message headers:</b><paragraphbreak />
<tt>Encoding</tt><paragraphbreak />
Character set encoding of the message part.<paragraphbreak />
<tt>Subject</tt><paragraphbreak />
The message subject.<paragraphbreak />
<tt>SubjectEncoding</tt><paragraphbreak />
Character set encoding of the message subject.<paragraphbreak />
<tt>Date</tt><paragraphbreak />
The message date.<paragraphbreak />
<tt>From</tt><paragraphbreak />
<tt>To</tt><paragraphbreak />
<tt>Cc</tt><paragraphbreak />
<tt>Bcc</tt><paragraphbreak />
Array of e-mail addresses found in the <tt>From</tt>,
<tt>To</tt>, <tt>Cc</tt>, <tt>Bcc</tt>.<paragraphbreak />
Each of the entries consists of an associative array with an
entry named <tt>address</tt> with the e-mail address and
optionally another named <tt>name</tt> with the associated
name.<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<b>For content message parts:</b><paragraphbreak />
<paragraphbreak />
<tt>Data</tt><paragraphbreak />
String of data of the message part.<paragraphbreak />
<tt>DataFile</tt><paragraphbreak />
File with data of the message part.<paragraphbreak />
<tt>DataLength</tt><paragraphbreak />
Length of the data of the message part.<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<b>For message with embedded files:</b><paragraphbreak />
<paragraphbreak />
<tt>FileName</tt><paragraphbreak />
Original name of the file.<paragraphbreak />
<tt>ContentID</tt><paragraphbreak />
Content identifier of the file to be used in references from
other message parts.<paragraphbreak />
For instance, an HTML message may reference images embedded in
the message using URLs that start with the
<stringvalue>cid:</stringvalue> followed by the content
identifier of the embedded image file part.<paragraphbreak />
<tt>Disposition</tt><paragraphbreak />
Information of whether the embedded file should be displayed
inline when the message is presented, or it is an attachment
file.<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<b>For composite message:</b><paragraphbreak />
<paragraphbreak />
<tt>Attachments</tt><paragraphbreak />
List of files attached to the message.<paragraphbreak />
<tt>Alternative</tt><paragraphbreak />
List of alternative message parts that can be displayed if the
main message type is not supported by the program displaying
the message.<paragraphbreak />
<tt>Related</tt><paragraphbreak />
List of message parts related with the main message type.<paragraphbreak />
It may list for instance embedded images or CSS files related
with an HTML message type.<paragraphbreak />
<paragraphbreak />
<paragraphbreak />
<b>For bounced messages or other types of delivery status report
messages:</b><paragraphbreak />
<paragraphbreak />
<tt>Recipients</tt><paragraphbreak />
List of recipients of the original message.<paragraphbreak />
Each entry contains an associative array that may have the
entries: <tt>Recipient</tt> with the original recipient address,
<tt>Action</tt> with the name action that triggered the delivery
status report, <tt>Status</tt> with the code of the status of
the message delivery.<paragraphbreak />
<tt>Response</tt><paragraphbreak />
Human readable response sent by the server the originated the
report.<paragraphbreak />
</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function Analyze($message, &$results)
{
$results = array();
if(!IsSet($message['Headers']['content-type:']))
$content_type = 'text/plain';
elseif(count($message['Headers']['content-type:']) == 1)
$content_type = $message['Headers']['content-type:'];
else
{
if(!$this->SetPositionedWarning('message contains multiple content-type headers', 0))
return(0);
$content_type = $message['Headers']['content-type:'][0];
}
$disposition = $this->ParseParameters($content_type, $content_type, $parameters, 'disposition');
$type = $this->Tokenize($content_type, '/');
$sub_type = $this->Tokenize(';');
$copy_body = 1;
$tolerate_unrecognized = 1;
switch($type)
{
case 'multipart':
$tolerate_unrecognized = 0;
$copy_body = 0;
$lp = count($message['Parts']);
if($lp == 0)
return($this->SetError($this->decode_bodies ? 'No parts were found in the '.$content_type.' part message' : 'It is not possible to analyze multipart messages without parsing the contained message parts. Please set the decode_bodies variable to 1 before parsing the message'));
$parts = array();
for($p = 0; $p < $lp; ++$p)
{
if(!$this->Analyze($message['Parts'][$p], $parts[$p]))
return(0);
}
switch($sub_type)
{
case 'alternative':
$p = $lp;
$results = $parts[--$p];
for(--$p ; $p >=0 ; --$p)
$results['Alternative'][] = $parts[$p];
break;
 
case 'related':
$results = $parts[0];
for($p = 1; $p < $lp; ++$p)
$results['Related'][] = $parts[$p];
break;
 
case 'mixed':
$results = $parts[0];
for($p = 1; $p < $lp; ++$p)
$results['Attachments'][] = $parts[$p];
break;
 
case 'report':
if(IsSet($parameters['report-type']))
{
switch($parameters['report-type'])
{
case 'delivery-status':
for($p = 1; $p < $lp; ++$p)
{
if(!strcmp($parts[$p]['Type'], $parameters['report-type']))
{
$results = $parts[$p];
break;
}
}
if(!$this->ReadMessageBody($parts[0], $body, 'Data'))
return(0);
if(strlen($body))
$results['Response'] = $body;
break;
}
}
$results['Type'] = $parameters['report-type'];
break;
 
case 'signed':
if($lp != 2)
return($this->SetError('this '.$content_type.' message does not have just 2 parts'));
if(strcmp($parts[1]['Type'], 'signature'))
{
$this->SetErrorWithContact('this '.$content_type.' message does not contain a signature');
$this->error = '';
}
$results = $parts[0];
$results['Signature'] = $parts[1];
break;
}
break;
case 'text':
switch($sub_type)
{
case 'plain':
$results['Type'] = 'text';
$results['Description'] = 'Text message';
break;
case 'html':
$results['Type'] = 'html';
$results['Description'] = 'HTML message';
break;
default:
$results['Type'] = $type;
$results['SubType'] = $sub_type;
$results['Description'] = 'Text file in the '.strtoupper($sub_type).' format';
break;
}
break;
case 'video':
$results['Type'] = $type;
$results['SubType'] = $sub_type;
$results['Description'] = 'Video file in the '.strtoupper($sub_type).' format';
break;
case 'image':
$results['Type'] = $type;
$results['SubType'] = $sub_type;
$results['Description'] = 'Image file in the '.strtoupper($sub_type).' format';
break;
case 'audio':
$results['Type'] = $type;
$results['SubType'] = $sub_type;
$results['Description'] = 'Audio file in the '.strtoupper($sub_type).' format';
break;
case 'application':
switch($sub_type)
{
case 'octet-stream':
case 'x-msdownload':
$results['Type'] = 'binary';
$results['Description'] = 'Binary file';
break;
case 'pdf':
$results['Type'] = $sub_type;
$results['Description'] = 'Document in PDF format';
break;
case 'postscript':
$results['Type'] = $sub_type;
$results['Description'] = 'Document in Postscript format';
break;
case 'msword':
$results['Type'] = 'ms-word';
$results['Description'] = 'Word processing document in Microsoft Word format';
break;
case 'vnd.ms-powerpoint':
$results['Type'] = 'ms-powerpoint';
$results['Description'] = 'Presentation in Microsoft PowerPoint format';
break;
case 'vnd.ms-excel':
$results['Type'] = 'ms-excel';
$results['Description'] = 'Spreadsheet in Microsoft Excel format';
break;
case 'zip':
case 'x-zip':
case 'x-zip-compressed':
$results['Type'] = 'zip';
$results['Description'] = 'ZIP archive with compressed files';
break;
case 'ms-tnef':
$results['Type'] = $sub_type;
$results['Description'] = 'Microsoft Exchange data usually sent by Microsoft Outlook';
break;
case 'pgp-signature':
$results['Type'] = 'signature';
$results['SubType'] = $sub_type;
$results['Description'] = 'Message signature for PGP';
break;
case 'x-pkcs7-signature':
case 'pkcs7-signature':
$results['Type'] = 'signature';
$results['SubType'] = $sub_type;
$results['Description'] = 'PKCS message signature';
break;
case 'vnd.oasis.opendocument.text':
$results['Type'] = 'odf-writer';
$results['Description'] = 'Word processing document in ODF text format used by OpenOffice Writer';
break;
}
break;
case 'message':
$tolerate_unrecognized = 0;
switch($sub_type)
{
case 'delivery-status':
$results['Type'] = $sub_type;
$results['Description'] = 'Notification of the status of delivery of a message';
if(!$this->ReadMessageBody($message, $body, 'Body'))
return(0);
if(($l = strlen($body)))
{
$position = 0;
$this->ParseHeaderString($body, $position, $headers);
$recipients = array();
for(;$position<$l;)
{
$this->ParseHeaderString($body, $position, $headers);
if(count($headers))
{
$r = count($recipients);
if(IsSet($headers['action']))
$recipients[$r]['Action'] = $headers['action'];
if(IsSet($headers['status']))
$recipients[$r]['Status'] = $headers['status'];
if(IsSet($headers['original-recipient']))
{
strtok($headers['original-recipient'], ';');
$recipients[$r]['Address'] = trim(strtok(''));
}
elseif(IsSet($headers['final-recipient']))
{
strtok($headers['final-recipient'], ';');
$recipients[$r]['Address'] = trim(strtok(''));
}
}
}
$results['Recipients'] = $recipients;
}
$copy_body = 0;
break;
case 'rfc822':
$results['Type'] = 'message';
$results['Description'] = 'E-mail message';
break;
}
break;
default:
$tolerate_unrecognized = 0;
break;
}
if(!IsSet($results['Type']))
{
$this->SetErrorWithContact($content_type.' message parts are not yet recognized');
$results['Type'] = $this->error;
$this->error = '';
}
if(IsSet($parameters['charset']))
$results['Encoding'] = strtolower($parameters['charset']);
if(IsSet($message['Headers']['subject:']))
{
if(IsSet($message['DecodedHeaders']['subject:'])
&& count($message['DecodedHeaders']['subject:']) == 1
&& count($message['DecodedHeaders']['subject:'][0]) == 1)
{
$results['Subject'] = $message['DecodedHeaders']['subject:'][0][0]['Value'];
$results['SubjectEncoding'] = strtolower($message['DecodedHeaders']['subject:'][0][0]['Encoding']);
}
else
$results['Subject'] = $message['Headers']['subject:'];
}
if(IsSet($message['Headers']['date:']))
{
if(IsSet($message['DecodedHeaders']['date:'])
&& count($message['DecodedHeaders']['date:']) == 1
&& count($message['DecodedHeaders']['date:'][0]) == 1)
$results['Date'] = $message['DecodedHeaders']['date:'][0][0]['Value'];
else
$results['Date'] = $message['Headers']['date:'];
}
$l = count($this->address_headers);
for(Reset($this->address_headers), $h = 0; $h<$l; Next($this->address_headers), ++$h)
$this->CopyAddresses($message, $results, Key($this->address_headers));
if($copy_body)
{
if(IsSet($message['Body']))
$results['Data'] = $message['Body'];
elseif(IsSet($message['BodyFile']))
$results['DataFile'] = $message['BodyFile'];
elseif(IsSet($message['BodyLength']))
$results['DataLength'] = $message['BodyLength'];
if(IsSet($message['FileName']))
$results['FileName'] = $message['FileName'];
if(IsSet($message['FileDisposition']))
$results['FileDisposition'] = $message['FileDisposition'];
if(IsSet($message['Headers']['content-id:']))
{
$content_id = trim($message['Headers']['content-id:']);
$l = strlen($content_id);
if(!strcmp($content_id[0], '<')
&& !strcmp($content_id[$l - 1], '>'))
$results['ContentID'] = substr($content_id, 1, $l - 2);
}
}
return(1);
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
 
};
 
/*
 
{metadocument}
</class>
{/metadocument}
 
*/
 
?>
/trunk/plugins/mail2wordpress/lib/rfc822_addresses.php
0,0 → 1,902
<?php
/*
* rfc822_addresses.php
*
* @(#) $Id: rfc822_addresses.php,v 1.12 2008/12/13 02:46:09 mlemos Exp $
*
*/
 
/*
{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
<class>
 
<package>net.manuellemos.mimeparser</package>
 
<version>@(#) $Id: rfc822_addresses.php,v 1.12 2008/12/13 02:46:09 mlemos Exp $</version>
<copyright>Copyright © (C) Manuel Lemos 2006 - 2008</copyright>
<title>RFC 822 e-mail addresses parser</title>
<author>Manuel Lemos</author>
<authoraddress>mlemos-at-acm.org</authoraddress>
 
<documentation>
<idiom>en</idiom>
<purpose>Parse e-mail addresses from headers of <link>
<url>http://www.ietf.org/rfc/rfc822.txt</url>
<data>RFC 822</data>
</link> compliant e-mail messages.</purpose>
<usage>Use the function <functionlink>ParseAddressList</functionlink>
function to retrieve the list of e-mail addresses contained in
e-mail message headers like <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt>
or <tt>Bcc</tt>.</usage>
</documentation>
 
{/metadocument}
*/
 
class rfc822_addresses_class
{
/* Private variables */
 
var $v = '';
 
/* Public variables */
 
/*
{metadocument}
<variable>
<name>error</name>
<type>STRING</type>
<value></value>
<documentation>
<purpose>Store the message that is returned when an error
occurs.</purpose>
<usage>Check this variable to understand what happened when a call to
any of the class functions has failed.<paragraphbreak />
This class uses cumulative error handling. This means that if one
class functions that may fail is called and this variable was
already set to an error message due to a failure in a previous call
to the same or other function, the function will also fail and does
not do anything.<paragraphbreak />
This allows programs using this class to safely call several
functions that may fail and only check the failure condition after
the last function call.<paragraphbreak />
Just set this variable to an empty string to clear the error
condition.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error = '';
 
/*
{metadocument}
<variable>
<name>error_position</name>
<type>INTEGER</type>
<value>-1</value>
<documentation>
<purpose>Point to the position of the message data or file that
refers to the last error that occurred.</purpose>
<usage>Check this variable to determine the relevant position of the
message when a parsing error occurs.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error_position = -1;
 
/*
{metadocument}
<variable>
<name>ignore_syntax_errors</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Specify whether the class should ignore syntax errors in
malformed addresses.</purpose>
<usage>Set this variable to <booleanvalue>0</booleanvalue> if it is
necessary to verify whether message data may be corrupted due to
to eventual bugs in the program that generated the
message.<paragraphbreak />
Currently the class only ignores some types of syntax errors.
Other syntax errors may still cause the
<functionlink>ParseAddressList</functionlink> to fail.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $ignore_syntax_errors=1;
 
/*
{metadocument}
<variable>
<name>warnings</name>
<type>HASH</type>
<value></value>
<documentation>
<purpose>Return a list of positions of the original message that
contain syntax errors.</purpose>
<usage>Check this variable to retrieve eventual message syntax
errors that were ignored when the
<variablelink>ignore_syntax_errors</variablelink> is set to
<booleanvalue>1</booleanvalue>.<paragraphbreak />
The indexes of this array are the positions of the errors. The
array values are the corresponding syntax error messages.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $warnings=array();
 
/* Private functions */
 
Function SetError($error)
{
$this->error = $error;
return(0);
}
 
Function SetPositionedError($error, $position)
{
$this->error_position = $position;
return($this->SetError($error));
}
 
Function SetWarning($warning, $position)
{
$this->warnings[$position]=$warning;
return(1);
}
 
Function SetPositionedWarning($error, $position)
{
if(!$this->ignore_syntax_errors)
return($this->SetPositionedError($error, $position));
return($this->SetWarning($error, $position));
}
 
Function QDecode($p, &$value, &$encoding)
{
$encoding = $charset = null;
$s = 0;
$decoded = '';
$l = strlen($value);
while($s < $l)
{
if(GetType($q = strpos($value, '=?', $s)) != 'integer')
{
if($s == 0)
return(1);
if($s < $l)
$decoded .= substr($value, $s);
break;
}
if($s < $q)
$decoded .= substr($value, $s, $q - $s);
$q += 2;
if(GetType($c = strpos($value, '?', $q)) != 'integer'
|| $q == $c)
return($this->SetPositionedWarning('invalid Q-encoding character set', $p + $q));
if(IsSet($charset))
{
$another_charset = strtolower(substr($value, $q, $c - $q));
if(strcmp($charset, $another_charset)
&& strcmp($another_charset, 'ascii'))
return($this->SetWarning('it is not possible to decode an encoded value using mixed character sets into a single value', $p + $q));
}
else
{
$charset = strtolower(substr($value, $q, $c - $q));
if(!strcmp($charset, 'ascii'))
$charset = null;
}
++$c;
if(GetType($t = strpos($value, '?', $c)) != 'integer'
|| $c==$t)
return($this->SetPositionedWarning('invalid Q-encoding type', $p + $c));
$type = strtolower(substr($value, $c, $t - $c));
++$t;
if(GetType($e = strpos($value, '?=', $t)) != 'integer')
return($this->SetPositionedWarning('invalid Q-encoding encoded data', $p + $e));
switch($type)
{
case 'q':
for($s = $t; $s<$e;)
{
switch($b = $value[$s])
{
case '=':
$h = HexDec($hex = strtolower(substr($value, $s + 1, 2)));
if($s + 3 > $e
|| strcmp(sprintf('%02x', $h), $hex))
return($this->SetPositionedWarning('invalid Q-encoding q encoded data', $p + $s));
$decoded .= chr($h);
$s += 3;
break;
 
case '_':
$decoded .= ' ';
++$s;
break;
 
default:
$decoded .= $b;
++$s;
}
}
break;
 
case 'b':
if($e <= $t
|| strlen($binary = base64_decode($data = substr($value, $t, $e - $t))) == 0
|| GetType($binary) != 'string')
return($this->SetPositionedWarning('invalid Q-encoding b encoded data', $p + $t));
$decoded .= $binary;
$s = $e;
break;
 
default:
return($this->SetPositionedWarning('Q-encoding '.$type.' is not yet supported', $p + $c));
}
$s += 2;
}
$value = $decoded;
$encoding = $charset;
return(1);
}
 
Function ParseCText(&$p, &$c_text)
{
$c_text = null;
$v = $this->v;
if($p<strlen($v)
&& GetType(strchr("\t\r\n ()\\\0", $c = $v[$p])) != 'string'
&& Ord($c)<128)
{
$c_text = $c;
++$p;
}
return(1);
}
 
Function ParseQText(&$p, &$q_text)
{
$q_text = null;
$v = $this->v;
if($p>strlen($v)
|| GetType(strchr("\t\r\n \"\\\0", $c = $v[$p])) == 'string')
return(1);
if(Ord($c) >= 128)
{
if(!$this->ignore_syntax_errors)
return(1);
$this->SetPositionedWarning('it was used an unencoded 8 bit character', $p);
}
$q_text = $c;
++$p;
return(1);
}
 
Function ParseQuotedPair(&$p, &$quoted_pair)
{
$quoted_pair = null;
$v = $this->v;
$l = strlen($v);
if($p+1 < $l
&& !strcmp($v[$p], '\\')
&& GetType(strchr("\r\n\0", $c = $v[$p + 1])) != 'string'
&& Ord($c)<128)
{
$quoted_pair = $c;
$p += 2;
}
return(1);
}
 
Function ParseCContent(&$p, &$c_content)
{
$c_content = null;
$c = $p;
if(!$this->ParseQuotedPair($c, $content))
return(0);
if(!IsSet($content))
{
if(!$this->ParseCText($c, $content))
return(0);
if(!IsSet($content))
{
if(!$this->ParseComment($c, $content))
return(0);
if(!IsSet($content))
return(1);
}
}
$c_content = $content;
$p = $c;
return(1);
}
 
Function SkipWhiteSpace(&$p)
{
$v = $this->v;
$l = strlen($v);
for(;$p<$l; ++$p)
{
switch($v[$p])
{
case ' ':
case "\n":
case "\r":
case "\t":
break;
default:
return(1);
}
}
return(1);
}
 
Function ParseComment(&$p, &$comment)
{
$comment = null;
$v = $this->v;
$l = strlen($v);
$c = $p;
if($c >= $l
|| strcmp($v[$c], '('))
return(1);
++$c;
for(; $c < $l;)
{
if(!$this->SkipWhiteSpace($c))
return(0);
if(!$this->ParseCContent($c, $c_content))
return(0);
if(!IsSet($c_content))
break;
}
if(!$this->SkipWhiteSpace($c))
return(0);
if($c >= $l
|| strcmp($v[$c], ')'))
return(1);
++$c;
$comment = substr($v, $p, $c - $p);
$p = $c;
return(1);
}
 
Function SkipCommentGetWhiteSpace(&$p, &$space)
{
$v = $this->v;
$l = strlen($v);
for($space = '';$p<$l;)
{
switch($w = $v[$p])
{
case ' ':
case "\n":
case "\r":
case "\t":
++$p;
$space .= $w;
break;
case '(':
if(!$this->ParseComment($p, $comment))
return(0);
default:
return(1);
}
}
return(1);
}
 
Function SkipCommentWhiteSpace(&$p)
{
$v = $this->v;
$l = strlen($v);
for(;$p<$l;)
{
switch($w = $v[$p])
{
case ' ':
case "\n":
case "\r":
case "\t":
++$p;
break;
case '(':
if(!$this->ParseComment($p, $comment))
return(0);
default:
return(1);
}
}
return(1);
}
 
Function ParseQContent(&$p, &$q_content)
{
$q_content = null;
$q = $p;
if(!$this->ParseQuotedPair($q, $content))
return(0);
if(!IsSet($content))
{
if(!$this->ParseQText($q, $content))
return(0);
if(!IsSet($content))
return(1);
}
$q_content = $content;
$p = $q;
return(1);
}
 
Function ParseAtom(&$p, &$atom, $dot)
{
$atom = null;
$v = $this->v;
$l = strlen($v);
$a = $p;
if(!$this->SkipCommentGetWhiteSpace($a, $space))
return(0);
$match = '/^([-'.($dot ? '.' : '').'A-Za-z0-9!#$&\'*+\\/=?^_{|}~]+)/';
for($s = $a;$a < $l;)
{
if(preg_match($match, substr($this->v, $a), $m))
$a += strlen($m[1]);
elseif(Ord($v[$a]) < 128)
break;
elseif(!$this->SetPositionedWarning('it was used an unencoded 8 bit character', $a))
return(0);
else
++$a;
}
if($s == $a)
return(1);
$atom = $space.substr($this->v, $s, $a - $s);
if(!$this->SkipCommentGetWhiteSpace($a, $space))
return(0);
$atom .= $space;
$p = $a;
return(1);
}
 
Function ParseQuotedString(&$p, &$quoted_string)
{
$quoted_string = null;
$v = $this->v;
$l = strlen($v);
$s = $p;
if(!$this->SkipCommentWhiteSpace($s))
return(0);
if($s >= $l
|| strcmp($v[$s], '"'))
return(1);
++$s;
for($string = '';$s < $l;)
{
$w = $s;
if(!$this->SkipWhiteSpace($s))
return(0);
if($w != $s)
$string .= substr($v, $w, $s - $w);
if(!$this->ParseQContent($s, $q_content))
return(0);
if(!IsSet($q_content))
break;
$string .= $q_content;
}
$w = $s;
if(!$this->SkipWhiteSpace($s))
return(0);
if($w != $s)
$string .= substr($v, $w, $s - $w);
if($s >= $l
|| strcmp($v[$s], '"'))
return(1);
++$s;
if(!$this->SkipCommentWhiteSpace($s))
return(0);
$quoted_string = $string;
$p = $s;
return(1);
}
 
Function ParseWord(&$p, &$word)
{
$word = null;
if(!$this->ParseQuotedString($p, $word))
return(0);
if(IsSet($word))
return(1);
if(!$this->ParseAtom($p, $word, 0))
return(0);
return(1);
}
 
Function ParseObsPhrase(&$p, &$obs_phrase)
{
$obs_phrase = null;
$v = $this->v;
$l = strlen($v);
$ph = $p;
if(!$this->ParseWord($ph, $word))
return(0);
$string = $word;
for(;;)
{
if(!$this->ParseWord($ph, $word))
return(0);
if(IsSet($word))
{
$string .= $word;
continue;
}
$w = $ph;
if(!$this->SkipCommentGetWhiteSpace($ph, $space))
return(0);
if($w != $ph)
{
$string .= $space;
continue;
}
if($ph >= $l
|| strcmp($v[$ph], '.'))
break;
$string .= '.';
++$ph;
}
$obs_phrase = $string;
$p = $ph;
return(1);
}
 
Function ParsePhrase(&$p, &$phrase)
{
$phrase = null;
if(!$this->ParseObsPhrase($p, $phrase))
return(0);
if(IsSet($phrase))
return(1);
$ph = $p;
if(!$this->ParseWord($ph, $word))
return(0);
$string = $word;
for(;;)
{
if(!$this->ParseWord($ph, $word))
return(0);
if(!IsSet($word))
break;
$string .= $word;
}
$phrase = $string;
$p = $ph;
return(1);
}
 
Function ParseAddrSpec(&$p, &$addr_spec)
{
$addr_spec = null;
$v = $this->v;
$l = strlen($v);
$a = $p;
if(!$this->ParseQuotedString($a, $local_part))
return(0);
if(!IsSet($local_part))
{
if(!$this->ParseAtom($a, $local_part, 1))
return(0);
$local_part = trim($local_part);
}
if($a >= $l
|| strcmp($v[$a], '@'))
return(1);
++$a;
if(!$this->ParseAtom($a, $domain, 1))
return(0);
if(!IsSet($domain))
return(1);
$addr_spec = $local_part.'@'.trim($domain);
$p = $a;
return(1);
}
 
Function ParseAngleAddr(&$p, &$addr)
{
$addr = null;
$v = $this->v;
$l = strlen($v);
$a = $p;
if(!$this->SkipCommentWhiteSpace($a))
return(0);
if($a >= $l
|| strcmp($v[$a], '<'))
return(1);
++$a;
if(!$this->ParseAddrSpec($a, $addr_spec))
return(0);
if($a >= $l
|| strcmp($v[$a], '>'))
return(1);
++$a;
if(!$this->SkipCommentWhiteSpace($a))
return(0);
$addr = $addr_spec;
$p = $a;
return(1);
}
 
Function ParseName(&$p, &$address)
{
$address = null;
$a = $p;
if(!$this->ParsePhrase($a, $display_name))
return(0);
if(IsSet($display_name))
{
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address['name'] = trim($display_name);
if(IsSet($encoding))
$address['encoding'] = $encoding;
}
$p = $a;
return(1);
}
 
Function ParseNameAddr(&$p, &$address)
{
$address = null;
$a = $p;
if(!$this->ParsePhrase($a, $display_name))
return(0);
if(!$this->ParseAngleAddr($a, $addr))
return(0);
if(!IsSet($addr))
return(1);
$address = array('address'=>$addr);
if(IsSet($display_name))
{
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address['name'] = trim($display_name);
if(IsSet($encoding))
$address['encoding'] = $encoding;
}
$p = $a;
return(1);
}
 
Function ParseAddrNameAddr(&$p, &$address)
{
$address = null;
$a = $p;
if(!$this->ParseAddrSpec($a, $display_name))
return(0);
if(!IsSet($display_name))
return(1);
if(!$this->ParseAngleAddr($a, $addr))
return(0);
if(!IsSet($addr))
return(1);
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address = array(
'address'=>$addr,
'name' => trim($display_name)
);
if(IsSet($encoding))
$address['encoding'] = $encoding;
$p = $a;
return(1);
}
 
Function ParseMailbox(&$p, &$address)
{
$address = null;
if($this->ignore_syntax_errors)
{
$a = $p;
if(!$this->ParseAddrNameAddr($p, $address))
return(0);
if(IsSet($address))
return($this->SetPositionedWarning('it was specified an unquoted address as name', $a));
}
if(!$this->ParseNameAddr($p, $address))
return(0);
if(IsSet($address))
return(1);
if(!$this->ParseAddrSpec($p, $addr_spec))
return(0);
if(IsSet($addr_spec))
{
$address = array('address'=>$addr_spec);
return(1);
}
$a = $p;
if($this->ignore_syntax_errors
&& $this->ParseName($p, $address)
&& IsSet($address))
return($this->SetPositionedWarning('it was specified a name without an address', $a));
return(1);
}
 
Function ParseMailboxGroup(&$p, &$mailbox_group)
{
$v = $this->v;
$l = strlen($v);
$g = $p;
if(!$this->ParseMailbox($g, $address))
return(0);
if(!IsSet($address))
return(1);
$addresses = array($address);
for(;$g < $l;)
{
if(strcmp($v[$g], ','))
break;
++$g;
if(!$this->ParseMailbox($g, $address))
return(0);
if(!IsSet($address))
return(1);
$addresses[] = $address;
}
$mailbox_group = $addresses;
$p = $g;
return(1);
}
 
Function ParseGroup(&$p, &$address)
{
$address = null;
$v = $this->v;
$l = strlen($v);
$g = $p;
if(!$this->ParsePhrase($g, $display_name))
return(0);
if(!IsSet($display_name)
|| $g >= $l
|| strcmp($v[$g], ':'))
return(1);
++$g;
if(!$this->ParseMailboxGroup($g, $mailbox_group))
return(0);
if(!IsSet($mailbox_group))
{
if(!$this->SkipCommentWhiteSpace($g))
return(0);
$mailbox_group = array();
}
if($g >= $l
|| strcmp($v[$g], ';'))
return(1);
$c = ++$g;
if($this->SkipCommentWhiteSpace($g)
&& $g > $c
&& !$this->SetPositionedWarning('it were used invalid comments after a group of addresses', $c))
return(0);
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address = array(
'name'=>$display_name,
'group'=>$mailbox_group
);
if(IsSet($encoding))
$address['encoding'] = $encoding;
$p = $g;
return(1);
}
 
Function ParseAddress(&$p, &$address)
{
$address = null;
if(!$this->ParseGroup($p, $address))
return(0);
if(!IsSet($address))
{
if(!$this->ParseMailbox($p, $address))
return(0);
}
return(1);
}
 
/* Public functions */
 
/*
{metadocument}
<function>
<name>ParseAddressList</name>
<type>BOOLEAN</type>
<documentation>
<purpose>Parse and extract e-mail addresses eventually from headers
of an e-mail message.</purpose>
<usage>Pass a string value with a list of e-mail addresses to the
<argumentlink>
<function>ParseAddressList</function>
<argument>value</argument>
</argumentlink>. The <argumentlink>
<function>ParseAddressList</function>
<argument>addresses</argument>
</argumentlink> returns the list of e-mail addresses found.</usage>
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
the specified value is parsed successfully. Otherwise,
check the variables <variablelink>error</variablelink> and
<variablelink>error_position</variablelink> to determine what
error occurred and the relevant value position.</returnvalue>
</documentation>
<argument>
<name>value</name>
<type>STRING</type>
<documentation>
<purpose>String with a list of e-mail addresses to parse.</purpose>
</documentation>
</argument>
<argument>
<name>addresses</name>
<type>ARRAY</type>
<out />
<documentation>
<purpose>Return the list of parsed e-mail addresses.
Each entry in the list is an associative array.<paragraphbreak />
For normal addresses, this associative array has the entry
<stringvalue>address</stringvalue> set to the e-mail address.
If the address has an associated name, it is stored in the
entry <stringvalue>name</stringvalue>.<paragraphbreak />
For address groups, there is the entry
<stringvalue>name</stringvalue>.
The group addresses list are stored in the entry
<stringvalue>group</stringvalue> as an array. The structure of
the group addresses list array is the same as this addresses
list array argument.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function ParseAddressList($value, &$addresses)
{
$this->warnings = array();
$addresses = array();
$this->v = $v = $value;
$l = strlen($v);
$p = 0;
if(!$this->ParseAddress($p, $address))
return(0);
if(!IsSet($address))
return($this->SetPositionedError('it was not specified a valid address', $p));
$addresses[] = $address;
while($p < $l)
{
if(strcmp($v[$p], ','))
return($this->SetPositionedError('multiple addresses must be separated by commas: ', $p));
++$p;
if(!$this->ParseAddress($p, $address))
return(0);
if(!IsSet($address))
return($this->SetPositionedError('it was not specified a valid address after comma', $p));
$addresses[] = $address;
}
return(1);
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
 
};
 
/*
 
{metadocument}
</class>
{/metadocument}
 
*/
 
?>
/trunk/plugins/mail2wordpress/lib/mime_parser_class.html
0,0 → 1,343
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Class: MIME parser</title>
</head>
<body>
<center><h1>Class: MIME parser</h1></center>
<hr />
<ul>
<p><b>Version:</b> <tt>@(#) $Id: mime_parser.php,v 1.60 2008/07/17 00:54:24 mlemos Exp $</tt></p>
<h2><a name="table_of_contents">Contents</a></h2>
<ul>
<li><a href="#2.1.1">Summary</a></li>
<ul>
<li><a href="#3.2.0">Name</a></li>
<li><a href="#3.2.0.0">Author</a></li>
<li><a href="#3.2.0.1">Copyright</a></li>
<li><a href="#3.2.0.2">Version</a></li>
<li><a href="#3.2.0.3">Purpose</a></li>
<li><a href="#3.2.0.4">Usage</a></li>
</ul>
<li><a href="#4.1.1">Variables</a></li>
<ul>
<li><a href="#5.2.11">error</a></li>
<li><a href="#5.2.12">error_position</a></li>
<li><a href="#5.2.13">mbox</a></li>
<li><a href="#5.2.14">decode_headers</a></li>
<li><a href="#5.2.15">decode_bodies</a></li>
<li><a href="#5.2.16">extract_addresses</a></li>
<li><a href="#5.2.17">address_headers</a></li>
<li><a href="#5.2.18">message_buffer_length</a></li>
<li><a href="#5.2.19">ignore_syntax_errors</a></li>
<li><a href="#5.2.20">warnings</a></li>
</ul>
<li><a href="#6.1.1">Functions</a></li>
<ul>
<li><a href="#7.2.3">Decode</a></li>
<li><a href="#9.2.4">Analyze</a></li>
</ul>
</ul>
<p><a href="#table_of_contents">Top of the table of contents</a></p>
</ul>
<hr />
<ul>
<h2><li><a name="2.1.1">Summary</a></li></h2>
<ul>
<h3><a name="3.2.0">Name</a></h3>
<p>MIME parser</p>
<h3><a name="3.2.0.0">Author</a></h3>
<p>Manuel Lemos (<a href="mailto:mlemos-at-acm.org">mlemos-at-acm.org</a>)</p>
<h3><a name="3.2.0.1">Copyright</a></h3>
<p>Copyright &copy; (C) Manuel Lemos 2006 - 2008</p>
<h3><a name="3.2.0.2">Version</a></h3>
<p>@(#) $Id: mime_parser.php,v 1.60 2008/07/17 00:54:24 mlemos Exp $</p>
<h3><a name="3.2.0.3">Purpose</a></h3>
<p>Parse MIME encapsulated e-mail message data compliant with the RFC 2822 or aggregated in mbox format.</p>
<h3><a name="3.2.0.4">Usage</a></h3>
<p>Use the function <tt><a href="#function_Decode">Decode</a></tt> function to retrieve the structure of the messages to be parsed. Adjust its parameters to tell how to return the decoded body data. Use the <tt>SaveBody</tt> parameter to make the body parts be saved to files when the message is larger than the available memory. Use the <tt>SkipBody</tt> parameter to just retrieve the message structure without returning the body data.</p>
<p> If the message data is an archive that may contain multiple messages aggregated in the mbox format, set the variable <tt><a href="#variable_mbox">mbox</a></tt> to 1.</p>
<p><a href="#table_of_contents">Table of contents</a></p>
</ul>
</ul>
<hr />
<ul>
<h2><li><a name="variables"></a><a name="4.1.1">Variables</a></li></h2>
<ul>
<li><tt><a href="#variable_error">error</a></tt></li><br />
<li><tt><a href="#variable_error_position">error_position</a></tt></li><br />
<li><tt><a href="#variable_mbox">mbox</a></tt></li><br />
<li><tt><a href="#variable_decode_headers">decode_headers</a></tt></li><br />
<li><tt><a href="#variable_decode_bodies">decode_bodies</a></tt></li><br />
<li><tt><a href="#variable_extract_addresses">extract_addresses</a></tt></li><br />
<li><tt><a href="#variable_address_headers">address_headers</a></tt></li><br />
<li><tt><a href="#variable_message_buffer_length">message_buffer_length</a></tt></li><br />
<li><tt><a href="#variable_ignore_syntax_errors">ignore_syntax_errors</a></tt></li><br />
<li><tt><a href="#variable_warnings">warnings</a></tt></li><br />
<p><a href="#table_of_contents">Table of contents</a></p>
<h3><a name="variable_error"></a><li><a name="5.2.11">error</a></li></h3>
<h3>Type</h3>
<p><tt><i>string</i></tt></p>
<h3>Default value</h3>
<p><tt>''</tt></p>
<h3>Purpose</h3>
<p>Store the message that is returned when an error occurs.</p>
<h3>Usage</h3>
<p>Check this variable to understand what happened when a call to any of the class functions has failed.</p>
<p> This class uses cumulative error handling. This means that if one class functions that may fail is called and this variable was already set to an error message due to a failure in a previous call to the same or other function, the function will also fail and does not do anything.</p>
<p> This allows programs using this class to safely call several functions that may fail and only check the failure condition after the last function call.</p>
<p> Just set this variable to an empty string to clear the error condition.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_error_position"></a><li><a name="5.2.12">error_position</a></li></h3>
<h3>Type</h3>
<p><tt><i>int</i></tt></p>
<h3>Default value</h3>
<p><tt>-1</tt></p>
<h3>Purpose</h3>
<p>Point to the position of the message data or file that refers to the last error that occurred.</p>
<h3>Usage</h3>
<p>Check this variable to determine the relevant position of the message when a parsing error occurs.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_mbox"></a><li><a name="5.2.13">mbox</a></li></h3>
<h3>Type</h3>
<p><tt><i>bool</i></tt></p>
<h3>Default value</h3>
<p><tt>0</tt></p>
<h3>Purpose</h3>
<p>Specify whether the message data to parse is a single RFC 2822 message or it is an archive that contain multiple messages in the mbox format.</p>
<h3>Usage</h3>
<p>Set this variable to 1 if it is it is intended to parse an mbox message archive.<br />
mbox archives may contain multiple messages. Each message starts with the header <tt>From</tt>. Since all valid RFC 2822 headers must with a colon, the class will fail to parse a mbox archive if this variable is set to 0.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_decode_headers"></a><li><a name="5.2.14">decode_headers</a></li></h3>
<h3>Type</h3>
<p><tt><i>bool</i></tt></p>
<h3>Default value</h3>
<p><tt>1</tt></p>
<h3>Purpose</h3>
<p>Specify whether the message headers should be decoded.</p>
<h3>Usage</h3>
<p>Set this variable to 1 if it is necessary to decode message headers that may have non-ASCII characters and use other character set encodings.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_decode_bodies"></a><li><a name="5.2.15">decode_bodies</a></li></h3>
<h3>Type</h3>
<p><tt><i>bool</i></tt></p>
<h3>Default value</h3>
<p><tt>1</tt></p>
<h3>Purpose</h3>
<p>Specify whether the message body parts should be decoded.</p>
<h3>Usage</h3>
<p>Set this variable to 1 if it is necessary to parse the message bodies and extract its part structure.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_extract_addresses"></a><li><a name="5.2.16">extract_addresses</a></li></h3>
<h3>Type</h3>
<p><tt><i>bool</i></tt></p>
<h3>Default value</h3>
<p><tt>1</tt></p>
<h3>Purpose</h3>
<p>Specify whether the message headers that usually contain e-mail addresses should be parsed and the addresses should be extracted by the <tt><a href="#function_Decode">Decode</a></tt> function.</p>
<h3>Usage</h3>
<p>Set this variable to 1 if it is necessary to extract the e-mail addresses contained in certain message headers.</p>
<p> The headers to be parsed are defined by the <tt><a href="#variable_address_headers">address_headers</a></tt> variable.</p>
<p> The parsed addresses are returned by the <tt>ExtractedAddresses</tt> entry of the <tt><a href="#argument_Decode_decoded">decoded</a></tt> argument of the <tt><a href="#function_Decode">Decode</a></tt> function.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_address_headers"></a><li><a name="5.2.17">address_headers</a></li></h3>
<h3>Type</h3>
<p><tt><i>array</i></tt></p>
<h3>Default value</h3>
<p><tt>array()</tt></p>
<h3>Purpose</h3>
<p>Specify which headers contain addresses that should be parsed and extracted.</p>
<h3>Usage</h3>
<p>Change this variable if you need to extract e-mail addresses from a different list of message headers.</p>
<p> It must be set to an associative array with keys set to the names of the headers to be parsed including the colon. The array values must be set to a boolean flag to tell whether the headers with the respective name should be parsed. The header names must be in lower case.</p>
<p> By default the class addresses from the headers: 'from:', 'to:', 'cc:', 'bcc:', 'return-path:', 'reply-to:' and 'disposition-notification-to:'.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_message_buffer_length"></a><li><a name="5.2.18">message_buffer_length</a></li></h3>
<h3>Type</h3>
<p><tt><i>int</i></tt></p>
<h3>Default value</h3>
<p><tt>8000</tt></p>
<h3>Purpose</h3>
<p>Maximum length of the chunks of message data that the class parse at one time.</p>
<h3>Usage</h3>
<p>Adjust this value according to the available memory.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_ignore_syntax_errors"></a><li><a name="5.2.19">ignore_syntax_errors</a></li></h3>
<h3>Type</h3>
<p><tt><i>bool</i></tt></p>
<h3>Default value</h3>
<p><tt>1</tt></p>
<h3>Purpose</h3>
<p>Specify whether the class should ignore syntax errors in malformed messages.</p>
<h3>Usage</h3>
<p>Set this variable to 0 if it is necessary to verify whether message data may be corrupted due to to eventual bugs in the program that generated the message.</p>
<p> Currently the class only ignores some types of syntax errors. Other syntax errors may still cause the <tt><a href="#function_Decode">Decode</a></tt> to fail.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_warnings"></a><li><a name="5.2.20">warnings</a></li></h3>
<h3>Type</h3>
<p><tt><i>array</i></tt></p>
<h3>Default value</h3>
<p><tt>array()</tt></p>
<h3>Purpose</h3>
<p>Return a list of positions of the original message that contain syntax errors.</p>
<h3>Usage</h3>
<p>Check this variable to retrieve eventual message syntax errors that were ignored when the <tt><a href="#variable_ignore_syntax_errors">ignore_syntax_errors</a></tt> is set to 1.</p>
<p> The indexes of this array are the positions of the errors. The array values are the corresponding syntax error messages.</p>
<p><a href="#variables">Variables</a></p>
<p><a href="#table_of_contents">Table of contents</a></p>
</ul>
</ul>
<hr />
<ul>
<h2><li><a name="functions"></a><a name="6.1.1">Functions</a></li></h2>
<ul>
<li><tt><a href="#function_Decode">Decode</a></tt></li><br />
<li><tt><a href="#function_Analyze">Analyze</a></tt></li><br />
<p><a href="#table_of_contents">Table of contents</a></p>
<h3><a name="function_Decode"></a><li><a name="7.2.3">Decode</a></li></h3>
<h3>Synopsis</h3>
<p><tt><i>bool</i> Decode(</tt><ul>
<tt>(input and output) <i>array</i> </tt><tt><a href="#argument_Decode_parameters">parameters</a></tt><tt>,</tt><br />
<tt>(output) <i>array</i> </tt><tt><a href="#argument_Decode_decoded">decoded</a></tt></ul>
<tt>)</tt></p>
<h3>Purpose</h3>
<p>Parse and decode message data and retrieve its structure.</p>
<h3>Usage</h3>
<p>Pass an array to the <tt><a href="#argument_Decode_parameters">parameters</a></tt> parameter to define whether the message data should be read and parsed from a file or a data string, as well additional parsing options. The <tt><a href="#argument_Decode_decoded">decoded</a></tt> returns the data structure of the parsed messages.</p>
<h3>Arguments</h3>
<ul>
<p><tt><b><a name="argument_Decode_parameters">parameters</a></b></tt> - Associative array to specify parameters for the message data parsing and decoding operation. Here follows the list of supported parameters that should be used as indexes of the array:</p>
<p> <tt>File</tt></p>
<p> Name of the file from which the message data will be read. It may be the name of a file stream or a remote URL, as long as your PHP installation is configured to allow accessing remote files with the <tt>fopen()</tt> function.</p>
<p> <tt>Data</tt></p>
<p> String that specifies the message data. This should be used as alternative data source for passing data available in memory, like for instance messages stored in a database that was queried dynamically and the message data was fetched into a string variable.</p>
<p> <tt>SaveBody</tt></p>
<p> If this parameter is specified, the message body parts are saved to files. The path of the directory where the files are saved is defined by this parameter value. The information about the message body part structure is returned by the <tt><a href="#argument_Decode_decoded">decoded</a></tt> argument, but it just returns the body data part file name instead of the actual body data. It is recommended for retrieving messages larger than the available memory. The names of the body part files are numbers starting from '1'.</p>
<p> <tt>SkipBody</tt></p>
<p> If this parameter is specified, the message body parts are skipped. This means the information about the message body part structure is returned by the <tt><a href="#argument_Decode_decoded">decoded</a></tt> but it does not return any body data. It is recommended just for parsing messages without the need to retrieve the message body part data.</p>
<p><tt><b><a name="argument_Decode_decoded">decoded</a></b></tt> - Retrieve the structure of the parsed message headers and body data.</p>
<p> The argument is used to return by reference an array of message structure definitions. Each array entry refers to the structure of each message that is found and parsed successfully.</p>
<p> Each message entry consists of an associative array with several entries that describe the message structure. Here follows the list of message structure entries names and the meaning of the respective values:</p>
<p> <tt>Headers</tt></p>
<p> Associative array that returns the list of all the message headers. The array entries are the header names mapped to lower case, including the end colon. The array values are the respective header raw values without any start or trailing white spaces. Long header values split between multiple message lines are gathered in single string without line breaks. If an header with the same name appears more than once in the message, the respective value is an array with the values of all of the header occurrences.</p>
<p> <tt>DecodedHeaders</tt></p>
<p> Associative array that returns the list of all the encoded message headers when the <tt><a href="#variable_decode_headers">decode_headers</a></tt> variable is set. The array entries are the header names mapped to lower case, including the end colon. The array values are also arrays that list only the occurrences of the header that originally were encoded. Each entry of the decoded header array contains more associative arrays that describe each part of the decoded header. Each of those associative arrays have an entry named <tt>Value</tt> that contains the decoded header part value, and another entry named <tt>Encoding</tt> that specifies the character set encoding of the value in upper case.</p>
<p> <tt>ExtractedAddresses</tt></p>
<p> If the <tt><a href="#variable_extract_addresses">extract_addresses</a></tt> variable is set to 1, this entry is set to an associative array with the addresses found in the headers specified by the <tt><a href="#variable_address_headers">address_headers</a></tt> variable.</p>
<p> The parsed addresses found on each header are returned as an array with the format of the <a href="rfc822_addresses_class.html#argument_ParseAddressList_addresses">addresses</a> argument of the <a href="rfc822_addresses_class.html#function_ParseAddressList">ParseAddressList</a> function of the <a href="rfc822_addresses_class.html">RFC 822 addresses</a> class.</p>
<p> <tt>Parts</tt></p>
<p> If this message content type is multipart, this entry is an array that describes each of the parts contained in the message body. Each message part is described by an associative array with the same structure of a complete message definition.</p>
<p> <tt>Body</tt></p>
<p> String with the decoded data contained in the message body. If the <tt>SaveBody</tt> or <tt>SkipBody</tt> parameters are defined, the <tt>Body</tt> entry is not set.</p>
<p> <tt>BodyFile</tt></p>
<p> Name of the file to which the message body data was saved when the <tt>SaveBody</tt> parameter is defined.</p>
<p> <tt>BodyLength</tt></p>
<p> Length of the current decoded body part.</p>
<p> <tt>BodyPart</tt></p>
<p> Number of the current message body part.</p>
<p> <tt>FileName</tt></p>
<p> Name of the file for body parts composed from files.</p>
<p> <tt>FileNameCharacterSet</tt></p>
<p> Character set encoding for file parts with names that may include non-ASCII characters.</p>
<p> <tt>FileNameLanguage</tt></p>
<p> Language of file parts with names that may include non-ASCII characters.</p>
<p> <tt>FileDisposition</tt></p>
<p> Disposition of parts that files. It may be either <tt>'inline'</tt> for file parts to be displayed with the message, or <tt>'attachment'</tt> otherwise.</p>
</ul>
<h3>Return value</h3>
<p>This function returns 1 if the specified message data is parsed successfully. Otherwise, check the variables <tt><a href="#variable_error">error</a></tt> and <tt><a href="#variable_error_position">error_position</a></tt> to determine what error occurred and the relevant message position.</p>
<p><a href="#functions">Functions</a></p>
<h3><a name="function_Analyze"></a><li><a name="9.2.4">Analyze</a></li></h3>
<h3>Synopsis</h3>
<p><tt><i>bool</i> Analyze(</tt><ul>
<tt>(input and output) <i>array</i> </tt><tt><a href="#argument_Analyze_message">message</a></tt><tt>,</tt><br />
<tt>(output) <i>array</i> </tt><tt><a href="#argument_Analyze_results">results</a></tt></ul>
<tt>)</tt></p>
<h3>Purpose</h3>
<p>Analyze a parsed message to describe its contents.</p>
<h3>Usage</h3>
<p>Pass an array to the <tt><a href="#argument_Analyze_message">message</a></tt> parameter with the decoded message array structure returned by the <tt><a href="#function_Decode">Decode</a></tt> function. The <tt><a href="#argument_Analyze_results">results</a></tt> returns details about the type of message that was analyzed and its contents.</p>
<h3>Arguments</h3>
<ul>
<p><tt><b><a name="argument_Analyze_message">message</a></b></tt> - Pass an associative array with the definition of an individual message returned by the <tt><a href="#argument_Decode_decoded">decoded</a></tt> argument of the <tt><a href="#function_Decode">Decode</a></tt> function..</p>
<p><tt><b><a name="argument_Analyze_results">results</a></b></tt> - Returns an associative array with the results of the analysis. Some types of entries are returned for all types of analyzed messages. Other entries are specific to each type of message.</p>
<p> <tt>Type</tt></p>
<p> Type of message that was analyzed. Currently it supports the types: <tt>binary</tt>, <tt>text</tt>, <tt>html</tt>, <tt>video</tt>, <tt>image</tt>, <tt>audio</tt>, <tt>zip</tt>, <tt>pdf</tt>, <tt>postscript</tt>, <tt>ms-word</tt>, <tt>ms-excel</tt>, <tt>ms-powerpoint</tt>, <tt>ms-tnef</tt>, <tt>odf-writer</tt>, <tt>signature</tt>, <tt>report-type</tt>, <tt>delivery-status</tt> and <tt>message</tt>.</p>
<p> <tt>SubType</tt></p>
<p> Name of the variant of the message type format.</p>
<p> <tt>Description</tt></p>
<p> Human readable description in English of the message type.</p>
<p> </p>
<p> </p>
<p> </p>
<p> <b>From message headers:</b></p>
<p> <tt>Encoding</tt></p>
<p> Character set encoding of the message part.</p>
<p> <tt>Subject</tt></p>
<p> The message subject.</p>
<p> <tt>SubjectEncoding</tt></p>
<p> Character set encoding of the message subject.</p>
<p> <tt>Date</tt></p>
<p> The message date.</p>
<p> <tt>From</tt></p>
<p> <tt>To</tt></p>
<p> <tt>Cc</tt></p>
<p> <tt>Bcc</tt></p>
<p> Array of e-mail addresses found in the <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt>, <tt>Bcc</tt>.</p>
<p> Each of the entries consists of an associative array with an entry named <tt>address</tt> with the e-mail address and optionally another named <tt>name</tt> with the associated name.</p>
<p> </p>
<p> </p>
<p> <b>For content message parts:</b></p>
<p> </p>
<p> <tt>Data</tt></p>
<p> String of data of the message part.</p>
<p> <tt>DataFile</tt></p>
<p> File with data of the message part.</p>
<p> <tt>DataLength</tt></p>
<p> Length of the data of the message part.</p>
<p> </p>
<p> </p>
<p> </p>
<p> <b>For message with embedded files:</b></p>
<p> </p>
<p> <tt>FileName</tt></p>
<p> Original name of the file.</p>
<p> <tt>ContentID</tt></p>
<p> Content identifier of the file to be used in references from other message parts.</p>
<p> For instance, an HTML message may reference images embedded in the message using URLs that start with the 'cid:' followed by the content identifier of the embedded image file part.</p>
<p> <tt>Disposition</tt></p>
<p> Information of whether the embedded file should be displayed inline when the message is presented, or it is an attachment file.</p>
<p> </p>
<p> </p>
<p> <b>For composite message:</b></p>
<p> </p>
<p> <tt>Attachments</tt></p>
<p> List of files attached to the message.</p>
<p> <tt>Alternative</tt></p>
<p> List of alternative message parts that can be displayed if the main message type is not supported by the program displaying the message.</p>
<p> <tt>Related</tt></p>
<p> List of message parts related with the main message type.</p>
<p> It may list for instance embedded images or CSS files related with an HTML message type.</p>
<p> </p>
<p> </p>
<p> <b>For bounced messages or other types of delivery status report messages:</b></p>
<p> </p>
<p> <tt>Recipients</tt></p>
<p> List of recipients of the original message.</p>
<p> Each entry contains an associative array that may have the entries: <tt>Recipient</tt> with the original recipient address, <tt>Action</tt> with the name action that triggered the delivery status report, <tt>Status</tt> with the code of the status of the message delivery.</p>
<p> <tt>Response</tt></p>
<p> Human readable response sent by the server the originated the report.</p>
<p> </p>
</ul>
<h3>Return value</h3>
<p>This function returns 1 if the specified message is analyzed successfully. Otherwise, check the variables <tt><a href="#variable_error">error</a></tt> and <tt><a href="#variable_error_position">error_position</a></tt> to determine what error occurred.</p>
<p><a href="#functions">Functions</a></p>
<p><a href="#table_of_contents">Table of contents</a></p>
</ul>
</ul>
 
<hr />
<address>Manuel Lemos (<a href="mailto:mlemos-at-acm.org">mlemos-at-acm.org</a>)</address>
</body>
</html>
/trunk/plugins/mail2wordpress/lib/rfc822_addresses_class.html
0,0 → 1,145
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Class: RFC 822 e-mail addresses parser</title>
</head>
<body>
<center><h1>Class: RFC 822 e-mail addresses parser</h1></center>
<hr />
<ul>
<p><b>Version:</b> <tt>@(#) $Id: rfc822_addresses.php,v 1.6 2008/01/05 06:36:08 mlemos Exp $</tt></p>
<h2><a name="table_of_contents">Contents</a></h2>
<ul>
<li><a href="#2.1.1">Summary</a></li>
<ul>
<li><a href="#3.2.0">Name</a></li>
<li><a href="#3.2.0.0">Author</a></li>
<li><a href="#3.2.0.1">Copyright</a></li>
<li><a href="#3.2.0.2">Version</a></li>
<li><a href="#3.2.0.3">Purpose</a></li>
<li><a href="#3.2.0.4">Usage</a></li>
</ul>
<li><a href="#4.1.1">Variables</a></li>
<ul>
<li><a href="#5.2.5">error</a></li>
<li><a href="#5.2.6">error_position</a></li>
<li><a href="#5.2.7">ignore_syntax_errors</a></li>
<li><a href="#5.2.8">warnings</a></li>
</ul>
<li><a href="#6.1.1">Functions</a></li>
<ul>
<li><a href="#7.2.2">ParseAddressList</a></li>
</ul>
</ul>
<p><a href="#table_of_contents">Top of the table of contents</a></p>
</ul>
<hr />
<ul>
<h2><li><a name="2.1.1">Summary</a></li></h2>
<ul>
<h3><a name="3.2.0">Name</a></h3>
<p>RFC 822 e-mail addresses parser</p>
<h3><a name="3.2.0.0">Author</a></h3>
<p>Manuel Lemos (<a href="mailto:mlemos-at-acm.org">mlemos-at-acm.org</a>)</p>
<h3><a name="3.2.0.1">Copyright</a></h3>
<p>Copyright &copy; (C) Manuel Lemos 2006 - 2008</p>
<h3><a name="3.2.0.2">Version</a></h3>
<p>@(#) $Id: rfc822_addresses.php,v 1.6 2008/01/05 06:36:08 mlemos Exp $</p>
<h3><a name="3.2.0.3">Purpose</a></h3>
<p>Parse e-mail addresses from headers of <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a> compliant e-mail messages.</p>
<h3><a name="3.2.0.4">Usage</a></h3>
<p>Use the function <tt><a href="#function_ParseAddressList">ParseAddressList</a></tt> function to retrieve the list of e-mail addresses contained in e-mail message headers like <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt> or <tt>Bcc</tt>.</p>
<p><a href="#table_of_contents">Table of contents</a></p>
</ul>
</ul>
<hr />
<ul>
<h2><li><a name="variables"></a><a name="4.1.1">Variables</a></li></h2>
<ul>
<li><tt><a href="#variable_error">error</a></tt></li><br />
<li><tt><a href="#variable_error_position">error_position</a></tt></li><br />
<li><tt><a href="#variable_ignore_syntax_errors">ignore_syntax_errors</a></tt></li><br />
<li><tt><a href="#variable_warnings">warnings</a></tt></li><br />
<p><a href="#table_of_contents">Table of contents</a></p>
<h3><a name="variable_error"></a><li><a name="5.2.5">error</a></li></h3>
<h3>Type</h3>
<p><tt><i>string</i></tt></p>
<h3>Default value</h3>
<p><tt>''</tt></p>
<h3>Purpose</h3>
<p>Store the message that is returned when an error occurs.</p>
<h3>Usage</h3>
<p>Check this variable to understand what happened when a call to any of the class functions has failed.</p>
<p> This class uses cumulative error handling. This means that if one class functions that may fail is called and this variable was already set to an error message due to a failure in a previous call to the same or other function, the function will also fail and does not do anything.</p>
<p> This allows programs using this class to safely call several functions that may fail and only check the failure condition after the last function call.</p>
<p> Just set this variable to an empty string to clear the error condition.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_error_position"></a><li><a name="5.2.6">error_position</a></li></h3>
<h3>Type</h3>
<p><tt><i>int</i></tt></p>
<h3>Default value</h3>
<p><tt>-1</tt></p>
<h3>Purpose</h3>
<p>Point to the position of the message data or file that refers to the last error that occurred.</p>
<h3>Usage</h3>
<p>Check this variable to determine the relevant position of the message when a parsing error occurs.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_ignore_syntax_errors"></a><li><a name="5.2.7">ignore_syntax_errors</a></li></h3>
<h3>Type</h3>
<p><tt><i>bool</i></tt></p>
<h3>Default value</h3>
<p><tt>1</tt></p>
<h3>Purpose</h3>
<p>Specify whether the class should ignore syntax errors in malformed addresses.</p>
<h3>Usage</h3>
<p>Set this variable to 0 if it is necessary to verify whether message data may be corrupted due to to eventual bugs in the program that generated the message.</p>
<p> Currently the class only ignores some types of syntax errors. Other syntax errors may still cause the <tt><a href="#function_ParseAddressList">ParseAddressList</a></tt> to fail.</p>
<p><a href="#variables">Variables</a></p>
<h3><a name="variable_warnings"></a><li><a name="5.2.8">warnings</a></li></h3>
<h3>Type</h3>
<p><tt><i>array</i></tt></p>
<h3>Default value</h3>
<p><tt>array()</tt></p>
<h3>Purpose</h3>
<p>Return a list of positions of the original message that contain syntax errors.</p>
<h3>Usage</h3>
<p>Check this variable to retrieve eventual message syntax errors that were ignored when the <tt><a href="#variable_ignore_syntax_errors">ignore_syntax_errors</a></tt> is set to 1.</p>
<p> The indexes of this array are the positions of the errors. The array values are the corresponding syntax error messages.</p>
<p><a href="#variables">Variables</a></p>
<p><a href="#table_of_contents">Table of contents</a></p>
</ul>
</ul>
<hr />
<ul>
<h2><li><a name="functions"></a><a name="6.1.1">Functions</a></li></h2>
<ul>
<li><tt><a href="#function_ParseAddressList">ParseAddressList</a></tt></li><br />
<p><a href="#table_of_contents">Table of contents</a></p>
<h3><a name="function_ParseAddressList"></a><li><a name="7.2.2">ParseAddressList</a></li></h3>
<h3>Synopsis</h3>
<p><tt><i>bool</i> ParseAddressList(</tt><ul>
<tt><i>string</i> </tt><tt><a href="#argument_ParseAddressList_value">value</a></tt><tt>,</tt><br />
<tt>(output) <i>array</i> </tt><tt><a href="#argument_ParseAddressList_addresses">addresses</a></tt></ul>
<tt>)</tt></p>
<h3>Purpose</h3>
<p>Parse and extract e-mail addresses eventually from headers of an e-mail message.</p>
<h3>Usage</h3>
<p>Pass a string value with a list of e-mail addresses to the <tt><a href="#argument_ParseAddressList_value">value</a></tt>. The <tt><a href="#argument_ParseAddressList_addresses">addresses</a></tt> returns the list of e-mail addresses found.</p>
<h3>Arguments</h3>
<ul>
<p><tt><b><a name="argument_ParseAddressList_value">value</a></b></tt> - String with a list of e-mail addresses to parse.</p>
<p><tt><b><a name="argument_ParseAddressList_addresses">addresses</a></b></tt> - Return the list of parsed e-mail addresses. Each entry in the list is an associative array.</p>
<p> For normal addresses, this associative array has the entry 'address' set to the e-mail address. If the address has an associated name, it is stored in the entry 'name'.</p>
<p> For address groups, there is the entry 'name'. The group addresses list are stored in the entry 'group' as an array. The structure of the group addresses list array is the same as this addresses list array argument.</p>
</ul>
<h3>Return value</h3>
<p>This function returns 1 if the specified value is parsed successfully. Otherwise, check the variables <tt><a href="#variable_error">error</a></tt> and <tt><a href="#variable_error_position">error_position</a></tt> to determine what error occurred and the relevant value position.</p>
<p><a href="#functions">Functions</a></p>
<p><a href="#table_of_contents">Table of contents</a></p>
</ul>
</ul>
 
<hr />
<address>Manuel Lemos (<a href="mailto:mlemos-at-acm.org">mlemos-at-acm.org</a>)</address>
</body>
</html>
/trunk/plugins/mail2wordpress/lib/README.mime_parser.txt
0,0 → 1,30
README
======
 
 
mime_parser.php library
-----------------------
 
mail2wp uses the "Mime E-mail message parser" library,
written by Manuel Lemos <http://www.manuellemos.net/>.
 
Version: 1.29
Download: mimeparser-2008-12-12.zip
website: http://www.phpclasses.org/browse/package/3169.html
 
Although no license file is included in the package
download, the site above specifies that the code
is released under a BSD license.
 
The following 4 files are taken from: mimeparser-2008-12-12.zip
 
mime_parser.php
mime_parser_class.html
rfc822_addresses.php
rfc822_addresses_class.html
 
I use Lemos' library because it avoids the hassle of installing the PEAR/PECL library Mailparser.
 
Should also investigate using something from SquirrelMail, as the wp-mail.php file uses a bit of the Squirrel lib for POP3 access.
 
 
/trunk/plugins/mail2wordpress/index.html
0,0 → 1,10
<html>
<head>
<title>mail2wordpress</title>
</head>
<body>
 
<h1>mail2wordpress</h1>
 
</body>
</html>
/trunk/plugins/mail2wordpress/README.txt
0,0 → 1,35
mail2wordpress
==============
 
A simple replacement for wp-mail.php
Just enough of a hack to support emailed photos.
 
Version: 0.1
 
Created: Jan 1-3, 2009.
Author: Phil Suh <http://filsa.net/>
 
Requires
--------
 
PHP 5 (not tested on php4, would probably work).
Wordpress.
 
 
 
That's it. :)
 
 
REQUIRES AND INCLUDES:
 
=> MIME Email message parser
Author: Manuel Lemos (http://www.ManuelLemos.net/)
version: 1.29
download: mimeparser-2008-12-12.zip
website: http://www.phpclasses.org/browse/package/3169.html
 
I use Lemos' library because it avoids the hassle of installing the PEAR/PECL library Mailparser.
 
Should also investigate using something from SquirrelMail, as the wp-mail.php file uses a bit of the Squirrel lib for POP3 access.