alecpl
2008-12-11 030c848b0d68321b711875886f90e680f232715b
program/lib/imap.inc
@@ -51,22 +51,47 @@
      - Abort do-loop on socket errors (fgets returns false)
      - $ICL_SSL is not boolean anymore but contains the connection schema (ssl or tls)
      - Removed some debuggers (echo ...)
      File altered by Aleksander Machniak <alec@alec.pl>
      - trim(chop()) replaced by trim()
      - added iil_Escape() with support for " and \ in folder names
      - support \ character in username in iil_C_Login()
      - fixed iil_MultLine(): use iil_ReadBytes() instead of iil_ReadLine()
      - fixed iil_C_FetchStructureString() to handle many literal strings in response
      - removed hardcoded data size in iil_ReadLine()
      - added iil_PutLine() wrapper for fputs()
      - code cleanup and identation fixes
      - removed flush() calls in iil_C_HandlePartBody() to prevent from memory leak (#1485187)
      - don't return "??" from iil_C_GetQuota()
      - RFC3501 [7.1] don't call CAPABILITY if was returned in server
        optional resposne in iil_Connect(), added iil_C_GetCapability()
      - remove 'undisclosed-recipients' string from 'To' header
      - iil_C_HandlePartBody(): added 6th argument and fixed endless loop
      - added iil_PutLineC()
      - fixed iil_C_Sort() to support very long and/or divided responses
      - added BYE response simple support for endless loop prevention
      - added 3rd argument in iil_StartsWith* functions
      - fix iil_C_FetchPartHeader() in some cases by use of iil_C_HandlePartBody()
      - allow iil_C_HandlePartBody() to fetch whole message
      - optimize iil_C_FetchHeaders() to use only one FETCH command
      - added 4th argument to iil_Connect()
      - allow setting rootdir and delimiter before connect
********************************************************/
/**
 * @todo Possibly clean up more CS.
 * @todo Try to replace most double-quotes with single-quotes.
 * @todo Split this file into smaller files.
 * @todo Refactor code.
 * @todo Replace echo-debugging (make it adhere to config setting and log)
 */
// changed path to work within roundcube webmail
include_once("lib/icl_commons.inc");
include_once 'lib/icl_commons.inc';
if (!$IMAP_USE_HEADER_DATE) {
   $IMAP_USE_INTERNAL_DATE = true;
if (!isset($IMAP_USE_HEADER_DATE) || !$IMAP_USE_HEADER_DATE) {
    $IMAP_USE_INTERNAL_DATE = true;
}
/**
@@ -77,6 +102,16 @@
    "Nov" => 11, "Dec" => 12);
$GLOBALS['IMAP_SERVER_TZ'] = date('Z');
$GLOBALS['IMAP_FLAGS'] = array(
    'SEEN'     => '\\Seen',
    'DELETED'  => '\\Deleted',
    'RECENT'   => '\\Recent',
    'ANSWERED' => '\\Answered',
    'DRAFT'    => '\\Draft',
    'FLAGGED'  => '\\Flagged',
    'FORWARDED' => '$Forwarded',
    'MDNSENT'  => '$MDNSent');
$iil_error;
$iil_errornum;
@@ -101,6 +136,8 @@
   var $rootdir;
   var $delimiter;
   var $capability = array();
   var $permanentflags = array();
   var $capability_readed = false;
}
/**
@@ -130,12 +167,14 @@
   var $priority;
   var $mdn_to;
   var $mdn_sent = false;
   var $is_reply = false;
   var $is_draft = false;
   var $seen = false;
   var $deleted = false;
   var $recent = false;
   var $answered = false;
   var $forwarded = false;
   var $junk = false;
   var $flagged = false;
}
/**
@@ -149,28 +188,60 @@
   var $mid;
}
function iil_xor($string, $string2) {
    $result = '';
    $size = strlen($string);
    for ($i=0; $i<$size; $i++) {
       $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
    }
    return $result;
   $result = '';
   $size = strlen($string);
   for ($i=0; $i<$size; $i++) {
          $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
   }
   return $result;
}
function iil_PutLine($fp, $string, $endln=true) {
      console('C: '. rtrim($string));
        return fputs($fp, $string . ($endln ? "\r\n" : ''));
}
// iil_PutLine replacement with Command Continuation Requests (RFC3501 7.5) support
function iil_PutLineC($fp, $string, $endln=true) {
   if ($endln)
      $string .= "\r\n";
   $res = 0;
   if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) {
      for($i=0, $cnt=count($parts); $i<$cnt; $i++) {
         if(preg_match('/^\{[0-9]+\}\r\n$/', $parts[$i+1])) {
            $res += iil_PutLine($fp, $parts[$i].$parts[$i+1], false);
            $line = iil_ReadLine($fp, 1000);
            $i++;
         }
         else
            $res += iil_PutLine($fp, $parts[$i], false);
      }
   }
   return $res;
}
function iil_ReadLine($fp, $size) {
   $line = '';
   if ($fp) {
      do {
          // FIXME: hardcode size?
         $buffer = fgets($fp, 2048);
         if ($buffer === false) {
            break;
            }
         $line .= $buffer;
      } while ($buffer[strlen($buffer)-1]!="\n");
   if (!$fp) {
          return $line;
   }
   if (!$size) {
      $size = 1024;
   }
   do {
          $buffer = fgets($fp, $size);
          if ($buffer === false) {
              break;
          }
//      console('S: '. chop($buffer));
          $line .= $buffer;
   } while ($buffer[strlen($buffer)-1] != "\n");
   return $line;
}
@@ -182,10 +253,11 @@
      preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a);
      $bytes = $a[2][0];
      while (strlen($out) < $bytes) {
          $line = iil_ReadLine($fp, 1024);
         $out .= chop($line);
         $line = iil_ReadBytes($fp, $bytes);
         $out .= $line;
      }
      $line = $a[1][0] . "\"$out\"";
//      console('[...] '. $out);
   }
   return $line;
}
@@ -194,15 +266,19 @@
   $data = '';
   $len  = 0;
   do {
      $data.=fread($fp, $bytes-$len);
      $len = strlen($data);
   } while ($len<$bytes);
          $data .= fread($fp, $bytes-$len);
      if ($len == strlen($data)) {
                  break; //nothing was read -> exit to avoid apache lockups
          }
          $len = strlen($data);
   } while ($len < $bytes);
   return $data;
}
function iil_ReadReply($fp) {
   do {
      $line = chop(trim(iil_ReadLine($fp, 1024)));
      $line = trim(iil_ReadLine($fp, 1024));
   } while ($line[0] == '*');
   
   return $line;
@@ -212,39 +288,85 @@
   $a=explode(' ', $string);
   if (count($a) > 2) {
      if (strcasecmp($a[1], 'OK') == 0) {
          return 0;
         return 0;
      } else if (strcasecmp($a[1], 'NO') == 0) {
          return -1;
         return -1;
      } else if (strcasecmp($a[1], 'BAD') == 0) {
          return -2;
        }
         return -2;
      } else if (strcasecmp($a[1], 'BYE') == 0) {
         return -3;
          }
   }
    return -3;
   return -4;
}
// check if $string starts with $match
function iil_StartsWith($string, $match) {
function iil_StartsWith($string, $match, $bye=false) {
   $len = strlen($match);
   if ($len == 0) {
       return false;
    }
      return false;
   }
   if (strncmp($string, $match, $len) == 0) {
       return true;
    }
      return true;
   }
   if ($bye && strncmp($string, '* BYE ', 6) == 0) {
      return true;
   }
   return false;
}
function iil_StartsWithI($string, $match) {
function iil_StartsWithI($string, $match, $bye=false) {
   $len = strlen($match);
   if ($len == 0) {
       return false;
    }
      return false;
   }
   if (strncasecmp($string, $match, $len) == 0) {
       return true;
    }
      return true;
   }
   if ($bye && strncmp($string, '* BYE ', 6) == 0) {
      return true;
   }
   return false;
}
function iil_Escape($string)
{
   return strtr($string, array('"'=>'\\"', '\\' => '\\\\'));
}
function iil_C_GetCapability(&$conn, $name)
{
   if (in_array($name, $conn->capability)) {
      return true;
   }
   else if ($conn->capability_readed) {
      return false;
   }
   // get capabilities (only once) because initial
   // optional CAPABILITY response may differ
   $conn->capability = array();
   iil_PutLine($conn->fp, "cp01 CAPABILITY");
   do {
      $line = trim(iil_ReadLine($conn->fp, 1024));
      $a = explode(' ', $line);
      if ($line[0] == '*') {
         while (list($k, $w) = each($a)) {
            if ($w != '*' && $w != 'CAPABILITY')
                   $conn->capability[] = strtoupper($w);
         }
      }
   } while ($a[0] != 'cp01');
   $conn->capability_readed = true;
   if (in_array($name, $conn->capability)) {
      return true;
   }
   return false;
}
function iil_C_Authenticate(&$conn, $user, $pass, $encChallenge) {
    
@@ -253,9 +375,10 @@
    
    // initialize ipad, opad
    for ($i=0;$i<64;$i++) {
        $ipad .=chr(0x36);
        $opad .=chr(0x5C);
        $ipad .= chr(0x36);
        $opad .= chr(0x5C);
    }
    // pad $pass so it's 64 bytes
    $padLen = 64 - strlen($pass);
    for ($i=0;$i<$padLen;$i++) {
@@ -263,53 +386,57 @@
    }
    
    // generate hash
    $hash  = iil_xor($pass,$opad);
    $hash .= pack("H*",md5(iil_xor($pass, $ipad) . base64_decode($encChallenge)));
    $hash  = md5($hash);
    $hash  = md5(iil_xor($pass,$opad) . pack("H*", md5(iil_xor($pass, $ipad) . base64_decode($encChallenge))));
    
    // generate reply
    $reply = base64_encode('"' . $user . '" "' . $hash . '"');
    $reply = base64_encode($user . ' ' . $hash);
    
    // send result, get reply
    fputs($conn->fp, $reply . "\r\n");
    iil_PutLine($conn->fp, $reply);
    $line = iil_ReadLine($conn->fp, 1024);
    
    // process result
    if (iil_ParseResult($line) == 0) {
    $result = iil_ParseResult($line);
    if ($result == 0) {
        $conn->error    .= '';
        $conn->errorNum  = 0;
        return $conn->fp;
    }
    if ($result == -3) fclose($conn->fp); // BYE response
    $conn->error    .= 'Authentication for ' . $user . ' failed (AUTH): "';
    $conn->error    .= htmlspecialchars($line) . '"';
    $conn->errorNum  = -2;
    return false;
    $conn->errorNum  = $result;
    return $result;
}
function iil_C_Login(&$conn, $user, $password) {
    $password = strtr($password, array('"'=>'\\"', '\\' => '\\\\'));
    fputs($conn->fp, "a001 LOGIN $user \"$password\"\r\n");
    iil_PutLine($conn->fp, 'a001 LOGIN "'.iil_Escape($user).'" "'.iil_Escape($password).'"');
    do {
        $line = iil_ReadReply($conn->fp);
        if ($line === false) {
            break;
        }
    } while (!iil_StartsWith($line, "a001 "));
    $a = explode(' ', $line);
    if (strcmp($a[1], 'OK') == 0) {
        $result          = $conn->fp;
    } while (!iil_StartsWith($line, 'a001 ', true));
    // process result
    $result = iil_ParseResult($line);
    if ($result == 0) {
        $conn->error    .= '';
        $conn->errorNum  = 0;
        return $result;
        return $conn->fp;
    }
    $result = false;
    fclose($conn->fp);
    
    $conn->error    .= 'Authentication for ' . $user . ' failed (LOGIN): "';
    $conn->error    .= htmlspecialchars($line)."\"";
    $conn->errorNum  = -2;
    $conn->errorNum  = $result;
    return $result;
}
@@ -317,10 +444,10 @@
function iil_ParseNamespace2($str, &$i, $len=0, $l) {
   if (!$l) {
       $str = str_replace('NIL', '()', $str);
    }
   }
   if (!$len) {
       $len = strlen($str);
    }
   }
   $data      = array();
   $in_quotes = false;
   $elem      = 0;
@@ -331,17 +458,17 @@
         $data[$elem] = iil_ParseNamespace2($str, $i, $len, $l++);
         $elem++;
      } else if ($c == ')' && !$in_quotes) {
          return $data;
        } else if ($c == '\\') {
         return $data;
          } else if ($c == '\\') {
         $i++;
         if ($in_quotes) {
             $data[$elem] .= $c.$str[$i];
            }
            $data[$elem] .= $c.$str[$i];
              }
      } else if ($c == '"') {
         $in_quotes = !$in_quotes;
         if (!$in_quotes) {
             $elem++;
            }
            $elem++;
              }
      } else if ($in_quotes) {
         $data[$elem].=$c;
      }
@@ -351,23 +478,24 @@
function iil_C_NameSpace(&$conn) {
   global $my_prefs;
   if (isset($my_prefs['rootdir']) && is_string($my_prefs['rootdir'])) {
          $conn->rootdir = $my_prefs['rootdir'];
      return true;
   }
   
   if (!in_array('NAMESPACE', $conn->capability)) {
   if (!iil_C_GetCapability($conn, 'NAMESPACE')) {
       return false;
   }
    
   if ($my_prefs["rootdir"]) {
       return true;
   }
   fputs($conn->fp, "ns1 NAMESPACE\r\n");
   iil_PutLine($conn->fp, "ns1 NAMESPACE");
   do {
      $line = iil_ReadLine($conn->fp, 1024);
      if (iil_StartsWith($line, '* NAMESPACE')) {
         $i    = 0;
         $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
      }
   } while (!iil_StartsWith($line, "ns1"));
   } while (!iil_StartsWith($line, 'ns1', true));
   
   if (!is_array($data)) {
       return false;
@@ -385,36 +513,37 @@
    
   $conn->rootdir       = $first_userspace[0];
   $conn->delimiter     = $first_userspace[1];
   $my_prefs["rootdir"] = substr($conn->rootdir, 0, -1);
   $my_prefs['rootdir'] = substr($conn->rootdir, 0, -1);
   $my_prefs['delimiter'] = $conn->delimiter;
   
   return true;
}
function iil_Connect($host, $user, $password) {
    global $iil_error, $iil_errornum;
function iil_Connect($host, $user, $password, $options=null) {
   global $iil_error, $iil_errornum;
   global $ICL_SSL, $ICL_PORT;
   global $IMAP_NO_CACHE;
   global $my_prefs, $IMAP_USE_INTERNAL_DATE;
   
   $iil_error = '';
   $iil_errornum = 0;
   //strip slashes
   // $user = stripslashes($user);
   // $password = stripslashes($password);
   //set auth method
   $auth_method = 'plain';
   if (func_num_args() >= 4) {
      $auth_array = func_get_arg(3);
      if (is_array($auth_array)) {
          $auth_method = $auth_array['imap'];
        }
      if (empty($auth_method)) {
            $auth_method = "plain";
        }
   // set some imap options
   if (is_array($options)) {
      foreach($options as $optkey => $optval) {
         if ($optkey == 'imap') {
            $auth_method = $optval;
         } else if ($optkey == 'rootdir') {
                $my_prefs['rootdir'] = $optval;
         } else if ($optkey == 'delimiter') {
                $my_prefs['delimiter'] = $optval;
         }
      }
   }
   if (empty($auth_method))
          $auth_method = 'plain';
   $message = "INITIAL: $auth_method\n";
      
   $result = false;
@@ -431,102 +560,103 @@
   $conn->cache_dirty = array();
   
   if ($my_prefs['sort_field'] == 'INTERNALDATE') {
       $IMAP_USE_INTERNAL_DATE = true;
    } else if ($my_prefs['sort_field'] == 'DATE') {
        $IMAP_USE_INTERNAL_DATE = false;
    }
      $IMAP_USE_INTERNAL_DATE = true;
   } else if ($my_prefs['sort_field'] == 'DATE') {
          $IMAP_USE_INTERNAL_DATE = false;
   }
   //echo '<!-- conn sort_field: '.$my_prefs['sort_field'].' //-->';
   
   //check input
   if (empty($host)) {
       $iil_error .= "Invalid host\n";
    }
      $iil_error = "Empty host";
      $iil_errornum = -1;
      return false;
   }
   if (empty($user)) {
       $iil_error .= "Invalid user\n";
    }
      $iil_error = "Empty user";
      $iil_errornum = -1;
      return false;
   }
   if (empty($password)) {
       $iil_error .= "Invalid password\n";
    }
   if (!empty($iil_error)) {
       return false;
    }
      $iil_error = "Empty password";
      $iil_errornum = -1;
      return false;
   }
   if (!$ICL_PORT) {
       $ICL_PORT = 143;
      $ICL_PORT = 143;
   }
    
   //check for SSL
   if ($ICL_SSL) {
      $host = $ICL_SSL."://".$host;
      $host = $ICL_SSL . '://' . $host;
   }
   
   //open socket connection
   $conn->fp = fsockopen($host, $ICL_PORT, $errno, $errstr, 10);
   if (!$conn->fp) {
        $iil_error    = "Could not connect to $host at port $ICL_PORT: $errstr";
        $iil_errornum = -1;
          $iil_error = "Could not connect to $host at port $ICL_PORT: $errstr";
          $iil_errornum = -2;
      return false;
   }
   $iil_error .= "Socket connection established\r\n";
   $line       = iil_ReadLine($conn->fp, 300);
   $line       = iil_ReadLine($conn->fp, 4096);
   // RFC3501 [7.1] optional CAPABILITY response
   if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
      $conn->capability = explode(' ', strtoupper($matches[1]));
   }
   $conn->message .= $line;
   if (strcasecmp($auth_method, "check") == 0) {
      //check for supported auth methods
      //default to plain text auth
      $auth_method = "plain";
      //check for CRAM-MD5
      fputs($conn->fp, "cp01 CAPABILITY\r\n");
      do {
          $line = trim(chop(iil_ReadLine($conn->fp, 100)));
          $conn->message.="$line\n";
         $a = explode(' ', $line);
         if ($line[0]=="*") {
            while ( list($k, $w) = each($a) ) {
                if ($w!='*' && $w!='CAPABILITY') {
                   $conn->capability[] = $w;
                    }
               if ((strcasecmp($w, "AUTH=CRAM_MD5") == 0)||
                  (strcasecmp($w, "AUTH=CRAM-MD5") == 0)) {
                   $auth_method = "auth";
               }
            }
         }
      } while ($a[0]!="cp01");
      if (iil_C_GetCapability($conn, 'AUTH=CRAM-MD5') || iil_C_GetCapability($conn, 'AUTH=CRAM_MD5')) {
         $auth_method = 'auth';
      }
      else {
         //default to plain text auth
         $auth_method = 'plain';
      }
   }
   if (strcasecmp($auth_method, "auth") == 0) {
   if (strcasecmp($auth_method, 'auth') == 0) {
      $conn->message .= "Trying CRAM-MD5\n";
      //do CRAM-MD5 authentication
      fputs($conn->fp, "a000 AUTHENTICATE CRAM-MD5\r\n");
      $line = trim(chop(iil_ReadLine($conn->fp, 1024)));
      $conn->message.="$line\n";
      if ($line[0] == "+") {
         $conn->message .= 'Got challenge: ' . htmlspecialchars($line)."\n";
      iil_PutLine($conn->fp, "a000 AUTHENTICATE CRAM-MD5");
      $line = trim(iil_ReadLine($conn->fp, 1024));
      $conn->message .= "$line\n";
      if ($line[0] == '+') {
         $conn->message .= 'Got challenge: ' . htmlspecialchars($line) . "\n";
         //got a challenge string, try CRAM-5
         $result = iil_C_Authenticate($conn, $user, $password, substr($line,2));
         // stop if server sent BYE response
         if($result == -3) {
                     $iil_error = $conn->error;
                     $iil_errornum = $conn->errorNum;
            return false;
         }
         $conn->message .= "Tried CRAM-MD5: $result \n";
      } else {
         $conn->message .='No challenge ('.htmlspecialchars($line)."), try plain\n";
            $auth = 'plain';
         $auth = 'plain';
      }
   }
      
   if ((!$result)||(strcasecmp($auth, "plain") == 0)) {
      //do plain text auth
      $result = iil_C_Login($conn, $user, $password);
      $conn->message.="Tried PLAIN: $result \n";
      $conn->message .= "Tried PLAIN: $result \n";
   }
      
   $conn->message .= $auth;
         
   if ($result) {
   if (!is_int($result)) {
      iil_C_Namespace($conn);
      return $conn;
   } else {
@@ -538,7 +668,7 @@
function iil_Close(&$conn) {
   iil_C_WriteCache($conn);
   if (fputs($conn->fp, "I LOGOUT\r\n")) {
   if (iil_PutLine($conn->fp, "I LOGOUT")) {
      fgets($conn->fp, 1024);
      fclose($conn->fp);
      $conn->fp = false;
@@ -547,7 +677,6 @@
function iil_ClearCache($user, $host) {
}
function iil_C_WriteCache(&$conn) {
   //echo "<!-- doing iil_C_WriteCache //-->\n";
@@ -587,14 +716,14 @@
function iil_C_ExpireCachedItems(&$conn, $folder, $message_set) {
   
   if (!$conn->do_cache) {
       return;   //caching disabled
      return;   //caching disabled
   }
    if (!is_array($conn->cache[$folder])) {
        return;   //cache not initialized|empty
   if (!is_array($conn->cache[$folder])) {
          return;   //cache not initialized|empty
   }
    if (count($conn->cache[$folder]) == 0) {
        return;   //cache not initialized|empty
    }
   if (count($conn->cache[$folder]) == 0) {
          return;   //cache not initialized|empty
   }
    
   $uids = iil_C_FetchHeaderIndex($conn, $folder, $message_set, 'UID');
   $num_removed = 0;
@@ -627,15 +756,15 @@
}
function iil_ExplodeQuotedString($delimiter, $string) {
   $quotes=explode('"', $string);
   $quotes = explode('"', $string);
   while ( list($key, $val) = each($quotes)) {
      if (($key % 2) == 1) {
         $quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
        }
    }
   $string=implode('"', $quotes);
          }
   }
   $string = implode('"', $quotes);
   
   $result=explode($delimiter, $string);
   $result = explode($delimiter, $string);
   while ( list($key, $val) = each($result) ) {
      $result[$key] = str_replace('_!@!_', $delimiter, $result[$key]);
   }
@@ -645,22 +774,22 @@
function iil_CheckForRecent($host, $user, $password, $mailbox) {
   if (empty($mailbox)) {
       $mailbox = 'INBOX';
      $mailbox = 'INBOX';
   }
    
   $conn = iil_Connect($host, $user, $password, 'plain');
   $fp   = $conn->fp;
   if ($fp) {
      fputs($fp, "a002 EXAMINE \"$mailbox\"\r\n");
      iil_PutLine($fp, "a002 EXAMINE \"".iil_Escape($mailbox)."\"");
      do {
         $line=chop(iil_ReadLine($fp, 300));
         $a=explode(' ', $line);
         if (($a[0] == '*') && (strcasecmp($a[2], 'RECENT') == 0)) {
             $result = (int) $a[1];
            }
      } while (!iil_StartsWith($a[0], 'a002'));
              }
      } while (!iil_StartsWith($a[0], 'a002', true));
      fputs($fp, "a003 LOGOUT\r\n");
      iil_PutLine($fp, "a003 LOGOUT");
      fclose($fp);
   } else {
       $result = -2;
@@ -670,57 +799,60 @@
}
function iil_C_Select(&$conn, $mailbox) {
   $fp = $conn->fp;
   if (empty($mailbox)) {
       return false;
      return false;
   }
    if (strcmp($conn->selected, $mailbox) == 0) {
        return true;
   if (strcmp($conn->selected, $mailbox) == 0) {
      return true;
   }
    
   iil_C_LoadCache($conn, $mailbox);
   
   if (fputs($fp, "sel1 SELECT \"$mailbox\"\r\n")) {
   if (iil_PutLine($conn->fp, "sel1 SELECT \"".iil_Escape($mailbox).'"')) {
      do {
         $line=chop(iil_ReadLine($fp, 300));
         $a=explode(' ', $line);
         $line = chop(iil_ReadLine($conn->fp, 300));
         $a = explode(' ', $line);
         if (count($a) == 3) {
            if (strcasecmp($a[2], 'EXISTS') == 0) {
                $conn->exists = (int) $a[1];
               $conn->exists = (int) $a[1];
            }
                if (strcasecmp($a[2], 'RECENT') == 0) {
                    $conn->recent = (int) $a[1];
                }
            if (strcasecmp($a[2], 'RECENT') == 0) {
               $conn->recent = (int) $a[1];
            }
         }
      } while (!iil_StartsWith($line, 'sel1'));
         else if (preg_match('/\[?PERMANENTFLAGS\s+\(([^\)]+)\)\]/U', $line, $match)) {
            $conn->permanentflags = explode(' ', $match[1]);
         }
      } while (!iil_StartsWith($line, 'sel1', true));
      $a=explode(' ', $line);
      $a = explode(' ', $line);
      if (strcasecmp($a[1], 'OK') == 0) {
         $conn->selected = $mailbox;
         return true;
      }
   }
    return false;
   return false;
}
function iil_C_CheckForRecent(&$conn, $mailbox) {
   if (empty($mailbox)) {
       $mailbox = 'INBOX';
      $mailbox = 'INBOX';
   }
    
   iil_C_Select($conn, $mailbox);
   if ($conn->selected == $mailbox) {
       return $conn->recent;
      return $conn->recent;
   }
    return false;
   return false;
}
function iil_C_CountMessages(&$conn, $mailbox, $refresh = false) {
   if ($refresh) {
      $conn->selected= '';
      $conn->selected = '';
   }
   iil_C_Select($conn, $mailbox);
   if ($conn->selected == $mailbox) {
      return $conn->exists;
@@ -735,16 +867,16 @@
      $res[1] = trim(substr($string, $pos+1));
      return $res;
   }
    return $string;
   return $string;
}
function iil_StrToTime($str) {
   $IMAP_MONTHS    = $GLOBALS['IMAP_MONTHS'];
    $IMAP_SERVER_TZ = $GLOBALS['IMAP_SERVER_TR'];
   $IMAP_SERVER_TZ = $GLOBALS['IMAP_SERVER_TZ'];
      
   if ($str) {
        $time1 = strtotime($str);
    }
           $time1 = strtotime($str);
   }
   if ($time1 && $time1 != -1) {
       return $time1-$IMAP_SERVER_TZ;
   }
@@ -758,9 +890,9 @@
   $pos = strpos($str, ' ');
   if (!is_numeric(substr($str, 0, $pos))) {
       $str = substr($str, $pos+1);
    }
   }
   //explode, take good parts
   $a=explode(' ',$str);
   $a = explode(' ', $str);
   $month_str = $a[1];
   $month     = $IMAP_MONTHS[$month_str];
@@ -782,18 +914,21 @@
function iil_C_Sort(&$conn, $mailbox, $field, $add='', $is_uid=FALSE,
    $encoding = 'US-ASCII') {
   /*  Do "SELECT" command */
   if (!iil_C_Select($conn, $mailbox)) {
       return false;
   }
   $field = strtoupper($field);
   if ($field == 'INTERNALDATE') {
       $field = 'ARRIVAL';
    }
   $fields = array('ARRIVAL'=>1,'CC'=>1,'DATE'=>1,'FROM'=>1,'SIZE'=>1,
 'SUBJECT'=>1,'TO'=>1);
   }
   $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1,
        'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1);
   
   if (!$fields[$field]) {
       return false;
   }
   /*  Do "SELECT" command */
   if (!iil_C_Select($conn, $mailbox)) {
       return false;
   }
    
@@ -801,25 +936,29 @@
   
   if (!empty($add)) {
       $add = " $add";
    }
   }
   $fp      = $conn->fp;
   $command = 's '. $is_uid .'SORT ('.$field.') '.$encoding.' ALL'."$add\r\n";
   $line    = $data = '';
   $command  = 's ' . $is_uid . 'SORT (' . $field . ') ';
   $command .= $encoding . ' ALL' . $add;
   $line     = $data = '';
   
   if (!fputs($fp, $command)) {
   if (!iil_PutLineC($conn->fp, $command)) {
       return false;
    }
   }
   do {
      $line = chop(iil_ReadLine($fp, 1024));
      $line = chop(iil_ReadLine($conn->fp, 1024));
      if (iil_StartsWith($line, '* SORT')) {
          $data .= ($data?' ':'') . substr($line, 7);
        }
   } while ($line[0]!='s');
         $data .= ($data ? ' ' : '') . substr($line, 7);
          } else if (preg_match('/^[0-9 ]+$/', $line)) {
         $data .= $line;
      }
   } while (!iil_StartsWith($line, 's ', true));
   
   if (empty($data)) {
      $conn->error = $line;
      return false;
   $result_code = iil_ParseResult($line);
   if ($result_code != 0) {
                $conn->error = 'iil_C_Sort: ' . $line . "\n";
                return false;
   }
   
   $out = explode(' ',$data);
@@ -836,14 +975,14 @@
      
   if (empty($index_field)) {
       $index_field = 'DATE';
    }
   }
   $index_field = strtoupper($index_field);
   
   list($from_idx, $to_idx) = explode(':', $message_set);
   if (empty($message_set) || (isset($to_idx)
        && (int)$from_idx > (int)$to_idx)) {
           && (int)$from_idx > (int)$to_idx)) {
      return false;
    }
   }
   
   //$fields_a['DATE'] = ($IMAP_USE_INTERNAL_DATE?6:1);
   $fields_a['DATE']         = 1;
