static void
SetSMValue(SmPropValue& val, const nsCString& data)
{
  val.value = static_cast<SmPointer>(const_cast<char*>(data.get()));
  val.length = data.Length();
}
Example #2
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;
}
nsresult nsMsgProtocol::DoGSSAPIStep2(nsCString &commandResponse, nsCString &response)
{
#ifdef DEBUG_BenB
    printf("GSSAPI step 2\n");
#endif
    nsresult rv;
    void *inBuf, *outBuf;
    uint32_t inBufLen, outBufLen;
    uint32_t len = commandResponse.Length();

    // Cyrus SASL may send us zero length tokens (grrrr)
    if (len > 0) {
        // decode into the input secbuffer
        inBufLen = (len * 3)/4;      // sufficient size (see plbase64.h)
        inBuf = nsMemory::Alloc(inBufLen);
        if (!inBuf)
            return NS_ERROR_OUT_OF_MEMORY;

        // strip off any padding (see bug 230351)
        const char *challenge = commandResponse.get();
        while (challenge[len - 1] == '=')
            len--;

        // We need to know the exact length of the decoded string to give to
        // the GSSAPI libraries. But NSPR's base64 routine doesn't seem capable
        // of telling us that. So, we figure it out for ourselves.

        // For every 4 characters, add 3 to the destination
        // If there are 3 remaining, add 2
        // If there are 2 remaining, add 1
        // 1 remaining is an error
        inBufLen = (len / 4)*3 + ((len % 4 == 3)?2:0) + ((len % 4 == 2)?1:0);

        rv = (PL_Base64Decode(challenge, len, (char *)inBuf))
             ? m_authModule->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen)
             : NS_ERROR_FAILURE;

        nsMemory::Free(inBuf);
    }
    else
    {
        rv = m_authModule->GetNextToken(NULL, 0, &outBuf, &outBufLen);
    }
    if (NS_SUCCEEDED(rv))
    {
        // And in return, we may need to send Cyrus zero length tokens back
        if (outBuf)
        {
            char *base64Str = PL_Base64Encode((char *)outBuf, outBufLen, nullptr);
            if (base64Str)
                response.Adopt(base64Str);
            else
                rv = NS_ERROR_OUT_OF_MEMORY;
        }
        else
            response.Adopt((char *)nsMemory::Clone("",1));
    }

#ifdef DEBUG_BenB
    printf(NS_SUCCEEDED(rv) ? "GSSAPI step 2 succeeded\n" : "GSSAPI step 2 failed\n");
