f8034018d446c435efb0ca60472681fbb21d5e3a
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.
14 require_once(SM_PATH
. 'functions/page_header.php');
15 require_once(SM_PATH
. 'functions/auth.php');
18 global $sqimap_session_id;
19 $sqimap_session_id = 1;
21 /* Sets an unique session id in order to avoid simultanous sessions crash. */
22 function sqimap_session_id($unique_id = false) {
23 global $data_dir, $username, $sqimap_session_id;
25 return( sprintf("A%03d", $sqimap_session_id++
) );
27 return( sprintf("A%03d", $sqimap_session_id++
) . ' UID' );
32 * Both send a command and accept the result from the command.
33 * This is to allow proper session number handling.
35 function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$response, &$message, $unique_id = false) {
37 $sid = sqimap_session_id($unique_id);
38 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
39 $tag_uid_a = explode(' ',trim($sid));
41 $read = sqimap_retrieve_imap_response ($imap_stream, $tag, $handle_errors, $response, $message, $query );
42 /* get the response and the message */
43 $message = $message[$tag];
44 $response = $response[$tag];
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.") .
53 error_box($string,$color);
58 function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response,
59 &$message, $unique_id = false,$filter=false,
60 $outputstream=false,$no_return=false) {
62 $sid = sqimap_session_id($unique_id);
63 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
64 $tag_uid_a = explode(' ',trim($sid));
67 $read = sqimap_read_data ($imap_stream, $tag, $handle_errors, $response,
68 $message, $query,$filter,$outputstream,$no_return);
69 /* retrieve the response and the message */
70 $response = $response[$tag];
71 $message = $message[$tag];
73 if (!empty($read[$tag])) {
74 return $read[$tag][0];
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.") .
85 error_box($string,$color);
89 function sqimap_prepare_pipelined_query($new_query,&$tag,&$aQuery,$unique_id) {
90 $sid = sqimap_session_id($unique_id);
91 $tag_uid_a = explode(' ',trim($sid));
93 $query = $sid . ' '.$new_query."\n";
94 $aQuery[$tag] = $query;
97 function sqimap_run_pipelined_command ($imap_stream, $aQueryList, $handle_errors,
98 &$aServerResponse, &$aServerMessage, $unique_id = false,
99 $filter=false,$outputstream=false,$no_return=false) {
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.
109 $iQueryCount = count($aQueryList);
111 // array_chunk would also do the job but it's supported from php > 4.2
112 $aQueryChunks = array();
113 $iLoops = floor($iQueryCount / $iChunkSize);
115 if ($iLoops * $iChunkSize !== $iQueryCount) ++
$iLoops;
117 if (!function_exists('array_chunk')) { // arraychunk replacement
119 for($i=0;$i<$iLoops;++
$i) {
120 for($j=0;$j<$iChunkSize;++
$j) {
121 $key = key($aQueryList);
122 $aTmp[$key] = $aQueryList[$key];
123 if (next($aQueryList) === false) break;
125 $aQueryChunks[] = $aTmp;
128 $aQueryChunks = array_chunk($aQueryList,$iChunkSize,true);
131 for ($i=0;$i<$iLoops;++
$i) {
132 $aQuery = $aQueryChunks[$i];
133 foreach($aQuery as $tag => $query) {
134 fputs($imap_stream,$query);
135 $aResults[$tag] = false;
138 foreach($aQuery as $tag => $query) {
139 if (!$aResults[$tag]) {
140 $aReturnedResponse = sqimap_retrieve_imap_response ($imap_stream, $tag,
141 $handle_errors, $response, $message, $query,
142 $filter,$outputstream,$no_return);
143 foreach ($aReturnedResponse as $returned_tag => $aResponse) {
144 if (!empty($aResponse)) {
145 $aResults[$returned_tag] = $aResponse[0];
147 $aResults[$returned_tag] = $aResponse;
149 $aServerResponse[$returned_tag] = $response[$returned_tag];
150 $aServerMessage[$returned_tag] = $message[$returned_tag];
159 * custom fgets function. gets a line from IMAP
160 * no matter how big it may be
163 function sqimap_fgets($imap_stream) {
168 while (strpos($results, "\r\n", $offset) === false) {
169 if (!($read = fgets($imap_stream, $buffer))) {
170 /* this happens in case of an error */
171 /* reset $results because it's useless */
175 if ( $results != '' ) {
176 $offset = strlen($results) - 1;
183 function sqimap_fread($imap_stream,$iSize,$filter=false,
184 $outputstream=false, $no_return=false) {
185 if (!$filter ||
!$outputstream) {
186 $iBufferSize = $iSize;
188 $iBufferSize = 62400; // multiple of 78 in case of base64 decoding.
190 $iRet = $iSize - $iBufferSize;
193 $results = $sReadRem = '';
194 $bFinished = $bBufferSizeAdapted = $bBufferIsOk = false;
195 while (($iRetrieved < ($iSize - $iBufferSize))) {
196 $sRead = fread($imap_stream,$iBufferSize);
201 $iRetrieved +
= $iBufferSize;
203 // in case line-endings do not appear at position 78 we adapt the buffersize so we can base64 decode on the fly
204 if (!$bBufferSizeAdapted) {
205 $i = strpos($sRead,"\n");
208 $iFragments = floor($iBufferSize / $i);
209 $iNewBufferSize = $iFragments * $i;
210 $iRemainder = $iNewBufferSize +
$i - $iBufferSize;
211 if ($iNewBufferSize == $iBufferSize) {
214 $iNewBufferSize = $iBufferSize;
215 $bBufferSizeAdapted = true;
217 if (!$bBufferIsOk && ($iRemainder +
$iBufferSize) < $iSize) {
218 $sReadRem = fread($imap_stream,$iRemainder);
219 } else if (!$bBufferIsOk) {
220 $sReadRem = fread($imap_stream,$iSize - $iBufferSize);
223 if (!$sReadRem && $sReadRem !== '') {
227 $iBufferSize = $iNewBufferSize;
228 $bBufferSizeAdapted = true;
230 $sReadRem = fread($imap_stream,$iSize - $iBufferSize);
238 $iRetrieved +
= $iRemainder;
244 if (is_resource($outputstream)) {
245 fwrite($outputstream,$sRead);
246 } else if ($outputstream == 'php://stdout') {
255 if (!$results && !$bFinished) {
256 $sRead = fread($imap_stream,($iSize - ($iRetrieved)));
261 if (is_resource($outputstream)) {
262 fwrite($outputstream,$sRead);
263 } else if ($outputstream == 'php://stdout') { // FIXME
274 /* obsolete function, inform plugins that use it */
275 function sqimap_read_data_list($imap_stream, $tag, $handle_errors,
276 &$response, &$message, $query = '') {
277 global $color, $squirrelmail_language;
278 set_up_language($squirrelmail_language);
279 require_once(SM_PATH
. 'functions/display_messages.php');
280 $string = "<b><font color=$color[2]>\n" .
281 _("ERROR : Bad function call.") .
284 'There is a plugin installed which make use of the <br>' .
285 'SquirrelMail internal function sqimap_read_data_list.<br>'.
286 'Please adapt the installed plugin and let it use<br>'.
287 'sqimap_run_command or sqimap_run_command_list instead<br><br>'.
288 'The following query was issued:<br>'.
289 htmlspecialchars($query) . '<br>' . "</font><br>\n";
290 error_box($string,$color);
291 echo '</body></html>';
296 * Reads the output from the IMAP stream. If handle_errors is set to true,
297 * this will also handle all errors that are received. If it is not set,
298 * the errors will be sent back through $response and $message
301 function sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
302 &$response, &$message, $query = '',
303 $filter = false, $outputstream = false, $no_return = false) {
304 global $color, $squirrelmail_language;
306 if (!is_array($message)) $message = array();
307 if (!is_array($response)) $response = array();
308 $resultlist = array();
310 $read = sqimap_fgets($imap_stream);
318 $read = sqimap_fgets($imap_stream);
323 /* get the command */
326 $s = substr($read,$i);
327 if (($j = strpos($s,' ')) ||
($j = strpos($s,"\n"))) {
328 $arg = substr($s,0,$j);
330 $found_tag = substr($read,0,$i-1);
331 if ($arg && $found_tag==$tag) {
339 $response[$found_tag] = $arg;
340 $message[$found_tag] = trim(substr($read,$i+
strlen($arg)));
342 $resultlist[] = $data;
344 $aResponse[$tag] = $resultlist;
345 break 3; /* switch switch while */
347 /* this shouldn't happen */
348 $response[$found_tag] = $arg;
349 $message[$found_tag] = trim(substr($read,$i+
strlen($arg)));
351 $resultlist[] = $data;
353 $aResponse[$found_tag] = $resultlist;
354 break 3; /* switch switch while */
356 } elseif($found_tag !== $tag) {
357 /* not the tag we are looking for, continue */
359 $resultlist[] = $data;
361 $aResponse[$found_tag] = $resultlist;
362 $resultlist = $data = array();
363 $read = sqimap_fgets($imap_stream);
364 if ($read === false) { /* error */
365 break 3; /* switch switch while */
369 } // end case $tag{0}
373 if (preg_match('/^\*\s\d+\sFETCH/',$read)) {
374 /* check for literal */
375 $s = substr($read,-3);
376 $fetch_data = array();
377 do { /* outer loop, continue until next untagged fetch
379 do { /* innerloop for fetching literals. with this loop
380 we prohibid that literal responses appear in the
381 outer loop so we can trust the untagged and
382 tagged info provided by $read */
383 if ($s === "}\r\n") {
384 $j = strrpos($read,'{');
385 $iLit = substr($read,$j+
1,-3);
386 $fetch_data[] = $read;
387 $sLiteral = sqimap_fread($imap_stream,$iLit,$filter,$outputstream,$no_return);
388 if ($sLiteral === false) { /* error */
389 break 4; /* while while switch while */
391 /* backwards compattibility */
392 $aLiteral = explode("\n", $sLiteral);
393 /* release not neaded data */
395 foreach ($aLiteral as $line) {
396 $fetch_data[] = $line ."\n";
398 /* release not neaded data */
400 /* next fgets belongs to this fetch because
401 we just got the exact literalsize and there
402 must follow data to complete the response */
403 $read = sqimap_fgets($imap_stream);
404 if ($read === false) { /* error */
405 break 4; /* while while switch while */
407 $fetch_data[] = $read;
409 $fetch_data[] = $read;
411 /* retrieve next line and check in the while
412 statements if it belongs to this fetch response */
413 $read = sqimap_fgets($imap_stream);
414 if ($read === false) { /* error */
415 break 4; /* while while switch while */
417 /* check for next untagged reponse and break */
418 if ($read{0} == '*') break 2;
419 $s = substr($read,-3);
420 } while ($s === "}\r\n");
421 $s = substr($read,-3);
422 } while ($read{0} !== '*' &&
423 substr($read,0,strlen($tag)) !== $tag);
424 $resultlist[] = $fetch_data;
425 /* release not neaded data */
428 $s = substr($read,-3);
430 if ($s === "}\r\n") {
431 $j = strrpos($read,'{');
432 $iLit = substr($read,$j+
1,-3);
434 $sLiteral = fread($imap_stream,$iLit);
435 if ($sLiteral === false) { /* error */
437 break 3; /* while switch while */
440 $data[] = sqimap_fgets($imap_stream);
444 $read = sqimap_fgets($imap_stream);
445 if ($read === false) {
446 break 3; /* while switch while */
447 } else if ($read{0} == '*') {
450 $s = substr($read,-3);
451 } while ($s === "}\r\n");
459 /* error processing in case $read is false */
460 if ($read === false) {
462 set_up_language($squirrelmail_language);
463 require_once(SM_PATH
. 'functions/display_messages.php');
464 $string = "<b><font color=$color[2]>\n" .
465 _("ERROR : Connection dropped by imap-server.") .
468 htmlspecialchars($query) . '<br>' . "</font><br>\n";
469 error_box($string,$color);
473 /* Set $resultlist array */
475 //$resultlist[] = $data;
477 elseif (empty($resultlist)) {
478 $resultlist[] = array();
481 /* Return result or handle errors */
482 if ($handle_errors == false) {
484 return( $resultlist );
486 switch ($response[$tag])
492 /* ignore this error from M$ exchange, it is not fatal (aka bug) */
493 if (strstr($message[$tag], 'command resulted in') === false) {
494 set_up_language($squirrelmail_language);
495 require_once(SM_PATH
. 'functions/display_messages.php');
496 $string = "<b><font color=$color[2]>\n" .
497 _("ERROR : Could not complete request.") .
500 htmlspecialchars($query) . '<br>' .
501 _("Reason Given: ") .
502 htmlspecialchars($message[$tag]) . "</font><br>\n";
503 error_box($string,$color);
504 echo '</body></html>';
509 set_up_language($squirrelmail_language);
510 require_once(SM_PATH
. 'functions/display_messages.php');
511 $string = "<b><font color=$color[2]>\n" .
512 _("ERROR : Bad or malformed request.") .
515 htmlspecialchars($query) . '<br>' .
516 _("Server responded: ") .
517 htmlspecialchars($message[$tag]) . "</font><br>\n";
518 error_box($string,$color);
519 echo '</body></html>';
522 set_up_language($squirrelmail_language);
523 require_once(SM_PATH
. 'functions/display_messages.php');
524 $string = "<b><font color=$color[2]>\n" .
525 _("ERROR : Imap server closed the connection.") .
528 htmlspecialchars($query) . '<br>' .
529 _("Server responded: ") .
530 htmlspecialchars($message[$tag]) . "</font><br>\n";
531 error_box($string,$color);
532 echo '</body></html>';
535 set_up_language($squirrelmail_language);
536 require_once(SM_PATH
. 'functions/display_messages.php');
537 $string = "<b><font color=$color[2]>\n" .
538 _("ERROR : Unknown imap response.") .
541 htmlspecialchars($query) . '<br>' .
542 _("Server responded: ") .
543 htmlspecialchars($message[$tag]) . "</font><br>\n";
544 error_box($string,$color);
545 /* the error is displayed but because we don't know the reponse we
546 return the result anyway */
552 function sqimap_read_data ($imap_stream, $tag_uid, $handle_errors,
553 &$response, &$message, $query = '',
554 $filter=false,$outputstream=false,$no_return=false) {
556 $tag_uid_a = explode(' ',trim($tag_uid));
557 $tag = $tag_uid_a[0];
559 $res = sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
560 $response, $message, $query,$filter,$outputstream,$no_return);
561 /* sqimap_read_data should be called for one response
562 but since it just calls sqimap_retrieve_imap_response which
563 handles multiple responses we need to check for that
564 and merge the $res array IF they are seperated and
565 IF it was a FETCH response. */
567 // if (isset($res[1]) && is_array($res[1]) && isset($res[1][0])
568 // && preg_match('/^\* \d+ FETCH/', $res[1][0])) {
569 // $result = array();
570 // foreach($res as $index=>$value) {
571 // $result = array_merge($result, $res["$index"]);
574 if (isset($result)) {
575 return $result[$tag];
583 * Logs the user into the imap server. If $hide is set, no error messages
584 * will be displayed. This function returns the imap connection handle.
586 function sqimap_login ($username, $password, $imap_server_address, $imap_port, $hide) {
587 global $color, $squirrelmail_language, $onetimepad, $use_imap_tls, $imap_auth_mech;
589 if (!isset($onetimepad) ||
empty($onetimepad)) {
590 sqgetglobalvar('onetimepad' , $onetimepad , SQ_SESSION
);
592 $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
593 $host=$imap_server_address;
595 if (($use_imap_tls == true) and (check_php_version(4,3)) and (extension_loaded('openssl'))) {
596 /* Use TLS by prefixing "tls://" to the hostname */
597 $imap_server_address = 'tls://' . $imap_server_address;
600 $imap_stream = fsockopen ( $imap_server_address, $imap_port, $error_number, $error_string, 15);
602 /* Do some error correction */
605 set_up_language($squirrelmail_language, true);
606 require_once(SM_PATH
. 'functions/display_messages.php');
607 $string = sprintf (_("Error connecting to IMAP server: %s.") .
608 "<br>\r\n", $imap_server_address) .
609 "$error_number : $error_string<br>\r\n";
610 logout_error($string,$color);
615 $server_info = fgets ($imap_stream, 1024);
617 /* Decrypt the password */
618 $password = OneTimePadDecrypt($password, $onetimepad);
620 if (($imap_auth_mech == 'cram-md5') OR ($imap_auth_mech == 'digest-md5')) {
621 // We're using some sort of authentication OTHER than plain or login
622 $tag=sqimap_session_id(false);
623 if ($imap_auth_mech == 'digest-md5') {
624 $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
625 } elseif ($imap_auth_mech == 'cram-md5') {
626 $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
628 fputs($imap_stream,$query);
629 $answer=sqimap_fgets($imap_stream);
630 // Trim the "+ " off the front
631 $response=explode(" ",$answer,3);
632 if ($response[0] == '+') {
633 // Got a challenge back
634 $challenge=$response[1];
635 if ($imap_auth_mech == 'digest-md5') {
636 $reply = digest_md5_response($username,$password,$challenge,'imap',$host);
637 } elseif ($imap_auth_mech == 'cram-md5') {
638 $reply = cram_md5_response($username,$password,$challenge);
640 fputs($imap_stream,$reply);
641 $read=sqimap_fgets($imap_stream);
642 if ($imap_auth_mech == 'digest-md5') {
643 // DIGEST-MD5 has an extra step..
644 if (substr($read,0,1) == '+') { // OK so far..
645 fputs($imap_stream,"\r\n");
646 $read=sqimap_fgets($imap_stream);
649 $results=explode(" ",$read,3);
650 $response=$results[1];
651 $message=$results[2];
653 // Fake the response, so the error trap at the bottom will work
655 $message='IMAP server does not appear to support the authentication method selected.';
656 $message .= ' Please contact your system administrator.';
658 } elseif ($imap_auth_mech == 'login') {
659 // Original IMAP login code
660 $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
661 $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
662 } elseif ($imap_auth_mech == 'plain') {
663 /* Replace this with SASL PLAIN if it ever gets implemented */
665 $message='SquirrelMail does not support SASL PLAIN yet. Rerun conf.pl and use login instead.';
668 $message="Internal SquirrelMail error - unknown IMAP authentication method chosen. Please contact the developers.";
671 /* If the connection was not successful, lets see why */
672 if ($response != 'OK') {
674 if ($response != 'NO') {
675 /* "BAD" and anything else gets reported here. */
676 $message = htmlspecialchars($message);
677 set_up_language($squirrelmail_language, true);
678 require_once(SM_PATH
. 'functions/display_messages.php');
679 if ($response == 'BAD') {
680 $string = sprintf (_("Bad request: %s")."<br>\r\n", $message);
682 $string = sprintf (_("Unknown error: %s") . "<br>\n", $message);
684 if (isset($read) && is_array($read)) {
685 $string .= '<br>' . _("Read data:") . "<br>\n";
686 foreach ($read as $line) {
687 $string .= htmlspecialchars($line) . "<br>\n";
690 error_box($string,$color);
694 * If the user does not log in with the correct
695 * username and password it is not possible to get the
696 * correct locale from the user's preferences.
697 * Therefore, apply the same hack as on the login
700 * $squirrelmail_language is set by a cookie when
701 * the user selects language and logs out
704 set_up_language($squirrelmail_language, true);
705 include_once(SM_PATH
. 'functions/display_messages.php' );
707 logout_error( _("Unknown user or password incorrect.") );
717 /* Simply logs out the IMAP session */
718 function sqimap_logout ($imap_stream) {
719 /* Logout is not valid until the server returns 'BYE'
720 * If we don't have an imap_ stream we're already logged out */
721 if(isset($imap_stream) && $imap_stream)
722 sqimap_run_command($imap_stream, 'LOGOUT', false, $response, $message);
725 function sqimap_capability($imap_stream, $capability='') {
726 global $sqimap_capabilities;
727 if (!is_array($sqimap_capabilities)) {
728 $read = sqimap_run_command($imap_stream, 'CAPABILITY', true, $a, $b);
730 $c = explode(' ', $read[0]);
731 for ($i=2; $i < count($c); $i++
) {
732 $cap_list = explode('=', $c[$i]);
733 if (isset($cap_list[1])) {
734 $sqimap_capabilities[$cap_list[0]] = $cap_list[1];
736 $sqimap_capabilities[$cap_list[0]] = TRUE;
741 if (isset($sqimap_capabilities[$capability])) {
742 return $sqimap_capabilities[$capability];
747 return $sqimap_capabilities;
750 /* Returns the delimeter between mailboxes: INBOX/Test, or INBOX.Test */
751 function sqimap_get_delimiter ($imap_stream = false) {
752 global $sqimap_delimiter, $optional_delimiter;
754 /* Use configured delimiter if set */
755 if((!empty($optional_delimiter)) && $optional_delimiter != 'detect') {
756 return $optional_delimiter;
759 /* Do some caching here */
760 if (!$sqimap_delimiter) {
761 if (sqimap_capability($imap_stream, 'NAMESPACE')) {
763 * According to something that I can't find, this is supposed to work on all systems
764 * OS: This won't work in Courier IMAP.
765 * OS: According to rfc2342 response from NAMESPACE command is:
766 * OS: * NAMESPACE (PERSONAL NAMESPACES) (OTHER_USERS NAMESPACE) (SHARED NAMESPACES)
767 * OS: We want to lookup all personal NAMESPACES...
769 $read = sqimap_run_command($imap_stream, 'NAMESPACE', true, $a, $b);
770 if (eregi('\\* NAMESPACE +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL)', $read[0], $data)) {
771 if (eregi('^\\( *\\((.*)\\) *\\)', $data[1], $data2)) {
774 $pna = explode(')(', $pn);
775 while (list($k, $v) = each($pna)) {
776 $lst = explode('"', $v);
777 if (isset($lst[3])) {
778 $pn[$lst[1]] = $lst[3];
784 $sqimap_delimiter = $pn[0];
786 fputs ($imap_stream, ". LIST \"INBOX\" \"\"\r\n");
787 $read = sqimap_read_data($imap_stream, '.', true, $a, $b);
788 $quote_position = strpos ($read[0], '"');
789 $sqimap_delimiter = substr ($read[0], $quote_position+
1, 1);
792 return $sqimap_delimiter;
796 /* Gets the number of messages in the current mailbox. */
797 function sqimap_get_num_messages ($imap_stream, $mailbox) {
798 $read_ary = sqimap_run_command ($imap_stream, "EXAMINE \"$mailbox\"", false, $result, $message);
799 for ($i = 0; $i < count($read_ary); $i++
) {
800 if (ereg("[^ ]+ +([^ ]+) +EXISTS", $read_ary[$i], $regs)) {
804 return false; //"BUG! Couldn't get number of messages in $mailbox!";
808 function parseAddress($address, $max=0) {
811 $iCnt = strlen($address);
812 $aSpecials = array('(' ,'<' ,',' ,';' ,':');
813 $aReplace = array(' (',' <',' ,',' ;',' :');
814 $address = str_replace($aSpecials,$aReplace,$address);
815 $i = $iAddrFound = $bGroup = 0;
817 $cChar = $address{$i};
821 $iEnd = strpos($address,'>',$i+
1);
823 $sToken = substr($address,$i);
826 $sToken = substr($address,$i,$iEnd - $i +
1);
829 $sToken = str_replace($aReplace, $aSpecials,$sToken);
830 $aTokens[] = $sToken;
833 $iEnd = strpos($address,$cChar,$i+
1);
835 // skip escaped quotes
836 $prev_char = $address{$iEnd-1};
837 while ($prev_char === '\\' && substr($address,$iEnd-2,2) !== '\\\\') {
838 $iEnd = strpos($address,$cChar,$iEnd+
1);
840 $prev_char = $address{$iEnd-1};
847 $sToken = substr($address,$i);
850 // also remove the surrounding quotes
851 $sToken = substr($address,$i+
1,$iEnd - $i -1);
854 $sToken = str_replace($aReplace, $aSpecials,$sToken);
855 if ($sToken) $aTokens[] = $sToken;
858 $iEnd = strpos($address,')',$i);
860 $sToken = substr($address,$i);
863 $sToken = substr($address,$i,$iEnd - $i +
1);
866 $sToken = str_replace($aReplace, $aSpecials,$sToken);
867 $aTokens[] = $sToken;
877 if ($max && $max == $iAddrFound) {
889 $iEnd = strpos($address,' ',$i+
1);
891 $sToken = trim(substr($address,$i,$iEnd - $i));
894 $sToken = trim(substr($address,$i));
897 if ($sToken) $aTokens[] = $sToken;
901 $sPersonal = $sEmail = $sComment = $sGroup = '';
902 $aStack = $aComment = array();
903 foreach ($aTokens as $sToken) {
904 if ($max && $max == count($aAddress)) {
916 $aComment[] = substr($sToken,1,-1);
920 $sEmail = trim(implode(' ',$aStack));
921 $aAddress[] = array($sGroup,$sEmail);
922 $aStack = $aComment = array();
928 while (count($aStack) && !$sEmail) {
929 $sEmail = trim(array_pop($aStack));
932 if (count($aStack)) {
933 $sPersonal = trim(implode('',$aStack));
937 if (!$sPersonal && count($aComment)) {
938 $sComment = implode(' ',$aComment);
939 $sPersonal .= $sComment;
941 $aAddress[] = array($sEmail,$sPersonal);
942 $sPersonal = $sComment = $sEmail = '';
943 $aStack = $aComment = array();
946 $sGroup = implode(' ',$aStack); break;
950 $sEmail = trim(substr($sToken,1,-1));
955 default: $aStack[] = $sToken; break;
958 /* now do the action again for the last address */
960 while (count($aStack) && !$sEmail) {
961 $sEmail = trim(array_pop($aStack));
964 if (count($aStack)) {
965 $sPersonal = trim(implode('',$aStack));
969 if (!$sPersonal && count($aComment)) {
970 $sComment = implode(' ',$aComment);
971 $sPersonal .= $sComment;
973 $aAddress[] = array($sEmail,$sPersonal);
980 * Returns the number of unseen messages in this folder
982 function sqimap_unseen_messages ($imap_stream, $mailbox) {
983 $read_ary = sqimap_run_command ($imap_stream, "STATUS \"$mailbox\" (UNSEEN)", false, $result, $message);
985 $regs = array(false, false);
986 while (isset($read_ary[$i])) {
987 if (ereg("UNSEEN ([0-9]+)", $read_ary[$i], $regs)) {
996 * Returns the number of unseen/total messages in this folder
998 function sqimap_status_messages ($imap_stream, $mailbox) {
999 $read_ary = sqimap_run_command ($imap_stream, "STATUS \"$mailbox\" (MESSAGES UNSEEN RECENT)", false, $result, $message);
1001 $messages = $unseen = $recent = false;
1002 $regs = array(false,false);
1003 while (isset($read_ary[$i])) {
1004 if (preg_match('/UNSEEN\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1007 if (preg_match('/MESSAGES\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1008 $messages = $regs[1];
1010 if (preg_match('/RECENT\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1015 return array('MESSAGES' => $messages, 'UNSEEN'=>$unseen, 'RECENT' => $recent);
1020 * Saves a message to a given folder -- used for saving sent messages
1022 function sqimap_append ($imap_stream, $sent_folder, $length) {
1023 fputs ($imap_stream, sqimap_session_id() . " APPEND \"$sent_folder\" (\\Seen) \{$length}\r\n");
1024 $tmp = fgets ($imap_stream, 1024);
1027 function sqimap_append_done ($imap_stream, $folder='') {
1028 global $squirrelmail_language, $color;
1029 fputs ($imap_stream, "\r\n");
1030 $tmp = fgets ($imap_stream, 1024);
1031 if (preg_match("/(.*)(BAD|NO)(.*)$/", $tmp, $regs)) {
1032 set_up_language($squirrelmail_language);
1033 require_once(SM_PATH
. 'functions/display_messages.php');
1035 if ($regs[2] == 'NO') {
1036 $string = "<b><font color=$color[2]>\n" .
1037 _("ERROR : Could not append message to") ." $folder." .
1039 _("Server responded: ") .
1041 if (preg_match("/(.*)(quota)(.*)$/i", $reason, $regs)) {
1042 $string .= _("Solution: ") .
1043 _("Remove unneccessary messages from your folder and start with your Trash folder.")
1046 $string .= "</font>\n";
1047 error_box($string,$color);
1049 $string = "<b><font color=$color[2]>\n" .
1050 _("ERROR : Bad or malformed request.") .
1052 _("Server responded: ") .
1053 $tmp . "</font><br>\n";
1054 error_box($string,$color);
1060 function sqimap_get_user_server ($imap_server, $username) {
1061 if (substr($imap_server, 0, 4) != "map:") {
1062 return $imap_server;
1064 $function = substr($imap_server, 4);
1065 return $function($username);
1068 /* This is an example that gets imapservers from yellowpages (NIS).
1069 * you can simple put map:map_yp_alias in your $imap_server_address
1070 * in config.php use your own function instead map_yp_alias to map your
1071 * LDAP whatever way to find the users imapserver. */
1073 function map_yp_alias($username) {
1074 $yp = `ypmatch
$username aliases`
;
1075 return chop(substr($yp, strlen($username)+
1));