@@ -867,21 +1006,21 @@
   /*  Do "SELECT" command */
   if (!iil_C_Select($conn, $mailbox)) {
       return false;
    }
   }
    
   /* FETCH date,from,subject headers */
   if ($mode == 1) {
      $key     = 'fhi' . ($c++);
      $request = $key . " FETCH $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)])\r\n";
      if (!fputs($fp, $request)) {
      $request = $key . " FETCH $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)])";
      if (!iil_PutLine($fp, $request)) {
          return false;
        }
          }
      do {
         
         $line=chop(iil_ReadLine($fp, 200));
         $a=explode(' ', $line);
         if (($line[0] == '*') && ($a[2] == 'FETCH')
                && ($line[strlen($line)-1] != ')')) {
                      && ($line[strlen($line)-1] != ')')) {
            $id=$a[1];
            $str=$line=chop(iil_ReadLine($fp, 300));
@@ -900,7 +1039,7 @@
                        $result[$id] = str_replace('"', '', $string);
                        if ($normalize) {
                            $result[$id] = strtoupper($result[$id]);
                                }
                                           }
                     }
                     $str=$line;
                  }
@@ -920,9 +1059,9 @@
               $line      = chop($line);
               
               if ($received>$bytes) {
                        break;
                                break;
               } else if (!$line) {
                        continue;
                                continue;
               }
               list($field, $string) = explode(': ', $line);
