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