#endif
    return rv;
}
// use the flagState to determine if the gaps in the msgUids correspond to gaps in the mailbox,
// in which case we can still use ranges. If flagState is null, we won't do this.
void AllocateImapUidString(uint32_t *msgUids, uint32_t &msgCount,
                           nsImapFlagAndUidState *flagState, nsCString &returnString)
{
  uint32_t startSequence = (msgCount > 0) ? msgUids[0] : 0xFFFFFFFF;
  uint32_t curSequenceEnd = startSequence;
  uint32_t total = msgCount;
  int32_t  curFlagStateIndex = -1;

  // a partial fetch flag state doesn't help us, so don't use it.
  if (flagState && flagState->GetPartialUIDFetch())
    flagState = nullptr;


  for (uint32_t keyIndex = 0; keyIndex < total; keyIndex++)
  {
    uint32_t curKey = msgUids[keyIndex];
    uint32_t nextKey = (keyIndex + 1 < total) ? msgUids[keyIndex + 1] : 0xFFFFFFFF;
    bool lastKey = (nextKey == 0xFFFFFFFF);

    if (lastKey)
      curSequenceEnd = curKey;

    if (!lastKey)
    {
      if (nextKey == curSequenceEnd + 1)
      {
        curSequenceEnd = nextKey;
        curFlagStateIndex++;
        continue;
      }
      if (flagState)
      {
        if (curFlagStateIndex == -1)
        {
          bool foundIt;
          flagState->GetMessageFlagsFromUID(curSequenceEnd, &foundIt, &curFlagStateIndex);
          if (!foundIt)
          {
            NS_WARNING("flag state missing key");
            // The start of this sequence is missing from flag state, so move
            // on to the next key.
            curFlagStateIndex = -1;
            curSequenceEnd = startSequence = nextKey;
            continue;
          }
        }
        curFlagStateIndex++;
        uint32_t nextUidInFlagState;
        nsresult rv = flagState->GetUidOfMessage(curFlagStateIndex, &nextUidInFlagState);
        if (NS_SUCCEEDED(rv) && nextUidInFlagState == nextKey)
        {
          curSequenceEnd = nextKey;
          continue;
        }
      }
    }
    if (curSequenceEnd > startSequence)
    {
      returnString.AppendInt((int64_t) startSequence);
      returnString += ':';
      returnString.AppendInt((int64_t) curSequenceEnd);
      startSequence = nextKey;
      curSequenceEnd = startSequence;
      curFlagStateIndex = -1;
    }
    else
    {
      startSequence = nextKey;
      curSequenceEnd = startSequence;
      returnString.AppendInt((int64_t) msgUids[keyIndex]);
      curFlagStateIndex = -1;
    }
    // check if we've generated too long a string - if there's no flag state,
    // it means we just need to go ahead and generate a too long string
    // because the calling code won't handle breaking up the strings.
    if (flagState && returnString.Length() > 950)
    {
      msgCount = keyIndex;
      break;
    }
    // If we are not the last item then we need to add the comma
    // but it's important we do it here, after the length check
    if (!lastKey)
      returnString += ',';
  }
}
Example #5
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));
  }
}
Example #6
0
    GMPErr Write(const nsCString& aRecordName,
                 const nsTArray<uint8_t>& aBytes) override
    {
        if (!IsOpen(aRecordName)) {
            return GMPClosedErr;
        }

        Record* record = nullptr;
        mRecords.Get(aRecordName, &record);
        MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this.

        // Write operations overwrite the entire record. So close it now.
        PR_Close(record->mFileDesc);
        record->mFileDesc = nullptr;

        // Writing 0 bytes means removing (deleting) the file.
        if (aBytes.Length() == 0) {
            nsresult rv = RemoveStorageFile(record->mFilename);
            if (NS_WARN_IF(NS_FAILED(rv))) {
                // Could not delete file -> Continue with trying to erase the contents.
            } else {
                return GMPNoErr;
            }
        }

        // Write operations overwrite the entire record. So re-open the file
        // in truncate mode, to clear its contents.
        if (NS_FAILED(OpenStorageFile(record->mFilename,
                                      Truncate,
                                      &record->mFileDesc))) {
            return GMPGenericErr;
        }

        // Store the length of the record name followed by the record name
        // at the start of the file.
        int32_t bytesWritten = 0;
        char buf[sizeof(uint32_t)] = {0};
        LittleEndian::writeUint32(buf, aRecordName.Length());
        bytesWritten = PR_Write(record->mFileDesc, buf, MOZ_ARRAY_LENGTH(buf));
        if (bytesWritten != MOZ_ARRAY_LENGTH(buf)) {
            NS_WARNING("Failed to write GMPStorage record name length.");
            return GMPRecordCorrupted;
        }
        bytesWritten = PR_Write(record->mFileDesc,
                                aRecordName.get(),
                                aRecordName.Length());
        if (bytesWritten != (int32_t)aRecordName.Length()) {
            NS_WARNING("Failed to write GMPStorage record name.");
            return GMPRecordCorrupted;
        }

        bytesWritten = PR_Write(record->mFileDesc, aBytes.Elements(), aBytes.Length());
        if (bytesWritten != (int32_t)aBytes.Length()) {
            NS_WARNING("Failed to write GMPStorage record data.");
            return GMPRecordCorrupted;
        }

        // Try to sync the file to disk, so that in the event of a crash,
        // the record is less likely to be corrupted.
        PR_Sync(record->mFileDesc);

        return GMPNoErr;
    }
