/*-
* $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 <jonas@codefactory.se>
* Copyright (c) 2002 Daniel Lundin <daniel@codefactory.se>
* Copyright (c) 2002 CodeFactory AB. All rights reserved.
*/
#include <librr/rr.h>
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
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
"<close number='%d' code='%03d'",
mclose->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</close>\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;
}
syntax highlighted by Code2HTML, v. 0.9.1