lm_message.c
changeset 17 ab4470465a0c
parent 16 09b375e9ce32
child 18 6effa1929af7
equal deleted inserted replaced
16:09b375e9ce32 17:ab4470465a0c
     1 
     1 
     2 #include <lua.h>
     2 #include <lua.h>
     3 #include <lauxlib.h>
     3 #include <lauxlib.h>
     4 #include <loudmouth/loudmouth.h>
     4 #include <loudmouth/loudmouth.h>
       
     5 #include <string.h>
     5 
     6 
     6 #include "config.h"
     7 #include "config.h"
     7 #include "util.h"
     8 #include "util.h"
     8 #include "lm_types.h"
     9 #include "lm_types.h"
     9 #include "lm_message_node.h"
    10 #include "lm_message_node.h"
    10 
    11 
    11 /// lm.message
    12 /// lm.message
    12 /// Module, representing individual message.
    13 /// Module, representing individual message.
    13 /// Message have a type and optionally a sub type.
    14 /// Message have a type and optionally a sub type.
    14 /// Message have a set common methods with message node,
    15 /// Message have a set common methods with message node,
    15 /// these are next, prev, children, parent, value, child,
    16 /// these are name, next, prev, children, parent, value, child,
    16 /// find_child, attribute, raw, xml and path. They just save
    17 /// find_child, attribute, raw, xml and path. They just save
    17 /// you typing :node() each time and save memory for
    18 /// you typing :node() each time and save memory for
    18 /// one node object.
    19 /// one node object.
    19 
    20 
    20 /// message type
    21 /// message type
    38 	{ "stream:stream",   LM_MESSAGE_TYPE_STREAM          },
    39 	{ "stream:stream",   LM_MESSAGE_TYPE_STREAM          },
    39 	{ "stream:error",    LM_MESSAGE_TYPE_STREAM_ERROR    },
    40 	{ "stream:error",    LM_MESSAGE_TYPE_STREAM_ERROR    },
    40 	{ "stream:features", LM_MESSAGE_TYPE_STREAM_FEATURES },
    41 	{ "stream:features", LM_MESSAGE_TYPE_STREAM_FEATURES },
    41 	{ "stream_error",    LM_MESSAGE_TYPE_STREAM_ERROR    },
    42 	{ "stream_error",    LM_MESSAGE_TYPE_STREAM_ERROR    },
    42 	{ "stream_features", LM_MESSAGE_TYPE_STREAM_FEATURES },
    43 	{ "stream_features", LM_MESSAGE_TYPE_STREAM_FEATURES },
    43 	{ NULL,              0                               },
    44 	{ NULL,              LM_MESSAGE_TYPE_MESSAGE         },
    44 };
    45 };
    45 
    46 
    46 /// message sub type
    47 /// message sub type
    47 /// Message subtype, not all combinations of type and subtype are possible.
    48 /// Message subtype, not all combinations of type and subtype are possible.
    48 /// G:
    49 /// G:
    62 	{ "get",           LM_MESSAGE_SUB_TYPE_GET          },
    63 	{ "get",           LM_MESSAGE_SUB_TYPE_GET          },
    63 	{ "set",           LM_MESSAGE_SUB_TYPE_SET          },
    64 	{ "set",           LM_MESSAGE_SUB_TYPE_SET          },
    64 	{ "result",        LM_MESSAGE_SUB_TYPE_RESULT       },
    65 	{ "result",        LM_MESSAGE_SUB_TYPE_RESULT       },
    65 	{ "error",         LM_MESSAGE_SUB_TYPE_ERROR        },
    66 	{ "error",         LM_MESSAGE_SUB_TYPE_ERROR        },
    66 	{ "not_set",       LM_MESSAGE_SUB_TYPE_NOT_SET      },
    67 	{ "not_set",       LM_MESSAGE_SUB_TYPE_NOT_SET      },
    67 	{ NULL,            0                                },
    68 	{ NULL,            LM_MESSAGE_SUB_TYPE_NOT_SET      },
    68 };
    69 };
    69 
    70 
    70 /// lm.message.new
    71 /// lm.message.new
    71 /// Creates new message object.
    72 /// Creates new message object.
    72 /// Note: you can specify nil as to argument to send message to server.
    73 /// Note: you can specify nil as to argument to send message to server.
    89 	lm_message_unref (message);
    90 	lm_message_unref (message);
    90 	D ("Message %X created", (int) message);
    91 	D ("Message %X created", (int) message);
    91 	return 1;
    92 	return 1;
    92 }
    93 }
    93 
    94 
       
    95 /// message table
       
    96 /// Table describes xml structure of the message, the only exception is mtype key of root table.
       
    97 /// mtype is a string of form "<message type>-<message sub type>", eg "iq-set".
       
    98 /// Best way to learn how this table is organized, is just to look at next example:
       
    99 /// [ lm.message.create { mtype = 'iq-result', to = 'foo@bar.xyz',
       
   100 /// 	command = { xmlns = 'http://jabber.org/protocol/commands', node = 'http://jabber.org/protocol/rc#set-status', status = 'executing', sessionid = 'set-status:aaa3',
       
   101 /// 		x = { xmlns = 'jabber:x:data', type = 'form',
       
   102 /// 			title = { "Change Status" },
       
   103 /// 			instructions = { "Choose the status and status message" },
       
   104 /// 			field = {{ type = 'hidden', var = 'FORM_TYPE',
       
   105 /// 				value = { "http://jabber.org/protocol/rc" },
       
   106 /// 			},{ type = 'list-single', label = 'Status', var = 'status',
       
   107 /// 				required = { },
       
   108 /// 				value = { "online" },
       
   109 /// 				option = {{ label = 'Chat',
       
   110 /// 					value = { "chat" },
       
   111 /// 				},{ label = 'Online',
       
   112 /// 					value = { "online" },
       
   113 /// 				},{ label = 'Away',
       
   114 /// 					value = { "away" },
       
   115 /// 				},{ label = 'Extended Away',
       
   116 /// 					value = { "xa" },
       
   117 /// 				},{ label = 'Do Not Disturb',
       
   118 /// 					value = { "dnd" },
       
   119 /// 				},{ label = 'Invisible',
       
   120 /// 					value = { "invisible" },
       
   121 /// 				},{ label = 'Offline',
       
   122 /// 					value = { "offline" },
       
   123 /// 				}},
       
   124 /// 			},{ type = 'text-single', label = 'Priority', var = 'status-priority',
       
   125 /// 				value = { "5" },
       
   126 /// 			},{ type = 'text-multi', label = 'Message', var = 'status-message' }},
       
   127 /// 		},
       
   128 /// 	},
       
   129 /// }
       
   130 /// ]
       
   131 static void fill_lm_node (lua_State *L, LmMessageNode *node, int index)
       
   132 {
       
   133 	int top = lua_gettop (L); // 0
       
   134 	for (lua_pushnil (L); lua_next (L, index) != 0; lua_pop (L, lua_gettop (L) - top - 1)) // 2 value
       
   135 		if (lua_type (L, top + 2) == LUA_TTABLE) {
       
   136 			const char *name = lua_tostring (L, top + 1);
       
   137 			lua_pushinteger (L, 1); // 3 1
       
   138 			lua_gettable (L, top + 2); // 3 value[1]
       
   139 			if (lua_type (L, top + 3) == LUA_TTABLE) {
       
   140 				int i = 1;
       
   141 				do {
       
   142 					fill_lm_node (L, lm_message_node_add_child (node, name, NULL), top + 3);
       
   143 					lua_pop (L, 1); // 2 value
       
   144 					lua_pushinteger (L, ++i); // 3 i
       
   145 					lua_gettable (L, top + 2); // 3 value[i]
       
   146 				} while (lua_type (L, top + 3) == LUA_TTABLE);
       
   147 			} else
       
   148 				fill_lm_node (L, lm_message_node_add_child (node, name, NULL), top + 2);
       
   149 		} else if (lua_type (L, top + 1) == LUA_TNUMBER && lua_tointeger (L, top + 1) == 1)
       
   150 			lm_message_node_set_value (node, lua_tostring (L, top + 2));
       
   151 		else
       
   152 			lm_message_node_set_attribute (node, lua_tostring (L, top + 1), lua_tostring (L, top + 2));
       
   153 }
       
   154 
       
   155 /// lm.message.create
       
   156 /// Creates new message object and fills it from message table.
       
   157 /// Note, that table fields are not checked for their types, so, on wrong input results may be undefined.
       
   158 /// A: message table
       
   159 /// R: lm message object
       
   160 static int create_lm_message (lua_State *L)
       
   161 {
       
   162 	const char *mtype;
       
   163 	const char *st;
       
   164 	const char *to      = NULL;
       
   165 	LmMessage  *message;
       
   166 	luaL_checktype (L, 1, LUA_TTABLE);
       
   167 
       
   168 	lua_getfield (L, 1, "mtype");
       
   169 	mtype = lua_tostring (L, -1);
       
   170 	st    = strchr (mtype, '-');
       
   171 
       
   172 	lua_getfield (L, 1, "to");
       
   173 	if (lua_type (L, -1) == LUA_TSTRING)
       
   174 		to = lua_tostring (L, -1);
       
   175 
       
   176 	if (st) {
       
   177 		LmMessageType mt;
       
   178 		lua_pushlstring (L, mtype, st - mtype);
       
   179 		mt = luaL_checkenum (L, -1, type_lm_message);
       
   180 		lua_pop (L, 1);
       
   181 		message = lm_message_new_with_sub_type (to, mt, string2enum (st + 1, sub_type_lm_message));
       
   182 	} else
       
   183 		message = lm_message_new (to, luaL_checkenum (L, -2, type_lm_message));
       
   184 
       
   185 	lua_pop (L, 2);
       
   186 	lua_pushnil (L);
       
   187 	lua_setfield (L, 1, "mtype");
       
   188 	lua_pushnil (L);
       
   189 	lua_setfield (L, 1, "to");
       
   190 
       
   191 	fill_lm_node (L, lm_message_get_node (message), 1);
       
   192 
       
   193 	bless_lm_message (L, message);
       
   194 	lm_message_unref (message);
       
   195 	D ("Message %X created", (int) message);
       
   196 
       
   197 	return 1;
       
   198 }
       
   199 
    94 /// lm.message.bless
   200 /// lm.message.bless
    95 /// Blesses given pointer to lm message object.
   201 /// Blesses given pointer to lm message object.
    96 /// A: lightuserdata (C lm message object)
   202 /// A: lightuserdata (C lm message object)
    97 /// R: lm message object
   203 /// R: lm message object
    98 static int bless_lua_lm_message (lua_State *L)
   204 static int bless_lua_lm_message (lua_State *L)
   142 	lm_message_unref (message->message);
   248 	lm_message_unref (message->message);
   143 	return 0;
   249 	return 0;
   144 }
   250 }
   145 
   251 
   146 static const luaL_Reg reg_f_lm_message[] = {
   252 static const luaL_Reg reg_f_lm_message[] = {
   147 	{ "new",   new_lm_message       },
   253 	{ "new",    new_lm_message       },
   148 	{ "bless", bless_lua_lm_message },
   254 	{ "create", create_lm_message    },
   149 	{ NULL,    NULL                 },
   255 	{ "bless",  bless_lua_lm_message },
       
   256 	{ NULL,     NULL                 },
   150 };
   257 };
   151 
   258 
   152 static const luaL_Reg reg_m_lm_message[] = {
   259 static const luaL_Reg reg_m_lm_message[] = {
   153 	{ "node",       node_lm_message    },
   260 	{ "node",       node_lm_message    },
   154 	{ "type",       kind_lm_message    },
   261 	{ "type",       kind_lm_message    },
   155 	// These methods are common for message and message node
   262 	// These methods are common for message and message node
       
   263 	{ "name",       name_lm_node       },
   156 	{ "next",       next_lm_node       },
   264 	{ "next",       next_lm_node       },
   157 	{ "prev",       prev_lm_node       },
   265 	{ "prev",       prev_lm_node       },
   158 	{ "children",   children_lm_node   },
   266 	{ "children",   children_lm_node   },
   159 	{ "parent",     parent_lm_node     },
   267 	{ "parent",     parent_lm_node     },
   160 	{ "value",      value_lm_node      },
   268 	{ "value",      value_lm_node      },