source: github/program/lib/imap.inc @ 078adf9

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since 078adf9 was 078adf9, checked in by thomascube <thomas@…>, 7 years ago

Improved usability (Ticket #1483807) and HTML validity; applied patch #1328032; fixed bug #1443200

  • Property mode set to 100644
File size: 56.7 KB
Line 
1<?php
2/////////////////////////////////////////////////////////
3//     
4//      Iloha IMAP Library (IIL)
5//
6//      (C)Copyright 2002 Ryo Chijiiwa <Ryo@IlohaMail.org>
7//
8//      This file is part of IlohaMail. IlohaMail is free software released
9//      under the GPL license.  See enclosed file COPYING for details, or
10//      see http://www.fsf.org/copyleft/gpl.html
11//
12/////////////////////////////////////////////////////////
13
14/********************************************************
15
16        FILE: include/imap.inc
17        PURPOSE:
18                Provide alternative IMAP library that doesn't rely on the standard
19                C-Client based version.  This allows IlohaMail to function regardless
20                of whether or not the PHP build it's running on has IMAP functionality
21                built-in.
22        USEAGE:
23                Function containing "_C_" in name require connection handler to be
24                passed as one of the parameters.  To obtain connection handler, use
25                iil_Connect()
26        VERSION:
27                IlohaMail-0.9-20050415
28        CHANGES:
29                File altered by Thomas Bruederli <roundcube@gmail.com>
30                to fit enhanced equirements by the RoundCube Webmail:
31                - Added list of server capabilites and check these before invoking commands
32                - Added junk flag to iilBasicHeader
33                - Enhanced error reporting on fsockopen()
34                - Additional parameter for SORT command
35                - Removed Call-time pass-by-reference because deprecated
36                - Parse charset from content-type in iil_C_FetchHeaders()
37                - Enhanced heaer sorting
38                - Pass message as reference in iil_C_Append (to save memory)
39                - Added BCC and REFERENCE to the list of headers to fetch in iil_C_FetchHeaders()
40                - Leave messageID unchanged in iil_C_FetchHeaders()
41                - Avoid stripslahes in iil_Connect()
42                - Added patch to iil_SortHeaders() by Richard Green
43                - Removed <br> from error messages (better for logging)
44                - Added patch to iil_C_Sort() enabling UID SORT commands
45                - Added function iil_C_ID2UID()
46                - Casting date parts in iil_StrToTime() to avoid mktime() warnings
47                - Removed some debuggers (echo ...)
48
49********************************************************/
50
51
52// changed path to work within roundcube webmail
53include_once("lib/icl_commons.inc");
54
55
56if (!$IMAP_USE_HEADER_DATE) $IMAP_USE_INTERNAL_DATE = true;
57$IMAP_MONTHS=array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
58$IMAP_SERVER_TZ = date('Z');
59
60$iil_error;
61$iil_errornum;
62$iil_selected;
63
64class iilConnection{
65        var $fp;
66        var $error;
67        var $errorNum;
68        var $selected;
69        var $message;
70        var $host;
71        var $cache;
72        var $uid_cache;
73        var $do_cache;
74        var $exists;
75        var $recent;
76        var $rootdir;
77        var $delimiter;
78        var $capability = array();
79}
80
81class iilBasicHeader{
82        var $id;
83        var $uid;
84        var $subject;
85        var $from;
86        var $to;
87        var $cc;
88        var $replyto;
89        var $in_reply_to;
90        var $date;
91        var $messageID;
92        var $size;
93        var $encoding;
94        var $ctype;
95        var $flags;
96        var $timestamp;
97        var $f;
98        var $seen;
99        var $deleted;
100        var $recent;
101        var $answered;
102        var $junk;
103        var $internaldate;
104        var $is_reply;
105}
106
107
108class iilThreadHeader{
109        var $id;
110        var $sbj;
111        var $irt;
112        var $mid;
113}
114
115
116function iil_xor($string, $string2){
117    $result = "";
118    $size = strlen($string);
119    for ($i=0; $i<$size; $i++) $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
120       
121    return $result;
122}
123
124function iil_ReadLine($fp, $size){
125        $line="";
126        if ($fp){
127                do{
128                        $buffer = fgets($fp, 2048);
129                        $line.=$buffer;
130                }while($buffer[strlen($buffer)-1]!="\n");
131        }
132        return $line;
133}
134
135function iil_MultLine($fp, $line){
136        $line = chop($line);
137        if (ereg('\{[0-9]+\}$', $line)){
138                $out = "";
139                preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a);
140                $bytes = $a[2][0];
141                while(strlen($out)<$bytes){
142                        $out.=chop(iil_ReadLine($fp, 1024));
143                }
144                $line = $a[1][0]."\"$out\"";
145        }
146        return $line;
147}
148
149function iil_ReadBytes($fp, $bytes){
150        $data = "";
151        $len = 0;
152        do{
153                $data.=fread($fp, $bytes-$len);
154                $len = strlen($data);
155        }while($len<$bytes);
156        return $data;
157}
158
159function iil_ReadReply($fp){
160        do{
161                $line = chop(trim(iil_ReadLine($fp, 1024)));
162        }while($line[0]=="*");
163       
164        return $line;
165}
166
167function iil_ParseResult($string){
168        $a=explode(" ", $string);
169        if (count($a) > 2){
170                if (strcasecmp($a[1], "OK")==0) return 0;
171                else if (strcasecmp($a[1], "NO")==0) return -1;
172                else if (strcasecmp($a[1], "BAD")==0) return -2;
173        }else return -3;
174}
175
176// check if $string starts with $match
177function iil_StartsWith($string, $match){
178        $len = strlen($match);
179        if ($len==0) return false;
180        if (strncmp($string, $match, $len)==0) return true;
181        else return false;
182}
183
184function iil_StartsWithI($string, $match){
185        $len = strlen($match);
186        if ($len==0) return false;
187        if (strncasecmp($string, $match, $len)==0) return true;
188        else return false;
189}
190
191
192function iil_C_Authenticate(&$conn, $user, $pass, $encChallenge){
193   
194    // initialize ipad, opad
195    for ($i=0;$i<64;$i++){
196        $ipad.=chr(0x36);
197        $opad.=chr(0x5C);
198    }
199    // pad $pass so it's 64 bytes
200    $padLen = 64 - strlen($pass);
201    for ($i=0;$i<$padLen;$i++) $pass .= chr(0);
202    // generate hash
203    $hash = md5(iil_xor($pass,$opad).pack("H*",md5(iil_xor($pass, $ipad).base64_decode($encChallenge))));
204    // generate reply
205    $reply = base64_encode($user." ".$hash);
206   
207    // send result, get reply
208    fputs($conn->fp, $reply."\r\n");
209    $line = iil_ReadLine($conn->fp, 1024);
210   
211    // process result
212    if (iil_ParseResult($line)==0){
213        $conn->error .= "";
214        $conn->errorNum = 0;
215        return $conn->fp;
216    }else{
217        $conn->error .= 'Authentication for '.$user.' failed (AUTH): "'.htmlspecialchars($line)."\"";
218        $conn->errorNum = -2;
219        return false;
220    }
221}
222
223function iil_C_Login(&$conn, $user, $password){
224
225    fputs($conn->fp, "a001 LOGIN $user \"$password\"\r\n");
226               
227        do{
228            $line = iil_ReadReply($conn->fp);
229        }while(!iil_StartsWith($line, "a001 "));
230    $a=explode(" ", $line);
231    if (strcmp($a[1],"OK")==0){
232        $result=$conn->fp;
233        $conn->error.="";
234        $conn->errorNum = 0;
235    }else{
236        $result=false;
237        fclose($conn->fp);
238        $conn->error .= 'Authentication for '.$user.' failed (LOGIN): "'.htmlspecialchars($line)."\"";
239        $conn->errorNum = -2;
240    }
241    return $result;
242}
243
244function iil_ParseNamespace2($str, &$i, $len=0, $l){
245        if (!$l) $str = str_replace("NIL", "()", $str);
246        if (!$len) $len = strlen($str);
247        $data = array();
248        $in_quotes = false;
249        $elem = 0;
250        for($i;$i<$len;$i++){
251                $c = (string)$str[$i];
252                if ($c=='(' && !$in_quotes){
253                        $i++;
254                        $data[$elem] = iil_ParseNamespace2($str, $i, $len, $l++);
255                        $elem++;
256                }else if ($c==')' && !$in_quotes) return $data;
257                else if ($c=="\\"){
258                        $i++;
259                        if ($in_quotes) $data[$elem].=$c.$str[$i];
260                }else if ($c=='"'){
261                        $in_quotes = !$in_quotes;
262                        if (!$in_quotes) $elem++;
263                }else if ($in_quotes){
264                        $data[$elem].=$c;
265                }
266        }
267        return $data;
268}
269
270function iil_C_NameSpace(&$conn){
271        global $my_prefs;
272       
273        if (!in_array('NAMESPACE', $conn->capability))
274          return false;
275       
276        if ($my_prefs["rootdir"]) return true;
277       
278        fputs($conn->fp, "ns1 NAMESPACE\r\n");
279        do{
280                $line = iil_ReadLine($conn->fp, 1024);
281                if (iil_StartsWith($line, "* NAMESPACE")){
282                        $i = 0;
283                        $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
284                }
285        }while(!iil_StartsWith($line, "ns1"));
286       
287        if (!is_array($data)) return false;
288       
289        $user_space_data = $data[0];
290        if (!is_array($user_space_data)) return false;
291       
292        $first_userspace = $user_space_data[0];
293        if (count($first_userspace)!=2) return false;
294       
295        $conn->rootdir = $first_userspace[0];
296        $conn->delimiter = $first_userspace[1];
297        $my_prefs["rootdir"] = substr($conn->rootdir, 0, -1);
298       
299        return true;
300
301}
302
303function iil_Connect($host, $user, $password){ 
304    global $iil_error, $iil_errornum;
305        global $ICL_SSL, $ICL_PORT;
306        global $IMAP_NO_CACHE;
307        global $my_prefs, $IMAP_USE_INTERNAL_DATE;
308       
309        $iil_error = "";
310        $iil_errornum = 0;
311       
312        //strip slashes
313        // $user = stripslashes($user);
314        // $password = stripslashes($password);
315       
316        //set auth method
317        $auth_method = "plain";
318        if (func_num_args() >= 4){
319                $auth_array = func_get_arg(3);
320                if (is_array($auth_array)) $auth_method = $auth_array["imap"];
321                if (empty($auth_method)) $auth_method = "plain";
322        }
323        $message = "INITIAL: $auth_method\n";
324               
325        $result = false;
326       
327        //initialize connection
328        $conn = new iilConnection;
329        $conn->error="";
330        $conn->errorNum=0;
331        $conn->selected="";
332        $conn->user = $user;
333        $conn->host = $host;
334        $conn->cache = array();
335        $conn->do_cache = (function_exists("cache_write")&&!$IMAP_NO_CACHE);
336        $conn->cache_dirty = array();
337       
338        if ($my_prefs['sort_field']=='INTERNALDATE') $IMAP_USE_INTERNAL_DATE = true;
339        else if ($my_prefs['sort_field']=='DATE') $IMAP_USE_INTERNAL_DATE = false;
340        //echo '<!-- conn sort_field: '.$my_prefs['sort_field'].' //-->';
341       
342        //check input
343        if (empty($host)) $iil_error .= "Invalid host\n";
344        if (empty($user)) $iil_error .= "Invalid user\n";
345        if (empty($password)) $iil_error .= "Invalid password\n";
346        if (!empty($iil_error)) return false;
347        if (!$ICL_PORT) $ICL_PORT = 143;
348       
349        //check for SSL
350        if ($ICL_SSL){
351                $host = "ssl://".$host;
352        }
353       
354        //open socket connection
355        $conn->fp = @fsockopen($host, $ICL_PORT, $errno, $errstr, 10);
356        if (!$conn->fp){
357        $iil_error = "Could not connect to $host at port $ICL_PORT: $errstr";
358        $iil_errornum = -1;
359                return false;
360        }
361
362        $iil_error.="Socket connection established\r\n";
363        $line=iil_ReadLine($conn->fp, 300);
364
365        if (strcasecmp($auth_method, "check")==0){
366                //check for supported auth methods
367               
368                //default to plain text auth
369                $auth_method = "plain";
370                       
371                //check for CRAM-MD5
372                fputs($conn->fp, "cp01 CAPABILITY\r\n");
373                do{
374                $line = trim(chop(iil_ReadLine($conn->fp, 100)));
375                $conn->message.="$line\n";
376                        $a = explode(" ", $line);
377                        if ($line[0]=="*"){
378                                while ( list($k, $w) = each($a) ){
379                                    if ($w!='*' && $w!='CAPABILITY')
380                                        $conn->capability[] = $w;
381                                        if ((strcasecmp($w, "AUTH=CRAM_MD5")==0)||
382                                                (strcasecmp($w, "AUTH=CRAM-MD5")==0)){
383                                                        $auth_method = "auth";
384                                                }
385                                }
386                        }
387                }while($a[0]!="cp01");
388        }
389
390        if (strcasecmp($auth_method, "auth")==0){
391                $conn->message.="Trying CRAM-MD5\n";
392                //do CRAM-MD5 authentication
393                fputs($conn->fp, "a000 AUTHENTICATE CRAM-MD5\r\n");
394                $line = trim(chop(iil_ReadLine($conn->fp, 1024)));
395                $conn->message.="$line\n";
396                if ($line[0]=="+"){
397                        $conn->message.='Got challenge: '.htmlspecialchars($line)."\n";
398                        //got a challenge string, try CRAM-5
399                        $result = iil_C_Authenticate($conn, $user, $password, substr($line,2));
400                        $conn->message.= "Tried CRAM-MD5: $result \n";
401                }else{
402                        $conn->message.='No challenge ('.htmlspecialchars($line)."), try plain\n";
403                        $auth = "plain";
404                }
405        }
406               
407        if ((!$result)||(strcasecmp($auth, "plain")==0)){
408                //do plain text auth
409                $result = iil_C_Login($conn, $user, $password);
410                $conn->message.="Tried PLAIN: $result \n";
411        }
412               
413        $conn->message .= $auth;
414                       
415        if ($result){
416                iil_C_Namespace($conn);
417                return $conn;
418        }else{
419                $iil_error = $conn->error;
420                $iil_errornum = $conn->errorNum;
421                return false;
422        }
423}
424
425function iil_Close(&$conn){
426        iil_C_WriteCache($conn);
427        if (@fputs($conn->fp, "I LOGOUT\r\n")){
428                fgets($conn->fp, 1024);
429                fclose($conn->fp);
430                $conn->fp = false;
431        }
432}
433
434function iil_ClearCache($user, $host){
435}
436
437
438function iil_C_WriteCache(&$conn){
439        //echo "<!-- doing iil_C_WriteCache //-->\n";
440        if (!$conn->do_cache) return false;
441       
442        if (is_array($conn->cache)){
443                while(list($folder,$data)=each($conn->cache)){
444                        if ($folder && is_array($data) && $conn->cache_dirty[$folder]){
445                                $key = $folder.".imap";
446                                $result = cache_write($conn->user, $conn->host, $key, $data, true);
447                                //echo "<!-- writing $key $data: $result //-->\n";
448                        }
449                }
450        }
451}
452
453function iil_C_EnableCache(&$conn){
454        $conn->do_cache = true;
455}
456
457function iil_C_DisableCache(&$conn){
458        $conn->do_cache = false;
459}
460
461function iil_C_LoadCache(&$conn, $folder){
462        if (!$conn->do_cache) return false;
463       
464        $key = $folder.".imap";
465        if (!is_array($conn->cache[$folder])){
466                $conn->cache[$folder] = cache_read($conn->user, $conn->host, $key);
467                $conn->cache_dirty[$folder] = false;
468        }
469}
470
471function iil_C_ExpireCachedItems(&$conn, $folder, $message_set){
472       
473        if (!$conn->do_cache) return;   //caching disabled
474        if (!is_array($conn->cache[$folder])) return;   //cache not initialized|empty
475        if (count($conn->cache[$folder])==0) return;    //cache not initialized|empty
476               
477        $uids = iil_C_FetchHeaderIndex($conn, $folder, $message_set, "UID");
478        $num_removed = 0;
479        if (is_array($uids)){
480                //echo "<!-- unsetting: ".implode(",",$uids)." //-->\n";
481                while(list($n,$uid)=each($uids)){
482                        unset($conn->cache[$folder][$uid]);
483                        //$conn->cache[$folder][$uid] = false;
484                        //$num_removed++;
485                }
486                $conn->cache_dirty[$folder] = true;
487
488                //echo '<!--'."\n";
489                //print_r($conn->cache);
490                //echo "\n".'//-->'."\n";
491        }else{
492                echo "<!-- failed to get uids: $message_set //-->\n";
493        }
494       
495        /*
496        if ($num_removed>0){
497                $new_cache;
498                reset($conn->cache[$folder]);
499                while(list($uid,$item)=each($conn->cache[$folder])){
500                        if ($item) $new_cache[$uid] = $conn->cache[$folder][$uid];
501                }
502                $conn->cache[$folder] = $new_cache;
503        }
504        */
505}
506
507function iil_ExplodeQuotedString($delimiter, $string){
508        $quotes=explode("\"", $string);
509        while ( list($key, $val) = each($quotes))
510                if (($key % 2) == 1)
511                        $quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
512        $string=implode("\"", $quotes);
513       
514        $result=explode($delimiter, $string);
515        while ( list($key, $val) = each($result) )
516                $result[$key] = str_replace("_!@!_", $delimiter, $result[$key]);
517       
518        return $result;
519}
520
521function iil_CheckForRecent($host, $user, $password, $mailbox){
522        if (empty($mailbox)) $mailbox="INBOX";
523       
524        $conn=iil_Connect($host, $user, $password, "plain");
525        $fp = $conn->fp;
526        if ($fp){
527                fputs($fp, "a002 EXAMINE \"$mailbox\"\r\n");
528                do{
529                        $line=chop(iil_ReadLine($fp, 300));
530                        $a=explode(" ", $line);
531                        if (($a[0]=="*") && (strcasecmp($a[2], "RECENT")==0))  $result=(int)$a[1];
532                }while (!iil_StartsWith($a[0],"a002"));
533
534                fputs($fp, "a003 LOGOUT\r\n");
535                fclose($fp);
536        }else $result=-2;
537       
538        return $result;
539}
540
541function iil_C_Select(&$conn, $mailbox){
542        $fp = $conn->fp;
543       
544        if (empty($mailbox)) return false;
545        if (strcmp($conn->selected, $mailbox)==0) return true;
546       
547        iil_C_LoadCache($conn, $mailbox);
548       
549        if (fputs($fp, "sel1 SELECT \"$mailbox\"\r\n")){
550                do{
551                        $line=chop(iil_ReadLine($fp, 300));
552                        $a=explode(" ", $line);
553                        if (count($a) == 3){
554                                if (strcasecmp($a[2], "EXISTS")==0) $conn->exists=(int)$a[1];
555                                if (strcasecmp($a[2], "RECENT")==0) $conn->recent=(int)$a[1];
556                        }
557                }while (!iil_StartsWith($line, "sel1"));
558
559                $a=explode(" ", $line);
560
561                if (strcasecmp($a[1],"OK")==0){
562                        $conn->selected = $mailbox;
563                        return true;
564                }else return false;
565        }else{
566                return false;
567        }
568}
569
570function iil_C_CheckForRecent(&$conn, $mailbox){
571        if (empty($mailbox)) $mailbox="INBOX";
572       
573        iil_C_Select($conn, $mailbox);
574        if ($conn->selected==$mailbox) return $conn->recent;
575        else return false;
576}
577
578function iil_C_CountMessages(&$conn, $mailbox, $refresh=false){
579        if ($refresh) $conn->selected="";
580        iil_C_Select($conn, $mailbox);
581        if ($conn->selected==$mailbox) return $conn->exists;
582        else return false;
583}
584
585function iil_SplitHeaderLine($string){
586        $pos=strpos($string, ":");
587        if ($pos>0){
588                $res[0]=substr($string, 0, $pos);
589                $res[1]=trim(substr($string, $pos+1));
590                return $res;
591        }else{
592                return $string;
593        }
594}
595
596function iil_StrToTime($str){
597        global $IMAP_MONTHS,$IMAP_SERVER_TZ;
598               
599        if ($str) $time1 = strtotime($str);
600        if ($time1 && $time1!=-1) return $time1-$IMAP_SERVER_TZ;
601       
602        //echo '<!--'.$str.'//-->';
603       
604        //replace double spaces with single space
605        $str = trim($str);
606        $str = str_replace("  ", " ", $str);
607       
608        //strip off day of week
609        $pos=strpos($str, " ");
610        if (!is_numeric(substr($str, 0, $pos))) $str = substr($str, $pos+1);
611
612        //explode, take good parts
613        $a=explode(" ",$str);
614        //$month_a=array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
615        $month_str=$a[1];
616        $month=$IMAP_MONTHS[$month_str];
617        $day=(int)$a[0];
618        $year=(int)$a[2];
619        $time=$a[3];
620        $tz_str = $a[4];
621        $tz = substr($tz_str, 0, 3);
622        $ta = explode(":",$time);
623        $hour=(int)$ta[0]-(int)$tz;
624        $minute=(int)$ta[1];
625        $second=(int)$ta[2];
626       
627        //make UNIX timestamp
628        $time2 = mktime($hour, $minute, $second, $month, $day, $year);
629        //echo '<!--'.$time1.' '.$time2.' //-->'."\n";
630        return $time2;
631}
632
633function iil_C_Sort(&$conn, $mailbox, $field, $add='', $is_uid=FALSE, $encoding='US-ASCII'){
634        /*  Do "SELECT" command */
635        if (!iil_C_Select($conn, $mailbox)) return false;
636       
637        $field = strtoupper($field);
638        if ($field=='INTERNALDATE') $field='ARRIVAL';
639        $fields = array('ARRIVAL'=>1,'CC'=>1,'DATE'=>1,'FROM'=>1,'SIZE'=>1,'SUBJECT'=>1,'TO'=>1);
640       
641        if (!$fields[$field])
642          return false;
643       
644        $is_uid = $is_uid ? 'UID ' : '';
645       
646        if (!empty($add))
647          $add = " $add";
648
649        $fp = $conn->fp;
650        $command = 's '. $is_uid .'SORT ('.$field.') '.$encoding.' ALL'."$add\r\n";
651        $line = $data = '';
652       
653        if (!fputs($fp, $command)) return false;
654        do{
655                $line = chop(iil_ReadLine($fp, 1024));
656                if (iil_StartsWith($line, '* SORT')) $data.=($data?' ':'').substr($line,7);
657        }while($line[0]!='s');
658       
659        if (empty($data)){
660                $conn->error = $line;
661                return false;
662        }
663       
664        $out = explode(' ',$data);
665        return $out;
666}
667
668function iil_C_FetchHeaderIndex(&$conn, $mailbox, $message_set, $index_field, $normalize=true){
669        global $IMAP_USE_INTERNAL_DATE;
670       
671        $c=0;
672        $result=array();
673        $fp = $conn->fp;
674               
675        if (empty($index_field)) $index_field="DATE";
676        $index_field = strtoupper($index_field);
677       
678        if ((empty($message_set)) || ($message_set == "1:0")) return array();
679       
680        //$fields_a["DATE"] = ($IMAP_USE_INTERNAL_DATE?6:1);
681        $fields_a['DATE'] = 1;
682        $fields_a['INTERNALDATE'] = 6;
683        $fields_a['FROM'] = 1;
684        $fields_a['REPLY-TO'] = 1;
685        $fields_a['SENDER'] = 1;
686        $fields_a['TO'] = 1;
687        $fields_a['SUBJECT'] = 1;
688        $fields_a['UID'] = 2;
689        $fields_a['SIZE'] = 2;
690        $fields_a['SEEN'] = 3;
691        $fields_a['RECENT'] = 4;
692        $fields_a['DELETED'] = 5;
693       
694        $mode=$fields_a[$index_field];
695        if (!($mode > 0)) return false;
696       
697        /*  Do "SELECT" command */
698        if (!iil_C_Select($conn, $mailbox)) return false;
699               
700        /* FETCH date,from,subject headers */
701        if ($mode==1){
702                $key="fhi".($c++);
703                $request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)])\r\n";
704                if (!fputs($fp, $request)) return false;
705                do{
706                       
707                        $line=chop(iil_ReadLine($fp, 200));
708                        $a=explode(" ", $line);
709                        if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
710                                $id=$a[1];
711
712                                $str=$line=chop(iil_ReadLine($fp, 300));
713
714                                while($line[0]!=")"){                                   //caution, this line works only in this particular case
715                                        $line=chop(iil_ReadLine($fp, 300));
716                                        if ($line[0]!=")"){
717                                                if (ord($line[0]) <= 32){                       //continuation from previous header line
718                                                        $str.=" ".trim($line);
719                                                }
720                                                if ((ord($line[0]) > 32) || (strlen($line[0]) == 0)){
721                                                        list($field, $string) = iil_SplitHeaderLine($str);
722                                                        if (strcasecmp($field, "date")==0){
723                                                                $result[$id]=iil_StrToTime($string);
724                                                        }else{
725                                                                $result[$id] = str_replace("\"", "", $string);
726                                                                if ($normalize) $result[$id]=strtoupper($result[$id]);
727                                                        }
728                                                        $str=$line;
729                                                }
730                                        }
731                                }
732                        }
733                        /*
734                        $end_pos = strlen($line)-1;
735                        if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[$end_pos]=="}")){
736                                $id = $a[1];
737                                $pos = strrpos($line, "{")+1;
738                                $bytes = (int)substr($line, $pos, $end_pos-$pos);
739                                $received = 0;
740                                do{
741                                        $line = iil_ReadLine($fp, 0);
742                                        $received+=strlen($line);
743                                        $line = chop($line);
744                                       
745                                        if ($received>$bytes) break;
746                                        else if (!$line) continue;
747                                       
748                                        list($field,$string)=explode(": ", $line);
749                                       
750                                        if (strcasecmp($field, "date")==0)
751                                                $result[$id] = iil_StrToTime($string);
752                                        else if ($index_field!="DATE")
753                                                $result[$id]=strtoupper(str_replace("\"", "", $string));
754                                }while($line[0]!=")");
755                        }else{
756                                //one line response, not expected so ignore                             
757                        }
758                        */
759                }while(!iil_StartsWith($line, $key));
760        }else if ($mode==6){
761                $key="fhi".($c++);
762                $request = $key." FETCH $message_set (INTERNALDATE)\r\n";
763                if (!fputs($fp, $request)) return false;
764                do{
765                        $line=chop(iil_ReadLine($fp, 200));
766                        if ($line[0]=="*"){
767                                //original: "* 10 FETCH (INTERNALDATE "31-Jul-2002 09:18:02 -0500")"
768                                $paren_pos = strpos($line, "(");
769                                $foo = substr($line, 0, $paren_pos);
770                                $a = explode(" ", $foo);
771                                $id = $a[1];
772                               
773                                $open_pos = strpos($line, "\"") + 1;
774                                $close_pos = strrpos($line, "\"");
775                                if ($open_pos && $close_pos){
776                                        $len = $close_pos - $open_pos;
777                                        $time_str = substr($line, $open_pos, $len);
778                                        $result[$id] = strtotime($time_str);
779                                }
780                        }else{
781                                $a = explode(" ", $line);
782                        }
783                }while(!iil_StartsWith($a[0], $key));
784        }else{
785                if ($mode >= 3) $field_name="FLAGS";
786                else if ($index_field=="SIZE") $field_name="RFC822.SIZE";
787                else $field_name=$index_field;
788
789                /*                      FETCH uid, size, flags          */
790                $key="fhi".($c++);
791                $request=$key." FETCH $message_set ($field_name)\r\n";
792
793                if (!fputs($fp, $request)) return false;
794                do{
795                        $line=chop(iil_ReadLine($fp, 200));
796                        $a = explode(" ", $line);
797                        if (($line[0]=="*") && ($a[2]=="FETCH")){
798                                $line=str_replace("(", "", $line);
799                                $line=str_replace(")", "", $line);
800                                $a=explode(" ", $line);
801                               
802                                $id=$a[1];
803
804                                if (isset($result[$id])) continue; //if we already got the data, skip forward
805                                if ($a[3]!=$field_name) continue;  //make sure it's returning what we requested
806                       
807                                /*  Caution, bad assumptions, next several lines */
808                                if ($mode==2) $result[$id]=$a[4];
809                                else{
810                                        $haystack=strtoupper($line);
811                                        $result[$id]=(strpos($haystack, $index_field) > 0 ? "F" : "N");
812                                }
813                        }
814                }while(!iil_StartsWith($line, $key));
815        }
816
817        //check number of elements...
818        list($start_mid,$end_mid)=explode(':',$message_set);
819        if (is_numeric($start_mid) && is_numeric($end_mid)){
820                //count how many we should have
821                $should_have = $end_mid - $start_mid +1;
822               
823                //if we have less, try and fill in the "gaps"
824                if (count($result)<$should_have){
825                        for($i=$start_mid;$i<=$end_mid;$i++) if (!isset($result[$i])) $result[$i] = '';
826                }
827        }
828       
829        return $result;
830
831}
832
833function iil_CompressMessageSet($message_set){
834        //given a comma delimited list of independent mid's,
835        //compresses by grouping sequences together
836       
837        //if less than 255 bytes long, let's not bother
838        if (strlen($message_set)<255) return $message_set;
839       
840        //see if it's already been compress
841        if (strpos($message_set,':')!==false) return $message_set;
842       
843        //separate, then sort
844        $ids = explode(',',$message_set);
845        sort($ids);
846       
847        $result = array();
848        $start = $prev = $ids[0];
849        foreach($ids as $id){
850                $incr = $id - $prev;
851                if ($incr>1){                   //found a gap
852                        if ($start==$prev) $result[] = $prev;   //push single id
853                        else $result[] = $start.':'.$prev;              //push sequence as start_id:end_id
854                        $start = $id;                                                   //start of new sequence
855                }
856                $prev = $id;
857        }
858        //handle the last sequence/id
859        if ($start==$prev) $result[] = $prev;
860        else $result[] = $start.':'.$prev;
861
862        //return as comma separated string
863        return implode(',',$result);
864}
865
866function iil_C_UIDsToMIDs(&$conn, $mailbox, $uids){
867        if (!is_array($uids) || count($uids)==0) return array();
868        return iil_C_Search($conn, $mailbox, "UID ".implode(",", $uids));
869}
870
871function iil_C_UIDToMID(&$conn, $mailbox, $uid){
872        $result = iil_C_UIDsToMIDs($conn, $mailbox, array($uid));
873        if (count($result)==1) return $result[0];
874        else return false;
875}
876
877function iil_C_FetchUIDs(&$conn,$mailbox){
878        global $clock;
879       
880        $num = iil_C_CountMessages($conn, $mailbox);
881        if ($num==0) return array();
882        $message_set = '1'.($num>1?':'.$num:'');
883       
884        //if cache not enabled, just call iil_C_FetchHeaderIndex on 'UID' field
885        if (!$conn->do_cache)
886                return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
887
888        //otherwise, let's check cache first
889        $key = $mailbox.'.uids';
890        $cache_good = true;
891        if ($conn->uid_cache) $data = $conn->uid_cache;
892        else $data = cache_read($conn->user, $conn->host, $key);
893       
894        //was anything cached at all?
895        if ($data===false) $cache_good = -1;
896       
897        //make sure number of messages were the same
898        if ($cache_good>0 && $data['n']!=$num) $cache_good = -2;
899       
900        //if everything's okay so far...
901        if ($cache_good>0){
902                //check UIDs of highest mid with current and cached
903                $temp = iil_C_Search($conn, $mailbox, 'UID '.$data['d'][$num]);
904                if (!$temp || !is_array($temp) || $temp[0]!=$num) $cache_good=-3;
905        }
906
907        //if cached data's good, return it
908        if ($cache_good>0){
909                return $data['d'];
910        }
911
912        //otherwise, we need to fetch it
913        $data = array('n'=>$num,'d'=>array());
914        $data['d'] = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
915        cache_write($conn->user, $conn->host, $key, $data);
916        $conn->uid_cache = $data;
917        return $data['d'];
918}
919
920function iil_SortThreadHeaders($headers, $index_a, $uids){
921        asort($index_a);
922        $result = array();
923        foreach($index_a as $mid=>$foobar){
924                $uid = $uids[$mid];
925                $result[$uid] = $headers[$uid];
926        }
927        return $result;
928}
929
930function iil_C_FetchThreadHeaders(&$conn, $mailbox, $message_set){
931        global $clock;
932        global $index_a;
933       
934        if (empty($message_set)) return false;
935
936        $result = array();
937        $uids = iil_C_FetchUIDs($conn, $mailbox);
938        $debug = false;
939       
940        /* Get cached records where possible */
941        if ($conn->do_cache){
942                $cached = cache_read($conn->user, $conn->host, $mailbox.'.thhd');
943                if ($cached && is_array($uids) && count($uids)>0){
944                        $needed_set = "";
945                        foreach($uids as $id=>$uid){
946                                if ($cached[$uid]){
947                                        $result[$uid] = $cached[$uid];
948                                        $result[$uid]->id = $id;
949                                }else $needed_set.=($needed_set?",":"").$id;
950                        }
951                        if ($needed_set) $message_set = $needed_set;
952                        else $message_set = '';
953                }
954        }
955        $message_set = iil_CompressMessageSet($message_set);
956        if ($debug) echo "Still need: ".$message_set;
957       
958        /* if we're missing any, get them */
959        if ($message_set){
960                /* FETCH date,from,subject headers */
961                $key="fh";
962                $fp = $conn->fp;
963                $request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS (SUBJECT MESSAGE-ID IN-REPLY-TO)])\r\n";
964                $mid_to_id = array();
965                if (!fputs($fp, $request)) return false;
966                do{
967                        $line = chop(iil_ReadLine($fp, 1024));
968                        if ($debug) echo $line."\n";
969                        if (ereg('\{[0-9]+\}$', $line)){
970                                $a = explode(" ", $line);
971                                $new = array();
972
973                                $new_thhd = new iilThreadHeader;
974                                $new_thhd->id = $a[1];
975                                do{
976                                        $line=chop(iil_ReadLine($fp, 1024),"\r\n");
977                                        if (iil_StartsWithI($line,'Message-ID:') || (iil_StartsWithI($line,'In-Reply-To:')) || (iil_StartsWithI($line,'SUBJECT:'))){
978                                                $pos = strpos($line, ":");
979                                                $field_name = substr($line, 0, $pos);
980                                                $field_val = substr($line, $pos+1);
981                                                $new[strtoupper($field_name)] = trim($field_val);
982                                        }else if (ereg('^[[:space:]]', $line)){
983                                                $new[strtoupper($field_name)].= trim($line);
984                                        }
985                                }while($line[0]!=')');
986                                $new_thhd->sbj = $new['SUBJECT'];
987                                $new_thhd->mid = substr($new['MESSAGE-ID'], 1, -1);
988                                $new_thhd->irt = substr($new['IN-REPLY-TO'], 1, -1);
989                               
990                                $result[$uids[$new_thhd->id]] = $new_thhd;
991                        }
992                }while(!iil_StartsWith($line, "fh"));
993        }
994       
995        /* sort headers */
996        if (is_array($index_a)){
997                $result = iil_SortThreadHeaders($result, $index_a, $uids);     
998        }
999       
1000        /* write new set to cache */
1001        if ($conn->do_cache){
1002                if (count($result)!=count($cached))
1003                        cache_write($conn->user, $conn->host, $mailbox.'.thhd', $result);               
1004        }
1005       
1006        //echo 'iil_FetchThreadHeaders:'."\n";
1007        //print_r($result);
1008       
1009        return $result;
1010}
1011
1012function iil_C_BuildThreads2(&$conn, $mailbox, $message_set, &$clock){
1013        global $index_a;
1014
1015        if (empty($message_set)) return false;
1016       
1017        $result=array();
1018        $roots=array();
1019        $root_mids = array();
1020        $sub_mids = array();
1021        $strays = array();
1022        $messages = array();
1023        $fp = $conn->fp;
1024        $debug = false;
1025       
1026        $sbj_filter_pat = '[a-zA-Z]{2,3}(\[[0-9]*\])?:([[:space:]]*)';
1027       
1028        /*  Do "SELECT" command */
1029        if (!iil_C_Select($conn, $mailbox)) return false;
1030
1031        /* FETCH date,from,subject headers */
1032        $mid_to_id = array();
1033        $messages = array();
1034        $headers = iil_C_FetchThreadHeaders($conn, $mailbox, $message_set);
1035        if ($clock) $clock->register('fetched headers');
1036       
1037        if ($debug) print_r($headers);
1038       
1039        /* go through header records */
1040        foreach($headers as $header){
1041                //$id = $header['i'];
1042                //$new = array('id'=>$id, 'MESSAGE-ID'=>$header['m'],
1043                //                      'IN-REPLY-TO'=>$header['r'], 'SUBJECT'=>$header['s']);
1044                $id = $header->id;
1045                $new = array('id'=>$id, 'MESSAGE-ID'=>$header->mid,
1046                                        'IN-REPLY-TO'=>$header->irt, 'SUBJECT'=>$header->sbj);
1047
1048                /* add to message-id -> mid lookup table */
1049                $mid_to_id[$new['MESSAGE-ID']] = $id;
1050               
1051                /* if no subject, use message-id */
1052                if (empty($new['SUBJECT'])) $new['SUBJECT'] = $new['MESSAGE-ID'];
1053               
1054                /* if subject contains 'RE:' or has in-reply-to header, it's a reply */
1055                $sbj_pre ='';
1056                $has_re = false;
1057                if (eregi($sbj_filter_pat, $new['SUBJECT'])) $has_re = true;
1058                if ($has_re||$new['IN-REPLY-TO']) $sbj_pre = 'RE:';
1059               
1060                /* strip out 're:', 'fw:' etc */
1061                if ($has_re) $sbj = ereg_replace($sbj_filter_pat,'', $new['SUBJECT']);
1062                else $sbj = $new['SUBJECT'];
1063                $new['SUBJECT'] = $sbj_pre.$sbj;
1064               
1065               
1066                /* if subject not a known thread-root, add to list */
1067                if ($debug) echo $id.' '.$new['SUBJECT']."\t".$new['MESSAGE-ID']."\n";
1068                $root_id = $roots[$sbj];
1069               
1070                if ($root_id && ($has_re || !$root_in_root[$root_id])){
1071                        if ($debug) echo "\tfound root: $root_id\n";
1072                        $sub_mids[$new['MESSAGE-ID']] = $root_id;
1073                        $result[$root_id][] = $id;
1074                }else if (!isset($roots[$sbj])||(!$has_re&&$root_in_root[$root_id])){
1075                        /* try to use In-Reply-To header to find root
1076                                unless subject contains 'Re:' */
1077                        if ($has_re&&$new['IN-REPLY-TO']){
1078                                if ($debug) echo "\tlooking: ".$new['IN-REPLY-TO']."\n";
1079                               
1080                                //reply to known message?
1081                                $temp = $sub_mids[$new['IN-REPLY-TO']];
1082                               
1083                                if ($temp){
1084                                        //found it, root:=parent's root
1085                                        if ($debug) echo "\tfound parent: ".$new['SUBJECT']."\n";
1086                                        $result[$temp][] = $id;
1087                                        $sub_mids[$new['MESSAGE-ID']] = $temp;
1088                                        $sbj = '';
1089                                }else{
1090                                        //if we can't find referenced parent, it's a "stray"
1091                                        $strays[$id] = $new['IN-REPLY-TO'];
1092                                }
1093                        }
1094                       
1095                        //add subject as root
1096                        if ($sbj){
1097                                if ($debug) echo "\t added to root\n";
1098                                $roots[$sbj] = $id;
1099                                $root_in_root[$id] = !$has_re;
1100                                $sub_mids[$new['MESSAGE-ID']] = $id;
1101                                $result[$id] = array($id);
1102                        }
1103                        if ($debug) echo $new['MESSAGE-ID']."\t".$sbj."\n";
1104                }
1105                       
1106        }
1107       
1108        //now that we've gone through all the messages,
1109        //go back and try and link up the stray threads
1110        if (count($strays)>0){
1111                foreach($strays as $id=>$irt){
1112                        $root_id = $sub_mids[$irt];
1113                        if (!$root_id || $root_id==$id) continue;
1114                        $result[$root_id] = array_merge($result[$root_id],$result[$id]);
1115                        unset($result[$id]);
1116                }
1117        }
1118       
1119        if ($clock) $clock->register('data prepped');
1120       
1121        if ($debug) print_r($roots);
1122        //print_r($result);
1123        return $result;
1124}
1125
1126
1127function iil_SortThreads(&$tree, $index, $sort_order='ASC'){
1128        if (!is_array($tree) || !is_array($index)) return false;
1129
1130        //create an id to position lookup table
1131        $i = 0;
1132        foreach($index as $id=>$val){
1133                $i++;
1134                $index[$id] = $i;
1135        }
1136        $max = $i+1;
1137       
1138        //for each tree, set array key to position
1139        $itree = array();
1140        foreach($tree as $id=>$node){
1141                if (count($tree[$id])<=1){
1142                        //for "threads" with only one message, key is position of that message
1143                        $n = $index[$id];
1144                        $itree[$n] = array($n=>$id);
1145                }else{
1146                        //for "threads" with multiple messages,
1147                        $min = $max;
1148                        $new_a = array();
1149                        foreach($tree[$id] as $mid){
1150                                $new_a[$index[$mid]] = $mid;            //create new sub-array mapping position to id
1151                                $pos = $index[$mid];
1152                                if ($pos&&$pos<$min) $min = $index[$mid];       //find smallest position
1153                        }
1154                        $n = $min;      //smallest position of child is thread position
1155                       
1156                        //assign smallest position to root level key
1157                        //set children array to one created above
1158                        ksort($new_a);
1159                        $itree[$n] = $new_a;
1160                }
1161        }
1162       
1163       
1164        //sort by key, this basically sorts all threads
1165        ksort($itree);
1166        $i=0;
1167        $out=array();
1168        foreach($itree as $k=>$node){
1169                $out[$i] = $itree[$k];
1170                $i++;
1171        }
1172       
1173        //return
1174        return $out;
1175}
1176
1177function iil_IndexThreads(&$tree){
1178        /* creates array mapping mid to thread id */
1179       
1180        if (!is_array($tree)) return false;
1181       
1182        $t_index = array();
1183        foreach($tree as $pos=>$kids){
1184                foreach($kids as $kid) $t_index[$kid] = $pos;
1185        }
1186       
1187        return $t_index;
1188}
1189
1190function iil_C_FetchHeaders(&$conn, $mailbox, $message_set){
1191        global $IMAP_USE_INTERNAL_DATE;
1192       
1193        $c=0;
1194        $result=array();
1195        $fp = $conn->fp;
1196       
1197        if (empty($message_set)) return array();
1198       
1199        /*  Do "SELECT" command */
1200        if (!iil_C_Select($conn, $mailbox)){
1201                $conn->error = "Couldn't select $mailbox";
1202                return false;
1203        }
1204               
1205        /* Get cached records where possible */
1206        if ($conn->do_cache){
1207                $uids = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, "UID");
1208                if (is_array($uids) && count($conn->cache[$mailbox]>0)){
1209                        $needed_set = "";
1210                        while(list($id,$uid)=each($uids)){
1211                                if ($conn->cache[$mailbox][$uid]){
1212                                        $result[$id] = $conn->cache[$mailbox][$uid];
1213                                        $result[$id]->id = $id;
1214                                }else $needed_set.=($needed_set?",":"").$id;
1215                        }
1216                        //echo "<!-- iil_C_FetchHeader\nMessage Set: $message_set\nNeeded Set:$needed_set\n//-->\n";
1217                        if ($needed_set) $message_set = iil_CompressMessageSet($needed_set);
1218                        else return $result;
1219                }
1220        }
1221
1222        /* FETCH date,from,subject headers */
1223        $key="fh".($c++);
1224        $request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT REPLY-TO IN-REPLY-TO CC BCC CONTENT-TRANSFER-ENCODING CONTENT-TYPE MESSAGE-ID REFERENCE)])\r\n";
1225
1226        if (!fputs($fp, $request)) return false;
1227        do{
1228                $line=chop(iil_ReadLine($fp, 200));
1229                $a=explode(" ", $line);
1230                if (($line[0]=="*") && ($a[2]=="FETCH")){
1231                        $id=$a[1];
1232                        $result[$id]=new iilBasicHeader;
1233                        $result[$id]->id = $id;
1234                        $result[$id]->subject = "";
1235                        /*
1236                                Start parsing headers.  The problem is, some header "lines" take up multiple lines.
1237                                So, we'll read ahead, and if the one we're reading now is a valid header, we'll
1238                                process the previous line.  Otherwise, we'll keep adding the strings until we come
1239                                to the next valid header line.
1240                        */
1241                        $i = 0;
1242                        $lines = array();
1243                        do{
1244                                $line = chop(iil_ReadLine($fp, 300),"\r\n");
1245                                if (ord($line[0])<=32) $lines[$i].=(empty($lines[$i])?"":"\n").trim(chop($line));
1246                                else{
1247                                        $i++;
1248                                        $lines[$i] = trim(chop($line));
1249                                }
1250                        }while($line[0]!=")" && strncmp($line, $key, strlen($key)));  // patch from "Maksim Rubis" <siburny@hotmail.com>
1251                       
1252            if(strncmp($line, $key, strlen($key)))
1253            {
1254                        //process header, fill iilBasicHeader obj.
1255                        //      initialize
1256                        if (is_array($headers)){
1257                                reset($headers);
1258                                while ( list($k, $bar) = each($headers) ) $headers[$k] = "";
1259                        }
1260
1261                        //      create array with header field:data
1262                        $headers = array();
1263                        while ( list($lines_key, $str) = each($lines) ){
1264                                list($field, $string) = iil_SplitHeaderLine($str);
1265                                $field = strtolower($field);
1266                                $headers[$field] = $string;
1267                        }
1268                        $result[$id]->date = $headers["date"];
1269                        $result[$id]->timestamp = iil_StrToTime($headers["date"]);
1270                        $result[$id]->from = $headers["from"];
1271                        $result[$id]->to = str_replace("\n", " ", $headers["to"]);
1272                        $result[$id]->subject = str_replace("\n", "", $headers["subject"]);
1273                        $result[$id]->replyto = str_replace("\n", " ", $headers["reply-to"]);
1274                        $result[$id]->cc = str_replace("\n", " ", $headers["cc"]);
1275                        $result[$id]->bcc = str_replace("\n", " ", $headers["bcc"]);
1276                        $result[$id]->encoding = str_replace("\n", " ", $headers["content-transfer-encoding"]);
1277                        $result[$id]->ctype = str_replace("\n", " ", $headers["content-type"]);
1278                        $result[$id]->in_reply_to = ereg_replace("[\n<>]",'', $headers['in-reply-to']);
1279                        $result[$id]->reference = $headers["reference"];
1280                       
1281                        list($result[$id]->ctype, $ctype_add) = explode(";", $headers["content-type"]);
1282
1283                        if (preg_match('/charset="?([a-z0-9\-]+)"?/i', $ctype_add, $regs))
1284                                $result[$id]->charset = $regs[1];
1285
1286                        $messageID = $headers["message-id"];
1287                        if (!$messageID) "mid:".$id;
1288                        $result[$id]->messageID = $messageID;
1289                        }
1290            else {
1291            $a=explode(" ", $line);
1292            }
1293                       
1294                }
1295        }while(strcmp($a[0], $key)!=0);
1296               
1297        /*
1298                FETCH uid, size, flags
1299                Sample reply line: "* 3 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen \Deleted))"
1300        */
1301        $command_key="fh".($c++);
1302        $request= $command_key." FETCH $message_set (UID RFC822.SIZE FLAGS INTERNALDATE)\r\n";
1303        if (!fputs($fp, $request)) return false;
1304        do{
1305                $line=chop(iil_ReadLine($fp, 200));
1306                //$a = explode(" ", $line);
1307                //if (($line[0]=="*") && ($a[2]=="FETCH")){
1308                if ($line[0]=="*"){
1309                        //echo "<!-- $line //-->\n";
1310                        //get outter most parens
1311                        $open_pos = strpos($line, "(") + 1;
1312                        $close_pos = strrpos($line, ")");
1313                        if ($open_pos && $close_pos){
1314                                //extract ID from pre-paren
1315                                $pre_str = substr($line, 0, $open_pos);
1316                                $pre_a = explode(" ", $line);
1317                                $id = $pre_a[1];
1318                               
1319                                //get data
1320                                $len = $close_pos - $open_pos;
1321                                $str = substr($line, $open_pos, $len);
1322                               
1323                                //swap parents with quotes, then explode
1324                                $str = eregi_replace("[()]", "\"", $str);
1325                                $a = iil_ExplodeQuotedString(" ", $str);
1326                               
1327                                //did we get the right number of replies?
1328                                $parts_count = count($a);
1329                                if ($parts_count>=8){
1330                                        for ($i=0;$i<$parts_count;$i=$i+2){
1331                                                if (strcasecmp($a[$i],"UID")==0) $result[$id]->uid=$a[$i+1];
1332                                                else if (strcasecmp($a[$i],"RFC822.SIZE")==0) $result[$id]->size=$a[$i+1];
1333                                                else if (strcasecmp($a[$i],"INTERNALDATE")==0) $time_str = $a[$i+1];
1334                                                else if (strcasecmp($a[$i],"FLAGS")==0) $flags_str = $a[$i+1];
1335                                        }
1336
1337                                        // process flags
1338                                        $flags_str = eregi_replace('[\\\"]', "", $flags_str);
1339                                        $flags_a = explode(" ", $flags_str);
1340                                        //echo "<!-- ID: $id FLAGS: ".implode(",", $flags_a)." //-->\n";
1341                                       
1342                                        $result[$id]->seen = false;
1343                                        $result[$id]->recent = false;
1344                                        $result[$id]->deleted = false;
1345                                        $result[$id]->answered = false;
1346                                        if (is_array($flags_a)){
1347                                                reset($flags_a);
1348                                                while (list($key,$val)=each($flags_a)){
1349                                                        if (strcasecmp($val,"Seen")==0) $result[$id]->seen = true;
1350                                                        else if (strcasecmp($val, "Deleted")==0) $result[$id]->deleted=true;
1351                                                        else if (strcasecmp($val, "Recent")==0) $result[$id]->recent = true;
1352                                                        else if (strcasecmp($val, "Answered")==0) $result[$id]->answered = true;
1353                                                }
1354                                                $result[$id]->flags=$flags_str;
1355                                        }
1356                       
1357                                        // if time is gmt...   
1358                                        $time_str = str_replace('GMT','+0000',$time_str);
1359                                       
1360                                        //get timezone
1361                                        $time_str = substr($time_str, 0, -1);
1362                                        $time_zone_str = substr($time_str, -5); //extract timezone
1363                                        $time_str = substr($time_str, 1, -6); //remove quotes
1364                                        $time_zone = (float)substr($time_zone_str, 1, 2); //get first two digits
1365                                        if ($time_zone_str[3]!='0') $time_zone += 0.5;  //handle half hour offset
1366                                        if ($time_zone_str[0]=="-") $time_zone = $time_zone * -1.0; //minus?
1367                                        $result[$id]->internaldate = $time_str;
1368                                       
1369                                        if ($IMAP_USE_INTERNAL_DATE){
1370                                                //calculate timestamp
1371                                                $timestamp = strtotime($time_str); //return's server's time
1372                                                $na_timestamp = $timestamp;
1373                                                $timestamp -= $time_zone * 3600; //compensate for tz, get GMT
1374                                                $result[$id]->timestamp = $timestamp;
1375                                        }
1376                                               
1377                                        if ($conn->do_cache){
1378                                                $uid = $result[$id]->uid;
1379                                                $conn->cache[$mailbox][$uid] = $result[$id];
1380                                                $conn->cache_dirty[$mailbox] = true;
1381                                        }
1382                                        //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";
1383                                }else{
1384                                        //echo "<!-- ERROR: $id : $str //-->\n";
1385                                }
1386                        }
1387                }
1388        }while(strpos($line, $command_key)===false);
1389               
1390        return $result;
1391}
1392
1393
1394function iil_C_FetchHeader(&$conn, $mailbox, $id){
1395        $fp = $conn->fp;
1396        $a=iil_C_FetchHeaders($conn, $mailbox, $id);
1397        if (is_array($a)) return $a[$id];
1398        else return false;
1399}
1400
1401
1402function iil_SortHeaders($a, $field, $flag){
1403        if (empty($field)) $field="uid";
1404        $field=strtolower($field);
1405        if ($field=="date"||$field=='internaldate') $field="timestamp";
1406        if (empty($flag)) $flag="ASC";
1407        $flag=strtoupper($flag);
1408        $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ',"\"") : array("\"");
1409
1410        $c=count($a);
1411        if ($c>0){
1412                /*
1413                        Strategy:
1414                        First, we'll create an "index" array.
1415                        Then, we'll use sort() on that array,
1416                        and use that to sort the main array.
1417                */
1418               
1419                // create "index" array
1420                $index=array();
1421                reset($a);
1422                while (list($key, $val)=each($a)){
1423
1424                        if ($field=="timestamp"){
1425                                $data = @strtotime($val->date);
1426                                if ($data == false)
1427                                        $data = $val->timestamp;
1428                                }
1429                        else {
1430                                $data = $val->$field;
1431                                if (is_string($data))
1432                                        $data=strtoupper(str_replace($stripArr, "", $data));
1433                                }
1434
1435                        $index[$key]=$data;
1436                }
1437               
1438                // sort index
1439                $i=0;
1440                if ($flag=="ASC") asort($index);
1441                else arsort($index);
1442               
1443                // form new array based on index
1444                $result=array();
1445                reset($index);
1446                while (list($key, $val)=each($index)){
1447                        $result[$key]=$a[$key];
1448                        $i++;
1449                }
1450        }
1451       
1452        return $result;
1453}
1454
1455function iil_C_Expunge(&$conn, $mailbox){
1456        $fp = $conn->fp;
1457        if (iil_C_Select($conn, $mailbox)){
1458                $c=0;
1459                fputs($fp, "exp1 EXPUNGE\r\n");
1460                do{
1461                        $line=chop(iil_ReadLine($fp, 100));
1462                        if ($line[0]=="*") $c++;
1463                }while (!iil_StartsWith($line, "exp1"));
1464               
1465                if (iil_ParseResult($line) == 0){
1466                        $conn->selected = ""; //state has changed, need to reselect                     
1467                        //$conn->exists-=$c;
1468                        return $c;
1469                }else{
1470                        $conn->error = $line;
1471                        return -1;
1472                }
1473        }
1474       
1475        return -1;
1476}
1477
1478function iil_C_ModFlag(&$conn, $mailbox, $messages, $flag, $mod){
1479        if ($mod!="+" && $mod!="-") return -1;
1480       
1481        $fp = $conn->fp;
1482        $flags=array(
1483                    "SEEN"=>"\\Seen",
1484                    "DELETED"=>"\\Deleted",
1485                    "RECENT"=>"\\Recent",
1486                    "ANSWERED"=>"\\Answered",
1487                    "DRAFT"=>"\\Draft",
1488                                        "FLAGGED"=>"\\Flagged"
1489                   );
1490        $flag=strtoupper($flag);
1491        $flag=$flags[$flag];
1492        if (iil_C_Select($conn, $mailbox)){
1493                $c=0;
1494                fputs($fp, "flg STORE $messages ".$mod."FLAGS (".$flag.")\r\n");
1495                do{
1496                        $line=chop(iil_ReadLine($fp, 100));
1497                        if ($line[0]=="*") $c++;
1498                }while (!iil_StartsWith($line, "flg"));
1499
1500                if (iil_ParseResult($line) == 0){
1501                        iil_C_ExpireCachedItems($conn, $mailbox, $messages);
1502                        return $c;
1503                }else{
1504                        $conn->error = $line;
1505                        return -1;
1506                }
1507        }else{
1508                $conn->error = "Select failed";
1509                return -1;
1510        }
1511}
1512
1513function iil_C_Flag(&$conn, $mailbox, $messages, $flag){
1514        return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "+");
1515}
1516
1517function iil_C_Unflag(&$conn, $mailbox, $messages, $flag){
1518        return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "-");
1519}
1520
1521function iil_C_Delete(&$conn, $mailbox, $messages){
1522        return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "+");
1523}
1524
1525function iil_C_Undelete(&$conn, $mailbox, $messages){
1526        return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "-");
1527}
1528
1529
1530function iil_C_Unseen(&$conn, $mailbox, $messages){
1531        return iil_C_ModFlag($conn, $mailbox, $messages, "SEEN", "-");
1532}
1533
1534
1535function iil_C_Copy(&$conn, $messages, $from, $to){
1536        $fp = $conn->fp;
1537
1538        if (empty($from) || empty($to)) return -1;
1539
1540        if (iil_C_Select($conn, $from)){
1541                $c=0;
1542               
1543                fputs($fp, "cpy1 COPY $messages \"$to\"\r\n");
1544                $line=iil_ReadReply($fp);
1545                return iil_ParseResult($line);
1546        }else{
1547                return -1;
1548        }
1549}
1550
1551function iil_FormatSearchDate($month, $day, $year){
1552        $month = (int)$month;
1553        $months=array(
1554                        1=>"Jan", 2=>"Feb", 3=>"Mar", 4=>"Apr",
1555                        5=>"May", 6=>"Jun", 7=>"Jul", 8=>"Aug",
1556                        9=>"Sep", 10=>"Oct", 11=>"Nov", 12=>"Dec"
1557                        );
1558        return $day."-".$months[$month]."-".$year;
1559}
1560
1561function iil_C_CountUnseen(&$conn, $folder){
1562        $index = iil_C_Search($conn, $folder, "ALL UNSEEN");
1563        if (is_array($index)){
1564                $str = implode(",", $index);
1565                if (empty($str)) return false;
1566                else return count($index);
1567        }else return false;
1568}
1569
1570function iil_C_UID2ID(&$conn, $folder, $uid){
1571        if ($uid > 0){
1572                $id_a = iil_C_Search($conn, $folder, "UID $uid");
1573                if (is_array($id_a)){
1574                        $count = count($id_a);
1575                        if ($count > 1) return false;
1576                        else return $id_a[0];
1577                }
1578        }
1579        return false;
1580}
1581
1582function iil_C_ID2UID(&$conn, $folder, $id){
1583        $fp = $conn->fp;
1584        $result=-1;
1585        if ($id > 0) {
1586                if (iil_C_Select($conn, $folder)){
1587                        $key = "FUID";
1588                        if (fputs($fp, "$key FETCH $id (UID)\r\n")){
1589                                do{
1590                                        $line=chop(iil_ReadLine($fp, 1024));
1591                                        if (eregi("^\* $id FETCH \(UID (.*)\)", $line, $r)){
1592                                                $result = $r[1];
1593                                        }
1594                                } while (!preg_match("/^$key/", $line));
1595                        }
1596                }
1597        }
1598        return $result;
1599}
1600
1601function iil_C_Search(&$conn, $folder, $criteria){
1602        $fp = $conn->fp;
1603        if (iil_C_Select($conn, $folder)){
1604                $c=0;
1605               
1606                $query = "srch1 SEARCH ".chop($criteria)."\r\n";
1607                fputs($fp, $query);
1608                do{
1609                        $line=trim(chop(iil_ReadLine($fp, 10000)));
1610                        if (eregi("^\* SEARCH", $line)){
1611                                $str = trim(substr($line, 8));
1612                                $messages = explode(" ", $str);
1613                        }
1614                }while(!iil_StartsWith($line, "srch1"));
1615               
1616                $result_code=iil_ParseResult($line);
1617                if ($result_code==0) return $messages;
1618                else{
1619                        $conn->error = "iil_C_Search: ".$line."\n";
1620                        return false;
1621                }
1622               
1623        }else{
1624                $conn->error = "iil_C_Search: Couldn't select \"$folder\"\n";
1625                return false;
1626        }
1627}
1628
1629function iil_C_Move(&$conn, $messages, $from, $to){
1630        $fp = $conn->fp;
1631       
1632        if (!$from || !$to) return -1;
1633       
1634        $r=iil_C_Copy($conn, $messages, $from,$to);
1635        if ($r==0){
1636                return iil_C_Delete($conn, $from, $messages);
1637        }else{
1638                return $r;
1639        }
1640}
1641
1642function iil_C_GetHierarchyDelimiter(&$conn){
1643        if ($conn->delimiter) return $conn->delimiter;
1644       
1645        $fp = $conn->fp;
1646        $delimiter = false;
1647       
1648        //try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
1649        if (!fputs($fp, "ghd LIST \"\" \"\"\r\n")) return false;
1650        do{
1651                $line=iil_ReadLine($fp, 500);
1652                if ($line[0]=="*"){
1653                        $line = rtrim($line);
1654                        $a=iil_ExplodeQuotedString(" ", $line);
1655                        if ($a[0]=="*") $delimiter = str_replace("\"", "", $a[count($a)-2]);
1656                }
1657        }while (!iil_StartsWith($line, "ghd"));
1658
1659        if (strlen($delimiter)>0) return $delimiter;
1660       
1661        //if that fails, try namespace extension
1662        //try to fetch namespace data
1663        fputs($conn->fp, "ns1 NAMESPACE\r\n");
1664        do{
1665                $line = iil_ReadLine($conn->fp, 1024);
1666                if (iil_StartsWith($line, "* NAMESPACE")){
1667                        $i = 0;
1668                        $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
1669                }
1670        }while(!iil_StartsWith($line, "ns1"));
1671               
1672        if (!is_array($data)) return false;
1673       
1674        //extract user space data (opposed to global/shared space)
1675        $user_space_data = $data[0];
1676        if (!is_array($user_space_data)) return false;
1677       
1678        //get first element
1679        $first_userspace = $user_space_data[0];
1680        if (!is_array($first_userspace)) return false;
1681
1682        //extract delimiter
1683        $delimiter = $first_userspace[1];       
1684
1685        return $delimiter;
1686}
1687
1688function iil_C_ListMailboxes(&$conn, $ref, $mailbox){
1689        global $IGNORE_FOLDERS;
1690       
1691        $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
1692               
1693        $fp = $conn->fp;
1694        if (empty($mailbox)) $mailbox="*";
1695        if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
1696       
1697    // send command
1698        if (!fputs($fp, "lmb LIST \"".$ref."\" \"$mailbox\"\r\n")) return false;
1699        $i=0;
1700    // get folder list
1701        do{
1702                $line=iil_ReadLine($fp, 500);
1703                $line=iil_MultLine($fp, $line);
1704
1705                $a = explode(" ", $line);
1706                if (($line[0]=="*") && ($a[1]=="LIST")){
1707                        $line = rtrim($line);
1708            // split one line
1709                        $a=iil_ExplodeQuotedString(" ", $line);
1710            // last string is folder name
1711                        $folder = str_replace("\"", "", $a[count($a)-1]);
1712            if (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder))) $folders[$i] = $folder;
1713            // second from last is delimiter
1714            $delim = str_replace("\"", "", $a[count($a)-2]);
1715            // is it a container?
1716            $i++;
1717                }
1718        }while (!iil_StartsWith($line, "lmb"));
1719
1720        if (is_array($folders)){
1721        if (!empty($ref)){
1722            // if rootdir was specified, make sure it's the first element
1723            // some IMAP servers (i.e. Courier) won't return it
1724            if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
1725            if ($folders[0]!=$ref) array_unshift($folders, $ref);
1726        }
1727        return $folders;
1728        }else if (iil_ParseResult($line)==0){
1729                return array('INBOX');
1730        }else{
1731                $conn->error = $line;
1732                return false;
1733        }
1734}
1735
1736
1737function iil_C_ListSubscribed(&$conn, $ref, $mailbox){
1738        global $IGNORE_FOLDERS;
1739       
1740        $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
1741       
1742        $fp = $conn->fp;
1743        if (empty($mailbox)) $mailbox = "*";
1744        if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
1745        $folders = array();
1746
1747    // send command
1748        if (!fputs($fp, "lsb LSUB \"".$ref."\" \"".$mailbox."\"\r\n")){
1749                $conn->error = "Couldn't send LSUB command\n";
1750                return false;
1751        }
1752        $i=0;
1753    // get folder list
1754        do{
1755                $line=iil_ReadLine($fp, 500);
1756                $line=iil_MultLine($fp, $line);
1757                $a = explode(" ", $line);
1758                if (($line[0]=="*") && ($a[1]=="LSUB" || $a[1]=="LIST")){
1759                        $line = rtrim($line);
1760            // split one line
1761                        $a=iil_ExplodeQuotedString(" ", $line);
1762            // last string is folder name
1763            //$folder = UTF7DecodeString(str_replace("\"", "", $a[count($a)-1]));
1764            $folder = str_replace("\"", "", $a[count($a)-1]);
1765                        if ((!in_array($folder, $folders)) && (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder)))) $folders[$i] = $folder;
1766            // second from last is delimiter
1767            $delim = str_replace("\"", "", $a[count($a)-2]);
1768            // is it a container?
1769            $i++;
1770                }
1771        }while (!iil_StartsWith($line, "lsb"));
1772
1773        if (is_array($folders)){
1774        if (!empty($ref)){
1775            // if rootdir was specified, make sure it's the first element
1776            // some IMAP servers (i.e. Courier) won't return it
1777            if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
1778            if ($folders[0]!=$ref) array_unshift($folders, $ref);
1779        }
1780        return $folders;
1781        }else{
1782                $conn->error = $line;
1783                return false;
1784        }
1785}
1786
1787
1788function iil_C_Subscribe(&$conn, $folder){
1789        $fp = $conn->fp;
1790
1791        $query = "sub1 SUBSCRIBE \"".$folder."\"\r\n";
1792        fputs($fp, $query);
1793        $line=trim(chop(iil_ReadLine($fp, 10000)));
1794        return iil_ParseResult($line);
1795}
1796
1797
1798function iil_C_UnSubscribe(&$conn, $folder){
1799        $fp = $conn->fp;
1800
1801        $query = "usub1 UNSUBSCRIBE \"".$folder."\"\r\n";
1802        fputs($fp, $query);
1803        $line=trim(chop(iil_ReadLine($fp, 10000)));
1804        return iil_ParseResult($line);
1805}
1806
1807
1808function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part){
1809        $fp = $conn->fp;
1810        $result=false;
1811        if (($part==0)||(empty($part))) $part="HEADER";
1812        else $part.=".MIME";
1813       
1814        if (iil_C_Select($conn, $mailbox)){
1815                $key="fh".($c++);
1816                $request=$key." FETCH $id (BODY.PEEK[$part])\r\n";
1817                if (!fputs($fp, $request)) return false;
1818                do{
1819                        $line=chop(iil_ReadLine($fp, 200));
1820                        $a=explode(" ", $line);
1821                        if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
1822                                $line=iil_ReadLine($fp, 300);
1823                                while(chop($line)!=")"){
1824                                        $result.=$line;
1825                                        $line=iil_ReadLine($fp, 300);
1826                                }
1827                        }
1828                }while(strcmp($a[0], $key)!=0);
1829        }
1830       
1831        return $result;
1832}
1833
1834
1835function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode){
1836    /* modes:
1837        1: return string
1838        2: print
1839        3: base64 and print
1840    */
1841        $fp = $conn->fp;
1842        $result=false;
1843        if (($part==0)||(empty($part))) $part="TEXT";
1844       
1845        if (iil_C_Select($conn, $mailbox)){
1846        $reply_key="* ".$id;
1847        // format request
1848                $key="ftch".($c++)." ";
1849                $request=$key."FETCH $id (BODY.PEEK[$part])\r\n";
1850        // send request
1851                if (!fputs($fp, $request)) return false;
1852        // receive reply line
1853        do{
1854            $line = chop(iil_ReadLine($fp, 1000));
1855            $a = explode(" ", $line);
1856        }while ($a[2]!="FETCH");
1857        $len = strlen($line);
1858        if ($line[$len-1] == ")"){
1859            //one line response, get everything between first and last quotes
1860            $from = strpos($line, "\"") + 1;
1861            $to = strrpos($line, "\"");
1862            $len = $to - $from;
1863            if ($mode==1) $result = substr($line, $from, $len);
1864            else if ($mode==2) echo substr($line, $from, $len);
1865            else if ($mode==3) echo base64_decode(substr($line, $from, $len));
1866        }else if ($line[$len-1] == "}"){
1867            //multi-line request, find sizes of content and receive that many bytes
1868            $from = strpos($line, "{") + 1;
1869            $to = strrpos($line, "}");
1870            $len = $to - $from;
1871            $sizeStr = substr($line, $from, $len);
1872            $bytes = (int)$sizeStr;
1873            $received = 0;
1874            while ($received < $bytes){
1875                $remaining = $bytes - $received;
1876                $line = iil_ReadLine($fp, 1024);
1877                $len = strlen($line);
1878                if ($len > $remaining) substr($line, 0, $remaining);
1879                $received += strlen($line);
1880                if ($mode==1) $result .= chop($line)."\n";
1881                else if ($mode==2){ echo chop($line)."\n"; flush(); }
1882                else if ($mode==3){ echo base64_decode($line); flush(); }
1883            }
1884        }
1885        // read in anything up until 'til last line
1886                do{
1887            $line = iil_ReadLine($fp, 1024);
1888                }while(!iil_StartsWith($line, $key));
1889       
1890        if ($result){
1891                        $result = chop($result);
1892            return $result; // substr($result, 0, strlen($result)-1);
1893        }else return false;
1894        }else{
1895                echo "Select failed.";
1896        }
1897   
1898    if ($mode==1) return $result;
1899    else return $received;
1900}
1901
1902function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part){
1903    return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
1904}
1905
1906function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part){
1907    iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
1908}
1909
1910function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part){
1911    iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
1912}
1913
1914function iil_C_CreateFolder(&$conn, $folder){
1915        $fp = $conn->fp;
1916        if (fputs($fp, "c CREATE \"".$folder."\"\r\n")){
1917                do{
1918                        $line=iil_ReadLine($fp, 300);
1919                }while($line[0]!="c");
1920        $conn->error = $line;
1921                return (iil_ParseResult($line)==0);
1922        }else{
1923                return false;
1924        }
1925}
1926
1927function iil_C_RenameFolder(&$conn, $from, $to){
1928        $fp = $conn->fp;
1929        if (fputs($fp, "r RENAME \"".$from."\" \"".$to."\"\r\n")){
1930                do{
1931                        $line=iil_ReadLine($fp, 300);
1932                }while($line[0]!="r");
1933                return (iil_ParseResult($line)==0);
1934        }else{
1935                return false;
1936        }       
1937}
1938
1939function iil_C_DeleteFolder(&$conn, $folder){
1940        $fp = $conn->fp;
1941        if (fputs($fp, "d DELETE \"".$folder."\"\r\n")){
1942                do{
1943                        $line=iil_ReadLine($fp, 300);
1944                }while($line[0]!="d");
1945                return (iil_ParseResult($line)==0);
1946        }else{
1947                $conn->error = "Couldn't send command\n";
1948                return false;
1949        }
1950}
1951
1952function iil_C_Append(&$conn, $folder, &$message){
1953        if (!$folder) return false;
1954        $fp = $conn->fp;
1955
1956        $message = str_replace("\r", "", $message);
1957        $message = str_replace("\n", "\r\n", $message);         
1958
1959        $len = strlen($message);
1960        if (!$len) return false;
1961       
1962        $request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
1963        if (fputs($fp, $request)){
1964                $line=iil_ReadLine($fp, 100);           
1965                $sent = fwrite($fp, $message."\r\n");
1966                flush();
1967                do{
1968                        $line=iil_ReadLine($fp, 1000);
1969                }while($line[0]!="A");
1970       
1971                $result = (iil_ParseResult($line)==0);
1972                if (!$result) $conn->error .= $line."\n";
1973                return $result;
1974       
1975        }else{
1976                $conn->error .= "Couldn't send command \"$request\"\n";
1977                return false;
1978        }
1979}
1980
1981
1982function iil_C_AppendFromFile(&$conn, $folder, $path){
1983        if (!$folder) return false;
1984       
1985        //open message file
1986        $in_fp = false;                         
1987        if (file_exists(realpath($path))) $in_fp = fopen($path, "r");
1988        if (!$in_fp){
1989                $conn->error .= "Couldn't open $path for reading\n";
1990                return false;
1991        }
1992       
1993        $fp = $conn->fp;
1994        $len = filesize($path);
1995        if (!$len) return false;
1996       
1997        //send APPEND command
1998        $request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
1999        $bytes_sent = 0;
2000        if (fputs($fp, $request)){
2001                $line=iil_ReadLine($fp, 100);
2002                               
2003                //send file
2004                while(!feof($in_fp)){
2005                        $buffer = fgets($in_fp, 4096);
2006                        $bytes_sent += strlen($buffer);
2007                        fputs($fp, $buffer);
2008                }
2009                fclose($in_fp);
2010
2011                fputs($fp, "\r\n");
2012
2013                //read response
2014                do{
2015                        $line=iil_ReadLine($fp, 1000);
2016                }while($line[0]!="A");
2017                       
2018                $result = (iil_ParseResult($line)==0);
2019                if (!$result) $conn->error .= $line."\n";
2020                return $result;
2021       
2022        }else{
2023                $conn->error .= "Couldn't send command \"$request\"\n";
2024                return false;
2025        }
2026}
2027
2028
2029function iil_C_FetchStructureString(&$conn, $folder, $id){
2030        $fp = $conn->fp;
2031        $result=false;
2032        if (iil_C_Select($conn, $folder)){
2033                $key = "F1247";
2034                if (fputs($fp, "$key FETCH $id (BODYSTRUCTURE)\r\n")){
2035                        do{
2036                                $line=chop(iil_ReadLine($fp, 5000));
2037                                if ($line[0]=="*"){
2038                                        if (ereg("\}$", $line)){
2039                                                preg_match('/(.+)\{([0-9]+)\}/', $line, $match); 
2040                                                $result = $match[1];
2041                                                do{
2042                                                        $line = chop(iil_ReadLine($fp, 100));
2043                                                        if (!preg_match("/^$key/", $line)) $result .= $line;
2044                                                        else $done = true;
2045                                                }while(!$done);
2046                                        }else{
2047                                                $result = $line;
2048                                        }
2049                                        list($pre, $post) = explode("BODYSTRUCTURE ", $result);
2050                                        $result = substr($post, 0, strlen($post)-1);            //truncate last ')' and return
2051                                }
2052                        }while (!preg_match("/^$key/",$line));
2053                }
2054        }
2055        return $result;
2056}
2057
2058function iil_C_PrintSource(&$conn, $folder, $id, $part){
2059        $header = iil_C_FetchPartHeader($conn, $folder, $id, $part);
2060        //echo str_replace("\r", "", $header);
2061        echo $header;
2062        echo iil_C_PrintPartBody($conn, $folder, $id, $part);
2063}
2064
2065function iil_C_GetQuota(&$conn){
2066/*
2067b GETQUOTAROOT "INBOX"
2068* QUOTAROOT INBOX user/rchijiiwa1
2069* QUOTA user/rchijiiwa1 (STORAGE 654 9765)
2070b OK Completed
2071*/
2072        $fp = $conn->fp;
2073        $result=false;
2074        $quota_line = "";
2075       
2076        //get line containing quota info
2077        if (fputs($fp, "QUOT1 GETQUOTAROOT \"INBOX\"\r\n")){
2078                do{
2079                        $line=chop(iil_ReadLine($fp, 5000));
2080                        if (iil_StartsWith($line, "* QUOTA ")) $quota_line = $line;
2081                }while(!iil_StartsWith($line, "QUOT1"));
2082        }
2083       
2084        //return false if not found, parse if found
2085        if (!empty($quota_line)){
2086                $quota_line = eregi_replace("[()]", "", $quota_line);
2087                $parts = explode(" ", $quota_line);
2088                $storage_part = array_search("STORAGE", $parts);
2089                if ($storage_part>0){
2090                        $result = array();
2091                        $used = $parts[$storage_part+1];
2092                        $total = $parts[$storage_part+2];
2093                        $result["used"] = $used;
2094                        $result["total"] = (empty($total)?"??":$total);
2095                        $result["percent"] = (empty($total)?"??":round(($used/$total)*100));
2096                        $result["free"] = 100 - $result["percent"];
2097                }
2098        }
2099       
2100        return $result;
2101}
2102
2103
2104function iil_C_ClearFolder(&$conn, $folder){
2105        $num_in_trash = iil_C_CountMessages($conn, $folder);
2106        if ($num_in_trash > 0) iil_C_Delete($conn, $folder, "1:".$num_in_trash);
2107        return (iil_C_Expunge($conn, $folder) >= 0);
2108}
2109
2110?>
Note: See TracBrowser for help on using the repository browser.