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