@@ -931,21 +1070,21 @@
                  $result[$id] = iil_StrToTime($string);
               } else if ($index_field != 'DATE') {
                  $result[$id]=strtoupper(str_replace('"', '', $string));
                    }
                         }
            } while ($line[0] != ')');
         } else {
            //one line response, not expected so ignore            
         }
         */
      } while (!iil_StartsWith($line, $key));
      } while (!iil_StartsWith($line, $key, true));
   }else if ($mode == 6) {
      $key     = 'fhi' . ($c++);
      $request = $key." FETCH $message_set (INTERNALDATE)\r\n";
      if (!fputs($fp, $request)) {
      $request = $key . " FETCH $message_set (INTERNALDATE)";
      if (!iil_PutLine($fp, $request)) {
          return false;
        }
          }
      do {
         $line=chop(iil_ReadLine($fp, 200));
         if ($line[0] == '*') {
@@ -968,7 +1107,7 @@
         } else {
            $a = explode(' ', $line);
         }
      } while (!iil_StartsWith($a[0], $key));
      } while (!iil_StartsWith($a[0], $key, true));
   } else {
      if ($mode >= 3) {
          $field_name = 'FLAGS';
@@ -976,15 +1115,15 @@
          $field_name = 'RFC822.SIZE';
      } else {
          $field_name = $index_field;
        }
          }
        
      /*          FETCH uid, size, flags      */
      $key     = 'fhi' .($c++);
      $request = $key . " FETCH $message_set ($field_name)\r\n";
      $request = $key . " FETCH $message_set ($field_name)";
      if (!fputs($fp, $request)) {
      if (!iil_PutLine($fp, $request)) {
          return false;
        }
          }
      do {
         $line=chop(iil_ReadLine($fp, 200));
         $a = explode(' ', $line);
@@ -998,9 +1137,9 @@
            if (isset($result[$id])) {
                continue; //if we already got the data, skip forward
            }
                if ($a[3]!=$field_name) {
                    continue;  //make sure it's returning what we requested
             }
                     if ($a[3]!=$field_name) {
                         continue;  //make sure it's returning what we requested
            }
                
            /*  Caution, bad assumptions, next several lines */
            if ($mode == 2) {
@@ -1010,27 +1149,25 @@
               $result[$id] = (strpos($haystack, $index_field) > 0 ? "F" : "N");
            }
         }
      } while (!iil_StartsWith($line, $key));
      } while (!iil_StartsWith($line, $key, true));
   }
   //check number of elements...
   list($start_mid,$end_mid) = explode(':', $message_set);
   list($start_mid, $end_mid) = explode(':', $message_set);
   if (is_numeric($start_mid) && is_numeric($end_mid)) {
      //count how many we should have
      $should_have = $end_mid - $start_mid +1;
      
      //if we have less, try and fill in the "gaps"
      if (count($result)<$should_have) {
         for ($i=$start_mid;$i<=$end_mid;$i++) {
             if (!isset($result[$i])) {
                 $result[$i] = '';
                }
            }
      if (count($result) < $should_have) {
         for ($i=$start_mid; $i<=$end_mid; $i++) {
            if (!isset($result[$i])) {
                   $result[$i] = '';
                     }
              }
      }
   }
   return $result;   
}
function iil_CompressMessageSet($message_set) {
@@ -1048,29 +1185,31 @@
   }
    
   //separate, then sort
   $ids = explode(',',$message_set);
   $ids = explode(',', $message_set);
   sort($ids);
   
   $result = array();
   $start = $prev = $ids[0];
   $start  = $prev = $ids[0];
   foreach ($ids as $id) {
      $incr = $id - $prev;
      if ($incr>1) {         //found a gap
         if ($start==$prev) {
      if ($incr > 1) {         //found a gap
         if ($start == $prev) {
             $result[] = $prev;   //push single id
         } else {
             $result[] = $start.':'.$prev;      //push sequence as start_id:end_id
             $result[] = $start . ':' . $prev;   //push sequence as start_id:end_id
         }
            $start = $id;                     //start of new sequence
              $start = $id;         //start of new sequence
      }
      $prev = $id;
   }
   //handle the last sequence/id
   if ($start==$prev) {
       $result[] = $prev;
    } else {
        $result[] = $start.':'.$prev;
    }
   } else {
           $result[] = $start.':'.$prev;
   }
    
   //return as comma separated string
   return implode(',', $result);
@@ -1079,16 +1218,16 @@
function iil_C_UIDsToMIDs(&$conn, $mailbox, $uids) {
   if (!is_array($uids) || count($uids) == 0) {
       return array();
    }
   return iil_C_Search($conn, $mailbox, "UID ".implode(",", $uids));
   }
   return iil_C_Search($conn, $mailbox, 'UID ' . implode(',', $uids));
}
function iil_C_UIDToMID(&$conn, $mailbox, $uid) {
   $result = iil_C_UIDsToMIDs($conn, $mailbox, array($uid));
   if (count($result)==1) {
   if (count($result) == 1) {
       return $result[0];
   }
    return false;
        return false;
}
function iil_C_FetchUIDs(&$conn,$mailbox) {
@@ -1097,7 +1236,7 @@
   $num = iil_C_CountMessages($conn, $mailbox);
   if ($num == 0) {
       return array();
    }
   }
   $message_set = '1' . ($num>1?':' . $num:'');
   
   //if cache not enabled, just call iil_C_FetchHeaderIndex on 'UID' field
@@ -1119,21 +1258,21 @@
   }
    
   //make sure number of messages were the same
   if ($cache_good>0 && $data['n']!=$num) {
   if ($cache_good > 0 && $data['n'] != $num) {
       $cache_good = -2;
   }
    
   //if everything's okay so far...
   if ($cache_good>0) {
   if ($cache_good > 0) {
      //check UIDs of highest mid with current and cached
      $temp = iil_C_Search($conn, $mailbox, 'UID ' . $data['d'][$num]);
      if (!$temp || !is_array($temp) || $temp[0] != $num) {
          $cache_good = -3;
        }
          }
   }
   //if cached data's good, return it
   if ($cache_good>0) {
   if ($cache_good > 0) {
      return $data['d'];
   }
@@ -1164,7 +1303,7 @@
   if (empty($message_set) || (isset($to_idx)
        && (int)$from_idx > (int)$to_idx)) {
      return false;
    }
   }
   $result = array();
   $uids   = iil_C_FetchUIDs($conn, $mailbox);
@@ -1181,13 +1320,13 @@
               $result[$uid]->id = $id;
            } else {
                $needed_set .= ($needed_set ? ',' : '') . $id;
                }
                     }
         }
         if ($needed_set) {
             $message_set = $needed_set;
         } else {
             $message_set = '';
            }
              }
      }
   }
   $message_set = iil_CompressMessageSet($message_set);
