NeoMutt  2021-10-29-33-g41675a
Teaching an old dog new tricks
DOXYGEN
header.h File Reference

Convenience wrapper for the send headers. More...

#include <stdbool.h>
#include <stdio.h>
#include "copy.h"
+ Include dependency graph for header.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  MuttWriteHeaderMode {
  MUTT_WRITE_HEADER_NORMAL , MUTT_WRITE_HEADER_FCC , MUTT_WRITE_HEADER_POSTPONE , MUTT_WRITE_HEADER_EDITHDRS ,
  MUTT_WRITE_HEADER_MIME
}
 Modes for mutt_rfc822_write_header() More...
 

Functions

int mutt_rfc822_write_header (FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
 Write out one RFC822 header line. More...
 
int mutt_write_mime_header (struct Body *a, FILE *fp, struct ConfigSubset *sub)
 Create a MIME header. More...
 
int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags, struct ConfigSubset *sub)
 Write one header line to a file. More...
 
void mutt_write_references (const struct ListHead *r, FILE *fp, size_t trim)
 Add the message references to a list. More...
 

Detailed Description

Convenience wrapper for the send headers.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file header.h.

Enumeration Type Documentation

◆ MuttWriteHeaderMode

Modes for mutt_rfc822_write_header()

Enumerator
MUTT_WRITE_HEADER_NORMAL 

A normal Email, write full header + MIME headers.

MUTT_WRITE_HEADER_FCC 

fcc mode, like normal mode but for Bcc header

MUTT_WRITE_HEADER_POSTPONE 

A postponed Email, just the envelope info.

MUTT_WRITE_HEADER_EDITHDRS 

"light" mode (used for edit_hdrs)

MUTT_WRITE_HEADER_MIME 

Write protected headers.

Definition at line 38 of file header.h.

39 {
45 };
@ MUTT_WRITE_HEADER_FCC
fcc mode, like normal mode but for Bcc header
Definition: header.h:41
@ MUTT_WRITE_HEADER_MIME
Write protected headers.
Definition: header.h:44
@ MUTT_WRITE_HEADER_NORMAL
A normal Email, write full header + MIME headers.
Definition: header.h:40
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition: header.h:42
@ MUTT_WRITE_HEADER_EDITHDRS
"light" mode (used for edit_hdrs)
Definition: header.h:43

Function Documentation

◆ mutt_rfc822_write_header()

int mutt_rfc822_write_header ( FILE *  fp,
struct Envelope env,
struct Body attach,
enum MuttWriteHeaderMode  mode,
bool  privacy,
bool  hide_protected_subject,
struct ConfigSubset sub 
)

Write out one RFC822 header line.

Parameters
fpFile to write to
envEnvelope of email
attachAttachment
modeMode, see MuttWriteHeaderMode
privacyIf true, remove headers that might identify the user
hide_protected_subjectIf true, replace subject header
subConfig Subset
Return values
0Success
-1Failure
Note
All RFC2047 encoding should be done outside of this routine, except for the "real name." This will allow this routine to be used more than once, if necessary.

Likewise, all IDN processing should happen outside of this routine.

privacy true => will omit any headers which may identify the user. Output generated is suitable for being sent through anonymous remailer chains.

hide_protected_subject: replaces the Subject header with $crypt_protected_headers_subject in NORMAL or POSTPONE mode.

Definition at line 572 of file header.c.

