| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @Author: Irakli Nadareishvili. irakli@gmail.com
|
| 6 |
* Copyright (C) The World Bank 2007
|
| 7 |
* Contents of this file are distributed under GPL license.
|
| 8 |
*
|
| 9 |
*/
|
| 10 |
|
| 11 |
define (INLINEIMAGES_TMPFOLDER, file_directory_temp() );
|
| 12 |
define (INLINEIMAGES_UPLOAD_FOLDER, file_directory_path() );
|
| 13 |
|
| 14 |
|
| 15 |
/**
|
| 16 |
* Implementation of hook_help().
|
| 17 |
*/
|
| 18 |
|
| 19 |
function inlineimages_help($section = 'admin/help#inlineimages') {
|
| 20 |
$output = '';
|
| 21 |
|
| 22 |
switch ($section) {
|
| 23 |
case 'admin/help#inlineimages':
|
| 24 |
$output = '<p>'. t('The inlineimages module provides integration with '.
|
| 25 |
'mailhandler module and adds ability to process '.
|
| 26 |
'images embedded in multipart (HTML) e-mails. ) </p>');
|
| 27 |
$output .= '<p>'. t('Extends and requires: mailhandler module. Requires: upload module') .'</p>';
|
| 28 |
return $output;
|
| 29 |
case 'admin/modules#description':
|
| 30 |
return t('Inline images support for mailhandler module. Requires upload module.');
|
| 31 |
case 'admin/mailhandler':
|
| 32 |
return t('Inline images support for mailhandler module. Requires upload module.');
|
| 33 |
|
| 34 |
}
|
| 35 |
}
|
| 36 |
|
| 37 |
/**
|
| 38 |
* Extremely useful function for debugging complex structures.
|
| 39 |
* It is effectively disabled by "return;" at the start of function for
|
| 40 |
* any production usage. Should be enabled only by inlineimages
|
| 41 |
* developers.
|
| 42 |
*/
|
| 43 |
function dbgr_show_object($object, $bgcolor="white", $color="black", $rows=20, $width="100%") {
|
| 44 |
|
| 45 |
//Always keep this disabled in production.
|
| 46 |
return;
|
| 47 |
|
| 48 |
echo '<textarea rows="'.$rows.'" style="'.$cols.'width: '.$width.'; '.
|
| 49 |
'background-color: '.$bgcolor.'; color: '.$color.'">';
|
| 50 |
|
| 51 |
print_r($object);
|
| 52 |
echo "</textarea>";
|
| 53 |
|
| 54 |
}
|
| 55 |
|
| 56 |
|
| 57 |
function inlineimages_mailhandler($node, $result, $i, $header, $mailbox) {
|
| 58 |
|
| 59 |
//For debugging only
|
| 60 |
//ini_set ("display_errors", "On");
|
| 61 |
|
| 62 |
$mailbox = $result;
|
| 63 |
$msg_no = $i;
|
| 64 |
|
| 65 |
|
| 66 |
$struct = imap_fetchstructure($mailbox, $msg_no);
|
| 67 |
|
| 68 |
// If it is not a multipart message, we should exit.
|
| 69 |
if ( !$struct->parts || $struct->parts<1) {
|
| 70 |
return $node;
|
| 71 |
}
|
| 72 |
|
| 73 |
/*
|
| 74 |
Attention: imap_fetchstructure may return non-flat
|
| 75 |
structure where a part contains other parts etc.
|
| 76 |
For instance, mime emails sent by Thunderbird represent
|
| 77 |
inline images like that. To process everything correctly,
|
| 78 |
and most importantly, determine the correct part_id (pid) that
|
| 79 |
can be used to fetch the body of the parts of the mail message,
|
| 80 |
we implemented a pre-scanner, based on code by Sito (thank you!):
|
| 81 |
http://us2.php.net/manual/en/function.imap-fetchbody.php#42622
|
| 82 |
*/
|
| 83 |
|
| 84 |
$info = scan($struct->parts, 0 );
|
| 85 |
|
| 86 |
$node->files = array();
|
| 87 |
|
| 88 |
$overview = imap_fetch_overview($mailbox, $msg_no);
|
| 89 |
|
| 90 |
$msgOrigID = $overview[0]->message_id;
|
| 91 |
$msgID = inlineimages_safe_messageid($msgOrigID);
|
| 92 |
|
| 93 |
$numparts = count($info);
|
| 94 |
|
| 95 |
dbgr_show_object ($info, "green", "yellow");
|
| 96 |
|
| 97 |
//echo '<div style="background-color:silver">'.$msgID.' with '.$numparts.' parts</div>';
|
| 98 |
|
| 99 |
|
| 100 |
if ($numparts > 1) {
|
| 101 |
|
| 102 |
$node = inlineimages_processParts($node, $info, $mailbox, $msg_no);
|
| 103 |
|
| 104 |
dbgr_show_object($node, "pink");
|
| 105 |
|
| 106 |
return $node;
|
| 107 |
}
|
| 108 |
|
| 109 |
//return $node;
|
| 110 |
|
| 111 |
}
|
| 112 |
|
| 113 |
function inlineimages_processParts($node, $parts, $mailbox, $msg_no, $numInlines=0, $partno=0) {
|
| 114 |
|
| 115 |
/*Trick: we append current unix timestamp to the original id
|
| 116 |
of the inline images. Thus, even if the same emails are fetched
|
| 117 |
multiple times, even though the id of the images in the email
|
| 118 |
are the same, there won't be a name-clash */
|
| 119 |
$utstamp = "_".time();
|
| 120 |
|
| 121 |
foreach ($parts as $part) {
|
| 122 |
|
| 123 |
if ($part['type'] == "image") {
|
| 124 |
|
| 125 |
$partno = $part['pid'];
|
| 126 |
$filename = $part['filename'];
|
| 127 |
$file_id = $part['file_id'];
|
| 128 |
$safe_file_id = strtr($file_id, "@", "_");
|
| 129 |
$ext= ".".strtolower($part['ext']);
|
| 130 |
if ( $ext == '.jpeg' ) $ext = '.jpg'; // minor hack :)
|
| 131 |
$filesize = $part['size'];
|
| 132 |
|
| 133 |
$rawContent = imap_fetchbody($mailbox, $msg_no, $partno);
|
| 134 |
$content = base64_decode($rawContent);
|
| 135 |
|
| 136 |
dbgr_show_object($rawContent, "black", "white");
|
| 137 |
|
| 138 |
$file_path = INLINEIMAGES_TMPFOLDER."/".$safe_file_id.$utstamp.$ext;
|
| 139 |
|
| 140 |
inlineimages_write_file($file_path, $content);
|
| 141 |
|
| 142 |
$base_url = url(NULL, NULL, NULL, TRUE);
|
| 143 |
$pattern='/cid\:'.preg_quote($file_id).'/';
|
| 144 |
$replacement = $base_url.INLINEIMAGES_UPLOAD_FOLDER."/".$safe_file_id.$utstamp.$ext;
|
| 145 |
$node->body = preg_replace($pattern, $replacement,$node->body);
|
| 146 |
|
| 147 |
// Fix all image tags (remove newline characters) to make them Drupal-safe
|
| 148 |
$pattern='/<img.+?>/ims';
|
| 149 |
$node->body = preg_replace_callback($pattern, "fixImageTags", $node->body );
|
| 150 |
$node->teaser = node_teaser($node->body);
|
| 151 |
|
| 152 |
$up=array();
|
| 153 |
$up[description] = $filename;
|
| 154 |
$up[remove] = 0; $up["list"]=1;
|
| 155 |
$up[filename] = $safe_file_id.$utstamp.$ext;
|
| 156 |
$up[filepath] = $file_path;
|
| 157 |
$up[filemime] = "image/".strtolower($part->subtype);
|
| 158 |
$up[filesize] = $filesize;
|
| 159 |
$up[fid]= "upload_".$numInlines;
|
| 160 |
|
| 161 |
//$up[description] =
|
| 162 |
//echo "<pre>";
|
| 163 |
//print_r($up);
|
| 164 |
|
| 165 |
|
| 166 |
$node->files["upload_".$numInlines]= $up;
|
| 167 |
|
| 168 |
$numInlines++;
|
| 169 |
|
| 170 |
}
|
| 171 |
|
| 172 |
$i++;
|
| 173 |
}
|
| 174 |
|
| 175 |
|
| 176 |
return $node;
|
| 177 |
|
| 178 |
}
|
| 179 |
|
| 180 |
/**
|
| 181 |
* Remove any carriage return or line feed characters within the
|
| 182 |
* image tag (passed through preg_replace_callback) as Drupal
|
| 183 |
* will try to put <br> or <p> tags and mess them
|
| 184 |
* up in a big way
|
| 185 |
*/
|
| 186 |
function fixImageTags ( $img_tags ) {
|
| 187 |
|
| 188 |
$tag = $img_tags[0];
|
| 189 |
$pattern='/\n|\r|\t/ims';
|
| 190 |
return preg_replace ( $pattern, '', $tag);
|
| 191 |
|
| 192 |
}
|
| 193 |
|
| 194 |
|
| 195 |
function inlineimages_safe_messageid($msgID) {
|
| 196 |
|
| 197 |
$trans = array("<" => "", ">" => "", "@" => "", "." => "");
|
| 198 |
$msgID= strtr($msgID, $trans);
|
| 199 |
return $msgID;
|
| 200 |
|
| 201 |
}
|
| 202 |
|
| 203 |
function inlineimages_write_file($path, $content) {
|
| 204 |
|
| 205 |
/*
|
| 206 |
* In reality we know the file with the same name will
|
| 207 |
* never exist since we make sure the filename is time-unique,
|
| 208 |
* but just in case, let's use REPLACE
|
| 209 |
*/
|
| 210 |
file_save_data($content, $path, FILE_EXISTS_REPLACE);
|
| 211 |
|
| 212 |
}
|
| 213 |
|
| 214 |
|
| 215 |
function scan($struct,$subkey, $ret_info=NULL){
|
| 216 |
|
| 217 |
$mime = array("text","multipart","message","application","audio",
|
| 218 |
"image","video","other","unknow");
|
| 219 |
|
| 220 |
$enc = array("7BIT","8BIT","BINARY","BASE64",
|
| 221 |
"QUOTED-PRINTABLE","OTHER");
|
| 222 |
|
| 223 |
$trans = array("<" => "", ">" => "");
|
| 224 |
|
| 225 |
if ($ret_info == NULL ) $ret_info = array();
|
| 226 |
$pos = count($ret_info);
|
| 227 |
|
| 228 |
foreach($struct as $key => $value){
|
| 229 |
|
| 230 |
|
| 231 |
if($subkey!=0){
|
| 232 |
$pid = $subkey.".".($key+1); }
|
| 233 |
else { $pid = ($key+1); }
|
| 234 |
|
| 235 |
$ret_info[$pos]['pid'] = $pid;
|
| 236 |
$ret_info[$pos]['type'] = $mime["$value->type"];
|
| 237 |
$ret_info[$pos]['encoding'] = $enc["$value->encoding"];
|
| 238 |
|
| 239 |
$ret_info[$pos]['filename']=$value->dparameters[0]->value;
|
| 240 |
$ret_info[$pos]['file_id']=strtr($value->id, $trans);
|
| 241 |
$ret_info[$pos]['ext']=$value->subtype;
|
| 242 |
$ret_info[$pos]['size']=$value->bytes;
|
| 243 |
|
| 244 |
$pos++;
|
| 245 |
|
| 246 |
if ( ($value->parts)!= null ) {
|
| 247 |
$ret_info = scan( $value->parts,$pid, $ret_info);
|
| 248 |
}
|
| 249 |
}
|
| 250 |
|
| 251 |
return $ret_info;
|
| 252 |
}
|