nsresult nsMsgI18NConvertToUnicode(const char* aCharset,
                                   const nsCString& inString, 
                                   nsAString& outString,
                                   bool aIsCharsetCanonical)
{
  if (inString.IsEmpty()) {
    outString.Truncate();
    return NS_OK;
  }
  else if (!*aCharset || !PL_strcasecmp(aCharset, "us-ascii") ||
           !PL_strcasecmp(aCharset, "ISO-8859-1")) {
    // Despite its name, it also works for Latin-1.
    CopyASCIItoUTF16(inString, outString);
    return NS_OK;
  }
  else if (!PL_strcasecmp(aCharset, "UTF-8")) {
    if (MsgIsUTF8(inString)) {
      nsAutoString tmp;
      CopyUTF8toUTF16(inString, tmp);
      if (!tmp.IsEmpty() && tmp.get()[0] == char16_t(0xFEFF))
        tmp.Cut(0, 1);
      outString.Assign(tmp);
      return NS_OK;
    }
    NS_WARNING("Invalid UTF-8 string");
    return NS_ERROR_UNEXPECTED;
  }

  nsresult rv;
  nsCOMPtr <nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr <nsIUnicodeDecoder> decoder;

  // get an unicode converter
  if (aIsCharsetCanonical)  // optimize for modified UTF-7 used by IMAP
    rv = ccm->GetUnicodeDecoderRaw(aCharset, getter_AddRefs(decoder));
  else
    rv = ccm->GetUnicodeDecoderInternal(aCharset, getter_AddRefs(decoder));
  NS_ENSURE_SUCCESS(rv, rv);

  const char *originalSrcPtr = inString.get();
  const char *currentSrcPtr = originalSrcPtr;
  int32_t originalLength = inString.Length();
  int32_t srcLength;
  int32_t dstLength;
  char16_t localbuf[512];
  int32_t consumedLen = 0;

  outString.Truncate();

  // convert
  while (consumedLen < originalLength) {
    srcLength = originalLength - consumedLen;  
    dstLength = 512;
    rv = decoder->Convert(currentSrcPtr, &srcLength, localbuf, &dstLength);
    if (NS_FAILED(rv) || dstLength == 0)
      break;
    outString.Append(localbuf, dstLength);

    currentSrcPtr += srcLength;
    consumedLen = currentSrcPtr - originalSrcPtr; // src length used so far
  }
  return rv;
}
static bool
SetOperator(OperatorData*   aOperatorData,
            nsOperatorFlags aForm,
            const nsCString& aOperator,
            nsString&        aAttributes)

