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