Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-object.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 <ctype.h>
27 #include <string.h>
28
29 #include "gmime-common.h"
30 #include "gmime-object.h"
31 #include "gmime-stream-mem.h"
32 #include "gmime-events.h"
33 #include "gmime-utils.h"
34
35
36 /**
37  * SECTION: gmime-object
38  * @title: GMimeObject
39  * @short_description: Abstract MIME objects
40  * @see_also:
41  *
42  * #GMimeObject is an abstract class from which all message and MIME
43  * parts are derived.
44  **/
45
46
47 struct _type_bucket {
48         char *type;
49         GType object_type;
50         GHashTable *subtype_hash;
51 };
52
53 struct _subtype_bucket {
54         char *subtype;
55         GType object_type;
56 };
57
58 static void _g_mime_object_set_content_disposition (GMimeObject *object, GMimeContentDisposition *disposition);
59 void _g_mime_object_set_content_type (GMimeObject *object, GMimeContentType *content_type);
60
61 static void g_mime_object_class_init (GMimeObjectClass *klass);
62 static void g_mime_object_init (GMimeObject *object, GMimeObjectClass *klass);
63 static void g_mime_object_finalize (GObject *object);
64
65 static void object_prepend_header (GMimeObject *object, const char *name, const char *value);
66 static void object_append_header (GMimeObject *object, const char *name, const char *value);
67 static void object_set_header (GMimeObject *object, const char *name, const char *value);
68 static const char *object_get_header (GMimeObject *object, const char *name);
69 static gboolean object_remove_header (GMimeObject *object, const char *name);
70 static void object_set_content_type (GMimeObject *object, GMimeContentType *content_type);
71 static char *object_get_headers (GMimeObject *object);
72 static ssize_t object_write_to_stream (GMimeObject *object, GMimeStream *stream);
73 static void object_encode (GMimeObject *object, GMimeEncodingConstraint constraint);
74
75 static ssize_t write_content_type (GMimeStream *stream, const char *name, const char *value);
76 static ssize_t write_disposition (GMimeStream *stream, const char *name, const char *value);
77
78 static void content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject *object);
79 static void content_disposition_changed (GMimeContentDisposition *disposition, gpointer args, GMimeObject *object);
80
81
82 static GHashTable *type_hash = NULL;
83
84 static GObjectClass *parent_class = NULL;
85
86
87 GType
88 g_mime_object_get_type (void)
89 {
90         static GType type = 0;
91         
92         if (!type) {
93                 static const GTypeInfo info = {
94                         sizeof (GMimeObjectClass),
95                         NULL, /* base_class_init */
96                         NULL, /* base_class_finalize */
97                         (GClassInitFunc) g_mime_object_class_init,
98                         NULL, /* class_finalize */
99                         NULL, /* class_data */
100                         sizeof (GMimeObject),
101                         0,    /* n_preallocs */
102                         (GInstanceInitFunc) g_mime_object_init,
103                 };
104                 
105                 type = g_type_register_static (G_TYPE_OBJECT, "GMimeObject",
106                                                &info, G_TYPE_FLAG_ABSTRACT);
107         }
108         
109         return type;
110 }
111
112
113 static void
114 g_mime_object_class_init (GMimeObjectClass *klass)
115 {
116         GObjectClass *object_class = G_OBJECT_CLASS (klass);
117         
118         parent_class = g_type_class_ref (G_TYPE_OBJECT);
119         
120         object_class->finalize = g_mime_object_finalize;
121         
122         klass->prepend_header = object_prepend_header;
123         klass->append_header = object_append_header;
124         klass->remove_header = object_remove_header;
125         klass->set_header = object_set_header;
126         klass->get_header = object_get_header;
127         klass->set_content_type = object_set_content_type;
128         klass->get_headers = object_get_headers;
129         klass->write_to_stream = object_write_to_stream;
130         klass->encode = object_encode;
131 }
132
133 static void
134 g_mime_object_init (GMimeObject *object, GMimeObjectClass *klass)
135 {
136         object->headers = g_mime_header_list_new ();
137         object->content_type = NULL;
138         object->disposition = NULL;
139         object->content_id = NULL;
140         
141         g_mime_header_list_register_writer (object->headers, "Content-Type", write_content_type);
142         g_mime_header_list_register_writer (object->headers, "Content-Disposition", write_disposition);
143 }
144
145 static void
146 g_mime_object_finalize (GObject *object)
147 {
148         GMimeObject *mime = (GMimeObject *) object;
149         
150         if (mime->content_type) {
151                 g_mime_event_remove (mime->content_type->priv, (GMimeEventCallback) content_type_changed, object);
152                 g_object_unref (mime->content_type);
153         }
154         
155         if (mime->disposition) {
156                 g_mime_event_remove (mime->disposition->priv, (GMimeEventCallback) content_disposition_changed, object);
157                 g_object_unref (mime->disposition);
158         }
159         
160         if (mime->headers)
161                 g_mime_header_list_destroy (mime->headers);
162         
163         g_free (mime->content_id);
164         
165         G_OBJECT_CLASS (parent_class)->finalize (object);
166 }
167
168
169 static ssize_t
170 write_content_type (GMimeStream *stream, const char *name, const char *value)
171 {
172         GMimeContentType *content_type;
173         ssize_t nwritten;
174         GString *out;
175         char *val;
176         
177         out = g_string_new ("");
178         g_string_printf (out, "%s: ", name);
179         
180         content_type = g_mime_content_type_new_from_string (value);
181         
182         val = g_mime_content_type_to_string (content_type);
183         g_string_append (out, val);
184         g_free (val);
185         
186         g_mime_param_write_to_string (content_type->params, TRUE, out);
187         g_object_unref (content_type);
188         
189         nwritten = g_mime_stream_write (stream, out->str, out->len);
190         g_string_free (out, TRUE);
191         
192         return nwritten;
193 }
194
195 static void
196 content_type_changed (GMimeContentType *content_type, gpointer args, GMimeObject *object)
197 {
198         GMimeParam *params;
199         GString *string;
200         char *type, *p;
201         
202         string = g_string_new ("Content-Type: ");
203         
204         type = g_mime_content_type_to_string (content_type);
205         g_string_append (string, type);
206         g_free (type);
207         
208         if ((params = content_type->params))
209                 g_mime_param_write_to_string (params, FALSE, string);
210         
211         p = string->str;
212         g_string_free (string, FALSE);
213         
214         type = p + strlen ("Content-Type: ");
215         g_mime_header_list_set (object->headers, "Content-Type", type);
216         g_free (p);
217 }
218
219 static ssize_t
220 write_disposition (GMimeStream *stream, const char *name, const char *value)
221 {
222         GMimeContentDisposition *disposition;
223         ssize_t nwritten;
224         GString *out;
225         
226         out = g_string_new ("");
227         g_string_printf (out, "%s: ", name);
228         
229         disposition = g_mime_content_disposition_new_from_string (value);
230         g_string_append (out, disposition->disposition);
231         
232         g_mime_param_write_to_string (disposition->params, TRUE, out);
233         g_object_unref (disposition);
234         
235         nwritten = g_mime_stream_write (stream, out->str, out->len);
236         g_string_free (out, TRUE);
237         
238         return nwritten;
239 }
240
241 static void
242 content_disposition_changed (GMimeContentDisposition *disposition, gpointer args, GMimeObject *object)
243 {
244         char *str;
245         
246         if (object->disposition) {
247                 str = g_mime_content_disposition_to_string (object->disposition, FALSE);
248                 g_mime_header_list_set (object->headers, "Content-Disposition", str);
249                 g_free (str);
250         } else {
251                 g_mime_header_list_remove (object->headers, "Content-Disposition");
252         }
253 }
254
255
256 /**
257  * g_mime_object_register_type:
258  * @type: mime type
259  * @subtype: mime subtype
260  * @object_type: object type
261  *
262  * Registers the object type @object_type for use with the
263  * g_mime_object_new_type() convenience function.
264  *
265  * Note: You may use the wildcard "*" to match any type and/or
266  * subtype.
267  **/
268 void
269 g_mime_object_register_type (const char *type, const char *subtype, GType object_type)
270 {
271         struct _type_bucket *bucket;
272         struct _subtype_bucket *sub;
273         
274         g_return_if_fail (object_type != 0);
275         g_return_if_fail (subtype != NULL);
276         g_return_if_fail (type != NULL);
277         
278         if (!(bucket = g_hash_table_lookup (type_hash, type))) {
279                 bucket = g_new (struct _type_bucket, 1);
280                 bucket->type = g_strdup (type);
281                 bucket->object_type = *type == '*' ? object_type : 0;
282                 bucket->subtype_hash = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
283                 g_hash_table_insert (type_hash, bucket->type, bucket);
284         }
285         
286         sub = g_new (struct _subtype_bucket, 1);
287         sub->subtype = g_strdup (subtype);
288         sub->object_type = object_type;
289         g_hash_table_insert (bucket->subtype_hash, sub->subtype, sub);
290 }
291
292
293 /**
294  * g_mime_object_new:
295  * @content_type: a #GMimeContentType object
296  *
297  * Performs a lookup of registered #GMimeObject subclasses, registered
298  * using g_mime_object_register_type(), to find an appropriate class
299  * capable of handling MIME parts of the specified Content-Type. If no
300  * class has been registered to handle that type, it looks for a
301  * registered class that can handle @content_type's media type. If
302  * that also fails, then it will use the generic part class,
303  * #GMimePart.
304  *
305  * Returns: an appropriate #GMimeObject registered to handle MIME
306  * parts appropriate for @content_type.
307  **/
308 GMimeObject *
309 g_mime_object_new (GMimeContentType *content_type)
310 {
311         struct _type_bucket *bucket;
312         struct _subtype_bucket *sub;
313         GMimeObject *object;
314         GType obj_type;
315         
316         g_return_val_if_fail (GMIME_IS_CONTENT_TYPE (content_type), NULL);
317         
318         if ((bucket = g_hash_table_lookup (type_hash, content_type->type))) {
319                 if (!(sub = g_hash_table_lookup (bucket->subtype_hash, content_type->subtype)))
320                         sub = g_hash_table_lookup (bucket->subtype_hash, "*");
321                 
322                 obj_type = sub ? sub->object_type : 0;
323         } else {
324                 bucket = g_hash_table_lookup (type_hash, "*");
325                 obj_type = bucket ? bucket->object_type : 0;
326         }
327         
328         if (!obj_type) {
329                 /* use the default mime object */
330                 if ((bucket = g_hash_table_lookup (type_hash, "*"))) {
331                         sub = g_hash_table_lookup (bucket->subtype_hash, "*");
332                         obj_type = sub ? sub->object_type : 0;
333                 }
334                 
335                 if (!obj_type)
336                         return NULL;
337         }
338         
339         object = g_object_newv (obj_type, 0, NULL);
340         
341         g_mime_object_set_content_type (object, content_type);
342         
343         return object;
344 }
345
346
347 /**
348  * g_mime_object_new_type:
349  * @type: mime type
350  * @subtype: mime subtype
351  *
352  * Performs a lookup of registered #GMimeObject subclasses, registered
353  * using g_mime_object_register_type(), to find an appropriate class
354  * capable of handling MIME parts of type @type/@subtype. If no class
355  * has been registered to handle that type, it looks for a registered
356  * class that can handle @type. If that also fails, then it will use
357  * the generic part class, #GMimePart.
358  *
359  * Returns: an appropriate #GMimeObject registered to handle mime-types
360  * of @type/@subtype.
361  **/
362 GMimeObject *
363 g_mime_object_new_type (const char *type, const char *subtype)
364 {
365         struct _type_bucket *bucket;
366         struct _subtype_bucket *sub;
367         GType obj_type;
368         
369         g_return_val_if_fail (type != NULL, NULL);
370         
371         if ((bucket = g_hash_table_lookup (type_hash, type))) {
372                 if (!(sub = g_hash_table_lookup (bucket->subtype_hash, subtype)))
373                         sub = g_hash_table_lookup (bucket->subtype_hash, "*");
374                 
375                 obj_type = sub ? sub->object_type : 0;
376         } else {
377                 bucket = g_hash_table_lookup (type_hash, "*");
378                 obj_type = bucket ? bucket->object_type : 0;
379         }
380         
381         if (!obj_type) {
382                 /* use the default mime object */
383                 if ((bucket = g_hash_table_lookup (type_hash, "*"))) {
384                         sub = g_hash_table_lookup (bucket->subtype_hash, "*");
385                         obj_type = sub ? sub->object_type : 0;
386                 }
387                 
388                 if (!obj_type)
389                         return NULL;
390         }
391         
392         return g_object_newv (obj_type, 0, NULL);
393 }
394
395
396 static void
397 object_set_content_type (GMimeObject *object, GMimeContentType *content_type)
398 {
399         if (object->content_type) {
400                 g_mime_event_remove (object->content_type->priv, (GMimeEventCallback) content_type_changed, object);
401                 g_object_unref (object->content_type);
402         }
403         
404         g_mime_event_add (content_type->priv, (GMimeEventCallback) content_type_changed, object);
405         object->content_type = content_type;
406         g_object_ref (content_type);
407 }
408
409
410 /**
411  * _g_mime_object_set_content_type:
412  * @object: a #GMimeObject
413  * @content_type: a #GMimeContentType object
414  *
415  * Sets the content-type for the specified MIME object.
416  *
417  * Note: This method is meant for internal-use only and avoids
418  * serialization of @content_type to the Content-Type header field.
419  **/
420 void
421 _g_mime_object_set_content_type (GMimeObject *object, GMimeContentType *content_type)
422 {
423         GMIME_OBJECT_GET_CLASS (object)->set_content_type (object, content_type);
424 }
425
426
427 /**
428  * g_mime_object_set_content_type:
429  * @object: a #GMimeObject
430  * @content_type: a #GMimeContentType object
431  *
432  * Sets the content-type for the specified MIME object and then
433  * serializes it to the Content-Type header field.
434  **/
435 void
436 g_mime_object_set_content_type (GMimeObject *object, GMimeContentType *content_type)
437 {
438         g_return_if_fail (GMIME_IS_CONTENT_TYPE (content_type));
439         g_return_if_fail (GMIME_IS_OBJECT (object));
440         
441         if (object->content_type == content_type)
442                 return;
443         
444         GMIME_OBJECT_GET_CLASS (object)->set_content_type (object, content_type);
445         
446         content_type_changed (content_type, NULL, object);
447 }
448
449
450 /**
451  * g_mime_object_get_content_type:
452  * @object: a #GMimeObject
453  *
454  * Gets the #GMimeContentType object for the given MIME object or
455  * %NULL on fail.
456  *
457  * Returns: the content-type object for the specified MIME object.
458  **/
459 GMimeContentType *
460 g_mime_object_get_content_type (GMimeObject *object)
461 {
462         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
463         
464         return object->content_type;
465 }
466
467
468 /**
469  * g_mime_object_set_content_type_parameter:
470  * @object: a #GMimeObject
471  * @name: param name
472  * @value: param value
473  *
474  * Sets the content-type param @name to the value @value.
475  **/
476 void
477 g_mime_object_set_content_type_parameter (GMimeObject *object, const char *name, const char *value)
478 {
479         g_return_if_fail (GMIME_IS_OBJECT (object));
480         g_return_if_fail (name != NULL);
481         
482         g_mime_content_type_set_parameter (object->content_type, name, value);
483 }
484
485
486 /**
487  * g_mime_object_get_content_type_parameter:
488  * @object: a #GMimeObject
489  * @name: param name
490  *
491  * Gets the value of the content-type param @name set on the MIME part
492  * @object.
493  *
494  * Returns: the value of the requested content-type param or %NULL on
495  * if the param doesn't exist.
496  **/
497 const char *
498 g_mime_object_get_content_type_parameter (GMimeObject *object, const char *name)
499 {
500         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
501         g_return_val_if_fail (name != NULL, NULL);
502         
503         return g_mime_content_type_get_parameter (object->content_type, name);
504 }
505
506
507 /**
508  * g_mime_object_get_content_disposition:
509  * @object: a #GMimeObject
510  *
511  * Gets the #GMimeContentDisposition for the specified MIME object.
512  *
513  * Returns: the #GMimeContentDisposition set on the MIME object.
514  **/
515 GMimeContentDisposition *
516 g_mime_object_get_content_disposition (GMimeObject *object)
517 {
518         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
519         
520         return object->disposition;
521 }
522
523 /**
524  * g_mime_object_set_content_disposition:
525  * @object: a #GMimeObject
526  * @disposition: a #GMimeContentDisposition object
527  *
528  * Set the content disposition for the specified mime part.
529  *
530  * Note: This method is meant for internal-use only and avoids
531  * serialization of @disposition to the Content-Disposition header
532  * field.
533  **/
534 static void
535 _g_mime_object_set_content_disposition (GMimeObject *object, GMimeContentDisposition *disposition)
536 {
537         if (object->disposition) {
538                 g_mime_event_remove (object->disposition->priv, (GMimeEventCallback) content_disposition_changed, object);
539                 g_object_unref (object->disposition);
540         }
541         
542         g_mime_event_add (disposition->priv, (GMimeEventCallback) content_disposition_changed, object);
543         object->disposition = disposition;
544         g_object_ref (disposition);
545 }
546
547
548 /**
549  * g_mime_object_set_content_disposition:
550  * @object: a #GMimeObject
551  * @disposition: a #GMimeContentDisposition object
552  *
553  * Set the content disposition for the specified mime part and then
554  * serializes it to the Content-Disposition header field.
555  **/
556 void
557 g_mime_object_set_content_disposition (GMimeObject *object, GMimeContentDisposition *disposition)
558 {
559         g_return_if_fail (GMIME_IS_CONTENT_DISPOSITION (disposition));
560         g_return_if_fail (GMIME_IS_OBJECT (object));
561         
562         if (object->disposition == disposition)
563                 return;
564         
565         _g_mime_object_set_content_disposition (object, disposition);
566         
567         content_disposition_changed (disposition, NULL, object);
568 }
569
570
571 /**
572  * g_mime_object_set_disposition:
573  * @object: a #GMimeObject
574  * @disposition: disposition ("attachment" or "inline")
575  *
576  * Sets the disposition to @disposition which may be one of
577  * #GMIME_DISPOSITION_ATTACHMENT or #GMIME_DISPOSITION_INLINE or, by
578  * your choice, any other string which would indicate how the MIME
579  * part should be displayed by the MUA.
580  **/
581 void
582 g_mime_object_set_disposition (GMimeObject *object, const char *disposition)
583 {
584         GMimeContentDisposition *disp;
585         
586         g_return_if_fail (GMIME_IS_OBJECT (object));
587         g_return_if_fail (disposition != NULL);
588         
589         if (object->disposition) {
590                 g_mime_content_disposition_set_disposition (object->disposition, disposition);
591                 return;
592         }
593         
594         disp = g_mime_content_disposition_new ();
595         g_mime_content_disposition_set_disposition (disp, disposition);
596         g_mime_object_set_content_disposition (object, disp);
597         g_object_unref (disp);
598 }
599
600
601 /**
602  * g_mime_object_get_disposition:
603  * @object: a #GMimeObject
604  *
605  * Gets the MIME object's disposition if set or %NULL otherwise.
606  *
607  * Returns: the disposition string which is probably one of
608  * #GMIME_DISPOSITION_ATTACHMENT or #GMIME_DISPOSITION_INLINE.
609  **/
610 const char *
611 g_mime_object_get_disposition (GMimeObject *object)
612 {
613         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
614         
615         if (object->disposition)
616                 return g_mime_content_disposition_get_disposition (object->disposition);
617         
618         return NULL;
619 }
620
621
622 /**
623  * g_mime_object_set_content_disposition_parameter:
624  * @object: a #GMimeObject
625  * @attribute: parameter name
626  * @value: parameter value
627  *
628  * Add a content-disposition parameter to the specified mime part.
629  **/
630 void
631 g_mime_object_set_content_disposition_parameter (GMimeObject *object, const char *attribute, const char *value)
632 {
633         GMimeContentDisposition *disposition;
634         
635         g_return_if_fail (GMIME_IS_OBJECT (object));
636         g_return_if_fail (attribute != NULL);
637         
638         if (!object->disposition) {
639                 disposition = g_mime_content_disposition_new ();
640                 _g_mime_object_set_content_disposition (object, disposition);
641         }
642         
643         g_mime_content_disposition_set_parameter (object->disposition, attribute, value);
644 }
645
646
647 /**
648  * g_mime_object_get_content_disposition_parameter:
649  * @object: a #GMimeObject
650  * @attribute: parameter name
651  *
652  * Gets the value of the Content-Disposition parameter specified by
653  * @attribute, or %NULL if the parameter does not exist.
654  *
655  * Returns: the value of a previously defined content-disposition
656  * parameter specified by @attribute.
657  **/
658 const char *
659 g_mime_object_get_content_disposition_parameter (GMimeObject *object, const char *attribute)
660 {
661         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
662         g_return_val_if_fail (attribute != NULL, NULL);
663         
664         if (!object->disposition)
665                 return NULL;
666         
667         return g_mime_content_disposition_get_parameter (object->disposition, attribute);
668 }
669
670
671 /**
672  * g_mime_object_set_content_id:
673  * @object: a #GMimeObject
674  * @content_id: content-id (addr-spec portion)
675  *
676  * Sets the Content-Id of the MIME object.
677  **/
678 void
679 g_mime_object_set_content_id (GMimeObject *object, const char *content_id)
680 {
681         char *msgid;
682         
683         g_return_if_fail (GMIME_IS_OBJECT (object));
684         
685         g_free (object->content_id);
686         object->content_id = g_strdup (content_id);
687         
688         msgid = g_strdup_printf ("<%s>", content_id);
689         g_mime_object_set_header (object, "Content-Id", msgid);
690         g_free (msgid);
691 }
692
693
694 /**
695  * g_mime_object_get_content_id:
696  * @object: a #GMimeObject
697  *
698  * Gets the Content-Id of the MIME object or NULL if one is not set.
699  *
700  * Returns: a const pointer to the Content-Id header.
701  **/
702 const char *
703 g_mime_object_get_content_id (GMimeObject *object)
704 {
705         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
706         
707         return object->content_id;
708 }
709
710
711 enum {
712         HEADER_CONTENT_DISPOSITION,
713         HEADER_CONTENT_TYPE,
714         HEADER_CONTENT_ID,
715         HEADER_UNKNOWN,
716 };
717
718 static char *content_headers[] = {
719         "Content-Disposition",
720         "Content-Type",
721         "Content-Id",
722 };
723
724 static gboolean
725 process_header (GMimeObject *object, const char *header, const char *value)
726 {
727         GMimeContentDisposition *disposition;
728         GMimeContentType *content_type;
729         guint i;
730         
731         if (g_ascii_strncasecmp (header, "Content-", 8) != 0)
732                 return FALSE;
733         
734         for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
735                 if (!g_ascii_strcasecmp (content_headers[i] + 8, header + 8))
736                         break;
737         }
738         
739         switch (i) {
740         case HEADER_CONTENT_DISPOSITION:
741                 disposition = g_mime_content_disposition_new_from_string (value);
742                 _g_mime_object_set_content_disposition (object, disposition);
743                 g_object_unref (disposition);
744                 break;
745         case HEADER_CONTENT_TYPE:
746                 content_type = g_mime_content_type_new_from_string (value);
747                 _g_mime_object_set_content_type (object, content_type);
748                 g_object_unref (content_type);
749                 break;
750         case HEADER_CONTENT_ID:
751                 g_free (object->content_id);
752                 object->content_id = g_mime_utils_decode_message_id (value);
753                 break;
754         default:
755                 return FALSE;
756         }
757         
758         g_mime_header_list_set (object->headers, header, value);
759         
760         return TRUE;
761 }
762
763 static void
764 object_prepend_header (GMimeObject *object, const char *header, const char *value)
765 {
766         if (!process_header (object, header, value))
767                 g_mime_header_list_prepend (object->headers, header, value);
768 }
769
770
771 /**
772  * g_mime_object_prepend_header:
773  * @object: a #GMimeObject
774  * @header: header name
775  * @value: header value
776  *
777  * Prepends a raw, unprocessed header to the MIME object.
778  **/
779 void
780 g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value)
781 {
782         g_return_if_fail (GMIME_IS_OBJECT (object));
783         g_return_if_fail (header != NULL);
784         g_return_if_fail (value != NULL);
785         
786         GMIME_OBJECT_GET_CLASS (object)->prepend_header (object, header, value);
787 }
788
789 static void
790 object_append_header (GMimeObject *object, const char *header, const char *value)
791 {
792         if (!process_header (object, header, value))
793                 g_mime_header_list_append (object->headers, header, value);
794 }
795
796
797 /**
798  * g_mime_object_append_header:
799  * @object: a #GMimeObject
800  * @header: header name
801  * @value: header value
802  *
803  * Appends a raw, unprocessed header to the MIME object.
804  **/
805 void
806 g_mime_object_append_header (GMimeObject *object, const char *header, const char *value)
807 {
808         g_return_if_fail (GMIME_IS_OBJECT (object));
809         g_return_if_fail (header != NULL);
810         g_return_if_fail (value != NULL);
811         
812         GMIME_OBJECT_GET_CLASS (object)->append_header (object, header, value);
813 }
814
815
816 static void
817 object_set_header (GMimeObject *object, const char *header, const char *value)
818 {
819         if (!process_header (object, header, value))
820                 g_mime_header_list_set (object->headers, header, value);
821 }
822
823
824 /**
825  * g_mime_object_set_header:
826  * @object: a #GMimeObject
827  * @header: header name
828  * @value: header value
829  *
830  * Sets an arbitrary raw, unprocessed header on the MIME object.
831  **/
832 void
833 g_mime_object_set_header (GMimeObject *object, const char *header, const char *value)
834 {
835         g_return_if_fail (GMIME_IS_OBJECT (object));
836         g_return_if_fail (header != NULL);
837         g_return_if_fail (value != NULL);
838         
839         GMIME_OBJECT_GET_CLASS (object)->set_header (object, header, value);
840 }
841
842
843 static const char *
844 object_get_header (GMimeObject *object, const char *header)
845 {
846         return g_mime_header_list_get (object->headers, header);
847 }
848
849
850 /**
851  * g_mime_object_get_header:
852  * @object: a #GMimeObject
853  * @header: header name
854  *
855  * Gets the raw, unprocessed value of the requested header.
856  *
857  * Returns: the raw, unprocessed value of the requested header if it
858  * exists or %NULL otherwise.
859  **/
860 const char *
861 g_mime_object_get_header (GMimeObject *object, const char *header)
862 {
863         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
864         g_return_val_if_fail (header != NULL, NULL);
865         
866         return GMIME_OBJECT_GET_CLASS (object)->get_header (object, header);
867 }
868
869
870 static gboolean
871 object_remove_header (GMimeObject *object, const char *header)
872 {
873         guint i;
874         
875         for (i = 0; i < G_N_ELEMENTS (content_headers); i++) {
876                 if (!g_ascii_strcasecmp (content_headers[i], header))
877                         break;
878         }
879         
880         switch (i) {
881         case HEADER_CONTENT_DISPOSITION:
882                 if (object->disposition) {
883                         g_mime_event_remove (object->disposition->priv, (GMimeEventCallback) content_disposition_changed, object);
884                         g_object_unref (object->disposition);
885                         object->disposition = NULL;
886                 }
887                 break;
888         case HEADER_CONTENT_TYPE:
889                 /* never allow the removal of the Content-Type header */
890                 return FALSE;
891         case HEADER_CONTENT_ID:
892                 g_free (object->content_id);
893                 object->content_id = NULL;
894                 break;
895         default:
896                 break;
897         }
898         
899         return g_mime_header_list_remove (object->headers, header);
900 }
901
902
903 /**
904  * g_mime_object_remove_header:
905  * @object: a #GMimeObject
906  * @header: header name
907  *
908  * Removed the specified header if it exists.
909  *
910  * Returns: %TRUE if the header was removed or %FALSE if it could not
911  * be found.
912  **/
913 gboolean
914 g_mime_object_remove_header (GMimeObject *object, const char *header)
915 {
916         g_return_val_if_fail (GMIME_IS_OBJECT (object), FALSE);
917         g_return_val_if_fail (header != NULL, FALSE);
918         
919         return GMIME_OBJECT_GET_CLASS (object)->remove_header (object, header);
920 }
921
922
923 static char *
924 object_get_headers (GMimeObject *object)
925 {
926         return g_mime_header_list_to_string (object->headers);
927 }
928
929
930 /**
931  * g_mime_object_get_headers:
932  * @object: a #GMimeObject
933  *
934  * Allocates a string buffer containing all of the MIME object's raw
935  * headers.
936  *
937  * Returns: an allocated string containing all of the raw MIME headers.
938  **/
939 char *
940 g_mime_object_get_headers (GMimeObject *object)
941 {
942         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
943         
944         return GMIME_OBJECT_GET_CLASS (object)->get_headers (object);
945 }
946
947
948 static ssize_t
949 object_write_to_stream (GMimeObject *object, GMimeStream *stream)
950 {
951         return -1;
952 }
953
954
955 /**
956  * g_mime_object_write_to_stream:
957  * @object: a #GMimeObject
958  * @stream: stream
959  *
960  * Write the contents of the MIME object to @stream.
961  *
962  * Returns: the number of bytes written or %-1 on fail.
963  **/
964 ssize_t
965 g_mime_object_write_to_stream (GMimeObject *object, GMimeStream *stream)
966 {
967         g_return_val_if_fail (GMIME_IS_OBJECT (object), -1);
968         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
969         
970         return GMIME_OBJECT_GET_CLASS (object)->write_to_stream (object, stream);
971 }
972
973
974 static void
975 object_encode (GMimeObject *object, GMimeEncodingConstraint constraint)
976 {
977         return;
978 }
979
980
981 /**
982  * g_mime_object_encode:
983  * @object: a #GMimeObject
984  * @constraint: a #GMimeEncodingConstraint
985  *
986  * Calculates and sets the most efficient Content-Transfer-Encoding
987  * for this #GMimeObject and all child parts based on the @constraint
988  * provided.
989  **/
990 void
991 g_mime_object_encode (GMimeObject *object, GMimeEncodingConstraint constraint)
992 {
993         g_return_if_fail (GMIME_IS_OBJECT (object));
994         
995         GMIME_OBJECT_GET_CLASS (object)->encode (object, constraint);
996 }
997
998
999 /**
1000  * g_mime_object_to_string:
1001  * @object: a #GMimeObject
1002  *
1003  * Allocates a string buffer containing the contents of @object.
1004  *
1005  * Returns: an allocated string containing the contents of the mime
1006  * object.
1007  **/
1008 char *
1009 g_mime_object_to_string (GMimeObject *object)
1010 {
1011         GMimeStream *stream;
1012         GByteArray *array;
1013         char *str;
1014         
1015         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
1016         
1017         array = g_byte_array_new ();
1018         stream = g_mime_stream_mem_new ();
1019         g_mime_stream_mem_set_byte_array (GMIME_STREAM_MEM (stream), array);
1020         
1021         g_mime_object_write_to_stream (object, stream);
1022         
1023         g_object_unref (stream);
1024         g_byte_array_append (array, (unsigned char *) "", 1);
1025         str = (char *) array->data;
1026         g_byte_array_free (array, FALSE);
1027         
1028         return str;
1029 }
1030
1031
1032 /**
1033  * g_mime_object_get_header_list:
1034  * @object: a #GMimeObject
1035  *
1036  * Get the header list for @object.
1037  *
1038  * Returns: the #GMimeHeaderList for @object. Do not free this pointer
1039  * when you are done with it.
1040  **/
1041 GMimeHeaderList *
1042 g_mime_object_get_header_list (GMimeObject *object)
1043 {
1044         g_return_val_if_fail (GMIME_IS_OBJECT (object), NULL);
1045         
1046         return object->headers;
1047 }
1048
1049
1050 static void
1051 subtype_bucket_foreach (gpointer key, gpointer value, gpointer user_data)
1052 {
1053         struct _subtype_bucket *bucket = value;
1054         
1055         g_free (bucket->subtype);
1056         g_free (bucket);
1057 }
1058
1059 static void
1060 type_bucket_foreach (gpointer key, gpointer value, gpointer user_data)
1061 {
1062         struct _type_bucket *bucket = value;
1063         
1064         g_free (bucket->type);
1065         
1066         if (bucket->subtype_hash) {
1067                 g_hash_table_foreach (bucket->subtype_hash, subtype_bucket_foreach, NULL);
1068                 g_hash_table_destroy (bucket->subtype_hash);
1069         }
1070         
1071         g_free (bucket);
1072 }
1073
1074 void
1075 g_mime_object_type_registry_shutdown (void)
1076 {
1077         g_hash_table_foreach (type_hash, type_bucket_foreach, NULL);
1078         g_hash_table_destroy (type_hash);
1079         type_hash = NULL;
1080 }
1081
1082 void
1083 g_mime_object_type_registry_init (void)
1084 {
1085         if (type_hash)
1086                 return;
1087         
1088         type_hash = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
1089 }