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