@@ -1201,16 +1340,16 @@
      $key        = 'fh';
      $fp         = $conn->fp;
      $request    = $key . " FETCH $message_set ";
        $request   .= "(BODY.PEEK[HEADER.FIELDS (SUBJECT MESSAGE-ID IN-REPLY-TO)])\r\n";
          $request   .= "(BODY.PEEK[HEADER.FIELDS (SUBJECT MESSAGE-ID IN-REPLY-TO)])";
      $mid_to_id  = array();
      if (!fputs($fp, $request)) {
      if (!iil_PutLine($fp, $request)) {
          return false;
        }
          }
      do {
         $line = chop(iil_ReadLine($fp, 1024));
         if ($debug) {
             echo $line . "\n";
            }
              }
         if (ereg('\{[0-9]+\}$', $line)) {
            $a     = explode(' ', $line);
            $new = array();
@@ -1218,16 +1357,19 @@
            $new_thhd = new iilThreadHeader;
            $new_thhd->id = $a[1];
            do {
               $line=chop(iil_ReadLine($fp, 1024),"\r\n");
               $line = chop(iil_ReadLine($fp, 1024), "\r\n");
               if (iil_StartsWithI($line, 'Message-ID:')
                        || (iil_StartsWithI($line,'In-Reply-To:'))
                        || (iil_StartsWithI($line,'SUBJECT:'))) {
                  $pos = strpos($line, ":");
                                || (iil_StartsWithI($line,'In-Reply-To:'))
                                || (iil_StartsWithI($line,'SUBJECT:'))) {
                  $pos        = strpos($line, ':');
                  $field_name = substr($line, 0, $pos);
                  $field_val = substr($line, $pos+1);
                  $field_val  = substr($line, $pos+1);
                  $new[strtoupper($field_name)] = trim($field_val);
               } else if (ereg('^[[:space:]]', $line)) {
                  $new[strtoupper($field_name)].= trim($line);
                  $new[strtoupper($field_name)] .= trim($line);
               }
            } while ($line[0] != ')');
                
@@ -1249,7 +1391,7 @@
   if ($conn->do_cache) {
      if (count($result)!=count($cached)) {
         cache_write($conn->user, $conn->host, $mailbox . '.thhd', $result);
        }
          }
   }
   
   //echo 'iil_FetchThreadHeaders:'."\n";
@@ -1263,7 +1405,7 @@
   list($from_idx, $to_idx) = explode(':', $message_set);
   if (empty($message_set) || (isset($to_idx)
        && (int)$from_idx > (int)$to_idx)) {
          && (int)$from_idx > (int)$to_idx)) {
      return false;
   }
    
@@ -1281,7 +1423,7 @@
   /*  Do "SELECT" command */
   if (!iil_C_Select($conn, $mailbox)) {
       return false;
    }
   }
    
   /* FETCH date,from,subject headers */
   $mid_to_id = array();
@@ -1301,8 +1443,8 @@
      //$new = array('id'=>$id, 'MESSAGE-ID'=>$header['m'], 
      //         'IN-REPLY-TO'=>$header['r'], 'SUBJECT'=>$header['s']);
      $id  = $header->id;
      $new = array('id'=>$id, 'MESSAGE-ID'=>$header->mid,
            'IN-REPLY-TO'=>$header->irt, 'SUBJECT'=>$header->sbj);
      $new = array('id' => $id, 'MESSAGE-ID' => $header->mid,
              'IN-REPLY-TO' => $header->irt, 'SUBJECT' => $header->sbj);
      /* add to message-id -> mid lookup table */
      $mid_to_id[$new['MESSAGE-ID']] = $id;
@@ -1318,8 +1460,8 @@
      if (eregi($sbj_filter_pat, $new['SUBJECT'])) {
          $has_re = true;
      }
        if ($has_re||$new['IN-REPLY-TO']) {
            $sbj_pre = 'RE:';
          if ($has_re||$new['IN-REPLY-TO']) {
               $sbj_pre = 'RE:';
      }
        
      /* strip out 're:', 'fw:' etc */
@@ -1328,22 +1470,22 @@
      } else {
          $sbj = $new['SUBJECT'];
      }
        $new['SUBJECT'] = $sbj_pre.$sbj;
          $new['SUBJECT'] = $sbj_pre.$sbj;
      
      
      /* if subject not a known thread-root, add to list */
      if ($debug) {
          echo $id . ' ' . $new['SUBJECT'] . "\t" . $new['MESSAGE-ID'] . "\n";
      }
        $root_id = $roots[$sbj];
          $root_id = $roots[$sbj];
      
      if ($root_id && ($has_re || !$root_in_root[$root_id])) {
         if ($debug) {
             echo "\tfound root: $root_id\n";
         }
            $sub_mids[$new['MESSAGE-ID']] = $root_id;
              $sub_mids[$new['MESSAGE-ID']] = $root_id;
         $result[$root_id][]           = $id;
      }else if (!isset($roots[$sbj])||(!$has_re&&$root_in_root[$root_id])) {
      } else if (!isset($roots[$sbj]) || (!$has_re && $root_in_root[$root_id])) {
         /* try to use In-Reply-To header to find root 
            unless subject contains 'Re:' */
         if ($has_re&&$new['IN-REPLY-TO']) {
@@ -1358,7 +1500,7 @@
               if ($debug) {
                   echo "\tfound parent: ".$new['SUBJECT']."\n";
               }
                    $result[$temp][]              = $id;
                         $result[$temp][]              = $id;
               $sub_mids[$new['MESSAGE-ID']] = $temp;
               $sbj                          = '';
            } else {
@@ -1372,27 +1514,26 @@
            if ($debug) {
                echo "\t added to root\n";
            }
                $roots[$sbj]                  = $id;
                     $roots[$sbj]                  = $id;
            $root_in_root[$id]            = !$has_re;
            $sub_mids[$new['MESSAGE-ID']] = $id;
            $result[$id]                  = array($id);
         }
         if ($debug) {
             echo $new['MESSAGE-ID'] . "\t" . $sbj . "\n";
            }
              }
      }
   }
   
   //now that we've gone through all the messages,
   //go back and try and link up the stray threads
   if (count($strays)>0) {
   if (count($strays) > 0) {
      foreach ($strays as $id=>$irt) {
         $root_id = $sub_mids[$irt];
         if (!$root_id || $root_id==$id) {
             continue;
         }
            $result[$root_id] = array_merge($result[$root_id],$result[$id]);
              $result[$root_id] = array_merge($result[$root_id],$result[$id]);
         unset($result[$id]);
      }
   }
@@ -1404,15 +1545,14 @@
   if ($debug) {
       print_r($roots);
   }
    //print_r($result);
   return $result;
}
function iil_SortThreads(&$tree, $index, $sort_order = 'ASC') {
   if (!is_array($tree) || !is_array($index)) {
       return false;
    }
   }
    
   //create an id to position lookup table
   $i = 0;
