thomascube
2006-01-13 be2380fb47b05a222ec5b22deff36d5156a8c943
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
15a9d1 610 function iil_C_Sort(&$conn, $mailbox, $field, $add=''){
4e17e6 611     /*  Do "SELECT" command */
T 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;
15a9d1 621     $command = 's SORT ('.$field.') US-ASCII ALL '."$add\r\n";
T 622     //$command = 's SORT ('.$field.') US-ASCII ALL UNDELETED'."\r\n";
4e17e6 623     $line = $data = '';
T 624     
625     if (!fputs($fp, $command)) return false;
626     do{
627         $line = chop(iil_ReadLine($fp, 1024));
628         if (iil_StartsWith($line, '* SORT')) $data.=($data?' ':'').substr($line,7);
629     }while($line[0]!='s');
630     
631     if (empty($data)){
632         $conn->error = $line;
633         return false;
634     }
635     
636     $out = explode(' ',$data);
637     return $out;
638 }
639
640 function iil_C_FetchHeaderIndex(&$conn, $mailbox, $message_set, $index_field,$normalize=true){
641     global $IMAP_USE_INTERNAL_DATE;
642     
643     $c=0;
644     $result=array();
645     $fp = $conn->fp;
646         
647     if (empty($index_field)) $index_field="DATE";
648     $index_field = strtoupper($index_field);
649     
650     if (empty($message_set)) return array();
651     
652     //$fields_a["DATE"] = ($IMAP_USE_INTERNAL_DATE?6:1);
653     $fields_a['DATE'] = 1;
654     $fields_a['INTERNALDATE'] = 6;
655     $fields_a['FROM'] = 1;
656     $fields_a['REPLY-TO'] = 1;
657     $fields_a['SENDER'] = 1;
658     $fields_a['TO'] = 1;
659     $fields_a['SUBJECT'] = 1;
660     $fields_a['UID'] = 2;
661     $fields_a['SIZE'] = 2;
662     $fields_a['SEEN'] = 3;
663     $fields_a['RECENT'] = 4;
664     $fields_a['DELETED'] = 5;
665     
666     $mode=$fields_a[$index_field];
667     if (!($mode > 0)) return false;
668     
669     /*  Do "SELECT" command */
670     if (!iil_C_Select($conn, $mailbox)) return false;
671         
672     /* FETCH date,from,subject headers */
673     if ($mode==1){
674         $key="fhi".($c++);
675         $request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)])\r\n";
676         if (!fputs($fp, $request)) return false;
677         do{
678             
679             $line=chop(iil_ReadLine($fp, 200));
680             $a=explode(" ", $line);
681             if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
682                 $id=$a[1];
683
684                 $str=$line=chop(iil_ReadLine($fp, 300));
685
686                 while($line[0]!=")"){                    //caution, this line works only in this particular case
687                     $line=chop(iil_ReadLine($fp, 300));
688                     if ($line[0]!=")"){
689                         if (ord($line[0]) <= 32){            //continuation from previous header line
690                             $str.=" ".trim($line);
691                         }
692                         if ((ord($line[0]) > 32) || (strlen($line[0]) == 0)){
693                             list($field, $string) = iil_SplitHeaderLine($str);
694                             if (strcasecmp($field, "date")==0){
695                                 $result[$id]=iil_StrToTime($string);
696                             }else{
697                                 $result[$id] = str_replace("\"", "", $string);
698                                 if ($normalize) $result[$id]=strtoupper($result[$id]);
699                             }
700                             $str=$line;
701                         }
702                     }
703                 }
704             }
705             /*
706             $end_pos = strlen($line)-1;
707             if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[$end_pos]=="}")){
708                 $id = $a[1];
709                 $pos = strrpos($line, "{")+1;
710                 $bytes = (int)substr($line, $pos, $end_pos-$pos);
711                 $received = 0;
712                 do{
713                     $line = iil_ReadLine($fp, 0);
714                     $received+=strlen($line);
715                     $line = chop($line);
716                     
717                     if ($received>$bytes) break;
718                     else if (!$line) continue;
719                     
720                     list($field,$string)=explode(": ", $line);
721                     
722                     if (strcasecmp($field, "date")==0)
723                         $result[$id] = iil_StrToTime($string);
724                     else if ($index_field!="DATE")
725                         $result[$id]=strtoupper(str_replace("\"", "", $string));
726                 }while($line[0]!=")");
727             }else{
728                 //one line response, not expected so ignore                
729             }
730             */
731         }while(!iil_StartsWith($line, $key));
732     }else if ($mode==6){
733         $key="fhi".($c++);
734         $request = $key." FETCH $message_set (INTERNALDATE)\r\n";
735         if (!fputs($fp, $request)) return false;
736         do{
737             $line=chop(iil_ReadLine($fp, 200));
738             if ($line[0]=="*"){
739                 //original: "* 10 FETCH (INTERNALDATE "31-Jul-2002 09:18:02 -0500")"
740                 $paren_pos = strpos($line, "(");
741                 $foo = substr($line, 0, $paren_pos);
742                 $a = explode(" ", $foo);
743                 $id = $a[1];
744                 
745                 $open_pos = strpos($line, "\"") + 1;
746                 $close_pos = strrpos($line, "\"");
747                 if ($open_pos && $close_pos){
748                     $len = $close_pos - $open_pos;
749                     $time_str = substr($line, $open_pos, $len);
750                     $result[$id] = strtotime($time_str);
751                 }
752             }else{
753                 $a = explode(" ", $line);
754             }
755         }while(!iil_StartsWith($a[0], $key));
756     }else{
757         if ($mode >= 3) $field_name="FLAGS";
758         else if ($index_field=="SIZE") $field_name="RFC822.SIZE";
759         else $field_name=$index_field;
760
761         /*             FETCH uid, size, flags        */
762         $key="fhi".($c++);
763         $request=$key." FETCH $message_set ($field_name)\r\n";
764
765         if (!fputs($fp, $request)) return false;
766         do{
767             $line=chop(iil_ReadLine($fp, 200));
768             $a = explode(" ", $line);
769             if (($line[0]=="*") && ($a[2]=="FETCH")){
770                 $line=str_replace("(", "", $line);
771                 $line=str_replace(")", "", $line);
772                 $a=explode(" ", $line);
773                 
774                 $id=$a[1];
775
776                 if (isset($result[$id])) continue; //if we already got the data, skip forward
777                 if ($a[3]!=$field_name) continue;  //make sure it's returning what we requested
778             
779                 /*  Caution, bad assumptions, next several lines */
780                 if ($mode==2) $result[$id]=$a[4];
781                 else{
782                     $haystack=strtoupper($line);
783                     $result[$id]=(strpos($haystack, $index_field) > 0 ? "F" : "N");
784                 }
785             }
786         }while(!iil_StartsWith($line, $key));
787     }
788
789     //check number of elements...
790     list($start_mid,$end_mid)=explode(':',$message_set);
791     if (is_numeric($start_mid) && is_numeric($end_mid)){
792         //count how many we should have
793         $should_have = $end_mid - $start_mid +1;
794         
795         //if we have less, try and fill in the "gaps"
796         if (count($result)<$should_have){
797             for($i=$start_mid;$i<=$end_mid;$i++) if (!isset($result[$i])) $result[$i] = '';
798         }
799     }
800     
801     return $result;    
802
803 }
804
805 function iil_CompressMessageSet($message_set){
806     //given a comma delimited list of independent mid's, 
807     //compresses by grouping sequences together
808     
809     //if less than 255 bytes long, let's not bother
810     if (strlen($message_set)<255) return $message_set;
811     
812     //see if it's already been compress
813     if (strpos($message_set,':')!==false) return $message_set;
814     
815     //separate, then sort
816     $ids = explode(',',$message_set);
817     sort($ids);
818     
819     $result = array();
820     $start = $prev = $ids[0];
821     foreach($ids as $id){
822         $incr = $id - $prev;
823         if ($incr>1){            //found a gap
824             if ($start==$prev) $result[] = $prev;    //push single id
825             else $result[] = $start.':'.$prev;        //push sequence as start_id:end_id
826             $start = $id;                            //start of new sequence
827         }
828         $prev = $id;
829     }
830     //handle the last sequence/id
831     if ($start==$prev) $result[] = $prev;
832     else $result[] = $start.':'.$prev;
833
834     //return as comma separated string
835     return implode(',',$result);
836 }
837
838 function iil_C_UIDsToMIDs(&$conn, $mailbox, $uids){
839     if (!is_array($uids) || count($uids)==0) return array();
840     return iil_C_Search($conn, $mailbox, "UID ".implode(",", $uids));
841 }
842
843 function iil_C_UIDToMID(&$conn, $mailbox, $uid){
844     $result = iil_C_UIDsToMIDs($conn, $mailbox, array($uid));
845     if (count($result)==1) return $result[0];
846     else return false;
847 }
848
849 function iil_C_FetchUIDs(&$conn,$mailbox){
850     global $clock;
851     
30233b 852     $num = iil_C_CountMessages($conn, $mailbox);
4e17e6 853     if ($num==0) return array();
T 854     $message_set = '1'.($num>1?':'.$num:'');
855     
856     //if cache not enabled, just call iil_C_FetchHeaderIndex on 'UID' field
857     if (!$conn->do_cache)
858         return iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
859
860     //otherwise, let's check cache first
861     $key = $mailbox.'.uids';
862     $cache_good = true;
863     if ($conn->uid_cache) $data = $conn->uid_cache;
864     else $data = cache_read($conn->user, $conn->host, $key);
865     
866     //was anything cached at all?
867     if ($data===false) $cache_good = -1;
868     
869     //make sure number of messages were the same
870     if ($cache_good>0 && $data['n']!=$num) $cache_good = -2;
871     
872     //if everything's okay so far...
873     if ($cache_good>0){
874         //check UIDs of highest mid with current and cached
875         $temp = iil_C_Search($conn, $mailbox, 'UID '.$data['d'][$num]);
876         if (!$temp || !is_array($temp) || $temp[0]!=$num) $cache_good=-3;
877     }
878
879     //if cached data's good, return it
880     if ($cache_good>0){
881         return $data['d'];
882     }
883
884     //otherwise, we need to fetch it
885     $data = array('n'=>$num,'d'=>array());
886     $data['d'] = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, 'UID');
887     cache_write($conn->user, $conn->host, $key, $data);
888     $conn->uid_cache = $data;
889     return $data['d'];
890 }
891
892 function iil_SortThreadHeaders($headers, $index_a, $uids){
893     asort($index_a);
894     $result = array();
895     foreach($index_a as $mid=>$foobar){
896         $uid = $uids[$mid];
897         $result[$uid] = $headers[$uid];
898     }
899     return $result;
900 }
901
902 function iil_C_FetchThreadHeaders(&$conn, $mailbox, $message_set){
903     global $clock;
904     global $index_a;
905     
906     if (empty($message_set)) return false;
907
908     $result = array();
909     $uids = iil_C_FetchUIDs($conn, $mailbox);
910     $debug = false;
911     
912     /* Get cached records where possible */
913     if ($conn->do_cache){
914         $cached = cache_read($conn->user, $conn->host, $mailbox.'.thhd');
915         if ($cached && is_array($uids) && count($uids)>0){
916             $needed_set = "";
917             foreach($uids as $id=>$uid){
918                 if ($cached[$uid]){
919                     $result[$uid] = $cached[$uid];
920                     $result[$uid]->id = $id;
921                 }else $needed_set.=($needed_set?",":"").$id;
922             }
923             if ($needed_set) $message_set = $needed_set;
924             else $message_set = '';
925         }
926     }
927     $message_set = iil_CompressMessageSet($message_set);
928     if ($debug) echo "Still need: ".$message_set;
929     
930     /* if we're missing any, get them */
931     if ($message_set){
932         /* FETCH date,from,subject headers */
933         $key="fh";
934         $fp = $conn->fp;
935         $request=$key." FETCH $message_set (BODY.PEEK[HEADER.FIELDS (SUBJECT MESSAGE-ID IN-REPLY-TO)])\r\n";
936         $mid_to_id = array();
937         if (!fputs($fp, $request)) return false;
938         do{
939             $line = chop(iil_ReadLine($fp, 1024));
940             if ($debug) echo $line."\n";
941             if (ereg('\{[0-9]+\}$', $line)){
942                 $a = explode(" ", $line);
943                 $new = array();
944
945                 $new_thhd = new iilThreadHeader;
946                 $new_thhd->id = $a[1];
947                 do{
948                     $line=chop(iil_ReadLine($fp, 1024),"\r\n");
949                     if (iil_StartsWithI($line,'Message-ID:') || (iil_StartsWithI($line,'In-Reply-To:')) || (iil_StartsWithI($line,'SUBJECT:'))){
950                         $pos = strpos($line, ":");
951                         $field_name = substr($line, 0, $pos);
952                         $field_val = substr($line, $pos+1);
953                         $new[strtoupper($field_name)] = trim($field_val);
954                     }else if (ereg('^[[:space:]]', $line)){
955                         $new[strtoupper($field_name)].= trim($line);
956                     }
957                 }while($line[0]!=')');
958                 $new_thhd->sbj = $new['SUBJECT'];
959                 $new_thhd->mid = substr($new['MESSAGE-ID'], 1, -1);
960                 $new_thhd->irt = substr($new['IN-REPLY-TO'], 1, -1);
961                 
962                 $result[$uids[$new_thhd->id]] = $new_thhd;
963             }
964         }while(!iil_StartsWith($line, "fh"));
965     }
966     
967     /* sort headers */
968     if (is_array($index_a)){
969         $result = iil_SortThreadHeaders($result, $index_a, $uids);    
970     }
971     
972     /* write new set to cache */
973     if ($conn->do_cache){
974         if (count($result)!=count($cached))
975             cache_write($conn->user, $conn->host, $mailbox.'.thhd', $result);        
976     }
977     
978     //echo 'iil_FetchThreadHeaders:'."\n";
979     //print_r($result);
980     
981     return $result;
982 }
983
984 function iil_C_BuildThreads2(&$conn, $mailbox, $message_set, &$clock){
985     global $index_a;
986
987     if (empty($message_set)) return false;
988     
989     $result=array();
990     $roots=array();
991     $root_mids = array();
992     $sub_mids = array();
993     $strays = array();
994     $messages = array();
995     $fp = $conn->fp;
996     $debug = false;
997     
998     $sbj_filter_pat = '[a-zA-Z]{2,3}(\[[0-9]*\])?:([[:space:]]*)';
999     
1000     /*  Do "SELECT" command */
1001     if (!iil_C_Select($conn, $mailbox)) return false;
1002
1003     /* FETCH date,from,subject headers */
1004     $mid_to_id = array();
1005     $messages = array();
1006     $headers = iil_C_FetchThreadHeaders($conn, $mailbox, $message_set);
1007     if ($clock) $clock->register('fetched headers');
1008     
1009     if ($debug) print_r($headers);
1010     
1011     /* go through header records */
1012     foreach($headers as $header){
1013         //$id = $header['i'];
1014         //$new = array('id'=>$id, 'MESSAGE-ID'=>$header['m'], 
1015         //            'IN-REPLY-TO'=>$header['r'], 'SUBJECT'=>$header['s']);
1016         $id = $header->id;
1017         $new = array('id'=>$id, 'MESSAGE-ID'=>$header->mid, 
1018                     'IN-REPLY-TO'=>$header->irt, 'SUBJECT'=>$header->sbj);
1019
1020         /* add to message-id -> mid lookup table */
1021         $mid_to_id[$new['MESSAGE-ID']] = $id;
1022         
1023         /* if no subject, use message-id */
1024         if (empty($new['SUBJECT'])) $new['SUBJECT'] = $new['MESSAGE-ID'];
1025         
1026         /* if subject contains 'RE:' or has in-reply-to header, it's a reply */
1027         $sbj_pre ='';
1028         $has_re = false;
1029         if (eregi($sbj_filter_pat, $new['SUBJECT'])) $has_re = true;
1030         if ($has_re||$new['IN-REPLY-TO']) $sbj_pre = 'RE:';
1031         
1032         /* strip out 're:', 'fw:' etc */
1033         if ($has_re) $sbj = ereg_replace($sbj_filter_pat,'', $new['SUBJECT']);
1034         else $sbj = $new['SUBJECT'];
1035         $new['SUBJECT'] = $sbj_pre.$sbj;
1036         
1037         
1038         /* if subject not a known thread-root, add to list */
1039         if ($debug) echo $id.' '.$new['SUBJECT']."\t".$new['MESSAGE-ID']."\n";
1040         $root_id = $roots[$sbj];
1041         
1042         if ($root_id && ($has_re || !$root_in_root[$root_id])){
1043             if ($debug) echo "\tfound root: $root_id\n";
1044             $sub_mids[$new['MESSAGE-ID']] = $root_id;
1045             $result[$root_id][] = $id;
1046         }else if (!isset($roots[$sbj])||(!$has_re&&$root_in_root[$root_id])){
1047             /* try to use In-Reply-To header to find root 
1048                 unless subject contains 'Re:' */
1049             if ($has_re&&$new['IN-REPLY-TO']){
1050                 if ($debug) echo "\tlooking: ".$new['IN-REPLY-TO']."\n";
1051                 
1052                 //reply to known message?
1053                 $temp = $sub_mids[$new['IN-REPLY-TO']];
1054                 
1055                 if ($temp){
1056                     //found it, root:=parent's root
1057                     if ($debug) echo "\tfound parent: ".$new['SUBJECT']."\n";
1058                     $result[$temp][] = $id;
1059                     $sub_mids[$new['MESSAGE-ID']] = $temp;
1060                     $sbj = '';
1061                 }else{
1062                     //if we can't find referenced parent, it's a "stray"
1063                     $strays[$id] = $new['IN-REPLY-TO'];
1064                 }
1065             }
1066             
1067             //add subject as root
1068             if ($sbj){
1069                 if ($debug) echo "\t added to root\n";
1070                 $roots[$sbj] = $id;
1071                 $root_in_root[$id] = !$has_re;
1072                 $sub_mids[$new['MESSAGE-ID']] = $id;
1073                 $result[$id] = array($id);
1074             }
1075             if ($debug) echo $new['MESSAGE-ID']."\t".$sbj."\n";
1076         }
1077             
1078     }
1079     
1080     //now that we've gone through all the messages,
1081     //go back and try and link up the stray threads
1082     if (count($strays)>0){
1083         foreach($strays as $id=>$irt){
1084             $root_id = $sub_mids[$irt];
1085             if (!$root_id || $root_id==$id) continue;
1086             $result[$root_id] = array_merge($result[$root_id],$result[$id]);
1087             unset($result[$id]);
1088         }
1089     }
1090     
1091     if ($clock) $clock->register('data prepped');
1092     
1093     if ($debug) print_r($roots);
1094     //print_r($result);
1095     return $result;
1096 }
1097
1098
1099 function iil_SortThreads(&$tree, $index, $sort_order='ASC'){
1100     if (!is_array($tree) || !is_array($index)) return false;
1101
1102     //create an id to position lookup table
1103     $i = 0;
1104     foreach($index as $id=>$val){
1105         $i++;
1106         $index[$id] = $i;
1107     }
1108     $max = $i+1;
1109     
1110     //for each tree, set array key to position
1111     $itree = array();
1112     foreach($tree as $id=>$node){
1113         if (count($tree[$id])<=1){
1114             //for "threads" with only one message, key is position of that message
1115             $n = $index[$id];
1116             $itree[$n] = array($n=>$id);
1117         }else{
1118             //for "threads" with multiple messages, 
1119             $min = $max;
1120             $new_a = array();
1121             foreach($tree[$id] as $mid){
1122                 $new_a[$index[$mid]] = $mid;        //create new sub-array mapping position to id
1123                 $pos = $index[$mid];
1124                 if ($pos&&$pos<$min) $min = $index[$mid];    //find smallest position
1125             }
1126             $n = $min;    //smallest position of child is thread position
1127             
1128             //assign smallest position to root level key
1129             //set children array to one created above
1130             ksort($new_a);
1131             $itree[$n] = $new_a;
1132         }
1133     }
1134     
1135     
1136     //sort by key, this basically sorts all threads
1137     ksort($itree);
1138     $i=0;
1139     $out=array();
1140     foreach($itree as $k=>$node){
1141         $out[$i] = $itree[$k];
1142         $i++;
1143     }
1144     
1145     //return
1146     return $out;
1147 }
1148
1149 function iil_IndexThreads(&$tree){
1150     /* creates array mapping mid to thread id */
1151     
1152     if (!is_array($tree)) return false;
1153     
1154     $t_index = array();
1155     foreach($tree as $pos=>$kids){
1156         foreach($kids as $kid) $t_index[$kid] = $pos;
1157     }
1158     
1159     return $t_index;
1160 }
1161
1162 function iil_C_FetchHeaders(&$conn, $mailbox, $message_set){
1163     global $IMAP_USE_INTERNAL_DATE;
1164     
1165     $c=0;
1166     $result=array();
1167     $fp = $conn->fp;
1168     
1169     if (empty($message_set)) return array();
1170     
1171     /*  Do "SELECT" command */
1172     if (!iil_C_Select($conn, $mailbox)){
1173         $conn->error = "Couldn't select $mailbox";
1174         return false;
1175     }
1176         
1177     /* Get cached records where possible */
1178     if ($conn->do_cache){
1179         $uids = iil_C_FetchHeaderIndex($conn, $mailbox, $message_set, "UID");
1180         if (is_array($uids) && count($conn->cache[$mailbox]>0)){
1181             $needed_set = "";
1182             while(list($id,$uid)=each($uids)){
1183                 if ($conn->cache[$mailbox][$uid]){
1184                     $result[$id] = $conn->cache[$mailbox][$uid];
1185                     $result[$id]->id = $id;
1186                 }else $needed_set.=($needed_set?",":"").$id;
1187             }
1188             //echo "<!-- iil_C_FetchHeader\nMessage Set: $message_set\nNeeded Set:$needed_set\n//-->\n";
1189             if ($needed_set) $message_set = iil_CompressMessageSet($needed_set);
1190             else return $result;
1191         }
1192     }
1193
1194     /* FETCH date,from,subject headers */
1195     $key="fh".($c++);
1196     $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";
1197
1198     // echo "// $request\n\n";
1199
1200     if (!fputs($fp, $request)) return false;
1201     do{
1202         $line=chop(iil_ReadLine($fp, 200));
1203         $a=explode(" ", $line);
1204         if (($line[0]=="*") && ($a[2]=="FETCH")){
1205             $id=$a[1];
1206             $result[$id]=new iilBasicHeader;
1207             $result[$id]->id = $id;
1208             $result[$id]->subject = "";
1209             /*
1210                 Start parsing headers.  The problem is, some header "lines" take up multiple lines.
1211                 So, we'll read ahead, and if the one we're reading now is a valid header, we'll
1212                 process the previous line.  Otherwise, we'll keep adding the strings until we come
1213                 to the next valid header line.
1214             */
1215             $i = 0;
1216             $lines = array();
1217             do{
1218                 $line = chop(iil_ReadLine($fp, 300),"\r\n");
1219                 if (ord($line[0])<=32) $lines[$i].=(empty($lines[$i])?"":"\n").trim(chop($line));
1220                 else{
1221                     $i++;
1222                     $lines[$i] = trim(chop($line));
1223                 }
b076a4 1224             }while($line[0]!=")" && strncmp($line, $key, strlen($key)));  // patch from "Maksim Rubis" <siburny@hotmail.com>
4e17e6 1225             
b076a4 1226             if(strncmp($line, $key, strlen($key)))
T 1227             { 
4e17e6 1228             //process header, fill iilBasicHeader obj.
T 1229             //    initialize
1230             if (is_array($headers)){
1231                 reset($headers);
1232                 while ( list($k, $bar) = each($headers) ) $headers[$k] = "";
1233             }
1234
1235             //    create array with header field:data
1236             $headers = array();
1237             while ( list($lines_key, $str) = each($lines) ){
1238                 list($field, $string) = iil_SplitHeaderLine($str);
1239                 $field = strtolower($field);
1240                 $headers[$field] = $string;
1241             }
1242             $result[$id]->date = $headers["date"];
1243             $result[$id]->timestamp = iil_StrToTime($headers["date"]);
1244             $result[$id]->from = $headers["from"];
1245             $result[$id]->to = str_replace("\n", " ", $headers["to"]);
1246             $result[$id]->subject = str_replace("\n", "", $headers["subject"]);
1247             $result[$id]->replyto = str_replace("\n", " ", $headers["reply-to"]);
1248             $result[$id]->cc = str_replace("\n", " ", $headers["cc"]);
1249             $result[$id]->encoding = str_replace("\n", " ", $headers["content-transfer-encoding"]);
1250             $result[$id]->ctype = str_replace("\n", " ", $headers["content-type"]);
a95e0e 1251             $result[$id]->in_reply_to = ereg_replace("[\n<>]",'', $headers['in-reply-to']);
T 1252             
1253             list($result[$id]->ctype, $ctype_add) = explode(";", $headers["content-type"]);
1254
1255             if (preg_match('/charset="?([a-z0-9\-]+)"?/i', $ctype_add, $regs))
1256                 $result[$id]->charset = $regs[1];
1257
4e17e6 1258             $messageID = $headers["message-id"];
T 1259             if ($messageID) $messageID = substr(substr($messageID, 1), 0, strlen($messageID)-2);
1260             else $messageID = "mid:".$id;
1261             $result[$id]->messageID = $messageID;
b076a4 1262             }
T 1263             else {
1264             $a=explode(" ", $line);
1265             } 
4e17e6 1266             
T 1267         }
1268     }while(strcmp($a[0], $key)!=0);
1269         
1270     /* 
1271         FETCH uid, size, flags
1272         Sample reply line: "* 3 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen \Deleted))"
1273     */
1274     $command_key="fh".($c++);
1275     $request= $command_key." FETCH $message_set (UID RFC822.SIZE FLAGS INTERNALDATE)\r\n";
1276     if (!fputs($fp, $request)) return false;
1277     do{
1278         $line=chop(iil_ReadLine($fp, 200));
1279         //$a = explode(" ", $line);
1280         //if (($line[0]=="*") && ($a[2]=="FETCH")){
1281         if ($line[0]=="*"){
1282             //echo "<!-- $line //-->\n";
1283             //get outter most parens
1284             $open_pos = strpos($line, "(") + 1;
1285             $close_pos = strrpos($line, ")");
1286             if ($open_pos && $close_pos){
1287                 //extract ID from pre-paren
1288                 $pre_str = substr($line, 0, $open_pos);
1289                 $pre_a = explode(" ", $line);
1290                 $id = $pre_a[1];
1291                 
1292                 //get data
1293                 $len = $close_pos - $open_pos;
1294                 $str = substr($line, $open_pos, $len);
1295                 
1296                 //swap parents with quotes, then explode
1297                 $str = eregi_replace("[()]", "\"", $str);
1298                 $a = iil_ExplodeQuotedString(" ", $str);
1299                 
1300                 //did we get the right number of replies?
1301                 $parts_count = count($a);
1302                 if ($parts_count>=8){
1303                     for ($i=0;$i<$parts_count;$i=$i+2){
1304                         if (strcasecmp($a[$i],"UID")==0) $result[$id]->uid=$a[$i+1];
1305                         else if (strcasecmp($a[$i],"RFC822.SIZE")==0) $result[$id]->size=$a[$i+1];
1306                         else if (strcasecmp($a[$i],"INTERNALDATE")==0) $time_str = $a[$i+1];
1307                         else if (strcasecmp($a[$i],"FLAGS")==0) $flags_str = $a[$i+1];
1308                     }
1309
1310                     // process flags
1311                     $flags_str = eregi_replace('[\\\"]', "", $flags_str);
1312                     $flags_a = explode(" ", $flags_str);
1313                     //echo "<!-- ID: $id FLAGS: ".implode(",", $flags_a)." //-->\n";
1314                     
1315                     $result[$id]->seen = false;
1316                     $result[$id]->recent = false;
1317                     $result[$id]->deleted = false;
1318                     $result[$id]->answered = false;
1319                     if (is_array($flags_a)){
1320                         reset($flags_a);
1321                         while (list($key,$val)=each($flags_a)){
1322                             if (strcasecmp($val,"Seen")==0) $result[$id]->seen = true;
1323                             else if (strcasecmp($val, "Deleted")==0) $result[$id]->deleted=true;
1324                             else if (strcasecmp($val, "Recent")==0) $result[$id]->recent = true;
1325                             else if (strcasecmp($val, "Answered")==0) $result[$id]->answered = true;
1326                         }
1327                         $result[$id]->flags=$flags_str;
1328                     }
1329             
1330                     // if time is gmt...    
1331                     $time_str = str_replace('GMT','+0000',$time_str);
1332                     
1333                     //get timezone
1334                     $time_str = substr($time_str, 0, -1);
1335                     $time_zone_str = substr($time_str, -5); //extract timezone
1336                     $time_str = substr($time_str, 1, -6); //remove quotes
1337                     $time_zone = (float)substr($time_zone_str, 1, 2); //get first two digits
1338                     if ($time_zone_str[3]!='0') $time_zone += 0.5;  //handle half hour offset
1339                     if ($time_zone_str[0]=="-") $time_zone = $time_zone * -1.0; //minus?
1340                     $result[$id]->internaldate = $time_str;
1341                     
1342                     if ($IMAP_USE_INTERNAL_DATE){
1343                         //calculate timestamp
1344                         $timestamp = strtotime($time_str); //return's server's time
1345                         $na_timestamp = $timestamp;
1346                         $timestamp -= $time_zone * 3600; //compensate for tz, get GMT
1347                         $result[$id]->timestamp = $timestamp;
1348                     }
1349                         
1350                     if ($conn->do_cache){
1351                         $uid = $result[$id]->uid;
1352                         $conn->cache[$mailbox][$uid] = $result[$id];
1353                         $conn->cache_dirty[$mailbox] = true;
1354                     }
1355                     //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";
1356                 }else{
1357                     //echo "<!-- ERROR: $id : $str //-->\n";
1358                 }
1359             }
1360         }
1361     }while(strpos($line, $command_key)===false);
1362         
1363     return $result;
1364 }
1365
1366
1367 function iil_C_FetchHeader(&$conn, $mailbox, $id){
1368     $fp = $conn->fp;
1369     $a=iil_C_FetchHeaders($conn, $mailbox, $id);
1370     if (is_array($a)) return $a[$id];
1371     else return false;
1372 }
1373
1374
1375 function iil_SortHeaders($a, $field, $flag){
1376     if (empty($field)) $field="uid";
1377     $field=strtolower($field);
1378     if ($field=="date"||$field=='internaldate') $field="timestamp";
1379     if (empty($flag)) $flag="ASC";
1380     $flag=strtoupper($flag);
b076a4 1381     $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ',"\"") : array("\"");
4e17e6 1382     
T 1383     $c=count($a);
1384     if ($c>0){
1385         /*
1386             Strategy:
1387             First, we'll create an "index" array.
1388             Then, we'll use sort() on that array, 
1389             and use that to sort the main array.
1390         */
1391                 
1392                 // create "index" array
1393         $index=array();
1394         reset($a);
1395         while (list($key, $val)=each($a)){
1396             $data=$a[$key]->$field;
b076a4 1397             if (is_string($data)) $data=strtoupper(str_replace($stripArr, "", $data));
4e17e6 1398             $index[$key]=$data;
T 1399         }
1400         
1401         // sort index
1402         $i=0;
1403         if ($flag=="ASC") asort($index);
1404         else arsort($index);
1405         
1406         // form new array based on index 
1407         $result=array();
1408         reset($index);
1409         while (list($key, $val)=each($index)){
9fee0e 1410             $result[$key]=$a[$key];
4e17e6 1411             $i++;
T 1412         }
1413     }
1414     
1415     return $result;
1416 }
1417
1418 function iil_C_Expunge(&$conn, $mailbox){
1419     $fp = $conn->fp;
1420     if (iil_C_Select($conn, $mailbox)){
1421         $c=0;
1422         fputs($fp, "exp1 EXPUNGE\r\n");
1423         do{
1424             $line=chop(iil_ReadLine($fp, 100));
1425             if ($line[0]=="*") $c++;
1426         }while (!iil_StartsWith($line, "exp1"));
1427         
1428         if (iil_ParseResult($line) == 0){
1429             $conn->selected = ""; //state has changed, need to reselect            
1430             //$conn->exists-=$c;
1431             return $c;
1432         }else{
1433             $conn->error = $line;
1434             return -1;
1435         }
1436     }
1437     
1438     return -1;
1439 }
1440
1441 function iil_C_ModFlag(&$conn, $mailbox, $messages, $flag, $mod){
1442     if ($mod!="+" && $mod!="-") return -1;
1443     
1444     $fp = $conn->fp;
1445     $flags=array(
1446                     "SEEN"=>"\\Seen",
1447                     "DELETED"=>"\\Deleted",
1448                     "RECENT"=>"\\Recent",
1449                     "ANSWERED"=>"\\Answered",
1450                     "DRAFT"=>"\\Draft",
1451                     "FLAGGED"=>"\\Flagged"
1452                    );
1453     $flag=strtoupper($flag);
1454     $flag=$flags[$flag];
1455     if (iil_C_Select($conn, $mailbox)){
1456         $c=0;
1457         fputs($fp, "flg STORE $messages ".$mod."FLAGS (".$flag.")\r\n");
1458         do{
1459             $line=chop(iil_ReadLine($fp, 100));
1460             if ($line[0]=="*") $c++;
1461         }while (!iil_StartsWith($line, "flg"));
520c36 1462
4e17e6 1463         if (iil_ParseResult($line) == 0){
T 1464             iil_C_ExpireCachedItems($conn, $mailbox, $messages);
1465             return $c;
1466         }else{
1467             $conn->error = $line;
1468             return -1;
1469         }
1470     }else{
1471         $conn->error = "Select failed";
1472         return -1;
1473     }
1474 }
1475
1476 function iil_C_Flag(&$conn, $mailbox, $messages, $flag){
1477     return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "+");
1478 }
1479
1480 function iil_C_Unflag(&$conn, $mailbox, $messages, $flag){
1481     return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "-");
1482 }
1483
1484 function iil_C_Delete(&$conn, $mailbox, $messages){
1485     return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "+");
1486 }
1487
1488 function iil_C_Undelete(&$conn, $mailbox, $messages){
1489     return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "-");
1490 }
1491
1492
1493 function iil_C_Unseen(&$conn, $mailbox, $messages){
1494     return iil_C_ModFlag($conn, $mailbox, $messages, "SEEN", "-");
1495 }
1496
1497
1498 function iil_C_Copy(&$conn, $messages, $from, $to){
1499     $fp = $conn->fp;
1500
1501     if (empty($from) || empty($to)) return -1;
1502
1503     if (iil_C_Select($conn, $from)){
1504         $c=0;
1505         
1506         fputs($fp, "cpy1 COPY $messages \"$to\"\r\n");
1507         $line=iil_ReadReply($fp);
1508         return iil_ParseResult($line);
1509     }else{
1510         return -1;
1511     }
1512 }
1513
1514 function iil_FormatSearchDate($month, $day, $year){
1515     $month = (int)$month;
1516     $months=array(
1517             1=>"Jan", 2=>"Feb", 3=>"Mar", 4=>"Apr", 
1518             5=>"May", 6=>"Jun", 7=>"Jul", 8=>"Aug", 
1519             9=>"Sep", 10=>"Oct", 11=>"Nov", 12=>"Dec"
1520             );
1521     return $day."-".$months[$month]."-".$year;
1522 }
1523
1524 function iil_C_CountUnseen(&$conn, $folder){
1525     $index = iil_C_Search($conn, $folder, "ALL UNSEEN");
1526     if (is_array($index)){
1527         $str = implode(",", $index);
1528         if (empty($str)) return false;
1529         else return count($index);
1530     }else return false;
1531 }
1532
1533 function iil_C_UID2ID(&$conn, $folder, $uid){
1534     if ($uid > 0){
1535         $id_a = iil_C_Search($conn, $folder, "UID $uid");
1536         if (is_array($id_a)){
1537             $count = count($id_a);
1538             if ($count > 1) return false;
1539             else return $id_a[0];
1540         }
1541     }
1542     return false;
1543 }
1544
1545 function iil_C_Search(&$conn, $folder, $criteria){
1546     $fp = $conn->fp;
1547     if (iil_C_Select($conn, $folder)){
1548         $c=0;
1549         
1550         $query = "srch1 SEARCH ".chop($criteria)."\r\n";
1551         fputs($fp, $query);
1552         do{
1553             $line=trim(chop(iil_ReadLine($fp, 10000)));
1554             if (eregi("^\* SEARCH", $line)){
1555                 $str = trim(substr($line, 8));
1556                 $messages = explode(" ", $str);
1557             }
1558         }while(!iil_StartsWith($line, "srch1"));
1559         
1560         $result_code=iil_ParseResult($line);
1561         if ($result_code==0) return $messages;
1562         else{
1563             $conn->error = "iil_C_Search: ".$line."<br>\n";
1564             return false;
1565         }
1566         
1567     }else{
1568         $conn->error = "iil_C_Search: Couldn't select \"$folder\" <br>\n";
1569         return false;
1570     }
1571 }
1572
1573 function iil_C_Move(&$conn, $messages, $from, $to){
1574     $fp = $conn->fp;
1575     
1576     if (!$from || !$to) return -1;
1577     
1578     $r=iil_C_Copy($conn, $messages, $from,$to);
1579     if ($r==0){
1580         return iil_C_Delete($conn, $from, $messages);
1581     }else{
1582         return $r;
1583     }
1584 }
1585
1586 function iil_C_GetHierarchyDelimiter(&$conn){
1587     if ($conn->delimiter) return $conn->delimiter;
1588     
1589     $fp = $conn->fp;
1590     $delimiter = false;
1591     
1592     //try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
1593     if (!fputs($fp, "ghd LIST \"\" \"\"\r\n")) return false;
1594     do{
1595         $line=iil_ReadLine($fp, 500);
1596         if ($line[0]=="*"){
1597             $line = rtrim($line);
1598             $a=iil_ExplodeQuotedString(" ", $line);
1599             if ($a[0]=="*") $delimiter = str_replace("\"", "", $a[count($a)-2]);
1600         }
1601     }while (!iil_StartsWith($line, "ghd"));
1602
1603     if (strlen($delimiter)>0) return $delimiter;
1604     
1605     //if that fails, try namespace extension
1606     //try to fetch namespace data
1607     fputs($conn->fp, "ns1 NAMESPACE\r\n");
1608     do{
1609         $line = iil_ReadLine($conn->fp, 1024);
1610         if (iil_StartsWith($line, "* NAMESPACE")){
1611             $i = 0;
1612             $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
1613         }
1614     }while(!iil_StartsWith($line, "ns1"));
1615         
1616     if (!is_array($data)) return false;
1617     
1618     //extract user space data (opposed to global/shared space)
1619     $user_space_data = $data[0];
1620     if (!is_array($user_space_data)) return false;
1621     
1622     //get first element
1623     $first_userspace = $user_space_data[0];
1624     if (!is_array($first_userspace)) return false;
1625
1626     //extract delimiter
1627     $delimiter = $first_userspace[1];    
1628
1629     return $delimiter;
1630 }
1631
1632 function iil_C_ListMailboxes(&$conn, $ref, $mailbox){
1633     global $IGNORE_FOLDERS;
1634     
1635     $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
1636         
1637     $fp = $conn->fp;
1638     if (empty($mailbox)) $mailbox="*";
1639     if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
1640     
1641     // send command
1642     if (!fputs($fp, "lmb LIST \"".$ref."\" \"$mailbox\"\r\n")) return false;
1643     $i=0;
1644     // get folder list
1645     do{
1646         $line=iil_ReadLine($fp, 500);
1647         $line=iil_MultLine($fp, $line);
1648
1649         $a = explode(" ", $line);
1650         if (($line[0]=="*") && ($a[1]=="LIST")){
1651             $line = rtrim($line);
1652             // split one line
1653             $a=iil_ExplodeQuotedString(" ", $line);
1654             // last string is folder name
1655             $folder = str_replace("\"", "", $a[count($a)-1]);
1656             if (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder))) $folders[$i] = $folder;
1657             // second from last is delimiter
1658             $delim = str_replace("\"", "", $a[count($a)-2]);
1659             // is it a container?
1660             $i++;
1661         }
1662     }while (!iil_StartsWith($line, "lmb"));
1663
1664     if (is_array($folders)){
1665         if (!empty($ref)){
1666             // if rootdir was specified, make sure it's the first element
1667             // some IMAP servers (i.e. Courier) won't return it
1668             if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
1669             if ($folders[0]!=$ref) array_unshift($folders, $ref);
1670         }
1671         return $folders;
1672     }else if (iil_ParseResult($line)==0){
1673         return array('INBOX');
1674     }else{
1675         $conn->error = $line;
1676         return false;
1677     }
1678 }
1679
1680
1681 function iil_C_ListSubscribed(&$conn, $ref, $mailbox){
1682     global $IGNORE_FOLDERS;
1683     
1684     $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
1685     
1686     $fp = $conn->fp;
1687     if (empty($mailbox)) $mailbox = "*";
1688     if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
1689     $folders = array();
1690
1691     // send command
1692     if (!fputs($fp, "lsb LSUB \"".$ref."\" \"".$mailbox."\"\r\n")){
1693         $conn->error = "Couldn't send LSUB command\n";
1694         return false;
1695     }
1696     $i=0;
1697     // get folder list
1698     do{
1699         $line=iil_ReadLine($fp, 500);
1700         $line=iil_MultLine($fp, $line);
1701         $a = explode(" ", $line);
1702         if (($line[0]=="*") && ($a[1]=="LSUB")){
1703             $line = rtrim($line);
1704             // split one line
1705             $a=iil_ExplodeQuotedString(" ", $line);
1706             // last string is folder name
1707             //$folder = UTF7DecodeString(str_replace("\"", "", $a[count($a)-1]));
1708             $folder = str_replace("\"", "", $a[count($a)-1]);
1709             if ((!in_array($folder, $folders)) && (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder)))) $folders[$i] = $folder;
1710             // second from last is delimiter
1711             $delim = str_replace("\"", "", $a[count($a)-2]);
1712             // is it a container?
1713             $i++;
1714         }
1715     }while (!iil_StartsWith($line, "lsb"));
1716
1717     if (is_array($folders)){
1718         if (!empty($ref)){
1719             // if rootdir was specified, make sure it's the first element
1720             // some IMAP servers (i.e. Courier) won't return it
1721             if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
1722             if ($folders[0]!=$ref) array_unshift($folders, $ref);
1723         }
1724         return $folders;
1725     }else{
1726         $conn->error = $line;
1727         return false;
1728     }
1729 }
1730
1731
1732 function iil_C_Subscribe(&$conn, $folder){
1733     $fp = $conn->fp;
1734
1735     $query = "sub1 SUBSCRIBE \"".$folder."\"\r\n";
1736     fputs($fp, $query);
1737     $line=trim(chop(iil_ReadLine($fp, 10000)));
1738     return iil_ParseResult($line);
1739 }
1740
1741
1742 function iil_C_UnSubscribe(&$conn, $folder){
1743     $fp = $conn->fp;
1744
1745     $query = "usub1 UNSUBSCRIBE \"".$folder."\"\r\n";
1746     fputs($fp, $query);
1747     $line=trim(chop(iil_ReadLine($fp, 10000)));
1748     return iil_ParseResult($line);
1749 }
1750
1751
1752 function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part){
1753     $fp = $conn->fp;
1754     $result=false;
1755     if (($part==0)||(empty($part))) $part="HEADER";
1756     else $part.=".MIME";
1757     
1758     if (iil_C_Select($conn, $mailbox)){
1759         $key="fh".($c++);
1760         $request=$key." FETCH $id (BODY.PEEK[$part])\r\n";
1761         if (!fputs($fp, $request)) return false;
1762         do{
1763             $line=chop(iil_ReadLine($fp, 200));
1764             $a=explode(" ", $line);
1765             if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
1766                 $line=iil_ReadLine($fp, 300);
1767                 while(chop($line)!=")"){
1768                     $result.=$line;
1769                     $line=iil_ReadLine($fp, 300);
1770                 }
1771             }
1772         }while(strcmp($a[0], $key)!=0);
1773     }
1774     
1775     return $result;
1776 }
1777
1778
1779 function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode){
1780     /* modes:
1781         1: return string
1782         2: print
1783         3: base64 and print
1784     */
1785     $fp = $conn->fp;
1786     $result=false;
1787     if (($part==0)||(empty($part))) $part="TEXT";
1788     
1789     if (iil_C_Select($conn, $mailbox)){
1790         $reply_key="* ".$id;
1791         // format request
1792         $key="ftch".($c++)." ";
1793         $request=$key."FETCH $id (BODY.PEEK[$part])\r\n";
1794         // send request
1795         if (!fputs($fp, $request)) return false;
1796         // receive reply line
1797         do{
1798             $line = chop(iil_ReadLine($fp, 1000));
1799             $a = explode(" ", $line);
1800         }while ($a[2]!="FETCH");
1801         $len = strlen($line);
1802         if ($line[$len-1] == ")"){
1803             //one line response, get everything between first and last quotes
1804             $from = strpos($line, "\"") + 1;
1805             $to = strrpos($line, "\"");
1806             $len = $to - $from;
1807             if ($mode==1) $result = substr($line, $from, $len);
1808             else if ($mode==2) echo substr($line, $from, $len);
1809             else if ($mode==3) echo base64_decode(substr($line, $from, $len));
1810         }else if ($line[$len-1] == "}"){
1811             //multi-line request, find sizes of content and receive that many bytes
1812             $from = strpos($line, "{") + 1;
1813             $to = strrpos($line, "}");
1814             $len = $to - $from;
1815             $sizeStr = substr($line, $from, $len);
1816             $bytes = (int)$sizeStr;
1817             $received = 0;
1818             while ($received < $bytes){
1819                 $remaining = $bytes - $received;
1820                 $line = iil_ReadLine($fp, 1024);
1821                 $len = strlen($line);
1822                 if ($len > $remaining) substr($line, 0, $remaining);
1823                 $received += strlen($line);
1824                 if ($mode==1) $result .= chop($line)."\n";
1825                 else if ($mode==2){ echo chop($line)."\n"; flush(); }
1826                 else if ($mode==3){ echo base64_decode($line); flush(); }
1827             }
1828         }
1829         // read in anything up until 'til last line
1830         do{
1831             $line = iil_ReadLine($fp, 1024);
1832         }while(!iil_StartsWith($line, $key));
1833         
1834         if ($result){
1835             $result = chop($result);
30233b 1836             return $result; // substr($result, 0, strlen($result)-1);
4e17e6 1837         }else return false;
T 1838     }else{
1839         echo "Select failed.";
1840     }
1841     
1842     if ($mode==1) return $result;
1843     else return $received;
1844 }
1845
1846 function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part){
1847     return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
1848 }
1849
1850 function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part){
1851     iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
1852 }
1853
1854 function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part){
1855     iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
1856 }
1857
1858 function iil_C_CreateFolder(&$conn, $folder){
1859     $fp = $conn->fp;
1860     if (fputs($fp, "c CREATE \"".$folder."\"\r\n")){
1861         do{
1862             $line=iil_ReadLine($fp, 300);
1863         }while($line[0]!="c");
1864         $conn->error = $line;
1865         return (iil_ParseResult($line)==0);
1866     }else{
1867         return false;
1868     }
1869 }
1870
1871 function iil_C_RenameFolder(&$conn, $from, $to){
1872     $fp = $conn->fp;
1873     if (fputs($fp, "r RENAME \"".$from."\" \"".$to."\"\r\n")){
1874         do{
1875             $line=iil_ReadLine($fp, 300);
1876         }while($line[0]!="r");
1877         return (iil_ParseResult($line)==0);
1878     }else{
1879         return false;
1880     }    
1881 }
1882
1883 function iil_C_DeleteFolder(&$conn, $folder){
1884     $fp = $conn->fp;
1885     if (fputs($fp, "d DELETE \"".$folder."\"\r\n")){
1886         do{
1887             $line=iil_ReadLine($fp, 300);
1888         }while($line[0]!="d");
1889         return (iil_ParseResult($line)==0);
1890     }else{
1891         $conn->error = "Couldn't send command\n";
1892         return false;
1893     }
1894 }
1895
e0ed97 1896 function iil_C_Append(&$conn, $folder, &$message){
4e17e6 1897     if (!$folder) return false;
T 1898     $fp = $conn->fp;
1899
1900     $message = str_replace("\r", "", $message);
1901     $message = str_replace("\n", "\r\n", $message);        
1902
1903     $len = strlen($message);
1904     if (!$len) return false;
1905     
1906     $request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
1907     // echo $request.'<br>';
1908     if (fputs($fp, $request)){
1909         $line=iil_ReadLine($fp, 100);
1910         // echo $line.'<br>';
1911         
1912         $sent = fwrite($fp, $message."\r\n");
1913         flush();
1914         do{
1915             $line=iil_ReadLine($fp, 1000);
1916             //echo $line.'<br>';
1917         }while($line[0]!="A");
1918     
1919         $result = (iil_ParseResult($line)==0);
1920         if (!$result) $conn->error .= $line."<br>\n";
1921         return $result;
1922     
1923     }else{
1924         $conn->error .= "Couldn't send command \"$request\"<br>\n";
1925         return false;
1926     }
1927 }
1928
1929
1930 function iil_C_AppendFromFile(&$conn, $folder, $path){
1931     if (!$folder) return false;
1932     
1933     //open message file
1934     $in_fp = false;                
1935     if (file_exists(realpath($path))) $in_fp = fopen($path, "r");
1936     if (!$in_fp){ 
1937         $conn->error .= "Couldn't open $path for reading<br>\n";
1938         return false;
1939     }
1940     
1941     $fp = $conn->fp;
1942     $len = filesize($path);
1943     if (!$len) return false;
1944     
1945     //send APPEND command
1946     $request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
1947     $bytes_sent = 0;
1948     if (fputs($fp, $request)){
1949         $line=iil_ReadLine($fp, 100);
1950                 
1951         //send file
1952         while(!feof($in_fp)){
1953             $buffer = fgets($in_fp, 4096);
1954             $bytes_sent += strlen($buffer);
1955             fputs($fp, $buffer);
1956         }
1957         fclose($in_fp);
1958
1959         fputs($fp, "\r\n");
1960
1961         //read response
1962         do{
1963             $line=iil_ReadLine($fp, 1000);
1964             //echo $line.'<br>';
1965         }while($line[0]!="A");
1966             
1967         $result = (iil_ParseResult($line)==0);
1968         if (!$result) $conn->error .= $line."<br>\n";
1969         return $result;
1970     
1971     }else{
1972         $conn->error .= "Couldn't send command \"$request\"<br>\n";
1973         return false;
1974     }
1975 }
1976
1977
1978 function iil_C_FetchStructureString(&$conn, $folder, $id){
1979     $fp = $conn->fp;
1980     $result=false;
1981     if (iil_C_Select($conn, $folder)){
1982         $key = "F1247";
1983         if (fputs($fp, "$key FETCH $id (BODYSTRUCTURE)\r\n")){
1984             do{
1985                 $line=chop(iil_ReadLine($fp, 5000));
1986                 if ($line[0]=="*"){
1987                     if (ereg("\}$", $line)){
1988                         preg_match('/(.+)\{([0-9]+)\}/', $line, $match);  
1989                         $result = $match[1];
1990                         do{
1991                             $line = chop(iil_ReadLine($fp, 100));
1992                             if (!preg_match("/^$key/", $line)) $result .= $line;
1993                             else $done = true;
1994                         }while(!$done);
1995                     }else{
1996                         $result = $line;
1997                     }
1998                     list($pre, $post) = explode("BODYSTRUCTURE ", $result);
1999                     $result = substr($post, 0, strlen($post)-1);        //truncate last ')' and return
2000                 }
2001             }while (!preg_match("/^$key/",$line));
2002         }
2003     }
2004     return $result;
2005 }
2006
2007 function iil_C_PrintSource(&$conn, $folder, $id, $part){
2008     $header = iil_C_FetchPartHeader($conn, $folder, $id, $part);
2009     //echo str_replace("\r", "", $header);
2010     echo $header;
2011     echo iil_C_PrintPartBody($conn, $folder, $id, $part);
2012 }
2013
2014 function iil_C_GetQuota(&$conn){
2015 /*
2016 b GETQUOTAROOT "INBOX"
2017 * QUOTAROOT INBOX user/rchijiiwa1
2018 * QUOTA user/rchijiiwa1 (STORAGE 654 9765)
2019 b OK Completed
2020 */
2021     $fp = $conn->fp;
2022     $result=false;
2023     $quota_line = "";
2024     
2025     //get line containing quota info
2026     if (fputs($fp, "QUOT1 GETQUOTAROOT \"INBOX\"\r\n")){
2027         do{
2028             $line=chop(iil_ReadLine($fp, 5000));
2029             if (iil_StartsWith($line, "* QUOTA ")) $quota_line = $line;
2030         }while(!iil_StartsWith($line, "QUOT1"));
2031     }
2032     
2033     //return false if not found, parse if found
2034     if (!empty($quota_line)){
2035         $quota_line = eregi_replace("[()]", "", $quota_line);
2036         $parts = explode(" ", $quota_line);
2037         $storage_part = array_search("STORAGE", $parts);
2038         if ($storage_part>0){
2039             $result = array();
2040             $used = $parts[$storage_part+1];
2041             $total = $parts[$storage_part+2];
2042             $result["used"] = $used;
2043             $result["total"] = (empty($total)?"??":$total);
2044             $result["percent"] = (empty($total)?"??":round(($used/$total)*100));
2045             $result["free"] = 100 - $result["percent"];
2046         }
2047     }
2048     
2049     return $result;
2050 }
2051
2052
2053 function iil_C_ClearFolder(&$conn, $folder){
2054     $num_in_trash = iil_C_CountMessages($conn, $folder);
2055     if ($num_in_trash > 0) iil_C_Delete($conn, $folder, "1:".$num_in_trash);
2056     return (iil_C_Expunge($conn, $folder) >= 0);
2057 }
2058
2059 ?>