diff -r 09b375e9ce32 -r ab4470465a0c lm_message.c --- a/lm_message.c Fri Mar 27 09:43:41 2009 +0200 +++ b/lm_message.c Sun Apr 05 14:55:51 2009 +0300 @@ -2,6 +2,7 @@ #include #include #include +#include #include "config.h" #include "util.h" @@ -12,7 +13,7 @@ /// Module, representing individual message. /// Message have a type and optionally a sub type. /// Message have a set common methods with message node, -/// these are next, prev, children, parent, value, child, +/// these are name, next, prev, children, parent, value, child, /// find_child, attribute, raw, xml and path. They just save /// you typing :node() each time and save memory for /// one node object. @@ -40,7 +41,7 @@ { "stream:features", LM_MESSAGE_TYPE_STREAM_FEATURES }, { "stream_error", LM_MESSAGE_TYPE_STREAM_ERROR }, { "stream_features", LM_MESSAGE_TYPE_STREAM_FEATURES }, - { NULL, 0 }, + { NULL, LM_MESSAGE_TYPE_MESSAGE }, }; /// message sub type @@ -64,7 +65,7 @@ { "result", LM_MESSAGE_SUB_TYPE_RESULT }, { "error", LM_MESSAGE_SUB_TYPE_ERROR }, { "not_set", LM_MESSAGE_SUB_TYPE_NOT_SET }, - { NULL, 0 }, + { NULL, LM_MESSAGE_SUB_TYPE_NOT_SET }, }; /// lm.message.new @@ -91,6 +92,111 @@ return 1; } +/// message table +/// Table describes xml structure of the message, the only exception is mtype key of root table. +/// mtype is a string of form "-", eg "iq-set". +/// Best way to learn how this table is organized, is just to look at next example: +/// [ lm.message.create { mtype = 'iq-result', to = 'foo@bar.xyz', +/// command = { xmlns = 'http://jabber.org/protocol/commands', node = 'http://jabber.org/protocol/rc#set-status', status = 'executing', sessionid = 'set-status:aaa3', +/// x = { xmlns = 'jabber:x:data', type = 'form', +/// title = { "Change Status" }, +/// instructions = { "Choose the status and status message" }, +/// field = {{ type = 'hidden', var = 'FORM_TYPE', +/// value = { "http://jabber.org/protocol/rc" }, +/// },{ type = 'list-single', label = 'Status', var = 'status', +/// required = { }, +/// value = { "online" }, +/// option = {{ label = 'Chat', +/// value = { "chat" }, +/// },{ label = 'Online', +/// value = { "online" }, +/// },{ label = 'Away', +/// value = { "away" }, +/// },{ label = 'Extended Away', +/// value = { "xa" }, +/// },{ label = 'Do Not Disturb', +/// value = { "dnd" }, +/// },{ label = 'Invisible', +/// value = { "invisible" }, +/// },{ label = 'Offline', +/// value = { "offline" }, +/// }}, +/// },{ type = 'text-single', label = 'Priority', var = 'status-priority', +/// value = { "5" }, +/// },{ type = 'text-multi', label = 'Message', var = 'status-message' }}, +/// }, +/// }, +/// } +/// ] +static void fill_lm_node (lua_State *L, LmMessageNode *node, int index) +{ + int top = lua_gettop (L); // 0 + for (lua_pushnil (L); lua_next (L, index) != 0; lua_pop (L, lua_gettop (L) - top - 1)) // 2 value + if (lua_type (L, top + 2) == LUA_TTABLE) { + const char *name = lua_tostring (L, top + 1); + lua_pushinteger (L, 1); // 3 1 + lua_gettable (L, top + 2); // 3 value[1] + if (lua_type (L, top + 3) == LUA_TTABLE) { + int i = 1; + do { + fill_lm_node (L, lm_message_node_add_child (node, name, NULL), top + 3); + lua_pop (L, 1); // 2 value + lua_pushinteger (L, ++i); // 3 i + lua_gettable (L, top + 2); // 3 value[i] + } while (lua_type (L, top + 3) == LUA_TTABLE); + } else + fill_lm_node (L, lm_message_node_add_child (node, name, NULL), top + 2); + } else if (lua_type (L, top + 1) == LUA_TNUMBER && lua_tointeger (L, top + 1) == 1) + lm_message_node_set_value (node, lua_tostring (L, top + 2)); + else + lm_message_node_set_attribute (node, lua_tostring (L, top + 1), lua_tostring (L, top + 2)); +} + +/// lm.message.create +/// Creates new message object and fills it from message table. +/// Note, that table fields are not checked for their types, so, on wrong input results may be undefined. +/// A: message table +/// R: lm message object +static int create_lm_message (lua_State *L) +{ + const char *mtype; + const char *st; + const char *to = NULL; + LmMessage *message; + luaL_checktype (L, 1, LUA_TTABLE); + + lua_getfield (L, 1, "mtype"); + mtype = lua_tostring (L, -1); + st = strchr (mtype, '-'); + + lua_getfield (L, 1, "to"); + if (lua_type (L, -1) == LUA_TSTRING) + to = lua_tostring (L, -1); + + if (st) { + LmMessageType mt; + lua_pushlstring (L, mtype, st - mtype); + mt = luaL_checkenum (L, -1, type_lm_message); + lua_pop (L, 1); + message = lm_message_new_with_sub_type (to, mt, string2enum (st + 1, sub_type_lm_message)); + } else + message = lm_message_new (to, luaL_checkenum (L, -2, type_lm_message)); + + lua_pop (L, 2); + lua_pushnil (L); + lua_setfield (L, 1, "mtype"); + lua_pushnil (L); + lua_setfield (L, 1, "to"); + + fill_lm_node (L, lm_message_get_node (message), 1); + + bless_lm_message (L, message); + lm_message_unref (message); + D ("Message %X created", (int) message); + + return 1; +} + /// lm.message.bless /// Blesses given pointer to lm message object. /// A: lightuserdata (C lm message object) @@ -144,15 +250,17 @@ } static const luaL_Reg reg_f_lm_message[] = { - { "new", new_lm_message }, - { "bless", bless_lua_lm_message }, - { NULL, NULL }, + { "new", new_lm_message }, + { "create", create_lm_message }, + { "bless", bless_lua_lm_message }, + { NULL, NULL }, }; static const luaL_Reg reg_m_lm_message[] = { { "node", node_lm_message }, { "type", kind_lm_message }, // These methods are common for message and message node + { "name", name_lm_node }, { "next", next_lm_node }, { "prev", prev_lm_node }, { "children", children_lm_node },