* * The ";" character in an address is a group delimiter, therefore it * should not be quoted in that case.
msg_quote_phrase_or_addr(char *address, PRInt32 length, PRBool addr_p){  int quotable_count = 0, in_quote = 0;  int unquotable_count = 0;  PRInt32 new_length, full_length = length;  char *in, *out, *orig_out, *atsign = NULL, *orig_address = address;  PRBool user_quote = PR_FALSE;  PRBool quote_all = PR_FALSE;  /* If the entire address is quoted, fall out now. */  if (address[0] == '\"' && address[length - 1] == '\"')     return length;  /* Check to see if there is a routing prefix.  If there is one, we can   * skip quoting it because by definition it can't need to be quoted.   */  if (addr_p && *address && *address == '@')  {    for (in = address; *in; NEXT_CHAR(in))    {      if (*in == ':')      {        length -= ++in - address;        address = in;        break;      }      else if (!nsCRT::IsAsciiDigit(*in) && !nsCRT::IsAsciiAlpha(*in) && *in != '@' && *in != '.')        break;    }  }    for (in = address; in < address + length; NEXT_CHAR(in))    {        if (*in == 0)            return full_length; /* #### horrible kludge... */        else if (*in == '@' && addr_p && !atsign && !in_quote)    {            /* Exactly one unquoted at-sign is allowed in an address. */      if (atsign)        quotable_count++;            atsign = in;      /* If address is of the form '"userid"@somewhere.com' don't quote       * the quotes around 'userid'.  Also reset the quotable count, since       * any quotables we've seen are already inside quotes.       */      if (address[0] == '\"' && in > address + 2 && *(in - 1) == '\"' && *(in - 2) != '\\')        unquotable_count -= 2, quotable_count = 0, user_quote = PR_TRUE;    }        else if (*in == '\\')        {            if (in + 1 < address + length && (*(in + 1) == '\\' || *(in + 1) == '\"'))                /* If the next character is a backslash or quote, this backslash */                /* is an escape backslash; ignore it and the next character.     */                in++;            else                /* If the name contains backslashes or quotes, they must be escaped. */                unquotable_count++;        }        else if (*in == '\"')            /* If the name contains quotes, they must be escaped. */            unquotable_count++, in_quote = !in_quote;        else if (  /* *in >= 127 || *in < 0  ducarroz: 8bits characters will be mime encoded therefore they are not a problem             ||*/ *in == ';' || *in == '$' || *in == '(' || *in == ')'                 || *in == '<' || *in == '>' || *in == '@' || *in == ',')             /* If the name contains control chars or Header specials, it needs to             * be enclosed in quotes.  Double-quotes and backslashes will be dealt             * with seperately.             *             * The ":" character is explicitly not in this list, though Header says             * it should be quoted, because that has been seen to break VMS             * systems.  (Rather, it has been seen that there are Unix SMTP servers             * which accept RCPT TO:<host::user> but not RCPT TO:<"host::user"> or             * RCPT TO:<host\:\:user>, which is the syntax that VMS/DECNET hosts             * use.             *             * For future reference: it is also claimed that some VMS SMTP servers             * allow \ quoting but not "" quoting; and that sendmail uses self-             * contradcitory quoting conventions that violate both RFCs 821 and             * 822, so any address quoting on a sendmail system will lose badly.             */      quotable_count++;    else if (!atsign && (*in == '[' || *in == ']'))      /* Braces are normally special characters, except when they're       * used for domain literals (e.g. johndoe@[127.0.0.1].acme.com).       */      quotable_count++;        else if (addr_p && *in == ' ')            /* Naked spaces are allowed in names, but not addresses. */            quotable_count++;        else if (   !addr_p             && (*in == '.' || *in == '!' || *in == '$' || *in == '%'))            /* Naked dots are allowed in addresses, but not in names.             * The other characters (!$%) are technically allowed in names, but             * are surely going to cause someone trouble, so we quote them anyway.             */            quotable_count++;    }    if (quotable_count == 0 && unquotable_count == 0)        return full_length;  /* We must quote the entire string if there are quotables outside the user   * quote.   */  if (!atsign || (user_quote && quotable_count > 0))    quote_all = PR_TRUE, atsign = NULL;    /* Add 2 to the length for the quotes, plus one for each character     * which will need a backslash, plus one for a null terminator.     */    new_length = length + quotable_count + unquotable_count + 3;    in = address;    out = orig_out = (char *)PR_Malloc(new_length);  if (!out)  {    *orig_address = 0;    return 0;  }  /* Start off with a quote.   */  *out++ = '\"';  while (*in)  {    if (*in == '@')    {      if (atsign == in)        *out++ = '\"';      *out++ = *in++;      continue;    }        else if (*in == '\"')    {      if (!user_quote || (in != address && in != atsign - 1))        *out++ = '\\';      *out++ = *in++;      continue;    }        else if (*in == '\\')        {        if (*(in + 1) == '\\' || *(in + 1) == '\"')          *out++ = *in++;      else                *out++ = '\\';      *out++ = *in++;      continue;        }    else      COPY_CHAR(out, in);    NEXT_CHAR(in);  }  /* Add a final quote if we are quoting the entire string.   */  if (quote_all)    *out++ = '\"';  *out++ = 0;  NS_ASSERTION(new_length >= (out - orig_out), "");  memcpy(address, orig_out, new_length);  PR_FREEIF(orig_out); /* make sure we release the string we allocated */  return full_length + unquotable_count + 2;}