loudmouth/src/lm-message.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       
     2 /*
       
     3  * Copyright (C) 2003 Imendio AB
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public License as
       
     7  * published by the Free Software Foundation; either version 2 of the
       
     8  * License, or (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this program; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 #include <config.h>
       
    22 #include <string.h>
       
    23 
       
    24 #include "lm-internals.h"
       
    25 #include "lm-message.h"
       
    26 
       
    27 #define PRIV(o) ((LmMessage *)o)->priv
       
    28 
       
    29 
       
    30 #ifdef EMULATOR
       
    31 #include "libloudmouth_wsd_solution.h"
       
    32 
       
    33 GET_STATIC_ARRAY_FROM_TLS(type_names, lm_message, TypeNames)
       
    34   #define type_names (GET_WSD_VAR_NAME(type_names, lm_message, s)())
       
    35   
       
    36 GET_STATIC_ARRAY_FROM_TLS(sub_type_names,lm_message,SubTypeNames)
       
    37 	#define sub_type_names (GET_WSD_VAR_NAME(sub_type_names,lm_message,s)())	
       
    38 
       
    39 
       
    40 #else
       
    41 static struct TypeNames 
       
    42 {
       
    43         LmMessageType  type;
       
    44         const gchar   *name;
       
    45 } type_names[] = {
       
    46 	{ LM_MESSAGE_TYPE_MESSAGE,         "message"         },
       
    47 	{ LM_MESSAGE_TYPE_PRESENCE,        "presence"        },
       
    48 	{ LM_MESSAGE_TYPE_IQ,              "iq"              },
       
    49 	{ LM_MESSAGE_TYPE_STREAM,          "stream:stream"   },
       
    50 	{ LM_MESSAGE_TYPE_STREAM_FEATURES, "stream:features" },
       
    51 	{ LM_MESSAGE_TYPE_STREAM_ERROR,    "stream:error"    },
       
    52 	{ LM_MESSAGE_TYPE_AUTH,            "auth"            },
       
    53 	{ LM_MESSAGE_TYPE_CHALLENGE,       "challenge"       },
       
    54 	{ LM_MESSAGE_TYPE_RESPONSE,        "response"        },
       
    55 	{ LM_MESSAGE_TYPE_SUCCESS,         "success"         },
       
    56 	{ LM_MESSAGE_TYPE_FAILURE,         "failure"         },
       
    57 	{ LM_MESSAGE_TYPE_PROCEED,         "proceed"         },
       
    58 	{ LM_MESSAGE_TYPE_STARTTLS,        "starttls"        },
       
    59 	{ LM_MESSAGE_TYPE_UNKNOWN,         NULL              }
       
    60 };
       
    61 
       
    62 static struct SubTypeNames 
       
    63 {
       
    64         LmMessageSubType  type;
       
    65         const gchar      *name;
       
    66 } sub_type_names[] = {
       
    67 	{ LM_MESSAGE_SUB_TYPE_NORMAL,          "normal"        },
       
    68         { LM_MESSAGE_SUB_TYPE_CHAT,            "chat"          },
       
    69 	{ LM_MESSAGE_SUB_TYPE_GROUPCHAT,       "groupchat"     },
       
    70 	{ LM_MESSAGE_SUB_TYPE_HEADLINE,        "headline"      },
       
    71 	{ LM_MESSAGE_SUB_TYPE_UNAVAILABLE,     "unavailable"   },
       
    72         { LM_MESSAGE_SUB_TYPE_PROBE,           "probe"         },
       
    73 	{ LM_MESSAGE_SUB_TYPE_SUBSCRIBE,       "subscribe"     },
       
    74 	{ LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE,     "unsubscribe"   },
       
    75 	{ LM_MESSAGE_SUB_TYPE_SUBSCRIBED,      "subscribed"    },
       
    76 	{ LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED,    "unsubscribed"  },
       
    77 	{ LM_MESSAGE_SUB_TYPE_GET,             "get"           },
       
    78 	{ LM_MESSAGE_SUB_TYPE_SET,             "set"           },
       
    79 	{ LM_MESSAGE_SUB_TYPE_RESULT,          "result"        }, 
       
    80 	{ LM_MESSAGE_SUB_TYPE_ERROR,           "error"         }
       
    81 };
       
    82 #endif
       
    83 
       
    84 struct LmMessagePriv {
       
    85 	LmMessageType    type;
       
    86 	LmMessageSubType sub_type;
       
    87 	gint             ref_count;
       
    88 };
       
    89 
       
    90 static LmMessageType
       
    91 message_type_from_string (const gchar *type_str)
       
    92 {
       
    93         gint i;
       
    94 
       
    95         if (!type_str) {
       
    96                 return LM_MESSAGE_TYPE_UNKNOWN;
       
    97         }
       
    98 
       
    99         for (i = LM_MESSAGE_TYPE_MESSAGE;
       
   100 	     i < LM_MESSAGE_TYPE_UNKNOWN;
       
   101 	     ++i) {
       
   102                 if (strcmp (type_str, type_names[i].name) == 0) {
       
   103                         return type_names[i].type;
       
   104                 }
       
   105         }
       
   106 
       
   107         return LM_MESSAGE_TYPE_UNKNOWN;
       
   108 }
       
   109 
       
   110 
       
   111 const gchar *
       
   112 _lm_message_type_to_string (LmMessageType type)
       
   113 {
       
   114         if (type < LM_MESSAGE_TYPE_MESSAGE ||
       
   115             type > LM_MESSAGE_TYPE_STARTTLS) {
       
   116                 type = LM_MESSAGE_TYPE_UNKNOWN;
       
   117         }
       
   118 
       
   119         return type_names[type].name;
       
   120 }
       
   121 
       
   122 static LmMessageSubType
       
   123 message_sub_type_from_string (const gchar *type_str)
       
   124 {
       
   125         gint i;
       
   126 
       
   127         if (!type_str) {
       
   128                 return LM_MESSAGE_SUB_TYPE_NOT_SET;
       
   129         }
       
   130 
       
   131         for (i = LM_MESSAGE_SUB_TYPE_NORMAL;
       
   132 	     i <= LM_MESSAGE_SUB_TYPE_ERROR;
       
   133 	     ++i) {
       
   134                 if (g_ascii_strcasecmp (type_str, 
       
   135 					sub_type_names[i].name) == 0) {
       
   136                         return i;
       
   137                 }
       
   138         }
       
   139 
       
   140         return LM_MESSAGE_SUB_TYPE_NOT_SET;
       
   141 }
       
   142 
       
   143 const gchar *
       
   144 _lm_message_sub_type_to_string (LmMessageSubType type)
       
   145 {
       
   146         if (type < LM_MESSAGE_SUB_TYPE_NORMAL ||
       
   147             type > LM_MESSAGE_SUB_TYPE_ERROR) {
       
   148 		return NULL;
       
   149         }
       
   150 
       
   151         return sub_type_names[type].name;
       
   152 }
       
   153 
       
   154 static LmMessageSubType
       
   155 message_sub_type_when_unset (LmMessageType type) {
       
   156 	LmMessageSubType sub_type = LM_MESSAGE_SUB_TYPE_NORMAL;
       
   157 
       
   158 	switch (type) {
       
   159 	case LM_MESSAGE_TYPE_MESSAGE:
       
   160 		/* A message without type should be handled like a message with
       
   161 		 * type=normal, but we won't set it to that since then the user
       
   162 		 * will not know if it's set or not.
       
   163 		 */
       
   164 		sub_type = LM_MESSAGE_SUB_TYPE_NOT_SET;
       
   165 		break;
       
   166 	case LM_MESSAGE_TYPE_PRESENCE:
       
   167 		sub_type = LM_MESSAGE_SUB_TYPE_AVAILABLE;
       
   168 		break;
       
   169 	case LM_MESSAGE_TYPE_IQ:
       
   170 		sub_type = LM_MESSAGE_SUB_TYPE_GET;
       
   171 		break;
       
   172 	default:
       
   173 		break;
       
   174 	}
       
   175 
       
   176 	return sub_type;
       
   177 }
       
   178 
       
   179 LmMessage *
       
   180 _lm_message_new_from_node (LmMessageNode *node)
       
   181 {
       
   182 	LmMessage        *m;
       
   183 	LmMessageType     type;
       
   184 	LmMessageSubType  sub_type;
       
   185 	const gchar      *sub_type_str;
       
   186 	
       
   187 	type = message_type_from_string (node->name);
       
   188 
       
   189 	if (type == LM_MESSAGE_TYPE_UNKNOWN) {
       
   190 		return NULL;
       
   191 	}
       
   192 
       
   193 	sub_type_str = lm_message_node_get_attribute (node, "type");
       
   194 	if (sub_type_str) {
       
   195 		sub_type = message_sub_type_from_string (sub_type_str);
       
   196 	} else {
       
   197 		sub_type = message_sub_type_when_unset (type);
       
   198 	}
       
   199 
       
   200 	m = g_new0 (LmMessage, 1);
       
   201 	m->priv = g_new0 (LmMessagePriv, 1);
       
   202 	
       
   203 	PRIV(m)->ref_count = 1;
       
   204 	PRIV(m)->type = type;
       
   205 	PRIV(m)->sub_type = sub_type;
       
   206 	
       
   207 	m->node = lm_message_node_ref (node);
       
   208 	
       
   209 	return m;
       
   210 }
       
   211 
       
   212 /**
       
   213  * lm_message_new:
       
   214  * @to: receipient jid
       
   215  * @type: message type
       
   216  * 
       
   217  * Creates a new #LmMessage which can be sent with lm_connection_send() or 
       
   218  * lm_connection_send_with_reply(). If @to is %NULL the message is sent to the
       
   219  * server. The returned message should be unreferenced with lm_message_unref() 
       
   220  * when caller is finished with it.
       
   221  * 
       
   222  * Return value: a newly created #LmMessage
       
   223  **/
       
   224 EXPORT_C LmMessage *
       
   225 lm_message_new (const gchar *to, LmMessageType type)
       
   226 {
       
   227 	LmMessage *m;
       
   228 	gchar     *id;
       
   229 
       
   230 	m       = g_new0 (LmMessage, 1);
       
   231 	m->priv = g_new0 (LmMessagePriv, 1);
       
   232 
       
   233 	PRIV(m)->ref_count = 1;
       
   234 	PRIV(m)->type      = type;
       
   235 	PRIV(m)->sub_type  = message_sub_type_when_unset (type);
       
   236 	
       
   237 	m->node = _lm_message_node_new (_lm_message_type_to_string (type));
       
   238 
       
   239 	id = _lm_utils_generate_id ();
       
   240 	lm_message_node_set_attribute (m->node, "id", id);
       
   241 	g_free (id);
       
   242 	
       
   243 	if (to) {
       
   244 		lm_message_node_set_attribute (m->node, "to", to);
       
   245 	}
       
   246 
       
   247 	if (type == LM_MESSAGE_TYPE_IQ) {
       
   248 		lm_message_node_set_attribute (m->node, "type", "get");
       
   249 	}
       
   250 	
       
   251 	return m;
       
   252 }
       
   253 
       
   254 /**
       
   255  * lm_message_new_with_sub_type:
       
   256  * @to: receipient jid
       
   257  * @type: message type
       
   258  * @sub_type: message sub type
       
   259  * 
       
   260  * Creates a new #LmMessage with sub type set. See lm_message_new() for more 
       
   261  * information.
       
   262  * 
       
   263  * Return value: a newly created #LmMessage
       
   264  **/
       
   265 EXPORT_C LmMessage *
       
   266 lm_message_new_with_sub_type (const gchar      *to,
       
   267 			      LmMessageType     type, 
       
   268 			      LmMessageSubType  sub_type)
       
   269 {
       
   270 	LmMessage   *m;
       
   271 	const gchar *type_str;
       
   272 
       
   273 	m = lm_message_new (to, type);
       
   274 
       
   275 	type_str = _lm_message_sub_type_to_string (sub_type);
       
   276 
       
   277 	if (type_str) {
       
   278 		lm_message_node_set_attributes (m->node,
       
   279 						"type", type_str, NULL);
       
   280 		PRIV(m)->sub_type = sub_type;
       
   281 	}
       
   282 
       
   283 	return m;
       
   284 }
       
   285 
       
   286 /**
       
   287  * lm_message_get_type:
       
   288  * @message: an #LmMessage
       
   289  * 
       
   290  * Fetches the type of @message.
       
   291  * 
       
   292  * Return value: the message type
       
   293  **/
       
   294 EXPORT_C LmMessageType
       
   295 lm_message_get_type (LmMessage *message)
       
   296 {
       
   297 	g_return_val_if_fail (message != NULL, LM_MESSAGE_TYPE_UNKNOWN);
       
   298 	
       
   299 	return PRIV(message)->type;
       
   300 }
       
   301 
       
   302 /**
       
   303  * lm_message_get_sub_type:
       
   304  * @message: 
       
   305  * 
       
   306  * Fetches the sub type of @message.
       
   307  * 
       
   308  * Return value: the message sub type
       
   309  **/
       
   310 EXPORT_C LmMessageSubType
       
   311 lm_message_get_sub_type (LmMessage *message)
       
   312 {
       
   313 	g_return_val_if_fail (message != NULL, LM_MESSAGE_TYPE_UNKNOWN);
       
   314 	
       
   315 	return PRIV(message)->sub_type;
       
   316 }
       
   317 
       
   318 /**
       
   319  * lm_message_get_node:
       
   320  * @message: an #LmMessage
       
   321  * 
       
   322  * Retrieves the root node from @message.
       
   323  * 
       
   324  * Return value: an #LmMessageNode
       
   325  **/
       
   326 EXPORT_C LmMessageNode *
       
   327 lm_message_get_node (LmMessage *message)
       
   328 {
       
   329 	g_return_val_if_fail (message != NULL, NULL);
       
   330 	
       
   331 	return message->node;
       
   332 }
       
   333 
       
   334 /**
       
   335  * lm_message_ref:
       
   336  * @message: an #LmMessage
       
   337  * 
       
   338  * Adds a reference to @message.
       
   339  * 
       
   340  * Return value: the message
       
   341  **/
       
   342 EXPORT_C LmMessage *
       
   343 lm_message_ref (LmMessage *message)
       
   344 {
       
   345 	g_return_val_if_fail (message != NULL, NULL);
       
   346 	
       
   347 	PRIV(message)->ref_count++;
       
   348 	
       
   349 	return message;
       
   350 }
       
   351 
       
   352 /**
       
   353  * lm_message_unref:
       
   354  * @message: an #LmMessage
       
   355  * 
       
   356  * Removes a reference from @message. When no more references are present the 
       
   357  * message is freed.
       
   358  **/
       
   359 EXPORT_C void
       
   360 lm_message_unref (LmMessage *message)
       
   361 {
       
   362 	//g_return_if_fail (message != NULL);
       
   363 	if(message==NULL)
       
   364 		return;
       
   365 	
       
   366 	PRIV(message)->ref_count--;
       
   367 	
       
   368 	if (PRIV(message)->ref_count == 0) {
       
   369 		lm_message_node_unref (message->node);
       
   370 		g_free (message->priv);
       
   371 		g_free (message);
       
   372 	}
       
   373 }