575 {
576  char buf[1024];
577 
578  if (((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_FCC) ||
579  (mode == MUTT_WRITE_HEADER_POSTPONE)) &&
580  !privacy)
581  {
582  struct Buffer *date = mutt_buffer_pool_get();
583  mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
584  fprintf(fp, "Date: %s\n", mutt_buffer_string(date));
586  }
587 
588  /* UseFrom is not consulted here so that we can still write a From:
589  * field if the user sets it with the 'my_hdr' command */
590  if (!TAILQ_EMPTY(&env->from) && !privacy)
591  {
592  buf[0] = '\0';
593  mutt_addrlist_write(&env->from, buf, sizeof(buf), false);
594  fprintf(fp, "From: %s\n", buf);
595  }
596 
597  if (!TAILQ_EMPTY(&env->sender) && !privacy)
598  {
599  buf[0] = '\0';
600  mutt_addrlist_write(&env->sender, buf, sizeof(buf), false);
601  fprintf(fp, "Sender: %s\n", buf);
602  }
603 
604  if (!TAILQ_EMPTY(&env->to))
605  {
606  fputs("To: ", fp);
607  mutt_addrlist_write_file(&env->to, fp, 4, false);
608  }
609  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
610 #ifdef USE_NNTP
611  if (!OptNewsSend)
612 #endif
613  fputs("To:\n", fp);
614 
615  if (!TAILQ_EMPTY(&env->cc))
616  {
617  fputs("Cc: ", fp);
618  mutt_addrlist_write_file(&env->cc, fp, 4, false);
619  }
620  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
621 #ifdef USE_NNTP
622  if (!OptNewsSend)
623 #endif
624  fputs("Cc:\n", fp);
625 
626  if (!TAILQ_EMPTY(&env->bcc))
627  {
628  const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
629 
630  if ((mode == MUTT_WRITE_HEADER_POSTPONE) ||
631  (mode == MUTT_WRITE_HEADER_EDITHDRS) || (mode == MUTT_WRITE_HEADER_FCC) ||
632  ((mode == MUTT_WRITE_HEADER_NORMAL) && c_write_bcc))
633  {
634  fputs("Bcc: ", fp);
635  mutt_addrlist_write_file(&env->bcc, fp, 5, false);
636  }
637  }
638  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
639 #ifdef USE_NNTP
640  if (!OptNewsSend)
641 #endif
642  fputs("Bcc:\n", fp);
643 
644 #ifdef USE_NNTP
645  if (env->newsgroups)
646  fprintf(fp, "Newsgroups: %s\n", env->newsgroups);
647  else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend)
648  fputs("Newsgroups:\n", fp);
649 
650  if (env->followup_to)
651  fprintf(fp, "Followup-To: %s\n", env->followup_to);
652  else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend)
653  fputs("Followup-To:\n", fp);
654 
655  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
656  if (env->x_comment_to)
657  fprintf(fp, "X-Comment-To: %s\n", env->x_comment_to);
658  else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend && c_x_comment_to)
659  fputs("X-Comment-To:\n", fp);
660 #endif
661 
662  if (env->subject)
663  {
664  if (hide_protected_subject &&
665  ((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_FCC) ||
666  (mode == MUTT_WRITE_HEADER_POSTPONE)))
667  {
668  const char *const c_crypt_protected_headers_subject =
669  cs_subset_string(sub, "crypt_protected_headers_subject");
670  mutt_write_one_header(fp, "Subject", c_crypt_protected_headers_subject,
671  NULL, 0, CH_NO_FLAGS, sub);
672  }
673  else
674  mutt_write_one_header(fp, "Subject", env->subject, NULL, 0, CH_NO_FLAGS, sub);
675  }
676  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
677  fputs("Subject:\n", fp);
678 
679  /* save message id if the user has set it */
680  if (env->message_id && !privacy)
681  fprintf(fp, "Message-ID: %s\n", env->message_id);
682 
683  if (!TAILQ_EMPTY(&env->reply_to))
684  {
685  fputs("Reply-To: ", fp);
686  mutt_addrlist_write_file(&env->reply_to, fp, 10, false);
687  }
688  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
689  fputs("Reply-To:\n", fp);
690 
691  if (!TAILQ_EMPTY(&env->mail_followup_to))
692  {
693 #ifdef USE_NNTP
694  if (!OptNewsSend)
695 #endif
696  {
697  fputs("Mail-Followup-To: ", fp);
698  mutt_addrlist_write_file(&env->mail_followup_to, fp, 18, false);
699  }
700  }
701 
702  /* Add any user defined headers */
703  struct UserHdrsOverride userhdrs_overrides =
704  write_userhdrs(fp, &env->userhdrs, privacy, sub);
705 
706  if ((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_FCC) ||
707  (mode == MUTT_WRITE_HEADER_POSTPONE) || (mode == MUTT_WRITE_HEADER_MIME))
708  {
709  if (!STAILQ_EMPTY(&env->references))
710  {
711  fputs("References:", fp);
712  mutt_write_references(&env->references, fp, 10);
713  fputc('\n', fp);
714  }
715 
716  /* Add the MIME headers */
717  if (!userhdrs_overrides.is_overridden[USERHDRS_OVERRIDE_CONTENT_TYPE])
718  {
719  fputs("MIME-Version: 1.0\n", fp);
720  mutt_write_mime_header(attach, fp, sub);
721  }
722  }
723 
724  if (!STAILQ_EMPTY(&env->in_reply_to))
725  {
726  fputs("In-Reply-To:", fp);
727  mutt_write_references(&env->in_reply_to, fp, 0);
728  fputc('\n', fp);
729  }
730 
731 #ifdef USE_AUTOCRYPT
732  const bool c_autocrypt = cs_subset_bool(sub, "autocrypt");
733  if (c_autocrypt)
734  {
735  if (mode == MUTT_WRITE_HEADER_NORMAL || mode == MUTT_WRITE_HEADER_FCC)
737  if (mode == MUTT_WRITE_HEADER_MIME)
739  }
740 #endif
741 
742  const bool c_user_agent = cs_subset_bool(sub, "user_agent");
743  if (((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_FCC)) && !privacy &&
744  c_user_agent && !userhdrs_overrides.is_overridden[USERHDRS_OVERRIDE_USER_AGENT])
745  {
746  /* Add a vanity header */
747  fprintf(fp, "User-Agent: NeoMutt/%s%s\n", PACKAGE_VERSION, GitVer);
748  }
749 
750  return (ferror(fp) == 0) ? 0 : -1;
751 }
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, int start_col, bool display)
Wrapper for mutt_write_address()
Definition: address.c:1231
int mutt_autocrypt_write_gossip_headers(struct Envelope *env, FILE *fp)
Write the Autocrypt gossip headers to a file.
Definition: autocrypt.c:809
int mutt_autocrypt_write_autocrypt_header(struct Envelope *env, FILE *fp)
Write the Autocrypt header to a file.
Definition: autocrypt.c:771
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:378
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:761
static struct UserHdrsOverride write_userhdrs(FILE *fp, const struct ListHead *userhdrs, bool privacy, struct ConfigSubset *sub)
Write user-defined headers and keep track of the interesting ones.
Definition: header.c:361
@ USERHDRS_OVERRIDE_CONTENT_TYPE
Override the "Content-Type".
Definition: header.c:60
@ USERHDRS_OVERRIDE_USER_AGENT
Override the "User-Agent".
Definition: header.c:61
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: header.c:514
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags, struct ConfigSubset *sub)
Write one header line to a file.
Definition: header.c:420
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
const char * GitVer
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:51
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define TAILQ_EMPTY(head)
Definition: queue.h:721
String manipulation buffer.
Definition: buffer.h:34
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:79
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:62
char * message_id
Message ID.
Definition: envelope.h:71
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:80
char * newsgroups
List of newsgroups.
Definition: envelope.h:77
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:63
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
struct AddressList sender
Email's sender.
Definition: envelope.h:61
struct ListHead references
message references (in reverse order)
Definition: envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:84
char * subject
Email's subject.
Definition: envelope.h:68
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
Which headers have been overridden.
Definition: header.c:68
bool is_overridden[mutt_array_size(userhdrs_override_headers)]
Which email headers have been overridden.
Definition: header.c:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_mime_header()

