source: subversion/branches/devel-vnext/program/lib/imap.inc @ 699

Last change on this file since 699 was 699, checked in by till, 6 years ago

# bugfixes
+ debugging

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