3 * FusionForge mail parser
5 * Copyright 2004, GForge, LLC
7 * This file is part of FusionForge.
9 * FusionForge is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License,
12 * or (at your option) any later version.
14 * FusionForge is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with FusionForge; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 require_once $gfcommon.'include/Error.class.php';
27 class MailParser extends Error {
29 var $max_file_size=2000000;
33 function MailParser($input_file) {
35 $size = filesize($input_file);
36 if ($size > $this->max_file_size) {
37 $this->setError("Error - file too large");
40 $fo = fopen($input_file, 'r');
41 $input_data = fread($fo, $size);
44 $lines=explode("\n",$input_data);
45 $linecount=count($lines);
48 //system("echo \"mp: headers".implode("***\n",$lines)."\n\" >> /tmp/forum.log");
50 // Read the message line-by-line
52 for ($i=0; $i<($linecount-1); $i++) {
53 //system("echo \"mp: line $i of $linecount length: ".strlen($lines[$i])." ".$lines[$i]."\n\" >> /tmp/forum.log");
55 // Still reading headers
59 // If we hit a blank line, end of headers
61 if (strlen($lines[$i]) < 2) {
65 // See if line starts with tab, if so ignore it for now
67 if (!ereg('^[A-z]',$lines[$i])) {
68 $header[$lastheader] = $header[$lastheader]."\n".$lines[$i];
70 $pos = (strpos($lines[$i],':'));
71 $header[substr($lines[$i],0,$pos)] = trim(substr($lines[$i],$pos+2,(strlen($lines[$i])-$pos-2)));
72 $lastheader=substr($lines[$i],0,$pos);
76 $body .= $lines[$i]."\r\n";
82 $this->headers =& $header;
84 if ($header['Content-Type']) {
85 $hdr = strtolower($header['Content-Type']);
86 if (strpos($hdr,'text/plain') !== false) {
89 $this->setError('Error - only text/plain supported at this time');
93 //echo "\n\n**".$header['Content-Type']."**\n\n";
98 //system("echo \"mp: headers".implode("***\n",$header)."\n\" >> /tmp/forum.log");
99 //system("echo \"mp: body".$body."\n\" >> /tmp/forum.log");
103 function &getBody() {
107 function &getHeader($header) {
108 return $this->headers[$header];
111 function getSubject() {
112 return $this->getHeader('Subject');
115 function getFromEmail() {
116 $mail = $this->getHeader('From');
117 if (strpos($mail,'(') !== false) {
118 $email = substr($mail,0,strpos($mail,' '));
119 } elseif (strpos($mail,'<') !== false) {
120 $begin=(strpos($mail,'<')+1);
121 $end = strpos($mail,'>');
122 $email = substr($mail,$begin,($end-$begin));
126 $email = str_replace('"','',$email);
128 //echo "***$mail*$begin*$end**".$email."*****";
129 //system("echo \"mp: email".$email."\n\" >> /tmp/forum.log");
133 /*------------------------------------------------------------------------
134 * MIME decoding functions
135 *-----------------------------------------------------------------------*/
137 * Subject and From decode implementation of RFC 2047
139 * @param String one or more encoded strings
140 * @return String strcat of all texts. Ignore all charsets
142 function mime_header_decode_string($string) {
144 $decoded_arr = $this->mime_header_decode($string);
146 $return_string = $decoded_arr[0]['text'];
149 for ($i=1; $i<count($decoded_arr); $i++) {
150 $return_string.=$decoded_arr[$i]['text'];
153 DBG("mime_header: $string -> $return_string \n");
155 return $return_string;
159 * Mime header decoding
161 * @param String to decode
162 * @return Decoded String Array. return['charset'] and retutn['text']
164 *# FIXME: Should we use imap_mime_headres_decode? It's too havey to install
165 * See http://us2.php.net/manual/en/function.imap-mime-header-decode.php
168 function mime_header_decode($string) {
169 /* We expecting series of encoded-word:
170 * encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
171 * See more detail in RFC 2407
174 $strlen = strlen($string);
176 for ($i=0; $i < $strlen; $i++) {
177 /* Start seperation */
178 if (!strcmp($string{$i} . $string{$i+1}, "=?")) {
183 if( !strcmp($string{$i} . $string{$i+1}, "?=")) {
184 $encoded_word_arr[$count].=$string{$i};
185 $encoded_word_arr[$count].=$string{++$i};
186 $count++; /* Null array should be OK */
190 $encoded_word_arr[$count].=$string{$i};
193 for ($i=0; $i<count($encoded_word_arr); $i++) {
194 $return_arr[$i] = $this->mime_header_one_word_decode($encoded_word_arr[$i]);
201 * one word decode implementation of RFC 2047
203 function mime_header_one_word_decode($string) {
204 /* Default charset */
207 /* We expecting : encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
208 * See more detail in RFC 2407
211 /* No encoded-word, return default */
212 if (strncmp($string, "=?", 2)) {
213 return array("charset"=>$charset, "text" => $string);
217 * Expecting [0]='=', [1]=charset, [2]=B|Q, [3]=encoded-text
219 $string_arr = explode('?', $string);
221 if (!strcasecmp($string_arr[2], "B") && $string_arr[3]) {
222 $string = base64_decode($string_arr[3]);
223 $charset = $string_arr[1];
224 } else if (!strcasecmp($string_arr[2], "Q") && $string_arr[3]) {
225 $string = quoted_printable_decode($string_arr[3]);
226 $charset = $string_arr[1];
229 /* Return what we have */
230 $ret_arr = array("charset"=>$charset, "text" => $string);
238 // c-file-style: "bsd"