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