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