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