e94bc475dfce3ee4371cc617a9b516d2784ac5ad
[asterisk/asterisk.git] / main / minimime / mm_envelope.c
1 /*
2  * $Id$
3  *
4  * MiniMIME - a library for handling MIME messages
5  *
6  * Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the author nor the names of the contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <assert.h>
40
41 #include "mm_internal.h"
42 #include "mm_util.h"
43
44 /** @file mm_envelope.c
45  *
46  * This module contains functions for accessing a message's envelope. This
47  * are mainly wrapper functions for easy access.
48  */
49
50 /** @defgroup envelope Accessing and manipulating a message's envelope
51  */
52
53 /** @{
54  * @name Accessing and manipulating a message's envelope
55  */
56
57 /**
58  * Gets an ASCII representation of all envelope headers
59  *
60  * @param ctx A valid MiniMIME context
61  * @param result Where to store the resulting ASCII headers
62  * @param length Where to store the length of the result
63  * @returns 0 on success or -1 on failure.
64  * @note Sets mm_errno on failure
65  *
66  * This is mainly a convinience function. It constructs an ASCII representation
67  * from all of the message's envelope headers and stores the result in headers.
68  * Memory is allocated dynamically, and the total length of the result is
69  * stored in length. This function takes care that the output is MIME conform,
70  * and folds long lines according to the MIME standard at position 78 of the
71  * string. It also nicely formats all MIME related header fields, such as
72  * the Content-Type header.
73  *
74  * Since the memory needed to store the result is allocated dynamically, one
75  * should take care of freeing it again when it's not needed anymore. If an
76  * error occurs, *result will be set to NULL, *length will be set to zero
77  * and mm_errno will be set to a reasonable value.
78  *
79  */
80 int
81 mm_envelope_getheaders(MM_CTX *ctx, char **result, size_t *length)
82 {
83         struct mm_mimepart *part;
84         struct mm_mimeheader *hdr;
85         char *buf, *hdrbuf;
86         size_t headers_length, tmp_length;
87
88         headers_length = 1;
89         buf = NULL;
90
91         part = mm_context_getpart(ctx, 0);
92         if (part == NULL) {
93                 return -1;
94         }       
95
96         /* Initialize our buffer */
97         if ((buf = (char *)xmalloc(headers_length)) == NULL) {
98                 mm_errno = MM_ERROR_ERRNO;
99                 goto cleanup;
100         }       
101         *buf = '\0';
102
103         /* Store each envelope header */
104         TAILQ_FOREACH(hdr, &part->headers, next) {
105                 tmp_length = strlen(hdr->name) + strlen(hdr->value) 
106                     + strlen(": \r\n");
107                 hdrbuf = (char *) xrealloc(buf, headers_length + tmp_length);
108                 if (hdrbuf == NULL) {
109                         mm_errno = MM_ERROR_ERRNO;
110                         goto cleanup;
111                 }
112
113                 headers_length += tmp_length;
114                 buf = hdrbuf;
115
116                 strlcat(buf, hdr->name, headers_length);
117                 strlcat(buf, ": ", headers_length);
118                 strlcat(buf, hdr->value, headers_length);
119                 strlcat(buf, "\r\n", headers_length);
120         }
121
122         /* Construct and store MIME headers */
123         if (part->type != NULL) {
124                 char *typebuf;
125                 typebuf = mm_content_tostring(part->type);
126                 if (typebuf == NULL) {
127                         goto cleanup;
128                 }
129                 tmp_length = strlen(typebuf) + strlen("\r\n");
130
131                 hdrbuf = (char *) xrealloc(buf, headers_length + tmp_length);
132                 if (hdrbuf == NULL) {
133                         mm_errno = MM_ERROR_ERRNO;
134                         goto cleanup;
135                 }
136
137                 headers_length += tmp_length;
138                 buf = hdrbuf;
139                 
140                 strlcat(buf, typebuf, headers_length);
141                 strlcat(buf, "\r\n", headers_length);
142         }
143
144         *result = buf;
145         *length = headers_length;
146
147         return 0;
148
149 cleanup:
150         if (buf != NULL) {
151                 xfree(buf);
152                 buf = NULL;
153         }
154         *result = NULL;
155         *length = 0;
156         return -1;
157 }
158
159 /**
160  * Sets a header field in the envelope
161  *
162  * @param ctx A valid MiniMIME context
163  * @param name The name of the header field to set
164  * @param fmt A format string specifying the value of the header field
165  * @return 0 on success or -1 on failure
166  *
167  * This function generates a new MIME header and attaches it to the first
168  * MIME part (the envelope) found in the given context. If no part is
169  * attached already, the function will return an error. The function will
170  * store a copy of ``name'' as the header's name field, and dynamically
171  * allocate the memory needed to build the format string.
172  */
173 int
174 mm_envelope_setheader(MM_CTX *ctx, const char *name, const char *fmt, ...)
175 {
176         va_list ap;
177         char *buf;
178         struct mm_mimeheader *hdr;
179         struct mm_mimepart *part;
180
181         part = mm_context_getpart(ctx, 0);
182         if (part == NULL) {
183                 return(-1);
184         }       
185
186         hdr = mm_mimeheader_new();
187         if (hdr == NULL) {
188                 return(-1);
189         }
190
191         hdr->name = xstrdup(name);
192
193         va_start(ap, fmt);
194         if (vasprintf(&buf, fmt, ap) == -1) {
195                 goto cleanup;
196         }       
197         va_end(ap);
198
199         hdr->value = buf;
200
201         if (mm_mimepart_attachheader(part, hdr) == -1) {
202                 goto cleanup;
203         }       
204
205         return(0);
206
207 cleanup:
208         if (hdr != NULL) {
209                 if (hdr->name != NULL) {
210                         xfree(hdr->name);
211                         hdr->name = NULL;
212                 }
213                 if (hdr->value != NULL) {
214                         xfree(hdr->value);
215                         hdr->value = NULL;
216                 }
217         }       
218         return(-1);
219 }
220
221 /**
222  * Gets the list of recipients for a MIME message
223  *
224  * @param ctx A valid MiniMIME context
225  * @param result Where to store the result
226  * @param length Where to store the length of the result
227  * @returns 0 on success or -1 on error
228  * @note Sets mm_errno on error
229  *
230  * This functions gets the list of recipients for a given MIME message. It
231  * does so by concatenating the "From" and "Cc" header fields, and storing
232  * the results in recipients. The memory needed to store the result is
233  * allocated dynamically, and the total length of the result is stored in
234  * length.
235  *
236  * One should take care to free() the result once it's not needed anymore.
237  */
238 int
239 mm_envelope_getrecipients(MM_CTX *ctx, char **result, size_t *length)
240 {
241         struct mm_mimepart *part;
242         struct mm_mimeheader *to, *cc;
243         size_t recipients_length;
244
245         part = mm_context_getpart(ctx, 0);
246         if (part == NULL) {
247                 return -1;
248         }
249
250         to = mm_mimepart_getheaderbyname(part, "From", 0);
251         cc = mm_mimepart_getheaderbyname(part, "Cc", 0);
252
253         if (to == NULL || cc == NULL) {
254                 *result = NULL;
255                 *length = 0;
256                 return -1;
257         }
258
259         if (to != NULL) {
260                 recipients_length += strlen(to->value);
261         }       
262         if (cc != NULL) {
263                 recipients_length += strlen(cc->value);
264         }       
265         
266         return 0;
267 }
268
269 /** @} */