ddbb9fdd2b195fe6d45ed7982156f5e1035ec76e
6 * Copyright (c) 1999-2003 The SquirrelMail Project Team
7 * Licensed under the GNU GPL. For full terms see the file COPYING.
9 * This implements all functions that do general imap functions.
12 * @package squirrelmail
16 require_once(SM_PATH
. 'functions/page_header.php');
17 require_once(SM_PATH
. 'functions/auth.php');
20 global $sqimap_session_id;
21 $sqimap_session_id = 1;
23 /* Sets an unique session id in order to avoid simultanous sessions crash. */
24 function sqimap_session_id($unique_id = false) {
25 global $data_dir, $username, $sqimap_session_id;
27 return( sprintf("A%03d", $sqimap_session_id++
) );
29 return( sprintf("A%03d", $sqimap_session_id++
) . ' UID' );
34 * Both send a command and accept the result from the command.
35 * This is to allow proper session number handling.
37 function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$response, &$message, $unique_id = false) {
39 $sid = sqimap_session_id($unique_id);
40 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
41 $tag_uid_a = explode(' ',trim($sid));
43 $read = sqimap_retrieve_imap_response ($imap_stream, $tag, $handle_errors, $response, $message, $query );
44 /* get the response and the message */
45 $message = $message[$tag];
46 $response = $response[$tag];
49 global $squirrelmail_language, $color;
50 set_up_language($squirrelmail_language);
51 require_once(SM_PATH
. 'functions/display_messages.php');
52 $string = "<b><font color=$color[2]>\n" .
53 _("ERROR : No available imapstream.") .
55 error_box($string,$color);
60 function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response,
61 &$message, $unique_id = false,$filter=false,
62 $outputstream=false,$no_return=false) {
64 $sid = sqimap_session_id($unique_id);
65 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
66 $tag_uid_a = explode(' ',trim($sid));
69 $read = sqimap_read_data ($imap_stream, $tag, $handle_errors, $response,
70 $message, $query,$filter,$outputstream,$no_return);
71 /* retrieve the response and the message */
72 $response = $response[$tag];
73 $message = $message[$tag];
75 if (!empty($read[$tag])) {
76 return $read[$tag][0];
81 global $squirrelmail_language, $color;
82 set_up_language($squirrelmail_language);
83 require_once(SM_PATH
. 'functions/display_messages.php');
84 $string = "<b><font color=$color[2]>\n" .
85 _("ERROR : No available imapstream.") .
87 error_box($string,$color);
91 function sqimap_prepare_pipelined_query($new_query,&$tag,&$aQuery,$unique_id) {
92 $sid = sqimap_session_id($unique_id);
93 $tag_uid_a = explode(' ',trim($sid));
95 $query = $sid . ' '.$new_query."\r\n";
96 $aQuery[$tag] = $query;
99 function sqimap_run_pipelined_command ($imap_stream, $aQueryList, $handle_errors,
100 &$aServerResponse, &$aServerMessage, $unique_id = false,
101 $filter=false,$outputstream=false,$no_return=false) {
105 Do not fire all calls at once to the imap-server but split the calls up
106 in portions of $iChunkSize. If we do not do that I think we misbehave as
107 IMAP client or should handle BYE calls if the IMAP-server drops the
108 connection because the number of queries is to large. This isn't tested
109 but a wild guess how it could work in the field.
111 After testing it on Exchange 2000 we discovered that a chunksize of 32
112 was quicker then when we raised it to 128.
114 $iQueryCount = count($aQueryList);
116 // array_chunk would also do the job but it's supported from php > 4.2
117 $aQueryChunks = array();
118 $iLoops = floor($iQueryCount / $iChunkSize);
120 if ($iLoops * $iChunkSize != $iQueryCount) ++
$iLoops;
122 if (!function_exists('array_chunk')) { // arraychunk replacement
124 for($i=0;$i<$iLoops;++
$i) {
125 for($j=0;$j<$iChunkSize;++
$j) {
126 $key = key($aQueryList);
127 $aTmp[$key] = $aQueryList[$key];
128 if (next($aQueryList) === false) break;
130 $aQueryChunks[] = $aTmp;
133 $aQueryChunks = array_chunk($aQueryList,$iChunkSize,true);
136 for ($i=0;$i<$iLoops;++
$i) {
137 $aQuery = $aQueryChunks[$i];
138 foreach($aQuery as $tag => $query) {
139 fputs($imap_stream,$query);
140 $aResults[$tag] = false;
142 foreach($aQuery as $tag => $query) {
143 if ($aResults[$tag] == false) {
144 $aReturnedResponse = sqimap_retrieve_imap_response ($imap_stream, $tag,
145 $handle_errors, $response, $message, $query,
146 $filter,$outputstream,$no_return);
147 foreach ($aReturnedResponse as $returned_tag => $aResponse) {
148 if (!empty($aResponse)) {
149 $aResults[$returned_tag] = $aResponse[0];
151 $aResults[$returned_tag] = $aResponse;
153 $aServerResponse[$returned_tag] = $response[$returned_tag];
154 $aServerMessage[$returned_tag] = $message[$returned_tag];
163 * custom fgets function. gets a line from IMAP
164 * no matter how big it may be
167 function sqimap_fgets($imap_stream) {
172 while (strpos($results, "\r\n", $offset) === false) {
173 if (!($read = fgets($imap_stream, $buffer))) {
174 /* this happens in case of an error */
175 /* reset $results because it's useless */
179 if ( $results != '' ) {
180 $offset = strlen($results) - 1;
187 function sqimap_fread($imap_stream,$iSize,$filter=false,
188 $outputstream=false, $no_return=false) {
189 if (!$filter ||
!$outputstream) {
190 $iBufferSize = $iSize;
192 // see php bug 24033. They changed fread behaviour %$^&$%
193 $iBufferSize = 7800; // multiple of 78 in case of base64 decoding.
195 if ($iSize < $iBufferSize) {
196 $iBufferSize = $iSize;
200 $sRead = $sReadRem = '';
201 // NB: fread can also stop at end of a packet on sockets.
202 while ($iRetrieved < $iSize) {
203 $sRead = fread($imap_stream,$iBufferSize);
204 $iLength = strlen($sRead);
205 $iRetrieved +
= $iLength ;
206 $iRemaining = $iSize - $iRetrieved;
207 if ($iRemaining < $iBufferSize) {
208 $iBufferSize = $iRemaining;
215 $sRead = $sReadRem . $sRead;
218 if (substr($sRead,-1) !== "\n") {
219 $i = strrpos($sRead,"\n");
220 if ($i !== false && $iRetrieved<$iSize) {
222 $sReadRem = substr($sRead,$i);
223 $sRead = substr($sRead,0,$i);
224 } else if ($iLength && $iRetrieved<$iSize) { // linelength > received buffer
229 if ($filter && $sRead) {
232 if ($outputstream && $sRead) {
233 if (is_resource($outputstream)) {
234 fwrite($outputstream,$sRead);
235 } else if ($outputstream == 'php://stdout') {
248 /* obsolete function, inform plugins that use it */
249 function sqimap_read_data_list($imap_stream, $tag, $handle_errors,
250 &$response, &$message, $query = '') {
251 global $color, $squirrelmail_language;
252 set_up_language($squirrelmail_language);
253 require_once(SM_PATH
. 'functions/display_messages.php');
254 $string = "<b><font color=$color[2]>\n" .
255 _("ERROR : Bad function call.") .
258 'There is a plugin installed which make use of the <br>' .
259 'SquirrelMail internal function sqimap_read_data_list.<br>'.
260 'Please adapt the installed plugin and let it use<br>'.
261 'sqimap_run_command or sqimap_run_command_list instead<br><br>'.
262 'The following query was issued:<br>'.
263 htmlspecialchars($query) . '<br>' . "</font><br>\n";
264 error_box($string,$color);
265 echo '</body></html>';
269 function sqimap_error_box($title, $query = '', $message_title = '', $message = '')
271 global $color, $squirrelmail_language;
273 set_up_language($squirrelmail_language);
274 require_once(SM_PATH
. 'functions/display_messages.php');
275 $string = "<font color=$color[2]><b>\n" . $title . "</b><br>\n";
276 $cmd = explode(' ',$query);
277 $cmd= strtolower($cmd[0]);
279 if ($query != '' && $cmd != 'login')
280 $string .= _("Query:") . ' ' . htmlspecialchars($query) . '<br>';
281 if ($message_title != '')
282 $string .= $message_title;
284 $string .= htmlspecialchars($message);
285 $string .= "</font><br>\n";
286 error_box($string,$color);
290 * Reads the output from the IMAP stream. If handle_errors is set to true,
291 * this will also handle all errors that are received. If it is not set,
292 * the errors will be sent back through $response and $message
295 function sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
296 &$response, &$message, $query = '',
297 $filter = false, $outputstream = false, $no_return = false) {
298 global $color, $squirrelmail_language;
300 if (!is_array($message)) $message = array();
301 if (!is_array($response)) $response = array();
302 $resultlist = array();
304 $read = sqimap_fgets($imap_stream);
312 $read = sqimap_fgets($imap_stream);
317 /* get the command */
320 $s = substr($read,$i);
321 if (($j = strpos($s,' ')) ||
($j = strpos($s,"\n"))) {
322 $arg = substr($s,0,$j);
324 $found_tag = substr($read,0,$i-1);
333 $response[$found_tag] = $arg;
334 $message[$found_tag] = trim(substr($read,$i+
strlen($arg)));
336 $resultlist[] = $data;
338 $aResponse[$found_tag] = $resultlist;
339 $data = $resultlist = array();
340 if ($found_tag == $tag) {
341 break 3; /* switch switch while */
345 /* this shouldn't happen */
346 $response[$found_tag] = $arg;
347 $message[$found_tag] = trim(substr($read,$i+
strlen($arg)));
349 $resultlist[] = $data;
351 $aResponse[$found_tag] = $resultlist;
352 $data = $resultlist = array();
353 if ($found_tag == $tag) {
354 break 3; /* switch switch while */
358 $read = sqimap_fgets($imap_stream);
359 if ($read === false) { /* error */
360 break 3; /* switch switch while */
363 } // end case $tag{0}
367 if (preg_match('/^\*\s\d+\sFETCH/',$read)) {
368 /* check for literal */
369 $s = substr($read,-3);
370 $fetch_data = array();
371 do { /* outer loop, continue until next untagged fetch
373 do { /* innerloop for fetching literals. with this loop
374 we prohibid that literal responses appear in the
375 outer loop so we can trust the untagged and
376 tagged info provided by $read */
377 if ($s === "}\r\n") {
378 $j = strrpos($read,'{');
379 $iLit = substr($read,$j+
1,-3);
380 $fetch_data[] = $read;
381 $sLiteral = sqimap_fread($imap_stream,$iLit,$filter,$outputstream,$no_return);
382 if ($sLiteral === false) { /* error */
383 break 4; /* while while switch while */
385 /* backwards compattibility */
386 $aLiteral = explode("\n", $sLiteral);
387 /* release not neaded data */
389 foreach ($aLiteral as $line) {
390 $fetch_data[] = $line ."\n";
392 /* release not neaded data */
394 /* next fgets belongs to this fetch because
395 we just got the exact literalsize and there
396 must follow data to complete the response */
397 $read = sqimap_fgets($imap_stream);
398 if ($read === false) { /* error */
399 break 4; /* while while switch while */
401 $fetch_data[] = $read;
403 $fetch_data[] = $read;
405 /* retrieve next line and check in the while
406 statements if it belongs to this fetch response */
407 $read = sqimap_fgets($imap_stream);
408 if ($read === false) { /* error */
409 break 4; /* while while switch while */
411 /* check for next untagged reponse and break */
412 if ($read{0} == '*') break 2;
413 $s = substr($read,-3);
414 } while ($s === "}\r\n");
415 $s = substr($read,-3);
416 } while ($read{0} !== '*' &&
417 substr($read,0,strlen($tag)) !== $tag);
418 $resultlist[] = $fetch_data;
419 /* release not neaded data */
422 $s = substr($read,-3);
424 if ($s === "}\r\n") {
425 $j = strrpos($read,'{');
426 $iLit = substr($read,$j+
1,-3);
428 $sLiteral = fread($imap_stream,$iLit);
429 if ($sLiteral === false) { /* error */
431 break 3; /* while switch while */
434 $data[] = sqimap_fgets($imap_stream);
438 $read = sqimap_fgets($imap_stream);
439 if ($read === false) {
440 break 3; /* while switch while */
441 } else if ($read{0} == '*') {
444 $s = substr($read,-3);
445 } while ($s === "}\r\n");
453 /* error processing in case $read is false */
454 if ($read === false) {
456 sqimap_error_box(_("ERROR : Connection dropped by imap-server."), $query);
460 /* Set $resultlist array */
462 //$resultlist[] = $data;
464 elseif (empty($resultlist)) {
465 $resultlist[] = array();
468 /* Return result or handle errors */
469 if ($handle_errors == false) {
471 return( $resultlist ); //?? Why this?
473 switch ($response[$tag]) {
478 /* ignore this error from M$ exchange, it is not fatal (aka bug) */
479 if (strstr($message[$tag], 'command resulted in') === false) {
480 sqimap_error_box(_("ERROR : Could not complete request."), $query, _("Reason Given: "), $message[$tag]);
481 echo '</body></html>';
486 sqimap_error_box(_("ERROR : Bad or malformed request."), $query, _("Server responded: "), $message[$tag]);
487 echo '</body></html>';
490 sqimap_error_box(_("ERROR : Imap server closed the connection."), $query, _("Server responded: "), $message[$tag]);
491 echo '</body></html>';
494 sqimap_error_box(_("ERROR : Unknown imap response."), $query, _("Server responded: "), $message[$tag]);
495 /* the error is displayed but because we don't know the reponse we
496 return the result anyway */
502 function sqimap_read_data ($imap_stream, $tag_uid, $handle_errors,
503 &$response, &$message, $query = '',
504 $filter=false,$outputstream=false,$no_return=false) {
506 $tag_uid_a = explode(' ',trim($tag_uid));
507 $tag = $tag_uid_a[0];
509 $res = sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
510 $response, $message, $query,$filter,$outputstream,$no_return);
511 /* sqimap_read_data should be called for one response
512 but since it just calls sqimap_retrieve_imap_response which
513 handles multiple responses we need to check for that
514 and merge the $res array IF they are seperated and
515 IF it was a FETCH response. */
517 // if (isset($res[1]) && is_array($res[1]) && isset($res[1][0])
518 // && preg_match('/^\* \d+ FETCH/', $res[1][0])) {
519 // $result = array();
520 // foreach($res as $index=>$value) {
521 // $result = array_merge($result, $res["$index"]);
524 if (isset($result)) {
525 return $result[$tag];
532 /** sqimap_create_stream()
533 * @return imap-stream resource identifier
534 * Connects to the IMAP server and returns a resource identifier for use with
535 * the other SquirrelMail IMAP functions. Does NOT login!
537 function sqimap_create_stream($server,$port,$tls=false) {
538 global $username, $use_imap_tls;
540 if ($use_imap_tls == true) {
541 if ((check_php_version(4,3)) and (extension_loaded('openssl'))) {
542 /* Use TLS by prefixing "tls://" to the hostname */
543 $server = 'tls://' . $imap_server_address;
545 require_once(SM_PATH
. 'functions/display_messages.php');
546 $string = "Unable to connect to IMAP server!<br>TLS is enabled, but this " .
547 "version of PHP does not support TLS sockets, or is missing the openssl " .
548 "extension.<br><br>Please contact your system administrator.";
549 logout_error($string,$color);
553 $imap_stream = fsockopen($server, $port, $error_number, $error_string, 15);
555 /* Do some error correction */
557 set_up_language($squirrelmail_language, true);
558 require_once(SM_PATH
. 'functions/display_messages.php');
559 $string = sprintf (_("Error connecting to IMAP server: %s.") .
560 "<br>\r\n", $server) .
561 "$error_number : $error_string<br>\r\n";
562 logout_error($string,$color);
565 $server_info = fgets ($imap_stream, 1024);
570 * Logs the user into the imap server. If $hide is set, no error messages
571 * will be displayed. This function returns the imap connection handle.
573 function sqimap_login ($username, $password, $imap_server_address, $imap_port, $hide) {
574 global $color, $squirrelmail_language, $onetimepad, $use_imap_tls,
575 $imap_auth_mech, $sqimap_capabilities;
577 if (!isset($onetimepad) ||
empty($onetimepad)) {
578 sqgetglobalvar('onetimepad' , $onetimepad , SQ_SESSION
);
580 if (!isset($sqimap_capabilities)) {
581 sqgetglobalvar('sqimap_capabilities' , $capability , SQ_SESSION
);
584 $host = $imap_server_address;
585 $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
587 $imap_stream = sqimap_create_stream($imap_server_address,$imap_port,$use_imap_tls);
589 /* Decrypt the password */
590 $password = OneTimePadDecrypt($password, $onetimepad);
592 if (($imap_auth_mech == 'cram-md5') OR ($imap_auth_mech == 'digest-md5')) {
593 // We're using some sort of authentication OTHER than plain or login
594 $tag=sqimap_session_id(false);
595 if ($imap_auth_mech == 'digest-md5') {
596 $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
597 } elseif ($imap_auth_mech == 'cram-md5') {
598 $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
600 fputs($imap_stream,$query);
601 $answer=sqimap_fgets($imap_stream);
602 // Trim the "+ " off the front
603 $response=explode(" ",$answer,3);
604 if ($response[0] == '+') {
605 // Got a challenge back
606 $challenge=$response[1];
607 if ($imap_auth_mech == 'digest-md5') {
608 $reply = digest_md5_response($username,$password,$challenge,'imap',$host);
609 } elseif ($imap_auth_mech == 'cram-md5') {
610 $reply = cram_md5_response($username,$password,$challenge);
612 fputs($imap_stream,$reply);
613 $read=sqimap_fgets($imap_stream);
614 if ($imap_auth_mech == 'digest-md5') {
615 // DIGEST-MD5 has an extra step..
616 if (substr($read,0,1) == '+') { // OK so far..
617 fputs($imap_stream,"\r\n");
618 $read=sqimap_fgets($imap_stream);
621 $results=explode(" ",$read,3);
622 $response=$results[1];
623 $message=$results[2];
625 // Fake the response, so the error trap at the bottom will work
627 $message='IMAP server does not appear to support the authentication method selected.';
628 $message .= ' Please contact your system administrator.';
630 } elseif ($imap_auth_mech == 'login') {
631 // Original IMAP login code
632 $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
633 $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
634 } elseif ($imap_auth_mech == 'plain') {
640 * The mechanism consists of a single message from the client to the
641 * server. The client sends the authorization identity (identity to
642 * login as), followed by a US-ASCII NUL character, followed by the
643 * authentication identity (identity whose password will be used),
644 * followed by a US-ASCII NUL character, followed by the clear-text
645 * password. The client may leave the authorization identity empty to
646 * indicate that it is the same as the authentication identity.
649 $tag=sqimap_session_id(false);
650 $sasl = (isset($capability['SASL']) && $capability['SASL']) ?
true : false;
651 $auth = base64_encode("$username\0$username\0$password");
653 // IMAP Extension for SASL Initial Client Response
654 // <draft-siemborski-imap-sasl-initial-response-00.txt>
655 $query = $tag . " AUTHENTICATE PLAIN $auth\r\n";
656 fputs($imap_stream, $query);
657 $read = sqimap_fgets($imap_stream);
659 $query = $tag . " AUTHENTICATE PLAIN\r\n";
660 fputs($imap_stream, $query);
661 $read=sqimap_fgets($imap_stream);
662 if (substr($read,0,1) == '+') { // OK so far..
663 fputs($imap_stream, "$auth\r\n");
664 $read = sqimap_fgets($imap_stream);
667 $results=explode(" ",$read,3);
668 $response=$results[1];
669 $message=$results[2];
672 $message="Internal SquirrelMail error - unknown IMAP authentication method chosen. Please contact the developers.";
675 /* If the connection was not successful, lets see why */
676 if ($response != 'OK') {
678 if ($response != 'NO') {
679 /* "BAD" and anything else gets reported here. */
680 $message = htmlspecialchars($message);
681 set_up_language($squirrelmail_language, true);
682 require_once(SM_PATH
. 'functions/display_messages.php');
683 if ($response == 'BAD') {
684 $string = sprintf (_("Bad request: %s")."<br>\r\n", $message);
686 $string = sprintf (_("Unknown error: %s") . "<br>\n", $message);
688 if (isset($read) && is_array($read)) {
689 $string .= '<br>' . _("Read data:") . "<br>\n";
690 foreach ($read as $line) {
691 $string .= htmlspecialchars($line) . "<br>\n";
694 error_box($string,$color);
698 * If the user does not log in with the correct
699 * username and password it is not possible to get the
700 * correct locale from the user's preferences.
701 * Therefore, apply the same hack as on the login
704 * $squirrelmail_language is set by a cookie when
705 * the user selects language and logs out
708 set_up_language($squirrelmail_language, true);
709 include_once(SM_PATH
. 'functions/display_messages.php' );
711 logout_error( _("Unknown user or password incorrect.") );
721 /* Simply logs out the IMAP session */
722 function sqimap_logout ($imap_stream) {
723 /* Logout is not valid until the server returns 'BYE'
724 * If we don't have an imap_ stream we're already logged out */
725 if(isset($imap_stream) && $imap_stream)
726 sqimap_run_command($imap_stream, 'LOGOUT', false, $response, $message);
729 function sqimap_capability($imap_stream, $capability='') {
730 global $sqimap_capabilities;
731 if (!is_array($sqimap_capabilities)) {
732 $read = sqimap_run_command($imap_stream, 'CAPABILITY', true, $a, $b);
734 $c = explode(' ', $read[0]);
735 for ($i=2; $i < count($c); $i++
) {
736 $cap_list = explode('=', $c[$i]);
737 if (isset($cap_list[1])) {
738 $sqimap_capabilities[$cap_list[0]] = $cap_list[1];
740 $sqimap_capabilities[$cap_list[0]] = TRUE;
745 if (isset($sqimap_capabilities[$capability])) {
746 return $sqimap_capabilities[$capability];
751 return $sqimap_capabilities;
754 /* Returns the delimeter between mailboxes: INBOX/Test, or INBOX.Test */
755 function sqimap_get_delimiter ($imap_stream = false) {
756 global $sqimap_delimiter, $optional_delimiter;
758 /* Use configured delimiter if set */
759 if((!empty($optional_delimiter)) && $optional_delimiter != 'detect') {
760 return $optional_delimiter;
763 /* Do some caching here */
764 if (!$sqimap_delimiter) {
765 if (sqimap_capability($imap_stream, 'NAMESPACE')) {
767 * According to something that I can't find, this is supposed to work on all systems
768 * OS: This won't work in Courier IMAP.
769 * OS: According to rfc2342 response from NAMESPACE command is:
770 * OS: * NAMESPACE (PERSONAL NAMESPACES) (OTHER_USERS NAMESPACE) (SHARED NAMESPACES)
771 * OS: We want to lookup all personal NAMESPACES...
773 $read = sqimap_run_command($imap_stream, 'NAMESPACE', true, $a, $b);
774 if (eregi('\\* NAMESPACE +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL)', $read[0], $data)) {
775 if (eregi('^\\( *\\((.*)\\) *\\)', $data[1], $data2)) {
778 $pna = explode(')(', $pn);
779 while (list($k, $v) = each($pna)) {
780 $lst = explode('"', $v);
781 if (isset($lst[3])) {
782 $pn[$lst[1]] = $lst[3];
788 $sqimap_delimiter = $pn[0];
790 fputs ($imap_stream, ". LIST \"INBOX\" \"\"\r\n");
791 $read = sqimap_read_data($imap_stream, '.', true, $a, $b);
792 $read = $read['.'][0]; //sqimap_read_data() now returns a tag array of response array
793 $quote_position = strpos ($read[0], '"');
794 $sqimap_delimiter = substr ($read[0], $quote_position+
1, 1);
797 return $sqimap_delimiter;
801 function sqimap_encode_mailbox_name($what)
803 if (ereg("[\"\\\r\n]", $what))
804 return '{' . strlen($what) . "}\r\n" . $what; /* 4.3 literal form */
805 return '"' . $what . '"'; /* 4.3 quoted string form */
809 /* Gets the number of messages in the current mailbox. */
810 function sqimap_get_num_messages ($imap_stream, $mailbox) {
811 $read_ary = sqimap_run_command ($imap_stream, 'EXAMINE ' . sqimap_encode_mailbox_name($mailbox), false, $result, $message);
812 for ($i = 0; $i < count($read_ary); $i++
) {
813 if (ereg("[^ ]+ +([^ ]+) +EXISTS", $read_ary[$i], $regs)) {
817 return false; //"BUG! Couldn't get number of messages in $mailbox!";
821 function parseAddress($address, $max=0) {
824 $iCnt = strlen($address);
825 $aSpecials = array('(' ,'<' ,',' ,';' ,':');
826 $aReplace = array(' (',' <',' ,',' ;',' :');
827 $address = str_replace($aSpecials,$aReplace,$address);
828 $i = $iAddrFound = $bGroup = 0;
830 $cChar = $address{$i};
834 $iEnd = strpos($address,'>',$i+
1);
836 $sToken = substr($address,$i);
839 $sToken = substr($address,$i,$iEnd - $i +
1);
842 $sToken = str_replace($aReplace, $aSpecials,$sToken);
843 $aTokens[] = $sToken;
846 $iEnd = strpos($address,$cChar,$i+
1);
848 // skip escaped quotes
849 $prev_char = $address{$iEnd-1};
850 while ($prev_char === '\\' && substr($address,$iEnd-2,2) !== '\\\\') {
851 $iEnd = strpos($address,$cChar,$iEnd+
1);
853 $prev_char = $address{$iEnd-1};
860 $sToken = substr($address,$i);
863 // also remove the surrounding quotes
864 $sToken = substr($address,$i+
1,$iEnd - $i -1);
867 $sToken = str_replace($aReplace, $aSpecials,$sToken);
868 if ($sToken) $aTokens[] = $sToken;
871 $iEnd = strpos($address,')',$i);
873 $sToken = substr($address,$i);
876 $sToken = substr($address,$i,$iEnd - $i +
1);
879 $sToken = str_replace($aReplace, $aSpecials,$sToken);
880 $aTokens[] = $sToken;
890 if ($max && $max == $iAddrFound) {
902 $iEnd = strpos($address,' ',$i+
1);
904 $sToken = trim(substr($address,$i,$iEnd - $i));
907 $sToken = trim(substr($address,$i));
910 if ($sToken) $aTokens[] = $sToken;
914 $sPersonal = $sEmail = $sComment = $sGroup = '';
915 $aStack = $aComment = array();
916 foreach ($aTokens as $sToken) {
917 if ($max && $max == count($aAddress)) {
929 $aComment[] = substr($sToken,1,-1);
933 $sEmail = trim(implode(' ',$aStack));
934 $aAddress[] = array($sGroup,$sEmail);
935 $aStack = $aComment = array();
941 while (count($aStack) && !$sEmail) {
942 $sEmail = trim(array_pop($aStack));
945 if (count($aStack)) {
946 $sPersonal = trim(implode('',$aStack));
950 if (!$sPersonal && count($aComment)) {
951 $sComment = implode(' ',$aComment);
952 $sPersonal .= $sComment;
954 $aAddress[] = array($sEmail,$sPersonal);
955 $sPersonal = $sComment = $sEmail = '';
956 $aStack = $aComment = array();
959 $sGroup = implode(' ',$aStack); break;
963 $sEmail = trim(substr($sToken,1,-1));
968 default: $aStack[] = $sToken; break;
971 /* now do the action again for the last address */
973 while (count($aStack) && !$sEmail) {
974 $sEmail = trim(array_pop($aStack));
977 if (count($aStack)) {
978 $sPersonal = trim(implode('',$aStack));
982 if (!$sPersonal && count($aComment)) {
983 $sComment = implode(' ',$aComment);
984 $sPersonal .= $sComment;
986 $aAddress[] = array($sEmail,$sPersonal);
993 * Returns the number of unseen messages in this folder
995 function sqimap_unseen_messages ($imap_stream, $mailbox) {
996 $read_ary = sqimap_run_command ($imap_stream, 'STATUS ' . sqimap_encode_mailbox_name($mailbox) . ' (UNSEEN)', false, $result, $message);
998 $regs = array(false, false);
999 while (isset($read_ary[$i])) {
1000 if (ereg("UNSEEN ([0-9]+)", $read_ary[$i], $regs)) {
1009 * Returns the number of total/unseen/recent messages in this folder
1011 function sqimap_status_messages ($imap_stream, $mailbox) {
1012 $read_ary = sqimap_run_command ($imap_stream, 'STATUS ' . sqimap_encode_mailbox_name($mailbox) . ' (MESSAGES UNSEEN RECENT)', false, $result, $message);
1014 $messages = $unseen = $recent = false;
1015 $regs = array(false,false);
1016 while (isset($read_ary[$i])) {
1017 if (preg_match('/UNSEEN\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1020 if (preg_match('/MESSAGES\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1021 $messages = $regs[1];
1023 if (preg_match('/RECENT\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1028 return array('MESSAGES' => $messages, 'UNSEEN'=>$unseen, 'RECENT' => $recent);
1033 * Saves a message to a given folder -- used for saving sent messages
1035 function sqimap_append ($imap_stream, $sent_folder, $length) {
1036 fputs ($imap_stream, sqimap_session_id() . ' APPEND ' . sqimap_encode_mailbox_name($sent_folder) . " (\\Seen) \{$length}\r\n");
1037 $tmp = fgets ($imap_stream, 1024);
1040 function sqimap_append_done ($imap_stream, $folder='') {
1041 global $squirrelmail_language, $color;
1042 fputs ($imap_stream, "\r\n");
1043 $tmp = fgets ($imap_stream, 1024);
1044 if (preg_match("/(.*)(BAD|NO)(.*)$/", $tmp, $regs)) {
1045 set_up_language($squirrelmail_language);
1046 require_once(SM_PATH
. 'functions/display_messages.php');
1048 if ($regs[2] == 'NO') {
1049 $string = "<b><font color=$color[2]>\n" .
1050 _("ERROR : Could not append message to") ." $folder." .
1052 _("Server responded: ") .
1054 if (preg_match("/(.*)(quota)(.*)$/i", $reason, $regs)) {
1055 $string .= _("Solution: ") .
1056 _("Remove unneccessary messages from your folder and start with your Trash folder.")
1059 $string .= "</font>\n";
1060 error_box($string,$color);
1062 $string = "<b><font color=$color[2]>\n" .
1063 _("ERROR : Bad or malformed request.") .
1065 _("Server responded: ") .
1066 $tmp . "</font><br>\n";
1067 error_box($string,$color);
1073 function sqimap_get_user_server ($imap_server, $username) {
1074 if (substr($imap_server, 0, 4) != "map:") {
1075 return $imap_server;
1077 $function = substr($imap_server, 4);
1078 return $function($username);
1081 /* This is an example that gets imapservers from yellowpages (NIS).
1082 * you can simple put map:map_yp_alias in your $imap_server_address
1083 * in config.php use your own function instead map_yp_alias to map your
1084 * LDAP whatever way to find the users imapserver. */
1086 function map_yp_alias($username) {
1087 $yp = `ypmatch
$username aliases`
;
1088 return chop(substr($yp, strlen($username)+
1));