/*- * $Id: rr-message-close.c,v 1.19 2002/11/08 12:35:28 jonas Exp $ * * See the file LICENSE for redistribution information. * If you have not received a copy of the license, please contact CodeFactory * by email at info@codefactory.se, or on the web at http://www.codefactory.se/ * You may also write to: CodeFactory AB, SE-903 47, Umeå, Sweden. * * Copyright (c) 2002 Jonas Borgström * Copyright (c) 2002 Daniel Lundin * Copyright (c) 2002 CodeFactory AB. All rights reserved. */ #include #include #include #include static GObjectClass *parent_class = NULL; static void finalize (GObject *object); static gboolean process_frame (RRMessage *message, RRFrame *frame, GError **error); static RRFrame *get_frame (RRMessage *stat, gsize max_size); static void finalize (GObject *object) { RRMessageClose *mclose = (RRMessageClose *)object; if (mclose->xml_lang) g_free (mclose->xml_lang); if (mclose->diagnostic) g_free (mclose->diagnostic); g_mutex_free (mclose->done_mutex); g_cond_free (mclose->done_cond); parent_class->finalize (object); } static void rr_message_close_init (GObject *object) { RRMessageClose *mclose = (RRMessageClose *)object; RRMessage *msg = (RRMessage *)object; mclose->done_mutex = g_mutex_new (); mclose->done_cond = g_cond_new (); msg->type = RR_FRAME_TYPE_MSG; } static void rr_message_close_class_init (GObjectClass *klass) { RRMessageClass *msg_class = (RRMessageClass *)klass; klass->finalize = finalize; msg_class->get_frame = get_frame; msg_class->process_frame = process_frame; parent_class = g_type_class_peek_parent (klass); } GType rr_message_close_get_type (void) { static GType rr_type = 0; if (!rr_type) { static GTypeInfo type_info = { sizeof (RRMessageCloseClass), NULL, NULL, (GClassInitFunc) rr_message_close_class_init, NULL, NULL, sizeof (RRMessageClose), 16, (GInstanceInitFunc) rr_message_close_init }; rr_type = g_type_register_static (RR_TYPE_MESSAGE, "RRMessageClose", &type_info, 0); } return rr_type; } RRMessageClose * rr_message_close_new (gint channelnumber, gint code, const gchar *xml_lang, const gchar *diagnostic) { RRMessageClose *mclose; mclose = g_object_new (RR_TYPE_MESSAGE_CLOSE, NULL); mclose->channelnumber = channelnumber; mclose->code = code; mclose->xml_lang = g_strdup (xml_lang); mclose->diagnostic = g_strdup (diagnostic); return mclose; } static gboolean process_frame (RRMessage *message, RRFrame *frame, GError **error) { RRMessageClose *close; RRConnection *conn; xmlDocPtr doc; xmlNodePtr node; gboolean ret; xmlChar *str; const gchar *data; gint len; g_return_val_if_fail (RR_IS_MESSAGE_CLOSE (message), FALSE); g_return_val_if_fail (RR_IS_FRAME (frame), FALSE); g_return_val_if_fail (RR_IS_CHANNEL (message->channel), FALSE); g_return_val_if_fail (RR_IS_CONNECTION (message->channel->connection), FALSE); conn = message->channel->connection; close = RR_MESSAGE_CLOSE (message); data = rr_frame_mime_get_body (frame); len = rr_frame_mime_get_body_size (frame); doc = xmlParseMemory (data, len); if (doc == NULL) { g_set_error (error, RR_ERROR, RR_BEEP_CODE_SYNTAX_ERROR, "Invalid close message."); return FALSE; } g_return_val_if_fail (doc != NULL, FALSE); node = xmlDocGetRootElement (doc); if (strcmp (node->name, "close") != 0) goto err; if ((str = xmlGetProp (node, "number")) == NULL) goto err; close->channelnumber = atoi (str); xmlFree (str); if ((str = xmlGetProp (node, "code")) == NULL) goto err; close->code = atoi (str); xmlFree (str); /* FIXME: check for a "xml:" namespace */ if ((str = xmlGetProp (node, "lang"))) { close->xml_lang = g_strdup (str); xmlFree (str); } /* Extract the piggyback data if it exists */ if (node->children) { xmlNode *child, *cdata_node = NULL; child = node->children; while (child) { if (child->type == XML_CDATA_SECTION_NODE && child->content) { cdata_node = child; break; } child = child->next; } if (cdata_node && child->content) close->diagnostic = g_strdup (cdata_node->content); else if (node->children->type == XML_TEXT_NODE && node->children->content) close->diagnostic = g_strdup (node->children->content); } ret = TRUE; goto end; err: g_set_error (error, RR_ERROR, RR_BEEP_CODE_PARAM_ERROR, RR_GERROR_DEFAULT_MESSAGE); ret = FALSE; end: xmlFreeDoc (doc); return ret; } static RRFrame * get_frame (RRMessage *message, gsize max_size) { RRMessageClose *mclose = RR_MESSAGE_CLOSE(message); RRFrame *frame; GString *str; g_assert (RR_IS_MESSAGE (mclose)); str = g_string_new (NULL); g_string_printf (str, RR_BEEP_MIME_HEADER "channelnumber, mclose->code); if (mclose->xml_lang) { g_string_append_printf (str, " xml:lang='%s'", mclose->xml_lang); } if (mclose->diagnostic) { g_string_append_printf (str, ">%s\r\n", mclose->diagnostic); } else { g_string_append (str, " />\r\n"); } if (str->len > max_size) { g_string_free (str, TRUE); return NULL; } frame = rr_frame_new (RR_FRAME_TYPE_MSG, message->channel->id, FALSE, message->msgno, str->len, 0, str->str, TRUE); g_string_free (str, FALSE); return frame; } void rr_message_close_done (RRMessageClose *mclose, GError *error) { g_mutex_lock (mclose->done_mutex); /* FIXME: */ if (error) mclose->done_error = g_error_copy (error); mclose->done = TRUE; g_cond_broadcast (mclose->done_cond); g_mutex_unlock (mclose->done_mutex); } gboolean rr_message_close_wait_for_reply (RRMessageClose *mclose, GError **error) { g_mutex_lock (mclose->done_mutex); while (!mclose->done) g_cond_wait (mclose->done_cond, mclose->done_mutex); g_mutex_unlock (mclose->done_mutex); if (mclose->done_error) { g_propagate_error (error, mclose->done_error); mclose->done_error = NULL; return FALSE; } return TRUE; }