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