Source for file imap_general.php
Documentation is available at imap_general.php
* This implements all functions that do general IMAP functions.
* @copyright © 1999-2006 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id: imap_general.php,v 1.237 2006/10/04 19:25:25 stekkel Exp $
require_once(SM_PATH .
'functions/rfc822address.php');
* Generates a new session ID by incrementing the last one used;
* this ensures that each command has a unique ID.
* @param bool $unique_id (since 1.3.0) controls use of unique
* identifiers/message sequence numbers in IMAP commands. See IMAP
* rfc 'UID command' chapter.
* @return string IMAP session id of the form 'A000'.
static $sqimap_session_id =
1;
return( sprintf("A%03d", $sqimap_session_id++
) );
return( sprintf("A%03d", $sqimap_session_id++
) .
' UID' );
* Both send a command and accept the result from the command.
* This is to allow proper session number handling.
* @param stream $imap_stream imap connection resource
* @param string $query imap command
* @param boolean $handle_errors see sqimap_retrieve_imap_response()
* @param boolean $unique_id (since 1.3.0) see sqimap_session_id().
* @return mixed returns false on imap error. displays error message
* if imap stream is not available.
function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$response, &$message, $unique_id =
false) {
fputs ($imap_stream, $sid .
' ' .
$query .
"\r\n");
/* get the response and the message */
$message =
$message[$tag];
$response =
$response[$tag];
global $squirrelmail_language, $color;
$string =
"<b><font color=\"$color[2]\">\n" .
_("ERROR: No available IMAP stream.") .
* @param stream $imap_stream imap connection resource
* @param string $query imap command
* @param boolean $handle_errors see sqimap_retrieve_imap_response()
* @param array $response empty string, if return = false
* @param array $message empty string, if return = false
* @param boolean $unique_id (since 1.3.0) see sqimap_session_id()
* @param boolean $filter (since 1.4.1 and 1.5.0) see sqimap_fread()
* @param mixed $outputstream (since 1.4.1 and 1.5.0) see sqimap_fread()
* @param boolean $no_return (since 1.4.1 and 1.5.0) see sqimap_fread()
* @return mixed returns false on imap error. displays error message
* if imap stream is not available.
&$message, $unique_id =
false,$filter=
false,
$outputstream=
false,$no_return=
false) {
fputs ($imap_stream, $sid .
' ' .
$query .
"\r\n");
$message, $query,$filter,$outputstream,$no_return);
if (empty($read)) { //IMAP server dropped its connection
/* retrieve the response and the message */
$response =
$response[$tag];
$message =
$message[$tag];
if (!empty($read[$tag])) {
global $squirrelmail_language, $color;
$string =
"<b><font color=\"$color[2]\">\n" .
_("ERROR: No available IMAP stream.") .
* @param mixed $new_query
* @param boolean $unique_id see sqimap_session_id()
$query =
$sid .
' '.
$new_query.
"\r\n";
* @param stream $imap_stream imap stream
* @param array $aQueryList
* @param boolean $handle_errors
* @param array $aServerResponse
* @param array $aServerMessage
* @param boolean $unique_id see sqimap_session_id()
* @param boolean $filter see sqimap_fread()
* @param mixed $outputstream see sqimap_fread()
* @param boolean $no_return see sqimap_fread()
&$aServerResponse, &$aServerMessage, $unique_id =
false,
$filter=
false,$outputstream=
false,$no_return=
false) {
Do not fire all calls at once to the IMAP server but split the calls up
in portions of $iChunkSize. If we do not do that I think we misbehave as
IMAP client or should handle BYE calls if the IMAP server drops the
connection because the number of queries is to large. This isn't tested
but a wild guess how it could work in the field.
After testing it on Exchange 2000 we discovered that a chunksize of 32
was quicker then when we raised it to 128.
$iQueryCount =
count($aQueryList);
// array_chunk would also do the job but it's supported from php > 4.2
$iLoops =
floor($iQueryCount /
$iChunkSize);
if ($iLoops *
$iChunkSize !=
$iQueryCount) ++
$iLoops;
for($i=
0;$i<
$iLoops;++
$i) {
for($j=
0;$j<
$iChunkSize;++
$j) {
$aTmp[$key] =
$aQueryList[$key];
if (next($aQueryList) ===
false) break;
$aQueryChunks =
array_chunk($aQueryList,$iChunkSize,true);
for ($i=
0;$i<
$iLoops;++
$i) {
$aQuery =
$aQueryChunks[$i];
foreach($aQuery as $tag =>
$query) {
fputs($imap_stream,$query);
foreach($aQuery as $tag =>
$query) {
if ($aResults[$tag] ==
false) {
$handle_errors, $response, $message, $query,
$filter,$outputstream,$no_return);
foreach ($aReturnedResponse as $returned_tag =>
$aResponse) {
if (!empty($aResponse)) {
$aResults[$returned_tag] =
$aResponse[0];
$aResults[$returned_tag] =
$aResponse;
$aServerResponse[$returned_tag] =
$response[$returned_tag];
$aServerMessage[$returned_tag] =
$message[$returned_tag];
* Custom fgets function: gets a line from the IMAP server,
* no matter how big it may be.
* @param stream $imap_stream the stream to read from
while (strpos($results, "\r\n", $offset) ===
false) {
if (!($read =
fgets($imap_stream, $buffer))) {
/* this happens in case of an error */
/* reset $results because it's useless */
$offset =
strlen($results) -
1;
* @param stream $imap_stream
* @param mixed $outputstream stream or 'php://stdout' string
* @param boolean $no_return controls data returned by function
$outputstream=
false, $no_return=
false) {
if (!$filter ||
!$outputstream) {
// see php bug 24033. They changed fread behaviour %$^&$%
$iBufferSize =
7800; // multiple of 78 in case of base64 decoding.
if ($iSize <
$iBufferSize) {
// NB: fread can also stop at end of a packet on sockets.
while ($iRetrieved <
$iSize) {
$sRead =
fread($imap_stream,$iBufferSize);
$iRetrieved +=
$iLength ;
$iRemaining =
$iSize -
$iRetrieved;
if ($iRemaining <
$iBufferSize) {
$iBufferSize =
$iRemaining;
$sRead =
$sReadRem .
$sRead;
if ($filter &&
$sRead !=
'') {
// in case the filter is base64 decoding we return a remainder
$sReadRem =
$filter($sRead);
if ($outputstream &&
$sRead !=
'') {
} else if ($outputstream ==
'php://stdout') {
* Obsolete function, inform plugins that use it
* @param stream $imap_stream
* @param boolean $handle_errors
* @deprecated (since 1.5.0) use sqimap_run_command or sqimap_run_command_list instead
&$response, &$message, $query =
'') {
global $color, $oTemplate, $squirrelmail_language;
$string =
"<b><font color=\"$color[2]\">\n" .
_("ERROR: Bad function call.") .
'There is a plugin installed which make use of the <br />' .
'SquirrelMail internal function sqimap_read_data_list.<br />'.
'Please adapt the installed plugin and let it use<br />'.
'sqimap_run_command or sqimap_run_command_list instead<br /><br />'.
'The following query was issued:<br />'.
$oTemplate->display('footer.tpl');
* Function to display an error related to an IMAP query.
* @param string title the caption of the error box
* @param string query the query that went wrong
* @param string message_title optional message title
* @param string message optional error message
* @param string $link an optional link to try again
function sqimap_error_box($title, $query =
'', $message_title =
'', $message =
'', $link =
'')
global $color, $squirrelmail_language;
$string =
"<font color=\"$color[2]\"><b>\n" .
$title .
"</b><br />\n";
if ($query !=
'' &&
$cmd !=
'login')
if ($message_title !=
'')
$string .=
$message_title;
$string .=
"</font><br />\n";
* Reads the output from the IMAP stream. If handle_errors is set to true,
* this will also handle all errors that are received. If it is not set,
* the errors will be sent back through $response and $message.
* @param stream $imap_stream imap stream
* @param boolean $handle_errors handle errors internally or send them in $response and $message.
* @param string $query command that can be printed if something fails
* @param boolean $filter see sqimap_fread()
* @param mixed $outputstream see sqimap_fread()
* @param boolean $no_return see sqimap_fread()
&$response, &$message, $query =
'',
$filter =
false, $outputstream =
false, $no_return =
false) {
global $color, $squirrelmail_language;
if (!is_array($message)) $message =
array();
if (!is_array($response)) $response =
array();
// error reporting (shouldn't happen)
$found_tag =
substr($read,0,$i-
1);
$response[$found_tag] =
$arg;
$aResponse[$found_tag] =
$resultlist;
$data =
$resultlist =
array();
if ($found_tag ==
$tag) {
break 3; /* switch switch while */
/* this shouldn't happen */
$response[$found_tag] =
$arg;
$aResponse[$found_tag] =
$resultlist;
$data =
$resultlist =
array();
if ($found_tag ==
$tag) {
break 3; /* switch switch while */
if ($read ===
false) { /* error */
break 2; /* switch while */
if (($sCommand ==
"FETCH" ||
$sCommand ==
"STORE") &&
preg_match('/^\*\s\d+\sFETCH/',$read)) {
do
{ /* outer loop, continue until next untagged fetch
do
{ /* innerloop for fetching literals. with this loop
we prohibid that literal responses appear in the
outer loop so we can trust the untagged and
tagged info provided by $read */
$iLit =
substr($read,$j+
1,-
3);
$sLiteral =
sqimap_fread($imap_stream,$iLit,$filter,$outputstream,$no_return);
if ($sLiteral ===
false) { /* error */