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