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