static HPOINTER GetIcon(nsCString& file, bool fExists,
                        bool fMini, bool *fWpsIcon)
{
  HPOINTER hRtn = 0;
  *fWpsIcon = false;

  if (file.IsEmpty()) {
    // append something so that we get at least the generic icon
    file.Append("pmwrlw");
  }

  // if RWS is enabled, try to get the icon from the WPS
  if (sUseRws) {
    nsCOMPtr<nsIRwsService> rwsSvc(do_GetService("@mozilla.org/rwsos2;1"));
    if (!rwsSvc)
      sUseRws = false;
    else {
      if (fExists) {
        rwsSvc->IconFromPath(file.get(), false, fMini, (uint32_t*)&hRtn);
      } else {
        const char *ptr = file.get();
        if (*ptr == '.')
          ptr++;
        rwsSvc->IconFromExtension(ptr, fMini, (uint32_t*)&hRtn);
      }
    }
  }

  // if we got an icon from the WPS, set the flag & exit
  if (hRtn) {
    *fWpsIcon = true;
    return hRtn;
  }

  // if the file exists already, get its icon
  if (fExists)
    return WinLoadFileIcon(file.get(), FALSE);

  // otherwise, create a temporary file with the correct extension,
  // then retrieve whatever icon PM assigns it
  if (file.First() == '.')
    file.Insert("moztmp", 0);

  nsCOMPtr<nsIFile> tempPath;
  if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempPath))) ||
      NS_FAILED(tempPath->AppendNative(file)))
    return 0;

  nsAutoCString pathStr;
  tempPath->GetNativePath(pathStr);
  FILE* fp = fopen(pathStr.get(), "wb+");
  if (fp) {
    fclose(fp);
    hRtn = WinLoadFileIcon(pathStr.get(), FALSE);
    remove(pathStr.get());
  }

  return hRtn;
}
/**
 * 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
 */
int32_t nsMsgBodyHandler::ApplyTransformations (const nsCString &line, int32_t length,
                                                bool &eatThisLine, nsCString &buf)
{
  int32_t newLength = length;
  eatThisLine = false;
  
  if (!m_pastHeaders)  // line is a line from the message headers
  {
    if (m_stripHeaders)
      eatThisLine = 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 = true;
      }
      else
      {
        ApplyTransformations(buf, buf.Length(), eatThisLine, buf);
        // Avoid spurious failures
        eatThisLine = false;
      }
    }
    else
    {
      buf.Truncate();
      eatThisLine = true; // We have no content...
    }

    // Reset all assumed headers
    m_base64part = false;
    m_pastHeaders = false;
    m_partIsHtml = false;
    m_partIsText = true;

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

  if (m_base64part)
  {
    // We need to keep track of all lines to parse base64encoded...
    buf.Append(line.get());
    eatThisLine = 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;
}