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