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