85a7395e5052272f843195cc91db4ee215a1a269
[squirrelmail.git] / class / deliver / Deliver.class.php
1 <?php
2
3 class Deliver {
4
5 function mail($message, $stream) {
6
7 $rfc822_header = $message->rfc822_header;
8 if (count($message->entities)) {
9 $boundary = mimeBoundary();
10 $rfc822_header->contenttype->properties['boundary']=$boundary;
11 } else {
12 $boundary='';
13 }
14 $header = prepareRFC822_Header($rfc822_header);
15 $raw_length = strlen($header);
16 if ($stream) {
17 $this->preWriteToStream($s);
18 $this->writeToStream($stream, $s);
19 }
20 writeBody($message, $stream, $length_raw, $boundary);
21 return $raw_length;
22 }
23
24 function writeBody($message, $stream, &$length_raw, $boundary='') {
25 if ($boundary) {
26 $s = '--'.$boundary."\r\n";
27 $s .= $this->prepareMIME_Header($message, $boundary);
28 $length_raw += strlen($s);
29 if ($stream) {
30 $this->preWriteToStream($s);
31 $this->writeToStream($stream, $s);
32 }
33 }
34 writeBodyPart($message, $stream, $length_raw);
35 $boundary_depth = substr_count($message->entity_id,'.');
36 if ($boundary_depth) {
37 $boundary .= '_part'.$boundary_depth;
38 }
39 for ($i=0, $entCount=count($message->entities);$i<$entCount;$i++) {
40 $msg = writeBody($message->entities[$i], $stream, $length_raw, $boundary);
41 }
42 if ($boundary) {
43 $s = '--'.$boundary."--\r\n";
44 $length_raw += strlen($s);
45 if ($stream) {
46 $this->preWriteToStream($s);
47 $this->writeToStream($stream, $s);
48 }
49 }
50 }
51
52 function writeBodyPart($message, $stream, &$length) {
53 $body_part = '';
54 switch ($message->type0) {
55 case 'text':
56 case 'message':
57 if ($message->body_part) {
58 $body_part = $message->body_part;
59 $length += $this->clean_crlf($body_part);
60 if ($stream) {
61 $this->preWriteToStream($body_part);
62 $this->writeToStream($stream, $body_part)
63 }
64 } elseif ($message->att_local_name) {
65 $filename = $message->att_local_name;
66 $file = fopen ($filename, 'rb');
67 while ($tmp = fgets($file, 4096)) {
68 $length += $this->clean_crlf($tmp);
69 if ($stream) {
70 $this->preWriteToStream($tmp);
71 $this->writeToStream($stream, $tmp);
72 }
73 }
74 fclose($file);
75 }
76 break;
77 default:
78 if ($message->body_part) {
79 $body_part = $message->body_part;
80 $length += $this->clean_crlf($body_part);
81 if ($stream) {
82 $this->writeToStream($stream, $body_part)
83 }
84 } elseif ($message->att_local_name) {
85 $filename = $message->att_local_name;
86 $file = fopen ($filename, 'rb');
87 while ($tmp = fread($file, 1520)) {
88 $encoded = chunk_split(base64_encode($tmp));
89 $length += strlen($encoded);
90 if ($stream) {
91 $this->writeToStream($stream, $encoded);
92 }
93 }
94 fclose($file);
95 }
96 break;
97 }
98 }
99
100 function clean_crlf($s) {
101 $s = str_replace("\r\n", "\n", $s);
102 $s = str_replace("\r", "\n", $s);
103 $s = str_replace("\n", "\r\n", $s);
104 return strlen($s);
105 }
106
107 function preWriteToStream($&s) {
108 }
109
110 function writeToStream($stream, $data) {
111 }
112
113 function initStream($message, $length=0, $host='', $port='', $user='', $pass='') {
114 return $stream;
115 }
116
117 function prepareMIME_Header($message, $boundary) {
118 $mime_header = $message->header;
119 $rn="\r\n"
120 $header = array();
121
122 $contenttype = 'Content-Type: '. $mime_header->contenttype->type0 .'/'.
123 $mime_header->contenttype->type1;
124 if (count($message->entities)) {
125 $contenttype .= ";\r\n " . 'boundary="'.$boundary.'"';
126 }
127 if (isset($mime_header->parameters['name'])) {
128 $contenttype .= ";\r\n " . 'name="'.
129 encodeHeader($mime_header->parameters['name']). '"';
130 }
131 $header[] = $contenttype . $rn;
132 if ($mime_header->description) {
133 $header[] .= 'Content-Description: ' . $mime_header->description . $rn;
134 }
135 if ($mime_header->encoding) {
136 $header[] .= 'Content-Transfer-Encoding: ' . $mime_header->encoding . $rn;
137 }
138 if ($mime_header->id) {
139 $header[] .= 'Content-ID: ' . $mime_header->id . $rn;
140 }
141 if ($mime_header->disposition) {
142 $contentdisp .= 'Content-Disposition: ' . $mime_header->disposition;
143 if (isset($mime_header->parameters['filename'])) {
144 $contentdisp .= ";\r\n " . 'filename="'.
145 encodeHeader($mime_header->parameters['filename']). '"';
146 }
147 $header[] = $contentdisp . $rn;
148 }
149 if ($mime_header->md5) {
150 $header[] .= 'Content-MD5: ' . $mime_header->md5 . $rn;
151 }
152 if ($mime_header->language) {
153 $header[] .= 'Content-Language: ' . $mime_header->language . $rn;
154 }
155
156 $cnt = count($header);
157 $hdr_s = '';
158 for ($i = 0 ; $i < $cnt ; $i++) {
159 $hdr_s .= foldLine($header[$i], 78, ' ');
160 }
161 $header = $hdr_s;
162 $header .= $rn; /* One blank line to separate mimeheader and body-entity */
163 return $header;
164 }
165
166 function prepareRFC822_Header($rfc822_header) {
167 global $REMOTE_ADDR, $SERVER_NAME, $REMOTE_PORT;
168 global $version, $useSendmail, $username;
169 global $HTTP_VIA, $HTTP_X_FORWARDED_FOR;
170 global $REMOTE_HOST;
171
172 /* This creates an RFC 822 date */
173 $date = date("D, j M Y H:i:s ", mktime()) . timezone();
174 /* Create a message-id */
175 $message_id = '<' . $REMOTE_PORT . '.' . $REMOTE_ADDR . '.';
176 $message_id .= time() . '.squirrel@' . $SERVER_NAME .'>';
177 /* Make an RFC822 Received: line */
178 if (isset($REMOTE_HOST))
179 {
180 $received_from = "$REMOTE_HOST ([$REMOTE_ADDR])";
181 }
182 else
183 {
184 $received_from = $REMOTE_ADDR;
185 }
186 if (isset($HTTP_VIA) || isset ($HTTP_X_FORWARDED_FOR)) {
187 if ($HTTP_X_FORWARDED_FOR == '') {
188 $HTTP_X_FORWARDED_FOR = 'unknown';
189 }
190 $received_from .= " (proxying for $HTTP_X_FORWARDED_FOR)";
191 }
192 $header = array();
193 $header[] = "Received: from $received_from" . $rn;
194 $header[] = " (SquirrelMail authenticated user $username)" . $rn;
195 $header[] = " by $SERVER_NAME with HTTP;" . $rn;
196 $header[] = " $date" . $rn;
197 /* Insert the rest of the header fields */
198 $header[] = "Message-ID: $message_id" . $rn;
199 $header[] = "Date: $date" . $rn;
200 $header[] = 'Subject: '.encodeHeader($rfc822_header->subject) . $rn;
201 $header[] = 'From: '. encodeHeader($rfc822_header->getAddr_s('from')) . $rn;
202 if (count($rfc822_header->from) > 1) /* RFC2822 if from contains
203 more then 1 address */
204 {
205 $header[] = 'Sender: '. encodeHeader($rfc822_header->getAddr_s('sender')) . $rn;
206 }
207 $header[] = 'To: '. encodeHeader($rfc822_header->getAddr_s('to')) . $rn; // Who it's TO
208 if (count($rfc_header->cc))
209 {
210 $header[] = 'Cc: '. encodeHeader($rfc822_header->getAddr_s('cc')) . $rn;
211 }
212 if (count($rfc822_header->$reply_to))
213 {
214 $header[] = 'Reply-To: '. encodeHeader($rfc822_header->getAddr_s('reply_to')) . $rn;
215 }
216 if (count($rfc_header->bcc) && $useSendmail)
217 {
218 $header[] = 'Bcc: '. encodeHeader($rfc822_header->getAddr_s('bcc')) . $rn;
219 }
220 /* Identify SquirrelMail */
221 $header[] = "X-Mailer: SquirrelMail (version $version)" . $rn;
222 /* Do the MIME-stuff */
223 $header[] = "MIME-Version: 1.0" . $rn;
224 $contenttype = 'Content-Type: '. $rfc822_header->contenttype->type0 .'/'.
225 $rfc822_header->contenttype->type1;
226 if (count($rfc822_header->contenttype->properties))
227 {
228 foreach ($rfc822_header->contenttype->properties as $k => $v)
229 {
230 $contenttype .= ';'. "\r\n " .$k.'='.$v; /* FOLDING */
231 }
232 }
233 $header[] = $contenttype . $rn;
234 if ($rfc822_header->dnt)
235 {
236 $dnt = $rfc822_header->getAddr_s('dnt');
237 /* Pegasus Mail */
238 $header[] = 'X-Confirm-Reading-To: '.$dnt;
239 /* RFC 2298 */
240 $header[] = 'Disposition-Notification-To: '.$dnt;
241 }
242 if ($rfc822_header->priority)
243 {
244 $prio = $rfc822_header->priority;
245 $header[] = 'X-Priority: '.$prio;
246 switch($prio)
247 {
248 case 1:
249 $header[] = 'Importance: High';
250 $header[] = 'X-MSMail-Priority: High';
251 break;
252 case 3:
253 $header[] = 'Importance: Normal';
254 $header[] = 'X-MSMail-Priority: Normal';
255 break;
256 case 5:
257 $header[] = 'Importance: Low';
258 $header[] = 'X-MSMail-Priority: Low';
259 break;
260 default:
261 break;
262 }
263 }
264 /* Insert headers from the $more_headers array */
265 if(count($more_headers))
266 {
267 reset($more_headers);
268 foreach ($more_headers as $k => $v)
269 {
270 $header[] = $k.': '.$v;
271 }
272 }
273 $cnt = count($header);
274 $hdr_s = '';
275 for ($i = 0 ; $i < $cnt ; $i++)
276 {
277 $hdr_s .= foldLine($header[$i], 78, ' ');
278 }
279 $header = $hdr_s;
280 $header .= $rn; /* One blank line to separate header and body */
281
282 return $header;
283 }
284
285 /*
286 * function for cleanly folding of headerlines
287 */
288 function foldLine($line, $length, $pre) {
289 $cnt = strlen($line);
290 $res = '';
291 if ($cnt > $lenght)
292 {
293 $fold_string = $pre.' '."\r\n";
294 for ($i=0;$i<($cnt-$length);$i++)
295 {
296 $fold_pos = 0;
297 /* first try to fold at delimiters */
298 for ($j=($i+$length); $j>$i; $j--)
299 {
300 switch ($line{$j})
301 {
302 case (','):
303 case (';'):
304 $fold_pos = $j;
305 break;
306 default:
307 break;
308 }
309 if ($fold_pos)
310 {
311 $j=$i;
312 }
313 }
314 if (!$fold_pos)
315 {
316 /* not succeed yet so we try at spaces and = */
317 for ($j=($i+$length); $j>$i; $j--)
318 {
319 switch ($line{$j})
320 {
321 case (' '):
322 case ('='):
323 $fold_pos = $j;
324 break;
325 default:
326 break;
327 }
328 if ($fold_pos)
329 {
330 $j=$i;
331 }
332 }
333 }
334 if (!$fold_pos)
335 {
336 /* clean folding didn't work */
337 $fold_pos = $i+$length;
338 }
339 $line = substr_replace($line,$line{$fold_pos}.$fold_string,$fold_pos,1);
340 $cnt += strlen($fold_string);
341 $i = $j + strlen($fold_string);
342 }
343 }
344 return $line;
345 }
346 }
347
348 function mimeBoundary () {
349 static $mimeBoundaryString;
350
351 if ( !isset( $mimeBoundaryString ) ||
352 $mimeBoundaryString == '') {
353 $mimeBoundaryString = '----=_' . date( 'YmdHis' ) . '_' .
354 mt_rand( 10000, 99999 );
355 }
356
357 return $mimeBoundaryString;
358 }
359
360 /* Time offset for correct timezone */
361 function timezone () {
362 global $invert_time;
363
364 $diff_second = date('Z');
365 if ($invert_time) {
366 $diff_second = - $diff_second;
367 }
368 if ($diff_second > 0) {
369 $sign = '+';
370 }
371 else {
372 $sign = '-';
373 }
374
375 $diff_second = abs($diff_second);
376
377 $diff_hour = floor ($diff_second / 3600);
378 $diff_minute = floor (($diff_second-3600*$diff_hour) / 60);
379
380 $zonename = '('.strftime('%Z').')';
381 $result = sprintf ("%s%02d%02d %s", $sign, $diff_hour, $diff_minute,
382 $zonename);
383 return ($result);
384 }
385
386
387 ?>
388