@@ -1449,17 +1589,15 @@
      }
   }
   
   //sort by key, this basically sorts all threads
   ksort($itree);
   $i=0;
   $out=array();
   $i   = 0;
   $out = array();
   foreach ($itree as $k=>$node) {
      $out[$i] = $itree[$k];
      $i++;
   }
   
   //return
   return $out;
}
@@ -1482,7 +1620,6 @@
{
   global $IMAP_USE_INTERNAL_DATE;
   
   $c      = 0;
   $result = array();
   $fp     = $conn->fp;
   
@@ -1520,20 +1657,19 @@
      }
   }
   /* FETCH date,from,subject headers */
   $key     = 'fh' . ($c++);
   $prefix     = $uidfetch?' UID':'';
   $request  = $key . $prefix;
   $request .= " FETCH $message_set (BODY.PEEK[HEADER.FIELDS ";
   /* FETCH uid, size, flags and headers */
   $key       = 'FH12';
   $request  = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set ";
   $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE BODY.PEEK[HEADER.FIELDS ";
   $request .= "(DATE FROM TO SUBJECT REPLY-TO IN-REPLY-TO CC BCC ";
   $request .= "CONTENT-TRANSFER-ENCODING CONTENT-TYPE MESSAGE-ID ";
   $request .= "REFERENCES DISPOSITION-NOTIFICATION-TO X-PRIORITY)])\r\n";
   $request .= "REFERENCES DISPOSITION-NOTIFICATION-TO X-PRIORITY)])";
   if (!fputs($fp, $request)) {
   if (!iil_PutLine($fp, $request)) {
      return false;
   }
   do {
      $line = chop(iil_ReadLine($fp, 200));
      $line = chop(iil_ReadLine($fp, 1024));
      $a    = explode(' ', $line);
      if (($line[0] == '*') && ($a[2] == 'FETCH')) {
         $id = $a[1];
@@ -1544,24 +1680,109 @@
         $result[$id]->messageID = 'mid:' . $id;
         /*
             Sample reply line:
             * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen)
             INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODY[HEADER.FIELDS ...
         */
         if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY\[HEADER/', $line, $matches)) {
            $str = $matches[1];
            //swap parents with quotes, then explode
            $str = eregi_replace("[()]", "\"", $str);
            $a = iil_ExplodeQuotedString(' ', $str);
            //did we get the right number of replies?
            $parts_count = count($a);
            if ($parts_count>=8) {
               for ($i=0; $i<$parts_count; $i=$i+2) {
                  if (strcasecmp($a[$i],'UID') == 0)
                     $result[$id]->uid = $a[$i+1];
                  else if (strcasecmp($a[$i],'RFC822.SIZE') == 0)
                     $result[$id]->size = $a[$i+1];
                  else if (strcasecmp($a[$i],'INTERNALDATE') == 0)
                     $time_str = $a[$i+1];
                  else if (strcasecmp($a[$i],'FLAGS') == 0)
                     $flags_str = $a[$i+1];
               }
               // process flags
               $flags_str = eregi_replace('[\\\"]', '', $flags_str);
               $flags_a   = explode(' ', $flags_str);
               if (is_array($flags_a)) {
                  reset($flags_a);
                  while (list(,$val)=each($flags_a)) {
                     if (strcasecmp($val,'Seen') == 0) {
                         $result[$id]->seen = true;
                     } else if (strcasecmp($val, 'Deleted') == 0) {
                         $result[$id]->deleted=true;
                     } else if (strcasecmp($val, 'Recent') == 0) {
                         $result[$id]->recent = true;
                     } else if (strcasecmp($val, 'Answered') == 0) {
                         $result[$id]->answered = true;
                     } else if (strcasecmp($val, '$Forwarded') == 0) {
                         $result[$id]->forwarded = true;
                     } else if (strcasecmp($val, 'Draft') == 0) {
                         $result[$id]->is_draft = true;
                     } else if (strcasecmp($val, '$MDNSent') == 0) {
                         $result[$id]->mdn_sent = true;
                     } else if (strcasecmp($val, 'Flagged') == 0) {
                          $result[$id]->flagged = true;
                     }
                  }
                  $result[$id]->flags = $flags_a;
               }
               $time_str = str_replace('"', '', $time_str);
               // if time is gmt...
                              $time_str = str_replace('GMT','+0000',$time_str);
               //get timezone
               $time_str      = substr($time_str, 0, -1);
               $time_zone_str = substr($time_str, -5); // extract timezone
               $time_str      = substr($time_str, 1, -6); // remove quotes
               $time_zone     = (float)substr($time_zone_str, 1, 2); // get first two digits
               if ($time_zone_str[3] != '0') {
                        $time_zone += 0.5;  //handle half hour offset
               }
               if ($time_zone_str[0] == '-') {
                       $time_zone = $time_zone * -1.0; //minus?
               }
               //calculate timestamp
                                        $timestamp     = strtotime($time_str); //return's server's time
               $timestamp    -= $time_zone * 3600; //compensate for tz, get GMT
               $result[$id]->internaldate = $time_str;
               $result[$id]->timestamp = $timestamp;
               $result[$id]->date = $time_str;
            }
         }
         /*
            Start parsing headers.  The problem is, some header "lines" take up multiple lines.
            So, we'll read ahead, and if the one we're reading now is a valid header, we'll
            process the previous line.  Otherwise, we'll keep adding the strings until we come
            to the next valid header line.
         */
         $i     = 0;
         $lines = array();
         do {
            $line = chop(iil_ReadLine($fp, 300), "\r\n");
            if (ord($line[0])<=32) {
                $lines[$i] .= (empty($lines[$i])?'':"\n").trim(chop($line));
                $lines[$i] .= (empty($lines[$i])?'':"\n").trim($line);
            } else {
               $i++;
               $lines[$i] = trim(chop($line));
               $lines[$i] = trim($line);
            }
            /* 
               The preg_match below works around communigate imap, which outputs " UID <number>)".
               Without this, the while statement continues on and gets the "fh0 OK completed" message.
               Without this, the while statement continues on and gets the "FH0 OK completed" message.
               If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249.  
               This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing
               If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin
@@ -1574,7 +1795,7 @@
            }
         // patch from "Maksim Rubis" <siburny@hotmail.com>
         } while (trim($line[0]) != ')' && strncmp($line, $key, strlen($key)));
         if (strncmp($line, $key, strlen($key))) { 
            //process header, fill iilBasicHeader obj.
            //   initialize
@@ -1589,33 +1810,36 @@
            while ( list($lines_key, $str) = each($lines) ) {
               list($field, $string) = iil_SplitHeaderLine($str);
               
               $field = strtolower($field);
               $field  = strtolower($field);
                                        $string = ereg_replace("\n[[:space:]]*"," ",$string);
               
               switch ($field) {
               case 'date';
                  $result[$id]->date = $string;
                  $result[$id]->timestamp = iil_StrToTime($string);
                  if (!$IMAP_USE_INTERNAL_DATE) {
                     $result[$id]->date = $string;
                     $result[$id]->timestamp = iil_StrToTime($string);
                  }
                  break;
               case 'from':
                  $result[$id]->from = $string;
                  break;
               case 'to':
                  $result[$id]->to = str_replace("\n", " ", $string);
                  $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string);
                  break;
               case 'subject':
                  $result[$id]->subject = str_replace("\n", '', $string);
                  $result[$id]->subject = $string;
                  break;
               case 'reply-to':
                  $result[$id]->replyto = str_replace("\n", " ", $string);
                  $result[$id]->replyto = $string;
                  break;
               case 'cc':
                  $result[$id]->cc = str_replace("\n", " ", $string);
                  $result[$id]->cc = $string;
                  break;
               case 'bcc':
                  $result[$id]->bcc = str_replace("\n", " ", $string);
                  $result[$id]->bcc = $string;
                  break;
               case 'content-transfer-encoding':
                  $result[$id]->encoding = str_replace("\n", " ", $string);
                  $result[$id]->encoding = $string;
                  break;
               case 'content-type':
                  $ctype_parts = explode(";", $string);
@@ -1636,7 +1860,7 @@
               case 'return-receipt-to':
               case 'disposition-notification-to':
               case 'x-confirm-reading-to':
                  $result[$id]->mdn_to = str_replace("\n", " ", $string);
                  $result[$id]->mdn_to = $string;
                  break;
               case 'message-id':
                  $result[$id]->messageID = $string;
@@ -1647,123 +1871,23 @@
                  break;
               } // end switch ()
            } // end while ()
            if ($conn->do_cache) {
               $uid = $result[$id]->uid;
               $conn->cache[$mailbox][$uid] = $result[$id];
               $conn->cache_dirty[$mailbox] = true;
            }
         } else {
            $a = explode(' ', $line);
         }
      }
   } while (strcmp($a[0], $key) != 0);
   /*
      FETCH uid, size, flags
      Sample reply line: "* 3 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen \Deleted))"
   */
   $command_key = 'fh' . ($c++);
   $request  = $command_key . $prefix;
   $request .= " FETCH $message_set (UID RFC822.SIZE FLAGS INTERNALDATE)\r\n";
   if (!fputs($fp, $request)) {
       return false;
   }
    do {
      $line = chop(iil_ReadLine($fp, 200));
      //$a = explode(' ', $line);
      //if (($line[0]=="*") && ($a[2]=="FETCH")) {
      if ($line[0] == '*') {
         //echo "<!-- $line //-->\n";
         //get outter most parens
         $open_pos = strpos($line, "(") + 1;
         $close_pos = strrpos($line, ")");
         if ($open_pos && $close_pos) {
            //extract ID from pre-paren
            $pre_str = substr($line, 0, $open_pos);
            $pre_a = explode(' ', $line);
            $id = $pre_a[1];
            //get data
            $len = $close_pos - $open_pos;
            $str = substr($line, $open_pos, $len);
            //swap parents with quotes, then explode
            $str = eregi_replace("[()]", "\"", $str);
            $a = iil_ExplodeQuotedString(' ', $str);
            //did we get the right number of replies?
            $parts_count = count($a);
            if ($parts_count>=8) {
               for ($i=0;$i<$parts_count;$i=$i+2) {
                  if (strcasecmp($a[$i],"UID") == 0) $result[$id]->uid=$a[$i+1];
                  else if (strcasecmp($a[$i],"RFC822.SIZE") == 0) $result[$id]->size=$a[$i+1];
                  else if (strcasecmp($a[$i],"INTERNALDATE") == 0) $time_str = $a[$i+1];
                  else if (strcasecmp($a[$i],"FLAGS") == 0) $flags_str = $a[$i+1];
               }
               // process flags
               $flags_str = eregi_replace('[\\\"]', '', $flags_str);
               $flags_a = explode(' ', $flags_str);
               //echo "<!-- ID: $id FLAGS: ".implode(",", $flags_a)." //-->\n";
               if (is_array($flags_a)) {
                  reset($flags_a);
                  while (list($key,$val)=each($flags_a)) {
                     if (strcasecmp($val,'Seen') == 0) {
                         $result[$id]->seen = true;
                     } else if (strcasecmp($val, 'Deleted') == 0) {
                         $result[$id]->deleted=true;
                     } else if (strcasecmp($val, 'Recent') == 0) {
                         $result[$id]->recent = true;
                     } else if (strcasecmp($val, 'Answered') == 0) {
                         $result[$id]->answered = true;
                     } else if (strcasecmp($val, "\$MDNSent") == 0) {
                         $result[$id]->mdn_sent = true;
                            }
                  }
                  $result[$id]->flags = $flags_a;
               }
               // if time is gmt...
               $time_str = str_replace('GMT','+0000',$time_str);
               //get timezone
               $time_str      = substr($time_str, 0, -1);
               $time_zone_str = substr($time_str, -5); //extract timezone
               $time_str      = substr($time_str, 1, -6); //remove quotes
               $time_zone     = (float)substr($time_zone_str, 1, 2); //get first two digits
               if ($time_zone_str[3] != '0') {
                   $time_zone += 0.5;  //handle half hour offset
               }
               if ($time_zone_str[0] == '-') {
                  $time_zone = $time_zone * -1.0; //minus?
               }
               $result[$id]->internaldate = $time_str;
               if ($IMAP_USE_INTERNAL_DATE || empty($result[$id]->date)) {
                  //calculate timestamp
                  $timestamp     = strtotime($time_str); //return's server's time
                  $na_timestamp  = $timestamp;
                  $timestamp    -= $time_zone * 3600; //compensate for tz, get GMT
                  $result[$id]->timestamp = $timestamp;
                  $result[$id]->date = $time_str;
               }
               if ($conn->do_cache) {
                  $uid = $result[$id]->uid;
                  $conn->cache[$mailbox][$uid] = $result[$id];
                  $conn->cache_dirty[$mailbox] = true;
               }
               //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";
            } else {
               //echo "<!-- ERROR: $id : $str //-->\n";
            }
         }
      }
   } while (strpos($line, $command_key) === false);
   return $result;
}
function iil_C_FetchHeader(&$conn, $mailbox, $id, $uidfetch=false) {
   $fp = $conn->fp;
   $a  = iil_C_FetchHeaders($conn, $mailbox, $id, $uidfetch);
   if (is_array($a)) {
      return array_shift($a);
@@ -1771,24 +1895,23 @@
   return false;
}
function iil_SortHeaders($a, $field, $flag) {
   if (empty($field)) {
       $field = 'uid';
    }
   }
   $field = strtolower($field);
   if ($field == 'date' || $field == 'internaldate') {
       $field = 'timestamp';
    }
   }
   if (empty($flag)) {
       $flag = 'ASC';
    }
   }
    
   $flag     = strtoupper($flag);
   $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ','"') : array('"');
   $c=count($a);
   if ($c>0) {
   if ($c > 0) {
      /*
         Strategy:
         First, we'll create an "index" array.
@@ -1805,12 +1928,12 @@
            $data = @strtotime($val->date);
            if ($data == false) {
               $data = $val->timestamp;
                }
                     }
         } else {
            $data = $val->$field;
            if (is_string($data)) {
               $data=strtoupper(str_replace($stripArr, '', $data));
                }
                     }
         }
         $index[$key]=$data;
      }
@@ -1818,9 +1941,9 @@
      // sort index
      $i = 0;
      if ($flag == 'ASC') {
          asort($index);
        } else {
            arsort($index);
         asort($index);
          } else {
              arsort($index);
      }
        
      // form new array based on index 
@@ -1836,16 +1959,16 @@
}
function iil_C_Expunge(&$conn, $mailbox) {
   $fp = $conn->fp;
   if (iil_C_Select($conn, $mailbox)) {
      $c=0;
      fputs($fp, "exp1 EXPUNGE\r\n");
      $c = 0;
      iil_PutLine($conn->fp, "exp1 EXPUNGE");
      do {
         $line=chop(iil_ReadLine($fp, 100));
         $line=chop(iil_ReadLine($conn->fp, 100));
         if ($line[0] == '*') {
                $c++;
            }
      } while (!iil_StartsWith($line, 'exp1'));
                     $c++;
              }
      } while (!iil_StartsWith($line, 'exp1', true));
      
      if (iil_ParseResult($line) == 0) {
         $conn->selected = ''; //state has changed, need to reselect         
@@ -1864,27 +1987,20 @@
   }
    
   $fp    = $conn->fp;
   $flags = array(
        'SEEN'     => '\\Seen',
        'DELETED'  => '\\Deleted',
        'RECENT'   => '\\Recent',
        'ANSWERED' => '\\Answered',
        'DRAFT'    => '\\Draft',
        'FLAGGED'  => '\\Flagged',
        'MDNSENT'  => "\$MDNSent");
   $flags = $GLOBALS['IMAP_FLAGS'];
        
   $flag = strtoupper($flag);
   $flag = $flags[$flag];
    
   if (iil_C_Select($conn, $mailbox)) {
      $c=0;
      fputs($fp, "flg STORE $messages " . $mod . "FLAGS (" . $flag . ")\r\n");
      $c = 0;
      iil_PutLine($fp, "flg STORE $messages " . $mod . "FLAGS (" . $flag . ")");
      do {
         $line=chop(iil_ReadLine($fp, 100));
         if ($line[0] == '*') {
             $c++;
            }
      } while (!iil_StartsWith($line, 'flg'));
              }
      } while (!iil_StartsWith($line, 'flg', true));
      if (iil_ParseResult($line) == 0) {
         iil_C_ExpireCachedItems($conn, $mailbox, $messages);
@@ -1913,23 +2029,21 @@
   return iil_C_ModFlag($conn, $mailbox, $messages, 'DELETED', '-');
}
function iil_C_Unseen(&$conn, $mailbox, $messages) {
   return iil_C_ModFlag($conn, $mailbox, $messages, 'SEEN', '-');
}
function iil_C_Copy(&$conn, $messages, $from, $to) {
   $fp = $conn->fp;
   if (empty($from) || empty($to)) {
       return -1;
    }
   }
    
   if (iil_C_Select($conn, $from)) {
      $c=0;
      
      fputs($fp, "cpy1 COPY $messages \"$to\"\r\n");
      iil_PutLine($fp, "cpy1 COPY $messages \"".iil_Escape($to)."\"");
      $line=iil_ReadReply($fp);
      return iil_ParseResult($line);
   } else {
@@ -1939,30 +2053,24 @@
function iil_FormatSearchDate($month, $day, $year) {
   $month  = (int) $month;
    $months = $GLOBALS['IMAP_MONTHS'];
   $months = $GLOBALS['IMAP_MONTHS'];
   return $day . '-' . $months[$month] . '-' . $year;
}
function iil_C_CountUnseen(&$conn, $folder) {
   $index = iil_C_Search($conn, $folder, 'ALL UNSEEN');
   if (is_array($index)) {
      $str = implode(',', $index);
      if (empty($str)) {
          return false;
        }
      return count($index);
      if (($cnt = count($index)) && $index[0] != '') {
         return $cnt;
      }
   }
    return false;
   return false;
}
function iil_C_UID2ID(&$conn, $folder, $uid) {
   if ($uid > 0) {
      $id_a = iil_C_Search($conn, $folder, "UID $uid");
      if (is_array($id_a)) {
         $count = count($id_a);
         if ($count > 1) {
             return false;
            }
      if (is_array($id_a) && count($id_a) == 1) {
         return $id_a[0];
      }
   }
@@ -1973,11 +2081,11 @@
   $fp = $conn->fp;
   if ($id == 0) {
       return    -1;
    }
    $result = -1;
   }
   $result = -1;
   if (iil_C_Select($conn, $folder)) {
      $key = 'FUID';
      if (fputs($fp, "$key FETCH $id (UID)\r\n")) {
      if (iil_PutLine($fp, "$key FETCH $id (UID)")) {
         do {
            $line=chop(iil_ReadLine($fp, 1024));
            if (eregi("^\* $id FETCH \(UID (.*)\)", $line, $r)) {
@@ -1992,41 +2100,39 @@
function iil_C_Search(&$conn, $folder, $criteria) {
   $fp = $conn->fp;
   if (iil_C_Select($conn, $folder)) {
      $c=0;
      $c = 0;
      
      $query = 'srch1 SEARCH ' . chop($criteria) . "\r\n";
      fputs($fp, $query);
      $query = 'srch1 SEARCH ' . chop($criteria);
      iil_PutLineC($fp, $query);
      do {
         $line=trim(chop(iil_ReadLine($fp, 10000)));
         $line=trim(iil_ReadLine($fp, 10000));
         if (eregi("^\* SEARCH", $line)) {
            $str = trim(substr($line, 8));
            $messages = explode(' ', $str);
         }
      } while (!iil_StartsWith($line, "srch1"));
      $result_code=iil_ParseResult($line);
      if ($result_code==0) {
      } while (!iil_StartsWith($line, 'srch1', true));
      $result_code = iil_ParseResult($line);
      if ($result_code == 0) {
          return $messages;
      }
      $conn->error = 'iil_C_Search: ' . $line . "\n";
      return false;
      return false;
   }
   $conn->error = "iil_C_Search: Couldn't select \"$folder\"\n";
   return false;
}
function iil_C_Move(&$conn, $messages, $from, $to) {
   $fp = $conn->fp;
   if (!$from || !$to) {
       return -1;
   }
   $r=iil_C_Copy($conn, $messages, $from,$to);
   if ($r==0) {
      return iil_C_Delete($conn, $from, $messages);
   }
    $fp = $conn->fp;
    if (!$from || !$to) {
        return -1;
    }
    $r = iil_C_Copy($conn, $messages, $from,$to);
    if ($r==0) {
        return iil_C_Delete($conn, $from, $messages);
    }
    return $r;
}
@@ -2041,17 +2147,23 @@
 * @see iil_Connect()
 */
function iil_C_GetHierarchyDelimiter(&$conn) {
   global $my_prefs;
   if ($conn->delimiter) {
        return $conn->delimiter;
          return $conn->delimiter;
   }
   if (!empty($my_prefs['delimiter'])) {
           return ($conn->delimiter = $my_prefs['delimiter']);
   }
    
   $fp        = $conn->fp;
   $delimiter = false;
   
   //try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
   if (!fputs($fp, 'ghd LIST "" ""' . "\r\n")) {
   if (!iil_PutLine($fp, 'ghd LIST "" ""')) {
       return false;
    }
   }
    
   do {
      $line=iil_ReadLine($fp, 500);
@@ -2060,9 +2172,9 @@
         $a=iil_ExplodeQuotedString(' ', $line);
         if ($a[0] == '*') {
             $delimiter = str_replace('"', '', $a[count($a)-2]);
            }
              }
      }
   } while (!iil_StartsWith($line, 'ghd'));
   } while (!iil_StartsWith($line, 'ghd', true));
   if (strlen($delimiter)>0) {
       return $delimiter;
@@ -2070,14 +2182,14 @@
    
   //if that fails, try namespace extension
   //try to fetch namespace data
   fputs($conn->fp, "ns1 NAMESPACE\r\n");
   iil_PutLine($conn->fp, "ns1 NAMESPACE");
   do {
      $line = iil_ReadLine($conn->fp, 1024);
      if (iil_StartsWith($line, '* NAMESPACE')) {
         $i = 0;
         $data = iil_ParseNamespace2(substr($line,11), $i, 0, 0);
      }
   } while (!iil_StartsWith($line, 'ns1'));
   } while (!iil_StartsWith($line, 'ns1', true));
      
   if (!is_array($data)) {
       return false;
@@ -2093,7 +2205,7 @@
   $first_userspace = $user_space_data[0];
   if (!is_array($first_userspace)) {
       return false;
    }
   }
    
   //extract delimiter
   $delimiter = $first_userspace[1];   
@@ -2107,20 +2219,22 @@
   $ignore = $IGNORE_FOLDERS[strtolower($conn->host)];
      
   $fp = $conn->fp;
   if (empty($mailbox)) {
       $mailbox = '*';
    }
   }
   if (empty($ref) && $conn->rootdir) {
       $ref = $conn->rootdir;
   }
    
    // send command
   if (!fputs($fp, "lmb LIST \"".$ref."\" \"$mailbox\"\r\n")) {
   // send command
   if (!iil_PutLine($fp, "lmb LIST \"".$ref."\" \"".iil_Escape($mailbox)."\"")) {
       return false;
    }
   }
    
   $i = 0;
    // get folder list
   // get folder list
   do {
      $line = iil_ReadLine($fp, 500);
      $line = iil_MultLine($fp, $line);
@@ -2128,40 +2242,40 @@
      $a = explode(' ', $line);
      if (($line[0] == '*') && ($a[1] == 'LIST')) {
         $line = rtrim($line);
            // split one line
              // split one line
         $a = iil_ExplodeQuotedString(' ', $line);
              // last string is folder name
         $folder = trim($a[count($a)-1], '"');
            
            // last string is folder name
         $folder = str_replace('"', '', $a[count($a)-1]);
              if (empty($ignore) || (!empty($ignore)
                     && !eregi($ignore, $folder))) {
                     $folders[$i] = $folder;
              }
            
            if (empty($ignore) || (!empty($ignore)
                && !eregi($ignore, $folder))) {
                $folders[$i] = $folder;
            }
            // second from last is delimiter
            $delim = str_replace('"', '', $a[count($a)-2]);
            // is it a container?
            $i++;
              // second from last is delimiter
              $delim = trim($a[count($a)-2], '"');
              // is it a container?
              $i++;
      }
   } while (!iil_StartsWith($line, 'lmb'));
   } while (!iil_StartsWith($line, 'lmb', true));
   if (is_array($folders)) {
        if (!empty($ref)) {
            // if rootdir was specified, make sure it's the first element
            // some IMAP servers (i.e. Courier) won't return it
            if ($ref[strlen($ref)-1]==$delim) $ref = substr($ref, 0, strlen($ref)-1);
            if ($folders[0]!=$ref) array_unshift($folders, $ref);
        }
        return $folders;
   }else if (iil_ParseResult($line) == 0) {
           if (!empty($ref)) {
           // if rootdir was specified, make sure it's the first element
           // some IMAP servers (i.e. Courier) won't return it
           if ($ref[strlen($ref)-1]==$delim)
          $ref = substr($ref, 0, strlen($ref)-1);
          if ($folders[0]!=$ref)
          array_unshift($folders, $ref);
           }
           return $folders;
   } else if (iil_ParseResult($line) == 0) {
      return array('INBOX');
   } else {
      $conn->error = $line;
      return false;
   }
}
function iil_C_ListSubscribed(&$conn, $ref, $mailbox) {
   global $IGNORE_FOLDERS;
@@ -2177,15 +2291,15 @@
   }
   $folders = array();
    // send command
   if (!fputs($fp, 'lsb LSUB "' . $ref . '" "' . $mailbox.'"' . "\r\n")) {
   // send command
   if (!iil_PutLine($fp, 'lsb LSUB "' . $ref . '" "' . iil_Escape($mailbox).'"')) {
      $conn->error = "Couldn't send LSUB command\n";
      return false;
   }
   
   $i = 0;
   
    // get folder list
   // get folder list
   do {
      $line = iil_ReadLine($fp, 500);
      $line = iil_MultLine($fp, $line);
@@ -2194,198 +2308,200 @@
      if (($line[0] == '*') && ($a[1] == 'LSUB' || $a[1] == 'LIST')) {
         $line = rtrim($line);
            
            // split one line
              // split one line
         $a = iil_ExplodeQuotedString(' ', $line);
            
            // last string is folder name
            //$folder = UTF7DecodeString(str_replace('"', '', $a[count($a)-1]));
            $folder = str_replace('"', '', $a[count($a)-1]);
              // last string is folder name
              //$folder = UTF7DecodeString(str_replace('"', '', $a[count($a)-1]));
              $folder = trim($a[count($a)-1], '"');
            
         if ((!in_array($folder, $folders)) && (empty($ignore)
                || (!empty($ignore) && !eregi($ignore, $folder)))) {
                     || (!empty($ignore) && !eregi($ignore, $folder)))) {
             $folders[$i] = $folder;
            }
              }
            
            // second from last is delimiter
            $delim = str_replace('"', '', $a[count($a)-2]);
              // second from last is delimiter
              $delim = trim($a[count($a)-2], '"');
            
            // is it a container?
            $i++;
              // is it a container?
              $i++;
      }
   } while (!iil_StartsWith($line, 'lsb'));
   } while (!iil_StartsWith($line, 'lsb', true));
   if (is_array($folders)) {
        if (!empty($ref)) {
            // if rootdir was specified, make sure it's the first element
            // some IMAP servers (i.e. Courier) won't return it
            if ($ref[strlen($ref)-1]==$delim) {
                $ref = substr($ref, 0, strlen($ref)-1);
            }
            if ($folders[0]!=$ref) {
                array_unshift($folders, $ref);
            }
        }
        return $folders;
           if (!empty($ref)) {
           // if rootdir was specified, make sure it's the first element
           // some IMAP servers (i.e. Courier) won't return it
           if ($ref[strlen($ref)-1]==$delim) {
                   $ref = substr($ref, 0, strlen($ref)-1);
           }
           if ($folders[0]!=$ref) {
                   array_unshift($folders, $ref);
           }
           }
           return $folders;
   }
   $conn->error = $line;
   return false;
}
function iil_C_Subscribe(&$conn, $folder) {
   $fp = $conn->fp;
   $query = 'sub1 SUBSCRIBE "' . $folder. '"' . "\r\n";
   fputs($fp, $query);
   $line = trim(chop(iil_ReadLine($fp, 10000)));
   $query = 'sub1 SUBSCRIBE "' . iil_Escape($folder). '"';
   iil_PutLine($fp, $query);
   $line = trim(iil_ReadLine($fp, 10000));
   return iil_ParseResult($line);
}
function iil_C_UnSubscribe(&$conn, $folder) {
   $fp = $conn->fp;
   $query = 'usub1 UNSUBSCRIBE "' . $folder . '"' . "\r\n";
   fputs($fp, $query);
   $query = 'usub1 UNSUBSCRIBE "' . iil_Escape($folder) . '"';
   iil_PutLine($fp, $query);
    
   $line = trim(chop(iil_ReadLine($fp, 10000)));
   $line = trim(iil_ReadLine($fp, 10000));
   return iil_ParseResult($line);
}
function iil_C_FetchPartHeader(&$conn, $mailbox, $id, $part) {
   $fp     = $conn->fp;
   $result = false;
   if (($part == 0) || (empty($part))) {
       $part = 'HEADER';
    } else {
        $part .= '.MIME';
   }
   if (iil_C_Select($conn, $mailbox)) {
      $key     = 'fh' . ($c++);
      $request = $key . " FETCH $id (BODY.PEEK[$part])\r\n";
      if (!fputs($fp, $request)) return false;
      do {
         $line=chop(iil_ReadLine($fp, 200));
         $a=explode(' ', $line);
         if (($line[0] == '*') && ($a[2] == 'FETCH')
                && ($line[strlen($line)-1] != ')')) {
            $line=iil_ReadLine($fp, 300);
            while (chop($line)!=")") {
               $result.=$line;
               $line=iil_ReadLine($fp, 300);
            }
         }
      } while (strcmp($a[0], $key)!=0);
   }
   return $result;
   $part = empty($part) ? 'HEADER' : $part.'.MIME';
   return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
}
function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) {
    /* modes:
        1: return string
function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part='', $mode=1, $file=NULL) {
   /* modes:
        1: return string (or write to $file pointer)
        2: print
        3: base64 and print
    */
        3: base64 and print (or write to $file pointer)
   */
   $fp     = $conn->fp;
   $result = false;
   if (($part==0) || (empty($part))) {
       $part = 'TEXT';
   }
   if (iil_C_Select($conn, $mailbox)) {
        $reply_key='* ' . $id;
          $reply_key = '* ' . $id;
        
        // format request
          // format request
      $key     = 'ftch' . ($c++) . ' ';
      $request = $key . "FETCH $id (BODY.PEEK[$part])\r\n";
        // send request
      if (!fputs($fp, $request)) {
      $request = $key . "FETCH $id (BODY.PEEK[$part])";
          // send request
      if (!iil_PutLine($fp, $request)) {
          return false;
        }
          }
        
        // receive reply line
        do {
            $line = chop(iil_ReadLine($fp, 1000));
            $a    = explode(' ', $line);
        } while ($a[2] != 'FETCH');
        $len = strlen($line);
        if ($line[$len-1] == ')') {
            //one line response, get everything between first and last quotes
            $from = strpos($line, '"') + 1;
            $to   = strrpos($line, '"');
            $len  = $to - $from;
            if ($mode == 1) {
                $result = substr($line, $from, $len);
            } else if ($mode == 2) {
                echo substr($line, $from, $len);
            } else if ($mode == 3) {
                echo base64_decode(substr($line, $from, $len));
            }
        }else if ($line[$len-1] == '}') {
            //multi-line request, find sizes of content and receive that many bytes
            $from     = strpos($line, '{') + 1;
            $to       = strrpos($line, '}');
            $len      = $to - $from;
            $sizeStr  = substr($line, $from, $len);
            $bytes    = (int)$sizeStr;
            $received = 0;
            while ($received < $bytes) {
                $remaining = $bytes - $received;
                $line      = iil_ReadLine($fp, 1024);
                $len       = strlen($line);
          // receive reply line
          do {
              $line = chop(iil_ReadLine($fp, 1000));
              $a    = explode(' ', $line);
          } while ($a[2] != 'FETCH');
          $len = strlen($line);
      // handle empty "* X FETCH ()" response
          if ($line[$len-1] == ')' && $line[$len-2] != '(') {
              // one line response, get everything between first and last quotes
         if (substr($line, -4, 3) == 'NIL') {
            // NIL response
            $result = '';
         } else {
                 $from = strpos($line, '"') + 1;
                 $to   = strrpos($line, '"');
                 $len  = $to - $from;
            $result = substr($line, $from, $len);
         }
                   if ($mode == 2) {
                      echo $result;
                   } else if ($mode == 3) {
            if ($file)
               fwrite($file, base64_decode($result));
                     else
               echo base64_decode($result);
         }
          } else if ($line[$len-1] == '}') {
                   //multi-line request, find sizes of content and receive that many bytes
              $from     = strpos($line, '{') + 1;
                   $to       = strrpos($line, '}');
              $len      = $to - $from;
                   $sizeStr  = substr($line, $from, $len);
              $bytes    = (int)$sizeStr;
              while ($bytes > 0) {
                          $line      = iil_ReadLine($fp, 1024);
                     $len       = strlen($line);
                
                if ($len > $remaining) {
                    $line = substr($line, 0, $remaining);
                }
                $received += strlen($line);
                if ($mode==1) {
                    $result .= chop($line)."\n";
                } else if ($mode==2) {
                    echo chop($line)."\n"; flush();
                } else if ($mode==3) {
                    echo base64_decode($line); flush();
                }
            }
        }
        // read in anything up until 'til last line
                      if ($len > $bytes) {
                             $line = substr($line, 0, $bytes);
                      }
                     $bytes -= strlen($line);
                      if ($mode == 1) {
               if ($file)
                  fwrite($file, rtrim($line, "\t\r\n\0\x0B") . "\n");
                             else
                  $result .= rtrim($line, "\t\r\n\0\x0B") . "\n";
                      } else if ($mode == 2) {
                             echo rtrim($line, "\t\r\n\0\x0B") . "\n";
                      } else if ($mode == 3) {
               if ($file)
                  fwrite($file, base64_decode($line));
                        else
                  echo base64_decode($line);
            }
              }
          }
           // read in anything up until last line
      do {
            $line = iil_ReadLine($fp, 1024);
      } while (!iil_StartsWith($line, $key));
              $line = iil_ReadLine($fp, 1024);
      } while (!iil_StartsWith($line, $key, true));
        
        if ($result) {
         $result = chop($result);
            return $result; // substr($result, 0, strlen($result)-1);
        }
        return false;
      if ($mode == 3 && $file) {
         return true;
      }
          if ($result) {
             $result = rtrim($result, "\t\r\n\0\x0B");
         if ($file) {
            fwrite($file, $result);
            return true;
         }
         return $result; // substr($result, 0, strlen($result)-1);
          }
      return false;
   } else {
      echo 'Select failed.';
   }
    
    if ($mode==1) {
        return $result;
    }
    return $received;
   if ($mode==1) {
      if ($file) {
         fwrite($file, $result);
         return true;
      }
          return $result;
   }
   return false;
}
function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part) {
    return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1);