int mutt_write_mime_header ( struct Body a,
FILE *  fp,
struct ConfigSubset sub 
)

Create a MIME header.

Parameters
aBody part
fpFile to write to
subConfig Subset
Return values
0Success
-1Failure

Definition at line 761 of file header.c.

762 {
763  if (!a || !fp)
764  return -1;
765 
766  int len;
767  int tmplen;
768  char buf[256] = { 0 };
769 
770  fprintf(fp, "Content-Type: %s/%s", TYPE(a), a->subtype);
771 
772  if (!TAILQ_EMPTY(&a->parameter))
773  {
774  len = 25 + mutt_str_len(a->subtype); /* approximate len. of content-type */
775 
776  struct Parameter *np = NULL;
777  TAILQ_FOREACH(np, &a->parameter, entries)
778  {
779  if (!np->attribute || !np->value)
780  continue;
781 
782  struct ParameterList pl_conts = TAILQ_HEAD_INITIALIZER(pl_conts);
783  rfc2231_encode_string(&pl_conts, np->attribute, np->value);
784  struct Parameter *cont = NULL;
785  TAILQ_FOREACH(cont, &pl_conts, entries)
786  {
787  fputc(';', fp);
788 
789  buf[0] = 0;
790  mutt_addr_cat(buf, sizeof(buf), cont->value, MimeSpecials);
791 
792  /* Dirty hack to make messages readable by Outlook Express
793  * for the Mac: force quotes around the boundary parameter
794  * even when they aren't needed. */
795  if (mutt_istr_equal(cont->attribute, "boundary") && mutt_str_equal(buf, cont->value))
796  snprintf(buf, sizeof(buf), "\"%s\"", cont->value);
797 
798  tmplen = mutt_str_len(buf) + mutt_str_len(cont->attribute) + 1;
799  if (len + tmplen + 2 > 76)
800  {
801  fputs("\n\t", fp);
802  len = tmplen + 1;
803  }
804  else
805  {
806  fputc(' ', fp);
807  len += tmplen + 1;
808  }
809 
810  fprintf(fp, "%s=%s", cont->attribute, buf);
811  }
812 
813  mutt_param_free(&pl_conts);
814  }
815  }
816 
817  fputc('\n', fp);
818 
819  if (a->language)
820  fprintf(fp, "Content-Language: %s\n", a->language);
821 
822  if (a->description)
823  fprintf(fp, "Content-Description: %s\n", a->description);
824 
825  if (a->disposition != DISP_NONE)
826  {
827  const char *dispstr[] = { "inline", "attachment", "form-data" };
828 
829  if (a->disposition < sizeof(dispstr) / sizeof(char *))
830  {
831  fprintf(fp, "Content-Disposition: %s", dispstr[a->disposition]);
832  len = 21 + mutt_str_len(dispstr[a->disposition]);
833 
834  if (a->use_disp && (a->disposition != DISP_INLINE))
835  {
836  char *fn = a->d_filename;
837  if (!fn)
838  fn = a->filename;
839 
840  if (fn)
841  {
842  /* Strip off the leading path... */
843  char *t = strrchr(fn, '/');
844  if (t)
845  t++;
846  else
847  t = fn;
848 
849  struct ParameterList pl_conts = TAILQ_HEAD_INITIALIZER(pl_conts);
850  rfc2231_encode_string(&pl_conts, "filename", t);
851  struct Parameter *cont = NULL;
852  TAILQ_FOREACH(cont, &pl_conts, entries)
853  {
854  fputc(';', fp);
855  buf[0] = 0;
856  mutt_addr_cat(buf, sizeof(buf), cont->value, MimeSpecials);
857 
858  tmplen = mutt_str_len(buf) + mutt_str_len(cont->attribute) + 1;
859  if (len + tmplen + 2 > 76)
860  {
861  fputs("\n\t", fp);
862  len = tmplen + 1;
863  }
864  else
865  {
866  fputc(' ', fp);
867  len += tmplen + 1;
868  }
869 
870  fprintf(fp, "%s=%s", cont->attribute, buf);
871  }
872 
873  mutt_param_free(&pl_conts);
874  }
875  }
876 
877  fputc('\n', fp);
878  }
879  else
880  {
881  mutt_debug(LL_DEBUG1, "ERROR: invalid content-disposition %d\n", a->disposition);
882  }
883  }
884 
885  if (a->encoding != ENC_7BIT)
886  fprintf(fp, "Content-Transfer-Encoding: %s\n", ENCODING(a->encoding));
887 
888  const bool c_crypt_protected_headers_write =
889  cs_subset_bool(sub, "crypt_protected_headers_write");
890  bool autocrypt = false;
891 #ifdef USE_AUTOCRYPT
892  autocrypt = cs_subset_bool(sub, "autocrypt");
893 #endif
894 
895  if ((c_crypt_protected_headers_write || autocrypt) && a->mime_headers)
896  {
898  false, false, sub);
899  }
900 
901  /* Do NOT add the terminator here!!! */
902  return ferror(fp) ? -1 : 0;
903 }
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:681
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:572
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
@ DISP_NONE
No preferred disposition.
Definition: mime.h:65
#define ENCODING(x)
Definition: mime.h:92
#define TYPE(body)
Definition: mime.h:89
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:727
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
size_t rfc2231_encode_string(struct ParameterList *head, const char *attribute, char *value)
Encode a string to be suitable for an RFC2231 header.
Definition: rfc2231.c:346
char * language
content-language (RFC8255)
Definition: body.h:76
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:55
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:74
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:61
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:46
char * description
content-description
Definition: body.h:54
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:41
char * subtype
content-type subtype
Definition: body.h:59
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:57
Attribute associated with a MIME part.
Definition: parameter.h:33
char * attribute
Parameter name.
Definition: parameter.h:34
char * value
Parameter value.
Definition: parameter.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_one_header()

