NeoMutt  2025-12-11-435-g4ac674
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
cid.c File Reference

Attachment Content-ID header functions. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "email/lib.h"
#include "core/lib.h"
#include "cid.h"
#include "attach.h"
#include "mutt_attach.h"
+ Include dependency graph for cid.c:

Go to the source code of this file.

Macros

#define CID_DEPTH_MAX   50
 Maximum MIME nesting depth for saving CID attachments.
 

Functions

void cid_map_free (struct CidMap **ptr)
 Free a CidMap.
 
struct CidMapcid_map_new (const char *cid, const char *filename)
 Initialise a new CidMap.
 
void cid_map_list_clear (struct CidMapList *cid_map_list)
 Empty a CidMapList.
 
static void cid_save_attachment (struct Body *b, struct CidMapList *cid_map_list)
 Save attachment if it has a Content-ID.
 
static void cid_save_attachments_r (struct Body *body, struct CidMapList *cid_map_list, int depth)
 Recursively save attachments with Content-IDs.
 
void cid_save_attachments (struct Body *body, struct CidMapList *cid_map_list)
 Save all attachments in a "multipart/related" group with a Content-ID.
 
void cid_to_filename (struct Buffer *filename, const struct CidMapList *cid_map_list)
 Replace Content-IDs with filenames.
 

Detailed Description

Attachment Content-ID header functions.

Authors
  • David Purton
  • 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 cid.c.

Macro Definition Documentation

◆ CID_DEPTH_MAX

#define CID_DEPTH_MAX   50

Maximum MIME nesting depth for saving CID attachments.

Definition at line 145 of file cid.c.

Function Documentation

◆ cid_map_free()

void cid_map_free ( struct CidMap ** ptr)

Free a CidMap.

Parameters
[out]ptrCidMap to free

Definition at line 44 of file cid.c.

45{
46 if (!ptr || !*ptr)
47 return;
48
49 struct CidMap *cid_map = *ptr;
50
51 FREE(&cid_map->cid);
52 FREE(&cid_map->fname);
53
54 FREE(ptr);
55}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
List of Content-ID to filename mappings.
Definition cid.h:35
char * fname
Filename.
Definition cid.h:37
char * cid
Content-ID.
Definition cid.h:36
+ Here is the caller graph for this function:

◆ cid_map_new()

struct CidMap * cid_map_new ( const char * cid,
const char * filename )

Initialise a new CidMap.

Parameters
cidContent-ID to replace including "cid:" prefix
filenamePath to file to replace Content-ID with
Return values
ptrNewly allocated CidMap

Definition at line 63 of file cid.c.

64{
65 if (!cid || !filename)
66 return NULL;
67
68 struct CidMap *cid_map = MUTT_MEM_CALLOC(1, struct CidMap);
69
70 cid_map->cid = mutt_str_dup(cid);
71 cid_map->fname = mutt_str_dup(filename);
72
73 return cid_map;
74}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cid_map_list_clear()

void cid_map_list_clear ( struct CidMapList * cid_map_list)

Empty a CidMapList.

Parameters
cid_map_listList of Content-ID to filename mappings

Definition at line 80 of file cid.c.

81{
82 if (!cid_map_list)
83 return;
84
85 while (!STAILQ_EMPTY(cid_map_list))
86 {
87 struct CidMap *cid_map = STAILQ_FIRST(cid_map_list);
88 STAILQ_REMOVE_HEAD(cid_map_list, entries);
89 cid_map_free(&cid_map);
90 }
91}
void cid_map_free(struct CidMap **ptr)
Free a CidMap.
Definition cid.c:44
#define STAILQ_REMOVE_HEAD(head, field)
Definition queue.h:461
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_EMPTY(head)
Definition queue.h:382
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cid_save_attachment()

static void cid_save_attachment ( struct Body * b,
struct CidMapList * cid_map_list )
static

Save attachment if it has a Content-ID.

Parameters
[in]bBody to check and save
[out]cid_map_listList of Content-ID to filename mappings

If body has a Content-ID, it is saved to disk and a new Content-ID to filename mapping is added to cid_map_list.

Definition at line 101 of file cid.c.

102{
103 if (!b || !cid_map_list)
104 return;
105
106 char *id = b->content_id;
107 if (!id)
108 return;
109
110 struct Buffer *tempfile = buf_pool_get();
111 struct Buffer *cid = buf_pool_get();
112 bool has_tempfile = false;
113 FILE *fp = NULL;
114
115 mutt_debug(LL_DEBUG2, "attachment found with \"Content-ID: %s\"\n", id);
116 /* get filename */
117 char *fname = mutt_str_dup(b->filename);
118 if (b->aptr)
119 fp = b->aptr->fp;
120 mutt_file_sanitize_filename(fname, fp ? true : false);
121 mailcap_expand_filename("%s", fname, tempfile);
122 FREE(&fname);
123
124 /* save attachment */
125 if (mutt_save_attachment(fp, b, buf_string(tempfile), 0, NULL) == -1)
126 goto bail;
127 has_tempfile = true;
128 mutt_debug(LL_DEBUG2, "attachment with \"Content-ID: %s\" saved to file \"%s\"\n",
129 id, buf_string(tempfile));
130
131 /* add Content-ID to filename mapping to list */
132 buf_printf(cid, "cid:%s", id);
133 struct CidMap *cid_map = cid_map_new(buf_string(cid), buf_string(tempfile));
134 STAILQ_INSERT_TAIL(cid_map_list, cid_map, entries);
135
136bail:
137
138 if ((fp && !buf_is_empty(tempfile)) || has_tempfile)
140 buf_pool_release(&tempfile);
142}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
struct CidMap * cid_map_new(const char *cid, const char *filename)
Initialise a new CidMap.
Definition cid.c:63
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:586
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition mailcap.c:553
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:427
FILE * fp
Used in the recvattach menu.
Definition attach.h:37
char * content_id
Content-Id (RFC2392)
Definition body.h:58
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition body.h:75
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cid_save_attachments_r()

