source: subversion/trunk/roundcubemail/program/lib/imap.inc @ 2448

Last change on this file since 2448 was 2448, checked in by alec, 4 years ago
  • Use UID STORE/COPY commands
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.8 KB
Line 
1<?php
2/////////////////////////////////////////////////////////
3//     
4//      Iloha IMAP Library (IIL)
5//
6//      (C)Copyright 2002 Ryo Chijiiwa <Ryo@IlohaMail.org>
7//
8//      This file is part of IlohaMail. IlohaMail is free software released
9//      under the GPL license.  See enclosed file COPYING for details, or
10//      see http://www.fsf.org/copyleft/gpl.html
11//
12/////////////////////////////////////////////////////////
13
14/********************************************************
15
16        FILE: include/imap.inc
17        PURPOSE:
18                Provide alternative IMAP library that doesn't rely on the standard
19                C-Client based version.  This allows IlohaMail to function regardless
20                of whether or not the PHP build it's running on has IMAP functionality
21                built-in.
22        USEAGE:
23                Function containing "_C_" in name require connection handler to be
24                passed as one of the parameters.  To obtain connection handler, use
25                iil_Connect()
26        VERSION:
27                IlohaMail-0.9-20050415
28        CHANGES:
29                File altered by Thomas Bruederli <roundcube@gmail.com>
30                to fit enhanced equirements by the RoundCube Webmail:
31                - Added list of server capabilites and check these before invoking commands
32                - Added junk flag to iilBasicHeader
33                - Enhanced error reporting on fsockopen()
34                - Additional parameter for SORT command
35                - Removed Call-time pass-by-reference because deprecated
36                - Parse charset from content-type in iil_C_FetchHeaders()
37                - Enhanced heaer sorting
38                - Pass message as reference in iil_C_Append (to save memory)
39                - Added BCC and REFERENCE to the list of headers to fetch in iil_C_FetchHeaders()
40                - Leave messageID unchanged in iil_C_FetchHeaders()
41                - Avoid stripslahes in iil_Connect()
42                - Escape quotes and backslashes in iil_C_Login()
43                - Added patch to iil_SortHeaders() by Richard Green
44                - Removed <br> from error messages (better for logging)
45                - Added patch to iil_C_Sort() enabling UID SORT commands
46                - Added function iil_C_ID2UID()
47                - Casting date parts in iil_StrToTime() to avoid mktime() warnings
48                - Also acceppt LIST responses in iil_C_ListSubscribed()
49                - Sanity check of $message_set in iil_C_FetchHeaders(), iil_C_FetchHeaderIndex(), iil_C_FetchThreadHeaders()
50                - Implemented UID FETCH in iil_C_FetchHeaders()
51                - Abort do-loop on socket errors (fgets returns false)
52                - $ICL_SSL is not boolean anymore but contains the connection schema (ssl or tls)
53                - Removed some debuggers (echo ...)
54                File altered by Aleksander Machniak <alec@alec.pl>
55                - trim(chop()) replaced by trim()
56                - added iil_Escape()/iil_UnEscape() with support for " and \ in folder names
57                - support \ character in username in iil_C_Login()
58                - fixed iil_MultLine(): use iil_ReadBytes() instead of iil_ReadLine()
59                - fixed iil_C_FetchStructureString() to handle many literal strings in response
60                - removed hardcoded data size in iil_ReadLine()
61                - added iil_PutLine() wrapper for fputs()
62                - code cleanup and identation fixes
63                - removed flush() calls in iil_C_HandlePartBody() to prevent from memory leak (#1485187)
64                - don't return "??" from iil_C_GetQuota()
65                - RFC3501 [7.1] don't call CAPABILITY if was returned in server
66                  optional resposne in iil_Connect(), added iil_C_GetCapability()
67                - remove 'undisclosed-recipients' string from 'To' header
68                - iil_C_HandlePartBody(): added 6th argument and fixed endless loop
69                - added iil_PutLineC()
70                - fixed iil_C_Sort() to support very long and/or divided responses
71                - added BYE/BAD response simple support for endless loop prevention
72                - added 3rd argument in iil_StartsWith* functions
73                - fix iil_C_FetchPartHeader() in some cases by use of iil_C_HandlePartBody()
74                - allow iil_C_HandlePartBody() to fetch whole message
75                - optimize iil_C_FetchHeaders() to use only one FETCH command
76                - added 4th argument to iil_Connect()
77                - allow setting rootdir and delimiter before connect
78                - support multiquota result
79                - include BODYSTRUCTURE in iil_C_FetchHeaders()
80                - added iil_C_FetchMIMEHeaders() function
81                - added \* flag support
82
83********************************************************/
84
85/**
86 * @todo Possibly clean up more CS.
87 * @todo Try to replace most double-quotes with single-quotes.
88 * @todo Split this file into smaller files.
89 * @todo Refactor code.
90 * @todo Replace echo-debugging (make it adhere to config setting and log)
91 */
92
93// changed path to work within roundcube webmail
94include_once 'lib/icl_commons.inc';
95
96
97if (!isset($IMAP_USE_HEADER_DATE) || !$IMAP_USE_HEADER_DATE) {
98    $IMAP_USE_INTERNAL_DATE = true;
99}
100
101/**
102 * @todo Maybe use date() to generate this.
103 */
104$GLOBALS['IMAP_MONTHS'] = array("Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4,
105    "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10,
106    "Nov" => 11, "Dec" => 12);
107
108$GLOBALS['IMAP_SERVER_TZ'] = date('Z');
109
110$GLOBALS['IMAP_FLAGS'] = array(
111    'SEEN'     => '\\Seen',
112    'DELETED'  => '\\Deleted',
113    'RECENT'   => '\\Recent',
114    'ANSWERED' => '\\Answered',
115    'DRAFT'    => '\\Draft',
116    'FLAGGED'  => '\\Flagged',
117    'FORWARDED' => '$Forwarded',
118    'MDNSENT'  => '$MDNSent',
119    '*'        => '\\*',
120);
121
122$iil_error;
123$iil_errornum;
124$iil_selected;
125
126/**
127 * @todo Change class vars to public/private
128 */
129class iilConnection
130{
131        var $fp;
132        var $error;
133        var $errorNum;
134        var $selected;
135        var $message;
136        var $host;
137        var $cache;
138        var $uid_cache;
139        var $do_cache;
140        var $exists;
141        var $recent;
142        var $rootdir;
143        var $delimiter;
144        var $capability = array();
145        var $permanentflags = array();
146        var $capability_readed = false;
147}
148
149/**
150 * @todo Change class vars to public/private
151 */
152class iilBasicHeader
153{
154        var $id;
155        var $uid;
156        var $subject;
157        var $from;
158        var $to;
159        var $cc;
160        var $replyto;
161        var $in_reply_to;
162        var $date;
163        var $messageID;
164        var $size;
165        var $encoding;
166        var $charset;
167        var $ctype;
168        var $flags;
169        var $timestamp;
170        var $f;
171        var $body_structure;
172        var $internaldate;
173        var $references;
174        var $priority;
175        var $mdn_to;
176        var $mdn_sent = false;
177        var $is_draft = false;
178        var $seen = false;
179        var $deleted = false;
180        var $recent = false;
181        var $answered = false;
182        var $forwarded = false;
183        var $junk = false;
184        var $flagged = false;
185        var $others = array();
186}
187
188/**
189 * @todo Change class vars to public/private
190 */
191class iilThreadHeader
192{
193        var $id;
194        var $sbj;
195        var $irt;
196        var $mid;
197}
198
199function iil_xor($string, $string2) {
200        $result = '';
201        $size = strlen($string);
202        for ($i=0; $i<$size; $i++) {
203                $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
204        }
205        return $result;
206}
207
208function iil_PutLine($fp, $string, $endln=true) {
209//      console('C: '. rtrim($string));
210        return fputs($fp, $string . ($endln ? "\r\n" : ''));
211}
212
213// iil_PutLine replacement with Command Continuation Requests (RFC3501 7.5) support
214function iil_PutLineC($fp, $string, $endln=true) {
215        if ($endln)
216                $string .= "\r\n";
217
218        $res = 0;
219        if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) {
220                for($i=0, $cnt=count($parts); $i<$cnt; $i++) {
221                        if(preg_match('/^\{[0-9]+\}\r\n$/', $parts[$i+1])) {
222                                $res += iil_PutLine($fp, $parts[$i].$parts[$i+1], false);
223                                $line = iil_ReadLine($fp, 1000);
224                                // handle error in command
225                                if ($line[0] != '+')
226                                        return false;
227                                $i++;
228                        }
229                        else
230                                $res += iil_PutLine($fp, $parts[$i], false);
231                }
232        }
233        return $res;
234}
235
236function iil_ReadLine($fp, $size) {
237        $line = '';
238
239        if (!$fp) {
240                return $line;
241        }
242   
243        if (!$size) {
244                $size = 1024;
245        }
246   
247        do {
248                $buffer = fgets($fp, $size);
249                if ($buffer === false) {
250                        break;
251                }
252//              console('S: '. chop($buffer));
253                $line .= $buffer;
254        } while ($buffer[strlen($buffer)-1] != "\n");
255       
256        return $line;
257}
258
259function iil_MultLine($fp, $line) {
260        $line = chop($line);
261        if (ereg('\{[0-9]+\}$', $line)) {
262                $out = '';
263       
264                preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a);
265                $bytes = $a[2][0];
266                while (strlen($out) < $bytes) {
267                        $line = iil_ReadBytes($fp, $bytes);
268                        $out .= $line;
269                }
270                $line = $a[1][0] . "\"$out\"";
271//              console('[...] '. $out);
272        }
273        return $line;
274}
275
276function iil_ReadBytes($fp, $bytes) {
277        $data = '';
278        $len  = 0;
279        do {
280                $data .= fread($fp, $bytes-$len);
281                if ($len == strlen($data)) {
282                        break; //nothing was read -> exit to avoid apache lockups
283                }
284                $len = strlen($data);
285        } while ($len < $bytes);
286       
287        return $data;
288}
289
290function iil_ReadReply($fp) {
291        do {
292                $line = trim(iil_ReadLine($fp, 1024));
293        } while ($line[0] == '*');
294       
295        return $line;
296}
297
298function iil_ParseResult($string) {
299        $a = explode(' ', $string);
300        if (count($a) > 2) {
301                if (strcasecmp($a[1], 'OK') == 0) {
302                        return 0;
303                } else if (strcasecmp($a[1], 'NO') == 0) {
304                        return -1;
305                } else if (strcasecmp($a[1], 'BAD') == 0) {
306                        return -2;
307                } else if (strcasecmp($a[1], 'BYE') == 0) {
308                        return -3;
309                }
310        }
311        return -4;
312}
313
314// check if $string starts with $match (or * BYE/BAD)
315function iil_StartsWith($string, $match, $error=false) {
316        $len = strlen($match);
317        if ($len == 0) {
318                return false;
319        }
320        if (strncmp($string, $match, $len) == 0) {
321                return true;
322        }
323        if ($error && preg_match('/^\* (BYE|BAD) /', $string)) {
324                return true;
325        }
326        return false;
327}
328
329function iil_StartsWithI($string, $match, $bye=false) {
330        $len = strlen($match);
331        if ($len == 0) {
332                return false;
333        }
334        if (strncasecmp($string, $match, $len) == 0) {
335                return true;
336        }
337        if ($bye && strncmp($string, '* BYE ', 6) == 0) {
338                return true;
339
340        }
341        return false;
342}
343
344function iil_Escape($string)
345{
346        return strtr($string, array('"'=>'\\"', '\\' => '\\\\'));
347}
348
349function iil_UnEscape($string)
350{
351        return strtr($string, array('\\"'=>'"', '\\\\' => '\\'));
352}
353
354function iil_C_GetCapability(&$conn, $name)
355{
356        if (in_array($name, $conn->capability)) {
357                return true;
358        }
359        else if ($conn->capability_readed) {
360                return false;
361        }
362
363        // get capabilities (only once) because initial
364        // optional CAPABILITY response may differ
365        $conn->capability = array();
366
367        iil_PutLine($conn->fp, "cp01 CAPABILITY");
368        do {
369                $line = trim(iil_ReadLine($conn->fp, 1024));
370                $a = explode(' ', $line);
371                if ($line[0] == '*') {
372                        while (list($k, $w) = each($a)) {
373                                if ($w != '*' && $w != 'CAPABILITY')
374                                        $conn->capability[] = strtoupper($w);
375                        }
376                }
377        } while ($a[0] != 'cp01');
378       
379        $conn->capability_readed = true;
380
381        if (in_array($name, $conn->capability)) {
382                return true;
383        }
384
385        return false;
386}
387
388function iil_C_ClearCapability(&$conn)
389{
390        $conn->capability = array();
391        $conn->capability_readed = false;
392}
393
394function iil_C_Authenticate(&$conn, $user, $pass, $encChallenge) {
395   
396    $ipad = '';
397    $opad = '';
398   
399    // initialize ipad, opad
400    for ($i=0;$i<64;$i++) {
401        $ipad .= chr(0x36);
402        $opad .= chr(0x5C);
403    }
404
405    // pad $pass so it's 64 bytes
406    $padLen = 64 - strlen($pass);
407    for ($i=0;$i<$padLen;$i++) {
408        $pass .= chr(0);
409    }
410   
411    // generate hash
412    $hash  = md5(iil_xor($pass,$opad) . pack("H*", md5(iil_xor($pass, $ipad) . base64_decode($encChallenge))));
413   
414    // generate reply
415    $reply = base64_encode($user . ' ' . $hash);
416   
417    // send result, get reply
418    iil_PutLine($conn->fp, $reply);
419    $line = iil_ReadLine($conn->fp, 1024);
420   
421    // process result
422    $result = iil_ParseResult($line);
423    if ($result == 0) {
424        $conn->error    .= '';
425        $conn->errorNum  = 0;
426        return $conn->fp;
427    }
428
429    if ($result == -3) fclose($conn->fp); // BYE response
430
431    $conn->error    .= 'Authentication for ' . $user . ' failed (AUTH): "';
432    $conn->error    .= htmlspecialchars($line) . '"';
433    $conn->errorNum  = $result;
434
435    return $result;
436}
437
438function iil_C_Login(&$conn, $user, $password) {
439
440    iil_PutLine($conn->fp, 'a001 LOGIN "'.iil_Escape($user).'" "'.iil_Escape($password).'"');
441
442    do {
443        $line = iil_ReadReply($conn->fp);
444        if ($line === false) {
445            break;
446        }
447    } while (!iil_StartsWith($line, 'a001 ', true));
448   
449    // process result
450    $result = iil_ParseResult($line);
451
452    if ($result == 0) {
453        $conn->error    .= '';
454        $conn->errorNum  = 0;
455        return $conn->fp;
456    }
457
458    fclose($conn->fp);
459   
460    $conn->error    .= 'Authentication for ' . $user . ' failed (LOGIN): "';
461    $conn->error    .= htmlspecialchars($line)."\"";
462    $conn->errorNum  = $result;
463
464    return $result;
465}
466
467function iil_ParseNamespace2($str, &$i, $len=0, $l) {
468        if (!$l) {
469            $str = str_replace('NIL', '()', $str);
470        }
471        if (!$len) {
472            $len = strlen($str);
473        }
474        $data      = array();
475        $in_quotes = false;
476        $elem      = 0;
477        for ($i;$i<$len;$i++) {
478                $c = (string)$str[$i];
479                if ($c == '(' && !$in_quotes) {
480                        $i++;
481                        $data[$elem] = iil_ParseNamespace2($str, $i, $len, $l++);
482                        $elem++;
483                } else if ($c == ')' && !$in_quotes) {
484                        return $data;
485                } else if ($c == '\\') {
486                        $i++;
487                        if ($in_quotes) {
488                                $data[$elem] .= $c.$str[$i];
489                        }
490                } else if ($c == '"') {
491                        $in_quotes = !$in_quotes;
492                        if (!$in_quotes) {
493                                $elem++;
494                        }
495                } else if ($in_quotes) {
496                        $data[$elem].=$c;
497                }
498        }
499        return $data;
500}
501
502function iil_C_NameSpace(&$conn) {
503        global $my_prefs;
504
505        if (isset($my_prefs['rootdir']) && is_string($my_prefs['rootdir'])) {
506                $conn->rootdir = $my_prefs['rootdir'];
507                return true;
508        }
509       
510        if (!iil_C_GetCapability($conn, 'NAMESPACE')) {
511            return false;
512        }
513   
514        iil_PutLine($conn->fp, "ns1 NAMESPACE");
515        do {
516                $line = iil_ReadLine($conn->fp, 1024);
517                if (iil_StartsWith($line, '* NAMESPACE')) {
518                        $i    = 0;
519                        $line = iil_UnEscape($line);
520                        $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
521                }
522        } while (!iil_StartsWith($line, 'ns1', true));
523       
524        if (!is_array($data)) {
525            return false;
526        }
527   
528        $user_space_data = $data[0];
529        if (!is_array($user_space_data)) {
530            return false;
531        }
532   
533        $first_userspace = $user_space_data[0];
534        if (count($first_userspace)!=2) {
535            return false;
536        }
537   
538        $conn->rootdir       = $first_userspace[0];
539        $conn->delimiter     = $first_userspace[1];
540        $my_prefs['rootdir'] = substr($conn->rootdir, 0, -1);
541        $my_prefs['delimiter'] = $conn->delimiter;
542       
543        return true;
544}
545
546function iil_Connect($host, $user, $password, $options=null) { 
547        global $iil_error, $iil_errornum;
548        global $ICL_SSL, $ICL_PORT;
549        global $IMAP_NO_CACHE;
550        global $my_prefs, $IMAP_USE_INTERNAL_DATE;
551       
552        $iil_error = '';
553        $iil_errornum = 0;
554
555        // set some imap options
556        if (is_array($options)) {
557                foreach($options as $optkey => $optval) {
558                        if ($optkey == 'imap') {
559                                $auth_method = $optval;
560                        } else if ($optkey == 'rootdir') {
561                                $my_prefs['rootdir'] = $optval;
562                        } else if ($optkey == 'delimiter') {
563                                $my_prefs['delimiter'] = $optval;
564                        }
565                }
566        }
567
568        if (empty($auth_method))
569                $auth_method = 'check';
570               
571        $message = "INITIAL: $auth_method\n";
572               
573        $result = false;
574       
575        // initialize connection
576        $conn              = new iilConnection;
577        $conn->error       = '';
578        $conn->errorNum    = 0;
579        $conn->selected    = '';
580        $conn->user        = $user;
581        $conn->host        = $host;
582        $conn->cache       = array();
583        $conn->do_cache    = (function_exists("cache_write")&&!$IMAP_NO_CACHE);
584        $conn->cache_dirty = array();
585       
586        if ($my_prefs['sort_field'] == 'INTERNALDATE') {
587                $IMAP_USE_INTERNAL_DATE = true;
588        } else if ($my_prefs['sort_field'] == 'DATE') {
589                $IMAP_USE_INTERNAL_DATE = false;
590        }
591        //echo '<!-- conn sort_field: '.$my_prefs['sort_field'].' //-->';
592       
593        //check input
594        if (empty($host)) {
595                $iil_error = "Empty host";
596                $iil_errornum = -1;
597                return false;
598        }
599        if (empty($user)) {
600                $iil_error = "Empty user";
601                $iil_errornum = -1;
602                return false;
603        }
604        if (empty($password)) {
605                $iil_error = "Empty password";
606                $iil_errornum = -1;
607                return false;
608        }
609
610        if (!$ICL_PORT) {
611                $ICL_PORT = 143;
612        }
613        //check for SSL
614        if ($ICL_SSL && $ICL_SSL != 'tls') {
615                $host = $ICL_SSL . '://' . $host;
616        }
617
618        $conn->fp = fsockopen($host, $ICL_PORT, $errno, $errstr, 10);
619        if (!$conn->fp) {
620                $iil_error = "Could not connect to $host at port $ICL_PORT: $errstr";
621                $iil_errornum = -2;
622                return false;
623        }
624
625        $iil_error .= "Socket connection established\r\n";
626        $line       = iil_ReadLine($conn->fp, 4096);
627
628        // RFC3501 [7.1] optional CAPABILITY response
629        if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
630                $conn->capability = explode(' ', strtoupper($matches[1]));
631        }
632
633        $conn->message .= $line;
634
635        // TLS connection
636        if ($ICL_SSL == 'tls' && iil_C_GetCapability($conn, 'STARTTLS')) {
637                if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
638                        iil_PutLine($conn->fp, 'stls000 STARTTLS');
639
640                        $line = iil_ReadLine($conn->fp, 4096);
641                        if (!iil_StartsWith($line, 'stls000 OK')) {
642                                $iil_error = "Server responded to STARTTLS with: $line";
643                                $iil_errornum = -2;
644                                return false;
645                        }
646
647                        if (!stream_socket_enable_crypto($conn->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
648                                $iil_error = "Unable to negotiate TLS";
649                                $iil_errornum = -2;
650                                return false;
651                        }
652                       
653                        // Now we're authenticated, capabilities need to be reread
654                        iil_C_ClearCapability($conn);
655                }
656        }
657
658        if (strcasecmp($auth_method, "check") == 0) {
659                //check for supported auth methods
660                if (iil_C_GetCapability($conn, 'AUTH=CRAM-MD5') || iil_C_GetCapability($conn, 'AUTH=CRAM_MD5')) {
661                        $auth_method = 'auth';
662                }
663                else {
664                        //default to plain text auth
665                        $auth_method = 'plain';
666                }
667        }
668
669        if (strcasecmp($auth_method, 'auth') == 0) {
670                $conn->message .= "Trying CRAM-MD5\n";
671
672                //do CRAM-MD5 authentication
673                iil_PutLine($conn->fp, "a000 AUTHENTICATE CRAM-MD5");
674                $line = trim(iil_ReadLine($conn->fp, 1024));
675
676                $conn->message .= "$line\n";
677
678                if ($line[0] == '+') {
679                        $conn->message .= 'Got challenge: ' . htmlspecialchars($line) . "\n";
680
681                        //got a challenge string, try CRAM-5
682                        $result = iil_C_Authenticate($conn, $user, $password, substr($line,2));
683                       
684                        // stop if server sent BYE response
685                        if($result == -3) {
686                                $iil_error = $conn->error;
687                                $iil_errornum = $conn->errorNum;
688                                return false;
689                        }
690                        $conn->message .= "Tried CRAM-MD5: $result \n";
691                } else {
692                        $conn->message .='No challenge ('.htmlspecialchars($line)."), try plain\n";
693                        $auth = 'plain';
694                }
695        }
696               
697        if ((!$result)||(strcasecmp($auth, "plain") == 0)) {
698                //do plain text auth
699                $result = iil_C_Login($conn, $user, $password);
700                $conn->message .= "Tried PLAIN: $result \n";
701        }
702               
703        $conn->message .= $auth;
704                       
705        if (!is_int($result)) {
706                iil_C_Namespace($conn);
707                return $conn;
708        } else {
709                $iil_error = $conn->error;
710                $iil_errornum = $conn->errorNum;
711                return false;
712        }
713}
714
715function iil_Close(&$conn) {
716        iil_C_WriteCache($conn);
717        if (iil_PutLine($conn->fp, "I LOGOUT")) {
718                fgets($conn->fp, 1024);
719                fclose($conn->fp);
720                $conn->fp = false;
721        }
722}
723
724function iil_ClearCache($user, $host) {
725}
726
727function iil_C_WriteCache(&$conn) {
728        //echo "<!-- doing iil_C_WriteCache //-->\n";
729        if (!$conn->do_cache) return false;
730       
731        if (is_array($conn->cache)) {
732                while (list($folder,$data)=each($conn->cache)) {
733                        if ($folder && is_array($data) && $conn->cache_dirty[$folder]) {
734                                $key = $folder.".imap";
735                                $result = cache_write($conn->user, $conn->host, $key, $data, true);
736                                //echo "<!-- writing $key $data: $result //-->\n";
737                        }
738                }
739        }
740}
741
742function iil_C_EnableCache(&$conn) {
743        $conn->do_cache = true;
744}
745
746function iil_C_DisableCache(&$conn) {
747        $conn->do_cache = false;
748}
749
750function iil_C_LoadCache(&$conn, $folder) {
751        if (!$conn->do_cache) {
752            return false;
753        }
754   
755        $key = $folder.'.imap';
756        if (!is_array($conn->cache[$folder])) {
757                $conn->cache[$folder]       = cache_read($conn->user, $conn->host, $key);
758                $conn->cache_dirty[$folder] = false;
759        }
760}
761
762function iil_C_ExpireCachedItems(&$conn, $folder, $message_set) {
763       
764        if (!$conn->do_cache) {
765                return; //caching disabled
766        }
767        if (!is_array($conn->cache[$folder])) {
768                return; //cache not initialized|empty
769        }
770        if (count($conn->cache[$folder]) == 0) {
771                return; //cache not initialized|empty
772        }
773   
774        $uids = iil_C_FetchHeaderIndex($conn, $folder, $message_set, 'UID');
775        $num_removed = 0;
776        if (is_array($uids)) {
777                //echo "<!-- unsetting: ".implode(",",$uids)." //-->\n";
778                while (list($n,$uid)=each($uids)) {
779                        unset($conn->cache[$folder][$uid]);
780                        //$conn->cache[$folder][$uid] = false;
781                        //$num_removed++;
782                }
783                $conn->cache_dirty[$folder] = true;
784
785                //echo '<!--'."\n";
786                //print_r($conn->cache);
787                //echo "\n".'//-->'."\n";
788        } else {
789                echo "<!-- failed to get uids: $message_set //-->\n";
790        }
791       
792        /*
793        if ($num_removed>0) {
794                $new_cache;
795                reset($conn->cache[$folder]);
796                while (list($uid,$item)=each($conn->cache[$folder])) {
797                        if ($item) $new_cache[$uid] = $conn->cache[$folder][$uid];
798                }
799                $conn->cache[$folder] = $new_cache;
800        }
801        */
802}
803
804function iil_ExplodeQuotedString($delimiter, $string) {
805        $quotes = explode('"', $string);
806        while ( list($key, $val) = each($quotes)) {
807                if (($key % 2) == 1) {
808                        $quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
809                }
810        }
811        $string = implode('"', $quotes);
812       
813        $result = explode($delimiter, $string);
814        while ( list($key, $val) = each($result) ) {
815                $result[$key] = str_replace('_!@!_', $delimiter, $result[$key]);
816        }
817   
818        return $result;
819}
820
821function iil_CheckForRecent($host, $user, $password, $mailbox) {
822        if (empty($mailbox)) {
823                $mailbox = 'INBOX';
824        }
825   
826        $conn = iil_Connect($host, $user, $password, 'plain');
827        $fp   = $conn->fp;
828        if ($fp) {
829                iil_PutLine($fp, "a002 EXAMINE \"".iil_Escape($mailbox)."\"");
830                do {
831                        $line=chop(iil_ReadLine($fp, 300));
832                        $a=explode(' ', $line);
833                        if (($a[0] == '*') && (strcasecmp($a[2], 'RECENT') == 0)) {
834                            $result = (int) $a[1];
835                        }
836                } while (!iil_StartsWith($a[0], 'a002', true));
837
838                iil_PutLine($fp, "a003 LOGOUT");
839                fclose($fp);
840        } else {
841            $result = -2;
842        }
843   
844        return $result;
845}
846
847function iil_C_Select(&$conn, $mailbox) {
848
849        if (empty($mailbox)) {
850                return false;
851        }
852        if (strcmp($conn->selected, $mailbox) == 0) {
853                return true;
854        }
855   
856        iil_C_LoadCache($conn, $mailbox);
857       
858        if (iil_PutLine($conn->fp, "sel1 SELECT \"".iil_Escape($mailbox).'"')) {
859                do {
860                        $line = chop(iil_ReadLine($conn->fp, 300));
861                        $a = explode(' ', $line);
862                        if (count($a) == 3) {
863                                if (strcasecmp($a[2], 'EXISTS') == 0) {
864                                        $conn->exists = (int) $a[1];
865                                }
866                                if (strcasecmp($a[2], 'RECENT') == 0) {
867                                        $conn->recent = (int) $a[1];
868                                }
869                        }
870                        else if (preg_match('/\[?PERMANENTFLAGS\s+\(([^\)]+)\)\]/U', $line, $match)) {
871                                $conn->permanentflags = explode(' ', $match[1]);
872                        }
873                } while (!iil_StartsWith($line, 'sel1', true));
874
875                $a = explode(' ', $line);
876
877                if (strcasecmp($a[1], 'OK') == 0) {
878                        $conn->selected = $mailbox;
879                        return true;
880                }
881        }
882        return false;
883}
884
885function iil_C_CheckForRecent(&$conn, $mailbox) {
886        if (empty($mailbox)) {
887                $mailbox = 'INBOX';
888        }
889   
890        iil_C_Select($conn, $mailbox);
891        if ($conn->selected == $mailbox) {
892                return $conn->recent;
893        }
894        return false;
895}
896
897function iil_C_CountMessages(&$conn, $mailbox, $refresh = false) {
898        if ($refresh) {
899                $conn->selected = '';
900        }
901       
902        iil_C_Select($conn, $mailbox);
903        if ($conn->selected == $mailbox) {
904                return $conn->exists;
905        }
906        return false;
907}
908
909function iil_SplitHeaderLine($string) {
910        $pos=strpos($string, ':');
911        if ($pos>0) {
912                $res[0] = substr($string, 0, $pos);
913                $res[1] = trim(substr($string, $pos+1));
914                return $res;
915        }
916        return $string;
917}
918
919function iil_StrToTime($str) {
920        $IMAP_MONTHS    = $GLOBALS['IMAP_MONTHS'];
921        $IMAP_SERVER_TZ = $GLOBALS['IMAP_SERVER_TZ'];
922               
923        if ($str) {
924            $time1 = strtotime($str);
925        }
926        if ($time1 && $time1 != -1) {
927            return $time1-$IMAP_SERVER_TZ;
928        }
929        //echo '<!--'.$str.'//-->';
930       
931        //replace double spaces with single space
932        $str = trim($str);
933        $str = str_replace('  ', ' ', $str);
934       
935        //strip off day of week
936        $pos = strpos($str, ' ');
937        if (!is_numeric(substr($str, 0, $pos))) {
938            $str = substr($str, $pos+1);
939        }
940        //explode, take good parts
941        $a = explode(' ', $str);
942
943        $month_str = $a[1];
944        $month     = $IMAP_MONTHS[$month_str];
945        $day       = (int)$a[0];
946        $year      = (int)$a[2];
947        $time      = $a[3];
948        $tz_str    = $a[4];
949        $tz        = substr($tz_str, 0, 3);
950        $ta        = explode(':', $time);
951        $hour      = (int)$ta[0]-(int)$tz;
952        $minute    = (int)$ta[1];
953        $second    = (int)$ta[2];
954       
955        //make UNIX timestamp
956        $time2 = mktime($hour, $minute, $second, $month, $day, $year);
957        //echo '<!--'.$time1.' '.$time2.' //-->'."\n";
958        return $time2;
959}
960
961function iil_C_Sort(&$conn, $mailbox, $field, $add='', $is_uid=FALSE,
962    $encoding = 'US-ASCII') {
963
964        $field = strtoupper($field);
965        if ($field == 'INTERNALDATE') {
966            $field = 'ARRIVAL';
967        }
968       
969        $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1,
970        'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1);
971       
972        if (!$fields[$field]) {
973            return false;
974        }
975
976        /*  Do "SELECT" command */
977        if (!iil_C_Select($conn, $mailbox)) {
978            return false;
979        }
980   
981        $is_uid = $is_uid ? 'UID ' : '';
982       
983        if (!empty($add)) {
984            $add = " $add";
985        }
986
987        $command  = 's ' . $is_uid . 'SORT (' . $field . ') ';
988        $command .= $encoding . ' ALL' . $add;
989        $line     = $data = '';
990       
991        if (!iil_PutLineC($conn->fp, $command)) {
992            return false;
993        }
994        do {
995                $line = chop(iil_ReadLine($conn->fp, 1024));
996                if (iil_StartsWith($line, '* SORT')) {
997                        $data .= ($data ? ' ' : '') . substr($line, 7);
998                } else if (preg_match('/^[0-9 ]+$/', $line)) {
999                        $data .= $line;
1000                }
1001        } while (!iil_StartsWith($line, 's ', true));
1002       
1003        $result_code = iil_ParseResult($line);
1004       
1005        if ($result_code != 0) {
1006                $conn->error = 'iil_C_Sort: ' . $line . "\n";
1007                return false;
1008        }
1009       
1010        $out = explode(' ',$data);
1011        return $out;
1012}
1013
1014function iil_C_FetchHeaderIndex(&$conn, $mailbox, $message_set, $index_field,
1015    $normalize=true) {
1016        global $IMAP_USE_INTERNAL_DATE;
1017       
1018        $c=0;
1019        $result=array();
1020        $fp = $conn->fp;
1021               
1022        if (empty($index_field)) {
1023            $index_field = 'DATE';
1024        }
1025        $index_field = strtoupper($index_field);
1026       
1027        list($from_idx, $to_idx) = explode(':', $message_set);
1028        if (empty($message_set) || (isset($to_idx)
1029            && (int)$from_idx > (int)$to_idx)) {
1030                return false;
1031        }
1032       
1033        //$fields_a['DATE'] = ($IMAP_USE_INTERNAL_DATE?6:1);
1034        $fields_a['DATE']         = 1;
1035        $fields_a['INTERNALDATE'] = 6;
1036        $fields_a['FROM']         = 1;
1037        $fields_a['REPLY-TO']     = 1;
1038        $fields_a['SENDER']       = 1;
1039        $fields_a['TO']           = 1;
1040        $fields_a['SUBJECT']      = 1;
1041        $fields_a['UID']          = 2;
1042        $fields_a['SIZE']         = 2;
1043        $fields_a['SEEN']         = 3;
1044        $fields_a['RECENT']       = 4;
1045        $fields_a['DELETED']      = 5;
1046       
1047        $mode=$fields_a[$index_field];
1048        if (!($mode > 0)) {
1049            return false;
1050        }
1051   
1052        /*  Do "SELECT" command */
1053        if (!iil_C_Select($conn, $mailbox)) {
1054            return false;
1055        }
1056   
1057        /* FETCH date,from,subject headers */
1058        if ($mode == 1) {
1059                $key     = 'fhi' . ($c++);
1060                $request = $key . " FETCH $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)])";
1061                if (!iil_PutLine($fp, $request)) {
1062                    return false;
1063                }
1064                do {
1065                       
1066                        $line=chop(iil_ReadLine($fp, 200));
1067                        $a=explode(' ', $line);
1068                        if (($line[0] == '*') && ($a[2] == 'FETCH')
1069                            && ($line[strlen($line)-1] != ')')) {
1070                                $id=$a[1];
1071
1072                                $str=$line=chop(iil_ReadLine($fp, 300));
1073
1074                                while ($line[0] != ')') {                                       //caution, this line works only in this particular case
1075                                        $line=chop(iil_ReadLine($fp, 300));
1076                                        if ($line[0] != ')') {
1077                                                if (ord($line[0]) <= 32) {                      //continuation from previous header line
1078                                                        $str.= ' ' . trim($line);
1079                                                }
1080                                                if ((ord($line[0]) > 32) || (strlen($line[0]) == 0)) {
1081                                                        list($field, $string) = iil_SplitHeaderLine($str);
1082                                                        if (strcasecmp($field, 'date') == 0) {
1083                                                                $result[$id] = iil_StrToTime($string);
1084                                                        } else {
1085                                                                $result[$id] = str_replace('"', '', $string);
1086                                                                if ($normalize) {
1087                                                                    $result[$id] = strtoupper($result[$id]);
1088                                                                }
1089                                                        }
1090                                                        $str=$line;
1091                                                }
1092                                        }
1093                                }
1094                        }
1095                        /*
1096                        $end_pos = strlen($line)-1;
1097                        if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[$end_pos]=="}")) {
1098                                $id = $a[1];
1099                                $pos = strrpos($line, "{")+1;
1100                                $bytes = (int)substr($line, $pos, $end_pos-$pos);
1101                                $received = 0;
1102                                do {
1103                                        $line      = iil_ReadLine($fp, 0);
1104                                        $received += strlen($line);
1105                                        $line      = chop($line);
1106                                       
1107                                        if ($received>$bytes) {
1108                                                break;
1109                                        } else if (!$line) {
1110                                                continue;
1111                                        }
1112
1113                                        list($field, $string) = explode(': ', $line);
1114                                       
1115                                        if (strcasecmp($field, 'date') == 0) {
1116                                                $result[$id] = iil_StrToTime($string);
1117                                        } else if ($index_field != 'DATE') {
1118                                                $result[$id]=strtoupper(str_replace('"', '', $string));
1119                                        }
1120                                } while ($line[0] != ')');
1121                        } else {
1122                                //one line response, not expected so ignore                             
1123                        }
1124                        */
1125                } while (!iil_StartsWith($line, $key, true));
1126
1127        }else if ($mode == 6) {
1128
1129                $key     = 'fhi' . ($c++);
1130                $request = $key . " FETCH $message_set (INTERNALDATE)";
1131                if (!iil_PutLine($fp, $request)) {
1132                    return false;
1133                }
1134                do {
1135                        $line=chop(iil_ReadLine($fp, 200));
1136                        if ($line[0] == '*') {
1137                                /*
1138                                 * original:
1139                                 * "* 10 FETCH (INTERNALDATE "31-Jul-2002 09:18:02 -0500")"
1140                                 */
1141                                $paren_pos = strpos($line, '(');
1142                                $foo       = substr($line, 0, $paren_pos);
1143                                $a         = explode(' ', $foo);
1144                                $id        = $a[1];
1145                               
1146                                $open_pos  = strpos($line, '"') + 1;
1147                                $close_pos = strrpos($line, '"');
1148                                if ($open_pos && $close_pos) {
1149                                        $len         = $close_pos - $open_pos;
1150                                        $time_str    = substr($line, $open_pos, $len);
1151                                        $result[$id] = strtotime($time_str);
1152                                }
1153                        } else {
1154                                $a = explode(' ', $line);
1155                        }
1156                } while (!iil_StartsWith($a[0], $key, true));
1157        } else {
1158                if ($mode >= 3) {
1159                    $field_name = 'FLAGS';
1160                } else if ($index_field == 'SIZE') {
1161                    $field_name = 'RFC822.SIZE';
1162                } else {
1163                    $field_name = $index_field;
1164                }
1165       
1166                /*                      FETCH uid, size, flags          */
1167                $key     = 'fhi' .($c++);
1168                $request = $key . " FETCH $message_set ($field_name)";
1169
1170                if (!iil_PutLine($fp, $request)) {
1171                    return false;
1172                }
1173                do {
1174                        $line=chop(iil_ReadLine($fp, 200));
1175                        $a = explode(' ', $line);
1176                        if (($line[0] == '*') && ($a[2] == 'FETCH')) {
1177                                $line = str_replace('(', '', $line);
1178                                $line = str_replace(')', '', $line);
1179                                $a    = explode(' ', $line);
1180                               
1181                                $id = $a[1];
1182
1183                                if (isset($result[$id])) {
1184                                    continue; //if we already got the data, skip forward
1185                                }
1186                                if ($a[3]!=$field_name) {
1187                                        continue;  //make sure it's returning what we requested
1188                                }
1189               
1190                                /*  Caution, bad assumptions, next several lines */
1191                                if ($mode == 2) {
1192                                    $result[$id] = $a[4];
1193                                } else {
1194                                        $haystack    = strtoupper($line);
1195                                        $result[$id] = (strpos($haystack, $index_field) > 0 ? "F" : "N");
1196                                }
1197                        }
1198                } while (!iil_StartsWith($line, $key, true));
1199        }
1200
1201        //check number of elements...
1202        list($start_mid, $end_mid) = explode(':', $message_set);
1203        if (is_numeric($start_mid) && is_numeric($end_mid)) {
1204                //count how many we should have
1205                $should_have = $end_mid - $start_mid +1;
1206               
1207                //if we have less, try and fill in the "gaps"
1208                if (count($result) < $should_have) {
1209                        for ($i=$start_mid; $i<=$end_mid; $i++) {
1210                                if (!isset($result[$i])) {
1211                                        $result[$i] = '';
1212                                }
1213                        }
1214                }
1215        }
1216        return $result;
1217}
1218
1219function iil_CompressMessageSet($message_set) {
1220        //given a comma delimited list of independent mid's,
1221        //compresses by grouping sequences together
1222       
1223        //if less than 255 bytes long, let's not bother
1224        if (strlen($message_set)<255) {
1225            return $message_set;
1226        }
1227   
1228        //see if it's already been compress
1229        if (strpos($message_set, ':') !== false) {
1230            return $message_set;
1231        }
1232   
1233        //separate, then sort
1234        $ids = explode(',', $message_set);
1235        sort($ids);
1236       
1237        $result = array();
1238        $start  = $prev = $ids[0];
1239
1240        foreach ($ids as $id) {
1241                $incr = $id - $prev;
1242                if ($incr > 1) {                        //found a gap
1243                        if ($start == $prev) {
1244                            $result[] = $prev;  //push single id
1245                        } else {
1246                            $result[] = $start . ':' . $prev;   //push sequence as start_id:end_id
1247                        }
1248                        $start = $id;                   //start of new sequence
1249                }
1250                $prev = $id;
1251        }
1252
1253        //handle the last sequence/id
1254        if ($start==$prev) {
1255            $result[] = $prev;
1256        } else {
1257            $result[] = $start.':'.$prev;
1258        }
1259   
1260        //return as comma separated string
1261        return implode(',', $result);
1262}
1263
1264function iil_C_UIDsToMIDs(&$conn, $mailbox, $uids) {
1265        if (!is_array($uids) || count($uids) == 0) {
1266            return array();
1267        }
1268        return iil_C_Search($conn, $mailbox, 'UID ' . implode(',', $uids));
1269}
1270
1271function iil_C_UIDToMID(&$conn, $mailbox, $uid) {
1272        $result = iil_C_UIDsToMIDs($conn, $mailbox, array($uid));
1273        if (count($result) == 1) {
1274            return $result[0];
1275        }
1276        return false;
1277}
1278
1279function iil_C_FetchUIDs(&$conn,$mailbox) {
1280        global $clock;
1281       
1282        $num = iil_C_CountMessages($conn, $mailbox);
1283        if ($num == 0) {
1284            return array();
1285        }
1286        $message_set = '1' . ($num>1?':' . $num:'');
1287       
1288        //if cache not enabled, just call iil_C_FetchHeaderIndex on 'UID' field
1289        if (!$conn->do_cache)
1290                return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
1291
1292        //otherwise, let's check cache first
1293        $key        = $mailbox.'.uids';
1294        $cache_good = true;
1295        if ($conn->uid_cache) {
1296            $data = $conn->uid_cache;
1297        } else {
1298            $data = cache_read($conn->user, $conn->host, $key);
1299        }
1300   
1301        //was anything cached at all?
1302        if ($data === false) {
1303            $cache_good = -1;
1304        }
1305   
1306        //make sure number of messages were the same
1307        if ($cache_good > 0 && $data['n'] != $num) {
1308            $cache_good = -2;
1309        }
1310   
1311        //if everything's okay so far...
1312        if ($cache_good > 0) {
1313                //check UIDs of highest mid with current and cached
1314                $temp = iil_C_Search($conn, $mailbox, 'UID ' . $data['d'][$num]);
1315                if (!$temp || !is_array($temp) || $temp[0] != $num) {
1316                    $cache_good = -3;
1317                }
1318        }
1319
1320        //if cached data's good, return it
1321        if ($cache_good > 0) {
1322                return $data['d'];
1323        }
1324
1325        //otherwise, we need to fetch it
1326        $data      = array('n' => $num, 'd' => array());
1327        $data['d'] = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
1328   
1329        cache_write($conn->user, $conn->host, $key, $data);
1330        $conn->uid_cache = $data;
1331        return $data['d'];
1332}
1333
1334function iil_SortThreadHeaders($headers, $index_a, $uids) {
1335        asort($index_a);
1336        $result = array();
1337        foreach ($index_a as $mid=>$foobar) {
1338                $uid = $uids[$mid];
1339                $result[$uid] = $headers[$uid];
1340        }
1341        return $result;
1342}
1343
1344function iil_C_FetchThreadHeaders(&$conn, $mailbox, $message_set) {
1345        global $clock;
1346        global $index_a;
1347       
1348        list($from_idx, $to_idx) = explode(':', $message_set);
1349        if (empty($message_set) || (isset($to_idx)
1350        && (int)$from_idx > (int)$to_idx)) {
1351                return false;
1352        }
1353
1354        $result = array();
1355        $uids   = iil_C_FetchUIDs($conn, $mailbox);
1356        $debug  = false;
1357       
1358        /* Get cached records where possible */
1359        if ($conn->do_cache) {
1360                $cached = cache_read($conn->user, $conn->host, $mailbox.'.thhd');
1361                if ($cached && is_array($uids) && count($uids)>0) {
1362                        $needed_set = '';
1363                        foreach ($uids as $id=>$uid) {
1364                                if ($cached[$uid]) {
1365                                        $result[$uid]     = $cached[$uid];
1366                                        $result[$uid]->id = $id;
1367                                } else {
1368                                    $needed_set .= ($needed_set ? ',' : '') . $id;
1369                                }
1370                        }
1371                        if ($needed_set) {
1372                            $message_set = $needed_set;
1373                        } else {
1374                            $message_set = '';
1375                        }
1376                }
1377        }
1378        $message_set = iil_CompressMessageSet($message_set);
1379        if ($debug) {
1380            echo "Still need: ".$message_set;
1381        }
1382   
1383        /* if we're missing any, get them */
1384        if ($message_set) {
1385                /* FETCH date,from,subject headers */
1386                $key        = 'fh';
1387                $fp         = $conn->fp;
1388                $request    = $key . " FETCH $message_set ";
1389                $request   .= "(BODY.PEEK[HEADER.FIELDS (SUBJECT MESSAGE-ID IN-REPLY-TO)])";
1390                $mid_to_id  = array();
1391                if (!iil_PutLine($fp, $request)) {
1392                    return false;
1393                }
1394                do {
1395                        $line = chop(iil_ReadLine($fp, 1024));
1396                        if ($debug) {
1397                            echo $line . "\n";
1398                        }
1399                        if (ereg('\{[0-9]+\}$', $line)) {
1400                                $a       = explode(' ', $line);
1401                                $new = array();
1402
1403                                $new_thhd = new iilThreadHeader;
1404                                $new_thhd->id = $a[1];
1405                                do {
1406                                        $line = chop(iil_ReadLine($fp, 1024), "\r\n");
1407                                        if (iil_StartsWithI($line, 'Message-ID:')
1408                                                || (iil_StartsWithI($line,'In-Reply-To:'))
1409                                                || (iil_StartsWithI($line,'SUBJECT:'))) {
1410
1411                                                $pos        = strpos($line, ':');
1412                                                $field_name = substr($line, 0, $pos);
1413                                                $field_val  = substr($line, $pos+1);
1414
1415                                                $new[strtoupper($field_name)] = trim($field_val);
1416
1417                                        } else if (ereg('^[[:space:]]', $line)) {
1418                                                $new[strtoupper($field_name)] .= trim($line);
1419                                        }
1420                                } while ($line[0] != ')');
1421               
1422                                $new_thhd->sbj = $new['SUBJECT'];
1423                                $new_thhd->mid = substr($new['MESSAGE-ID'], 1, -1);
1424                                $new_thhd->irt = substr($new['IN-REPLY-TO'], 1, -1);
1425                               
1426                                $result[$uids[$new_thhd->id]] = $new_thhd;
1427                        }
1428                } while (!iil_StartsWith($line, 'fh'));
1429        }
1430       
1431        /* sort headers */
1432        if (is_array($index_a)) {
1433                $result = iil_SortThreadHeaders($result, $index_a, $uids);     
1434        }
1435       
1436        /* write new set to cache */
1437        if ($conn->do_cache) {
1438                if (count($result)!=count($cached)) {
1439                        cache_write($conn->user, $conn->host, $mailbox . '.thhd', $result);
1440                }
1441        }
1442       
1443        //echo 'iil_FetchThreadHeaders:'."\n";
1444        //print_r($result);
1445       
1446        return $result;
1447}
1448
1449function iil_C_BuildThreads2(&$conn, $mailbox, $message_set, &$clock) {
1450        global $index_a;
1451
1452        list($from_idx, $to_idx) = explode(':', $message_set);
1453        if (empty($message_set) || (isset($to_idx)
1454                && (int)$from_idx > (int)$to_idx)) {
1455                return false;
1456        }
1457   
1458        $result    = array();
1459        $roots     = array();
1460        $root_mids = array();
1461        $sub_mids  = array();
1462        $strays    = array();
1463        $messages  = array();
1464        $fp        = $conn->fp;
1465        $debug     = false;
1466       
1467        $sbj_filter_pat = '[a-zA-Z]{2,3}(\[[0-9]*\])?:([[:space:]]*)';
1468       
1469        /*  Do "SELECT" command */
1470        if (!iil_C_Select($conn, $mailbox)) {
1471            return false;
1472        }
1473   
1474        /* FETCH date,from,subject headers */
1475        $mid_to_id = array();
1476        $messages  = array();
1477        $headers   = iil_C_FetchThreadHeaders($conn, $mailbox, $message_set);
1478        if ($clock) {
1479            $clock->register('fetched headers');
1480        }
1481   
1482        if ($debug) {
1483            print_r($headers);
1484        }
1485   
1486        /* go through header records */
1487        foreach ($headers as $header) {
1488                //$id = $header['i'];
1489                //$new = array('id'=>$id, 'MESSAGE-ID'=>$header['m'],
1490                //                      'IN-REPLY-TO'=>$header['r'], 'SUBJECT'=>$header['s']);
1491                $id  = $header->id;
1492                $new = array('id' => $id, 'MESSAGE-ID' => $header->mid,
1493                        'IN-REPLY-TO' => $header->irt, 'SUBJECT' => $header->sbj);
1494
1495                /* add to message-id -> mid lookup table */
1496                $mid_to_id[$new['MESSAGE-ID']] = $id;
1497               
1498                /* if no subject, use message-id */
1499                if (empty($new['SUBJECT'])) {
1500                    $new['SUBJECT'] = $new['MESSAGE-ID'];
1501                }
1502       
1503                /* if subject contains 'RE:' or has in-reply-to header, it's a reply */
1504                $sbj_pre ='';
1505                $has_re = false;
1506                if (eregi($sbj_filter_pat, $new['SUBJECT'])) {
1507                    $has_re = true;
1508                }
1509                if ($has_re||$new['IN-REPLY-TO']) {
1510                    $sbj_pre = 'RE:';
1511                }
1512       
1513                /* strip out 're:', 'fw:' etc */
1514                if ($has_re) {
1515                    $sbj = ereg_replace($sbj_filter_pat, '', $new['SUBJECT']);
1516                } else {
1517                    $sbj = $new['SUBJECT'];
1518                }
1519                $new['SUBJECT'] = $sbj_pre.$sbj;
1520               
1521               
1522                /* if subject not a known thread-root, add to list */
1523                if ($debug) {
1524                    echo $id . ' ' . $new['SUBJECT'] . "\t" . $new['MESSAGE-ID'] . "\n";
1525                }
1526                $root_id = $roots[$sbj];
1527               
1528                if ($root_id && ($has_re || !$root_in_root[$root_id])) {
1529                        if ($debug) {
1530                            echo "\tfound root: $root_id\n";
1531                        }
1532                        $sub_mids[$new['MESSAGE-ID']] = $root_id;
1533                        $result[$root_id][]           = $id;
1534                } else if (!isset($roots[$sbj]) || (!$has_re && $root_in_root[$root_id])) {
1535                        /* try to use In-Reply-To header to find root
1536                                unless subject contains 'Re:' */
1537                        if ($has_re&&$new['IN-REPLY-TO']) {
1538                                if ($debug) {
1539                                    echo "\tlooking: ".$new['IN-REPLY-TO']."\n";
1540                                }
1541                                //reply to known message?
1542                                $temp = $sub_mids[$new['IN-REPLY-TO']];
1543                               
1544                                if ($temp) {
1545                                        //found it, root:=parent's root
1546                                        if ($debug) {
1547                                            echo "\tfound parent: ".$new['SUBJECT']."\n";
1548                                        }
1549                                        $result[$temp][]              = $id;
1550                                        $sub_mids[$new['MESSAGE-ID']] = $temp;
1551                                        $sbj                          = '';
1552                                } else {
1553                                        //if we can't find referenced parent, it's a "stray"
1554                                        $strays[$id] = $new['IN-REPLY-TO'];
1555                                }
1556                        }
1557                       
1558                        //add subject as root
1559                        if ($sbj) {
1560                                if ($debug) {
1561                                    echo "\t added to root\n";
1562                                }
1563                                $roots[$sbj]                  = $id;
1564                                $root_in_root[$id]            = !$has_re;
1565                                $sub_mids[$new['MESSAGE-ID']] = $id;
1566                                $result[$id]                  = array($id);
1567                        }
1568                        if ($debug) {
1569                            echo $new['MESSAGE-ID'] . "\t" . $sbj . "\n";
1570                        }
1571                }
1572        }
1573       
1574        //now that we've gone through all the messages,
1575        //go back and try and link up the stray threads
1576        if (count($strays) > 0) {
1577                foreach ($strays as $id=>$irt) {
1578                        $root_id = $sub_mids[$irt];
1579                        if (!$root_id || $root_id==$id) {
1580                            continue;
1581                        }
1582                        $result[$root_id] = array_merge($result[$root_id],$result[$id]);
1583                        unset($result[$id]);
1584                }
1585        }
1586       
1587        if ($clock) {
1588            $clock->register('data prepped');
1589        }
1590   
1591        if ($debug) {
1592            print_r($roots);
1593        }
1594
1595        return $result;
1596}
1597
1598function iil_SortThreads(&$tree, $index, $sort_order = 'ASC') {
1599        if (!is_array($tree) || !is_array($index)) {
1600            return false;
1601        }
1602   
1603        //create an id to position lookup table
1604        $i = 0;
1605        foreach ($index as $id=>$val) {
1606                $i++;
1607                $index[$id] = $i;
1608        }
1609        $max = $i+1;
1610       
1611        //for each tree, set array key to position
1612        $itree = array();
1613        foreach ($tree as $id=>$node) {
1614                if (count($tree[$id])<=1) {
1615                        //for "threads" with only one message, key is position of that message
1616                        $n         = $index[$id];
1617                        $itree[$n] = array($n=>$id);
1618                } else {
1619                        //for "threads" with multiple messages,
1620                        $min   = $max;
1621                        $new_a = array();
1622                        foreach ($tree[$id] as $mid) {
1623                                $new_a[$index[$mid]] = $mid;            //create new sub-array mapping position to id
1624                                $pos                 = $index[$mid];
1625                                if ($pos&&$pos<$min) {
1626                                    $min = $index[$mid];        //find smallest position
1627                                }
1628                        }
1629                        $n = $min;      //smallest position of child is thread position
1630                       
1631                        //assign smallest position to root level key
1632                        //set children array to one created above
1633                        ksort($new_a);
1634                        $itree[$n] = $new_a;
1635                }
1636        }
1637       
1638        //sort by key, this basically sorts all threads
1639        ksort($itree);
1640        $i   = 0;
1641        $out = array();
1642        foreach ($itree as $k=>$node) {
1643                $out[$i] = $itree[$k];
1644                $i++;
1645        }
1646       
1647        return $out;
1648}
1649
1650function iil_IndexThreads(&$tree) {
1651        /* creates array mapping mid to thread id */
1652       
1653        if (!is_array($tree)) {
1654            return false;
1655        }
1656   
1657        $t_index = array();
1658        foreach ($tree as $pos=>$kids) {
1659                foreach ($kids as $kid) $t_index[$kid] = $pos;
1660        }
1661       
1662        return $t_index;
1663}
1664
1665function iil_C_FetchHeaders(&$conn, $mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='')
1666{
1667        global $IMAP_USE_INTERNAL_DATE;
1668       
1669        $result = array();
1670        $fp     = $conn->fp;
1671       
1672        list($from_idx, $to_idx) = explode(':', $message_set);
1673        if (empty($message_set) || (isset($to_idx)
1674                && (int)$from_idx > (int)$to_idx)) {
1675                return false;
1676        }
1677               
1678        /*  Do "SELECT" command */
1679        if (!iil_C_Select($conn, $mailbox)) {
1680                $conn->error = "Couldn't select $mailbox";
1681                return false;
1682        }
1683               
1684        /* Get cached records where possible */
1685        if ($conn->do_cache) {
1686                $uids = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, "UID");
1687                if (is_array($uids) && count($conn->cache[$mailbox]>0)) {
1688                        $needed_set = '';
1689                        while (list($id,$uid)=each($uids)) {
1690                                if ($conn->cache[$mailbox][$uid]) {
1691                                        $result[$id]     = $conn->cache[$mailbox][$uid];
1692                                        $result[$id]->id = $id;
1693                                } else {
1694                                    $needed_set.=($needed_set ? ',': '') . $id;
1695                                }
1696                        }
1697                        //echo "<!-- iil_C_FetchHeader\nMessage Set: $message_set\nNeeded Set:$needed_set\n//-->\n";
1698                        if ($needed_set) {
1699                                $message_set = iil_CompressMessageSet($needed_set);
1700                        } else {
1701                                return $result;
1702                        }
1703                }
1704        }
1705       
1706        if ($add)
1707          $add = ' '.strtoupper(trim($add));
1708
1709        /* FETCH uid, size, flags and headers */
1710        $key      = 'FH12';
1711        $request  = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set ";
1712        $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE ";
1713        if ($bodystr)
1714                $request .= "BODYSTRUCTURE ";
1715        $request .= "BODY.PEEK[HEADER.FIELDS ";
1716        $request .= "(DATE FROM TO SUBJECT REPLY-TO IN-REPLY-TO CC BCC ";
1717        $request .= "CONTENT-TRANSFER-ENCODING CONTENT-TYPE MESSAGE-ID ";
1718        $request .= "REFERENCES DISPOSITION-NOTIFICATION-TO X-PRIORITY".$add.")])";
1719
1720        if (!iil_PutLine($fp, $request)) {
1721                return false;
1722        }
1723        do {
1724                $line = iil_ReadLine($fp, 1024);
1725                $line = iil_MultLine($fp, $line);
1726
1727                $a    = explode(' ', $line);
1728                if (($line[0] == '*') && ($a[2] == 'FETCH')) {
1729                        $id = $a[1];
1730           
1731                        $result[$id]            = new iilBasicHeader;
1732                        $result[$id]->id        = $id;
1733                        $result[$id]->subject   = '';
1734                        $result[$id]->messageID = 'mid:' . $id;
1735
1736                        $lines = array();
1737                        $ln = 0;
1738                        /*
1739                            Sample reply line:
1740                            * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen)
1741                            INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...)
1742                            BODY[HEADER.FIELDS ...
1743                        */
1744
1745                        if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/s', $line, $matches)) {
1746                                $str = $matches[1];
1747
1748                                // swap parents with quotes, then explode
1749                                $str = eregi_replace("[()]", "\"", $str);
1750                                $a = iil_ExplodeQuotedString(' ', $str);
1751
1752                                // did we get the right number of replies?
1753                                $parts_count = count($a);
1754                                if ($parts_count>=6) {
1755                                        for ($i=0; $i<$parts_count; $i=$i+2) {
1756                                                if (strcasecmp($a[$i],'UID') == 0)
1757                                                        $result[$id]->uid = $a[$i+1];
1758                                                else if (strcasecmp($a[$i],'RFC822.SIZE') == 0)
1759                                                        $result[$id]->size = $a[$i+1];
1760                                                else if (strcasecmp($a[$i],'INTERNALDATE') == 0)
1761                                                        $time_str = $a[$i+1];
1762                                                else if (strcasecmp($a[$i],'FLAGS') == 0)
1763                                                        $flags_str = $a[$i+1];
1764                                        }
1765
1766                                        $time_str = str_replace('"', '', $time_str);
1767                                       
1768                                        // if time is gmt...
1769                                        $time_str = str_replace('GMT','+0000',$time_str);
1770                                       
1771                                        //get timezone
1772                                        $time_str      = substr($time_str, 0, -1);
1773                                        $time_zone_str = substr($time_str, -5); // extract timezone
1774                                        $time_str      = substr($time_str, 0, -5); // remove timezone
1775                                        $time_zone     = (float)substr($time_zone_str, 1, 2); // get first two digits
1776                       
1777                                        if ($time_zone_str[3] != '0') {
1778                                                 $time_zone += 0.5;  //handle half hour offset
1779                                        }
1780                                        if ($time_zone_str[0] == '-') {
1781                                                $time_zone = $time_zone * -1.0; //minus?
1782                                        }
1783                                       
1784                                        //calculate timestamp
1785                                        $timestamp     = strtotime($time_str); //return's server's time
1786                                        $timestamp    -= $time_zone * 3600; //compensate for tz, get GMT
1787
1788                                        $result[$id]->internaldate = $time_str;
1789                                        $result[$id]->timestamp = $timestamp;
1790                                        $result[$id]->date = $time_str;
1791                                }
1792
1793                                // BODYSTRUCTURE
1794                                if($bodystr) {
1795                                        while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) {
1796                                                $line2 = iil_ReadLine($fp, 1024);
1797                                                $line .= iil_MultLine($fp, $line2);
1798                                        }
1799                                        $result[$id]->body_structure = $m[1];
1800                                }
1801
1802                                // the rest of the result
1803                                preg_match('/ BODY\[HEADER.FIELDS \(.*\)\]\s*(.*)/s', $line, $m);
1804                                $reslines = explode("\n", trim($m[1], '"'));
1805                                // re-parse (see below)
1806                                foreach ($reslines as $line) {
1807                                        if (ord($line[0])<=32) {
1808                                                $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
1809                                        } else {
1810                                                $lines[++$ln] = trim($line);
1811                                        }
1812                                }
1813                        }
1814
1815                        /*
1816                                Start parsing headers.  The problem is, some header "lines" take up multiple lines.
1817                                So, we'll read ahead, and if the one we're reading now is a valid header, we'll
1818                                process the previous line.  Otherwise, we'll keep adding the strings until we come
1819                                to the next valid header line.
1820                        */
1821       
1822                        do {
1823                                $line = chop(iil_ReadLine($fp, 300), "\r\n");
1824
1825                                // The preg_match below works around communigate imap, which outputs " UID <number>)".
1826                                // Without this, the while statement continues on and gets the "FH0 OK completed" message.
1827                                // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. 
1828                                // This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing
1829                                // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin
1830                                // An alternative might be:
1831                                // if (!preg_match("/:/",$line) && preg_match("/\)$/",$line)) break;
1832                                // however, unsure how well this would work with all imap clients.
1833                                if (preg_match("/^\s*UID [0-9]+\)$/", $line)) {
1834                                    break;
1835                                }
1836
1837                                // handle FLAGS reply after headers (AOL, Zimbra?)
1838                                if (preg_match('/\s+FLAGS \((.*)\)\)$/', $line, $matches)) {
1839                                        $flags_str = $matches[1];
1840                                        break;
1841                                }
1842
1843                                if (ord($line[0])<=32) {
1844                                        $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line);
1845                                } else {
1846                                        $lines[++$ln] = trim($line);
1847                                }
1848                        // patch from "Maksim Rubis" <siburny@hotmail.com>
1849                        } while (trim($line[0]) != ')' && strncmp($line, $key, strlen($key)));
1850
1851                        if (strncmp($line, $key, strlen($key))) {
1852                                // process header, fill iilBasicHeader obj.
1853                                // initialize
1854                                if (is_array($headers)) {
1855                                        reset($headers);
1856                                        while (list($k, $bar) = each($headers)) {
1857                                                $headers[$k] = '';
1858                                        }
1859                                }
1860       
1861                                // create array with header field:data
1862                                while ( list($lines_key, $str) = each($lines) ) {
1863                                        list($field, $string) = iil_SplitHeaderLine($str);
1864                                       
1865                                        $field  = strtolower($field);
1866                                        $string = ereg_replace("\n[[:space:]]*"," ",$string);
1867                                       
1868                                        switch ($field) {
1869                                        case 'date';
1870                                                if (!$IMAP_USE_INTERNAL_DATE) {
1871                                                        $result[$id]->date = $string;
1872                                                        $result[$id]->timestamp = iil_StrToTime($string);
1873                                                }
1874                                                break;
1875                                        case 'from':
1876                                                $result[$id]->from = $string;
1877                                                break;
1878                                        case 'to':
1879                                                $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string);
1880                                                break;
1881                                        case 'subject':
1882                                                $result[$id]->subject = $string;
1883                                                break;
1884                                        case 'reply-to':
1885                                                $result[$id]->replyto = $string;
1886                                                break;
1887                                        case 'cc':
1888                                                $result[$id]->cc = $string;
1889                                                break;
1890                                        case 'bcc':
1891                                                $result[$id]->bcc = $string;
1892                                                break;
1893                                        case 'content-transfer-encoding':
1894                                                $result[$id]->encoding = $string;
1895                                                break;
1896                                        case 'content-type':
1897                                                $ctype_parts = explode(";", $string);
1898                                                $result[$id]->ctype = array_shift($ctype_parts);
1899                                                foreach ($ctype_parts as $ctype_add) {
1900                                                        if (preg_match('/charset="?([a-z0-9\-\.\_]+)"?/i',
1901                                                                $ctype_add, $regs)) {
1902                                                                $result[$id]->charset = $regs[1];
1903                                                        }
1904                                                }
1905                                                break;
1906                                        case 'in-reply-to':
1907                                                $result[$id]->in_reply_to = ereg_replace("[\n<>]", '', $string);
1908                                                break;
1909                                        case 'references':
1910                                                $result[$id]->references = $string;
1911                                                break;
1912                                        case 'return-receipt-to':
1913                                        case 'disposition-notification-to':
1914                                        case 'x-confirm-reading-to':
1915                                                $result[$id]->mdn_to = $string;
1916                                                break;
1917                                        case 'message-id':
1918                                                $result[$id]->messageID = $string;
1919                                                break;
1920                                        case 'x-priority':
1921                                                if (preg_match('/^(\d+)/', $string, $matches))
1922                                                        $result[$id]->priority = intval($matches[1]);
1923                                                break;
1924                                        default:
1925                                                if (strlen($field) > 2)
1926                                                        $result[$id]->others[$field] = $string;
1927                                                break;
1928                                        } // end switch ()
1929                                } // end while ()
1930               
1931                                if ($conn->do_cache) {
1932                                        $uid = $result[$id]->uid;
1933                                        $conn->cache[$mailbox][$uid] = $result[$id];
1934                                        $conn->cache_dirty[$mailbox] = true;
1935                                }
1936                        } else {
1937                                $a = explode(' ', $line);
1938                        }
1939
1940                        // process flags
1941                        if (!empty($flags_str)) {
1942                                $flags_str = eregi_replace('[\\\"]', '', $flags_str);
1943                                $flags_a   = explode(' ', $flags_str);
1944                                       
1945                                if (is_array($flags_a)) {
1946                                        reset($flags_a);
1947                                        while (list(,$val)=each($flags_a)) {
1948                                                if (strcasecmp($val,'Seen') == 0) {
1949                                                    $result[$id]->seen = true;
1950                                                } else if (strcasecmp($val, 'Deleted') == 0) {
1951                                                    $result[$id]->deleted=true;
1952                                                } else if (strcasecmp($val, 'Recent') == 0) {
1953                                                    $result[$id]->recent = true;
1954                                                } else if (strcasecmp($val, 'Answered') == 0) {
1955                                                        $result[$id]->answered = true;
1956                                                } else if (strcasecmp($val, '$Forwarded') == 0) {
1957                                                        $result[$id]->forwarded = true;
1958                                                } else if (strcasecmp($val, 'Draft') == 0) {
1959                                                        $result[$id]->is_draft = true;
1960                                                } else if (strcasecmp($val, '$MDNSent') == 0) {
1961                                                        $result[$id]->mdn_sent = true;
1962                                                } else if (strcasecmp($val, 'Flagged') == 0) {
1963                                                         $result[$id]->flagged = true;
1964                                                }
1965                                        }
1966                                        $result[$id]->flags = $flags_a;
1967                                }
1968                        }
1969                }
1970        } while (strcmp($a[0], $key) != 0);
1971
1972        return $result;
1973}
1974
1975function iil_C_FetchHeader(&$conn, $mailbox, $id, $uidfetch=false, $bodystr=false, $add='') {
1976
1977        $a  = iil_C_FetchHeaders($conn, $mailbox, $id, $uidfetch, $bodystr, $add);
1978        if (is_array($a)) {
1979                return array_shift($a);
1980        }
1981        return false;
1982}
1983
1984function iil_SortHeaders($a, $field, $flag) {
1985        if (empty($field)) {
1986            $field = 'uid';
1987        }
1988        $field = strtolower($field);
1989        if ($field == 'date' || $field == 'internaldate') {
1990            $field = 'timestamp';
1991        }
1992        if (empty($flag)) {
1993            $flag = 'ASC';
1994        }
1995   
1996        $flag     = strtoupper($flag);
1997        $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ','"') : array('"');
1998
1999        $c=count($a);
2000        if ($c > 0) {
2001                /*
2002                        Strategy:
2003                        First, we'll create an "index" array.
2004                        Then, we'll use sort() on that array,
2005                        and use that to sort the main array.
2006                */
2007               
2008                // create "index" array
2009                $index = array();
2010                reset($a);
2011                while (list($key, $val)=each($a)) {
2012
2013                        if ($field == 'timestamp') {
2014                                $data = @strtotime($val->date);
2015                                if ($data == false) {
2016                                        $data = $val->timestamp;
2017                                }
2018                        } else {
2019                                $data = $val->$field;
2020                                if (is_string($data)) {
2021                                        $data=strtoupper(str_replace($stripArr, '', $data));
2022                                }
2023                        }
2024                        $index[$key]=$data;
2025                }
2026               
2027                // sort index
2028                $i = 0;
2029                if ($flag == 'ASC') {
2030                        asort($index);
2031                } else {
2032                        arsort($index);
2033                }
2034       
2035                // form new array based on index
2036                $result = array();
2037                reset($index);
2038                while (list($key, $val)=each($index)) {
2039                        $result[$key]=$a[$key];
2040                        $i++;
2041                }
2042        }
2043       
2044        return $result;
2045}
2046
2047function iil_C_Expunge(&$conn, $mailbox) {
2048
2049        if (iil_C_Select($conn, $mailbox)) {
2050                $c = 0;
2051                iil_PutLine($conn->fp, "exp1 EXPUNGE");
2052                do {
2053                        $line=chop(iil_ReadLine($conn->fp, 100));
2054                        if ($line[0] == '*') {
2055                                $c++;
2056                        }
2057                } while (!iil_StartsWith($line, 'exp1', true));
2058               
2059                if (iil_ParseResult($line) == 0) {
2060                        $conn->selected = ''; //state has changed, need to reselect                     
2061                        //$conn->exists-=$c;
2062                        return $c;
2063                }
2064                $conn->error = $line;
2065        }
2066       
2067        return -1;
2068}
2069
2070function iil_C_ModFlag(&$conn, $mailbox, $messages, $flag, $mod) {
2071        if ($mod != '+' && $mod != '-') {
2072            return -1;
2073        }
2074   
2075        $fp    = $conn->fp;
2076        $flags = $GLOBALS['IMAP_FLAGS'];
2077       
2078        $flag = strtoupper($flag);
2079        $flag = $flags[$flag];
2080   
2081        if (iil_C_Select($conn, $mailbox)) {
2082                $c = 0;
2083                iil_PutLine($fp, "flg UID STORE $messages " . $mod . "FLAGS (" . $flag . ")");
2084                do {
2085                        $line=chop(iil_ReadLine($fp, 100));
2086                        if ($line[0] == '*') {
2087                            $c++;
2088                        }
2089                } while (!iil_StartsWith($line, 'flg', true));
2090
2091                if (iil_ParseResult($line) == 0) {
2092                        iil_C_ExpireCachedItems($conn, $mailbox, $messages);
2093                        return $c;
2094                }
2095                $conn->error = $line;
2096                return -1;
2097        }
2098        $conn->error = 'Select failed';
2099        return -1;
2100}
2101
2102function iil_C_Flag(&$conn, $mailbox, $messages, $flag) {
2103        return iil_C_ModFlag($conn, $mailbox, $messages, $flag, '+');
2104}
2105
2106function iil_C_Unflag(&$conn, $mailbox, $messages, $flag) {
2107        return iil_C_ModFlag($conn, $mailbox, $messages, $flag, '-');
2108}
2109
2110function iil_C_Delete(&$conn, $mailbox, $messages) {
2111        return iil_C_ModFlag($conn, $mailbox, $messages, 'DELETED', '+');
2112}
2113
2114function iil_C_Undelete(&$conn, $mailbox, $messages) {
2115        return iil_C_ModFlag($conn, $mailbox, $messages, 'DELETED', '-');
2116}
2117
2118function iil_C_Unseen(&$conn, $mailbox, $messages) {
2119        return iil_C_ModFlag($conn, $mailbox, $messages, 'SEEN', '-');
2120}
2121
2122function iil_C_Copy(&$conn, $messages, $from, $to) {
2123        $fp = $conn->fp;
2124
2125        if (empty($from) || empty($to)) {
2126            return -1;
2127        }
2128   
2129        if (iil_C_Select($conn, $from)) {
2130                $c=0;
2131               
2132                iil_PutLine($fp, "cpy1 UID COPY $messages \"".iil_Escape($to)."\"");
2133                $line=iil_ReadReply($fp);
2134                return iil_ParseResult($line);
2135        } else {
2136                return -1;
2137        }
2138}
2139
2140function iil_FormatSearchDate($month, $day, $year) {
2141        $month  = (int) $month;
2142        $months = $GLOBALS['IMAP_MONTHS'];
2143        return $day . '-' . $months[$month] . '-' . $year;
2144}
2145
2146function iil_C_CountUnseen(&$conn, $folder) {
2147        $index = iil_C_Search($conn, $folder, 'ALL UNSEEN');
2148        if (is_array($index)) {
2149                if (($cnt = count($index)) && $index[0] != '') {
2150                        return $cnt;
2151                }
2152        }
2153        return false;
2154}
2155
2156function iil_C_UID2ID(&$conn, $folder, $uid) {
2157        if ($uid > 0) {
2158                $id_a = iil_C_Search($conn, $folder, "UID $uid");
2159                if (is_array($id_a) && count($id_a) == 1) {
2160                        return $id_a[0];
2161                }
2162        }
2163        return false;
2164}
2165
2166function iil_C_ID2UID(&$conn, $folder, $id) {
2167        $fp = $conn->fp;
2168        if ($id == 0) {
2169            return      -1;
2170        }
2171        $result = -1;
2172        if (iil_C_Select($conn, $folder)) {
2173                $key = 'FUID';
2174                if (iil_PutLine($fp, "$key FETCH $id (UID)")) {
2175                        do {
2176                                $line=chop(iil_ReadLine($fp, 1024));
2177                                if (eregi("^\* $id FETCH \(UID (.*)\)", $line, $r)) {
2178                                        $result = $r[1];
2179                                }
2180                        } while (!preg_match("/^$key/", $line));
2181                }
2182        }
2183        return $result;
2184}
2185
2186function iil_C_Search(&$conn, $folder, $criteria) {
2187        $fp = $conn->fp;
2188        if (iil_C_Select($conn, $folder)) {
2189                $c = 0;
2190               
2191                $query = 'srch1 SEARCH ' . chop($criteria);
2192                if (!iil_PutLineC($fp, $query)) {
2193                        return false;
2194                }
2195                do {
2196                        $line=trim(iil_ReadLine($fp, 10000));
2197                        if (eregi("^\* SEARCH", $line)) {
2198                                $str = trim(substr($line, 8));
2199                                $messages = explode(' ', $str);
2200                        }
2201                } while (!iil_StartsWith($line, 'srch1', true));
2202
2203                $result_code = iil_ParseResult($line);
2204                if ($result_code == 0) {
2205                    return $messages;
2206                }
2207                $conn->error = 'iil_C_Search: ' . $line . "\n";
2208                return false;   
2209        }
2210        $conn->error = "iil_C_Search: Couldn't select \"$folder\"\n";
2211        return false;
2212}
2213
2214function iil_C_Move(&$conn, $messages, $from, $to) {
2215    $fp = $conn->fp;
2216
2217    if (!$from || !$to) {
2218        return -1;
2219    }
2220    $r = iil_C_Copy($conn, $messages, $from,$to);
2221    if ($r==0) {
2222        return iil_C_Delete($conn, $from, $messages);
2223    }
2224    return $r;
2225}
2226
2227/**
2228 * Gets the delimiter, for example:
2229 * INBOX.foo -> .
2230 * INBOX/foo -> /
2231 * INBOX\foo -> \
2232 *
2233 * @return mixed A delimiter (string), or false.
2234 * @param object $conn The current connection.
2235 * @see iil_Connect()
2236 */
2237function iil_C_GetHierarchyDelimiter(&$conn) {
2238
2239        global $my_prefs;
2240       
2241        if ($conn->delimiter) {
2242                return $conn->delimiter;
2243        }
2244        if (!empty($my_prefs['delimiter'])) {
2245            return ($conn->delimiter = $my_prefs['delimiter']);
2246        }
2247   
2248        $fp        = $conn->fp;
2249        $delimiter = false;
2250       
2251        //try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
2252        if (!iil_PutLine($fp, 'ghd LIST "" ""')) {
2253            return false;
2254        }
2255   
2256        do {
2257                $line=iil_ReadLine($fp, 500);
2258                if ($line[0] == '*') {
2259                        $line = rtrim($line);
2260                        $a=iil_ExplodeQuotedString(' ', iil_UnEscape($line));
2261                        if ($a[0] == '*') {
2262                            $delimiter = str_replace('"', '', $a[count($a)-2]);
2263                        }
2264                }
2265        } while (!iil_StartsWith($line, 'ghd', true));
2266
2267        if (strlen($delimiter)>0) {
2268            return $delimiter;
2269        }
2270
2271        //if that fails, try namespace extension
2272        //try to fetch namespace data
2273        iil_PutLine($conn->fp, "ns1 NAMESPACE");
2274        do {
2275                $line = iil_ReadLine($conn->fp, 1024);
2276                if (iil_StartsWith($line, '* NAMESPACE')) {
2277                        $i = 0;
2278                        $line = iil_UnEscape($line);
2279                        $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
2280                }
2281        } while (!iil_StartsWith($line, 'ns1', true));
2282               
2283        if (!is_array($data)) {
2284            return false;
2285        }
2286   
2287        //extract user space data (opposed to global/shared space)
2288        $user_space_data = $data[0];
2289        if (!is_array($user_space_data)) {
2290            return false;
2291        }
2292   
2293        //get first element
2294        $first_userspace = $user_space_data[0];
2295        if (!is_array($first_userspace)) {
2296            return false;
2297        }
2298   
2299        //extract delimiter
2300        $delimiter = $first_userspace[1];       
2301
2302        return $delimiter;
2303}
2304
2305function iil_C_ListMailboxes(&$conn, $ref, $mailbox) {
2306        global $IGNORE_FOLDERS;
2307       
2308        $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
2309               
2310        $fp = $conn->fp;
2311       
2312        if (empty($mailbox)) {
2313            $mailbox = '*';
2314        }
2315       
2316        if (empty($ref) && $conn->rootdir) {
2317            $ref = $conn->rootdir;
2318        }
2319   
2320        // send command
2321        if (!iil_PutLine($fp, "lmb LIST \"".$ref."\" \"".iil_Escape($mailbox)."\"")) {
2322            return false;
2323        }
2324   
2325        $i = 0;
2326        // get folder list
2327        do {
2328                $line = iil_ReadLine($fp, 500);
2329                $line = iil_MultLine($fp, $line);
2330
2331                $a = explode(' ', $line);
2332                if (($line[0] == '*') && ($a[1] == 'LIST')) {
2333                        $line = rtrim($line);
2334                        // split one line
2335                        $a = iil_ExplodeQuotedString(' ', $line);
2336                        // last string is folder name
2337                        $folder = trim($a[count($a)-1], '"');
2338           
2339                        if (empty($ignore) || (!empty($ignore)
2340                                && !eregi($ignore, $folder))) {
2341                                $folders[$i] = $folder;
2342                        }
2343           
2344                        // second from last is delimiter
2345                        $delim = trim($a[count($a)-2], '"');
2346                        // is it a container?
2347                        $i++;
2348                }
2349        } while (!iil_StartsWith($line, 'lmb', true));
2350
2351        if (is_array($folders)) {
2352            if (!empty($ref)) {
2353                // if rootdir was specified, make sure it's the first element
2354                // some IMAP servers (i.e. Courier) won't return it
2355                if ($ref[strlen($ref)-1]==$delim)
2356                    $ref = substr($ref, 0, strlen($ref)-1);
2357                if ($folders[0]!=$ref)
2358                    array_unshift($folders, $ref);
2359            }
2360            return $folders;
2361        } else if (iil_ParseResult($line) == 0) {
2362                return array('INBOX');
2363        } else {
2364                $conn->error = $line;
2365                return false;
2366        }
2367}
2368
2369function iil_C_ListSubscribed(&$conn, $ref, $mailbox) {
2370        global $IGNORE_FOLDERS;
2371       
2372        $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
2373       
2374        $fp = $conn->fp;
2375        if (empty($mailbox)) {
2376                $mailbox = '*';
2377        }
2378        if (empty($ref) && $conn->rootdir) {
2379                $ref = $conn->rootdir;
2380        }
2381        $folders = array();
2382
2383        // send command
2384        if (!iil_PutLine($fp, 'lsb LSUB "' . $ref . '" "' . iil_Escape($mailbox).'"')) {
2385                $conn->error = "Couldn't send LSUB command\n";
2386                return false;
2387        }
2388       
2389        $i = 0;
2390       
2391        // get folder list
2392        do {
2393                $line = iil_ReadLine($fp, 500);
2394                $line = iil_MultLine($fp, $line);
2395                $a    = explode(' ', $line);
2396       
2397                if (($line[0] == '*') && ($a[1] == 'LSUB' || $a[1] == 'LIST')) {
2398                        $line = rtrim($line);
2399           
2400                        // split one line
2401                        $a = iil_ExplodeQuotedString(' ', $line);
2402           
2403                        // last string is folder name
2404                        //$folder = UTF7DecodeString(str_replace('"', '', $a[count($a)-1]));
2405                        $folder = trim($a[count($a)-1], '"');
2406           
2407                        if ((!in_array($folder, $folders)) && (empty($ignore)
2408                                || (!empty($ignore) && !eregi($ignore, $folder)))) {
2409                            $folders[$i] = $folder;
2410                        }
2411           
2412                        // second from last is delimiter
2413                        $delim = trim($a[count($a)-2], '"');
2414           
2415                        // is it a container?
2416                        $i++;
2417                }
2418        } while (!iil_StartsWith($line, 'lsb', true));
2419
2420        if (is_array($folders)) {
2421            if (!empty($ref)) {
2422                // if rootdir was specified, make sure it's the first element
2423                // some IMAP servers (i.e. Courier) won't return it
2424                if ($ref[strlen($ref)-1]==$delim) {
2425                    $ref = substr($ref, 0, strlen($ref)-1);
2426                }
2427                if ($folders[0]!=$ref) {
2428                    array_unshift($folders, $ref);
2429                }
2430            }
2431            return $folders;
2432        }
2433        $conn->error = $line;
2434        return false;
2435}
2436
2437function iil_C_Subscribe(&$conn, $folder) {
2438        $fp = $conn->fp;
2439
2440        $query = 'sub1 SUBSCRIBE "' . iil_Escape($folder). '"';
2441        iil_PutLine($fp, $query);
2442
2443        $line = trim(iil_ReadLine($fp, 10000));
2444        return iil_ParseResult($line);
2445}
2446
2447function iil_C_UnSubscribe(&$conn, $folder) {
2448        $fp = $conn->fp;
2449
2450        $query = 'usub1 UNSUBSCRIBE "' . iil_Escape($folder) . '"';
2451        iil_PutLine($fp, $query);
2452   
2453        $line = trim(iil_ReadLine($fp, 10000));
2454        return iil_ParseResult($line);
2455}
2456
2457function iil_C_FetchMIMEHeaders(&$conn, $mailbox, $id, $parts) {
2458       
2459        $fp     = $conn->fp;
2460
2461        if (!iil_C_Select($conn, $mailbox)) {
2462                return false;
2463        }
2464       
2465        $result = false;
2466        $parts = (array) $parts;
2467        $key = 'fmh0';
2468        $peeks = '';
2469        $idx = 0;
2470
2471        // format request
2472        foreach($parts as $part)
2473                $peeks[] = "BODY.PEEK[$part.MIME]";
2474       
2475        $request = "$key FETCH $id (" . implode(' ', $peeks) . ')';
2476
2477        // send request
2478        if (!iil_PutLine($fp, $request)) {
2479            return false;
2480        }
2481       
2482        do {
2483                $line = iil_ReadLine($fp, 1000);
2484                $line = iil_MultLine($fp, $line);
2485
2486                if (preg_match('/BODY\[([0-9\.]+)\.MIME\]/', $line, $matches)) {
2487                        $idx = $matches[1];
2488                        $result[$idx] = preg_replace('/^(\* '.$id.' FETCH \()?\s*BODY\['.$idx.'\.MIME\]\s+/', '', $line);
2489                        $result[$idx] = trim($result[$idx], '"');
2490                        $result[$idx] = rtrim($result[$idx], "\t\r\n\0\x0B");
2491                }
2492        } while (!iil_StartsWith($line, $key, true));
2493
2494        return $result;
2495}
2496
2497function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part) {
2498
2499        $part = empty($part) ? 'HEADER' : $part.'.MIME';
2500
2501        return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
2502}
2503
2504function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part='', $mode=1, $file=NULL) {
2505        /* modes:
2506        1: return string (or write to $file pointer)
2507        2: print
2508        3: base64 and print (or write to $file pointer)
2509        */
2510       
2511        $fp     = $conn->fp;
2512        $result = false;
2513       
2514        if (iil_C_Select($conn, $mailbox)) {
2515                $reply_key = '* ' . $id;
2516       
2517                // format request
2518                $key     = 'ftch' . ($c++) . ' ';
2519                $request = $key . "FETCH $id (BODY.PEEK[$part])";
2520                // send request
2521                if (!iil_PutLine($fp, $request)) {
2522                    return false;
2523                }
2524       
2525                // receive reply line
2526                do {
2527                        $line = chop(iil_ReadLine($fp, 1000));
2528                        $a    = explode(' ', $line);
2529                } while ($a[2] != 'FETCH');
2530                $len = strlen($line);
2531
2532                // handle empty "* X FETCH ()" response
2533                if ($line[$len-1] == ')' && $line[$len-2] != '(') {
2534                        // one line response, get everything between first and last quotes
2535                        if (substr($line, -4, 3) == 'NIL') {
2536                                // NIL response
2537                                $result = '';
2538                        } else {
2539                                $from = strpos($line, '"') + 1;
2540                                $to   = strrpos($line, '"');
2541                                $len  = $to - $from;
2542                                $result = substr($line, $from, $len);
2543                        }
2544           
2545                        if ($mode == 2) {
2546                                echo $result;
2547                        } else if ($mode == 3) {
2548                                if ($file)
2549                                        fwrite($file, base64_decode($result));
2550                                else
2551                                        echo base64_decode($result);
2552                        }                           
2553                } else if ($line[$len-1] == '}') {
2554                        //multi-line request, find sizes of content and receive that many bytes
2555                        $from     = strpos($line, '{') + 1;
2556                        $to       = strrpos($line, '}');
2557                        $len      = $to - $from;
2558                        $sizeStr  = substr($line, $from, $len);
2559                        $bytes    = (int)$sizeStr;
2560                        $prev     = '';
2561                       
2562                        while ($bytes > 0) {
2563                                $line      = iil_ReadLine($fp, 1024);
2564                                $len       = strlen($line);
2565               
2566                                if ($len > $bytes) {
2567                                        $line = substr($line, 0, $bytes);
2568                                }
2569                                $bytes -= strlen($line);
2570
2571                                $line = rtrim($line, "\t\r\n\0\x0B");
2572
2573                                if ($mode == 1) {
2574                                        if ($file)
2575                                                fwrite($file, $line . "\n");
2576                                        else
2577                                                $result .= $line . "\n";
2578                                } else if ($mode == 2) {
2579                                        echo $line . "\n";
2580                                } else if ($mode == 3) {
2581                                        // create chunks with proper length for base64 decoding
2582                                        $line = $prev.$line;
2583                                        $length = strlen($line);
2584                                        if ($length % 4) {
2585                                                $length = floor($length / 4) * 4;
2586                                                $prev = substr($line, $length);
2587                                                $line = substr($line, 0, $length);
2588                                        }
2589                                        else
2590                                                $prev = '';
2591
2592                                        if ($file)
2593                                                fwrite($file, base64_decode($line));
2594                                        else
2595                                                echo base64_decode($line);
2596                                }
2597                        }
2598                }
2599                // read in anything up until last line
2600                do {
2601                        $line = iil_ReadLine($fp, 1024);
2602                } while (!iil_StartsWith($line, $key, true));
2603       
2604                if ($mode == 3 && $file) {
2605                        return true;
2606                }
2607       
2608                if ($result) {
2609                        $result = rtrim($result, "\t\r\n\0\x0B");
2610                        if ($file) {
2611                                fwrite($file, $result);
2612                                return true;
2613                        }       
2614                        return $result; // substr($result, 0, strlen($result)-1);
2615                }
2616               
2617                return false;
2618        } else {
2619                echo 'Select failed.';
2620        }
2621   
2622        if ($mode==1) {
2623                if ($file) {
2624                        fwrite($file, $result);
2625                        return true;
2626                }
2627                return $result;
2628        }
2629       
2630        return false;
2631}
2632
2633function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part, $file=NULL) {
2634        return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1, $file);
2635}
2636
2637function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part) {
2638        iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
2639}
2640
2641function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part) {
2642        iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
2643}
2644
2645function iil_C_CreateFolder(&$conn, $folder) {
2646        $fp = $conn->fp;
2647        if (iil_PutLine($fp, 'c CREATE "' . iil_Escape($folder) . '"')) {
2648                do {
2649                        $line=iil_ReadLine($fp, 300);
2650                } while ($line[0] != 'c');
2651        $conn->error = $line;
2652                return (iil_ParseResult($line) == 0);
2653        }
2654        return false;
2655}
2656
2657function iil_C_RenameFolder(&$conn, $from, $to) {
2658        $fp = $conn->fp;
2659        if (iil_PutLine($fp, 'r RENAME "' . iil_Escape($from) . '" "' . iil_Escape($to) . '"')) {
2660                do {
2661                        $line = iil_ReadLine($fp, 300);
2662                } while ($line[0] != 'r');
2663                return (iil_ParseResult($line) == 0);
2664        }
2665        return false;
2666}
2667
2668function iil_C_DeleteFolder(&$conn, $folder) {
2669        $fp = $conn->fp;
2670        if (iil_PutLine($fp, 'd DELETE "' . iil_Escape($folder). '"')) {
2671                do {
2672                        $line=iil_ReadLine($fp, 300);
2673                } while ($line[0] != 'd');
2674                return (iil_ParseResult($line) == 0);
2675        }
2676        $conn->error = "Couldn't send command\n";
2677        return false;
2678}
2679
2680function iil_C_Append(&$conn, $folder, &$message) {
2681        if (!$folder) {
2682                return false;
2683        }
2684        $fp = $conn->fp;
2685
2686        $message = str_replace("\r", '', $message);
2687        $message = str_replace("\n", "\r\n", $message);         
2688
2689        $len = strlen($message);
2690        if (!$len) {
2691                return false;
2692        }
2693
2694        $request = 'A APPEND "' . iil_Escape($folder) .'" (\\Seen) {' . $len . '}';
2695   
2696        if (iil_PutLine($fp, $request)) {
2697                $line=iil_ReadLine($fp, 100);           
2698                $sent = fwrite($fp, $message."\r\n");
2699                do {
2700                        $line=iil_ReadLine($fp, 1000);
2701                } while ($line[0] != 'A');
2702       
2703                $result = (iil_ParseResult($line) == 0);
2704                if (!$result) {
2705                    $conn->error .= $line . "\n";
2706                }
2707                return $result;
2708        }
2709
2710        $conn->error .= "Couldn't send command \"$request\"\n";
2711        return false;
2712}
2713
2714function iil_C_AppendFromFile(&$conn, $folder, $path) {
2715        if (!$folder) {
2716            return false;
2717        }
2718   
2719        //open message file
2720        $in_fp = false;                         
2721        if (file_exists(realpath($path))) {
2722                $in_fp = fopen($path, 'r');
2723        }
2724        if (!$in_fp) {
2725                $conn->error .= "Couldn't open $path for reading\n";
2726                return false;
2727        }
2728       
2729        $fp  = $conn->fp;
2730        $len = filesize($path);
2731        if (!$len) {
2732                return false;
2733        }
2734   
2735        //send APPEND command
2736        $request    = 'A APPEND "' . iil_Escape($folder) . '" (\\Seen) {' . $len . '}';
2737        $bytes_sent = 0;
2738        if (iil_PutLine($fp, $request)) {
2739                $line = iil_ReadLine($fp, 100);
2740                               
2741                //send file
2742                while (!feof($in_fp)) {
2743                        $buffer      = fgets($in_fp, 4096);
2744                        $bytes_sent += strlen($buffer);
2745                        iil_PutLine($fp, $buffer, false);
2746                }
2747                fclose($in_fp);
2748
2749                iil_PutLine($fp, '');
2750
2751                //read response
2752                do {
2753                        $line = iil_ReadLine($fp, 1000);
2754                } while ($line[0] != 'A');
2755                       
2756                $result = (iil_ParseResult($line) == 0);
2757                if (!$result) {
2758                    $conn->error .= $line . "\n";
2759                }
2760       
2761                return $result;
2762        }
2763       
2764        $conn->error .= "Couldn't send command \"$request\"\n";
2765        return false;
2766}
2767
2768function iil_C_FetchStructureString(&$conn, $folder, $id) {
2769        $fp     = $conn->fp;
2770        $result = false;
2771       
2772        if (iil_C_Select($conn, $folder)) {
2773                $key = 'F1247';
2774
2775                if (iil_PutLine($fp, "$key FETCH $id (BODYSTRUCTURE)")) {
2776                        do {
2777                                $line = iil_ReadLine($fp, 5000);
2778                                $line = iil_MultLine($fp, $line);
2779                                list(, $index, $cmd, $rest) = explode(' ', $line);
2780                                if ($cmd != 'FETCH' || $index == $id || preg_match("/^$key/", $line))
2781                                        $result .= $line;
2782                        } while (!preg_match("/^$key/", $line));
2783
2784                        $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -(strlen($result)-strrpos($result, $key)+1)));
2785                }
2786        }
2787        return $result;
2788}
2789
2790function iil_C_PrintSource(&$conn, $folder, $id, $part) {
2791        $header = iil_C_FetchPartHeader($conn, $folder, $id, $part);
2792        //echo str_replace("\r", '', $header);
2793        echo $header;
2794        echo iil_C_PrintPartBody($conn, $folder, $id, $part);
2795}
2796
2797function iil_C_GetQuota(&$conn) {
2798/*
2799 * GETQUOTAROOT "INBOX"
2800 * QUOTAROOT INBOX user/rchijiiwa1
2801 * QUOTA user/rchijiiwa1 (STORAGE 654 9765)
2802 * OK Completed
2803 */
2804        $fp         = $conn->fp;
2805        $result     = false;
2806        $quota_lines = array();
2807       
2808        // get line(s) containing quota info
2809        if (iil_PutLine($fp, 'QUOT1 GETQUOTAROOT "INBOX"')) {
2810                do {
2811                        $line=chop(iil_ReadLine($fp, 5000));
2812                        if (iil_StartsWith($line, '* QUOTA ')) {
2813                                $quota_lines[] = $line;
2814                        }
2815                } while (!iil_StartsWith($line, 'QUOT1', true));
2816        }
2817       
2818        // return false if not found, parse if found
2819        $min_free = PHP_INT_MAX;
2820        foreach ($quota_lines as $key => $quota_line) {
2821                $quota_line   = eregi_replace('[()]', '', $quota_line);
2822                $parts        = explode(' ', $quota_line);
2823                $storage_part = array_search('STORAGE', $parts);
2824               
2825                if (!$storage_part) continue;
2826       
2827                $used   = intval($parts[$storage_part+1]);
2828                $total  = intval($parts[$storage_part+2]);
2829                $free   = $total - $used;
2830       
2831                // return lowest available space from all quotas
2832                if ($free < $min_free) {
2833                        $min_free = $free;
2834                        $result['used']    = $used;
2835                        $result['total']   = $total;
2836                        $result['percent'] = min(100, round(($used/max(1,$total))*100));
2837                        $result['free']    = 100 - $result['percent'];
2838                }
2839        }
2840        return $result;
2841}
2842
2843function iil_C_ClearFolder(&$conn, $folder) {
2844        $num_in_trash = iil_C_CountMessages($conn, $folder);
2845        if ($num_in_trash > 0) {
2846                iil_C_Delete($conn, $folder, '1:*');
2847        }
2848        return (iil_C_Expunge($conn, $folder) >= 0);
2849}
2850
2851?>
Note: See TracBrowser for help on using the repository browser.