3 * FusionForge mail parser
5 * Copyright 2004, GForge, LLC
7 * This file is part of FusionForge. FusionForge is free software;
8 * you can redistribute it and/or modify it under the terms of the
9 * GNU General Public License as published by the Free Software
10 * Foundation; either version 2 of the Licence, or (at your option)
13 * FusionForge is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 require_once $gfcommon.'include/Error.class.php';
25 class MailParser extends Error {
27 var $max_file_size=2000000;
31 function MailParser($input_file) {
33 $size = filesize($input_file);
34 if ($size > $this->max_file_size) {
35 $this->setError("Error - file too large");
38 $fo = fopen($input_file, 'r');
39 $input_data = fread($fo, $size);
42 $lines=explode("\n",$input_data);
43 $linecount=count($lines);
46 //system("echo \"mp: headers".implode("***\n",$lines)."\n\" >> /tmp/forum.log");
48 // Read the message line-by-line
50 for ($i=0; $i<($linecount-1); $i++) {
51 //system("echo \"mp: line $i of $linecount length: ".strlen($lines[$i])." ".$lines[$i]."\n\" >> /tmp/forum.log");
53 // Still reading headers
57 // If we hit a blank line, end of headers
59 if (strlen($lines[$i]) < 2) {
63 // See if line starts with tab, if so ignore it for now
65 if (!preg_match('/^[A-z]/',$lines[$i])) {
66 $header[$lastheader] = $header[$lastheader]."\n".$lines[$i];
68 $pos = (strpos($lines[$i],':'));
69 $header[substr($lines[$i],0,$pos)] = trim(substr($lines[$i],$pos+2,(strlen($lines[$i])-$pos-2)));
70 $lastheader=substr($lines[$i],0,$pos);
74 $body .= $lines[$i]."\r\n";
80 $this->headers =& $header;
82 if ($header['Content-Type']) {
83 $hdr = strtolower($header['Content-Type']);
84 if (strpos($hdr,'text/plain') !== false) {
87 $this->setError('Error - only text/plain supported at this time');
91 //echo "\n\n**".$header['Content-Type']."**\n\n";
96 //system("echo \"mp: headers".implode("***\n",$header)."\n\" >> /tmp/forum.log");
97 //system("echo \"mp: body".$body."\n\" >> /tmp/forum.log");
101 function &getBody() {
105 function &getHeader($header) {
106 return $this->headers[$header];
109 function getSubject() {
110 return $this->getHeader('Subject');
113 function getFromEmail() {
114 $mail = $this->getHeader('From');
115 if (strpos($mail,'(') !== false) {
116 $email = substr($mail,0,strpos($mail,' '));
117 } elseif (strpos($mail,'<') !== false) {
118 $begin=(strpos($mail,'<')+1);
119 $end = strpos($mail,'>');
120 $email = substr($mail,$begin,($end-$begin));
124 $email = str_replace('"','',$email);
126 //echo "***$mail*$begin*$end**".$email."*****";
127 //system("echo \"mp: email".$email."\n\" >> /tmp/forum.log");
131 /*------------------------------------------------------------------------
132 * MIME decoding functions
133 *-----------------------------------------------------------------------*/
135 * Subject and From decode implementation of RFC 2047
137 * @param String one or more encoded strings
138 * @return String strcat of all texts. Ignore all charsets
140 function mime_header_decode_string($string) {
142 $decoded_arr = $this->mime_header_decode($string);
144 $return_string = $decoded_arr[0]['text'];
147 for ($i=1; $i<count($decoded_arr); $i++) {
148 $return_string.=$decoded_arr[$i]['text'];
151 DBG("mime_header: $string -> $return_string \n");
153 return $return_string;
157 * Mime header decoding
159 * @param String to decode
160 * @return Decoded String Array. return['charset'] and retutn['text']
162 *# FIXME: Should we use imap_mime_headres_decode? It's too havey to install
163 * See http://us2.php.net/manual/en/function.imap-mime-header-decode.php
166 function mime_header_decode($string) {
167 /* We expecting series of encoded-word:
168 * encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
169 * See more detail in RFC 2407
172 $strlen = strlen($string);
174 for ($i=0; $i < $strlen; $i++) {
175 /* Start seperation */
176 if (!strcmp($string{$i} . $string{$i+1}, "=?")) {
181 if( !strcmp($string{$i} . $string{$i+1}, "?=")) {
182 $encoded_word_arr[$count].=$string{$i};
183 $encoded_word_arr[$count].=$string{++$i};
184 $count++; /* Null array should be OK */
188 $encoded_word_arr[$count].=$string{$i};
191 for ($i=0; $i<count($encoded_word_arr); $i++) {
192 $return_arr[$i] = $this->mime_header_one_word_decode($encoded_word_arr[$i]);
199 * one word decode implementation of RFC 2047
201 function mime_header_one_word_decode($string) {
202 /* Default charset */
205 /* We expecting : encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
206 * See more detail in RFC 2407
209 /* No encoded-word, return default */
210 if (strncmp($string, "=?", 2)) {
211 return array("charset"=>$charset, "text" => $string);
215 * Expecting [0]='=', [1]=charset, [2]=B|Q, [3]=encoded-text
217 $string_arr = explode('?', $string);
219 if (!strcasecmp($string_arr[2], "B") && $string_arr[3]) {
220 $string = base64_decode($string_arr[3]);
221 $charset = $string_arr[1];
222 } elseif (!strcasecmp($string_arr[2], "Q") && $string_arr[3]) {
223 $string = quoted_printable_decode($string_arr[3]);
224 $charset = $string_arr[1];
227 /* Return what we have */
228 $ret_arr = array("charset"=>$charset, "text" => $string);
236 // c-file-style: "bsd"