static void cid_save_attachments_r ( struct Body * body,
struct CidMapList * cid_map_list,
int depth )
static

Recursively save attachments with Content-IDs.

Parameters
[in]bodyFirst body in "multipart/related" group
[out]cid_map_listList of Content-ID to filename mappings
[in]depthCurrent recursion depth

Definition at line 153 of file cid.c.

154{
155 if (!body || !cid_map_list || (depth >= CID_DEPTH_MAX))
156 return;
157
158 for (struct Body *b = body; b; b = b->next)
159 {
160 if (b->parts)
161 cid_save_attachments_r(b->parts, cid_map_list, depth + 1);
162 else
163 cid_save_attachment(b, cid_map_list);
164 }
165}
#define CID_DEPTH_MAX
Maximum MIME nesting depth for saving CID attachments.
Definition cid.c:145
static void cid_save_attachment(struct Body *b, struct CidMapList *cid_map_list)
Save attachment if it has a Content-ID.
Definition cid.c:101
static void cid_save_attachments_r(struct Body *body, struct CidMapList *cid_map_list, int depth)
Recursively save attachments with Content-IDs.
Definition cid.c:153
The body of an email.
Definition body.h:36
struct Body * next
next attachment in the list
Definition body.h:72
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cid_save_attachments()

void cid_save_attachments ( struct Body * body,
struct CidMapList * cid_map_list )

Save all attachments in a "multipart/related" group with a Content-ID.

Parameters
[in]bodyFirst body in "multipart/related" group
[out]cid_map_listList of Content-ID to filename mappings

Definition at line 172 of file cid.c.

173{
174 cid_save_attachments_r(body, cid_map_list, 0);
175}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cid_to_filename()

void cid_to_filename ( struct Buffer * filename,
const struct CidMapList * cid_map_list )

Replace Content-IDs with filenames.

Parameters
filenamePath to file to replace Content-IDs with filenames
cid_map_listList of Content-ID to filename mappings

Definition at line 182 of file cid.c.

183{
184 if (!filename || !cid_map_list)
185 return;
186
187 FILE *fp_out = NULL;
188 char *pbuf = NULL;
189 char *searchbuf = NULL;
190 char *buf = NULL;
191 char *cid = NULL;
192 size_t blen = 0;
193 struct CidMap *cid_map = NULL;
194
195 struct Buffer *tempfile = buf_pool_get();
196 struct Buffer *tmpbuf = buf_pool_get();
197
198 FILE *fp_in = mutt_file_fopen(buf_string(filename), "r");
199 if (!fp_in)
200 goto bail;
201
202 /* ensure tempfile has the same file extension as filename otherwise an
203 * HTML file may be opened as plain text by the viewer */
204 const char *suffix = buf_rfind(filename, ".");
205 if (suffix && *(suffix++))
206 buf_mktemp_pfx_sfx(tempfile, "neomutt", suffix);
207 else
208 buf_mktemp(tempfile);
209 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
210 if (!fp_out)
211 goto bail;
212
213 /* Read in lines from filename into buf */
214 while ((buf = mutt_file_read_line(buf, &blen, fp_in, NULL, MUTT_RL_NO_FLAGS)) != NULL)
215 {
216 if (mutt_str_len(buf) == 0)
217 {
218 fputs(buf, fp_out);
219 continue;
220 }
221
222 /* copy buf to searchbuf because we need to edit multiple times */
223 searchbuf = mutt_str_dup(buf);
224 buf_reset(tmpbuf);
225
226 /* loop through Content-ID to filename mappings and do search and replace */
227 STAILQ_FOREACH(cid_map, cid_map_list, entries)
228 {
229 pbuf = searchbuf;
230 while ((cid = strstr(pbuf, cid_map->cid)) != NULL)
231 {
232 buf_addstr_n(tmpbuf, pbuf, cid - pbuf);
233 buf_addstr(tmpbuf, cid_map->fname);
234 pbuf = cid + mutt_str_len(cid_map->cid);
235 mutt_debug(LL_DEBUG2, "replaced \"%s\" with \"%s\" in file \"%s\"\n",
236 cid_map->cid, cid_map->fname, buf_string(filename));
237 }
238 buf_addstr(tmpbuf, pbuf);
239 FREE(&searchbuf);
240 searchbuf = buf_strdup(tmpbuf);
241 buf_reset(tmpbuf);
242 }
243
244 /* write edited line to output file */
245 fputs(searchbuf, fp_out);
246 fputs("\n", fp_out);
247 FREE(&searchbuf);
248 }
249
250 mutt_file_set_mtime(buf_string(filename), buf_string(tempfile));
251
252 /* add filename to TempAtachmentsList so it doesn't get left lying around */
254 /* update filename to point to new file */
255 buf_copy(filename, tempfile);
256
257bail:
258 FREE(&buf);
259 mutt_file_fclose(&fp_in);
260 mutt_file_fclose(&fp_out);
261 buf_pool_release(&tempfile);
262 buf_pool_release(&tmpbuf);
263}
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition buffer.c:96
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
const char * buf_rfind(const struct Buffer *buf, const char *str)
Find last instance of a substring.
Definition buffer.c:795
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:682
void mutt_file_set_mtime(const char *from, const char *to)
Set the modification time of one file from another.
Definition file.c:942
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:500
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define buf_mktemp(buf)
Definition tmp.h:33
#define buf_mktemp_pfx_sfx(buf, prefix, suffix)
Definition tmp.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function: