/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* GMime
* Copyright (C) 2000-2007 Jeffrey Stedfast
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <ctype.h>
#include "gmime-common.h"
#include "gmime-header.h"
#include "gmime-utils.h"
#include "gmime-stream-mem.h"
struct raw_header {
struct raw_header *next;
char *name;
char *value;
};
struct _GMimeHeader {
GHashTable *hash;
GHashTable *writers;
struct raw_header *headers;
char *raw;
};
/**
* g_mime_header_new:
*
* Creates a new #GMimeHeader object.
*
* Returns a new header object.
**/
GMimeHeader *
g_mime_header_new (void)
{
GMimeHeader *new;
new = g_new (GMimeHeader, 1);
new->hash = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
new->writers = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
new->headers = NULL;
new->raw = NULL;
return new;
}
static void
writer_free (gpointer key, gpointer value, gpointer user_data)
{
g_free (key);
}
/**
* g_mime_header_destroy:
* @header: header object
*
* Destroy the header object
**/
void
g_mime_header_destroy (GMimeHeader *header)
{
if (header) {
struct raw_header *h, *n;
h = header->headers;
while (h) {
g_free (h->name);
g_free (h->value);
n = h->next;
g_free (h);
h = n;
}
g_hash_table_destroy (header->hash);
g_hash_table_foreach (header->writers, writer_free, NULL);
g_hash_table_destroy (header->writers);
g_free (header->raw);
g_free (header);
}
}
/**
* g_mime_header_set:
* @header: header object
* @name: header name
* @value: header value
*
* Set the value of the specified header. If @value is %NULL and the
* header, @name, had not been previously set, a space will be set
* aside for it (useful for setting the order of headers before values
* can be obtained for them) otherwise the header will be unset.
**/
void
g_mime_header_set (GMimeHeader *header, const char *name, const char *value)
{
struct raw_header *h, *n;
g_return_if_fail (header != NULL);
g_return_if_fail (name != NULL);
if ((h = g_hash_table_lookup (header->hash, name))) {
g_free (h->value);
h->value = g_strdup (value);
} else {
n = g_new (struct raw_header, 1);
n->next = NULL;
n->name = g_strdup (name);
n->value = g_strdup (value);
h = header->headers;
while (h && h->next)
h = h->next;
if (h != NULL)
h->next = n;
else
header->headers = n;
g_hash_table_insert (header->hash, n->name, n);
}
g_free (header->raw);
header->raw = NULL;
}
/**
* g_mime_header_add:
* @header: header object
* @name: header name
* @value: header value
*
* Adds a header. If @value is %NULL, a space will be set aside for it
* (useful for setting the order of headers before values can be
* obtained for them) otherwise the header will be unset.
**/
void
g_mime_header_add (GMimeHeader *header, const char *name, const char *value)
{
struct raw_header *h, *n;
g_return_if_fail (header != NULL);
g_return_if_fail (name != NULL);
n = g_new (struct raw_header, 1);
n->next = NULL;
n->name = g_strdup (name);
n->value = g_strdup (value);
h = header->headers;
while (h && h->next)
h = h->next;
if (h)
h->next = n;
else
header->headers = n;
if (!g_hash_table_lookup (header->hash, name))
g_hash_table_insert (header->hash, n->name, n);
g_free (header->raw);
header->raw = NULL;
}
/**
* g_mime_header_prepend:
* @header: header object
* @name: header name
* @value: header value
*
* Adds a header to the head of the list. If @value is %NULL, a space
* will be set aside for it (useful for setting the order of headers
* before values can be obtained for them) otherwise the header will
* be unset.
**/
void
g_mime_header_prepend (GMimeHeader *header, const char *name, const char *value)
{
struct raw_header *n;
g_return_if_fail (header != NULL);
g_return_if_fail (name != NULL);
n = g_new (struct raw_header, 1);
n->next = header->headers;
n->name = g_strdup (name);
n->value = g_strdup (value);
header->headers = n;
if (!g_hash_table_lookup (header->hash, name))
g_hash_table_insert (header->hash, n->name, n);
g_free (header->raw);
header->raw = NULL;
}
/**
* g_mime_header_get:
* @header: header object
* @name: header name
*
* Gets the value of the header requested.
*
* Returns the value of the header requested.
**/
const char *
g_mime_header_get (const GMimeHeader *header, const char *name)
{
const struct raw_header *h;
g_return_val_if_fail (header != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
h = g_hash_table_lookup (header->hash, name);
return h ? h->value : NULL;
}
/**
* g_mime_header_remove:
* @header: header object
* @name: header name
*
* Remove the specified header.
**/
void
g_mime_header_remove (GMimeHeader *header, const char *name)
{
struct raw_header *h, *n;
g_return_if_fail (header != NULL);
g_return_if_fail (name != NULL);
if ((h = g_hash_table_lookup (header->hash, name))) {
/* remove the header */
g_hash_table_remove (header->hash, name);
n = header->headers;
if (h == n) {
header->headers = h->next;
} else {
while (n->next != h)
n = n->next;
n->next = h->next;
}
g_free (h->name);
g_free (h->value);
g_free (h);
}
g_free (header->raw);
header->raw = NULL;
}
static ssize_t
write_default (GMimeStream *stream, const char *name, const char *value)
{
ssize_t nwritten;
char *val;
val = g_mime_utils_header_printf ("%s: %s\n", name, value);
nwritten = g_mime_stream_write_string (stream, val);
g_free (val);
return nwritten;
}
/**
* g_mime_header_write_to_stream:
* @header: header object
* @stream: output stream
*
* Write the headers to a stream.
*
* Returns the number of bytes written or %-1 on fail.
**/
ssize_t
g_mime_header_write_to_stream (const GMimeHeader *header, GMimeStream *stream)
{
GMimeHeaderWriter header_write;
ssize_t nwritten, total = 0;
struct raw_header *h;
g_return_val_if_fail (header != NULL, -1);
g_return_val_if_fail (stream != NULL, -1);
if (header->raw)
return g_mime_stream_write_string (stream, header->raw);
h = header->headers;
while (h) {
if (h->value) {
header_write = g_hash_table_lookup (header->writers, h->name);
if (header_write)
nwritten = (*header_write) (stream, h->name, h->value);
else
nwritten = write_default (stream, h->name, h->value);
if (nwritten == -1)
return -1;
total += nwritten;
}
h = h->next;
}
return total;
}
/**
* g_mime_header_to_string:
* @header: header object
*
* Allocates a string buffer containing the raw rfc822 headers
* contained in @header.
*
* Returns a string containing the header block
**/
char *
g_mime_header_to_string (const GMimeHeader *header)
{
GMimeStream *stream;
GByteArray *array;
char *str;
g_return_val_if_fail (header != NULL, NULL);
array = g_byte_array_new ();
stream = g_mime_stream_mem_new ();
g_mime_stream_mem_set_byte_array (GMIME_STREAM_MEM (stream), array);
g_mime_header_write_to_stream (header, stream);
g_object_unref (stream);
g_byte_array_append (array, (unsigned char *) "", 1);
str = (char *) array->data;
g_byte_array_free (array, FALSE);
return str;
}
/**
* g_mime_header_foreach:
* @header: header object
* @func: function to be called for each header.
* @user_data: User data to be passed to the func.
*
* Calls @func for each header name/value pair.
*/
void
g_mime_header_foreach (const GMimeHeader *header, GMimeHeaderForeachFunc func, gpointer user_data)
{
const struct raw_header *h;
g_return_if_fail (header != NULL);
g_return_if_fail (header->hash != NULL);
g_return_if_fail (func != NULL);
for (h = header->headers; h != NULL; h = h->next)
(*func) (h->name, h->value, user_data);
}
/**
* g_mime_header_register_writer:
* @header: header object
* @name: header name
* @writer: writer function
*
* Changes the function used to write @name headers to @writer (or the
* default if @writer is %NULL). This is useful if you want to change
* the default header folding style for a particular header.
**/
void
g_mime_header_register_writer (GMimeHeader *header, const char *name, GMimeHeaderWriter writer)
{
gpointer okey, oval;
g_return_if_fail (header != NULL);
g_return_if_fail (name != NULL);
if (g_hash_table_lookup (header->writers, name)) {
g_hash_table_lookup_extended (header->writers, name, &okey, &oval);
g_hash_table_remove (header->writers, name);
g_free (okey);
}
if (writer)
g_hash_table_insert (header->writers, g_strdup (name), writer);
}
/**
* g_mime_header_set_raw:
* @header: header object
* @raw: raw mime part header
*
* Set the raw header.
**/
void
g_mime_header_set_raw (GMimeHeader *header, const char *raw)
{
g_return_if_fail (header != NULL);
g_free (header->raw);
header->raw = raw ? g_strdup (raw) : NULL;
}
/**
* g_mime_header_has_raw:
* @header: ehader object
*
* Gets whether or not a raw header has been set on @header.
*
* Returns %TRUE if a raw header is set or %FALSE otherwise.
**/
gboolean
g_mime_header_has_raw (GMimeHeader *header)
{
g_return_val_if_fail (header != NULL, FALSE);
return header->raw ? TRUE : FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1