source: github/program/lib/imap.inc @ 14432db

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