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 |
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 }, |