*** empty log message ***
[squirrelmail.git] / functions / imap_general.php
CommitLineData
59177427 1<?php
bccadd02 2
35586184 3/**
a6fd80f5 4 * imap_general.php
35586184 5 *
76911253 6 * Copyright (c) 1999-2003 The SquirrelMail Project Team
15e6162e 7 * Licensed under the GNU GPL. For full terms see the file COPYING.
35586184 8 *
15e6162e 9 * This implements all functions that do general imap functions.
35586184 10 *
15e6162e 11 * $Id$
35586184 12 */
13
b68edc75 14require_once(SM_PATH . 'functions/page_header.php');
47a29326 15require_once(SM_PATH . 'functions/auth.php');
16
35586184 17
41600f7d 18global $sqimap_session_id;
19$sqimap_session_id = 1;
71257f8b 20
3411d4ec 21/* Sets an unique session id in order to avoid simultanous sessions crash. */
487daa81 22function sqimap_session_id($unique_id = false) {
41600f7d 23 global $data_dir, $username, $sqimap_session_id;
487daa81 24 if (!$unique_id) {
098ea084 25 return( sprintf("A%03d", $sqimap_session_id++) );
487daa81 26 } else {
098ea084 27 return( sprintf("A%03d", $sqimap_session_id++) . ' UID' );
487daa81 28 }
9c737111 29}
30
3411d4ec 31/*
32 * Both send a command and accept the result from the command.
33 * This is to allow proper session number handling.
34 */
487daa81 35function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$response, &$message, $unique_id = false) {
c5809184 36 if ($imap_stream) {
098ea084 37 $sid = sqimap_session_id($unique_id);
38 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
bc78cc6e 39 $tag_uid_a = explode(' ',trim($sid));
40 $tag = $tag_uid_a[0];
0dc05a81 41 $read = sqimap_retrieve_imap_response ($imap_stream, $tag, $handle_errors, $response, $message, $query );
bc78cc6e 42 /* get the response and the message */
43 $message = $message[$tag];
44 $response = $response[$tag];
45 return $read[$tag];
c5809184 46 } else {
47 global $squirrelmail_language, $color;
48 set_up_language($squirrelmail_language);
49 require_once(SM_PATH . 'functions/display_messages.php');
50 $string = "<b><font color=$color[2]>\n" .
51 _("ERROR : No available imapstream.") .
52 "</b></font>\n";
53 error_box($string,$color);
098ea084 54 return false;
c5809184 55 }
1c72b151 56}
57
7c7b74b3 58function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response,
59 &$message, $unique_id = false,$filter=false,
60 $outputstream=false,$no_return=false) {
c5809184 61 if ($imap_stream) {
62 $sid = sqimap_session_id($unique_id);
bc78cc6e 63 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
64 $tag_uid_a = explode(' ',trim($sid));
65 $tag = $tag_uid_a[0];
66
67 $read = sqimap_read_data ($imap_stream, $tag, $handle_errors, $response,
7c7b74b3 68 $message, $query,$filter,$outputstream,$no_return);
bc78cc6e 69 /* retrieve the response and the message */
70 $response = $response[$tag];
71 $message = $message[$tag];
5c300c60 72
bc78cc6e 73 if (!empty($read[$tag])) {
74 return $read[$tag][0];
75 } else {
76 return $read[$tag];
77 }
c5809184 78 } else {
79 global $squirrelmail_language, $color;
80 set_up_language($squirrelmail_language);
81 require_once(SM_PATH . 'functions/display_messages.php');
82 $string = "<b><font color=$color[2]>\n" .
83 _("ERROR : No available imapstream.") .
84 "</b></font>\n";
85 error_box($string,$color);
098ea084 86 return false;
bc78cc6e 87 }
88}
89function sqimap_prepare_pipelined_query($new_query,&$tag,&$aQuery,$unique_id) {
90 $sid = sqimap_session_id($unique_id);
91 $tag_uid_a = explode(' ',trim($sid));
92 $tag = $tag_uid_a[0];
0b38d197 93 $query = $sid . ' '.$new_query."\r\n";
bc78cc6e 94 $aQuery[$tag] = $query;
42a07ac1 95}
96
52c8b585 97function sqimap_run_pipelined_command ($imap_stream, $aQueryList, $handle_errors,
bc78cc6e 98 &$aServerResponse, &$aServerMessage, $unique_id = false,
5c300c60 99 $filter=false,$outputstream=false,$no_return=false) {
bc78cc6e 100 $aResponse = false;
5c300c60 101
52c8b585 102 /*
103 Do not fire all calls at once to the imap-server but split the calls up
104 in portions of $iChunkSize. If we do not do that I think we misbehave as
105 IMAP client or should handle BYE calls if the IMAP-server drops the
106 connection because the number of queries is to large. This isn't tested
107 but a wild guess how it could work in the field.
0b38d197 108
c03cba15 109 After testing it on Exchange 2000 we discovered that a chunksize of 32
0b38d197 110 was quicker then when we raised it to 128.
52c8b585 111 */
112 $iQueryCount = count($aQueryList);
113 $iChunkSize = 32;
114 // array_chunk would also do the job but it's supported from php > 4.2
115 $aQueryChunks = array();
116 $iLoops = floor($iQueryCount / $iChunkSize);
117
5c300c60 118 if ($iLoops * $iChunkSize != $iQueryCount) ++$iLoops;
52c8b585 119
120 if (!function_exists('array_chunk')) { // arraychunk replacement
5c300c60 121 reset($aQueryList);
52c8b585 122 for($i=0;$i<$iLoops;++$i) {
5c300c60 123 for($j=0;$j<$iChunkSize;++$j) {
124 $key = key($aQueryList);
125 $aTmp[$key] = $aQueryList[$key];
126 if (next($aQueryList) === false) break;
127 }
128 $aQueryChunks[] = $aTmp;
129 }
52c8b585 130 } else {
131 $aQueryChunks = array_chunk($aQueryList,$iChunkSize,true);
bc78cc6e 132 }
52c8b585 133
134 for ($i=0;$i<$iLoops;++$i) {
135 $aQuery = $aQueryChunks[$i];
136 foreach($aQuery as $tag => $query) {
137 fputs($imap_stream,$query);
138 $aResults[$tag] = false;
139 }
52c8b585 140 foreach($aQuery as $tag => $query) {
5c300c60 141 if ($aResults[$tag] == false) {
0dc05a81 142 $aReturnedResponse = sqimap_retrieve_imap_response ($imap_stream, $tag,
bc78cc6e 143 $handle_errors, $response, $message, $query,
144 $filter,$outputstream,$no_return);
52c8b585 145 foreach ($aReturnedResponse as $returned_tag => $aResponse) {
5c300c60 146 if (!empty($aResponse)) {
52c8b585 147 $aResults[$returned_tag] = $aResponse[0];
5c300c60 148 } else {
149 $aResults[$returned_tag] = $aResponse;
150 }
52c8b585 151 $aServerResponse[$returned_tag] = $response[$returned_tag];
152 $aServerMessage[$returned_tag] = $message[$returned_tag];
153 }
bc78cc6e 154 }
155 }
156 }
b7277e4f 157 return $aResults;
bc78cc6e 158}
9c737111 159
b8c285ab 160/*
161 * custom fgets function. gets a line from IMAP
162 * no matter how big it may be
163 */
164
165function sqimap_fgets($imap_stream) {
166 $read = '';
167 $buffer = 4096;
168 $results = '';
c41daf03 169 $offset = 0;
170 while (strpos($results, "\r\n", $offset) === false) {
b8c285ab 171 if (!($read = fgets($imap_stream, $buffer))) {
329a7ca5 172 /* this happens in case of an error */
173 /* reset $results because it's useless */
174 $results = false;
b8c285ab 175 break;
176 }
c41daf03 177 if ( $results != '' ) {
178 $offset = strlen($results) - 1;
179 }
b8c285ab 180 $results .= $read;
181 }
182 return $results;
183}
184
7c7b74b3 185function sqimap_fread($imap_stream,$iSize,$filter=false,
186 $outputstream=false, $no_return=false) {
187 if (!$filter || !$outputstream) {
188 $iBufferSize = $iSize;
189 } else {
811318c5 190 // see php bug 24033. They changed fread behaviour %$^&$%
191 $iBufferSize = 780; // multiple of 78 in case of base64 decoding.
7c7b74b3 192 }
193 $iRet = $iSize - $iBufferSize;
5eba0be2 194 $iRetrieved = 0;
7c7b74b3 195 $i = 0;
bc78cc6e 196 $results = $sReadRem = '';
197 $bFinished = $bBufferSizeAdapted = $bBufferIsOk = false;
5eba0be2 198 while (($iRetrieved < ($iSize - $iBufferSize))) {
7c7b74b3 199 $sRead = fread($imap_stream,$iBufferSize);
bc78cc6e 200 if (!$sRead) {
7c7b74b3 201 $results = false;
202 break;
203 }
5eba0be2 204 $iRetrieved += $iBufferSize;
7c7b74b3 205 if ($filter) {
bc78cc6e 206 // in case line-endings do not appear at position 78 we adapt the buffersize so we can base64 decode on the fly
207 if (!$bBufferSizeAdapted) {
208 $i = strpos($sRead,"\n");
209 if ($i) {
210 ++$i;
211 $iFragments = floor($iBufferSize / $i);
212 $iNewBufferSize = $iFragments * $i;
213 $iRemainder = $iNewBufferSize + $i - $iBufferSize;
214 if ($iNewBufferSize == $iBufferSize) {
215 $bBufferIsOk = true;
216 $iRemainder = 0;
217 $iNewBufferSize = $iBufferSize;
218 $bBufferSizeAdapted = true;
219 }
220 if (!$bBufferIsOk && ($iRemainder + $iBufferSize) < $iSize) {
221 $sReadRem = fread($imap_stream,$iRemainder);
222 } else if (!$bBufferIsOk) {
223 $sReadRem = fread($imap_stream,$iSize - $iBufferSize);
224 $bFinished = true;
225 }
226 if (!$sReadRem && $sReadRem !== '') {
227 $results = false;
228 break;
229 }
230 $iBufferSize = $iNewBufferSize;
231 $bBufferSizeAdapted = true;
232 } else {
233 $sReadRem = fread($imap_stream,$iSize - $iBufferSize);
234 $bFinished = true;
235 if (!$sReadRem) {
236 $results = false;
237 break;
238 }
239 }
240 $sRead .= $sReadRem;
241 $iRetrieved += $iRemainder;
242 unset($sReadRem);
243 }
7c7b74b3 244 $filter($sRead);
245 }
246 if ($outputstream) {
247 if (is_resource($outputstream)) {
248 fwrite($outputstream,$sRead);
249 } else if ($outputstream == 'php://stdout') {
250 echo $sRead;
251 }
252 }
253 if ($no_return) {
254 $sRead = '';
255 }
256 $results .= $sRead;
257 }
bc78cc6e 258 if (!$results && !$bFinished) {
5eba0be2 259 $sRead = fread($imap_stream,($iSize - ($iRetrieved)));
7c7b74b3 260 if ($filter) {
261 $filter($sRead);
262 }
263 if ($outputstream) {
264 if (is_resource($outputstream)) {
265 fwrite($outputstream,$sRead);
266 } else if ($outputstream == 'php://stdout') { // FIXME
267 echo $sRead;
268 }
269 }
270 if ($no_return) {
271 $sRead = '';
272 }
273 $results .= $sRead;
274 }
275 return $results;
276}
0dc05a81 277/* obsolete function, inform plugins that use it */
278function sqimap_read_data_list($imap_stream, $tag, $handle_errors,
279 &$response, &$message, $query = '') {
280 global $color, $squirrelmail_language;
281 set_up_language($squirrelmail_language);
282 require_once(SM_PATH . 'functions/display_messages.php');
283 $string = "<b><font color=$color[2]>\n" .
284 _("ERROR : Bad function call.") .
285 "</b><br>\n" .
286 _("Reason:") . ' '.
287 'There is a plugin installed which make use of the <br>' .
288 'SquirrelMail internal function sqimap_read_data_list.<br>'.
5c300c60 289 'Please adapt the installed plugin and let it use<br>'.
290 'sqimap_run_command or sqimap_run_command_list instead<br><br>'.
291 'The following query was issued:<br>'.
0dc05a81 292 htmlspecialchars($query) . '<br>' . "</font><br>\n";
293 error_box($string,$color);
294 echo '</body></html>';
295 exit;
296}
7c7b74b3 297
4974c2a0 298function sqimap_error_box($title, $query = '', $message_title = '', $message = '')
299{
300 global $color, $squirrelmail_language;
301
302 set_up_language($squirrelmail_language);
303 require_once(SM_PATH . 'functions/display_messages.php');
304 $string = "<font color=$color[2]><b>\n" . $title . "</b><br>\n";
305 if ($query != '')
306 $string .= _("Query:") . ' ' . htmlspecialchars($query) . '<br>';
307 if ($message_title != '')
308 $string .= $message_title;
309 if ($message != '')
310 $string .= htmlspecialchars($message);
311 $string .= "</font><br>\n";
312 error_box($string,$color);
313}
314
bee165ef 315/*
3411d4ec 316 * Reads the output from the IMAP stream. If handle_errors is set to true,
317 * this will also handle all errors that are received. If it is not set,
318 * the errors will be sent back through $response and $message
bee165ef 319 */
b8c285ab 320
0dc05a81 321function sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
7c7b74b3 322 &$response, &$message, $query = '',
323 $filter = false, $outputstream = false, $no_return = false) {
9c737111 324 global $color, $squirrelmail_language;
9c737111 325 $read = '';
bc78cc6e 326 if (!is_array($message)) $message = array();
327 if (!is_array($response)) $response = array();
b8c285ab 328 $resultlist = array();
329 $data = array();
330 $read = sqimap_fgets($imap_stream);
5c300c60 331 $i = $k = 0;
bea3eb1e 332 while ($read) {
333 $char = $read{0};
334 switch ($char)
335 {
15bc7f66 336 case '+':
337 default:
338 $read = sqimap_fgets($imap_stream);
339 break;
340
341 case $tag{0}:
342 {
bea3eb1e 343 /* get the command */
344 $arg = '';
345 $i = strlen($tag)+1;
346 $s = substr($read,$i);
347 if (($j = strpos($s,' ')) || ($j = strpos($s,"\n"))) {
348 $arg = substr($s,0,$j);
349 }
350 $found_tag = substr($read,0,$i-1);
5c300c60 351 if ($found_tag) {
bea3eb1e 352 switch ($arg)
353 {
15bc7f66 354 case 'OK':
355 case 'BAD':
356 case 'NO':
357 case 'BYE':
358 case 'PREAUTH':
bc78cc6e 359 $response[$found_tag] = $arg;
360 $message[$found_tag] = trim(substr($read,$i+strlen($arg)));
361 if (!empty($data)) {
362 $resultlist[] = $data;
363 }
5c300c60 364 $aResponse[$found_tag] = $resultlist;
365 $data = $resultlist = array();
366 if ($found_tag == $tag) {
367 break 3; /* switch switch while */
368 }
369 break;
329a7ca5 370 default:
bea3eb1e 371 /* this shouldn't happen */
bc78cc6e 372 $response[$found_tag] = $arg;
373 $message[$found_tag] = trim(substr($read,$i+strlen($arg)));
374 if (!empty($data)) {
375 $resultlist[] = $data;
376 }
377 $aResponse[$found_tag] = $resultlist;
5c300c60 378 $data = $resultlist = array();
379 if ($found_tag == $tag) {
380 break 3; /* switch switch while */
381 }
bc78cc6e 382 }
bea3eb1e 383 }
5c300c60 384 $read = sqimap_fgets($imap_stream);
385 if ($read === false) { /* error */
386 break 3; /* switch switch while */
387 }
388 break;
15bc7f66 389 } // end case $tag{0}
390
391 case '*':
392 {
bea3eb1e 393 if (preg_match('/^\*\s\d+\sFETCH/',$read)) {
394 /* check for literal */
395 $s = substr($read,-3);
396 $fetch_data = array();
397 do { /* outer loop, continue until next untagged fetch
398 or tagged reponse */
399 do { /* innerloop for fetching literals. with this loop
400 we prohibid that literal responses appear in the
401 outer loop so we can trust the untagged and
402 tagged info provided by $read */
403 if ($s === "}\r\n") {
404 $j = strrpos($read,'{');
405 $iLit = substr($read,$j+1,-3);
406 $fetch_data[] = $read;
7c7b74b3 407 $sLiteral = sqimap_fread($imap_stream,$iLit,$filter,$outputstream,$no_return);
329a7ca5 408 if ($sLiteral === false) { /* error */
409 break 4; /* while while switch while */
410 }
bea3eb1e 411 /* backwards compattibility */
412 $aLiteral = explode("\n", $sLiteral);
413 /* release not neaded data */
414 unset($sLiteral);
415 foreach ($aLiteral as $line) {
416 $fetch_data[] = $line ."\n";
417 }
418 /* release not neaded data */
419 unset($aLiteral);
420 /* next fgets belongs to this fetch because
421 we just got the exact literalsize and there
422 must follow data to complete the response */
329a7ca5 423 $read = sqimap_fgets($imap_stream);
424 if ($read === false) { /* error */
425 break 4; /* while while switch while */
426 }
c0b23345 427 $fetch_data[] = $read;
bea3eb1e 428 } else {
329a7ca5 429 $fetch_data[] = $read;
bea3eb1e 430 }
431 /* retrieve next line and check in the while
432 statements if it belongs to this fetch response */
433 $read = sqimap_fgets($imap_stream);
329a7ca5 434 if ($read === false) { /* error */
435 break 4; /* while while switch while */
436 }
bea3eb1e 437 /* check for next untagged reponse and break */
438 if ($read{0} == '*') break 2;
439 $s = substr($read,-3);
440 } while ($s === "}\r\n");
441 $s = substr($read,-3);
442 } while ($read{0} !== '*' &&
106d4087 443 substr($read,0,strlen($tag)) !== $tag);
329a7ca5 444 $resultlist[] = $fetch_data;
bea3eb1e 445 /* release not neaded data */
446 unset ($fetch_data);
447 } else {
448 $s = substr($read,-3);
449 do {
450 if ($s === "}\r\n") {
451 $j = strrpos($read,'{');
452 $iLit = substr($read,$j+1,-3);
453 $data[] = $read;
329a7ca5 454 $sLiteral = fread($imap_stream,$iLit);
c0b23345 455 if ($sLiteral === false) { /* error */
329a7ca5 456 $read = false;
457 break 3; /* while switch while */
458 }
c0b23345 459 $data[] = $sLiteral;
b7277e4f 460 $data[] = sqimap_fgets($imap_stream);
bea3eb1e 461 } else {
329a7ca5 462 $data[] = $read;
bea3eb1e 463 }
464 $read = sqimap_fgets($imap_stream);
329a7ca5 465 if ($read === false) {
466 break 3; /* while switch while */
467 } else if ($read{0} == '*') {
106d4087 468 break;
469 }
bea3eb1e 470 $s = substr($read,-3);
471 } while ($s === "}\r\n");
472 break 1;
5c300c60 473 }
bea3eb1e 474 break;
15bc7f66 475 } // end case '*'
476 } // end switch
c0b23345 477 } // end while
478
479 /* error processing in case $read is false */
480 if ($read === false) {
481 unset($data);
4974c2a0 482 sqimap_error_box(_("ERROR : Connection dropped by imap-server."), $query);
c0b23345 483 exit;
b8c285ab 484 }
c0b23345 485
15bc7f66 486 /* Set $resultlist array */
b8c285ab 487 if (!empty($data)) {
bc78cc6e 488 //$resultlist[] = $data;
9c737111 489 }
b8c285ab 490 elseif (empty($resultlist)) {
491 $resultlist[] = array();
492 }
15bc7f66 493
494 /* Return result or handle errors */
bee165ef 495 if ($handle_errors == false) {
bc78cc6e 496 return $aResponse;
4974c2a0 497 return( $resultlist ); //?? Why this?
dd381002 498 }
4974c2a0 499 switch ($response[$tag]) {
dd381002 500 case 'OK':
bc78cc6e 501 return $aResponse;
329a7ca5 502 break;
dd381002 503 case 'NO':
504 /* ignore this error from M$ exchange, it is not fatal (aka bug) */
6b6c2e06 505 if (strstr($message[$tag], 'command resulted in') === false) {
4974c2a0 506 sqimap_error_box(_("ERROR : Could not complete request."), $query, _("Reason Given: "), $message[$tag]);
329a7ca5 507 echo '</body></html>';
052e0c26 508 exit;
9c737111 509 }
329a7ca5 510 break;
dd381002 511 case 'BAD':
4974c2a0 512 sqimap_error_box(_("ERROR : Bad or malformed request."), $query, _("Server responded: "), $message[$tag]);
329a7ca5 513 echo '</body></html>';
dd381002 514 exit;
515 case 'BYE':
4974c2a0 516 sqimap_error_box(_("ERROR : Imap server closed the connection."), $query, _("Server responded: "), $message[$tag]);
329a7ca5 517 echo '</body></html>';
9c737111 518 exit;
dd381002 519 default:
4974c2a0 520 sqimap_error_box(_("ERROR : Unknown imap response."), $query, _("Server responded: "), $message[$tag]);
329a7ca5 521 /* the error is displayed but because we don't know the reponse we
522 return the result anyway */
bc78cc6e 523 return $aResponse;
329a7ca5 524 break;
9c737111 525 }
9c737111 526}
527
7c7b74b3 528function sqimap_read_data ($imap_stream, $tag_uid, $handle_errors,
529 &$response, &$message, $query = '',
530 $filter=false,$outputstream=false,$no_return=false) {
bc78cc6e 531
532 $tag_uid_a = explode(' ',trim($tag_uid));
533 $tag = $tag_uid_a[0];
534
0dc05a81 535 $res = sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
7c7b74b3 536 $response, $message, $query,$filter,$outputstream,$no_return);
863936bb 537 /* sqimap_read_data should be called for one response
0dc05a81 538 but since it just calls sqimap_retrieve_imap_response which
863936bb 539 handles multiple responses we need to check for that
540 and merge the $res array IF they are seperated and
541 IF it was a FETCH response. */
542
ba8f367a 543// if (isset($res[1]) && is_array($res[1]) && isset($res[1][0])
544// && preg_match('/^\* \d+ FETCH/', $res[1][0])) {
545// $result = array();
546// foreach($res as $index=>$value) {
547// $result = array_merge($result, $res["$index"]);
548// }
549// }
863936bb 550 if (isset($result)) {
bc78cc6e 551 return $result[$tag];
56afb33f 552 }
56afb33f 553 else {
bc78cc6e 554 return $res;
56afb33f 555 }
9c737111 556}
557
3411d4ec 558/*
559 * Logs the user into the imap server. If $hide is set, no error messages
560 * will be displayed. This function returns the imap connection handle.
561 */
9c737111 562function sqimap_login ($username, $password, $imap_server_address, $imap_port, $hide) {
47a29326 563 global $color, $squirrelmail_language, $onetimepad, $use_imap_tls, $imap_auth_mech;
85fc999e 564
eb2f6102 565 if (!isset($onetimepad) || empty($onetimepad)) {
566 sqgetglobalvar('onetimepad' , $onetimepad , SQ_SESSION );
567 }
bd9829d7 568 $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
098ea084 569 $host=$imap_server_address;
570
571 if (($use_imap_tls == true) and (check_php_version(4,3)) and (extension_loaded('openssl'))) {
572 /* Use TLS by prefixing "tls://" to the hostname */
573 $imap_server_address = 'tls://' . $imap_server_address;
574 }
47a29326 575
3411d4ec 576 $imap_stream = fsockopen ( $imap_server_address, $imap_port, $error_number, $error_string, 15);
85fc999e 577
3411d4ec 578 /* Do some error correction */
9c737111 579 if (!$imap_stream) {
580 if (!$hide) {
441f2d33 581 set_up_language($squirrelmail_language, true);
098ea084 582 require_once(SM_PATH . 'functions/display_messages.php');
583 $string = sprintf (_("Error connecting to IMAP server: %s.") .
584 "<br>\r\n", $imap_server_address) .
1f720b34 585 "$error_number : $error_string<br>\r\n";
098ea084 586 logout_error($string,$color);
9c737111 587 }
588 exit;
589 }
052e0c26 590
2f1f7a12 591 $server_info = fgets ($imap_stream, 1024);
592
593 /* Decrypt the password */
594 $password = OneTimePadDecrypt($password, $onetimepad);
595
098ea084 596 if (($imap_auth_mech == 'cram-md5') OR ($imap_auth_mech == 'digest-md5')) {
fe0b18b3 597 // We're using some sort of authentication OTHER than plain or login
098ea084 598 $tag=sqimap_session_id(false);
599 if ($imap_auth_mech == 'digest-md5') {
600 $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
601 } elseif ($imap_auth_mech == 'cram-md5') {
602 $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
603 }
604 fputs($imap_stream,$query);
605 $answer=sqimap_fgets($imap_stream);
606 // Trim the "+ " off the front
607 $response=explode(" ",$answer,3);
608 if ($response[0] == '+') {
609 // Got a challenge back
610 $challenge=$response[1];
611 if ($imap_auth_mech == 'digest-md5') {
612 $reply = digest_md5_response($username,$password,$challenge,'imap',$host);
613 } elseif ($imap_auth_mech == 'cram-md5') {
614 $reply = cram_md5_response($username,$password,$challenge);
615 }
616 fputs($imap_stream,$reply);
617 $read=sqimap_fgets($imap_stream);
618 if ($imap_auth_mech == 'digest-md5') {
619 // DIGEST-MD5 has an extra step..
620 if (substr($read,0,1) == '+') { // OK so far..
621 fputs($imap_stream,"\r\n");
622 $read=sqimap_fgets($imap_stream);
623 }
624 }
625 $results=explode(" ",$read,3);
626 $response=$results[1];
627 $message=$results[2];
47a29326 628 } else {
098ea084 629 // Fake the response, so the error trap at the bottom will work
630 $response="BAD";
631 $message='IMAP server does not appear to support the authentication method selected.';
632 $message .= ' Please contact your system administrator.';
47a29326 633 }
fe0b18b3 634 } elseif ($imap_auth_mech == 'login') {
098ea084 635 // Original IMAP login code
fbb76d0e 636 $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
47a29326 637 $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
1e7fc1cb 638 } elseif ($imap_auth_mech == 'plain') {
098ea084 639 /* Replace this with SASL PLAIN if it ever gets implemented */
640 $response="BAD";
641 $message='SquirrelMail does not support SASL PLAIN yet. Rerun conf.pl and use login instead.';
642 } else {
643 $response="BAD";
644 $message="Internal SquirrelMail error - unknown IMAP authentication method chosen. Please contact the developers.";
645 }
47a29326 646
098ea084 647 /* If the connection was not successful, lets see why */
9c737111 648 if ($response != 'OK') {
649 if (!$hide) {
74424a43 650 if ($response != 'NO') {
3411d4ec 651 /* "BAD" and anything else gets reported here. */
098ea084 652 $message = htmlspecialchars($message);
9c737111 653 set_up_language($squirrelmail_language, true);
098ea084 654 require_once(SM_PATH . 'functions/display_messages.php');
9c737111 655 if ($response == 'BAD') {
bea3eb1e 656 $string = sprintf (_("Bad request: %s")."<br>\r\n", $message);
9c737111 657 } else {
bea3eb1e 658 $string = sprintf (_("Unknown error: %s") . "<br>\n", $message);
9c737111 659 }
1e7fc1cb 660 if (isset($read) && is_array($read)) {
bea3eb1e 661 $string .= '<br>' . _("Read data:") . "<br>\n";
9c737111 662 foreach ($read as $line) {
1f720b34 663 $string .= htmlspecialchars($line) . "<br>\n";
9c737111 664 }
665 }
098ea084 666 error_box($string,$color);
9c737111 667 exit;
165e24a7 668 } else {
3411d4ec 669 /*
670 * If the user does not log in with the correct
1c72b151 671 * username and password it is not possible to get the
672 * correct locale from the user's preferences.
673 * Therefore, apply the same hack as on the login
674 * screen.
3411d4ec 675 *
676 * $squirrelmail_language is set by a cookie when
1c72b151 677 * the user selects language and logs out
bee165ef 678 */
9be8198d 679
9c737111 680 set_up_language($squirrelmail_language, true);
bd9c880b 681 include_once(SM_PATH . 'functions/display_messages.php' );
098ea084 682 sqsession_destroy();
bd9c880b 683 logout_error( _("Unknown user or password incorrect.") );
9c737111 684 exit;
052e0c26 685 }
9c737111 686 } else {
052e0c26 687 exit;
9c737111 688 }
689 }
9c737111 690 return $imap_stream;
691}
f1e6f580 692
3411d4ec 693/* Simply logs out the IMAP session */
9c737111 694function sqimap_logout ($imap_stream) {
8d936b0c 695 /* Logout is not valid until the server returns 'BYE'
696 * If we don't have an imap_ stream we're already logged out */
26a2cc8b 697 if(isset($imap_stream) && $imap_stream)
8d936b0c 698 sqimap_run_command($imap_stream, 'LOGOUT', false, $response, $message);
9c737111 699}
700
487daa81 701function sqimap_capability($imap_stream, $capability='') {
9c737111 702 global $sqimap_capabilities;
9c737111 703 if (!is_array($sqimap_capabilities)) {
1c72b151 704 $read = sqimap_run_command($imap_stream, 'CAPABILITY', true, $a, $b);
705
9c737111 706 $c = explode(' ', $read[0]);
707 for ($i=2; $i < count($c); $i++) {
708 $cap_list = explode('=', $c[$i]);
3411d4ec 709 if (isset($cap_list[1])) {
9c737111 710 $sqimap_capabilities[$cap_list[0]] = $cap_list[1];
3411d4ec 711 } else {
9c737111 712 $sqimap_capabilities[$cap_list[0]] = TRUE;
3411d4ec 713 }
f1e6f580 714 }
9c737111 715 }
487daa81 716 if ($capability) {
098ea084 717 if (isset($sqimap_capabilities[$capability])) {
718 return $sqimap_capabilities[$capability];
719 } else {
720 return false;
721 }
f1e6f580 722 }
487daa81 723 return $sqimap_capabilities;
9c737111 724}
725
3411d4ec 726/* Returns the delimeter between mailboxes: INBOX/Test, or INBOX.Test */
9c737111 727function sqimap_get_delimiter ($imap_stream = false) {
3411d4ec 728 global $sqimap_delimiter, $optional_delimiter;
85fc999e 729
9c737111 730 /* Use configured delimiter if set */
731 if((!empty($optional_delimiter)) && $optional_delimiter != 'detect') {
732 return $optional_delimiter;
733 }
85fc999e 734
9c737111 735 /* Do some caching here */
736 if (!$sqimap_delimiter) {
737 if (sqimap_capability($imap_stream, 'NAMESPACE')) {
3411d4ec 738 /*
739 * According to something that I can't find, this is supposed to work on all systems
740 * OS: This won't work in Courier IMAP.
741 * OS: According to rfc2342 response from NAMESPACE command is:
742 * OS: * NAMESPACE (PERSONAL NAMESPACES) (OTHER_USERS NAMESPACE) (SHARED NAMESPACES)
743 * OS: We want to lookup all personal NAMESPACES...
744 */
1c72b151 745 $read = sqimap_run_command($imap_stream, 'NAMESPACE', true, $a, $b);
f1e6f580 746 if (eregi('\\* NAMESPACE +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL)', $read[0], $data)) {
9c737111 747 if (eregi('^\\( *\\((.*)\\) *\\)', $data[1], $data2)) {
f1e6f580 748 $pn = $data2[1];
9c737111 749 }
f1e6f580 750 $pna = explode(')(', $pn);
9c737111 751 while (list($k, $v) = each($pna)) {
862ff2d3 752 $lst = explode('"', $v);
753 if (isset($lst[3])) {
754 $pn[$lst[1]] = $lst[3];
755 } else {
74424a43 756 $pn[$lst[1]] = '';
862ff2d3 757 }
f1e6f580 758 }
759 }
760 $sqimap_delimiter = $pn[0];
761 } else {
762 fputs ($imap_stream, ". LIST \"INBOX\" \"\"\r\n");
763 $read = sqimap_read_data($imap_stream, '.', true, $a, $b);
764 $quote_position = strpos ($read[0], '"');
765 $sqimap_delimiter = substr ($read[0], $quote_position+1, 1);
766 }
767 }
768 return $sqimap_delimiter;
9c737111 769}
052e0c26 770
771
b2306cbe 772function sqimap_encode_mailbox_name($what)
773{
774 if (ereg("[\"\\\r\n]", $what))
775 return '{' . strlen($what) . "}\r\n" . $what; /* 4.3 literal form */
776 return '"' . $what . '"'; /* 4.3 quoted string form */
777}
778
779
3411d4ec 780/* Gets the number of messages in the current mailbox. */
9c737111 781function sqimap_get_num_messages ($imap_stream, $mailbox) {
b2306cbe 782 $read_ary = sqimap_run_command ($imap_stream, 'EXAMINE ' . sqimap_encode_mailbox_name($mailbox), false, $result, $message);
9c737111 783 for ($i = 0; $i < count($read_ary); $i++) {
85fc999e 784 if (ereg("[^ ]+ +([^ ]+) +EXISTS", $read_ary[$i], $regs)) {
785 return $regs[1];
786 }
9c737111 787 }
1f720b34 788 return false; //"BUG! Couldn't get number of messages in $mailbox!";
9c737111 789}
790
cfe1a81e 791
91688e5f 792function parseAddress($address, $max=0) {
793 $aTokens = array();
794 $aAddress = array();
795 $iCnt = strlen($address);
796 $aSpecials = array('(' ,'<' ,',' ,';' ,':');
797 $aReplace = array(' (',' <',' ,',' ;',' :');
798 $address = str_replace($aSpecials,$aReplace,$address);
bc78cc6e 799 $i = $iAddrFound = $bGroup = 0;
91688e5f 800 while ($i < $iCnt) {
801 $cChar = $address{$i};
802 switch($cChar)
329a7ca5 803 {
804 case '<':
805 $iEnd = strpos($address,'>',$i+1);
806 if (!$iEnd) {
807 $sToken = substr($address,$i);
808 $i = $iCnt;
809 } else {
810 $sToken = substr($address,$i,$iEnd - $i +1);
811 $i = $iEnd;
812 }
813 $sToken = str_replace($aReplace, $aSpecials,$sToken);
814 $aTokens[] = $sToken;
815 break;
816 case '"':
817 $iEnd = strpos($address,$cChar,$i+1);
da1e42a1 818 if ($iEnd) {
819 // skip escaped quotes
820 $prev_char = $address{$iEnd-1};
821 while ($prev_char === '\\' && substr($address,$iEnd-2,2) !== '\\\\') {
822 $iEnd = strpos($address,$cChar,$iEnd+1);
823 if ($iEnd) {
824 $prev_char = $address{$iEnd-1};
825 } else {
826 $prev_char = false;
827 }
828 }
829 }
329a7ca5 830 if (!$iEnd) {
831 $sToken = substr($address,$i);
832 $i = $iCnt;
833 } else {
834 // also remove the surrounding quotes
835 $sToken = substr($address,$i+1,$iEnd - $i -1);
836 $i = $iEnd;
837 }
838 $sToken = str_replace($aReplace, $aSpecials,$sToken);
76c3ee28 839 if ($sToken) $aTokens[] = $sToken;
329a7ca5 840 break;
841 case '(':
842 $iEnd = strpos($address,')',$i);
843 if (!$iEnd) {
844 $sToken = substr($address,$i);
845 $i = $iCnt;
846 } else {
847 $sToken = substr($address,$i,$iEnd - $i + 1);
848 $i = $iEnd;
849 }
850 $sToken = str_replace($aReplace, $aSpecials,$sToken);
851 $aTokens[] = $sToken;
852 break;
853 case ',':
bc78cc6e 854 ++$iAddrFound;
329a7ca5 855 case ';':
bc78cc6e 856 if (!$bGroup) {
857 ++$iAddrFound;
858 } else {
859 $bGroup = false;
860 }
861 if ($max && $max == $iAddrFound) {
862 break 2;
863 } else {
864 $aTokens[] = $cChar;
865 break;
866 }
867 case ':':
868 $bGroup = true;
329a7ca5 869 case ' ':
870 $aTokens[] = $cChar;
871 break;
91688e5f 872 default:
329a7ca5 873 $iEnd = strpos($address,' ',$i+1);
874 if ($iEnd) {
875 $sToken = trim(substr($address,$i,$iEnd - $i));
876 $i = $iEnd-1;
91688e5f 877 } else {
329a7ca5 878 $sToken = trim(substr($address,$i));
879 $i = $iCnt;
91688e5f 880 }
329a7ca5 881 if ($sToken) $aTokens[] = $sToken;
91688e5f 882 }
329a7ca5 883 ++$i;
9c737111 884 }
91688e5f 885 $sPersonal = $sEmail = $sComment = $sGroup = '';
886 $aStack = $aComment = array();
887 foreach ($aTokens as $sToken) {
888 if ($max && $max == count($aAddress)) {
329a7ca5 889 return $aAddress;
092d4f2c 890 }
329a7ca5 891 $cChar = $sToken{0};
91688e5f 892 switch ($cChar)
329a7ca5 893 {
894 case '=':
895 case '"':
896 case ' ':
897 $aStack[] = $sToken;
898 break;
899 case '(':
900 $aComment[] = substr($sToken,1,-1);
901 break;
902 case ';':
903 if ($sGroup) {
904 $sEmail = trim(implode(' ',$aStack));
905 $aAddress[] = array($sGroup,$sEmail);
906 $aStack = $aComment = array();
907 $sGroup = '';
908 break;
909 }
910 case ',':
911 if (!$sEmail) {
912 while (count($aStack) && !$sEmail) {
913 $sEmail = trim(array_pop($aStack));
914 }
915 }
916 if (count($aStack)) {
917 $sPersonal = trim(implode('',$aStack));
918 } else {
919 $sPersonal = '';
bea3eb1e 920 }
329a7ca5 921 if (!$sPersonal && count($aComment)) {
922 $sComment = implode(' ',$aComment);
923 $sPersonal .= $sComment;
924 }
925 $aAddress[] = array($sEmail,$sPersonal);
926 $sPersonal = $sComment = $sEmail = '';
927 $aStack = $aComment = array();
928 break;
929 case ':':
930 $sGroup = implode(' ',$aStack); break;
931 $aStack = array();
932 break;
933 case '<':
934 $sEmail = trim(substr($sToken,1,-1));
935 break;
936 case '>':
937 /* skip */
938 break;
939 default: $aStack[] = $sToken; break;
33565ec4 940 }
7e3de682 941 }
91688e5f 942 /* now do the action again for the last address */
943 if (!$sEmail) {
944 while (count($aStack) && !$sEmail) {
329a7ca5 945 $sEmail = trim(array_pop($aStack));
91688e5f 946 }
7e3de682 947 }
91688e5f 948 if (count($aStack)) {
329a7ca5 949 $sPersonal = trim(implode('',$aStack));
098ea084 950 } else {
91688e5f 951 $sPersonal = '';
9c737111 952 }
329a7ca5 953 if (!$sPersonal && count($aComment)) {
91688e5f 954 $sComment = implode(' ',$aComment);
329a7ca5 955 $sPersonal .= $sComment;
91688e5f 956 }
957 $aAddress[] = array($sEmail,$sPersonal);
958 return $aAddress;
959}
960
961
85fc999e 962
9c737111 963/*
3411d4ec 964 * Returns the number of unseen messages in this folder
965 */
9c737111 966function sqimap_unseen_messages ($imap_stream, $mailbox) {
b2306cbe 967 $read_ary = sqimap_run_command ($imap_stream, 'STATUS ' . sqimap_encode_mailbox_name($mailbox) . ' (UNSEEN)', false, $result, $message);
ea7ff111 968 $i = 0;
1f720b34 969 $regs = array(false, false);
ea7ff111 970 while (isset($read_ary[$i])) {
971 if (ereg("UNSEEN ([0-9]+)", $read_ary[$i], $regs)) {
972 break;
973 }
974 $i++;
975 }
9c737111 976 return $regs[1];
977}
978
1f720b34 979/*
4974c2a0 980 * Returns the number of total/unseen/recent messages in this folder
1f720b34 981 */
982function sqimap_status_messages ($imap_stream, $mailbox) {
b2306cbe 983 $read_ary = sqimap_run_command ($imap_stream, 'STATUS ' . sqimap_encode_mailbox_name($mailbox) . ' (MESSAGES UNSEEN RECENT)', false, $result, $message);
1f720b34 984 $i = 0;
b8ec18ef 985 $messages = $unseen = $recent = false;
1f720b34 986 $regs = array(false,false);
987 while (isset($read_ary[$i])) {
988 if (preg_match('/UNSEEN\s+([0-9]+)/i', $read_ary[$i], $regs)) {
098ea084 989 $unseen = $regs[1];
990 }
1f720b34 991 if (preg_match('/MESSAGES\s+([0-9]+)/i', $read_ary[$i], $regs)) {
098ea084 992 $messages = $regs[1];
993 }
b8ec18ef 994 if (preg_match('/RECENT\s+([0-9]+)/i', $read_ary[$i], $regs)) {
098ea084 995 $recent = $regs[1];
996 }
1f720b34 997 $i++;
998 }
b8ec18ef 999 return array('MESSAGES' => $messages, 'UNSEEN'=>$unseen, 'RECENT' => $recent);
1f720b34 1000}
1001
9c737111 1002
1003/*
3411d4ec 1004 * Saves a message to a given folder -- used for saving sent messages
1005 */
9c737111 1006function sqimap_append ($imap_stream, $sent_folder, $length) {
b2306cbe 1007 fputs ($imap_stream, sqimap_session_id() . ' APPEND ' . sqimap_encode_mailbox_name($sent_folder) . " (\\Seen) \{$length}\r\n");
85fc999e 1008 $tmp = fgets ($imap_stream, 1024);
9c737111 1009}
1010
8813fb15 1011function sqimap_append_done ($imap_stream, $folder='') {
1f720b34 1012 global $squirrelmail_language, $color;
9c737111 1013 fputs ($imap_stream, "\r\n");
1014 $tmp = fgets ($imap_stream, 1024);
69146537 1015 if (preg_match("/(.*)(BAD|NO)(.*)$/", $tmp, $regs)) {
1016 set_up_language($squirrelmail_language);
1f720b34 1017 require_once(SM_PATH . 'functions/display_messages.php');
098ea084 1018 $reason = $regs[3];
1019 if ($regs[2] == 'NO') {
1020 $string = "<b><font color=$color[2]>\n" .
1021 _("ERROR : Could not append message to") ." $folder." .
1022 "</b><br>\n" .
1023 _("Server responded: ") .
1024 $reason . "<br>\n";
1025 if (preg_match("/(.*)(quota)(.*)$/i", $reason, $regs)) {
1026 $string .= _("Solution: ") .
1027 _("Remove unneccessary messages from your folder and start with your Trash folder.")
1028 ."<br>\n";
1029 }
1030 $string .= "</font>\n";
1031 error_box($string,$color);
1032 } else {
8813fb15 1033 $string = "<b><font color=$color[2]>\n" .
098ea084 1034 _("ERROR : Bad or malformed request.") .
1035 "</b><br>\n" .
1036 _("Server responded: ") .
1037 $tmp . "</font><br>\n";
1038 error_box($string,$color);
8813fb15 1039 exit;
098ea084 1040 }
69146537 1041 }
9c737111 1042}
85fc999e 1043
bd9829d7 1044function sqimap_get_user_server ($imap_server, $username) {
bd9829d7 1045 if (substr($imap_server, 0, 4) != "map:") {
1046 return $imap_server;
1047 }
bd9829d7 1048 $function = substr($imap_server, 4);
1049 return $function($username);
1050}
1051
1052/* This is an example that gets imapservers from yellowpages (NIS).
1053 * you can simple put map:map_yp_alias in your $imap_server_address
1054 * in config.php use your own function instead map_yp_alias to map your
1055 * LDAP whatever way to find the users imapserver. */
1056
1057function map_yp_alias($username) {
1058 $yp = `ypmatch $username aliases`;
1059 return chop(substr($yp, strlen($username)+1));
1060}
1061
15e6162e 1062?>