svncommit
2005-10-26 43fa235da354c8b53aa69ba745c1d398a758fcaf
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                 }
1223             }while($line[0]!=")");
1224             
1225             //process header, fill iilBasicHeader obj.
1226             //    initialize
1227             if (is_array($headers)){
1228                 reset($headers);
1229                 while ( list($k, $bar) = each($headers) ) $headers[$k] = "";
1230             }
1231
1232             //    create array with header field:data
1233             $headers = array();
1234             while ( list($lines_key, $str) = each($lines) ){
1235                 list($field, $string) = iil_SplitHeaderLine($str);
1236                 $field = strtolower($field);
1237                 $headers[$field] = $string;
1238             }
1239             $result[$id]->date = $headers["date"];
1240             $result[$id]->timestamp = iil_StrToTime($headers["date"]);
1241             $result[$id]->from = $headers["from"];
1242             $result[$id]->to = str_replace("\n", " ", $headers["to"]);
1243             $result[$id]->subject = str_replace("\n", "", $headers["subject"]);
1244             $result[$id]->replyto = str_replace("\n", " ", $headers["reply-to"]);
1245             $result[$id]->cc = str_replace("\n", " ", $headers["cc"]);
1246             $result[$id]->encoding = str_replace("\n", " ", $headers["content-transfer-encoding"]);
1247             $result[$id]->ctype = str_replace("\n", " ", $headers["content-type"]);
a95e0e 1248             $result[$id]->in_reply_to = ereg_replace("[\n<>]",'', $headers['in-reply-to']);
T 1249             
1250             list($result[$id]->ctype, $ctype_add) = explode(";", $headers["content-type"]);
1251
1252             if (preg_match('/charset="?([a-z0-9\-]+)"?/i', $ctype_add, $regs))
1253                 $result[$id]->charset = $regs[1];
1254
4e17e6 1255             $messageID = $headers["message-id"];
T 1256             if ($messageID) $messageID = substr(substr($messageID, 1), 0, strlen($messageID)-2);
1257             else $messageID = "mid:".$id;
1258             $result[$id]->messageID = $messageID;
1259             
1260         }
1261     }while(strcmp($a[0], $key)!=0);
1262         
1263     /* 
1264         FETCH uid, size, flags
1265         Sample reply line: "* 3 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen \Deleted))"
1266     */
1267     $command_key="fh".($c++);
1268     $request= $command_key." FETCH $message_set (UID RFC822.SIZE FLAGS INTERNALDATE)\r\n";
1269     if (!fputs($fp, $request)) return false;
1270     do{
1271         $line=chop(iil_ReadLine($fp, 200));
1272         //$a = explode(" ", $line);
1273         //if (($line[0]=="*") && ($a[2]=="FETCH")){
1274         if ($line[0]=="*"){
1275             //echo "<!-- $line //-->\n";
1276             //get outter most parens
1277             $open_pos = strpos($line, "(") + 1;
1278             $close_pos = strrpos($line, ")");
1279             if ($open_pos && $close_pos){
1280                 //extract ID from pre-paren
1281                 $pre_str = substr($line, 0, $open_pos);
1282                 $pre_a = explode(" ", $line);
1283                 $id = $pre_a[1];
1284                 
1285                 //get data
1286                 $len = $close_pos - $open_pos;
1287                 $str = substr($line, $open_pos, $len);
1288                 
1289                 //swap parents with quotes, then explode
1290                 $str = eregi_replace("[()]", "\"", $str);
1291                 $a = iil_ExplodeQuotedString(" ", $str);
1292                 
1293                 //did we get the right number of replies?
1294                 $parts_count = count($a);
1295                 if ($parts_count>=8){
1296                     for ($i=0;$i<$parts_count;$i=$i+2){
1297                         if (strcasecmp($a[$i],"UID")==0) $result[$id]->uid=$a[$i+1];
1298                         else if (strcasecmp($a[$i],"RFC822.SIZE")==0) $result[$id]->size=$a[$i+1];
1299                         else if (strcasecmp($a[$i],"INTERNALDATE")==0) $time_str = $a[$i+1];
1300                         else if (strcasecmp($a[$i],"FLAGS")==0) $flags_str = $a[$i+1];
1301                     }
1302
1303                     // process flags
1304                     $flags_str = eregi_replace('[\\\"]', "", $flags_str);
1305                     $flags_a = explode(" ", $flags_str);
1306                     //echo "<!-- ID: $id FLAGS: ".implode(",", $flags_a)." //-->\n";
1307                     
1308                     $result[$id]->seen = false;
1309                     $result[$id]->recent = false;
1310                     $result[$id]->deleted = false;
1311                     $result[$id]->answered = false;
1312                     if (is_array($flags_a)){
1313                         reset($flags_a);
1314                         while (list($key,$val)=each($flags_a)){
1315                             if (strcasecmp($val,"Seen")==0) $result[$id]->seen = true;
1316                             else if (strcasecmp($val, "Deleted")==0) $result[$id]->deleted=true;
1317                             else if (strcasecmp($val, "Recent")==0) $result[$id]->recent = true;
1318                             else if (strcasecmp($val, "Answered")==0) $result[$id]->answered = true;
1319                         }
1320                         $result[$id]->flags=$flags_str;
1321                     }
1322             
1323                     // if time is gmt...    
1324                     $time_str = str_replace('GMT','+0000',$time_str);
1325                     
1326                     //get timezone
1327                     $time_str = substr($time_str, 0, -1);
1328                     $time_zone_str = substr($time_str, -5); //extract timezone
1329                     $time_str = substr($time_str, 1, -6); //remove quotes
1330                     $time_zone = (float)substr($time_zone_str, 1, 2); //get first two digits
1331                     if ($time_zone_str[3]!='0') $time_zone += 0.5;  //handle half hour offset
1332                     if ($time_zone_str[0]=="-") $time_zone = $time_zone * -1.0; //minus?
1333                     $result[$id]->internaldate = $time_str;
1334                     
1335                     if ($IMAP_USE_INTERNAL_DATE){
1336                         //calculate timestamp
1337                         $timestamp = strtotime($time_str); //return's server's time
1338                         $na_timestamp = $timestamp;
1339                         $timestamp -= $time_zone * 3600; //compensate for tz, get GMT
1340                         $result[$id]->timestamp = $timestamp;
1341                     }
1342                         
1343                     if ($conn->do_cache){
1344                         $uid = $result[$id]->uid;
1345                         $conn->cache[$mailbox][$uid] = $result[$id];
1346                         $conn->cache_dirty[$mailbox] = true;
1347                     }
1348                     //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";
1349                 }else{
1350                     //echo "<!-- ERROR: $id : $str //-->\n";
1351                 }
1352             }
1353         }
1354     }while(strpos($line, $command_key)===false);
1355         
1356     return $result;
1357 }
1358
1359
1360 function iil_C_FetchHeader(&$conn, $mailbox, $id){
1361     $fp = $conn->fp;
1362     $a=iil_C_FetchHeaders($conn, $mailbox, $id);
1363     if (is_array($a)) return $a[$id];
1364     else return false;
1365 }
1366
1367
1368 function iil_SortHeaders($a, $field, $flag){
1369     if (empty($field)) $field="uid";
1370     $field=strtolower($field);
1371     if ($field=="date"||$field=='internaldate') $field="timestamp";
1372     if (empty($flag)) $flag="ASC";
1373     $flag=strtoupper($flag);
1374     
1375     $c=count($a);
1376     if ($c>0){
1377         /*
1378             Strategy:
1379             First, we'll create an "index" array.
1380             Then, we'll use sort() on that array, 
1381             and use that to sort the main array.
1382         */
1383                 
1384                 // create "index" array
1385         $index=array();
1386         reset($a);
1387         while (list($key, $val)=each($a)){
1388             $data=$a[$key]->$field;
1389             if (is_string($data)) $data=strtoupper(str_replace("\"", "", $data));
1390             $index[$key]=$data;
1391         }
1392         
1393         // sort index
1394         $i=0;
1395         if ($flag=="ASC") asort($index);
1396         else arsort($index);
1397         
1398         // form new array based on index 
1399         $result=array();
1400         reset($index);
1401         while (list($key, $val)=each($index)){
9fee0e 1402             $result[$key]=$a[$key];
4e17e6 1403             $i++;
T 1404         }
1405     }
1406     
1407     return $result;
1408 }
1409
1410 function iil_C_Expunge(&$conn, $mailbox){
1411     $fp = $conn->fp;
1412     if (iil_C_Select($conn, $mailbox)){
1413         $c=0;
1414         fputs($fp, "exp1 EXPUNGE\r\n");
1415         do{
1416             $line=chop(iil_ReadLine($fp, 100));
1417             if ($line[0]=="*") $c++;
1418         }while (!iil_StartsWith($line, "exp1"));
1419         
1420         if (iil_ParseResult($line) == 0){
1421             $conn->selected = ""; //state has changed, need to reselect            
1422             //$conn->exists-=$c;
1423             return $c;
1424         }else{
1425             $conn->error = $line;
1426             return -1;
1427         }
1428     }
1429     
1430     return -1;
1431 }
1432
1433 function iil_C_ModFlag(&$conn, $mailbox, $messages, $flag, $mod){
1434     if ($mod!="+" && $mod!="-") return -1;
1435     
1436     $fp = $conn->fp;
1437     $flags=array(
1438                     "SEEN"=>"\\Seen",
1439                     "DELETED"=>"\\Deleted",
1440                     "RECENT"=>"\\Recent",
1441                     "ANSWERED"=>"\\Answered",
1442                     "DRAFT"=>"\\Draft",
1443                     "FLAGGED"=>"\\Flagged"
1444                    );
1445     $flag=strtoupper($flag);
1446     $flag=$flags[$flag];
1447     if (iil_C_Select($conn, $mailbox)){
1448         $c=0;
1449         fputs($fp, "flg STORE $messages ".$mod."FLAGS (".$flag.")\r\n");
1450         do{
1451             $line=chop(iil_ReadLine($fp, 100));
1452             if ($line[0]=="*") $c++;
1453         }while (!iil_StartsWith($line, "flg"));
520c36 1454
4e17e6 1455         if (iil_ParseResult($line) == 0){
T 1456             iil_C_ExpireCachedItems($conn, $mailbox, $messages);
1457             return $c;
1458         }else{
1459             $conn->error = $line;
1460             return -1;
1461         }
1462     }else{
1463         $conn->error = "Select failed";
1464         return -1;
1465     }
1466 }
1467
1468 function iil_C_Flag(&$conn, $mailbox, $messages, $flag){
1469     return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "+");
1470 }
1471
1472 function iil_C_Unflag(&$conn, $mailbox, $messages, $flag){
1473     return iil_C_ModFlag($conn, $mailbox, $messages, $flag, "-");
1474 }
1475
1476 function iil_C_Delete(&$conn, $mailbox, $messages){
1477     return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "+");
1478 }
1479
1480 function iil_C_Undelete(&$conn, $mailbox, $messages){
1481     return iil_C_ModFlag($conn, $mailbox, $messages, "DELETED", "-");
1482 }
1483
1484
1485 function iil_C_Unseen(&$conn, $mailbox, $messages){
1486     return iil_C_ModFlag($conn, $mailbox, $messages, "SEEN", "-");
1487 }
1488
1489
1490 function iil_C_Copy(&$conn, $messages, $from, $to){
1491     $fp = $conn->fp;
1492
1493     if (empty($from) || empty($to)) return -1;
1494
1495     if (iil_C_Select($conn, $from)){
1496         $c=0;
1497         
1498         fputs($fp, "cpy1 COPY $messages \"$to\"\r\n");
1499         $line=iil_ReadReply($fp);
1500         return iil_ParseResult($line);
1501     }else{
1502         return -1;
1503     }
1504 }
1505
1506 function iil_FormatSearchDate($month, $day, $year){
1507     $month = (int)$month;
1508     $months=array(
1509             1=>"Jan", 2=>"Feb", 3=>"Mar", 4=>"Apr", 
1510             5=>"May", 6=>"Jun", 7=>"Jul", 8=>"Aug", 
1511             9=>"Sep", 10=>"Oct", 11=>"Nov", 12=>"Dec"
1512             );
1513     return $day."-".$months[$month]."-".$year;
1514 }
1515
1516 function iil_C_CountUnseen(&$conn, $folder){
1517     $index = iil_C_Search($conn, $folder, "ALL UNSEEN");
1518     if (is_array($index)){
1519         $str = implode(",", $index);
1520         if (empty($str)) return false;
1521         else return count($index);
1522     }else return false;
1523 }
1524
1525 function iil_C_UID2ID(&$conn, $folder, $uid){
1526     if ($uid > 0){
1527         $id_a = iil_C_Search($conn, $folder, "UID $uid");
1528         if (is_array($id_a)){
1529             $count = count($id_a);
1530             if ($count > 1) return false;
1531             else return $id_a[0];
1532         }
1533     }
1534     return false;
1535 }
1536
1537 function iil_C_Search(&$conn, $folder, $criteria){
1538     $fp = $conn->fp;
1539     if (iil_C_Select($conn, $folder)){
1540         $c=0;
1541         
1542         $query = "srch1 SEARCH ".chop($criteria)."\r\n";
1543         fputs($fp, $query);
1544         do{
1545             $line=trim(chop(iil_ReadLine($fp, 10000)));
1546             if (eregi("^\* SEARCH", $line)){
1547                 $str = trim(substr($line, 8));
1548                 $messages = explode(" ", $str);
1549             }
1550         }while(!iil_StartsWith($line, "srch1"));
1551         
1552         $result_code=iil_ParseResult($line);
1553         if ($result_code==0) return $messages;
1554         else{
1555             $conn->error = "iil_C_Search: ".$line."<br>\n";
1556             return false;
1557         }
1558         
1559     }else{
1560         $conn->error = "iil_C_Search: Couldn't select \"$folder\" <br>\n";
1561         return false;
1562     }
1563 }
1564
1565 function iil_C_Move(&$conn, $messages, $from, $to){
1566     $fp = $conn->fp;
1567     
1568     if (!$from || !$to) return -1;
1569     
1570     $r=iil_C_Copy($conn, $messages, $from,$to);
1571     if ($r==0){
1572         return iil_C_Delete($conn, $from, $messages);
1573     }else{
1574         return $r;
1575     }
1576 }
1577
1578 function iil_C_GetHierarchyDelimiter(&$conn){
1579     if ($conn->delimiter) return $conn->delimiter;
1580     
1581     $fp = $conn->fp;
1582     $delimiter = false;
1583     
1584     //try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
1585     if (!fputs($fp, "ghd LIST \"\" \"\"\r\n")) return false;
1586     do{
1587         $line=iil_ReadLine($fp, 500);
1588         if ($line[0]=="*"){
1589             $line = rtrim($line);
1590             $a=iil_ExplodeQuotedString(" ", $line);
1591             if ($a[0]=="*") $delimiter = str_replace("\"", "", $a[count($a)-2]);
1592         }
1593     }while (!iil_StartsWith($line, "ghd"));
1594
1595     if (strlen($delimiter)>0) return $delimiter;
1596     
1597     //if that fails, try namespace extension
1598     //try to fetch namespace data
1599     fputs($conn->fp, "ns1 NAMESPACE\r\n");
1600     do{
1601         $line = iil_ReadLine($conn->fp, 1024);
1602         if (iil_StartsWith($line, "* NAMESPACE")){
1603             $i = 0;
1604             $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
1605         }
1606     }while(!iil_StartsWith($line, "ns1"));
1607         
1608     if (!is_array($data)) return false;
1609     
1610     //extract user space data (opposed to global/shared space)
1611     $user_space_data = $data[0];
1612     if (!is_array($user_space_data)) return false;
1613     
1614     //get first element
1615     $first_userspace = $user_space_data[0];
1616     if (!is_array($first_userspace)) return false;
1617
1618     //extract delimiter
1619     $delimiter = $first_userspace[1];    
1620
1621     return $delimiter;
1622 }
1623
1624 function iil_C_ListMailboxes(&$conn, $ref, $mailbox){
1625     global $IGNORE_FOLDERS;
1626     
1627     $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
1628         
1629     $fp = $conn->fp;
1630     if (empty($mailbox)) $mailbox="*";
1631     if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
1632     
1633     // send command
1634     if (!fputs($fp, "lmb LIST \"".$ref."\" \"$mailbox\"\r\n")) return false;
1635     $i=0;
1636     // get folder list
1637     do{
1638         $line=iil_ReadLine($fp, 500);
1639         $line=iil_MultLine($fp, $line);
1640
1641         $a = explode(" ", $line);
1642         if (($line[0]=="*") && ($a[1]=="LIST")){
1643             $line = rtrim($line);
1644             // split one line
1645             $a=iil_ExplodeQuotedString(" ", $line);
1646             // last string is folder name
1647             $folder = str_replace("\"", "", $a[count($a)-1]);
1648             if (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder))) $folders[$i] = $folder;
1649             // second from last is delimiter
1650             $delim = str_replace("\"", "", $a[count($a)-2]);
1651             // is it a container?
1652             $i++;
1653         }
1654     }while (!iil_StartsWith($line, "lmb"));
1655
1656     if (is_array($folders)){
1657         if (!empty($ref)){
1658             // if rootdir was specified, make sure it's the first element
1659             // some IMAP servers (i.e. Courier) won't return it
1660             if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
1661             if ($folders[0]!=$ref) array_unshift($folders, $ref);
1662         }
1663         return $folders;
1664     }else if (iil_ParseResult($line)==0){
1665         return array('INBOX');
1666     }else{
1667         $conn->error = $line;
1668         return false;
1669     }
1670 }
1671
1672
1673 function iil_C_ListSubscribed(&$conn, $ref, $mailbox){
1674     global $IGNORE_FOLDERS;
1675     
1676     $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
1677     
1678     $fp = $conn->fp;
1679     if (empty($mailbox)) $mailbox = "*";
1680     if (empty($ref) && $conn->rootdir) $ref = $conn->rootdir;
1681     $folders = array();
1682
1683     // send command
1684     if (!fputs($fp, "lsb LSUB \"".$ref."\" \"".$mailbox."\"\r\n")){
1685         $conn->error = "Couldn't send LSUB command\n";
1686         return false;
1687     }
1688     $i=0;
1689     // get folder list
1690     do{
1691         $line=iil_ReadLine($fp, 500);
1692         $line=iil_MultLine($fp, $line);
1693         $a = explode(" ", $line);
1694         if (($line[0]=="*") && ($a[1]=="LSUB")){
1695             $line = rtrim($line);
1696             // split one line
1697             $a=iil_ExplodeQuotedString(" ", $line);
1698             // last string is folder name
1699             //$folder = UTF7DecodeString(str_replace("\"", "", $a[count($a)-1]));
1700             $folder = str_replace("\"", "", $a[count($a)-1]);
1701             if ((!in_array($folder, $folders)) && (empty($ignore) || (!empty($ignore) && !eregi($ignore, $folder)))) $folders[$i] = $folder;
1702             // second from last is delimiter
1703             $delim = str_replace("\"", "", $a[count($a)-2]);
1704             // is it a container?
1705             $i++;
1706         }
1707     }while (!iil_StartsWith($line, "lsb"));
1708
1709     if (is_array($folders)){
1710         if (!empty($ref)){
1711             // if rootdir was specified, make sure it's the first element
1712             // some IMAP servers (i.e. Courier) won't return it
1713             if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
1714             if ($folders[0]!=$ref) array_unshift($folders, $ref);
1715         }
1716         return $folders;
1717     }else{
1718         $conn->error = $line;
1719         return false;
1720     }
1721 }
1722
1723
1724 function iil_C_Subscribe(&$conn, $folder){
1725     $fp = $conn->fp;
1726
1727     $query = "sub1 SUBSCRIBE \"".$folder."\"\r\n";
1728     fputs($fp, $query);
1729     $line=trim(chop(iil_ReadLine($fp, 10000)));
1730     return iil_ParseResult($line);
1731 }
1732
1733
1734 function iil_C_UnSubscribe(&$conn, $folder){
1735     $fp = $conn->fp;
1736
1737     $query = "usub1 UNSUBSCRIBE \"".$folder."\"\r\n";
1738     fputs($fp, $query);
1739     $line=trim(chop(iil_ReadLine($fp, 10000)));
1740     return iil_ParseResult($line);
1741 }
1742
1743
1744 function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part){
1745     $fp = $conn->fp;
1746     $result=false;
1747     if (($part==0)||(empty($part))) $part="HEADER";
1748     else $part.=".MIME";
1749     
1750     if (iil_C_Select($conn, $mailbox)){
1751         $key="fh".($c++);
1752         $request=$key." FETCH $id (BODY.PEEK[$part])\r\n";
1753         if (!fputs($fp, $request)) return false;
1754         do{
1755             $line=chop(iil_ReadLine($fp, 200));
1756             $a=explode(" ", $line);
1757             if (($line[0]=="*") && ($a[2]=="FETCH") && ($line[strlen($line)-1]!=")")){
1758                 $line=iil_ReadLine($fp, 300);
1759                 while(chop($line)!=")"){
1760                     $result.=$line;
1761                     $line=iil_ReadLine($fp, 300);
1762                 }
1763             }
1764         }while(strcmp($a[0], $key)!=0);
1765     }
1766     
1767     return $result;
1768 }
1769
1770
1771 function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode){
1772     /* modes:
1773         1: return string
1774         2: print
1775         3: base64 and print
1776     */
1777     $fp = $conn->fp;
1778     $result=false;
1779     if (($part==0)||(empty($part))) $part="TEXT";
1780     
1781     if (iil_C_Select($conn, $mailbox)){
1782         $reply_key="* ".$id;
1783         // format request
1784         $key="ftch".($c++)." ";
1785         $request=$key."FETCH $id (BODY.PEEK[$part])\r\n";
1786         // send request
1787         if (!fputs($fp, $request)) return false;
1788         // receive reply line
1789         do{
1790             $line = chop(iil_ReadLine($fp, 1000));
1791             $a = explode(" ", $line);
1792         }while ($a[2]!="FETCH");
1793         $len = strlen($line);
1794         if ($line[$len-1] == ")"){
1795             //one line response, get everything between first and last quotes
1796             $from = strpos($line, "\"") + 1;
1797             $to = strrpos($line, "\"");
1798             $len = $to - $from;
1799             if ($mode==1) $result = substr($line, $from, $len);
1800             else if ($mode==2) echo substr($line, $from, $len);
1801             else if ($mode==3) echo base64_decode(substr($line, $from, $len));
1802         }else if ($line[$len-1] == "}"){
1803             //multi-line request, find sizes of content and receive that many bytes
1804             $from = strpos($line, "{") + 1;
1805             $to = strrpos($line, "}");
1806             $len = $to - $from;
1807             $sizeStr = substr($line, $from, $len);
1808             $bytes = (int)$sizeStr;
1809             $received = 0;
1810             while ($received < $bytes){
1811                 $remaining = $bytes - $received;
1812                 $line = iil_ReadLine($fp, 1024);
1813                 $len = strlen($line);
1814                 if ($len > $remaining) substr($line, 0, $remaining);
1815                 $received += strlen($line);
1816                 if ($mode==1) $result .= chop($line)."\n";
1817                 else if ($mode==2){ echo chop($line)."\n"; flush(); }
1818                 else if ($mode==3){ echo base64_decode($line); flush(); }
1819             }
1820         }
1821         // read in anything up until 'til last line
1822         do{
1823             $line = iil_ReadLine($fp, 1024);
1824         }while(!iil_StartsWith($line, $key));
1825         
1826         if ($result){
1827             $result = chop($result);
30233b 1828             return $result; // substr($result, 0, strlen($result)-1);
4e17e6 1829         }else return false;
T 1830     }else{
1831         echo "Select failed.";
1832     }
1833     
1834     if ($mode==1) return $result;
1835     else return $received;
1836 }
1837
1838 function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part){
1839     return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
1840 }
1841
1842 function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part){
1843     iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
1844 }
1845
1846 function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part){
1847     iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
1848 }
1849
1850 function iil_C_CreateFolder(&$conn, $folder){
1851     $fp = $conn->fp;
1852     if (fputs($fp, "c CREATE \"".$folder."\"\r\n")){
1853         do{
1854             $line=iil_ReadLine($fp, 300);
1855         }while($line[0]!="c");
1856         $conn->error = $line;
1857         return (iil_ParseResult($line)==0);
1858     }else{
1859         return false;
1860     }
1861 }
1862
1863 function iil_C_RenameFolder(&$conn, $from, $to){
1864     $fp = $conn->fp;
1865     if (fputs($fp, "r RENAME \"".$from."\" \"".$to."\"\r\n")){
1866         do{
1867             $line=iil_ReadLine($fp, 300);
1868         }while($line[0]!="r");
1869         return (iil_ParseResult($line)==0);
1870     }else{
1871         return false;
1872     }    
1873 }
1874
1875 function iil_C_DeleteFolder(&$conn, $folder){
1876     $fp = $conn->fp;
1877     if (fputs($fp, "d DELETE \"".$folder."\"\r\n")){
1878         do{
1879             $line=iil_ReadLine($fp, 300);
1880         }while($line[0]!="d");
1881         return (iil_ParseResult($line)==0);
1882     }else{
1883         $conn->error = "Couldn't send command\n";
1884         return false;
1885     }
1886 }
1887
e0ed97 1888 function iil_C_Append(&$conn, $folder, &$message){
4e17e6 1889     if (!$folder) return false;
T 1890     $fp = $conn->fp;
1891
1892     $message = str_replace("\r", "", $message);
1893     $message = str_replace("\n", "\r\n", $message);        
1894
1895     $len = strlen($message);
1896     if (!$len) return false;
1897     
1898     $request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
1899     // echo $request.'<br>';
1900     if (fputs($fp, $request)){
1901         $line=iil_ReadLine($fp, 100);
1902         // echo $line.'<br>';
1903         
1904         $sent = fwrite($fp, $message."\r\n");
1905         flush();
1906         do{
1907             $line=iil_ReadLine($fp, 1000);
1908             //echo $line.'<br>';
1909         }while($line[0]!="A");
1910     
1911         $result = (iil_ParseResult($line)==0);
1912         if (!$result) $conn->error .= $line."<br>\n";
1913         return $result;
1914     
1915     }else{
1916         $conn->error .= "Couldn't send command \"$request\"<br>\n";
1917         return false;
1918     }
1919 }
1920
1921
1922 function iil_C_AppendFromFile(&$conn, $folder, $path){
1923     if (!$folder) return false;
1924     
1925     //open message file
1926     $in_fp = false;                
1927     if (file_exists(realpath($path))) $in_fp = fopen($path, "r");
1928     if (!$in_fp){ 
1929         $conn->error .= "Couldn't open $path for reading<br>\n";
1930         return false;
1931     }
1932     
1933     $fp = $conn->fp;
1934     $len = filesize($path);
1935     if (!$len) return false;
1936     
1937     //send APPEND command
1938     $request="A APPEND \"".$folder."\" (\\Seen) {".$len."}\r\n";
1939     $bytes_sent = 0;
1940     if (fputs($fp, $request)){
1941         $line=iil_ReadLine($fp, 100);
1942                 
1943         //send file
1944         while(!feof($in_fp)){
1945             $buffer = fgets($in_fp, 4096);
1946             $bytes_sent += strlen($buffer);
1947             fputs($fp, $buffer);
1948         }
1949         fclose($in_fp);
1950
1951         fputs($fp, "\r\n");
1952
1953         //read response
1954         do{
1955             $line=iil_ReadLine($fp, 1000);
1956             //echo $line.'<br>';
1957         }while($line[0]!="A");
1958             
1959         $result = (iil_ParseResult($line)==0);
1960         if (!$result) $conn->error .= $line."<br>\n";
1961         return $result;
1962     
1963     }else{
1964         $conn->error .= "Couldn't send command \"$request\"<br>\n";
1965         return false;
1966     }
1967 }
1968
1969
1970 function iil_C_FetchStructureString(&$conn, $folder, $id){
1971     $fp = $conn->fp;
1972     $result=false;
1973     if (iil_C_Select($conn, $folder)){
1974         $key = "F1247";
1975         if (fputs($fp, "$key FETCH $id (BODYSTRUCTURE)\r\n")){
1976             do{
1977                 $line=chop(iil_ReadLine($fp, 5000));
1978                 if ($line[0]=="*"){
1979                     if (ereg("\}$", $line)){
1980                         preg_match('/(.+)\{([0-9]+)\}/', $line, $match);  
1981                         $result = $match[1];
1982                         do{
1983                             $line = chop(iil_ReadLine($fp, 100));
1984                             if (!preg_match("/^$key/", $line)) $result .= $line;
1985                             else $done = true;
1986                         }while(!$done);
1987                     }else{
1988                         $result = $line;
1989                     }
1990                     list($pre, $post) = explode("BODYSTRUCTURE ", $result);
1991                     $result = substr($post, 0, strlen($post)-1);        //truncate last ')' and return
1992                 }
1993             }while (!preg_match("/^$key/",$line));
1994         }
1995     }
1996     return $result;
1997 }
1998
1999 function iil_C_PrintSource(&$conn, $folder, $id, $part){
2000     $header = iil_C_FetchPartHeader($conn, $folder, $id, $part);
2001     //echo str_replace("\r", "", $header);
2002     echo $header;
2003     echo iil_C_PrintPartBody($conn, $folder, $id, $part);
2004 }
2005
2006 function iil_C_GetQuota(&$conn){
2007 /*
2008 b GETQUOTAROOT "INBOX"
2009 * QUOTAROOT INBOX user/rchijiiwa1
2010 * QUOTA user/rchijiiwa1 (STORAGE 654 9765)
2011 b OK Completed
2012 */
2013     $fp = $conn->fp;
2014     $result=false;
2015     $quota_line = "";
2016     
2017     //get line containing quota info
2018     if (fputs($fp, "QUOT1 GETQUOTAROOT \"INBOX\"\r\n")){
2019         do{
2020             $line=chop(iil_ReadLine($fp, 5000));
2021             if (iil_StartsWith($line, "* QUOTA ")) $quota_line = $line;
2022         }while(!iil_StartsWith($line, "QUOT1"));
2023     }
2024     
2025     //return false if not found, parse if found
2026     if (!empty($quota_line)){
2027         $quota_line = eregi_replace("[()]", "", $quota_line);
2028         $parts = explode(" ", $quota_line);
2029         $storage_part = array_search("STORAGE", $parts);
2030         if ($storage_part>0){
2031             $result = array();
2032             $used = $parts[$storage_part+1];
2033             $total = $parts[$storage_part+2];
2034             $result["used"] = $used;
2035             $result["total"] = (empty($total)?"??":$total);
2036             $result["percent"] = (empty($total)?"??":round(($used/$total)*100));
2037             $result["free"] = 100 - $result["percent"];
2038         }
2039     }
2040     
2041     return $result;
2042 }
2043
2044
2045 function iil_C_ClearFolder(&$conn, $folder){
2046     $num_in_trash = iil_C_CountMessages($conn, $folder);
2047     if ($num_in_trash > 0) iil_C_Delete($conn, $folder, "1:".$num_in_trash);
2048     return (iil_C_Expunge($conn, $folder) >= 0);
2049 }
2050
2051 ?>