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