Adding template for error box.
[squirrelmail.git] / functions / imap_general.php
CommitLineData
59177427 1<?php
bccadd02 2
35586184 3/**
a6fd80f5 4 * imap_general.php
35586184 5 *
0e1a248b 6 * This implements all functions that do general IMAP functions.
35586184 7 *
47ccfad4 8 * @copyright &copy; 1999-2006 The SquirrelMail Project Team
4b4abf93 9 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
eb19bc67 10 * @version $Id$
d6c32258 11 * @package squirrelmail
eb19bc67 12 * @subpackage imap
35586184 13 */
14
d6c32258 15/** Includes.. */
b68edc75 16require_once(SM_PATH . 'functions/page_header.php');
47a29326 17require_once(SM_PATH . 'functions/auth.php');
938d39ca 18include_once(SM_PATH . 'functions/rfc822address.php');
47a29326 19
35586184 20
48af4b64 21/**
22 * Generates a new session ID by incrementing the last one used;
23 * this ensures that each command has a unique ID.
0e1a248b 24 * @param bool $unique_id (since 1.3.0) controls use of unique
b35a5862 25 * identifiers/message sequence numbers in IMAP commands. See IMAP
26 * rfc 'UID command' chapter.
48af4b64 27 * @return string IMAP session id of the form 'A000'.
b35a5862 28 * @since 1.2.0
48af4b64 29 */
2aca19a1 30function sqimap_session_id($unique_id = FALSE) {
31 static $sqimap_session_id = 1;
32
487daa81 33 if (!$unique_id) {
098ea084 34 return( sprintf("A%03d", $sqimap_session_id++) );
487daa81 35 } else {
098ea084 36 return( sprintf("A%03d", $sqimap_session_id++) . ' UID' );
487daa81 37 }
9c737111 38}
39
48af4b64 40/**
3411d4ec 41 * Both send a command and accept the result from the command.
42 * This is to allow proper session number handling.
95e3afc1 43 * @param stream $imap_stream imap connection resource
b35a5862 44 * @param string $query imap command
45 * @param boolean $handle_errors see sqimap_retrieve_imap_response()
95e3afc1 46 * @param array $response
47 * @param array $message
48 * @param boolean $unique_id (since 1.3.0) see sqimap_session_id().
0e1a248b 49 * @return mixed returns false on imap error. displays error message
b35a5862 50 * if imap stream is not available.
51 * @since 1.2.3
3411d4ec 52 */
487daa81 53function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$response, &$message, $unique_id = false) {
c5809184 54 if ($imap_stream) {
098ea084 55 $sid = sqimap_session_id($unique_id);
56 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
bc78cc6e 57 $tag_uid_a = explode(' ',trim($sid));
58 $tag = $tag_uid_a[0];
0dc05a81 59 $read = sqimap_retrieve_imap_response ($imap_stream, $tag, $handle_errors, $response, $message, $query );
bc78cc6e 60 /* get the response and the message */
61 $message = $message[$tag];
1e0a2f0e 62 $response = $response[$tag];
bc78cc6e 63 return $read[$tag];
c5809184 64 } else {
65 global $squirrelmail_language, $color;
66 set_up_language($squirrelmail_language);
67 require_once(SM_PATH . 'functions/display_messages.php');
6fd95361 68 $string = "<b><font color=\"$color[2]\">\n" .
0e1a248b 69 _("ERROR: No available IMAP stream.") .
c5809184 70 "</b></font>\n";
71 error_box($string,$color);
098ea084 72 return false;
c5809184 73 }
1c72b151 74}
75
b35a5862 76/**
95e3afc1 77 * @param stream $imap_stream imap connection resource
b35a5862 78 * @param string $query imap command
79 * @param boolean $handle_errors see sqimap_retrieve_imap_response()
95e3afc1 80 * @param array $response empty string, if return = false
81 * @param array $message empty string, if return = false
82 * @param boolean $unique_id (since 1.3.0) see sqimap_session_id()
83 * @param boolean $filter (since 1.4.1 and 1.5.0) see sqimap_fread()
84 * @param mixed $outputstream (since 1.4.1 and 1.5.0) see sqimap_fread()
85 * @param boolean $no_return (since 1.4.1 and 1.5.0) see sqimap_fread()
0e1a248b 86 * @return mixed returns false on imap error. displays error message
b35a5862 87 * if imap stream is not available.
88 * @since 1.2.3
89 */
1e0a2f0e 90function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response,
7c7b74b3 91 &$message, $unique_id = false,$filter=false,
92 $outputstream=false,$no_return=false) {
c5809184 93 if ($imap_stream) {
94 $sid = sqimap_session_id($unique_id);
1e0a2f0e 95 fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
bc78cc6e 96 $tag_uid_a = explode(' ',trim($sid));
97 $tag = $tag_uid_a[0];
1e0a2f0e 98
bc78cc6e 99 $read = sqimap_read_data ($imap_stream, $tag, $handle_errors, $response,
7c7b74b3 100 $message, $query,$filter,$outputstream,$no_return);
0e1a248b 101 if (empty($read)) { //IMAP server dropped its connection
ec73f243 102 $response = '';
103 $message = '';
104 return false;
105 }
bc78cc6e 106 /* retrieve the response and the message */
107 $response = $response[$tag];
108 $message = $message[$tag];
1e0a2f0e 109
bc78cc6e 110 if (!empty($read[$tag])) {
111 return $read[$tag][0];
112 } else {
113 return $read[$tag];
114 }
c5809184 115 } else {
116 global $squirrelmail_language, $color;
117 set_up_language($squirrelmail_language);
118 require_once(SM_PATH . 'functions/display_messages.php');
6fd95361 119 $string = "<b><font color=\"$color[2]\">\n" .
0e1a248b 120 _("ERROR: No available IMAP stream.") .
c5809184 121 "</b></font>\n";
122 error_box($string,$color);
098ea084 123 return false;
1e0a2f0e 124 }
bc78cc6e 125}
48af4b64 126
0022f6db 127/**
128 * @param mixed $new_query
129 * @param string $tag
130 * @param array $aQuery
95e3afc1 131 * @param boolean $unique_id see sqimap_session_id()
0022f6db 132 * @since 1.5.0
133 */
bc78cc6e 134function sqimap_prepare_pipelined_query($new_query,&$tag,&$aQuery,$unique_id) {
135 $sid = sqimap_session_id($unique_id);
136 $tag_uid_a = explode(' ',trim($sid));
137 $tag = $tag_uid_a[0];
0b38d197 138 $query = $sid . ' '.$new_query."\r\n";
bc78cc6e 139 $aQuery[$tag] = $query;
42a07ac1 140}
141
0022f6db 142/**
95e3afc1 143 * @param stream $imap_stream imap stream
0022f6db 144 * @param array $aQueryList
145 * @param boolean $handle_errors
146 * @param array $aServerResponse
147 * @param array $aServerMessage
95e3afc1 148 * @param boolean $unique_id see sqimap_session_id()
149 * @param boolean $filter see sqimap_fread()
150 * @param mixed $outputstream see sqimap_fread()
151 * @param boolean $no_return see sqimap_fread()
0022f6db 152 * @since 1.5.0
153 */
1e0a2f0e 154function sqimap_run_pipelined_command ($imap_stream, $aQueryList, $handle_errors,
bc78cc6e 155 &$aServerResponse, &$aServerMessage, $unique_id = false,
1e0a2f0e 156 $filter=false,$outputstream=false,$no_return=false) {
bc78cc6e 157 $aResponse = false;
5c300c60 158
1e0a2f0e 159 /*
0e1a248b 160 Do not fire all calls at once to the IMAP server but split the calls up
1e0a2f0e 161 in portions of $iChunkSize. If we do not do that I think we misbehave as
0e1a248b 162 IMAP client or should handle BYE calls if the IMAP server drops the
52c8b585 163 connection because the number of queries is to large. This isn't tested
164 but a wild guess how it could work in the field.
1e0a2f0e 165
166 After testing it on Exchange 2000 we discovered that a chunksize of 32
0b38d197 167 was quicker then when we raised it to 128.
52c8b585 168 */
169 $iQueryCount = count($aQueryList);
170 $iChunkSize = 32;
171 // array_chunk would also do the job but it's supported from php > 4.2
172 $aQueryChunks = array();
173 $iLoops = floor($iQueryCount / $iChunkSize);
174
5c300c60 175 if ($iLoops * $iChunkSize != $iQueryCount) ++$iLoops;
52c8b585 176
177 if (!function_exists('array_chunk')) { // arraychunk replacement
5c300c60 178 reset($aQueryList);
52c8b585 179 for($i=0;$i<$iLoops;++$i) {
5c300c60 180 for($j=0;$j<$iChunkSize;++$j) {
181 $key = key($aQueryList);
182 $aTmp[$key] = $aQueryList[$key];
183 if (next($aQueryList) === false) break;
184 }
185 $aQueryChunks[] = $aTmp;
1e0a2f0e 186 }
52c8b585 187 } else {
188 $aQueryChunks = array_chunk($aQueryList,$iChunkSize,true);
bc78cc6e 189 }
1e0a2f0e 190
52c8b585 191 for ($i=0;$i<$iLoops;++$i) {
192 $aQuery = $aQueryChunks[$i];
193 foreach($aQuery as $tag => $query) {
194 fputs($imap_stream,$query);
195 $aResults[$tag] = false;
196 }
52c8b585 197 foreach($aQuery as $tag => $query) {
5c300c60 198 if ($aResults[$tag] == false) {
1e0a2f0e 199 $aReturnedResponse = sqimap_retrieve_imap_response ($imap_stream, $tag,
bc78cc6e 200 $handle_errors, $response, $message, $query,
201 $filter,$outputstream,$no_return);
52c8b585 202 foreach ($aReturnedResponse as $returned_tag => $aResponse) {
5c300c60 203 if (!empty($aResponse)) {
52c8b585 204 $aResults[$returned_tag] = $aResponse[0];
5c300c60 205 } else {
206 $aResults[$returned_tag] = $aResponse;
207 }
52c8b585 208 $aServerResponse[$returned_tag] = $response[$returned_tag];
209 $aServerMessage[$returned_tag] = $message[$returned_tag];
210 }
bc78cc6e 211 }
212 }
213 }
b7277e4f 214 return $aResults;
bc78cc6e 215}
9c737111 216
1e0a2f0e 217/**
0e1a248b 218 * Custom fgets function: gets a line from the IMAP server,
48af4b64 219 * no matter how big it may be.
95e3afc1 220 * @param stream $imap_stream the stream to read from
48af4b64 221 * @return string a line
0022f6db 222 * @since 1.2.8
b8c285ab 223 */
b8c285ab 224function sqimap_fgets($imap_stream) {
225 $read = '';
226 $buffer = 4096;
227 $results = '';
c41daf03 228 $offset = 0;
229 while (strpos($results, "\r\n", $offset) === false) {
b8c285ab 230 if (!($read = fgets($imap_stream, $buffer))) {
329a7ca5 231 /* this happens in case of an error */
232 /* reset $results because it's useless */
233 $results = false;
b8c285ab 234 break;
235 }
c41daf03 236 if ( $results != '' ) {
237 $offset = strlen($results) - 1;
238 }
b8c285ab 239 $results .= $read;
240 }
241 return $results;
242}
243
0022f6db 244/**
245 * @param stream $imap_stream
246 * @param integer $iSize
95e3afc1 247 * @param boolean $filter
248 * @param mixed $outputstream stream or 'php://stdout' string
0e1a248b 249 * @param boolean $no_return controls data returned by function
0022f6db 250 * @return string
251 * @since 1.4.1
252 */
7c7b74b3 253function sqimap_fread($imap_stream,$iSize,$filter=false,
254 $outputstream=false, $no_return=false) {
255 if (!$filter || !$outputstream) {
256 $iBufferSize = $iSize;
257 } else {
811318c5 258 // see php bug 24033. They changed fread behaviour %$^&$%
977a6085 259 $iBufferSize = 7800; // multiple of 78 in case of base64 decoding.
260 }
261 if ($iSize < $iBufferSize) {
262 $iBufferSize = $iSize;
7c7b74b3 263 }
7c0ec1d8 264
5eba0be2 265 $iRetrieved = 0;
977a6085 266 $results = '';
267 $sRead = $sReadRem = '';
1e0a2f0e 268 // NB: fread can also stop at end of a packet on sockets.
977a6085 269 while ($iRetrieved < $iSize) {
7c7b74b3 270 $sRead = fread($imap_stream,$iBufferSize);
977a6085 271 $iLength = strlen($sRead);
272 $iRetrieved += $iLength ;
273 $iRemaining = $iSize - $iRetrieved;
274 if ($iRemaining < $iBufferSize) {
275 $iBufferSize = $iRemaining;
276 }
13aabbcf 277 if ($sRead == '') {
7c7b74b3 278 $results = false;
279 break;
280 }
13aabbcf 281 if ($sReadRem != '') {
977a6085 282 $sRead = $sReadRem . $sRead;
283 $sReadRem = '';
284 }
7c0ec1d8 285
13aabbcf 286 if ($filter && $sRead != '') {
1e0a2f0e 287 // in case the filter is base64 decoding we return a remainder
7c0ec1d8 288 $sReadRem = $filter($sRead);
7c7b74b3 289 }
13aabbcf 290 if ($outputstream && $sRead != '') {
7c7b74b3 291 if (is_resource($outputstream)) {
292 fwrite($outputstream,$sRead);
293 } else if ($outputstream == 'php://stdout') {
294 echo $sRead;
295 }
296 }
297 if ($no_return) {
298 $sRead = '';
1e0a2f0e 299 } else {
977a6085 300 $results .= $sRead;
7c7b74b3 301 }
7c7b74b3 302 }
1e0a2f0e 303 return $results;
304}
977a6085 305
7c0ec1d8 306
48af4b64 307/**
308 * Obsolete function, inform plugins that use it
95e3afc1 309 * @param stream $imap_stream
310 * @param string $tag
311 * @param boolean $handle_errors
312 * @param array $response
313 * @param array $message
314 * @param string $query
b35a5862 315 * @since 1.1.3
316 * @deprecated (since 1.5.0) use sqimap_run_command or sqimap_run_command_list instead
48af4b64 317 */
1e0a2f0e 318function sqimap_read_data_list($imap_stream, $tag, $handle_errors,
0dc05a81 319 &$response, &$message, $query = '') {
320 global $color, $squirrelmail_language;
321 set_up_language($squirrelmail_language);
322 require_once(SM_PATH . 'functions/display_messages.php');
6fd95361 323 $string = "<b><font color=\"$color[2]\">\n" .
0e1a248b 324 _("ERROR: Bad function call.") .
6fd95361 325 "</b><br />\n" .
0dc05a81 326 _("Reason:") . ' '.
6fd95361 327 'There is a plugin installed which make use of the <br />' .
328 'SquirrelMail internal function sqimap_read_data_list.<br />'.
329 'Please adapt the installed plugin and let it use<br />'.
330 'sqimap_run_command or sqimap_run_command_list instead<br /><br />'.
331 'The following query was issued:<br />'.
332 htmlspecialchars($query) . '<br />' . "</font><br />\n";
0dc05a81 333 error_box($string,$color);
1e0a2f0e 334 echo '</body></html>';
335 exit;
0dc05a81 336}
7c7b74b3 337
48af4b64 338/**
0e1a248b 339 * Function to display an error related to an IMAP query.
48af4b64 340 * @param string title the caption of the error box
341 * @param string query the query that went wrong
ec73f243 342 * @param string message_title optional message title
343 * @param string message optional error message
344 * @param string $link an optional link to try again
48af4b64 345 * @return void
0022f6db 346 * @since 1.5.0
48af4b64 347 */
ec73f243 348function sqimap_error_box($title, $query = '', $message_title = '', $message = '', $link = '')
4974c2a0 349{
350 global $color, $squirrelmail_language;
351
352 set_up_language($squirrelmail_language);
353 require_once(SM_PATH . 'functions/display_messages.php');
6fd95361 354 $string = "<font color=\"$color[2]\"><b>\n" . $title . "</b><br />\n";
bf15f116 355 $cmd = explode(' ',$query);
356 $cmd= strtolower($cmd[0]);
357
358 if ($query != '' && $cmd != 'login')
6fd95361 359 $string .= _("Query:") . ' ' . htmlspecialchars($query) . '<br />';
4974c2a0 360 if ($message_title != '')
361 $string .= $message_title;
362 if ($message != '')
363 $string .= htmlspecialchars($message);
6fd95361 364 $string .= "</font><br />\n";
ec73f243 365 if ($link != '')
366 $string .= $link;
4974c2a0 367 error_box($string,$color);
368}
369
48af4b64 370/**
3411d4ec 371 * Reads the output from the IMAP stream. If handle_errors is set to true,
372 * this will also handle all errors that are received. If it is not set,
48af4b64 373 * the errors will be sent back through $response and $message.
95e3afc1 374 * @param stream $imap_stream imap stream
375 * @param string $tag
376 * @param boolean $handle_errors handle errors internally or send them in $response and $message.
0022f6db 377 * @param array $response
378 * @param array $message
95e3afc1 379 * @param string $query command that can be printed if something fails
380 * @param boolean $filter see sqimap_fread()
381 * @param mixed $outputstream see sqimap_fread()
382 * @param boolean $no_return see sqimap_fread()
0022f6db 383 * @since 1.5.0
bee165ef 384 */
1e0a2f0e 385function sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
7c7b74b3 386 &$response, &$message, $query = '',
387 $filter = false, $outputstream = false, $no_return = false) {
9c737111 388 global $color, $squirrelmail_language;
9c737111 389 $read = '';
bc78cc6e 390 if (!is_array($message)) $message = array();
391 if (!is_array($response)) $response = array();
ec73f243 392 $aResponse = '';
b8c285ab 393 $resultlist = array();
394 $data = array();
ee231c8b 395 $sCommand = '';
396 if (preg_match("/^(\w+)\s*/",$query,$aMatch)) {
397 $sCommand = strtoupper($aMatch[1]);
398 } else {
399 // error reporting (shouldn't happen)
400 }
b8c285ab 401 $read = sqimap_fgets($imap_stream);
8d8da447 402 $i = 0;
bea3eb1e 403 while ($read) {
404 $char = $read{0};
405 switch ($char)
406 {
15bc7f66 407 case '+':
408 default:
409 $read = sqimap_fgets($imap_stream);
410 break;
411
412 case $tag{0}:
413 {
bea3eb1e 414 /* get the command */
415 $arg = '';
416 $i = strlen($tag)+1;
417 $s = substr($read,$i);
418 if (($j = strpos($s,' ')) || ($j = strpos($s,"\n"))) {
419 $arg = substr($s,0,$j);
420 }
421 $found_tag = substr($read,0,$i-1);
5c300c60 422 if ($found_tag) {
bea3eb1e 423 switch ($arg)
424 {
15bc7f66 425 case 'OK':
426 case 'BAD':
427 case 'NO':
428 case 'BYE':
429 case 'PREAUTH':
bc78cc6e 430 $response[$found_tag] = $arg;
431 $message[$found_tag] = trim(substr($read,$i+strlen($arg)));
432 if (!empty($data)) {
433 $resultlist[] = $data;
434 }
5c300c60 435 $aResponse[$found_tag] = $resultlist;
436 $data = $resultlist = array();
437 if ($found_tag == $tag) {
438 break 3; /* switch switch while */
439 }
440 break;
1e0a2f0e 441 default:
bea3eb1e 442 /* this shouldn't happen */
bc78cc6e 443 $response[$found_tag] = $arg;
444 $message[$found_tag] = trim(substr($read,$i+strlen($arg)));
445 if (!empty($data)) {
446 $resultlist[] = $data;
447 }
448 $aResponse[$found_tag] = $resultlist;
5c300c60 449 $data = $resultlist = array();
450 if ($found_tag == $tag) {
451 break 3; /* switch switch while */
452 }
bc78cc6e 453 }
bea3eb1e 454 }
5c300c60 455 $read = sqimap_fgets($imap_stream);
456 if ($read === false) { /* error */
4920e1e0 457 break 2; /* switch while */
5c300c60 458 }
459 break;
15bc7f66 460 } // end case $tag{0}
461
462 case '*':
463 {
b2e8c7a0 464 if (($sCommand == "FETCH" || $sCommand == "STORE") && preg_match('/^\*\s\d+\sFETCH/',$read)) {
bea3eb1e 465 /* check for literal */
466 $s = substr($read,-3);
467 $fetch_data = array();
468 do { /* outer loop, continue until next untagged fetch
469 or tagged reponse */
470 do { /* innerloop for fetching literals. with this loop
471 we prohibid that literal responses appear in the
472 outer loop so we can trust the untagged and
473 tagged info provided by $read */
474 if ($s === "}\r\n") {
475 $j = strrpos($read,'{');
476 $iLit = substr($read,$j+1,-3);
477 $fetch_data[] = $read;
7c7b74b3 478 $sLiteral = sqimap_fread($imap_stream,$iLit,$filter,$outputstream,$no_return);
329a7ca5 479 if ($sLiteral === false) { /* error */
480 break 4; /* while while switch while */
481 }
bea3eb1e 482 /* backwards compattibility */
483 $aLiteral = explode("\n", $sLiteral);
484 /* release not neaded data */
485 unset($sLiteral);
486 foreach ($aLiteral as $line) {
487 $fetch_data[] = $line ."\n";
488 }
489 /* release not neaded data */
1e0a2f0e 490 unset($aLiteral);
bea3eb1e 491 /* next fgets belongs to this fetch because
492 we just got the exact literalsize and there
493 must follow data to complete the response */
329a7ca5 494 $read = sqimap_fgets($imap_stream);
495 if ($read === false) { /* error */
496 break 4; /* while while switch while */
497 }
c0b23345 498 $fetch_data[] = $read;
bea3eb1e 499 } else {
329a7ca5 500 $fetch_data[] = $read;
bea3eb1e 501 }
502 /* retrieve next line and check in the while
503 statements if it belongs to this fetch response */
504 $read = sqimap_fgets($imap_stream);
329a7ca5 505 if ($read === false) { /* error */
506 break 4; /* while while switch while */
507 }
bea3eb1e 508 /* check for next untagged reponse and break */
509 if ($read{0} == '*') break 2;
510 $s = substr($read,-3);
511 } while ($s === "}\r\n");
512 $s = substr($read,-3);
513 } while ($read{0} !== '*' &&
106d4087 514 substr($read,0,strlen($tag)) !== $tag);
329a7ca5 515 $resultlist[] = $fetch_data;
bea3eb1e 516 /* release not neaded data */
517 unset ($fetch_data);
518 } else {
519 $s = substr($read,-3);
520 do {
521 if ($s === "}\r\n") {
522 $j = strrpos($read,'{');
523 $iLit = substr($read,$j+1,-3);
524 $data[] = $read;
329a7ca5 525 $sLiteral = fread($imap_stream,$iLit);
c0b23345 526 if ($sLiteral === false) { /* error */
329a7ca5 527 $read = false;
528 break 3; /* while switch while */
529 }
c0b23345 530 $data[] = $sLiteral;
b7277e4f 531 $data[] = sqimap_fgets($imap_stream);
bea3eb1e 532 } else {
329a7ca5 533 $data[] = $read;
bea3eb1e 534 }
535 $read = sqimap_fgets($imap_stream);
329a7ca5 536 if ($read === false) {
537 break 3; /* while switch while */
538 } else if ($read{0} == '*') {
106d4087 539 break;
540 }
bea3eb1e 541 $s = substr($read,-3);
542 } while ($s === "}\r\n");
543 break 1;
1e0a2f0e 544 }
bea3eb1e 545 break;
15bc7f66 546 } // end case '*'
547 } // end switch
c0b23345 548 } // end while
1e0a2f0e 549
c0b23345 550 /* error processing in case $read is false */
d7542838 551 if ($read === false) {
d3d9ef2d 552 // try to retrieve an untagged bye respons from the results
553 $sResponse = array_pop($data);
d7542838 554 if ($sResponse !== NULL && strpos($sResponse,'* BYE') !== false) {
555 if (!$handle_errors) {
556 $query = '';
557 }
0e1a248b 558 sqimap_error_box(_("ERROR: IMAP server closed the connection."), $query, _("Server responded:"),$sResponse);
d7542838 559 echo '</body></html>';
560 exit;
561 } else if ($handle_errors) {
1e0a2f0e 562 unset($data);
0e1a248b 563 sqimap_error_box(_("ERROR: Connection dropped by IMAP server."), $query);
ec73f243 564 exit;
565 }
b8c285ab 566 }
1e0a2f0e 567
15bc7f66 568 /* Set $resultlist array */
b8c285ab 569 if (!empty($data)) {
bc78cc6e 570 //$resultlist[] = $data;
9c737111 571 }
b8c285ab 572 elseif (empty($resultlist)) {
1e0a2f0e 573 $resultlist[] = array();
b8c285ab 574 }
15bc7f66 575
576 /* Return result or handle errors */
bee165ef 577 if ($handle_errors == false) {
bc78cc6e 578 return $aResponse;
dd381002 579 }
4974c2a0 580 switch ($response[$tag]) {
dd381002 581 case 'OK':
bc78cc6e 582 return $aResponse;
329a7ca5 583 break;
1e0a2f0e 584 case 'NO':
dd381002 585 /* ignore this error from M$ exchange, it is not fatal (aka bug) */
6b6c2e06 586 if (strstr($message[$tag], 'command resulted in') === false) {
0e1a248b 587 sqimap_error_box(_("ERROR: Could not complete request."), $query, _("Reason Given:") . ' ', $message[$tag]);
329a7ca5 588 echo '</body></html>';
052e0c26 589 exit;
9c737111 590 }
329a7ca5 591 break;
1e0a2f0e 592 case 'BAD':
0e1a248b 593 sqimap_error_box(_("ERROR: Bad or malformed request."), $query, _("Server responded:") . ' ', $message[$tag]);
1e0a2f0e 594 echo '</body></html>';
595 exit;
596 case 'BYE':
0e1a248b 597 sqimap_error_box(_("ERROR: IMAP server closed the connection."), $query, _("Server responded:") . ' ', $message[$tag]);
1e0a2f0e 598 echo '</body></html>';
9c737111 599 exit;
1e0a2f0e 600 default:
0e1a248b 601 sqimap_error_box(_("ERROR: Unknown IMAP response."), $query, _("Server responded:") . ' ', $message[$tag]);
329a7ca5 602 /* the error is displayed but because we don't know the reponse we
603 return the result anyway */
1e0a2f0e 604 return $aResponse;
329a7ca5 605 break;
9c737111 606 }
9c737111 607}
608
0022f6db 609/**
95e3afc1 610 * @param stream $imap_stream imap string
0022f6db 611 * @param string $tag_uid
612 * @param boolean $handle_errors
613 * @param array $response
614 * @param array $message
95e3afc1 615 * @param string $query (since 1.2.5)
616 * @param boolean $filter (since 1.4.1) see sqimap_fread()
617 * @param mixed $outputstream (since 1.4.1) see sqimap_fread()
618 * @param boolean $no_return (since 1.4.1) see sqimap_fread()
0022f6db 619 */
1e0a2f0e 620function sqimap_read_data ($imap_stream, $tag_uid, $handle_errors,
7c7b74b3 621 &$response, &$message, $query = '',
622 $filter=false,$outputstream=false,$no_return=false) {
bc78cc6e 623
624 $tag_uid_a = explode(' ',trim($tag_uid));
625 $tag = $tag_uid_a[0];
626
1e0a2f0e 627 $res = sqimap_retrieve_imap_response($imap_stream, $tag, $handle_errors,
628 $response, $message, $query,$filter,$outputstream,$no_return);
629 return $res;
9c737111 630}
631
48af4b64 632/**
b98732e8 633 * Connects to the IMAP server and returns a resource identifier for use with
a15f9d93 634 * the other SquirrelMail IMAP functions. Does NOT login!
48af4b64 635 * @param string server hostname of IMAP server
636 * @param int port port number to connect to
a15f9d93 637 * @param integer $tls whether to use plain text(0), TLS(1) or STARTTLS(2) when connecting.
638 * Argument was boolean before 1.5.1.
48af4b64 639 * @return imap-stream resource identifier
0022f6db 640 * @since 1.5.0 (usable only in 1.5.1 or later)
b98732e8 641 */
a15f9d93 642function sqimap_create_stream($server,$port,$tls=0) {
ce68b76b 643 global $squirrelmail_language;
b98732e8 644
abc4a428 645 if (strstr($server,':') && ! preg_match("/^\[.*\]$/",$server)) {
646 // numerical IPv6 address must be enclosed in square brackets
647 $server = '['.$server.']';
648 }
a15f9d93 649
650 if ($tls == 1) {
b98732e8 651 if ((check_php_version(4,3)) and (extension_loaded('openssl'))) {
652 /* Use TLS by prefixing "tls://" to the hostname */
57ffe0af 653 $server = 'tls://' . $server;
b98732e8 654 } else {
655 require_once(SM_PATH . 'functions/display_messages.php');
3b151851 656 logout_error( sprintf(_("Error connecting to IMAP server: %s."), $server).
657 '<br />'.
658 _("TLS is enabled, but this version of PHP does not support TLS sockets, or is missing the openssl extension.").
659 '<br /><br />'.
0a6be7d1 660 _("Please contact your system administrator and report this error."),
abc4a428 661 sprintf(_("Error connecting to IMAP server: %s."), $server));
b98732e8 662 }
663 }
664
82f403aa 665 $imap_stream = @fsockopen($server, $port, $error_number, $error_string, 15);
b98732e8 666
667 /* Do some error correction */
668 if (!$imap_stream) {
669 set_up_language($squirrelmail_language, true);
670 require_once(SM_PATH . 'functions/display_messages.php');
3b151851 671 logout_error( sprintf(_("Error connecting to IMAP server: %s."), $server).
0a6be7d1 672 "<br />\r\n$error_number : $error_string<br />\r\n",
abc4a428 673 sprintf(_("Error connecting to IMAP server: %s."), $server) );
b98732e8 674 exit;
675 }
676 $server_info = fgets ($imap_stream, 1024);
a15f9d93 677
678 /**
679 * Implementing IMAP STARTTLS (rfc2595) in php 5.1.0+
680 * http://www.php.net/stream-socket-enable-crypto
681 */
c4de9863 682 if ($tls === 2) {
a15f9d93 683 if (function_exists('stream_socket_enable_crypto')) {
684 // check starttls capability, don't use cached capability version
685 if (! sqimap_capability($imap_stream, 'STARTTLS', false)) {
686 // imap server does not declare starttls support
687 sqimap_error_box(sprintf(_("Error connecting to IMAP server: %s."), $server),
688 '','',
689 _("IMAP STARTTLS is enabled in SquirrelMail configuration, but used IMAP server does not support STARTTLS."));
690 exit;
691 }
692
693 // issue starttls command and check response
694 sqimap_run_command($imap_stream, 'STARTTLS', false, $starttls_response, $starttls_message);
695 // check response
696 if ($starttls_response!='OK') {
697 // starttls command failed
698 sqimap_error_box(sprintf(_("Error connecting to IMAP server: %s."), $server),
699 'STARTTLS',
3c021d16 700 _("Server replied:") . ' ',
a15f9d93 701 $starttls_message);
702 exit();
703 }
704
705 // start crypto on connection. suppress function errors.
706 if (@stream_socket_enable_crypto($imap_stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
707 // starttls was successful
708
709 /**
4ae9beb7 710 * RFC 2595 requires to discard CAPABILITY information after successful
711 * STARTTLS command. We don't follow RFC, because SquirrelMail stores CAPABILITY
712 * information only after successful login (src/redirect.php) and cached information
713 * is used only in other php script connections after successful STARTTLS. If script
714 * issues sqimap_capability() call before sqimap_login() and wants to get initial
715 * capability response, script should set third sqimap_capability() argument to false.
a15f9d93 716 */
4ae9beb7 717 //sqsession_unregister('sqimap_capabilities');
a15f9d93 718 } else {
719 /**
720 * stream_socket_enable_crypto() call failed. Possible issues:
721 * - broken ssl certificate (uw drops connection, error is in syslog mail facility)
4ae9beb7 722 * - some ssl error (can reproduce with STREAM_CRYPTO_METHOD_SSLv3_CLIENT, PHP E_WARNING
a15f9d93 723 * suppressed in stream_socket_enable_crypto() call)
724 */
725 sqimap_error_box(sprintf(_("Error connecting to IMAP server: %s."), $server),
726 '','',
727 _("Unable to start TLS."));
728 /**
4ae9beb7 729 * Bug: stream_socket_enable_crypto() does not register SSL errors in
730 * openssl_error_string() or stream notification wrapper and displays
731 * them in E_WARNING level message. It is impossible to retrieve error
a15f9d93 732 * message without own error handler.
733 */
734 exit;
735 }
736 } else {
737 // php install does not support stream_socket_enable_crypto() function
738 sqimap_error_box(sprintf(_("Error connecting to IMAP server: %s."), $server),
739 '','',
740 _("IMAP STARTTLS is enabled in SquirrelMail configuration, but used PHP version does not support functions that allow to enable encryption on open socket."));
741 exit;
742 }
743 }
b98732e8 744 return $imap_stream;
745}
746
48af4b64 747/**
0e1a248b 748 * Logs the user into the IMAP server. If $hide is set, no error messages
749 * will be displayed. This function returns the IMAP connection handle.
0022f6db 750 * @param string $username user name
751 * @param string $password encrypted password
752 * @param string $imap_server_address address of imap server
753 * @param integer $imap_port port of imap server
754 * @param boolean $hide controls display connection errors
755 * @return stream
3411d4ec 756 */
9c737111 757function sqimap_login ($username, $password, $imap_server_address, $imap_port, $hide) {
fe55c7c7 758 global $color, $squirrelmail_language, $onetimepad, $use_imap_tls,
759 $imap_auth_mech, $sqimap_capabilities;
85fc999e 760
eb2f6102 761 if (!isset($onetimepad) || empty($onetimepad)) {
762 sqgetglobalvar('onetimepad' , $onetimepad , SQ_SESSION );
763 }
fe55c7c7 764 if (!isset($sqimap_capabilities)) {
765 sqgetglobalvar('sqimap_capabilities' , $capability , SQ_SESSION );
766 }
767
b98732e8 768 $host = $imap_server_address;
bd9829d7 769 $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
fe55c7c7 770
b98732e8 771 $imap_stream = sqimap_create_stream($imap_server_address,$imap_port,$use_imap_tls);
fe55c7c7 772
2f1f7a12 773 /* Decrypt the password */
774 $password = OneTimePadDecrypt($password, $onetimepad);
775
b98732e8 776 if (($imap_auth_mech == 'cram-md5') OR ($imap_auth_mech == 'digest-md5')) {
3b151851 777 // We're using some sort of authentication OTHER than plain or login
b98732e8 778 $tag=sqimap_session_id(false);
779 if ($imap_auth_mech == 'digest-md5') {
098ea084 780 $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
b98732e8 781 } elseif ($imap_auth_mech == 'cram-md5') {
098ea084 782 $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
b98732e8 783 }
784 fputs($imap_stream,$query);
785 $answer=sqimap_fgets($imap_stream);
786 // Trim the "+ " off the front
787 $response=explode(" ",$answer,3);
788 if ($response[0] == '+') {
098ea084 789 // Got a challenge back
b98732e8 790 $challenge=$response[1];
791 if ($imap_auth_mech == 'digest-md5') {
792 $reply = digest_md5_response($username,$password,$challenge,'imap',$host);
793 } elseif ($imap_auth_mech == 'cram-md5') {
794 $reply = cram_md5_response($username,$password,$challenge);
795 }
796 fputs($imap_stream,$reply);
797 $read=sqimap_fgets($imap_stream);
798 if ($imap_auth_mech == 'digest-md5') {
3b151851 799 // DIGEST-MD5 has an extra step..
b98732e8 800 if (substr($read,0,1) == '+') { // OK so far..
098ea084 801 fputs($imap_stream,"\r\n");
802 $read=sqimap_fgets($imap_stream);
098ea084 803 }
b98732e8 804 }
805 $results=explode(" ",$read,3);
806 $response=$results[1];
807 $message=$results[2];
808 } else {
3b151851 809 // Fake the response, so the error trap at the bottom will work
b98732e8 810 $response="BAD";
811 $message='IMAP server does not appear to support the authentication method selected.';
812 $message .= ' Please contact your system administrator.';
813 }
fe0b18b3 814 } elseif ($imap_auth_mech == 'login') {
b98732e8 815 // Original IMAP login code
816 $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
817 $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
1e7fc1cb 818 } elseif ($imap_auth_mech == 'plain') {
fe55c7c7 819 /***
820 * SASL PLAIN
821 *
822 * RFC 2595 Chapter 6
823 *
824 * The mechanism consists of a single message from the client to the
825 * server. The client sends the authorization identity (identity to
826 * login as), followed by a US-ASCII NUL character, followed by the
827 * authentication identity (identity whose password will be used),
828 * followed by a US-ASCII NUL character, followed by the clear-text
829 * password. The client may leave the authorization identity empty to
830 * indicate that it is the same as the authentication identity.
831 *
832 **/
b98732e8 833 $tag=sqimap_session_id(false);
2bd6b461 834 $sasl = (isset($capability['SASL-IR']) && $capability['SASL-IR']) ? true : false;
b98732e8 835 $auth = base64_encode("$username\0$username\0$password");
fe55c7c7 836 if ($sasl) {
837 // IMAP Extension for SASL Initial Client Response
2bd6b461 838 // <draft-siemborski-imap-sasl-initial-response-01b.txt>
fe55c7c7 839 $query = $tag . " AUTHENTICATE PLAIN $auth\r\n";
840 fputs($imap_stream, $query);
b98732e8 841 $read = sqimap_fgets($imap_stream);
fe55c7c7 842 } else {
843 $query = $tag . " AUTHENTICATE PLAIN\r\n";
844 fputs($imap_stream, $query);
845 $read=sqimap_fgets($imap_stream);
846 if (substr($read,0,1) == '+') { // OK so far..
847 fputs($imap_stream, "$auth\r\n");
848 $read = sqimap_fgets($imap_stream);
849 }
098ea084 850 }
b98732e8 851 $results=explode(" ",$read,3);
852 $response=$results[1];
853 $message=$results[2];
854 } else {
855 $response="BAD";
856 $message="Internal SquirrelMail error - unknown IMAP authentication method chosen. Please contact the developers.";
857 }
fe55c7c7 858
b98732e8 859 /* If the connection was not successful, lets see why */
9c737111 860 if ($response != 'OK') {
861 if (!$hide) {
74424a43 862 if ($response != 'NO') {
3411d4ec 863 /* "BAD" and anything else gets reported here. */
098ea084 864 $message = htmlspecialchars($message);
9c737111 865 set_up_language($squirrelmail_language, true);
098ea084 866 require_once(SM_PATH . 'functions/display_messages.php');
9c737111 867 if ($response == 'BAD') {
6fd95361 868 $string = sprintf (_("Bad request: %s")."<br />\r\n", $message);
9c737111 869 } else {
6fd95361 870 $string = sprintf (_("Unknown error: %s") . "<br />\n", $message);
9c737111 871 }
1e7fc1cb 872 if (isset($read) && is_array($read)) {
6fd95361 873 $string .= '<br />' . _("Read data:") . "<br />\n";
9c737111 874 foreach ($read as $line) {
6fd95361 875 $string .= htmlspecialchars($line) . "<br />\n";
9c737111 876 }
877 }
098ea084 878 error_box($string,$color);
9c737111 879 exit;
165e24a7 880 } else {
3411d4ec 881 /*
882 * If the user does not log in with the correct
1c72b151 883 * username and password it is not possible to get the
884 * correct locale from the user's preferences.
885 * Therefore, apply the same hack as on the login
886 * screen.
3411d4ec 887 *
888 * $squirrelmail_language is set by a cookie when
1c72b151 889 * the user selects language and logs out
bee165ef 890 */
fe55c7c7 891
9c737111 892 set_up_language($squirrelmail_language, true);
bd9c880b 893 include_once(SM_PATH . 'functions/display_messages.php' );
098ea084 894 sqsession_destroy();
d5c472f1 895 /* terminate the session nicely */
896 sqimap_logout($imap_stream);
bd9c880b 897 logout_error( _("Unknown user or password incorrect.") );
9c737111 898 exit;
052e0c26 899 }
9c737111 900 } else {
052e0c26 901 exit;
9c737111 902 }
903 }
1d20443c 904
905 /* Special error case:
906 * Login referrals. The server returns:
0e1a248b 907 * ? OK [REFERRAL <imap url>]
908 * Check RFC 2221 for details. Since we do not support login referrals yet
909 * we log the user out.
910 */
2da1524c 911 if ( stristr($message, 'REFERRAL imap') === TRUE ) {
0e1a248b 912 sqimap_logout($imap_stream);
1d20443c 913 set_up_language($squirrelmail_language, true);
914 include_once(SM_PATH . 'functions/display_messages.php' );
915 sqsession_destroy();
edde1f5c 916 logout_error( _("Your mailbox is not located at this server. Try a different server or consult your system administrator") );
1d20443c 917 exit;
918 }
0e1a248b 919
9c737111 920 return $imap_stream;
921}
f1e6f580 922
48af4b64 923/**
924 * Simply logs out the IMAP session
95e3afc1 925 * @param stream $imap_stream the IMAP connection to log out.
48af4b64 926 * @return void
927 */
9c737111 928function sqimap_logout ($imap_stream) {
8d936b0c 929 /* Logout is not valid until the server returns 'BYE'
930 * If we don't have an imap_ stream we're already logged out */
26a2cc8b 931 if(isset($imap_stream) && $imap_stream)
8d936b0c 932 sqimap_run_command($imap_stream, 'LOGOUT', false, $response, $message);
9c737111 933}
934
48af4b64 935/**
95e3afc1 936 * Retrieve the CAPABILITY string from the IMAP server.
48af4b64 937 * If capability is set, returns only that specific capability,
938 * else returns array of all capabilities.
95e3afc1 939 * @param stream $imap_stream
a15f9d93 940 * @param string $capability (since 1.3.0)
4ae9beb7 941 * @param boolean $bUseCache (since 1.5.1) Controls use of capability data stored in session
0e1a248b 942 * @return mixed (string if $capability is set and found,
0022f6db 943 * false, if $capability is set and not found,
944 * array if $capability not set)
48af4b64 945 */
a15f9d93 946function sqimap_capability($imap_stream, $capability='', $bUseCache=true) {
947 // sqgetGlobalVar('sqimap_capabilities', $sqimap_capabilities, SQ_SESSION);
0493ed11 948
a15f9d93 949 if (!$bUseCache || ! sqgetGlobalVar('sqimap_capabilities', $sqimap_capabilities, SQ_SESSION)) {
1c72b151 950 $read = sqimap_run_command($imap_stream, 'CAPABILITY', true, $a, $b);
951
9c737111 952 $c = explode(' ', $read[0]);
953 for ($i=2; $i < count($c); $i++) {
954 $cap_list = explode('=', $c[$i]);
3411d4ec 955 if (isset($cap_list[1])) {
3cfa833d 956 $sqimap_capabilities[trim($cap_list[0])][] = $cap_list[1];
3411d4ec 957 } else {
3cfa833d 958 $sqimap_capabilities[trim($cap_list[0])] = TRUE;
3411d4ec 959 }
f1e6f580 960 }
9c737111 961 }
487daa81 962 if ($capability) {
098ea084 963 if (isset($sqimap_capabilities[$capability])) {
964 return $sqimap_capabilities[$capability];
965 } else {
966 return false;
967 }
f1e6f580 968 }
487daa81 969 return $sqimap_capabilities;
9c737111 970}
971
48af4b64 972/**
95e3afc1 973 * Returns the delimiter between mailboxes: INBOX/Test, or INBOX.Test
0022f6db 974 * @param stream $imap_stream
975 * @return string
48af4b64 976 */
9c737111 977function sqimap_get_delimiter ($imap_stream = false) {
3411d4ec 978 global $sqimap_delimiter, $optional_delimiter;
85fc999e 979
9c737111 980 /* Use configured delimiter if set */
981 if((!empty($optional_delimiter)) && $optional_delimiter != 'detect') {
982 return $optional_delimiter;
983 }
85fc999e 984
7eb6261e 985 /* Delimiter is stored in the session from redirect. Try fetching from there first */
cc54580f 986 if (empty($sqimap_delimiter)) {
7eb6261e 987 sqgetGlobalVar('delimiter',$sqimap_delimiter,SQ_SESSION);
988 }
989
9c737111 990 /* Do some caching here */
991 if (!$sqimap_delimiter) {
992 if (sqimap_capability($imap_stream, 'NAMESPACE')) {
3411d4ec 993 /*
994 * According to something that I can't find, this is supposed to work on all systems
995 * OS: This won't work in Courier IMAP.
996 * OS: According to rfc2342 response from NAMESPACE command is:
997 * OS: * NAMESPACE (PERSONAL NAMESPACES) (OTHER_USERS NAMESPACE) (SHARED NAMESPACES)
998 * OS: We want to lookup all personal NAMESPACES...
999 */
1c72b151 1000 $read = sqimap_run_command($imap_stream, 'NAMESPACE', true, $a, $b);
f1e6f580 1001 if (eregi('\\* NAMESPACE +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL)', $read[0], $data)) {
9c737111 1002 if (eregi('^\\( *\\((.*)\\) *\\)', $data[1], $data2)) {
f1e6f580 1003 $pn = $data2[1];
9c737111 1004 }
f1e6f580 1005 $pna = explode(')(', $pn);
9c737111 1006 while (list($k, $v) = each($pna)) {
862ff2d3 1007 $lst = explode('"', $v);
1008 if (isset($lst[3])) {
1009 $pn[$lst[1]] = $lst[3];
1010 } else {
74424a43 1011 $pn[$lst[1]] = '';
862ff2d3 1012 }
f1e6f580 1013 }
1014 }
1015 $sqimap_delimiter = $pn[0];
1016 } else {
1017 fputs ($imap_stream, ". LIST \"INBOX\" \"\"\r\n");
1018 $read = sqimap_read_data($imap_stream, '.', true, $a, $b);
91e0dccc 1019 $read = $read['.'][0]; //sqimap_read_data() now returns a tag array of response array
f1e6f580 1020 $quote_position = strpos ($read[0], '"');
1021 $sqimap_delimiter = substr ($read[0], $quote_position+1, 1);
1022 }
1023 }
1024 return $sqimap_delimiter;
9c737111 1025}
052e0c26 1026
48af4b64 1027/**
1028 * This encodes a mailbox name for use in IMAP commands.
95e3afc1 1029 * @param string $what the mailbox to encode
48af4b64 1030 * @return string the encoded mailbox string
0022f6db 1031 * @since 1.5.0
48af4b64 1032 */
b2306cbe 1033function sqimap_encode_mailbox_name($what)
1034{
91e0dccc 1035 if (ereg("[\"\\\r\n]", $what))
1036 return '{' . strlen($what) . "}\r\n" . $what; /* 4.3 literal form */
1037 return '"' . $what . '"'; /* 4.3 quoted string form */
b2306cbe 1038}
1039
48af4b64 1040/**
1041 * Gets the number of messages in the current mailbox.
1e0a2f0e 1042 *
1043 * OBSOLETE use sqimap_status_messages instead.
95e3afc1 1044 * @param stream $imap_stream imap stream
1045 * @param string $mailbox
1046 * @deprecated
48af4b64 1047 */
9c737111 1048function sqimap_get_num_messages ($imap_stream, $mailbox) {
48879ef0 1049 $aStatus = sqimap_status_messages($imap_stream,$mailbox,array('MESSAGES'));
1050 return $aStatus['MESSAGES'];
9c737111 1051}
95e3afc1 1052
1e0a2f0e 1053/**
1054 * OBSOLETE FUNCTION should be removed after mailbox_display,
1055 * printMessage function is adapted
95e3afc1 1056 * $addr_ar = array(), $group = '' and $host='' arguments are used in 1.4.0
1057 * @param string $address
1058 * @param integer $max
1059 * @since 1.4.0
1060 * @deprecated See Rfc822Address.php
1e0a2f0e 1061 */
91688e5f 1062function parseAddress($address, $max=0) {
1e0a2f0e 1063 $aAddress = parseRFC822Address($address,array('limit'=> $max));
1064 /*
1065 * Because the expected format of the array element is changed we adapt it now.
1066 * This also implies that this function is obsolete and should be removed after the
1067 * rest of the source is adapted. See Rfc822Address.php for the new function.
1068 */
1069 array_walk($aAddress, '_adaptAddress');
1070 return $aAddress;
1071}
91688e5f 1072
1e0a2f0e 1073/**
1074 * OBSOLETE FUNCTION should be removed after mailbox_display,
1075 * printMessage function is adapted
95e3afc1 1076 *
0e1a248b 1077 * callback function used for formating of addresses array in
95e3afc1 1078 * parseAddress() function
1079 * @param array $aAddr
1080 * @param integer $k array key
1081 * @since 1.5.1
1082 * @deprecated
1e0a2f0e 1083 */
1084function _adaptAddress(&$aAddr,$k) {
1085 $sPersonal = (isset($aAddr[SQM_ADDR_PERSONAL]) && $aAddr[SQM_ADDR_PERSONAL]) ?
1086 $aAddr[SQM_ADDR_PERSONAL] : '';
1087 $sEmail = ($aAddr[SQM_ADDR_HOST]) ?
3cd52f38 1088 $aAddr[SQM_ADDR_MAILBOX] . '@'.$aAddr[SQM_ADDR_HOST] :
1089 $aAddr[SQM_ADDR_MAILBOX];
1e0a2f0e 1090 $aAddr = array($sEmail,$sPersonal);
1091}
91688e5f 1092
48af4b64 1093/**
1094 * Returns the number of unseen messages in this folder.
26e90c74 1095 * obsoleted by sqimap_status_messages !
95e3afc1 1096 * Arguments differ in 1.0.x
1097 * @param stream $imap_stream
1098 * @param string $mailbox
1099 * @return integer
1100 * @deprecated
3411d4ec 1101 */
9c737111 1102function sqimap_unseen_messages ($imap_stream, $mailbox) {
26e90c74 1103 $aStatus = sqimap_status_messages($imap_stream,$mailbox,array('UNSEEN'));
1104 return $aStatus['UNSEEN'];
9c737111 1105}
1106
48af4b64 1107/**
26e90c74 1108 * Returns the status items of a mailbox.
1109 * Default it returns MESSAGES,UNSEEN and RECENT
0e1a248b 1110 * Supported status items are MESSAGES, UNSEEN, RECENT (since 1.4.0),
95e3afc1 1111 * UIDNEXT (since 1.5.1) and UIDVALIDITY (since 1.5.1)
1112 * @param stream $imap_stream imap stream
1113 * @param string $mailbox mail folder
1114 * @param array $aStatusItems status items
1115 * @return array
1116 * @since 1.3.2
1f720b34 1117 */
1e0a2f0e 1118function sqimap_status_messages ($imap_stream, $mailbox,
26e90c74 1119 $aStatusItems = array('MESSAGES','UNSEEN','RECENT')) {
1120
3fedd15b 1121 $aStatusItems = implode(' ',$aStatusItems);
26e90c74 1122 $read_ary = sqimap_run_command ($imap_stream, 'STATUS ' . sqimap_encode_mailbox_name($mailbox) .
1123 " ($aStatusItems)", false, $result, $message);
1f720b34 1124 $i = 0;
26e90c74 1125 $messages = $unseen = $recent = $uidnext = $uidvalidity = false;
1f720b34 1126 $regs = array(false,false);
1127 while (isset($read_ary[$i])) {
1128 if (preg_match('/UNSEEN\s+([0-9]+)/i', $read_ary[$i], $regs)) {
098ea084 1129 $unseen = $regs[1];
1130 }
1f720b34 1131 if (preg_match('/MESSAGES\s+([0-9]+)/i', $read_ary[$i], $regs)) {
098ea084 1132 $messages = $regs[1];
1133 }
b8ec18ef 1134 if (preg_match('/RECENT\s+([0-9]+)/i', $read_ary[$i], $regs)) {
098ea084 1135 $recent = $regs[1];
1e0a2f0e 1136 }
26e90c74 1137 if (preg_match('/UIDNEXT\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1138 $uidnext = $regs[1];
1e0a2f0e 1139 }
26e90c74 1140 if (preg_match('/UIDVALIDITY\s+([0-9]+)/i', $read_ary[$i], $regs)) {
1141 $uidvalidity = $regs[1];
1e0a2f0e 1142 }
1f720b34 1143 $i++;
1144 }
48879ef0 1145
1146 $status=array('MESSAGES' => $messages,
1e0a2f0e 1147 'UNSEEN'=>$unseen,
26e90c74 1148 'RECENT' => $recent,
1149 'UIDNEXT' => $uidnext,
1150 'UIDVALIDITY' => $uidvalidity);
48879ef0 1151
1152 if (!empty($messages)) { $hook_status['MESSAGES']=$messages; }
1153 if (!empty($unseen)) { $hook_status['UNSEEN']=$unseen; }
1154 if (!empty($recent)) { $hook_status['RECENT']=$recent; }
81de00c0 1155 if (!empty($hook_status)) {
48879ef0 1156 $hook_status['MAILBOX']=$mailbox;
1157 $hook_status['CALLER']='sqimap_status_messages';
1158 do_hook_function('folder_status',$hook_status);
1159 }
1160 return $status;
1f720b34 1161}
1162
9c737111 1163
48af4b64 1164/**
1165 * Saves a message to a given folder -- used for saving sent messages
95e3afc1 1166 * @param stream $imap_stream
1167 * @param string $sent_folder
1168 * @param $length
81de00c0 1169 * @return string $sid
3411d4ec 1170 */
81de00c0 1171function sqimap_append ($imap_stream, $sMailbox, $length) {
1172 $sid = sqimap_session_id();
1173 $query = $sid . ' APPEND ' . sqimap_encode_mailbox_name($sMailbox) . " (\\Seen) {".$length."}";
1174 fputs ($imap_stream, "$query\r\n");
85fc999e 1175 $tmp = fgets ($imap_stream, 1024);
81de00c0 1176 sqimap_append_checkresponse($tmp, $sMailbox,$sid, $query);
1177 return $sid;
9c737111 1178}
1179
95e3afc1 1180/**
1181 * @param stream imap_stream
1182 * @param string $folder (since 1.3.2)
1183 */
81de00c0 1184function sqimap_append_done ($imap_stream, $sMailbox='') {
9c737111 1185 fputs ($imap_stream, "\r\n");
1186 $tmp = fgets ($imap_stream, 1024);
81de00c0 1187 while (!sqimap_append_checkresponse($tmp, $sMailbox)) {
1188 $tmp = fgets ($imap_stream, 1024);
1189 }
7ec3a6b9 1190}
1191
95e3afc1 1192/**
0e1a248b 1193 * Displays error messages, if there are errors in responses to
95e3afc1 1194 * commands issues by sqimap_append() and sqimap_append_done() functions.
1195 * @param string $response
81de00c0 1196 * @param string $sMailbox
1197 * @return bool $bDone
9948500c 1198 * @since 1.5.1 and 1.4.5
95e3afc1 1199 */
81de00c0 1200function sqimap_append_checkresponse($response, $sMailbox, $sid='', $query='') {
81de00c0 1201 // static vars to keep them available when sqimap_append_done calls this function.
1202 static $imapquery, $imapsid;
7ec3a6b9 1203
81de00c0 1204 $bDone = false;
1205
1206 if ($query) {
1207 $imapquery = $query;
1208 }
1209 if ($sid) {
1210 $imapsid = $sid;
1211 }
1212 if ($response{0} == '+') {
1213 // continuation request triggerd by sqimap_append()
1214 $bDone = true;
1215 } else {
1216 $i = strpos($response, ' ');
1217 $sRsp = substr($response,0,$i);
1218 $sMsg = substr($response,$i+1);
1219 $aExtra = array('MAILBOX' => $sMailbox);
1220 switch ($sRsp) {
1221 case '*': //untagged response
1222 $i = strpos($sMsg, ' ');
1223 $sRsp = strtoupper(substr($sMsg,0,$i));
1224 $sMsg = substr($sMsg,$i+1);
1225 if ($sRsp == 'NO' || $sRsp == 'BAD') {
1226 // for the moment disabled. Enable after 1.5.1 release.
1227 // Notices could give valueable information about the mailbox
1228 // sqm_trigger_imap_error('SQM_IMAP_APPEND_NOTICE',$imapquery,$sRsp,$sMsg);
1229 }
1230 $bDone = false;
1231 case $imapsid:
1232 // A001 OK message
1233 // $imapsid<space>$sRsp<space>$sMsg
1234 $bDone = true;
1235 $i = strpos($sMsg, ' ');
1236 $sRsp = strtoupper(substr($sMsg,0,$i));
1237 $sMsg = substr($sMsg,$i+1);
1238 switch ($sRsp) {
1239 case 'NO':
1240 if (preg_match("/(.*)(quota)(.*)$/i", $sMsg, $aMatch)) {
1241 sqm_trigger_imap_error('SQM_IMAP_APPEND_QUOTA_ERROR',$imapquery,$sRsp,$sMsg,$aExtra);
1242 } else {
1243 sqm_trigger_imap_error('SQM_IMAP_APPEND_ERROR',$imapquery,$sRsp,$sMsg,$aExtra);
1244 }
1245 break;
1246 case 'BAD':
1247 sqm_trigger_imap_error('SQM_IMAP_ERROR',$imapquery,$sRsp,$sMsg,$aExtra);
1248 break;
1249 case 'BYE':
1250 sqm_trigger_imap_error('SQM_IMAP_BYE',$imapquery,$sRsp,$sMsg,$aExtra);
1251 break;
1252 case 'OK':
1253 break;
1254 default:
1255 break;
1256 }
1257 break;
1258 default:
1259 // should be false because of the unexpected response but i'm not sure if
1260 // that will cause an endless loop in sqimap_append_done
1261 $bDone = true;
098ea084 1262 }
69146537 1263 }
81de00c0 1264 return $bDone;
9c737111 1265}
85fc999e 1266
95e3afc1 1267/**
0e1a248b 1268 * Allows mapping of IMAP server address with custom function
95e3afc1 1269 * see map_yp_alias()
1270 * @param string $imap_server imap server address or mapping
1271 * @param string $username
1272 * @return string
1273 * @since 1.3.0
1274 */
bd9829d7 1275function sqimap_get_user_server ($imap_server, $username) {
bd9829d7 1276 if (substr($imap_server, 0, 4) != "map:") {
1277 return $imap_server;
1278 }
bd9829d7 1279 $function = substr($imap_server, 4);
1280 return $function($username);
1281}
1282
48af4b64 1283/**
0e1a248b 1284 * This is an example that gets IMAP servers from yellowpages (NIS).
1e0a2f0e 1285 * you can simple put map:map_yp_alias in your $imap_server_address
bd9829d7 1286 * in config.php use your own function instead map_yp_alias to map your
0e1a248b 1287 * LDAP whatever way to find the users IMAP server.
1288 *
95e3afc1 1289 * Requires access to external ypmatch program
1290 * FIXME: it can be implemented in php yp extension or pecl (since php 5.1.0)
1291 * @param string $username
1292 * @return string
1293 * @since 1.3.0
48af4b64 1294 */
bd9829d7 1295function map_yp_alias($username) {
1296 $yp = `ypmatch $username aliases`;
1297 return chop(substr($yp, strlen($username)+1));
1e0a2f0e 1298}
bd9829d7 1299
c4de9863 1300?>