int mutt_write_one_header ( FILE *  fp,
const char *  tag,
const char *  value,
const char *  pfx,
int  wraplen,
CopyHeaderFlags  chflags,
struct ConfigSubset sub 
)

Write one header line to a file.

Parameters
fpFile to write to
tagHeader key, e.g. "From"
valueHeader value
pfxPrefix for header
wraplenColumn to wrap at
chflagsFlags, see CopyHeaderFlags
subConfig Subset
Return values
0Success
-1Failure

split several headers into individual ones and call write_one_header for each one

Definition at line 420 of file header.c.

423 {
424  char *last = NULL, *line = NULL;
425  int max = 0, w, rc = -1;
426  int pfxw = mutt_strwidth(pfx);
427  char *v = mutt_str_dup(value);
428  bool display = (chflags & CH_DISPLAY);
429 
430  const bool c_weed = cs_subset_bool(sub, "weed");
431  if (!display || c_weed)
432  v = unfold_header(v);
433 
434  /* when not displaying, use sane wrap value */
435  if (!display)
436  {
437  const short c_wrap_headers = cs_subset_number(sub, "wrap_headers");
438  if ((c_wrap_headers < 78) || (c_wrap_headers > 998))
439  wraplen = 78;
440  else
441  wraplen = c_wrap_headers;
442  }
443  else if (wraplen <= 0)
444  wraplen = 78;
445 
446  const size_t vlen = mutt_str_len(v);
447  if (tag)
448  {
449  /* if header is short enough, simply print it */
450  if (!display && (mutt_strwidth(tag) + 2 + pfxw + mutt_strnwidth(v, vlen) <= wraplen))
451  {
452  mutt_debug(LL_DEBUG5, "buf[%s%s: %s] is short enough\n", NONULL(pfx), tag, v);
453  if (fprintf(fp, "%s%s: %s\n", NONULL(pfx), tag, v) <= 0)
454  goto out;
455  rc = 0;
456  goto out;
457  }
458  else
459  {
460  rc = fold_one_header(fp, tag, v, vlen, pfx, wraplen, chflags);
461  goto out;
462  }
463  }
464 
465  char *p = v;
466  last = v;
467  line = v;
468  while (p && *p)
469  {
470  p = strchr(p, '\n');
471 
472  /* find maximum line width in current header */
473  if (p)
474  *p = '\0';
475  w = mutt_mb_width(line, 0, display);
476  if (w > max)
477  max = w;
478  if (p)
479  *p = '\n';
480 
481  if (!p)
482  break;
483 
484  line = ++p;
485  if ((*p != ' ') && (*p != '\t'))
486  {
487  if (write_one_header(fp, pfxw, max, wraplen, pfx, last, p, chflags) < 0)
488  goto out;
489  last = p;
490  max = 0;
491  }
492  }
493 
494  if (last && *last)
495  if (write_one_header(fp, pfxw, max, wraplen, pfx, last, p, chflags) < 0)
496  goto out;
497 
498  rc = 0;
499 
500 out:
501  FREE(&v);
502  return rc;
503 }
#define CH_DISPLAY
Display result to user.
Definition: copy.h:70
int mutt_strnwidth(const char *s, size_t n)
Measure a string's width in screen cells.
Definition: curs_lib.c:1001
int mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:988
static int fold_one_header(FILE *fp, const char *tag, const char *value, size_t vlen, const char *pfx, int wraplen, CopyHeaderFlags chflags)
Fold one header line.
Definition: header.c:130
static char * unfold_header(char *s)
Unfold a wrapped email header.
Definition: header.c:235
static int write_one_header(FILE *fp, int pfxw, int max, int wraplen, const char *pfx, const char *start, const char *end, CopyHeaderFlags chflags)
Write out one header line.
Definition: header.c:292
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
int mutt_mb_width(const char *str, int col, bool display)
Measure a string's display width (in screen columns)
Definition: mbyte.c:138
#define FREE(x)
Definition: memory.h:40
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_references()

void mutt_write_references ( const struct ListHead *  r,
FILE *  fp,
size_t  trim 
)

Add the message references to a list.

Parameters
rString List of references
fpFile to write to
trimTrim the list to at most this many items

Write the list in reverse because they are stored in reverse order when parsed to speed up threading.

Definition at line 514 of file header.c.

515 {
516  struct ListNode *np = NULL;
517  size_t length = 0;
518 
519  STAILQ_FOREACH(np, r, entries)
520  {
521  if (++length == trim)
522  break;
523  }
524 
525  struct ListNode **ref = mutt_mem_calloc(length, sizeof(struct ListNode *));
526 
527  // store in reverse order
528  size_t tmp = length;
529  STAILQ_FOREACH(np, r, entries)
530  {
531  ref[--tmp] = np;
532  if (tmp == 0)
533  break;
534  }
535 
536  for (size_t i = 0; i < length; i++)
537  {
538  fputc(' ', fp);
539  fputs(ref[i]->data, fp);
540  if (i != length - 1)
541  fputc('\n', fp);
542  }
543 
544  FREE(&ref);
545 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function: