NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
cid.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include "email/lib.h"
35#include "core/lib.h"
36#include "cid.h"
37#include "attach.h"
38#include "mailcap.h"
39#include "mutt_attach.h"
40
45void cid_map_free(struct CidMap **ptr)
46{
47 if (!ptr || !*ptr)
48 return;
49
50 struct CidMap *cid_map = *ptr;
51
52 FREE(&cid_map->cid);
53 FREE(&cid_map->fname);
54
55 FREE(ptr);
56}
57
64struct CidMap *cid_map_new(const char *cid, const char *filename)
65{
66 if (!cid || !filename)
67 return NULL;
68
69 struct CidMap *cid_map = MUTT_MEM_CALLOC(1, struct CidMap);
70
71 cid_map->cid = mutt_str_dup(cid);
72 cid_map->fname = mutt_str_dup(filename);
73
74 return cid_map;
75}
76
81void cid_map_list_clear(struct CidMapList *cid_map_list)
82{
83 if (!cid_map_list)
84 return;
85
86 while (!STAILQ_EMPTY(cid_map_list))
87 {
88 struct CidMap *cid_map = STAILQ_FIRST(cid_map_list);
89 STAILQ_REMOVE_HEAD(cid_map_list, entries);
90 cid_map_free(&cid_map);
91 }
92}
93
102static void cid_save_attachment(struct Body *b, struct CidMapList *cid_map_list)
103{
104 if (!b || !cid_map_list)
105 return;
106
107 char *id = b->content_id;
108 if (!id)
109 return;
110
111 struct Buffer *tempfile = buf_pool_get();
112 struct Buffer *cid = buf_pool_get();
113 bool has_tempfile = false;
114 FILE *fp = NULL;
115
116 mutt_debug(LL_DEBUG2, "attachment found with \"Content-ID: %s\"\n", id);
117 /* get filename */
118 char *fname = mutt_str_dup(b->filename);
119 if (b->aptr)
120 fp = b->aptr->fp;
121 mutt_file_sanitize_filename(fname, fp ? true : false);
122 mailcap_expand_filename("%s", fname, tempfile);
123 FREE(&fname);
124
125 /* save attachment */
126 if (mutt_save_attachment(fp, b, buf_string(tempfile), 0, NULL) == -1)
127 goto bail;
128 has_tempfile = true;
129 mutt_debug(LL_DEBUG2, "attachment with \"Content-ID: %s\" saved to file \"%s\"\n",
130 id, buf_string(tempfile));
131
132 /* add Content-ID to filename mapping to list */
133 buf_printf(cid, "cid:%s", id);
134 struct CidMap *cid_map = cid_map_new(buf_string(cid), buf_string(tempfile));
135 STAILQ_INSERT_TAIL(cid_map_list, cid_map, entries);
136
137bail:
138
139 if ((fp && !buf_is_empty(tempfile)) || has_tempfile)
141 buf_pool_release(&tempfile);
143}
144
150void cid_save_attachments(struct Body *body, struct CidMapList *cid_map_list)
151{
152 if (!body || !cid_map_list)
153 return;
154
155 for (struct Body *b = body; b; b = b->next)
156 {
157 if (b->parts)
158 cid_save_attachments(b->parts, cid_map_list);
159 else
160 cid_save_attachment(b, cid_map_list);
161 }
162}
163
169void cid_to_filename(struct Buffer *filename, const struct CidMapList *cid_map_list)
170{
171 if (!filename || !cid_map_list)
172 return;
173
174 FILE *fp_out = NULL;
175 char *pbuf = NULL;
176 char *searchbuf = NULL;
177 char *buf = NULL;
178 char *cid = NULL;
179 size_t blen = 0;
180 struct CidMap *cid_map = NULL;
181
182 struct Buffer *tempfile = buf_pool_get();
183 struct Buffer *tmpbuf = buf_pool_get();
184
185 FILE *fp_in = mutt_file_fopen(buf_string(filename), "r");
186 if (!fp_in)
187 goto bail;
188
189 /* ensure tempfile has the same file extension as filename otherwise an
190 * HTML file may be opened as plain text by the viewer */
191 const char *suffix = buf_rfind(filename, ".");
192 if (suffix && *(suffix++))
193 buf_mktemp_pfx_sfx(tempfile, "neomutt", suffix);
194 else
195 buf_mktemp(tempfile);
196 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
197 if (!fp_out)
198 goto bail;
199
200 /* Read in lines from filename into buf */
201 while ((buf = mutt_file_read_line(buf, &blen, fp_in, NULL, MUTT_RL_NO_FLAGS)) != NULL)
202 {
203 if (mutt_str_len(buf) == 0)
204 {
205 fputs(buf, fp_out);
206 continue;
207 }
208
209 /* copy buf to searchbuf because we need to edit multiple times */
210 searchbuf = mutt_str_dup(buf);
211 buf_reset(tmpbuf);
212
213 /* loop through Content-ID to filename mappings and do search and replace */
214 STAILQ_FOREACH(cid_map, cid_map_list, entries)
215 {
216 pbuf = searchbuf;
217 while ((cid = strstr(pbuf, cid_map->cid)) != NULL)
218 {
219 buf_addstr_n(tmpbuf, pbuf, cid - pbuf);
220 buf_addstr(tmpbuf, cid_map->fname);
221 pbuf = cid + mutt_str_len(cid_map->cid);
222 mutt_debug(LL_DEBUG2, "replaced \"%s\" with \"%s\" in file \"%s\"\n",
223 cid_map->cid, cid_map->fname, buf_string(filename));
224 }
225 buf_addstr(tmpbuf, pbuf);
226 FREE(&searchbuf);
227 searchbuf = buf_strdup(tmpbuf);
228 buf_reset(tmpbuf);
229 }
230
231 /* write edited line to output file */
232 fputs(searchbuf, fp_out);
233 fputs("\n", fp_out);
234 FREE(&searchbuf);
235 }
236
237 mutt_file_set_mtime(buf_string(filename), buf_string(tempfile));
238
239 /* add filename to TempAtachmentsList so it doesn't get left lying around */
241 /* update filename to point to new file */
242 buf_copy(filename, tempfile);
243
244bail:
245 FREE(&buf);
246 mutt_file_fclose(&fp_in);
247 mutt_file_fclose(&fp_out);
248 buf_pool_release(&tempfile);
249 buf_pool_release(&tmpbuf);
250}
Handling of email attachments.
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
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
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
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
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:64
void cid_map_free(struct CidMap **ptr)
Free a CidMap.
Definition cid.c:45
static void cid_save_attachment(struct Body *b, struct CidMapList *cid_map_list)
Save attachment if it has a Content-ID.
Definition cid.c:102
void cid_save_attachments(struct Body *body, struct CidMapList *cid_map_list)
Save all attachments in a "multipart/related" group with a Content-ID.
Definition cid.c:150
void cid_to_filename(struct Buffer *filename, const struct CidMapList *cid_map_list)
Replace Content-IDs with filenames.
Definition cid.c:169
void cid_map_list_clear(struct CidMapList *cid_map_list)
Empty a CidMapList.
Definition cid.c:81
Attachment Content-ID header functions.
Convenience wrapper for the core headers.
Structs that make up an email.
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:685
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:589
void mutt_file_set_mtime(const char *from, const char *to)
Set the modification time of one file from another.
Definition file.c:945
#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
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:45
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:552
RFC1524 Mailcap routines.
#define FREE(x)
Definition memory.h:62
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
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.
Handling of email attachments.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
#define STAILQ_REMOVE_HEAD(head, field)
Definition queue.h:461
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:427
#define STAILQ_EMPTY(head)
Definition queue.h:382
FILE * fp
Used in the recvattach menu.
Definition attach.h:37
The body of an email.
Definition body.h:36
char * content_id
Content-Id (RFC2392)
Definition body.h:58
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition body.h:75
struct Body * next
next attachment in the list
Definition body.h:72
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
List of Content-ID to filename mappings.
Definition cid.h:36
char * fname
Filename.
Definition cid.h:38
char * cid
Content-ID.
Definition cid.h:37
#define buf_mktemp(buf)
Definition tmp.h:33
#define buf_mktemp_pfx_sfx(buf, prefix, suffix)
Definition tmp.h:34