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