{
  static const char16_t kNullCh = char16_t('\0');

  // aOperator is in the expanded format \uNNNN\uNNNN ...
  // First compress these Unicode points to the internal nsString format
  int32_t i = 0;
  nsAutoString name, value;
  int32_t len = aOperator.Length();
  char16_t c = aOperator[i++];
  uint32_t state  = 0;
  char16_t uchar = 0;
  while (i <= len) {
    if (0 == state) {
      if (c != '\\')
        return false;
      if (i < len)
        c = aOperator[i];
      i++;
      if (('u' != c) && ('U' != c))
        return false;
      if (i < len)
        c = aOperator[i];
      i++;
      state++;
    }
    else {
      if (('0' <= c) && (c <= '9'))
         uchar = (uchar << 4) | (c - '0');
      else if (('a' <= c) && (c <= 'f'))
         uchar = (uchar << 4) | (c - 'a' + 0x0a);
      else if (('A' <= c) && (c <= 'F'))
         uchar = (uchar << 4) | (c - 'A' + 0x0a);
      else return false;
      if (i < len)
        c = aOperator[i];
      i++;
      state++;
      if (5 == state) {
        value.Append(uchar);
        uchar = 0;
        state = 0;
      }
    }
  }
  if (0 != state) return false;

  // Quick return when the caller doesn't care about the attributes and just wants
  // to know if this is a valid operator (this is the case at the first pass of the
  // parsing of the dictionary in InitOperators())
  if (!aForm) return true;

  // Add operator to hash table
  aOperatorData->mFlags |= aForm;
  aOperatorData->mStr.Assign(value);
  value.AppendInt(aForm, 10);
  nsStringKey key(value);
  gOperatorTable->Put(&key, aOperatorData);

#ifdef DEBUG
  NS_LossyConvertUTF16toASCII str(aAttributes);
#endif
  // Loop over the space-delimited list of attributes to get the name:value pairs
  aAttributes.Append(kNullCh);  // put an extra null at the end
  char16_t* start = aAttributes.BeginWriting();
  char16_t* end   = start;
  while ((kNullCh != *start) && (kDashCh != *start)) {
    name.SetLength(0);
    value.SetLength(0);
    // skip leading space, the dash amounts to the end of the line
    while ((kNullCh!=*start) && (kDashCh!=*start) && nsCRT::IsAsciiSpace(*start)) {
      ++start;
    }
    end = start;
    // look for ':'
    while ((kNullCh!=*end) && (kDashCh!=*end) && !nsCRT::IsAsciiSpace(*end) &&
           (kColonCh!=*end)) {
      ++end;
    }
    // If ':' is not found, then it's a boolean property
    bool IsBooleanProperty = (kColonCh != *end);
    *end = kNullCh; // end segment here
    // this segment is the name
    if (start < end) {
      name.Assign(start);
    }
    if (IsBooleanProperty) {
      SetBooleanProperty(aOperatorData, name);
    } else {
      start = ++end;
      // look for space or end of line
      while ((kNullCh!=*end) && (kDashCh!=*end) &&
             !nsCRT::IsAsciiSpace(*end)) {
        ++end;
      }
      *end = kNullCh; // end segment here
      if (start < end) {
        // this segment is the value
        value.Assign(start);
      }
      SetProperty(aOperatorData, name, value);
    }
    start = ++end;
  }
  return true;
}
/**
 * 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;
}
// Finds the base domain for a host, with requested number of additional parts.
// This will fail, generating an error, if the host is an IPv4/IPv6 address,
// if more subdomain parts are requested than are available, or if the hostname
// includes characters that are not valid in a URL. Normalization is performed
// on the host string and the result will be in UTF8.
nsresult
nsEffectiveTLDService::GetBaseDomainInternal(nsCString  &aHostname,
                                             int32_t    aAdditionalParts,
                                             nsACString &aBaseDomain)
{
  if (aHostname.IsEmpty())
    return NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS;

  // chomp any trailing dot, and keep track of it for later
  bool trailingDot = aHostname.Last() == '.';
  if (trailingDot)
    aHostname.Truncate(aHostname.Length() - 1);

  // check the edge cases of the host being '.' or having a second trailing '.',
  // since subsequent checks won't catch it.
  if (aHostname.IsEmpty() || aHostname.Last() == '.')
    return NS_ERROR_INVALID_ARG;

  // Check if we're dealing with an IPv4/IPv6 hostname, and return
  PRNetAddr addr;
  PRStatus result = PR_StringToNetAddr(aHostname.get(), &addr);
  if (result == PR_SUCCESS)
    return NS_ERROR_HOST_IS_IP_ADDRESS;

  // Walk up the domain tree, most specific to least specific,
  // looking for matches at each level.  Note that a given level may
  // have multiple attributes (e.g. IsWild() and IsNormal()).
  const char *prevDomain = nullptr;
  const char *currDomain = aHostname.get();
  const char *nextDot = strchr(currDomain, '.');
  const char *end = currDomain + aHostname.Length();
  const char *eTLD = currDomain;
  while (1) {
    // sanity check the string we're about to look up: it should not begin with
    // a '.'; this would mean the hostname began with a '.' or had an
    // embedded '..' sequence.
    if (*currDomain == '.')
      return NS_ERROR_INVALID_ARG;

    // perform the hash lookup.
    nsDomainEntry *entry = mHash.GetEntry(currDomain);
    if (entry) {
      if (entry->IsWild() && prevDomain) {
        // wildcard rules imply an eTLD one level inferior to the match.
        eTLD = prevDomain;
        break;

      } else if (entry->IsNormal() || !nextDot) {
        // specific match, or we've hit the top domain level
        eTLD = currDomain;
        break;

      } else if (entry->IsException()) {
        // exception rules imply an eTLD one level superior to the match.
        eTLD = nextDot + 1;
        break;
      }
    }

    if (!nextDot) {
      // we've hit the top domain level; use it by default.
      eTLD = currDomain;
      break;
    }

    prevDomain = currDomain;
    currDomain = nextDot + 1;
    nextDot = strchr(currDomain, '.');
  }

  const char *begin, *iter;
  if (aAdditionalParts < 0) {
    NS_ASSERTION(aAdditionalParts == -1,
                 "aAdditionalParts can't be negative and different from -1");

    for (iter = aHostname.get(); iter != eTLD && *iter != '.'; iter++);

    if (iter != eTLD) {
      iter++;
    }
    if (iter != eTLD) {
      aAdditionalParts = 0;
    }
  } else {
    // count off the number of requested domains.
    begin = aHostname.get();
    iter = eTLD;

    while (1) {
      if (iter == begin)
        break;

      if (*(--iter) == '.' && aAdditionalParts-- == 0) {
        ++iter;
        ++aAdditionalParts;
        break;
      }
    }
  }

  if (aAdditionalParts != 0)
    return NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS;

  aBaseDomain = Substring(iter, end);
  // add on the trailing dot, if applicable
  if (trailingDot)
    aBaseDomain.Append('.');

  return NS_OK;
}
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;
}
nsresult
PendingLookup::OnStopRequestInternal(nsIRequest *aRequest,
                                     nsISupports *aContext,
                                     nsresult aResult,
                                     bool* aShouldBlock) {
  if (NS_FAILED(aResult)) {
    Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
      SERVER_RESPONSE_FAILED);
    return aResult;
  }

  *aShouldBlock = false;
  nsresult rv;
  nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest, &rv);
  if (NS_FAILED(rv)) {
    Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
      SERVER_RESPONSE_FAILED);
    return rv;
  }

  uint32_t status = 0;
  rv = channel->GetResponseStatus(&status);
  if (NS_FAILED(rv)) {
    Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
      SERVER_RESPONSE_FAILED);
    return rv;
  }

  if (status != 200) {
    Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
      SERVER_RESPONSE_FAILED);
    return NS_ERROR_NOT_AVAILABLE;
  }

  std::string buf(mResponse.Data(), mResponse.Length());
  safe_browsing::ClientDownloadResponse response;
  if (!response.ParseFromString(buf)) {
    LOG(("Invalid protocol buffer response [this = %p]: %s", this, buf.c_str()));
    Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
                                   SERVER_RESPONSE_INVALID);
    return NS_ERROR_CANNOT_CONVERT_DATA;
  }

  // There are several more verdicts, but we only respect DANGEROUS and
  // DANGEROUS_HOST for now and treat everything else as SAFE.
  Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER,
    SERVER_RESPONSE_VALID);
  // Clamp responses 0-7, we only know about 0-4 for now.
  Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER_VERDICT,
    std::min<uint32_t>(response.verdict(), 7));
  switch(response.verdict()) {
    case safe_browsing::ClientDownloadResponse::DANGEROUS:
    case safe_browsing::ClientDownloadResponse::DANGEROUS_HOST:
      *aShouldBlock = true;
      break;
    default:
      break;
  }

  return NS_OK;
}
/**
 * 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;
}