diff options
author | Not Zed <NotZed@Ximian.com> | 2003-09-18 05:19:04 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2003-09-18 05:19:04 +0800 |
commit | 81a0ff5bc44a3bd11399e6b3c985735737606c8c (patch) | |
tree | 54b5ed4342a6843c1db4c7e75f2e1b1fe9b82dff /mail/em-camel-stream.c | |
parent | a36a1bb70b6ebcb51ac39304370c89bda63e11b9 (diff) | |
download | gsoc2013-evolution-81a0ff5bc44a3bd11399e6b3c985735737606c8c.tar.gz gsoc2013-evolution-81a0ff5bc44a3bd11399e6b3c985735737606c8c.tar.zst gsoc2013-evolution-81a0ff5bc44a3bd11399e6b3c985735737606c8c.zip |
cvs removed.
2003-09-17 Not Zed <NotZed@Ximian.com>
* folder-browser.c, folder-browser.h, folder-browser-ui.c
folder-browser-ui.h, mail-callbacks.c, mail-callbacks.h
mail-display.c, mail-display.h, mail-display-stream.c
mail-display-stream.h, mail-format.c, mail-format.h
mail-identify.c, mail-search.c, mail-search.h
message-browser.c, message-browser.h, subscribe-dialog.c
subscribe-dialog.h, mail-font-prefs.c, mail-font-prefs.h: cvs
removed.
* Makefile.am: Removed mail-font-prefs.[ch], hasn't been built for
ages.
* em-*.c: killed a bunch of printfs.
* em-format-html-display.c (efhd_html_button_press_event): update
for html object api chagnes.
** Merge in mail-refactor-2 branch.
svn path=/trunk/; revision=22602
Diffstat (limited to 'mail/em-camel-stream.c')
-rw-r--r-- | mail/em-camel-stream.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/mail/em-camel-stream.c b/mail/em-camel-stream.c new file mode 100644 index 0000000000..a1274d634a --- /dev/null +++ b/mail/em-camel-stream.c @@ -0,0 +1,326 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * Michael Zucchi <notzed@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdio.h> +#include <camel/camel-stream.h> +#include <camel/camel-object.h> +#include <gtkhtml/gtkhtml.h> +#include <gtkhtml/gtkhtml-stream.h> +#include <gtk/gtkmain.h> +#include "em-camel-stream.h" + +#include "mail-mt.h" + +#define EMCS_BUFFER_SIZE (4096) + +/*#define LOG_STREAM*/ + +#define d(x) + +enum _write_msg_t { + EMCS_WRITE, + EMCS_FLUSH, + EMCS_CLOSE_OK, + EMCS_CLOSE_ERROR, +}; + +struct _write_msg { + EMsg msg; + + enum _write_msg_t op; + + const char *data; + size_t n; +}; + +static void em_camel_stream_class_init (EMCamelStreamClass *klass); +static void em_camel_stream_init (CamelObject *object); +static void em_camel_stream_finalize (CamelObject *object); + +static ssize_t stream_write(CamelStream *stream, const char *buffer, size_t n); +static int stream_close(CamelStream *stream); +static int stream_flush(CamelStream *stream); + +static CamelStreamClass *parent_class = NULL; + +CamelType +em_camel_stream_get_type (void) +{ + static CamelType type = CAMEL_INVALID_TYPE; + + if (type == CAMEL_INVALID_TYPE) { + type = camel_type_register (CAMEL_STREAM_TYPE, + "EMCamelStream", + sizeof (EMCamelStream), + sizeof (EMCamelStreamClass), + (CamelObjectClassInitFunc) em_camel_stream_class_init, + NULL, + (CamelObjectInitFunc) em_camel_stream_init, + (CamelObjectFinalizeFunc) em_camel_stream_finalize); + } + + return type; +} + +static void +em_camel_stream_class_init (EMCamelStreamClass *klass) +{ + CamelStreamClass *stream_class = CAMEL_STREAM_CLASS (klass); + + parent_class = (CamelStreamClass *) CAMEL_STREAM_TYPE; + + /* virtual method overload */ + stream_class->write = stream_write; + stream_class->flush = stream_flush; + stream_class->close = stream_close; +} + +static gboolean +emcs_gui_received(GIOChannel *source, GIOCondition cond, void *data) +{ + EMCamelStream *estream = data; + struct _write_msg *msg; + + d(printf("%p: gui sync op job waiting\n", estream)); + + msg = (struct _write_msg *)e_msgport_get(estream->data_port); + /* Should never happen ... */ + if (msg == NULL) + return TRUE; + + d(printf("%p: running sync op %d\n", estream, msg->op)); + + /* force out any pending data before doing anything else */ + if (estream->used > 0) { + d(printf("sync write %d\n", estream->used)); + + if (estream->html_stream) + gtk_html_stream_write(estream->html_stream, estream->buffer, estream->used); + estream->used = 0; + } + + switch (msg->op) { + case EMCS_WRITE: + d(printf("sync write %d\n", msg->n)); + if (estream->html_stream) + gtk_html_stream_write(estream->html_stream, msg->data, msg->n); + break; + case EMCS_FLUSH: + stream_flush((CamelStream *)estream); + break; + case EMCS_CLOSE_OK: + if (estream->html_stream) { + gtk_html_stream_close(estream->html_stream, GTK_HTML_STREAM_OK); + estream->html_stream = NULL; + } + break; + case EMCS_CLOSE_ERROR: + if (estream->html_stream) { + gtk_html_stream_close(estream->html_stream, GTK_HTML_STREAM_ERROR); + estream->html_stream = NULL; + } + break; + } + + e_msgport_reply((EMsg *)msg); + d(printf("%p: gui sync op jobs done\n", estream)); + + return TRUE; +} + +static void +em_camel_stream_init (CamelObject *object) +{ + EMCamelStream *estream = (EMCamelStream *)object; + + estream->data_port = e_msgport_new(); + estream->reply_port = e_msgport_new(); + + estream->gui_channel = g_io_channel_unix_new(e_msgport_fd(estream->data_port)); + estream->gui_watch = g_io_add_watch(estream->gui_channel, G_IO_IN, emcs_gui_received, estream); + + estream->used = 0; + estream->buffer = g_malloc(EMCS_BUFFER_SIZE); + + d(printf("%p: new estream\n", estream)); +} + +static void +sync_op(EMCamelStream *estream, enum _write_msg_t op, const char *data, size_t n) +{ + struct _write_msg msg; + + d(printf("%p: launching sync op %d\n", estream, op)); + /* we do everything synchronous, we should never have any locks, and + this prevents overflow from banked up data */ + msg.msg.reply_port = estream->reply_port; + msg.op = op; + msg.data = data; + msg.n = n; + e_msgport_put(estream->data_port, &msg.msg); + e_msgport_wait(estream->reply_port); + g_assert(e_msgport_get(msg.msg.reply_port) == &msg.msg); + d(printf("%p: returned sync op %d\n", estream, op)); +} + +static void +em_camel_stream_finalize (CamelObject *object) +{ + EMCamelStream *estream = (EMCamelStream *)object; + + d(printf("%p: finalising stream\n", object)); + if (estream->html_stream) { + d(printf("%p: html stream still open - error\n", object)); + if (pthread_self() == mail_gui_thread) + gtk_html_stream_close(estream->html_stream, GTK_HTML_STREAM_ERROR); + else + sync_op(estream, EMCS_CLOSE_ERROR, NULL, 0); + } + + /* TODO: is this stuff safe to do in another thread? */ + g_source_remove(estream->gui_watch); + g_io_channel_unref(estream->gui_channel); + e_msgport_destroy(estream->data_port); + estream->data_port = NULL; + e_msgport_destroy(estream->reply_port); + estream->reply_port = NULL; + g_free(estream->buffer); +} + +static ssize_t +stream_write (CamelStream *stream, const char *buffer, size_t n) +{ + EMCamelStream *estream = EM_CAMEL_STREAM (stream); + + if (estream->html_stream == NULL) + return -1; + +#ifdef LOG_STREAM + if (estream->save) + fwrite(buffer, sizeof(char), n, estream->save); +#endif + + if (pthread_self() == mail_gui_thread) + gtk_html_stream_write(estream->html_stream, buffer, n); + else { +#if 1 + size_t left = EMCS_BUFFER_SIZE-estream->used; + + /* A super-simple buffer, if we get too much to fit, just do a sync + write, which will implicitly clear our previous writes first */ + d(printf("thread write '%d'\n", n)); + + if (n >= left) { + sync_op(estream, EMCS_WRITE, buffer, n); + } else { + memcpy(estream->buffer + estream->used, buffer, n); + estream->used += n; + } +#else + sync_op(estream, EMCS_WRITE, buffer, n); +#endif + } + return (ssize_t) n; +} + +static int +stream_flush(CamelStream *stream) +{ + EMCamelStream *estream = (EMCamelStream *)stream; + + if (estream->html_stream) { + if (pthread_self() == mail_gui_thread) { + /* FIXME: flush html stream via gtkhtml_stream_flush which doens't exist yet ... */ + while (gtk_events_pending ()) + gtk_main_iteration (); + } else { + sync_op(estream, EMCS_FLUSH, NULL, 0); + } + } + + return 0; +} + +static int +stream_close(CamelStream *stream) +{ + EMCamelStream *estream = (EMCamelStream *)stream; + + d(printf("%p: closing stream\n", stream)); + +#ifdef LOG_STREAM + if (estream->save) { + fclose(estream->save); + estream->save = NULL; + } +#endif + + if (estream->html_stream) { + if (pthread_self() == mail_gui_thread) { + gtk_html_stream_close(estream->html_stream, GTK_HTML_STREAM_OK); + estream->html_stream = NULL; + } else { + sync_op(estream, EMCS_CLOSE_OK, NULL, 0); + } + } + + return 0; +} + +static void +emcs_gtkhtml_destroy(struct _GtkHTML *html, EMCamelStream *emcs) +{ + d(printf("%p: emcs gtkhtml destroy\n", emcs)); + emcs->html = NULL; + emcs->html_stream = NULL; +} + +/* TODO: Could pass NULL for html_stream, and do a gtk_html_begin + on first data -> less flashing */ +CamelStream * +em_camel_stream_new(struct _GtkHTML *html, struct _GtkHTMLStream *html_stream) +{ + EMCamelStream *new; + + new = EM_CAMEL_STREAM (camel_object_new (EM_CAMEL_STREAM_TYPE)); + new->html_stream = html_stream; + g_signal_connect(html, "destroy", G_CALLBACK(emcs_gtkhtml_destroy), new); + +#ifdef LOG_STREAM + { + static int count; + char name[32]; + + sprintf(name, "camel-stream.%d.html", count++); + printf("saving raw html to '%s'\n", name); + new->save = fopen(name, "w"); + } +#endif + return CAMEL_STREAM (new); +} |