source: subversion/trunk/roundcubemail/program/lib/imap.inc @ 938

Last change on this file since 938 was 938, checked in by thomasb, 6 years ago

New class rcube_user + send message disposition notification

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