Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-part.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  GMime
3  *  Copyright (C) 2000-2012 Jeffrey Stedfast
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public License
7  *  as published by the Free Software Foundation; either version 2.1
8  *  of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free
17  *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
18  *  02110-1301, USA.
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <string.h>
29
30 #include "gmime-part.h"
31 #include "gmime-utils.h"
32 #include "gmime-common.h"
33 #include "gmime-stream-mem.h"
34 #include "gmime-stream-null.h"
35 #include "gmime-stream-filter.h"
36 #include "gmime-filter-basic.h"
37 #include "gmime-filter-best.h"
38 #include "gmime-filter-crlf.h"
39 #include "gmime-filter-md5.h"
40 #include "gmime-table-private.h"
41
42 #define d(x)
43
44
45 /**
46  * SECTION: gmime-part
47  * @title: GMimePart
48  * @short_description: MIME parts
49  * @see_also:
50  *
51  * A #GMimePart represents any MIME leaf part (meaning it has no
52  * sub-parts).
53  **/
54
55 /* GObject class methods */
56 static void g_mime_part_class_init (GMimePartClass *klass);
57 static void g_mime_part_init (GMimePart *mime_part, GMimePartClass *klass);
58 static void g_mime_part_finalize (GObject *object);
59
60 /* GMimeObject class methods */
61 static void mime_part_prepend_header (GMimeObject *object, const char *header, const char *value);
62 static void mime_part_append_header (GMimeObject *object, const char *header, const char *value);
63 static void mime_part_set_header (GMimeObject *object, const char *header, const char *value);
64 static gboolean mime_part_remove_header (GMimeObject *object, const char *header);
65 static ssize_t mime_part_write_to_stream (GMimeObject *object, GMimeStream *stream);
66 static void mime_part_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
67
68 /* GMimePart class methods */
69 static void set_content_object (GMimePart *mime_part, GMimeDataWrapper *content);
70
71
72 static GMimeObjectClass *parent_class = NULL;
73
74
75 GType
76 g_mime_part_get_type (void)
77 {
78         static GType type = 0;
79         
80         if (!type) {
81                 static const GTypeInfo info = {
82                         sizeof (GMimePartClass),
83                         NULL, /* base_class_init */
84                         NULL, /* base_class_finalize */
85                         (GClassInitFunc) g_mime_part_class_init,
86                         NULL, /* class_finalize */
87                         NULL, /* class_data */
88                         sizeof (GMimePart),
89                         0,    /* n_preallocs */
90                         (GInstanceInitFunc) g_mime_part_init,
91                 };
92                 
93                 type = g_type_register_static (GMIME_TYPE_OBJECT, "GMimePart", &info, 0);
94         }
95         
96         return type;
97 }
98
99
100 static void
101 g_mime_part_class_init (GMimePartClass *klass)
102 {
103         GMimeObjectClass *object_class = GMIME_OBJECT_CLASS (klass);
104         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
105         
106         parent_class = g_type_class_ref (GMIME_TYPE_OBJECT);
107         
108         gobject_class->finalize = g_mime_part_finalize;
109         
110         object_class->prepend_header = mime_part_prepend_header;
111         object_class->append_header = mime_part_append_header;
112         object_class->remove_header = mime_part_remove_header;
113         object_class->set_header = mime_part_set_header;
114         object_class->write_to_stream = mime_part_write_to_stream;
115         object_class->encode = mime_part_encode;
116         
117         klass->set_content_object = set_content_object;
118 }
119
120 static void
121 g_mime_part_init (GMimePart *mime_part, GMimePartClass *klass)
122 {
123         mime_part->encoding = GMIME_CONTENT_ENCODING_DEFAULT;
124         mime_part->content_description = NULL;
125         mime_part->content_location = NULL;
126         mime_part->content_md5 = NULL;
127         mime_part->content = NULL;
128 }
129
130 static void
131 g_mime_part_finalize (GObject *object)
132 {
133         GMimePart *mime_part = (GMimePart *) object;
134         
135         g_free (mime_part->content_description);
136         g_free (mime_part->content_location);
137         g_free (mime_part->content_md5);
138         
139         if (mime_part->content)
140                 g_object_unref (mime_part->content);
141         
142         G_OBJECT_CLASS (parent_class)->finalize (object);
143 }
144
145
146 enum {
147         HEADER_CONTENT_TRANSFER_ENCODING,
148         HEADER_CONTENT_DESCRIPTION,
149         HEADER_CONTENT_LOCATION,
150         HEADER_CONTENT_MD5,
151         HEADER_UNKNOWN
152 };
153
154 static const char *content_headers[] = {
155         "Content-Transfer-Encoding",
156         "Content-Description",
157         "Content-Location",
158         "Content-Md5",
159 };
160
161
162 static void
163 copy_atom (const char *src, char *dest, size_t n)
164 {
165         register const char *inptr = src;
166         register char *outptr = dest;
167         char *outend = dest + n;
168         
169         while (is_lwsp (*inptr))
170                 inptr++;
171         
172         while (is_atom (*inptr) && outptr < outend)
173                 *outptr++ = *inptr++;
174         
175         *outptr = '\0';
176 }
177
178 static gboolean
179 process_header (GMimeObject *object, const char *header, const char *value)
180 {
181         GMimePart *mime_part = (GMimePart *) object;
182         char encoding[32];
183         guint i;
184         
185         if (g_ascii_strncasecmp (header, "Content-", 8) != 0)
186                 return FALSE;
187         
188         for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
189                 if (!g_ascii_strcasecmp (content_headers[i] + 8, header + 8))
190                         break;
191         }
192         
193         switch (i) {
194         case HEADER_CONTENT_TRANSFER_ENCODING:
195                 copy_atom (value, encoding, sizeof (encoding) - 1);
196                 mime_part->encoding = g_mime_content_encoding_from_string (encoding);
197                 break;
198         case HEADER_CONTENT_DESCRIPTION:
199                 /* FIXME: we should decode this */
200                 g_free (mime_part->content_description);
201                 mime_part->content_description = g_mime_strdup_trim (value);
202                 break;
203         case HEADER_CONTENT_LOCATION:
204                 g_free (mime_part->content_location);
205                 mime_part->content_location = g_mime_strdup_trim (value);
206                 break;
207         case HEADER_CONTENT_MD5:
208                 g_free (mime_part->content_md5);
209                 mime_part->content_md5 = g_mime_strdup_trim (value);
210                 break;
211         default:
212                 return FALSE;
213         }
214         
215         return TRUE;
216 }
217
218 static void
219 mime_part_prepend_header (GMimeObject *object, const char *header, const char *value)
220 {
221         if (!process_header (object, header, value))
222                 GMIME_OBJECT_CLASS (parent_class)->prepend_header (object, header, value);
223         else
224                 g_mime_header_list_prepend (object->headers, header, value);
225 }
226
227 static void
228 mime_part_append_header (GMimeObject *object, const char *header, const char *value)
229 {
230         if (!process_header (object, header, value))
231                 GMIME_OBJECT_CLASS (parent_class)->append_header (object, header, value);
232         else
233                 g_mime_header_list_append (object->headers, header, value);
234 }
235
236 static void
237 mime_part_set_header (GMimeObject *object, const char *header, const char *value)
238 {
239         if (!process_header (object, header, value))
240                 GMIME_OBJECT_CLASS (parent_class)->set_header (object, header, value);
241         else
242                 g_mime_header_list_set (object->headers, header, value);
243 }
244
245 static gboolean
246 mime_part_remove_header (GMimeObject *object, const char *header)
247 {
248         GMimePart *mime_part = (GMimePart *) object;
249         guint i;
250         
251         if (!g_ascii_strncasecmp (header, "Content-", 8)) {
252                 for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
253                         if (!g_ascii_strcasecmp (content_headers[i] + 8, header + 8))
254                                 break;
255                 }
256                 
257                 switch (i) {
258                 case HEADER_CONTENT_TRANSFER_ENCODING:
259                         mime_part->encoding = GMIME_CONTENT_ENCODING_DEFAULT;
260                         break;
261                 case HEADER_CONTENT_DESCRIPTION:
262                         g_free (mime_part->content_description);
263                         mime_part->content_description = NULL;
264                         break;
265                 case HEADER_CONTENT_LOCATION:
266                         g_free (mime_part->content_location);
267                         mime_part->content_location = NULL;
268                         break;
269                 case HEADER_CONTENT_MD5:
270                         g_free (mime_part->content_md5);
271                         mime_part->content_md5 = NULL;
272                         break;
273                 default:
274                         break;
275                 }
276         }
277         
278         return GMIME_OBJECT_CLASS (parent_class)->remove_header (object, header);
279 }
280
281 static ssize_t
282 write_content (GMimePart *part, GMimeStream *stream)
283 {
284         ssize_t nwritten, total = 0;
285         
286         if (!part->content)
287                 return 0;
288         
289         /* Evil Genius's "slight" optimization: Since GMimeDataWrapper::write_to_stream()
290          * decodes its content stream to the raw format, we can cheat by requesting its
291          * content stream and not doing any encoding on the data if the source and
292          * destination encodings are identical.
293          */
294         
295         if (part->encoding != g_mime_data_wrapper_get_encoding (part->content)) {
296                 GMimeStream *filtered_stream;
297                 const char *filename;
298                 GMimeFilter *filter;
299                 
300                 switch (part->encoding) {
301                 case GMIME_CONTENT_ENCODING_UUENCODE:
302                         filename = g_mime_part_get_filename (part);
303                         nwritten = g_mime_stream_printf (stream, "begin 0644 %s\n",
304                                                          filename ? filename : "unknown");
305                         if (nwritten == -1)
306                                 return -1;
307                         
308                         total += nwritten;
309                         
310                         /* fall thru... */
311                 case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
312                 case GMIME_CONTENT_ENCODING_BASE64:
313                         filtered_stream = g_mime_stream_filter_new (stream);
314                         filter = g_mime_filter_basic_new (part->encoding, TRUE);
315                         g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter);
316                         g_object_unref (filter);
317                         break;
318                 default:
319                         filtered_stream = stream;
320                         g_object_ref (stream);
321                         break;
322                 }
323                 
324                 nwritten = g_mime_data_wrapper_write_to_stream (part->content, filtered_stream);
325                 g_mime_stream_flush (filtered_stream);
326                 g_object_unref (filtered_stream);
327                 
328                 if (nwritten == -1)
329                         return -1;
330                 
331                 total += nwritten;
332                 
333                 if (part->encoding == GMIME_CONTENT_ENCODING_UUENCODE) {
334                         /* FIXME: get rid of this special-case x-uuencode crap */
335                         nwritten = g_mime_stream_write (stream, "end\n", 4);
336                         if (nwritten == -1)
337                                 return -1;
338                         
339                         total += nwritten;
340                 }
341         } else {
342                 GMimeStream *content_stream;
343                 
344                 content_stream = g_mime_data_wrapper_get_stream (part->content);
345                 g_mime_stream_reset (content_stream);
346                 nwritten = g_mime_stream_write_to_stream (content_stream, stream);
347                 
348                 if (nwritten == -1)
349                         return -1;
350                 
351                 total += nwritten;
352         }
353         
354         return total;
355 }
356
357 static ssize_t
358 mime_part_write_to_stream (GMimeObject *object, GMimeStream *stream)
359 {
360         GMimePart *mime_part = (GMimePart *) object;
361         ssize_t nwritten, total = 0;
362         
363         /* write the content headers */
364         if ((nwritten = g_mime_header_list_write_to_stream (object->headers, stream)) == -1)
365                 return -1;
366         
367         total += nwritten;
368         
369         /* terminate the headers */
370         if (g_mime_stream_write (stream, "\n", 1) == -1)
371                 return -1;
372         
373         total++;
374         
375         if ((nwritten = write_content (mime_part, stream)) == -1)
376                 return -1;
377         
378         total += nwritten;
379         
380         return total;
381 }
382
383 static void
384 mime_part_encode (GMimeObject *object, GMimeEncodingConstraint constraint)
385 {
386         GMimePart *part = (GMimePart *) object;
387         GMimeContentEncoding encoding;
388         GMimeStream *stream, *null;
389         GMimeFilter *filter;
390         
391         switch (part->encoding) {
392         case GMIME_CONTENT_ENCODING_DEFAULT:
393                 /* Unspecified encoding, we need to figure out the
394                  * best encoding no matter what */
395                 break;
396         case GMIME_CONTENT_ENCODING_7BIT:
397                 /* This encoding is always safe. */
398                 return;
399         case GMIME_CONTENT_ENCODING_8BIT:
400                 /* This encoding is safe unless the constraint is 7bit. */
401                 if (constraint != GMIME_ENCODING_CONSTRAINT_7BIT)
402                         return;
403                 break;
404         case GMIME_CONTENT_ENCODING_BINARY:
405                 /* This encoding is only safe if the constraint is binary. */
406                 if (constraint == GMIME_ENCODING_CONSTRAINT_BINARY)
407                         return;
408                 break;
409         case GMIME_CONTENT_ENCODING_BASE64:
410         case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
411         case GMIME_CONTENT_ENCODING_UUENCODE:
412                 /* These encodings are always safe. */
413                 return;
414         }
415         
416         filter = g_mime_filter_best_new (GMIME_FILTER_BEST_ENCODING);
417         
418         null = g_mime_stream_null_new ();
419         stream = g_mime_stream_filter_new (null);
420         g_mime_stream_filter_add ((GMimeStreamFilter *) stream, filter);
421         g_object_unref (null);
422         
423         g_mime_object_write_to_stream (object, stream);
424         g_object_unref (stream);
425         
426         encoding = g_mime_filter_best_encoding ((GMimeFilterBest *) filter, constraint);
427         g_mime_part_set_content_encoding (part, encoding);
428         g_object_unref (filter);
429 }
430
431
432 /**
433  * g_mime_part_new:
434  *
435  * Creates a new MIME Part object with a default content-type of
436  * text/plain.
437  *
438  * Returns: an empty MIME Part object with a default content-type of
439  * text/plain.
440  **/
441 GMimePart *
442 g_mime_part_new (void)
443 {
444         GMimeContentType *content_type;
445         GMimePart *mime_part;
446         
447         mime_part = g_object_newv (GMIME_TYPE_PART, 0, NULL);
448         
449         content_type = g_mime_content_type_new ("text", "plain");
450         g_mime_object_set_content_type (GMIME_OBJECT (mime_part), content_type);
451         g_object_unref (content_type);
452         
453         return mime_part;
454 }
455
456
457 /**
458  * g_mime_part_new_with_type:
459  * @type: content-type string
460  * @subtype: content-subtype string
461  *
462  * Creates a new MIME Part with a sepcified type.
463  *
464  * Returns: an empty MIME Part object with the specified content-type.
465  **/
466 GMimePart *
467 g_mime_part_new_with_type (const char *type, const char *subtype)
468 {
469         GMimeContentType *content_type;
470         GMimePart *mime_part;
471         
472         mime_part = g_object_newv (GMIME_TYPE_PART, 0, NULL);
473         
474         content_type = g_mime_content_type_new (type, subtype);
475         g_mime_object_set_content_type (GMIME_OBJECT (mime_part), content_type);
476         g_object_unref (content_type);
477         
478         return mime_part;
479 }
480
481
482 /**
483  * g_mime_part_set_content_description:
484  * @mime_part: a #GMimePart object
485  * @description: content description
486  *
487  * Set the content description for the specified mime part.
488  **/
489 void
490 g_mime_part_set_content_description (GMimePart *mime_part, const char *description)
491 {
492         g_return_if_fail (GMIME_IS_PART (mime_part));
493         
494         if (mime_part->content_description == description)
495                 return;
496         
497         g_free (mime_part->content_description);
498         mime_part->content_description = g_strdup (description);
499         g_mime_header_list_set (GMIME_OBJECT (mime_part)->headers, "Content-Description", description);
500 }
501
502
503 /**
504  * g_mime_part_get_content_description:
505  * @mime_part: a #GMimePart object
506  *
507  * Gets the value of the Content-Description for the specified mime
508  * part if it exists or %NULL otherwise.
509  *
510  * Returns: the content description for the specified mime part.
511  **/
512 const char *
513 g_mime_part_get_content_description (GMimePart *mime_part)
514 {
515         g_return_val_if_fail (GMIME_IS_PART (mime_part), NULL);
516         
517         return mime_part->content_description;
518 }
519
520
521 /**
522  * g_mime_part_set_content_id:
523  * @mime_part: a #GMimePart object
524  * @content_id: content id
525  *
526  * Set the content id for the specified mime part.
527  **/
528 void
529 g_mime_part_set_content_id (GMimePart *mime_part, const char *content_id)
530 {
531         g_return_if_fail (GMIME_IS_PART (mime_part));
532         
533         g_mime_object_set_content_id (GMIME_OBJECT (mime_part), content_id);
534 }
535
536
537 /**
538  * g_mime_part_get_content_id:
539  * @mime_part: a #GMimePart object
540  *
541  * Gets the content-id of the specified mime part if it exists, or
542  * %NULL otherwise.
543  *
544  * Returns: the content id for the specified mime part.
545  **/
546 const char *
547 g_mime_part_get_content_id (GMimePart *mime_part)
548 {
549         g_return_val_if_fail (GMIME_IS_PART (mime_part), NULL);
550         
551         return g_mime_object_get_content_id (GMIME_OBJECT (mime_part));
552 }
553
554
555 /**
556  * g_mime_part_set_content_md5:
557  * @mime_part: a #GMimePart object
558  * @content_md5: content md5 or %NULL to generate the md5 digest.
559  *
560  * Set the content md5 for the specified mime part.
561  **/
562 void
563 g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5)
564 {
565         unsigned char digest[16], b64digest[32];
566         GMimeStreamFilter *filtered_stream;
567         GMimeContentType *content_type;
568         GMimeFilter *md5_filter;
569         GMimeStream *stream;
570         guint32 save = 0;
571         int state = 0;
572         size_t len;
573         
574         g_return_if_fail (GMIME_IS_PART (mime_part));
575         
576         g_free (mime_part->content_md5);
577         
578         if (!content_md5) {
579                 /* compute a md5sum */
580                 stream = g_mime_stream_null_new ();
581                 filtered_stream = (GMimeStreamFilter *) g_mime_stream_filter_new (stream);
582                 g_object_unref (stream);
583                 
584                 content_type = g_mime_object_get_content_type ((GMimeObject *) mime_part);
585                 if (g_mime_content_type_is_type (content_type, "text", "*")) {
586                         GMimeFilter *crlf_filter;
587                         
588                         crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE);
589                         g_mime_stream_filter_add (filtered_stream, crlf_filter);
590                         g_object_unref (crlf_filter);
591                 }
592                 
593                 md5_filter = g_mime_filter_md5_new ();
594                 g_mime_stream_filter_add (filtered_stream, md5_filter);
595                 
596                 stream = (GMimeStream *) filtered_stream;
597                 g_mime_data_wrapper_write_to_stream (mime_part->content, stream);
598                 g_object_unref (stream);
599                 
600                 memset (digest, 0, 16);
601                 g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) md5_filter, digest);
602                 g_object_unref (md5_filter);
603                 
604                 len = g_mime_encoding_base64_encode_close (digest, 16, b64digest, &state, &save);
605                 b64digest[len] = '\0';
606                 g_strstrip ((char *) b64digest);
607                 
608                 content_md5 = (const char *) b64digest;
609         }
610         
611         mime_part->content_md5 = g_strdup (content_md5);
612         g_mime_header_list_set (GMIME_OBJECT (mime_part)->headers, "Content-Md5", content_md5);
613 }
614
615
616 /**
617  * g_mime_part_verify_content_md5:
618  * @mime_part: a #GMimePart object
619  *
620  * Verify the content md5 for the specified mime part.
621  *
622  * Returns: %TRUE if the md5 is valid or %FALSE otherwise. Note: will
623  * return %FALSE if the mime part does not contain a Content-MD5.
624  **/
625 gboolean
626 g_mime_part_verify_content_md5 (GMimePart *mime_part)
627 {
628         unsigned char digest[16], b64digest[32];
629         GMimeStreamFilter *filtered_stream;
630         GMimeContentType *content_type;
631         GMimeFilter *md5_filter;
632         GMimeStream *stream;
633         guint32 save = 0;
634         int state = 0;
635         size_t len;
636         
637         g_return_val_if_fail (GMIME_IS_PART (mime_part), FALSE);
638         g_return_val_if_fail (mime_part->content != NULL, FALSE);
639         
640         if (!mime_part->content_md5)
641                 return FALSE;
642         
643         stream = g_mime_stream_null_new ();
644         filtered_stream = (GMimeStreamFilter *) g_mime_stream_filter_new (stream);
645         g_object_unref (stream);
646         
647         content_type = g_mime_object_get_content_type ((GMimeObject *) mime_part);
648         if (g_mime_content_type_is_type (content_type, "text", "*")) {
649                 GMimeFilter *crlf_filter;
650                 
651                 crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE);
652                 g_mime_stream_filter_add (filtered_stream, crlf_filter);
653                 g_object_unref (crlf_filter);
654         }
655         
656         md5_filter = g_mime_filter_md5_new ();
657         g_mime_stream_filter_add (filtered_stream, md5_filter);
658         
659         stream = (GMimeStream *) filtered_stream;
660         g_mime_data_wrapper_write_to_stream (mime_part->content, stream);
661         g_object_unref (stream);
662         
663         memset (digest, 0, 16);
664         g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) md5_filter, digest);
665         g_object_unref (md5_filter);
666         
667         len = g_mime_encoding_base64_encode_close (digest, 16, b64digest, &state, &save);
668         b64digest[len] = '\0';
669         g_strstrip ((char *) b64digest);
670         
671         return !strcmp ((char *) b64digest, mime_part->content_md5);
672 }
673
674
675 /**
676  * g_mime_part_get_content_md5:
677  * @mime_part: a #GMimePart object
678  *
679  * Gets the md5sum contained in the Content-Md5 header of the
680  * specified mime part if it exists, or %NULL otherwise.
681  *
682  * Returns: the content md5 for the specified mime part.
683  **/
684 const char *
685 g_mime_part_get_content_md5 (GMimePart *mime_part)
686 {
687         g_return_val_if_fail (GMIME_IS_PART (mime_part), NULL);
688         
689         return mime_part->content_md5;
690 }
691
692
693 /**
694  * g_mime_part_set_content_location:
695  * @mime_part: a #GMimePart object
696  * @content_location: content location
697  *
698  * Set the content location for the specified mime part.
699  **/
700 void
701 g_mime_part_set_content_location (GMimePart *mime_part, const char *content_location)
702 {
703         g_return_if_fail (GMIME_IS_PART (mime_part));
704         
705         if (mime_part->content_location == content_location)
706                 return;
707         
708         g_free (mime_part->content_location);
709         mime_part->content_location = g_strdup (content_location);
710         g_mime_header_list_set (GMIME_OBJECT (mime_part)->headers, "Content-Location", content_location);
711 }
712
713
714 /**
715  * g_mime_part_get_content_location:
716  * @mime_part: a #GMimePart object
717  *
718  * Gets the value of the Content-Location header if it exists, or
719  * %NULL otherwise.
720  *
721  * Returns: the content location for the specified mime part.
722  **/
723 const char *
724 g_mime_part_get_content_location (GMimePart *mime_part)
725 {
726         g_return_val_if_fail (GMIME_IS_PART (mime_part), NULL);
727         
728         return mime_part->content_location;
729 }
730
731
732 /**
733  * g_mime_part_set_content_encoding:
734  * @mime_part: a #GMimePart object
735  * @encoding: a #GMimeContentEncoding
736  *
737  * Set the content encoding for the specified mime part.
738  **/
739 void
740 g_mime_part_set_content_encoding (GMimePart *mime_part, GMimeContentEncoding encoding)
741 {
742         g_return_if_fail (GMIME_IS_PART (mime_part));
743         
744         mime_part->encoding = encoding;
745         g_mime_header_list_set (GMIME_OBJECT (mime_part)->headers, "Content-Transfer-Encoding",
746                                 g_mime_content_encoding_to_string (encoding));
747 }
748
749
750 /**
751  * g_mime_part_get_content_encoding:
752  * @mime_part: a #GMimePart object
753  *
754  * Gets the content encoding of the mime part.
755  *
756  * Returns: the content encoding for the specified mime part.
757  **/
758 GMimeContentEncoding
759 g_mime_part_get_content_encoding (GMimePart *mime_part)
760 {
761         g_return_val_if_fail (GMIME_IS_PART (mime_part), GMIME_CONTENT_ENCODING_DEFAULT);
762         
763         return mime_part->encoding;
764 }
765
766
767 /**
768  * g_mime_part_get_best_content_encoding:
769  * @mime_part: a #GMimePart object
770  * @constraint: a #GMimeEncodingConstraint
771  *
772  * Calculates the most efficient content encoding for the @mime_part
773  * given the @constraint.
774  *
775  * Returns: the best content encoding for the specified mime part.
776  **/
777 GMimeContentEncoding
778 g_mime_part_get_best_content_encoding (GMimePart *mime_part, GMimeEncodingConstraint constraint)
779 {
780         GMimeStream *filtered, *stream;
781         GMimeContentEncoding encoding;
782         GMimeFilterBest *best;
783         GMimeFilter *filter;
784         
785         g_return_val_if_fail (GMIME_IS_PART (mime_part), GMIME_CONTENT_ENCODING_DEFAULT);
786         
787         stream = g_mime_stream_null_new ();
788         filtered = g_mime_stream_filter_new (stream);
789         g_object_unref (stream);
790         
791         filter = g_mime_filter_best_new (GMIME_FILTER_BEST_ENCODING);
792         g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
793         best = (GMimeFilterBest *) filter;
794         
795         g_mime_data_wrapper_write_to_stream (mime_part->content, filtered);
796         g_mime_stream_flush (filtered);
797         g_object_unref (filtered);
798         
799         encoding = g_mime_filter_best_encoding (best, constraint);
800         g_object_unref (best);
801         
802         return encoding;
803 }
804
805
806 /**
807  * g_mime_part_set_filename:
808  * @mime_part: a #GMimePart object
809  * @filename: the filename of the Mime Part's content
810  *
811  * Sets the "filename" parameter on the Content-Disposition and also sets the
812  * "name" parameter on the Content-Type.
813  **/
814 void
815 g_mime_part_set_filename (GMimePart *mime_part, const char *filename)
816 {
817         GMimeObject *object = (GMimeObject *) mime_part;
818         
819         g_return_if_fail (GMIME_IS_PART (mime_part));
820         
821         g_mime_object_set_content_disposition_parameter (object, "filename", filename);
822         g_mime_object_set_content_type_parameter (object, "name", filename);
823 }
824
825
826 /**
827  * g_mime_part_get_filename:
828  * @mime_part: a #GMimePart object
829  *
830  * Gets the filename of the specificed mime part, or %NULL if the mime
831  * part does not have the filename or name parameter set.
832  *
833  * Returns: the filename of the specified MIME Part. It first checks to
834  * see if the "filename" parameter was set on the Content-Disposition
835  * and if not then checks the "name" parameter in the Content-Type.
836  **/
837 const char *
838 g_mime_part_get_filename (GMimePart *mime_part)
839 {
840         GMimeObject *object = (GMimeObject *) mime_part;
841         const char *filename = NULL;
842         
843         g_return_val_if_fail (GMIME_IS_PART (mime_part), NULL);
844         
845         if ((filename = g_mime_object_get_content_disposition_parameter (object, "filename")))
846                 return filename;
847         
848         /* check the "name" param in the content-type */
849         return g_mime_object_get_content_type_parameter (object, "name");
850 }
851
852
853 static void
854 set_content_object (GMimePart *mime_part, GMimeDataWrapper *content)
855 {
856         if (mime_part->content)
857                 g_object_unref (mime_part->content);
858         
859         mime_part->content = content;
860         g_object_ref (content);
861 }
862
863
864 /**
865  * g_mime_part_set_content_object:
866  * @mime_part: a #GMimePart object
867  * @content: a #GMimeDataWrapper content object
868  *
869  * Sets the content object on the mime part.
870  **/
871 void
872 g_mime_part_set_content_object (GMimePart *mime_part, GMimeDataWrapper *content)
873 {
874         g_return_if_fail (GMIME_IS_PART (mime_part));
875         
876         if (mime_part->content == content)
877                 return;
878         
879         GMIME_PART_GET_CLASS (mime_part)->set_content_object (mime_part, content);
880 }
881
882
883 /**
884  * g_mime_part_get_content_object:
885  * @mime_part: a #GMimePart object
886  *
887  * Gets the internal data-wrapper of the specified mime part, or %NULL
888  * on error.
889  *
890  * Returns: the data-wrapper for the mime part's contents.
891  **/
892 GMimeDataWrapper *
893 g_mime_part_get_content_object (GMimePart *mime_part)
894 {
895         g_return_val_if_fail (GMIME_IS_PART (mime_part), NULL);
896         
897         return mime_part->content;
898 }