function iil_C_FetchPartBody(&$conn, $mailbox, $id, $part, $file=NULL) {
   return iil_C_HandlePartBody($conn, $mailbox, $id, $part, 1, $file);
}
function iil_C_PrintPartBody(&$conn, $mailbox, $id, $part) {
    iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
   iil_C_HandlePartBody($conn, $mailbox, $id, $part, 2);
}
function iil_C_PrintBase64Body(&$conn, $mailbox, $id, $part) {
    iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
   iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3);
}
function iil_C_CreateFolder(&$conn, $folder) {
   $fp = $conn->fp;
   if (fputs($fp, 'c CREATE "' . $folder . '"' . "\r\n")) {
   if (iil_PutLine($fp, 'c CREATE "' . iil_Escape($folder) . '"')) {
      do {
         $line=iil_ReadLine($fp, 300);
      } while ($line[0] != 'c');
@@ -2397,43 +2513,46 @@
function iil_C_RenameFolder(&$conn, $from, $to) {
   $fp = $conn->fp;
   if (fputs($fp, 'r RENAME "' . $from . '" "' . $to . '"' . "\r\n")) {
   if (iil_PutLine($fp, 'r RENAME "' . iil_Escape($from) . '" "' . iil_Escape($to) . '"')) {
      do {
         $line=iil_ReadLine($fp, 300);
      } while ($line[0]!="r");
         $line = iil_ReadLine($fp, 300);
      } while ($line[0] != 'r');
      return (iil_ParseResult($line) == 0);
   }
    return false;
   return false;
}
function iil_C_DeleteFolder(&$conn, $folder) {
   $fp = $conn->fp;
   if (fputs($fp, 'd DELETE "' . $folder. '"' . "\r\n")) {
   if (iil_PutLine($fp, 'd DELETE "' . iil_Escape($folder). '"')) {
      do {
         $line=iil_ReadLine($fp, 300);
      } while ($line[0]!="d");
      } while ($line[0] != 'd');
      return (iil_ParseResult($line) == 0);
   }
    $conn->error = "Couldn't send command\n";
   $conn->error = "Couldn't send command\n";
   return false;
}
function iil_C_Append(&$conn, $folder, &$message) {
   if (!$folder) return false;
   if (!$folder) {
          return false;
   }
   $fp = $conn->fp;
   $message = str_replace("\r", '', $message);
   $message = str_replace("\n", "\r\n", $message);      
   $len = strlen($message);
   if (!$len) return false;
   $request = 'A APPEND "' . $folder .'" (\\Seen) {' . $len . "}\r\n";
   if (!$len) {
          return false;
   }
   $request = 'A APPEND "' . iil_Escape($folder) .'" (\\Seen) {' . $len . '}';
    
   if (fputs($fp, $request)) {
   if (iil_PutLine($fp, $request)) {
      $line=iil_ReadLine($fp, 100);      
      $sent = fwrite($fp, $message."\r\n");
      flush();
      do {
         $line=iil_ReadLine($fp, 1000);
      } while ($line[0] != 'A');
@@ -2441,14 +2560,13 @@
      $result = (iil_ParseResult($line) == 0);
      if (!$result) {
          $conn->error .= $line . "\n";
        }
          }
      return $result;
   }
   $conn->error .= "Couldn't send command \"$request\"\n";
    return false;
}
   $conn->error .= "Couldn't send command \"$request\"\n";
   return false;
}
function iil_C_AppendFromFile(&$conn, $folder, $path) {
   if (!$folder) {
@@ -2458,8 +2576,8 @@
   //open message file
   $in_fp = false;            
   if (file_exists(realpath($path))) {
       $in_fp = fopen($path, 'r');
    }
      $in_fp = fopen($path, 'r');
   }
   if (!$in_fp) { 
      $conn->error .= "Couldn't open $path for reading\n";
      return false;
@@ -2468,72 +2586,59 @@
   $fp  = $conn->fp;
   $len = filesize($path);
   if (!$len) {
       return false;
      return false;
   }
    
   //send APPEND command
   $request    = 'A APPEND "' . $folder . '" (\\Seen) {' . $len . "}\r\n";
   $request    = 'A APPEND "' . iil_Escape($folder) . '" (\\Seen) {' . $len . '}';
   $bytes_sent = 0;
   if (fputs($fp, $request)) {
      $line=iil_ReadLine($fp, 100);
   if (iil_PutLine($fp, $request)) {
      $line = iil_ReadLine($fp, 100);
            
      //send file
      while (!feof($in_fp)) {
         $buffer = fgets($in_fp, 4096);
         $buffer      = fgets($in_fp, 4096);
         $bytes_sent += strlen($buffer);
         fputs($fp, $buffer);
         iil_PutLine($fp, $buffer, false);
      }
      fclose($in_fp);
      fputs($fp, "\r\n");
      iil_PutLine($fp, '');
      //read response
      do {
         $line=iil_ReadLine($fp, 1000);
         $line = iil_ReadLine($fp, 1000);
      } while ($line[0] != 'A');
         
      $result = (iil_ParseResult($line) == 0);
      if (!$result) {
          $conn->error .= $line . "\n";
      }
        return $result;
      return $result;
   }
   $conn->error .= "Couldn't send command \"$request\"\n";
   return false;
}
function iil_C_FetchStructureString(&$conn, $folder, $id) {
   $fp     = $conn->fp;
   $result = false;
   if (iil_C_Select($conn, $folder)) {
      $key = 'F1247';
      if (fputs($fp, "$key FETCH $id (BODYSTRUCTURE)\r\n")) {
      if (iil_PutLine($fp, "$key FETCH $id (BODYSTRUCTURE)")) {
         do {
            $line=chop(iil_ReadLine($fp, 5000));
            if ($line[0] == '*') {
               if (ereg("\}$", $line)) {
                  preg_match('/(.+)\{([0-9]+)\}/', $line, $match);
                  $result = $match[1];
                  do {
                     $line = chop(iil_ReadLine($fp, 100));
                     if (!preg_match("/^$key/", $line)) {
                         $result .= $line;
                            } else {
                                $done = true;
                            }
                  } while (!$done);
               } else {
                  $result = $line;
               }
               list($pre, $post) = explode('BODYSTRUCTURE ', $result);
               //truncate last ')' and return
               $result = substr($post, 0, strlen($post)-1);
            }
         } while (!preg_match("/^$key/",$line));
            $line = iil_ReadLine($fp, 5000);
            $line = iil_MultLine($fp, $line);
            list(, $index, $cmd, $rest) = explode(' ', $line);
            if ($cmd != 'FETCH' || $index == $id || preg_match("/^$key/", $line))
               $result .= $line;
         } while (!preg_match("/^$key/", $line));
         $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -(strlen($result)-strrpos($result, $key)+1)));
      }
   }
   return $result;
@@ -2558,41 +2663,35 @@
   $quota_line = '';
   
   //get line containing quota info
   if (fputs($fp, 'QUOT1 GETQUOTAROOT "INBOX"' . "\r\n")) {
   if (iil_PutLine($fp, 'QUOT1 GETQUOTAROOT "INBOX"')) {
      do {
         $line=chop(iil_ReadLine($fp, 5000));
         if (iil_StartsWith($line, '* QUOTA ')) {
             $quota_line = $line;
            }
      } while (!iil_StartsWith($line, 'QUOT1'));
            $quota_line = $line;
              }
      } while (!iil_StartsWith($line, 'QUOT1', true));
   }
   
   //return false if not found, parse if found
   if (!empty($quota_line)) {
      $quota_line = eregi_replace('[()]', '', $quota_line);
      $parts = explode(' ', $quota_line);
      $quota_line   = eregi_replace('[()]', '', $quota_line);
      $parts        = explode(' ', $quota_line);
      $storage_part = array_search('STORAGE', $parts);
      if ($storage_part>0) {
         $result = array();
         $used   = $parts[$storage_part+1];
         $total  = $parts[$storage_part+2];
         $result['used']    = $used;
         $result['total']   = (empty($total)?"??":$total);
         $result['percent'] = (empty($total)?"??":round(($used/$total)*100));
      if ($storage_part > 0) {
         $result['used']    = intval($parts[$storage_part+1]);
         $result['total']   = intval($parts[$storage_part+2]);
         $result['percent'] = min(100, round(($result['used']/max(1,$result['total']))*100));
         $result['free']    = 100 - $result['percent'];
      }
   }
   return $result;
}
function iil_C_ClearFolder(&$conn, $folder) {
   $num_in_trash = iil_C_CountMessages($conn, $folder);
   if ($num_in_trash > 0) {
       iil_C_Delete($conn, $folder, '1:' . $num_in_trash);
    }
      iil_C_Delete($conn, $folder, '1:' . $num_in_trash);
   }
   return (iil_C_Expunge($conn, $folder) >= 0);
}