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