--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/src/lm-message.c Tue Feb 02 01:10:06 2010 +0200
@@ -0,0 +1,373 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "lm-internals.h"
+#include "lm-message.h"
+
+#define PRIV(o) ((LmMessage *)o)->priv
+
+
+#ifdef EMULATOR
+#include "libloudmouth_wsd_solution.h"
+
+GET_STATIC_ARRAY_FROM_TLS(type_names, lm_message, TypeNames)
+ #define type_names (GET_WSD_VAR_NAME(type_names, lm_message, s)())
+
+GET_STATIC_ARRAY_FROM_TLS(sub_type_names,lm_message,SubTypeNames)
+ #define sub_type_names (GET_WSD_VAR_NAME(sub_type_names,lm_message,s)())
+
+
+#else
+static struct TypeNames
+{
+ LmMessageType type;
+ const gchar *name;
+} type_names[] = {
+ { LM_MESSAGE_TYPE_MESSAGE, "message" },
+ { LM_MESSAGE_TYPE_PRESENCE, "presence" },
+ { LM_MESSAGE_TYPE_IQ, "iq" },
+ { LM_MESSAGE_TYPE_STREAM, "stream:stream" },
+ { LM_MESSAGE_TYPE_STREAM_FEATURES, "stream:features" },
+ { LM_MESSAGE_TYPE_STREAM_ERROR, "stream:error" },
+ { LM_MESSAGE_TYPE_AUTH, "auth" },
+ { LM_MESSAGE_TYPE_CHALLENGE, "challenge" },
+ { LM_MESSAGE_TYPE_RESPONSE, "response" },
+ { LM_MESSAGE_TYPE_SUCCESS, "success" },
+ { LM_MESSAGE_TYPE_FAILURE, "failure" },
+ { LM_MESSAGE_TYPE_PROCEED, "proceed" },
+ { LM_MESSAGE_TYPE_STARTTLS, "starttls" },
+ { LM_MESSAGE_TYPE_UNKNOWN, NULL }
+};
+
+static struct SubTypeNames
+{
+ LmMessageSubType type;
+ const gchar *name;
+} sub_type_names[] = {
+ { LM_MESSAGE_SUB_TYPE_NORMAL, "normal" },
+ { LM_MESSAGE_SUB_TYPE_CHAT, "chat" },
+ { LM_MESSAGE_SUB_TYPE_GROUPCHAT, "groupchat" },
+ { LM_MESSAGE_SUB_TYPE_HEADLINE, "headline" },
+ { LM_MESSAGE_SUB_TYPE_UNAVAILABLE, "unavailable" },
+ { LM_MESSAGE_SUB_TYPE_PROBE, "probe" },
+ { LM_MESSAGE_SUB_TYPE_SUBSCRIBE, "subscribe" },
+ { LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE, "unsubscribe" },
+ { LM_MESSAGE_SUB_TYPE_SUBSCRIBED, "subscribed" },
+ { LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED, "unsubscribed" },
+ { LM_MESSAGE_SUB_TYPE_GET, "get" },
+ { LM_MESSAGE_SUB_TYPE_SET, "set" },
+ { LM_MESSAGE_SUB_TYPE_RESULT, "result" },
+ { LM_MESSAGE_SUB_TYPE_ERROR, "error" }
+};
+#endif
+
+struct LmMessagePriv {
+ LmMessageType type;
+ LmMessageSubType sub_type;
+ gint ref_count;
+};
+
+static LmMessageType
+message_type_from_string (const gchar *type_str)
+{
+ gint i;
+
+ if (!type_str) {
+ return LM_MESSAGE_TYPE_UNKNOWN;
+ }
+
+ for (i = LM_MESSAGE_TYPE_MESSAGE;
+ i < LM_MESSAGE_TYPE_UNKNOWN;
+ ++i) {
+ if (strcmp (type_str, type_names[i].name) == 0) {
+ return type_names[i].type;
+ }
+ }
+
+ return LM_MESSAGE_TYPE_UNKNOWN;
+}
+
+
+const gchar *
+_lm_message_type_to_string (LmMessageType type)
+{
+ if (type < LM_MESSAGE_TYPE_MESSAGE ||
+ type > LM_MESSAGE_TYPE_STARTTLS) {
+ type = LM_MESSAGE_TYPE_UNKNOWN;
+ }
+
+ return type_names[type].name;
+}
+
+static LmMessageSubType
+message_sub_type_from_string (const gchar *type_str)
+{
+ gint i;
+
+ if (!type_str) {
+ return LM_MESSAGE_SUB_TYPE_NOT_SET;
+ }
+
+ for (i = LM_MESSAGE_SUB_TYPE_NORMAL;
+ i <= LM_MESSAGE_SUB_TYPE_ERROR;
+ ++i) {
+ if (g_ascii_strcasecmp (type_str,
+ sub_type_names[i].name) == 0) {
+ return i;
+ }
+ }
+
+ return LM_MESSAGE_SUB_TYPE_NOT_SET;
+}
+
+const gchar *
+_lm_message_sub_type_to_string (LmMessageSubType type)
+{
+ if (type < LM_MESSAGE_SUB_TYPE_NORMAL ||
+ type > LM_MESSAGE_SUB_TYPE_ERROR) {
+ return NULL;
+ }
+
+ return sub_type_names[type].name;
+}
+
+static LmMessageSubType
+message_sub_type_when_unset (LmMessageType type) {
+ LmMessageSubType sub_type = LM_MESSAGE_SUB_TYPE_NORMAL;
+
+ switch (type) {
+ case LM_MESSAGE_TYPE_MESSAGE:
+ /* A message without type should be handled like a message with
+ * type=normal, but we won't set it to that since then the user
+ * will not know if it's set or not.
+ */
+ sub_type = LM_MESSAGE_SUB_TYPE_NOT_SET;
+ break;
+ case LM_MESSAGE_TYPE_PRESENCE:
+ sub_type = LM_MESSAGE_SUB_TYPE_AVAILABLE;
+ break;
+ case LM_MESSAGE_TYPE_IQ:
+ sub_type = LM_MESSAGE_SUB_TYPE_GET;
+ break;
+ default:
+ break;
+ }
+
+ return sub_type;
+}
+
+LmMessage *
+_lm_message_new_from_node (LmMessageNode *node)
+{
+ LmMessage *m;
+ LmMessageType type;
+ LmMessageSubType sub_type;
+ const gchar *sub_type_str;
+
+ type = message_type_from_string (node->name);
+
+ if (type == LM_MESSAGE_TYPE_UNKNOWN) {
+ return NULL;
+ }
+
+ sub_type_str = lm_message_node_get_attribute (node, "type");
+ if (sub_type_str) {
+ sub_type = message_sub_type_from_string (sub_type_str);
+ } else {
+ sub_type = message_sub_type_when_unset (type);
+ }
+
+ m = g_new0 (LmMessage, 1);
+ m->priv = g_new0 (LmMessagePriv, 1);
+
+ PRIV(m)->ref_count = 1;
+ PRIV(m)->type = type;
+ PRIV(m)->sub_type = sub_type;
+
+ m->node = lm_message_node_ref (node);
+
+ return m;
+}
+
+/**
+ * lm_message_new:
+ * @to: receipient jid
+ * @type: message type
+ *
+ * Creates a new #LmMessage which can be sent with lm_connection_send() or
+ * lm_connection_send_with_reply(). If @to is %NULL the message is sent to the
+ * server. The returned message should be unreferenced with lm_message_unref()
+ * when caller is finished with it.
+ *
+ * Return value: a newly created #LmMessage
+ **/
+EXPORT_C LmMessage *
+lm_message_new (const gchar *to, LmMessageType type)
+{
+ LmMessage *m;
+ gchar *id;
+
+ m = g_new0 (LmMessage, 1);
+ m->priv = g_new0 (LmMessagePriv, 1);
+
+ PRIV(m)->ref_count = 1;
+ PRIV(m)->type = type;
+ PRIV(m)->sub_type = message_sub_type_when_unset (type);
+
+ m->node = _lm_message_node_new (_lm_message_type_to_string (type));
+
+ id = _lm_utils_generate_id ();
+ lm_message_node_set_attribute (m->node, "id", id);
+ g_free (id);
+
+ if (to) {
+ lm_message_node_set_attribute (m->node, "to", to);
+ }
+
+ if (type == LM_MESSAGE_TYPE_IQ) {
+ lm_message_node_set_attribute (m->node, "type", "get");
+ }
+
+ return m;
+}
+
+/**
+ * lm_message_new_with_sub_type:
+ * @to: receipient jid
+ * @type: message type
+ * @sub_type: message sub type
+ *
+ * Creates a new #LmMessage with sub type set. See lm_message_new() for more
+ * information.
+ *
+ * Return value: a newly created #LmMessage
+ **/
+EXPORT_C LmMessage *
+lm_message_new_with_sub_type (const gchar *to,
+ LmMessageType type,
+ LmMessageSubType sub_type)
+{
+ LmMessage *m;
+ const gchar *type_str;
+
+ m = lm_message_new (to, type);
+
+ type_str = _lm_message_sub_type_to_string (sub_type);
+
+ if (type_str) {
+ lm_message_node_set_attributes (m->node,
+ "type", type_str, NULL);
+ PRIV(m)->sub_type = sub_type;
+ }
+
+ return m;
+}
+
+/**
+ * lm_message_get_type:
+ * @message: an #LmMessage
+ *
+ * Fetches the type of @message.
+ *
+ * Return value: the message type
+ **/
+EXPORT_C LmMessageType
+lm_message_get_type (LmMessage *message)
+{
+ g_return_val_if_fail (message != NULL, LM_MESSAGE_TYPE_UNKNOWN);
+
+ return PRIV(message)->type;
+}
+
+/**
+ * lm_message_get_sub_type:
+ * @message:
+ *
+ * Fetches the sub type of @message.
+ *
+ * Return value: the message sub type
+ **/
+EXPORT_C LmMessageSubType
+lm_message_get_sub_type (LmMessage *message)
+{
+ g_return_val_if_fail (message != NULL, LM_MESSAGE_TYPE_UNKNOWN);
+
+ return PRIV(message)->sub_type;
+}
+
+/**
+ * lm_message_get_node:
+ * @message: an #LmMessage
+ *
+ * Retrieves the root node from @message.
+ *
+ * Return value: an #LmMessageNode
+ **/
+EXPORT_C LmMessageNode *
+lm_message_get_node (LmMessage *message)
+{
+ g_return_val_if_fail (message != NULL, NULL);
+
+ return message->node;
+}
+
+/**
+ * lm_message_ref:
+ * @message: an #LmMessage
+ *
+ * Adds a reference to @message.
+ *
+ * Return value: the message
+ **/
+EXPORT_C LmMessage *
+lm_message_ref (LmMessage *message)
+{
+ g_return_val_if_fail (message != NULL, NULL);
+
+ PRIV(message)->ref_count++;
+
+ return message;
+}
+
+/**
+ * lm_message_unref:
+ * @message: an #LmMessage
+ *
+ * Removes a reference from @message. When no more references are present the
+ * message is freed.
+ **/
+EXPORT_C void
+lm_message_unref (LmMessage *message)
+{
+ //g_return_if_fail (message != NULL);
+ if(message==NULL)
+ return;
+
+ PRIV(message)->ref_count--;
+
+ if (PRIV(message)->ref_count == 0) {
+ lm_message_node_unref (message->node);
+ g_free (message->priv);
+ g_free (message);
+ }
+}