const char* pBcc = fields->GetBcc(); if (pBcc && *pBcc) ENCODE_AND_PUSH("To: ", PR_TRUE, pFrom, charset, usemime);
PRBool bAddUndisclosedRecipients = PR_TRUE; prefs->GetBoolPref("mail.compose.add_undisclosed_recipients", &bAddUndisclosedRecipients); if (bAddUndisclosedRecipients) { const char* pBcc = fields->GetBcc(); if (pBcc && *pBcc) { nsCOMPtr<nsIStringBundleService> stringService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIStringBundle> composeStringBundle; rv = stringService->CreateBundle("chrome: if (NS_SUCCEEDED(rv)) { nsXPIDLString undisclosedRecipients; rv = composeStringBundle->GetStringFromID(NS_MSG_UNDISCLOSED_RECIPIENTS, getter_Copies(undisclosedRecipients)); if (NS_SUCCEEDED(rv) && !undisclosedRecipients.IsEmpty()){ char * cstr = ToNewCString(undisclosedRecipients); if (cstr) { PUSH_STRING("To: "); PUSH_STRING(cstr); PUSH_STRING(":;"); PUSH_NEWLINE (); } PR_Free(cstr); } } } } }
mime_generate_headers (nsMsgCompFields *fields,                       const char *charset,                       nsMsgDeliverMode deliver_mode, nsIPrompt * aPrompt, PRInt32 *status){  nsresult rv;  *status = 0;  nsCOMPtr<nsIPref> prefs(do_GetService(kPrefCID, &rv));   if (NS_FAILED(rv)) {  *status = rv;    return nsnull;  }  PRBool usemime = nsMsgMIMEGetConformToStandard();  PRInt32 size = 0;  char *buffer = 0, *buffer_tail = 0;  PRBool isDraft =  deliver_mode == nsIMsgSend::nsMsgSaveAsDraft ||  deliver_mode == nsIMsgSend::nsMsgSaveAsTemplate ||  deliver_mode == nsIMsgSend::nsMsgQueueForLater;  const char* pFrom;  const char* pTo;  const char* pCc;  const char* pMessageID;  const char* pReplyTo;  const char* pOrg;  const char* pNewsGrp;  const char* pFollow;  const char* pSubject;  const char* pPriority;  const char* pReference;  const char* pOtherHdr;  char *convbuf;  PRBool hasDisclosedRecipient = PR_FALSE;  nsCAutoString headerBuf;    // accumulate header strings to get length  headerBuf.Truncate(0);  NS_ASSERTION (fields, "null fields");  if (!fields)    return nsnull;  pFrom = fields->GetFrom();   if (pFrom)    headerBuf.Append(pFrom);  pReplyTo =fields->GetReplyTo();   if (pReplyTo)    headerBuf.Append(pReplyTo);  pTo = fields->GetTo();  if (pTo)    headerBuf.Append(pTo);  pCc = fields->GetCc();   if (pCc)    headerBuf.Append(pCc);  pNewsGrp = fields->GetNewsgroups(); if (pNewsGrp)     size += 3 * PL_strlen (pNewsGrp);  pFollow= fields->GetFollowupTo(); if (pFollow)        size += 3 * PL_strlen (pFollow);  pSubject = fields->GetSubject();   if (pSubject)    headerBuf.Append(pSubject);  pReference = fields->GetReferences(); if (pReference)   size += 3 * PL_strlen (pReference);  pOrg= fields->GetOrganization();   if (pOrg)    headerBuf.Append(pOrg);  pOtherHdr= fields->GetOtherRandomHeaders(); if (pOtherHdr)  size += 3 * PL_strlen (pOtherHdr);  pPriority = fields->GetPriority();  if (pPriority)      size += 3 * PL_strlen (pPriority);  pMessageID = fields->GetMessageId(); if (pMessageID)    size += PL_strlen (pMessageID);  /* Multiply by 3 here to make enough room for MimePartII conversion */  size += 3 * headerBuf.Length();  /* Add a bunch of slop for the static parts of the headers. */  /* size += 2048; */  size += 2560;  buffer = (char *) PR_Malloc (size);  if (!buffer)    return nsnull; /* NS_ERROR_OUT_OF_MEMORY */    buffer_tail = buffer;  if (pMessageID && *pMessageID) {    PUSH_STRING ("Message-ID: ");    PUSH_STRING (pMessageID);    PUSH_NEWLINE ();    /* MDN request header requires to have MessageID header presented    * in the message in order to    * coorelate the MDN reports to the original message. Here will be    * the right place    */    if (fields->GetReturnReceipt() &&       (deliver_mode != nsIMsgSend::nsMsgSaveAsDraft &&      deliver_mode != nsIMsgSend::nsMsgSaveAsTemplate))    {        PRInt32 receipt_header_type = nsIMsgMdnGenerator::eDntType;        fields->GetReceiptHeaderType(&receipt_header_type);        // nsIMsgMdnGenerator::eDntType = MDN Disposition-Notification-To: ;        // nsIMsgMdnGenerator::eRrtType  = Return-Receipt-To: ;         // nsIMsgMdnGenerator::eDntRrtType = both MDN DNT & RRT headers      if (receipt_header_type == nsIMsgMdnGenerator::eRrtType) {RRT_HEADER:        ENCODE_AND_PUSH("Return-Receipt-To: ", PR_TRUE, pFrom, charset, usemime);      }      else  {        ENCODE_AND_PUSH("Disposition-Notification-To: ", PR_TRUE, pFrom, charset, usemime);        if (receipt_header_type == nsIMsgMdnGenerator::eDntRrtType)          goto RRT_HEADER;      }    }#ifdef SUPPORT_X_TEMPLATE_NAME    if (deliver_mode == MSG_SaveAsTemplate) {      const char *pStr = fields->GetTemplateName();      pStr = pStr ? pStr : "";      ENCODE_AND_PUSH("X-Template: ", PR_FALSE, pStr, charset, usemime);    }#endif /* SUPPORT_X_TEMPLATE_NAME */  }  PRExplodedTime now;  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now);  int gmtoffset = (now.tm_params.tp_gmt_offset + now.tm_params.tp_dst_offset) / 60;  /* Use PR_FormatTimeUSEnglish() to format the date in US English format,     then figure out what our local GMT offset is, and append it (since     PR_FormatTimeUSEnglish() can't do that.) Generate four digit years as     per RFC 1123 (superceding RFC 822.)   */  PR_FormatTimeUSEnglish(buffer_tail, 100,               "Date: %a, %d %b %Y %H:%M:%S ",               &now);  buffer_tail += PL_strlen (buffer_tail);  PR_snprintf(buffer_tail, buffer + size - buffer_tail,        "%c%02d%02d" CRLF,        (gmtoffset >= 0 ? '+' : '-'),        ((gmtoffset >= 0 ? gmtoffset : -gmtoffset) / 60),        ((gmtoffset >= 0 ? gmtoffset : -gmtoffset) % 60));  buffer_tail += PL_strlen (buffer_tail);  if (pFrom && *pFrom)   {    ENCODE_AND_PUSH("From: ", PR_TRUE, pFrom, charset, usemime);  }  if (pReplyTo && *pReplyTo)  {    ENCODE_AND_PUSH("Reply-To: ", PR_TRUE, pReplyTo, charset, usemime);  }  if (pOrg && *pOrg)  {    ENCODE_AND_PUSH("Organization: ", PR_FALSE, pOrg, charset, usemime);  }  // X-Mozilla-Draft-Info  if (isDraft)   {    PUSH_STRING(HEADER_X_MOZILLA_DRAFT_INFO);    PUSH_STRING(": internal/draft; ");    if (fields->GetAttachVCard())      PUSH_STRING("vcard=1");    else      PUSH_STRING("vcard=0");    PUSH_STRING("; ");    if (fields->GetReturnReceipt()) {      // slight change compared to 4.x; we used to use receipt= to tell      // whether the draft/template has request for either MDN or DNS or both      // return receipt; since the DNS is out of the picture we now use the      // header type + 1 to tell whether user has requested the return receipt      PRInt32 headerType = 0;      fields->GetReceiptHeaderType(&headerType);      char *type = PR_smprintf("%d", (int)headerType + 1);      if (type)      {        PUSH_STRING("receipt=");        PUSH_STRING(type);        PR_FREEIF(type);      }    }    else      PUSH_STRING("receipt=0");    PUSH_STRING("; ");    if (fields->GetUuEncodeAttachments())      PUSH_STRING("uuencode=1");    else      PUSH_STRING("uuencode=0");    PUSH_NEWLINE ();  }  nsCOMPtr<nsIHttpProtocolHandler> pHTTPHandler =            do_GetService(kHTTPHandlerCID, &rv);   if (NS_SUCCEEDED(rv) && pHTTPHandler)  {        nsCAutoString userAgentString;        pHTTPHandler->GetUserAgent(userAgentString);    if (!userAgentString.IsEmpty())    {      // PUSH_STRING ("X-Mailer: ");  // To be more standards compliant      PUSH_STRING ("User-Agent: ");        PUSH_STRING(userAgentString.get());      PUSH_NEWLINE ();    }  }  /* for Netscape Server, Accept-Language data sent in Mail header */  char *acceptlang = nsMsgI18NGetAcceptLanguage();  if( (acceptlang != NULL) && ( *acceptlang != '\0') ){    PUSH_STRING( "X-Accept-Language: " );    PUSH_STRING( acceptlang );    PUSH_NEWLINE();  }  PUSH_STRING ("MIME-Version: 1.0" CRLF);  if (pNewsGrp && *pNewsGrp) {    /* turn whitespace into a comma list    */    char *duppedNewsGrp = PL_strdup(pNewsGrp);    if (!duppedNewsGrp) {      PR_FREEIF(buffer);      return nsnull; /* NS_ERROR_OUT_OF_MEMORY */    }    char *n2 = nsMsgStripLine(duppedNewsGrp);    for(char *ptr = n2; *ptr != '\0'; ptr++) {      /* find first non white space */      while(!IS_SPACE(*ptr) && *ptr != ',' && *ptr != '\0')        ptr++;      if(*ptr == '\0')        break;      if(*ptr != ',')        *ptr = ',';      /* find next non white space */      char *ptr2 = ptr+1;      while(IS_SPACE(*ptr2))        ptr2++;      if(ptr2 != ptr+1)        PL_strcpy(ptr+1, ptr2);    }    // we need to decide the Newsgroup related headers    // to write to the outgoing message. In ANY case, we need to write the    // "Newsgroup" header which is the "proper" header as opposed to the    // HEADER_X_MOZILLA_NEWSHOST which can contain the "news:" URL's.    //    // Since n2 can contain data in the form of:    // "news://news.mozilla.org/netscape.test,news://news.mozilla.org/netscape.junk"    // we need to turn that into: "netscape.test,netscape.junk"    //    nsCOMPtr <nsINntpService> nntpService = do_GetService("@mozilla.org/messenger/nntpservice;1");    if (NS_FAILED(rv) || !nntpService) {      *status = NS_ERROR_FAILURE;      return nsnull;    }    nsXPIDLCString newsgroupsHeaderVal;    nsXPIDLCString newshostHeaderVal;    rv = nntpService->GenerateNewsHeaderValsForPosting(n2, getter_Copies(newsgroupsHeaderVal), getter_Copies(newshostHeaderVal));    if (NS_FAILED(rv)) {      *status = rv;      return nsnull;    }    PUSH_STRING ("Newsgroups: ");    PUSH_STRING (newsgroupsHeaderVal.get());    PUSH_NEWLINE ();    // If we are here, we are NOT going to send this now. (i.e. it is a Draft,     // Send Later file, etc...). Because of that, we need to store what the user    // typed in on the original composition window for use later when rebuilding    // the headers    if (deliver_mode != nsIMsgSend::nsMsgDeliverNow && deliver_mode != nsIMsgSend::nsMsgSendUnsent)    {      // This is going to be saved for later, that means we should just store      // what the user typed into the "Newsgroup" line in the HEADER_X_MOZILLA_NEWSHOST      // header for later use by "Send Unsent Messages", "Drafts" or "Templates"      PUSH_STRING (HEADER_X_MOZILLA_NEWSHOST);      PUSH_STRING (": ");      PUSH_STRING (newshostHeaderVal.get());      PUSH_NEWLINE ();    }    PR_FREEIF(duppedNewsGrp);    hasDisclosedRecipient = PR_TRUE;  }  /* #### shamelessly duplicated from above */  if (pFollow && *pFollow) {    /* turn whitespace into a comma list    */    char *duppedFollowup = PL_strdup(pFollow);    if (!duppedFollowup) {      PR_FREEIF(buffer);      return nsnull; /* NS_ERROR_OUT_OF_MEMORY */    }    char *n2 = nsMsgStripLine (duppedFollowup);    for (char *ptr = n2; *ptr != '\0'; ptr++) {      /* find first non white space */      while(!IS_SPACE(*ptr) && *ptr != ',' && *ptr != '\0')        ptr++;      if(*ptr == '\0')        break;      if(*ptr != ',')        *ptr = ',';      /* find next non white space */      char *ptr2 = ptr+1;      while(IS_SPACE(*ptr2))        ptr2++;      if(ptr2 != ptr+1)        PL_strcpy(ptr+1, ptr2);    }    PUSH_STRING ("Followup-To: ");    PUSH_STRING (n2);    PR_Free (duppedFollowup);    PUSH_NEWLINE ();  }  if (pTo && *pTo) {    ENCODE_AND_PUSH("To: ", PR_TRUE, pTo, charset, usemime);    hasDisclosedRecipient = PR_TRUE;  }   if (pCc && *pCc) {    ENCODE_AND_PUSH("CC: ", PR_TRUE, pCc, charset, usemime);    hasDisclosedRecipient = PR_TRUE;  }  // If we don't have disclosed recipient (only Bcc), address the message to the sender to  // prevent problem with some servers  if (!hasDisclosedRecipient) {    const char* pBcc = fields->GetBcc(); //Do not free me!    if (pBcc && *pBcc)      ENCODE_AND_PUSH("To: ", PR_TRUE, pFrom, charset, usemime);  }  if (pSubject && *pSubject) {    ENCODE_AND_PUSH("Subject: ", PR_FALSE, pSubject, charset, usemime);  }    if (pPriority && *pPriority)    if (!PL_strcasestr(pPriority, "normal")) {      PUSH_STRING ("X-Priority: ");      /* Important: do not change the order of the       * following if statements      */      if (PL_strcasestr (pPriority, "highest"))        PUSH_STRING("1 (");      else if (PL_strcasestr(pPriority, "high"))        PUSH_STRING("2 (");      else if (PL_strcasestr(pPriority, "lowest"))        PUSH_STRING("5 (");      else if (PL_strcasestr(pPriority, "low"))        PUSH_STRING("4 (");      PUSH_STRING (pPriority);      PUSH_STRING(")");      PUSH_NEWLINE ();    }  if (pReference && *pReference) {    PUSH_STRING ("References: ");    if (PL_strlen(pReference) >= 986) {      char *references = PL_strdup(pReference);      char *trimAt = PL_strchr(references+1, '<');      char *ptr;      // per sfraser, RFC 1036 - a message header line should not exceed      // 998 characters including the header identifier      // retiring the earliest reference one after the other      // but keep the first one for proper threading      while (references && PL_strlen(references) >= 986 && trimAt) {        ptr = PL_strchr(trimAt+1, '<');        if (ptr)          memmove(trimAt, ptr, PL_strlen(ptr)+1); // including the        else          break;      }      NS_ASSERTION(references, "null references");      if (references) {        PUSH_STRING (references);        PR_Free(references);      }    }    else      PUSH_STRING (pReference);    PUSH_NEWLINE ();    {      const char *lastRef = PL_strrchr(pReference, '<');      if (lastRef) {        PUSH_STRING ("In-Reply-To: ");        PUSH_STRING (lastRef);        PUSH_NEWLINE ();      }    }  }  if (pOtherHdr && *pOtherHdr) {    /* Assume they already have the right newlines and continuations     and so on. */    PUSH_STRING (pOtherHdr);  }  if (buffer_tail > buffer + size - 1)    return nsnull;  /* realloc it smaller... */  buffer = (char*)PR_REALLOC (buffer, buffer_tail - buffer + 1);  return buffer;}