00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00087 class t3lib_readmail {
00088 var $dateAbbrevs = array(
00089 'JAN' => 1,
00090 'FEB' => 2,
00091 'MAR' => 3,
00092 'APR' => 4,
00093 'MAY' => 5,
00094 'JUN' => 6,
00095 'JUL' => 7,
00096 'AUG' => 8,
00097 'SEP' => 9,
00098 'OCT' => 10,
00099 'NOV' => 11,
00100 'DEC' => 12
00101 );
00102 var $serverGMToffsetMinutes = 60;
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00122 function find_MIDfromReturnPath($to) {
00123 $parts = explode('mid',strtolower($to));
00124 $moreParts=explode('_',$parts[1]);
00125 $out=array(
00126 'mid' => $moreParts[0],
00127 'rtbl' => substr($moreParts[1],0,1),
00128 'rid' => intval(substr($moreParts[1],1))
00129 );
00130 if ($out['rtbl']=='p') $out['rtbl']='P';
00131
00132 return($out);
00133 }
00134
00142 function find_XTypo3MID($content) {
00143 if (strstr($content,'X-Typo3MID:')) {
00144 $p=explode('X-Typo3MID:',$content,2);
00145 $l=explode(chr(10),$p[1],2);
00146 list($mid,$hash)=t3lib_div::trimExplode('-',$l[0]);
00147 if (md5($mid)==$hash) {
00148 $moreParts=explode('_',substr($mid,3));
00149 $out=array(
00150 'mid' => $moreParts[0],
00151 'rtbl' => substr($moreParts[1],0,1),
00152 'rid' => substr($moreParts[1],1)
00153 );
00154 return($out);
00155 }
00156 }
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00188 function getMessage($mailParts) {
00189 if ($mailParts['content-type']) {
00190 $CType = $this->getCType($mailParts['content-type']);
00191 if ($CType['boundary']) {
00192 $parts = $this->getMailBoundaryParts($CType['boundary'],$mailParts['CONTENT']);
00193 $c=$this->getTextContent($parts[0]);
00194 } else {
00195 $c=$this->getTextContent(
00196 'Content-Type: '.$mailParts['content-type'].'
00197 '.$mailParts['CONTENT']
00198 );
00199 }
00200 } else {
00201 $c = $mailParts['CONTENT'];
00202 }
00203 return $c;
00204 }
00205
00213 function getTextContent($content) {
00214 $p=$this->extractMailHeader($content);
00215
00216
00217 return $p['CONTENT'];
00218 }
00219
00228 function getMailBoundaryParts($boundary,$content) {
00229 $mParts = explode('--'.$boundary,$content);
00230 unset($mParts[0]);
00231 reset($mParts);
00232 $new=array();
00233 while(list(,$val)=each($mParts)) {
00234 if (trim($val)=='--') break;
00235 $new[] = ltrim($val);
00236 }
00237 return $new;
00238 }
00239
00248 function getCType($str) {
00249 $parts = explode(';',$str);
00250 $cTypes=array();
00251 $cTypes['ContentType']=$parts[0];
00252 next($parts);
00253 while(list(,$ppstr)=each($parts)) {
00254 $mparts = explode('=',$ppstr,2);
00255 if (count($mparts)>1) {
00256 $cTypes[strtolower(trim($mparts[0]))]=ereg_replace('^"','',trim(ereg_replace('"$','',trim($mparts[1]))));
00257 } else {
00258 $cTypes[]=$ppstr;
00259 }
00260 }
00261 return $cTypes;
00262 }
00263
00271 function analyseReturnError($c) {
00272 $cp=array();
00273 if (strstr($c,'--- Below this line is a copy of the message.')) {
00274 list($c)=explode('--- Below this line is a copy of the message.',$c);
00275 $cp['content']=trim($c);
00276 $parts = explode('>:',$c,2);
00277 $cp['reason_text']=trim($parts[1]);
00278 $cp['mailserver']='Qmail';
00279 if (eregi('550|no mailbox|account does not exist',$cp['reason_text'])) {
00280 $cp['reason']=550;
00281 } elseif (stristr($cp['reason_text'],'couldn\'t find any host named')) {
00282 $cp['reason']=2;
00283 } elseif (eregi('Error in Header|invalid Message-ID header',$cp['reason_text'])) {
00284 $cp['reason']=554;
00285 } else {
00286 $cp['reason']=-1;
00287 }
00288 } elseif (strstr($c,'The Postfix program')) {
00289 $cp['content']=trim($c);
00290 $parts = explode('>:',$c,2);
00291 $cp['reason_text']=trim($parts[1]);
00292 $cp['mailserver']='Postfix';
00293 if (stristr($cp['reason_text'],'550')) {
00294 $cp['reason']=550;
00295 } elseif (stristr($cp['reason_text'],'553')) {
00296 $cp['reason']=553;
00297 } elseif (stristr($cp['reason_text'],'551')) {
00298 $cp['reason']=551;
00299 } else {
00300 $cp['reason']=-1;
00301 }
00302 } else {
00303 $cp['content']=trim($c);
00304 $cp['reason_text']=trim(substr($c,0,1000));
00305 $cp['mailserver']='unknown';
00306 if (eregi('Unknown Recipient|Delivery failed 550|Receiver not found|User not listed|recipient problem|Delivery to the following recipients failed|User unknown|recipient name is not recognized',$cp['reason_text'])) {
00307 $cp['reason']=550;
00308 } elseif (eregi('over quota|mailbox full',$cp['reason_text'])) {
00309 $cp['reason']=551;
00310 } elseif (eregi('Error in Header',$cp['reason_text'])) {
00311 $cp['reason']=554;
00312 } else {
00313 $cp['reason']=-1;
00314 }
00315 }
00316
00317 return $cp;
00318 }
00319
00326 function decodeHeaderString($str) {
00327 $parts = explode('=?',$str,2);
00328 if (count($parts)==2) {
00329 list($charset,$encType,$encContent)=explode('?',$parts[1],3);
00330 $subparts =explode('?=',$encContent,2);
00331 $encContent=$subparts[0];
00332
00333 switch(strtolower($encType)) {
00334 case 'q':
00335 $encContent = quoted_printable_decode($encContent);
00336 $encContent = str_replace('_',' ',$encContent);
00337 break;
00338 case 'b':
00339 $encContent=base64_decode($encContent);
00340 break;
00341 }
00342
00343 $parts[1]=$encContent.$this->decodeHeaderString($subparts[1]);
00344 }
00345 return implode('',$parts);
00346 }
00347
00354 function extractNameEmail($str) {
00355 $outArr=array();
00356
00357
00358 $reg='';
00359 ereg('<([^>]*)>',$str,$reg);
00360 if (t3lib_div::validEmail($str)) {
00361 $outArr['email']=$str;
00362 } elseif ($reg[1] && t3lib_div::validEmail($reg[1])) {
00363 $outArr['email']=$reg[1];
00364
00365 list($namePart)=explode($reg[0],$str);
00366 if (trim($namePart)) {
00367 $reg='';
00368 ereg('"([^"]*)"',$str,$reg);
00369 if (trim($reg[1])) {
00370 $outArr['name']=trim($reg[1]);
00371 } else $outArr['name']=trim($namePart);
00372 }
00373 }
00374 return $outArr;
00375 }
00376
00383 function getContentTypeData($contentTypeStr) {
00384 $outValue=array();
00385 $cTypeParts = t3lib_div::trimExplode(';',$contentTypeStr,1);
00386 $outValue['_MIME_TYPE']=$cTypeParts[0]; // content type, first value is supposed to be the mime-type, whatever after the first is something else.
00387
00388 reset($cTypeParts);
00389 next($cTypeParts);
00390 while(list(,$v)=Each($cTypeParts)) {
00391 $reg='';
00392 eregi('([^=]*)="(.*)"',$v,$reg);
00393 if (trim($reg[1]) && trim($reg[2])) {
00394 $outValue[strtolower($reg[1])] = $reg[2];
00395 }
00396 }
00397 return $outValue;
00398 }
00399
00406 function makeUnixDate($dateStr) {
00407 $dateParts=explode(',',$dateStr);
00408 $dateStr=count($dateParts)>1 ? $dateParts[1] : $dateParts[0];
00409
00410 $spaceParts = t3lib_div::trimExplode(' ',$dateStr,1);
00411
00412 $spaceParts[1]=$this->dateAbbrevs[strtoupper($spaceParts[1])];
00413 $timeParts = explode(':',$spaceParts[3]);
00414 $timeStamp = mktime ($timeParts[0], $timeParts[1], $timeParts[2], $spaceParts[1], $spaceParts[0], $spaceParts[2]);
00415
00416 $offset = $this->getGMToffset($spaceParts[4]);
00417 $timeStamp-=($offset*60); // Compensates for GMT by subtracting the number of seconds which the date is offset from serverTime
00418
00419 return $timeStamp;
00420 }
00421
00429 function getGMToffset($GMT) {
00430 $GMToffset=substr($GMT,1,2)*60+substr($GMT,3,2);
00431 $GMToffset*=substr($GMT,0,1)=='+'?1:-1;
00432 $GMToffset-=$this->serverGMToffsetMinutes;
00433 return $GMToffset;
00434 }
00435
00443 function extractMailHeader($content,$limit=0) {
00444 if ($limit) $content = substr($content,0,$limit);
00445
00446 $lines=explode(chr(10),ltrim($content));
00447 $headers=array();
00448 $p='';
00449 while(list($k,$str)=each($lines)) {
00450 if (!trim($str)) break; // header finished
00451 $parts = explode(' ',$str,2);
00452 if ($parts[0] && substr($parts[0],-1)==':') {
00453 $p=strtolower(substr($parts[0],0,-1));
00454 if (isset($headers[$p])) {
00455 $headers[$p.'.'][]=$headers[$p];
00456 $headers[$p]='';
00457 }
00458 $headers[$p]=trim($parts[1]);
00459 } else {
00460 $headers[$p].=' '.trim($str);
00461 }
00462 unset($lines[$k]);
00463 }
00464 if (!$limit) $headers['CONTENT']=ltrim(implode(chr(10),$lines));
00465 return $headers;
00466 }
00467
00474 function fullParse($content) {
00475 // *************************
00476 // PROCESSING the HEADER part of the mail
00477 // *************************
00478
00479 // Splitting header and body of mail:
00480 $mailParts = $this->extractMailHeader($content);
00481
00482 // Decoding header values which potentially can be encoded by =?...?=
00483 $list = explode(',','subject,thread-topic,from,to');
00484 while(list(,$headerType)=each($list)) {
00485 if (isset($mailParts[$headerType])) $mailParts[$headerType]=$this->decodeHeaderString($mailParts[$headerType]);
00486 }
00487 // Separating email/names from header fields which can contain email addresses.
00488 $list = explode(',','from,to,reply-to,sender,return-path');
00489 while(list(,$headerType)=each($list)) {
00490 if (isset($mailParts[$headerType])) {
00491 $mailParts['_'.strtoupper($headerType)]=$this->extractNameEmail($mailParts[$headerType]);
00492 }
00493 }
00494 // Decode date from human-readable format to unix-time (includes compensation for GMT CET)
00495 $mailParts['_DATE']=$this->makeUnixDate($mailParts['date']);
00496
00497 // Transfer encodings of body content
00498 switch(strtolower($mailParts['content-transfer-encoding'])) {
00499 case 'quoted-printable':
00500 $mailParts['CONTENT']=quoted_printable_decode($mailParts['CONTENT']);
00501 break;
00502 case 'base64':
00503 $mailParts['CONTENT']=base64_decode($mailParts['CONTENT']);
00504 break;
00505 }
00506
00507 // Content types
00508 $mailParts['_CONTENT_TYPE_DAT']=$this->getContentTypeData($mailParts['content-type']);
00509
00510
00511 // *************************
00512 // PROCESSING the CONTENT part of the mail (the body)
00513 // *************************
00514 $cType = strtolower($mailParts['_CONTENT_TYPE_DAT']['_MIME_TYPE']);
00515 $cType = substr($cType,0,9); // only looking for 'multipart' in string.
00516 switch($cType) {
00517 /* case 'multipart/mixed':
00518 case 'multipart/related':
00519 case 'multipart/alternative':
00520 case 'multipart/signed':
00521 */
00522 case 'multipart':
00523 if ($mailParts['_CONTENT_TYPE_DAT']['boundary']) {
00524 $contentSectionParts = t3lib_div::trimExplode('--'.$mailParts['_CONTENT_TYPE_DAT']['boundary'],$mailParts['CONTENT'],1);
00525 $contentSectionParts_proc=array();
00526
00527 reset($contentSectionParts);
00528 while(list($k,$v)=each($contentSectionParts)) {
00529 if (substr($v,0,2)=='--') break;
00530 $contentSectionParts_proc[$k]=$this->fullParse($v);
00531 }
00532 $mailParts['CONTENT']=$contentSectionParts_proc;
00533 } else $mailParts['CONTENT'] = 'ERROR: No boundary found.';
00534 break;
00535 default:
00536 if (strtolower($mailParts['_CONTENT_TYPE_DAT']['charset'])=='utf-8') {
00537 $mailParts['CONTENT']=utf8_decode($mailParts['CONTENT']);
00538 }
00539 break;
00540 }
00541 return $mailParts;
00542 }
00543 }
00544
00545 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_readmail.php']) {
00546 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_readmail.php']);
00547 }
00548 ?>