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 FFError {
27 var $max_file_size=2000000;
31 function MailParser($input_file) {
33 $size = filesize($input_file);
34 if ($size > $this->max_file_size) {
35 return $this->setError(_("Error: file too large"));
37 $fo = fopen($input_file, 'r');
38 $input_data = fread($fo, $size);
41 $lines=explode("\n",$input_data);
42 $linecount=count($lines);
45 //system("echo \"mp: headers".implode("***\n",$lines)."\n\" >> /tmp/forum.log");
47 // Read the message line-by-line
49 for ($i=0; $i<($linecount-1); $i++) {
50 //system("echo \"mp: line $i of $linecount length: ".strlen($lines[$i])." ".$lines[$i]."\n\" >> /tmp/forum.log");
52 // Still reading headers
56 // If we hit a blank line, end of headers
58 if (strlen($lines[$i]) < 2) {
62 // See if line starts with tab, if so ignore it for now
64 if (!preg_match('/^[A-z]/',$lines[$i])) {
65 $header[$lastheader] = $header[$lastheader]."\n".$lines[$i];
67 $pos = (strpos($lines[$i],':'));
68 $header[substr($lines[$i],0,$pos)] = trim(substr($lines[$i],$pos+2,(strlen($lines[$i])-$pos-2)));
69 $lastheader=substr($lines[$i],0,$pos);
73 $body .= $lines[$i]."\r\n";
77 $this->headers =& $header;
79 if ($header['Content-Type']) {
80 $hdr = strtolower($header['Content-Type']);
81 if (strpos($hdr,'text/plain') !== false) {
84 $this->setError(_('Error - only text/plain supported at this time'));
88 //echo "\n\n**".$header['Content-Type']."**\n\n";
91 //system("echo \"mp: headers".implode("***\n",$header)."\n\" >> /tmp/forum.log");
92 //system("echo \"mp: body".$body."\n\" >> /tmp/forum.log");
100 function &getHeader($header) {
101 return $this->headers[$header];
104 function getSubject() {
105 return $this->getHeader('Subject');
108 function getFromEmail() {
109 $mail = $this->getHeader('From');
110 if (strpos($mail,'(') !== false) {
111 $email = substr($mail,0,strpos($mail,' '));
112 } elseif (strpos($mail,'<') !== false) {
113 $begin=(strpos($mail,'<')+1);
114 $end = strpos($mail,'>');
115 $email = substr($mail,$begin,($end-$begin));
119 $email = str_replace('"','',$email);
121 //echo "***$mail*$begin*$end**".$email."*****";
122 //system("echo \"mp: email".$email."\n\" >> /tmp/forum.log");
126 /*------------------------------------------------------------------------
127 * MIME decoding functions
128 *-----------------------------------------------------------------------*/
130 * Subject and From decode implementation of RFC 2047
132 * @param string one or more encoded strings
133 * @return string strcat of all texts. Ignore all charsets
135 function mime_header_decode_string($string) {
137 $decoded_arr = $this->mime_header_decode($string);
139 $return_string = $decoded_arr[0]['text'];
142 for ($i=1; $i<count($decoded_arr); $i++) {
143 $return_string.=$decoded_arr[$i]['text'];
146 DBG("mime_header: $string -> $return_string \n");
148 return $return_string;
152 * Mime header decoding
154 * @param $string String to decode
155 * @return array Decoded String Array. return['charset'] and retutn['text']
157 *# FIXME: Should we use imap_mime_headres_decode? It's too havey to install
158 * See http://us2.php.net/manual/en/function.imap-mime-header-decode.php
161 function mime_header_decode($string) {
162 /* We expecting series of encoded-word:
163 * encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
164 * See more detail in RFC 2407
167 $strlen = strlen($string);
169 for ($i=0; $i < $strlen; $i++) {
170 /* Start seperation */
171 if (!strcmp($string{$i} . $string{$i+1}, "=?")) {
176 if( !strcmp($string{$i} . $string{$i+1}, "?=")) {
177 $encoded_word_arr[$count].=$string{$i};
178 $encoded_word_arr[$count].=$string{++$i};
179 $count++; /* Null array should be OK */
183 $encoded_word_arr[$count].=$string{$i};
186 for ($i=0; $i<count($encoded_word_arr); $i++) {
187 $return_arr[$i] = $this->mime_header_one_word_decode($encoded_word_arr[$i]);
194 * one word decode implementation of RFC 2047
196 function mime_header_one_word_decode($string) {
197 /* Default charset */
200 /* We expecting : encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
201 * See more detail in RFC 2407
204 /* No encoded-word, return default */
205 if (strncmp($string, "=?", 2)) {
206 return array("charset"=>$charset, "text" => $string);
210 * Expecting [0]='=', [1]=charset, [2]=B|Q, [3]=encoded-text
212 $string_arr = explode('?', $string);
214 if (!strcasecmp($string_arr[2], "B") && $string_arr[3]) {
215 $string = base64_decode($string_arr[3]);
216 $charset = $string_arr[1];
217 } elseif (!strcasecmp($string_arr[2], "Q") && $string_arr[3]) {
218 $string = quoted_printable_decode($string_arr[3]);
219 $charset = $string_arr[1];
222 /* Return what we have */
223 $ret_arr = array("charset"=>$charset, "text" => $string);
231 // c-file-style: "bsd"