Пример #1
0
void nsEudoraWin32::GetMimeTypeFromExtension( nsCString& ext, nsCString& mimeType)
{
  HKEY  sKey;
  if (::RegOpenKeyEx( HKEY_CLASSES_ROOT, ext.get(), 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS)
  {
    // get the value of "Current"
    BYTE *pBytes = GetValueBytes( sKey, "Content Type");
    if (pBytes)
    {
      mimeType = (const char *)pBytes;
      delete [] pBytes;
    }
    ::RegCloseKey( sKey);
  }

  if (!mimeType.IsEmpty() || !m_mailImportLocation || (ext.Length() > 10))
    return;

  // TLR: FIXME: We should/could cache the extension to mime type maps we find
  // and check the cache first before scanning all of eudora's mappings?

  // It's not in the registry, try and find the .ini file for Eudora's private
  // mime type list
  if (!m_pMimeSection)
  {
    nsCOMPtr <nsILocalFile> pFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
    if (!pFile)
      return;

    pFile->InitWithFile(m_mailImportLocation);

    pFile->AppendNative(NS_LITERAL_CSTRING("eudora.ini"));
    bool exists = false;
    bool isFile = false;
    nsresult rv = pFile->Exists( &exists);
    if (NS_SUCCEEDED( rv))
      rv = pFile->IsFile( &isFile);
    if (!isFile || !exists)
    {
      rv = pFile->InitWithFile( m_mailImportLocation);
      if (NS_FAILED( rv))
        return;
      if (!FindMimeIniFile( pFile))
        return;
    }

    nsCAutoString fileName;
    pFile->GetNativePath(fileName);
    if (fileName.IsEmpty())
      return;
    // Read the mime map section
    DWORD  size = 1024;
    DWORD  dSize = size - 2;
    while (dSize == (size - 2))
    {
      if (m_pMimeSection)
        delete [] m_pMimeSection;
      size += 1024;
      m_pMimeSection = new char[size];
      dSize = ::GetPrivateProfileSection( "Mappings", m_pMimeSection, size, fileName.get());
    }
  }

  if (!m_pMimeSection)
    return;

  IMPORT_LOG1( "Looking for mime type for extension: %s\n", ext.get());

  // out/in/both=extension,mac creator,mac type,mime type1,mime type2
  const char *pExt = ext.get();
  pExt++;

  char  *  pChar = m_pMimeSection;
  char  *  pStart;
  int      len;
  nsCString  tStr;
  for(;;)
  {
    while (*pChar != '=')
    {
      if (!(*pChar) && !(*(pChar + 1)))
        return;
      pChar++;
    }
    if (*pChar)
      pChar++;
    pStart = pChar;
    len = 0;
    while (*pChar && (*pChar != ','))
    {
      pChar++;
      len++;
    }
    if (!*pChar)
      return;

    tStr.Truncate();
    tStr.Append( pStart, len);
    tStr.Trim( kWhitespace);
    if (!PL_strcasecmp( tStr.get(), pExt))
    {
      // skip the mac creator and type
      pChar++;
      while (*pChar && (*pChar != ','))
        pChar++;
      if (!*pChar)
        return;

      pChar++;
      while (*pChar && (*pChar != ','))
        pChar++;
      if (!*pChar)
        return;

      pChar++;
      // Get the first mime type
      len = 0;
      pStart = pChar;
      while (*pChar && (*pChar != ','))
      {
        pChar++;
        len++;
      }
      if (!*pChar)
        return;

      pChar++;
      if (!len)
        continue;

      tStr.Truncate();
      tStr.Append( pStart, len);
      tStr.Trim( kWhitespace);
      if (tStr.IsEmpty())
        continue;

      mimeType.Truncate();
      mimeType.Append( tStr.get());
      mimeType.Append( "/");
      pStart = pChar;
      len = 0;
      // Skip to next end of line.
      while (*pChar && (*pChar != nsCRT::CR) && (*pChar != nsCRT::LF))
      {
        pChar++;
        len++;
      }
      if (!len)
        continue;

      tStr.Truncate();
      tStr.Append( pStart, len);
      tStr.Trim( kWhitespace);
      if (tStr.IsEmpty())
        continue;

      mimeType.Append( tStr.get());

      IMPORT_LOG1( "Found Mime Type: %s\n", mimeType.get());

      return;
    }
  }
}
Пример #2
0
void AppendUid(nsCString &msgIds, PRUint32 uid)
{
  char buf[20];
  PR_snprintf(buf, sizeof(buf), "%u", uid);
  msgIds.Append(buf);
}
Пример #3
0
nsresult nsAbBoolExprToLDAPFilter::FilterCondition (
    nsIAbLDAPAttributeMap* map,
    nsIAbBooleanConditionString* condition,
    nsCString& filter,
    int flags)
{
    nsCString name;
    nsresult rv = condition->GetName(getter_Copies (name));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCAutoString ldapAttr(name);
    if (flags & TRANSLATE_CARD_PROPERTY)
    {
        rv = map->GetFirstAttribute (name, ldapAttr);
        if (!(flags & ALLOW_NON_CONVERTABLE_CARD_PROPERTY) && 
            !ATTRMAP_FOUND_ATTR(rv, ldapAttr))
            return NS_OK;
    }

    nsAbBooleanConditionType conditionType;
    rv = condition->GetCondition(&conditionType);
    NS_ENSURE_SUCCESS(rv, rv);

    nsString value;
    rv = condition->GetValue (getter_Copies (value));
    NS_ENSURE_SUCCESS(rv, rv);
    NS_ConvertUTF16toUTF8 vUTF8 (value);

    switch (conditionType)
    {
        case nsIAbBooleanConditionTypes::DoesNotExist:
            filter.AppendLiteral("(!("); 
            filter.Append(ldapAttr);
            filter.AppendLiteral("=*))");
            break;
        case nsIAbBooleanConditionTypes::Exists:
            filter.AppendLiteral("("); 
            filter.Append(ldapAttr);
            filter.AppendLiteral("=*)");
            break;
        case nsIAbBooleanConditionTypes::Contains:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.Append("=*");
            filter.Append(vUTF8);
            filter.AppendLiteral("*)");
            break;
        case nsIAbBooleanConditionTypes::DoesNotContain:
            filter.AppendLiteral("(!(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("=*");
            filter.Append(vUTF8);
            filter.AppendLiteral("*))");
            break;
        case nsIAbBooleanConditionTypes::Is:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("=");
            filter.Append(vUTF8);
            filter.AppendLiteral(")");
            break;
        case nsIAbBooleanConditionTypes::IsNot:
            filter.AppendLiteral("(!(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("=");
            filter.Append(vUTF8);
            filter.AppendLiteral("))");
            break;
        case nsIAbBooleanConditionTypes::BeginsWith:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("=");
            filter.Append(vUTF8);
            filter.AppendLiteral("*)");
            break;
        case nsIAbBooleanConditionTypes::EndsWith:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("=*");
            filter.Append(vUTF8);
            filter.AppendLiteral(")");
            break;
        case nsIAbBooleanConditionTypes::LessThan:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("<=");
            filter.Append(vUTF8);
            filter.AppendLiteral(")");
            break;
        case nsIAbBooleanConditionTypes::GreaterThan:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.AppendLiteral(">=");
            filter.Append(vUTF8);
            filter.AppendLiteral(")");
            break;
        case nsIAbBooleanConditionTypes::SoundsLike:
            filter.AppendLiteral("(");
            filter.Append(ldapAttr);
            filter.AppendLiteral("~=");
            filter.Append(vUTF8);
            filter.AppendLiteral(")");
            break;
        case nsIAbBooleanConditionTypes::RegExp:
            break;
        default:
            break;
    }

    return rv;
}
bool CAliasData::Process(const char *pLine, int32_t len)
{
  // Extract any comments first!
  nsCString  str;

  const char *pStart = pLine;
  int32_t    tCnt = 0;
  int32_t    cnt = 0;
  int32_t    max = len;
  bool      endCollect = false;

    // Keep track of the full entry without any processing for potential alias
    // nickname resolution. Previously alias resolution was done with m_email,
    // but unfortunately that doesn't work for nicknames with spaces.
    // For example for the nickname "Joe Smith", "Smith" was being interpreted
    // as the potential email address and placed in m_email, but routines like
    // ResolveAlias were failing because "Smith" is not the full nickname.
    // Now we just stash the full entry for nickname resolution before processing
    // the line as a potential entry in its own right.
    m_fullEntry.Append(pLine, len);

  while (max) {
    if (*pLine == '"') {
      if (tCnt && !endCollect) {
        str.Trim(kWhitespace);
        if (!str.IsEmpty())
          str.Append(" ", 1);
        str.Append(pStart, tCnt);
      }
      cnt = nsEudoraAddress::CountQuote(pLine, max);
      if ((cnt > 2) && m_realName.IsEmpty()) {
        m_realName.Append(pLine + 1, cnt - 2);
      }
      pLine += cnt;
      max -= cnt;
      pStart = pLine;
      tCnt = 0;
    }
    else if (*pLine == '<') {
      if (tCnt && !endCollect) {
        str.Trim(kWhitespace);
        if (!str.IsEmpty())
          str.Append(" ", 1);
        str.Append(pStart, tCnt);
      }
      cnt = nsEudoraAddress::CountAngle(pLine, max);
      if ((cnt > 2) && m_email.IsEmpty()) {
        m_email.Append(pLine + 1, cnt - 2);
      }
      pLine += cnt;
      max -= cnt;
      pStart = pLine;
      tCnt = 0;
      endCollect = true;
    }
    else if (*pLine == '(') {
      if (tCnt && !endCollect) {
        str.Trim(kWhitespace);
        if (!str.IsEmpty())
          str.Append(" ", 1);
        str.Append(pStart, tCnt);
      }
      cnt = nsEudoraAddress::CountComment(pLine, max);
      if (cnt > 2) {
        if (!m_realName.IsEmpty() && m_nickName.IsEmpty())
          m_nickName = m_realName;
        m_realName.Truncate();
        m_realName.Append(pLine + 1, cnt - 2);
      }
      pLine += cnt;
      max -= cnt;
      pStart = pLine;
      tCnt = 0;
    }
    else {
      tCnt++;
      pLine++;
      max--;
    }
  }

  if (tCnt) {
    str.Trim(kWhitespace);
    if (!str.IsEmpty())
      str.Append(" ", 1);
    str.Append(pStart, tCnt);
  }

  str.Trim(kWhitespace);

  if (!m_realName.IsEmpty() && !m_email.IsEmpty())
    return true;

  // now we should have a string with any remaining non-delimitted text
  // we assume that the last token is the email
  // anything before that is realName
  if (!m_email.IsEmpty()) {
    m_realName = str;
    return true;
  }

  tCnt = str.RFindChar(' ');
  if (tCnt == -1) {
    if (!str.IsEmpty()) {
      m_email = str;
      return true;
    }
    return false;
  }

  m_email = Substring(str, tCnt + 1);
  m_realName = StringHead(str, tCnt);
  m_realName.Trim(kWhitespace);
  m_email.Trim(kWhitespace);

  return !m_email.IsEmpty();
}
Пример #5
0
void nsEudoraCompose::GetNthHeader(const char *pData,
                                   int32_t dataLen,
                                   int32_t n,
                                   nsCString& header,
                                   nsCString& val,
                                   bool unwrap)
{
  header.Truncate();
  val.Truncate();
  if (!pData)
    return;

  int32_t index = 0;
  int32_t len;
  int32_t start = 0;
  const char *pChar = pData;
  const char *pStart;
  if (n == 0) {
    pStart = pChar;
    len = 0;
    while ((start < dataLen) && (*pChar != ':')) {
      start++;
      len++;
      pChar++;
    }
    header.Append(pStart, len);
    header.Trim(kWhitespace);
    start++;
    pChar++;
  }
  else {
    while (start < dataLen) {
      if ((*pChar != ' ') && (*pChar != '\t')) {
        if (n == index) {
          pStart = pChar;
          len = 0;
          while ((start < dataLen) && (*pChar != ':')) {
            start++;
            len++;
            pChar++;
          }
          header.Append(pStart, len);
          header.Trim(kWhitespace);
          start++;
          pChar++;
          break;
        }
        else
          index++;
      }

      // Skip to next end of line.
      while ((start < dataLen) &&
             (*pChar != nsCRT::CR) && (*pChar != nsCRT::LF)) {
        start++;
        pChar++;
      }
      // Skip over end of line(s).
      while ((start < dataLen) &&
             ((*pChar == nsCRT::CR) || (*pChar == nsCRT::LF))) {
        start++;
        pChar++;
      }
    }
  }

  if (start >= dataLen)
    return;

  int32_t lineEnd;
  int32_t end = start;
  while (end < dataLen) {
    // Skip to next end of line.
    while ((end < dataLen) && (*pChar != nsCRT::CR) && (*pChar != nsCRT::LF)) {
      end++;
      pChar++;
    }

    if (end > start) {
      val.Append(pData + start, end - start);
    }

    lineEnd = end;
    pStart = pChar;

    // Skip over end of line(s).
    while ((end < dataLen) &&
           ((*pChar == nsCRT::CR) || (*pChar == nsCRT::LF))) {
      end++;
      pChar++;
    }

    start = end;

    // Skip over space(s) and tab(s).
    while ((end < dataLen) && ((*pChar == ' ') || (*pChar == '\t'))) {
      end++;
      pChar++;
    }

    if (start == end)
      break;

    if (unwrap)
      val.Append(' ');
    else {
      val.Append(pStart, end - lineEnd);
    }

    start = end;
  }

  val.Trim(kWhitespace);
}
Пример #6
0
void nsEudoraCompose::GetHeaderValue(const char *pData,
                                     int32_t dataLen,
                                     const char *pHeader,
                                     nsCString& val,
                                     bool unwrap)
{
  val.Truncate();
  if (!pData)
    return;

  int32_t  start = 0;
  int32_t len = strlen(pHeader);
  const char *pChar = pData;
  if (!PL_strncasecmp(pHeader, pData, len)) {
    start = len;
  }
  else {
    while (start < dataLen) {
      // Skip to next end of line.
      while ((start < dataLen) &&
             (*pChar != nsCRT::CR) && (*pChar != nsCRT::LF)) {
        start++;
        pChar++;
      }
      // Skip over end of line(s).
      while ((start < dataLen) &&
             ((*pChar == nsCRT::CR) || (*pChar == nsCRT::LF))) {
        start++;
        pChar++;
      }

      if ((start < dataLen) && !PL_strncasecmp(pChar, pHeader, len))
        break;
    }
    if (start < dataLen)
      start += len;
  }

  if (start >= dataLen)
    return;

  int32_t end = start;
  int32_t lineEnd;
  const char * pStart;

  pChar = pData + start;

  while (end < dataLen) {
    // Skip to next end of line.
    while ((end < dataLen) && (*pChar != nsCRT::CR) && (*pChar != nsCRT::LF)) {
      end++;
      pChar++;
    }

    if (end > start)
      val.Append(pData + start, end - start);

    lineEnd = end;
    pStart = pChar;

    // Skip over the end of line(s).
    while ((end < dataLen) &&
           ((*pChar == nsCRT::CR) || (*pChar == nsCRT::LF))) {
      end++;
      pChar++;
    }

    start = end;

    // Skip over space(s) and tab(s).
    while ((end < dataLen) && ((*pChar == ' ') || (*pChar == '\t'))) {
      end++;
      pChar++;
    }

    if (start == end)
      break;

    if (unwrap)
      val.Append(' ');
    else {
      val.Append(pStart, end - lineEnd);
    }

    start = end;
  }

  val.Trim(kWhitespace);
}
Пример #7
0
bool nsTextAddress::GetField( const char *pLine, PRInt32 maxLen, PRInt32 index, nsCString& field, char delim)
{
    bool result = false;
    const char *pChar = pLine;
    PRInt32 len = 0;
    char tab = '\t';

    field.Truncate();

    if (delim == tab)
        tab = 0;

    while (index && (len < maxLen)) {
        while (((*pChar == ' ') || (*pChar == tab)) && (len < maxLen)) {
            pChar++;
            len++;
        }
        if (len >= maxLen)
            break;
        if (*pChar == '"') {
            len = -1;
            do {
                len++;
                pChar++;
                if (((len + 1) < maxLen) && (*pChar == '"') && (*(pChar + 1) == '"')) {
                    len += 2;
                    pChar += 2;
                }
            } while ((len < maxLen) && (*pChar != '"'));
            if (len < maxLen) {
                pChar++;
                len++;
            }
        }
        if (len >= maxLen)
            break;

        while ((len < maxLen) && (*pChar != delim)) {
            len++;
            pChar++;
        }

        if (len >= maxLen)
            break;

        index--;
        pChar++;
        len++;
    }

    if (len >= maxLen) {
        return( result);
    }

    result = true;

    while ((len < maxLen) && ((*pChar == ' ') || (*pChar == tab))) {
        len++;
        pChar++;
    }

    const char *pStart = pChar;
    PRInt32        fLen = 0;
    bool          quoted = false;
    if (*pChar == '"') {
        pStart++;
        fLen = -1;
        do {
            pChar++;
            len++;
            fLen++;
            if (((len + 1) < maxLen) && (*pChar == '"') && (*(pChar + 1) == '"')) {
                quoted = true;
                len += 2;
                pChar += 2;
                fLen += 2;
            }
        } while ((len < maxLen) && (*pChar != '"'));
    }
    else {
        while ((len < maxLen) && (*pChar != delim)) {
            pChar++;
            len++;
            fLen++;
        }
    }

    if (!fLen) {
        return( result);
    }

    field.Append( pStart, fLen);
    field.Trim( kWhitespace);

    if (quoted) {
        PRInt32 offset = field.Find(NS_LITERAL_CSTRING("\"\""));
        while (offset != -1) {
            field.Cut(offset, 1);
            offset = field.Find(NS_LITERAL_CSTRING("\"\""), offset + 1);
        }
    }

    return( result);
}
Пример #8
0
static void
HandleMailtoSubject(nsCString& aPath) {

  // Walk through the string and see if we have a subject already.
  bool hasSubject = false;
  bool hasParams = false;
  int32_t paramSep = aPath.FindChar('?');
  while (paramSep != kNotFound && paramSep < (int32_t)aPath.Length()) {
    hasParams = true;

    // Get the end of the name at the = op.  If it is *after* the next &,
    // assume that someone made a parameter without an = in it
    int32_t nameEnd = aPath.FindChar('=', paramSep+1);
    int32_t nextParamSep = aPath.FindChar('&', paramSep+1);
    if (nextParamSep == kNotFound) {
      nextParamSep = aPath.Length();
    }

    // If the = op is after the &, this parameter is a name without value.
    // If there is no = op, same thing.
    if (nameEnd == kNotFound || nextParamSep < nameEnd) {
      nameEnd = nextParamSep;
    }

    if (nameEnd != kNotFound) {
      if (Substring(aPath, paramSep+1, nameEnd-(paramSep+1)).
          LowerCaseEqualsLiteral("subject")) {
        hasSubject = true;
        break;
      }
    }

    paramSep = nextParamSep;
  }

  // If there is no subject, append a preformed subject to the mailto line
  if (!hasSubject) {
    if (hasParams) {
      aPath.Append('&');
    } else {
      aPath.Append('?');
    }

    // Get the default subject
    nsXPIDLString brandName;
    nsresult rv =
      nsContentUtils::GetLocalizedString(nsContentUtils::eBRAND_PROPERTIES,
                                         "brandShortName", brandName);
    if (NS_FAILED(rv))
      return;
    const char16_t *formatStrings[] = { brandName.get() };
    nsXPIDLString subjectStr;
    rv = nsContentUtils::FormatLocalizedString(
                                           nsContentUtils::eFORMS_PROPERTIES,
                                           "DefaultFormSubject",
                                           formatStrings,
                                           subjectStr);
    if (NS_FAILED(rv))
      return;
    aPath.AppendLiteral("subject=");
    nsCString subjectStrEscaped;
    aPath.Append(NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
                              subjectStrEscaped));
  }
}
Пример #9
0
// Return number of bytes consumed (>= 0) or -1 on error
PRInt32
nsPipeFilterListener::MatchDelimiter(const char* buf, PRUint32 bufLen,
                                     LineMatchStatus& delim,
                                     nsCString& delimStr,
                                     nsCString& delimLine)
{
  //DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: bufLen=%d\n", bufLen));

  PRUint32 count = bufLen;

  while ((count > 0) && (delim.matchCount <= delim.skipCount)) {

    if (delim.matchOffset < delimStr.Length()) {
      PRUint32 consumed = MatchString(buf, count, delimStr.get(),
                                      delimStr.Length(),
                                      delim.matchOffset);
      //DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: consumed=%d\n", consumed));
      if (!consumed) {
          ERROR_LOG(("nsPipeFilterListener::MatchDelimiter: consumed=%d\n", consumed));
        return -1;
      }

      buf   += consumed;
      count -= consumed;

      if (delim.matchOffset >= delimStr.Length()) {
        DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: delimStr='%s'\n", delimStr.get()));
        if (mLastMatch) {
          delimLine = mPartMatch;
          mPartMatch = "";
        } else {
          delimLine = delimStr;
        }
        mLinebreak = 0;
      }

      if (!count)
        return bufLen;

      if (delim.matchOffset < delimStr.Length()) {
        ERROR_LOG(("nsPipeFilterListener::MatchDelimiter: count=%d, delim.matchOffset=%d, delimStr='%s'\n", count, delim.matchOffset, delimStr.get() ));
        return -1;
      }
    }

    // Match to end of line
    while (count > 0) {
      char ch = buf[0];

      if (delim.matchedCR) {
        // Already matched a CR

        if (ch == '\n') {
          // Consume LF following CR
          delimLine.Append(ch);
          buf++;
          count--;
        }

        delim.matchedLine = PR_TRUE;
        break;
      }

      delimLine.Append(ch);
      buf++;
      count--;

      if (ch == '\n') {
        delim.matchedLine = PR_TRUE;
        break;
      }

      if (ch == '\r') {
        delim.matchedCR = PR_TRUE;
      }
    }

    if (delim.matchedLine) {
      delim.matchCount++;
      delim.matchOffset = 0;
      delim.matchedCR = PR_FALSE;
      delim.matchedLine = PR_FALSE;

      DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: delimLine(%d)='%s'\n", delimLine.Length(), delimLine.get()));
      DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: matchCount=%d\n", delim.matchCount));

      if (mAutoMimeBoundary) {
        // Eliminate all trailing whitespace (including linebreaks) for delimiter
        mAutoMimeBoundary = PR_FALSE;
        mStartDelimiter = mStartLine;
        mStartDelimiter.Trim(" \t\r\n", PR_FALSE, PR_TRUE);
        mEndDelimiter = mStartDelimiter;
        DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: Mime Boundary='%s'\n", mStartDelimiter.get()));
      }

    }
  }

  return bufLen - count;
}
Пример #10
0
/**
 * This method applies a sequence of transformations to the line.
 * 
 * It applies the following sequences in order
 * * Removes headers if the searcher doesn't want them
 *   (sets m_pastHeaders)
 * * Determines the current MIME type.
 *   (via SniffPossibleMIMEHeader)
 * * Strips any HTML if the searcher doesn't want it
 * * Strips non-text parts
 * * Decodes any base64 part
 *   (resetting part variables: m_base64part, m_pastHeaders, m_partIsHtml,
 *    m_partIsText)
 *
 * @param line        (in)    the current line
 * @param length      (in)    the length of said line
 * @param eatThisLine (out)   whether or not to ignore this line
 * @param buf         (inout) if m_base64part, the current part as needed for
 *                            decoding; else, it is treated as an out param (a
 *                            redundant version of line).
 * @return            the length of the line after applying transformations
 */
PRInt32 nsMsgBodyHandler::ApplyTransformations (const nsCString &line, PRInt32 length,
                                                bool &eatThisLine, nsCString &buf)
{
  PRInt32 newLength = length;
  eatThisLine = PR_FALSE;
  
  if (!m_pastHeaders)  // line is a line from the message headers
  {
    if (m_stripHeaders)
      eatThisLine = PR_TRUE;

    // We have already grabbed all worthwhile information from the headers,
    // so there is no need to keep track of the current lines
    buf.Assign(line);
   
    SniffPossibleMIMEHeader(buf);
    
    m_pastHeaders = buf.IsEmpty() || buf.First() == '\r' ||
      buf.First() == '\n';

    return length;
  }

  // Check to see if this is the boundary string
  if (m_isMultipart && StringBeginsWith(line, boundary))
  {
    if (m_base64part && m_partIsText) 
    {
      Base64Decode(buf);
      // Work on the parsed string
      if (!buf.Length())
      {
        NS_WARNING("Trying to transform an empty buffer");
        eatThisLine = PR_TRUE;
      }
      else
      {
        ApplyTransformations(buf, buf.Length(), eatThisLine, buf);
        // Avoid spurious failures
        eatThisLine = PR_FALSE;
      }
    }
    else
    {
      buf.Truncate();
      eatThisLine = PR_TRUE; // We have no content...
    }

    // Reset all assumed headers
    m_base64part = PR_FALSE;
    m_pastHeaders = PR_FALSE;
    m_partIsHtml = PR_FALSE;
    m_partIsText = PR_TRUE;

    return buf.Length();
  }
 
  if (!m_partIsText)
  {
    // Ignore non-text parts
    buf.Truncate();
    eatThisLine = PR_TRUE;
    return 0;
  }

  if (m_base64part)
  {
    // We need to keep track of all lines to parse base64encoded...
    buf.Append(line.get());
    eatThisLine = PR_TRUE;
    return buf.Length();
  }
    
  // ... but there's no point if we're not parsing base64.
  buf.Assign(line);
  if (m_stripHtml && m_partIsHtml)
  {
    StripHtml (buf);
    newLength = buf.Length();
  }
  
  return newLength;
}
GnomeVFSResult
nsGnomeVFSInputStream::DoRead(char *aBuf, PRUint32 aCount, PRUint32 *aCountRead)
{
  GnomeVFSResult rv;

  if (mHandle)
  {
    GnomeVFSFileSize bytesRead;
    rv = gnome_vfs_read(mHandle, aBuf, aCount, &bytesRead);
    if (rv == GNOME_VFS_OK)
    {
      // XXX 64-bit here
      *aCountRead = (PRUint32) bytesRead;
      mBytesRemaining -= *aCountRead;
    }
  }
  else if (mDirOpen)
  {
    rv = GNOME_VFS_OK;

    while (aCount && rv != GNOME_VFS_ERROR_EOF)
    {
      // Copy data out of our buffer
      PRUint32 bufLen = mDirBuf.Length() - mDirBufCursor;
      if (bufLen)
      {
        PRUint32 n = PR_MIN(bufLen, aCount);
        memcpy(aBuf, mDirBuf.get() + mDirBufCursor, n);
        *aCountRead += n;
        aBuf += n;
        aCount -= n;
        mDirBufCursor += n;
      }

      if (!mDirListPtr)    // Are we at the end of the directory list?
      {
        rv = GNOME_VFS_ERROR_EOF;
      }
      else if (aCount)     // Do we need more data?
      {
        GnomeVFSFileInfo *info = (GnomeVFSFileInfo *) mDirListPtr->data;

        // Prune '.' and '..' from directory listing.
        if (info->name[0] == '.' &&
               (info->name[1] == '\0' ||
                   (info->name[1] == '.' && info->name[2] == '\0')))
        {
          mDirListPtr = mDirListPtr->next;
          continue;
        }

        mDirBuf.Assign("201: ");

        // The "filename" field
        nsCString escName;
        nsCOMPtr<nsINetUtil> nu = do_GetService(NS_NETUTIL_CONTRACTID);
        if (nu) {
          nu->EscapeString(nsDependentCString(info->name),
                           nsINetUtil::ESCAPE_URL_PATH, escName);

          mDirBuf.Append(escName);
          mDirBuf.Append(' ');
        }

        // The "content-length" field
        // XXX truncates size from 64-bit to 32-bit
        mDirBuf.AppendInt(PRInt32(info->size));
        mDirBuf.Append(' ');

        // The "last-modified" field
        // 
        // NSPR promises: PRTime is compatible with time_t
        // we just need to convert from seconds to microseconds
        PRExplodedTime tm;
        PRTime pt = ((PRTime) info->mtime) * 1000000;
        PR_ExplodeTime(pt, PR_GMTParameters, &tm);
        {
          char buf[64];
          PR_FormatTimeUSEnglish(buf, sizeof(buf),
              "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm);
          mDirBuf.Append(buf);
        }

        // The "file-type" field
        switch (info->type)
        {
          case GNOME_VFS_FILE_TYPE_REGULAR:
            mDirBuf.Append("FILE ");
            break;
          case GNOME_VFS_FILE_TYPE_DIRECTORY:
            mDirBuf.Append("DIRECTORY ");
            break;
          case GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK:
            mDirBuf.Append("SYMBOLIC-LINK ");
            break;
          default:
            break;
        }

        mDirBuf.Append('\n');

        mDirBufCursor = 0;
        mDirListPtr = mDirListPtr->next;
      }
    }
  }
  else
  {
    NS_NOTREACHED("reading from what?");
    rv = GNOME_VFS_ERROR_GENERIC;
  }

  return rv;
}
GnomeVFSResult
nsGnomeVFSInputStream::DoOpen()
{
  GnomeVFSResult rv;

  NS_ASSERTION(mHandle == nsnull, "already open");

  // Push a callback handler on the stack for this thread, so we can intercept
  // authentication requests from GnomeVFS.  We'll use the channel to get a
  // nsIAuthPrompt instance.

  gnome_vfs_module_callback_push(GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION,
                                 AuthCallback, mChannel, NULL);

  // Query the mime type first (this could return NULL). 
  //
  // XXX We need to do this up-front in order to determine how to open the URI.
  //     Unfortunately, the error code GNOME_VFS_ERROR_IS_DIRECTORY is not
  //     always returned by gnome_vfs_open when we pass it a URI to a directory!
  //     Otherwise, we could have used that as a way to failover to opening the
  //     URI as a directory.  Also, it would have been ideal if
  //     gnome_vfs_get_file_info_from_handle were actually implemented by the
  //     smb:// module, since that would have allowed us to potentially save a
  //     round trip to the server to discover the mime type of the document in
  //     the case where gnome_vfs_open would have been used.  (Oh well!  /me
  //     throws hands up in the air and moves on...)

  GnomeVFSFileInfo info = {0};
  rv = gnome_vfs_get_file_info(mSpec.get(), &info, GnomeVFSFileInfoOptions(
                               GNOME_VFS_FILE_INFO_DEFAULT |
                               GNOME_VFS_FILE_INFO_FOLLOW_LINKS));
  if (rv == GNOME_VFS_OK)
  {
    if (info.type == GNOME_VFS_FILE_TYPE_DIRECTORY)
    {
      rv = gnome_vfs_directory_list_load(&mDirList, mSpec.get(),
                                         GNOME_VFS_FILE_INFO_DEFAULT);

      LOG(("gnomevfs: gnome_vfs_directory_list_load returned %d (%s) [spec=\"%s\"]\n",
          rv, gnome_vfs_result_to_string(rv), mSpec.get()));
    }
    else
    {
      rv = gnome_vfs_open(&mHandle, mSpec.get(), GNOME_VFS_OPEN_READ);

      LOG(("gnomevfs: gnome_vfs_open returned %d (%s) [spec=\"%s\"]\n",
          rv, gnome_vfs_result_to_string(rv), mSpec.get()));
    }
  }

  gnome_vfs_module_callback_pop(GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION);

  if (rv == GNOME_VFS_OK)
  {
    if (mHandle)
    {
      // Here we set the content type of the channel to the value of the mime
      // type determined by GnomeVFS.  However, if GnomeVFS is telling us that
      // the document is binary, we'll ignore that and keep the channel's
      // content type unspecified.  That will enable our content type sniffing
      // algorithms.  This should provide more consistent mime type handling.

      if (info.mime_type && (strcmp(info.mime_type, APPLICATION_OCTET_STREAM) != 0))
        SetContentTypeOfChannel(info.mime_type);

      mBytesRemaining = info.size;

      // Update the content length attribute on the channel.  We do this
      // synchronously without proxying.  This hack is not as bad as it looks!
      if (mBytesRemaining != PRUint64(-1))
        mChannel->SetContentLength(mBytesRemaining);
    }
    else
    {
      mDirOpen = PR_TRUE;

      // Sort mDirList
      mDirList = g_list_sort(mDirList, FileInfoComparator);
      mDirListPtr = mDirList;

      // Write base URL (make sure it ends with a '/')
      mDirBuf.Append("300: ");
      mDirBuf.Append(mSpec);
      if (mSpec.get()[mSpec.Length() - 1] != '/')
        mDirBuf.Append('/');
      mDirBuf.Append('\n');

      // Write column names
      mDirBuf.Append("200: filename content-length last-modified file-type\n");

      // Write charset (assume UTF-8)
      // XXX is this correct?
      mDirBuf.Append("301: UTF-8\n");

      SetContentTypeOfChannel(APPLICATION_HTTP_INDEX_FORMAT);
    }
  }

  gnome_vfs_file_info_clear(&info);
  return rv;
}
/**
 * Read content of file or create file list from directory
 * @param aBuf read destination buffer
 * @param aCount length of destination buffer
 * @param aCountRead number of read characters
 * @return NS_OK when read successfully, NS_BASE_STREAM_CLOSED when end of file,
 *         error code otherwise
 */
nsresult
nsGIOInputStream::DoRead(char *aBuf, PRUint32 aCount, PRUint32 *aCountRead)
{
  nsresult rv = NS_ERROR_NOT_AVAILABLE;
  if (mStream) {
    // file read
    GError *error = NULL;    
    PRUint32 bytes_read = g_input_stream_read(G_INPUT_STREAM(mStream),
                                              aBuf,
                                              aCount,
                                              NULL,
                                              &error);
    if (error) {
      rv = MapGIOResult(error);
      *aCountRead = 0;
      g_warning("Cannot read from file: %s", error->message);
      g_error_free(error);
      return rv;
    }
    *aCountRead = bytes_read;
    mBytesRemaining -= *aCountRead;
    return NS_OK;
  }
  else if (mDirOpen) {
    // directory read
    while (aCount && rv != NS_BASE_STREAM_CLOSED)
    {
      // Copy data out of our buffer
      PRUint32 bufLen = mDirBuf.Length() - mDirBufCursor;
      if (bufLen)
      {
        PRUint32 n = NS_MIN(bufLen, aCount);
        memcpy(aBuf, mDirBuf.get() + mDirBufCursor, n);
        *aCountRead += n;
        aBuf += n;
        aCount -= n;
        mDirBufCursor += n;
      }

      if (!mDirListPtr)    // Are we at the end of the directory list?
      {
        rv = NS_BASE_STREAM_CLOSED;
      }
      else if (aCount)     // Do we need more data?
      {
        GFileInfo *info = (GFileInfo *) mDirListPtr->data;

        // Prune '.' and '..' from directory listing.
        const char * fname = g_file_info_get_name(info);
        if (fname && fname[0] == '.' && 
            (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
        {
          mDirListPtr = mDirListPtr->next;
          continue;
        }

        mDirBuf.Assign("201: ");

        // The "filename" field
        nsCString escName;
        nsCOMPtr<nsINetUtil> nu = do_GetService(NS_NETUTIL_CONTRACTID);
        if (nu && fname) {
          nu->EscapeString(nsDependentCString(fname),
                           nsINetUtil::ESCAPE_URL_PATH, escName);

          mDirBuf.Append(escName);
          mDirBuf.Append(' ');
        }

        // The "content-length" field
        // XXX truncates size from 64-bit to 32-bit
        mDirBuf.AppendInt(PRInt32(g_file_info_get_size(info)));
        mDirBuf.Append(' ');

        // The "last-modified" field
        //
        // NSPR promises: PRTime is compatible with time_t
        // we just need to convert from seconds to microseconds
        GTimeVal gtime;
        g_file_info_get_modification_time(info, &gtime);

        PRExplodedTime tm;
        PRTime pt = ((PRTime) gtime.tv_sec) * 1000000;
        PR_ExplodeTime(pt, PR_GMTParameters, &tm);
        {
          char buf[64];
          PR_FormatTimeUSEnglish(buf, sizeof(buf),
              "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm);
          mDirBuf.Append(buf);
        }

        // The "file-type" field
        switch (g_file_info_get_file_type(info))
        {
          case G_FILE_TYPE_REGULAR:
            mDirBuf.Append("FILE ");
            break;
          case G_FILE_TYPE_DIRECTORY:
            mDirBuf.Append("DIRECTORY ");
            break;
          case G_FILE_TYPE_SYMBOLIC_LINK:
            mDirBuf.Append("SYMBOLIC-LINK ");
            break;
          default:
            break;
        }
        mDirBuf.Append('\n');

        mDirBufCursor = 0;
        mDirListPtr = mDirListPtr->next;
      }
    }
  }
  return rv;
}