Mercurial > pidgin.yaz
comparison libpurple/protocols/myspace/message.c @ 17321:ddcf9ef2ccec
Add MsimMessage implementation (sending only).
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Thu, 31 May 2007 02:29:50 +0000 |
parents | |
children | 793301c04e3a |
comparison
equal
deleted
inserted
replaced
17320:0409947da92f | 17321:ddcf9ef2ccec |
---|---|
1 /** MySpaceIM protocol messages | |
2 * | |
3 * \author Jeff Connelly | |
4 * | |
5 * Copyright (C) 2007, Jeff Connelly <jeff2@homing.pidgin.im> | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 */ | |
21 | |
22 #include "myspace.h" | |
23 #include "message.h" | |
24 | |
25 static void msim_msg_free_element(gpointer data, gpointer user_data); | |
26 static void msim_msg_debug_string_element(gpointer data, gpointer user_data); | |
27 static gchar *msim_msg_pack_using(MsimMessage *msg, GFunc gf, gchar *sep, gchar *begin, gchar *end); | |
28 | |
29 MsimMessage *msim_msg_new(void) | |
30 { | |
31 /* Just an empty list. */ | |
32 return NULL; | |
33 } | |
34 | |
35 /** Free an individual message element. */ | |
36 static void msim_msg_free_element(gpointer data, gpointer user_data) | |
37 { | |
38 MsimMessageElement *elem; | |
39 | |
40 elem = (MsimMessageElement *)data; | |
41 | |
42 switch (elem->type) | |
43 { | |
44 case MSIM_TYPE_BOOLEAN: /* Fall through */ | |
45 case MSIM_TYPE_INTEGER: | |
46 /* Integer value stored in gpointer - no need to free(). */ | |
47 break; | |
48 | |
49 case MSIM_TYPE_STRING: | |
50 /* Always free strings - caller should have g_strdup()'d if | |
51 * string was static or temporary and not to be freed. */ | |
52 g_free(elem->data); | |
53 break; | |
54 | |
55 case MSIM_TYPE_BINARY: | |
56 /* Free the GString itself and the binary data. */ | |
57 g_string_free((GString *)elem->data, TRUE); | |
58 break; | |
59 | |
60 case MSIM_TYPE_DICTIONARY: | |
61 /* TODO: free dictionary */ | |
62 break; | |
63 | |
64 case MSIM_TYPE_LIST: | |
65 /* TODO: free list */ | |
66 break; | |
67 | |
68 default: | |
69 purple_debug_info("msim", "msim_msg_free_element: not freeing unknown type %d\n", | |
70 elem->type); | |
71 break; | |
72 } | |
73 | |
74 g_free(elem); | |
75 } | |
76 | |
77 /** Free a complete message. */ | |
78 void msim_msg_free(MsimMessage *msg) | |
79 { | |
80 if (!msg) | |
81 { | |
82 /* already free as can be */ | |
83 return; | |
84 } | |
85 | |
86 g_list_foreach(msg, msim_msg_free_element, NULL); | |
87 g_list_free(msg); | |
88 } | |
89 | |
90 /** Send an existing MsimMessage. */ | |
91 gboolean msim_msg_send(MsimSession *session, MsimMessage *msg) | |
92 { | |
93 gchar *raw; | |
94 gboolean success; | |
95 | |
96 raw = msim_msg_pack(msg); | |
97 success = msim_send_raw(session, raw); | |
98 g_free(raw); | |
99 | |
100 return success; | |
101 } | |
102 | |
103 /** | |
104 * | |
105 * Send a message to the server, whose contents is specified using | |
106 * variable arguments. | |
107 * | |
108 * @param session | |
109 * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL. | |
110 * | |
111 * This function exists for coding convenience: it allows a message to be created | |
112 * and sent in one line of code. Internally it calls msim_msg_send(). | |
113 * | |
114 * IMPORTANT: See msim_msg_append() documentation for details on element types. | |
115 * | |
116 */ | |
117 gboolean msim_send(MsimSession *session, ...) | |
118 { | |
119 va_list argp; | |
120 gchar *key, *value; | |
121 MsimMessageType type; | |
122 gboolean success; | |
123 MsimMessage *msg; | |
124 GString *gs; | |
125 | |
126 msg = msim_msg_new(); | |
127 | |
128 /* Read key, type, value triplets until NULL. */ | |
129 va_start(argp, session); | |
130 do | |
131 { | |
132 key = va_arg(argp, gchar *); | |
133 if (!key) | |
134 { | |
135 break; | |
136 } | |
137 | |
138 type = va_arg(argp, int); | |
139 | |
140 switch (type) | |
141 { | |
142 case MSIM_TYPE_INTEGER: | |
143 msg = msim_msg_append(msg, key, type, GUINT_TO_POINTER(va_arg(argp, int))); | |
144 break; | |
145 | |
146 case MSIM_TYPE_STRING: | |
147 value = va_arg(argp, char *); | |
148 | |
149 g_return_val_if_fail(value != NULL, FALSE); | |
150 | |
151 msg = msim_msg_append(msg, key, type, value); | |
152 break; | |
153 | |
154 case MSIM_TYPE_BINARY: | |
155 gs = va_arg(argp, GString *); | |
156 | |
157 g_return_val_if_fail(gs != NULL, FALSE); | |
158 | |
159 /* msim_msg_free() will free this GString the caller created. */ | |
160 msg = msim_msg_append(msg, key, type, gs); | |
161 break; | |
162 | |
163 default: | |
164 purple_debug_info("msim", "msim_send: unknown type %d\n", type); | |
165 break; | |
166 } | |
167 } while(key); | |
168 | |
169 /* Actually send the message. */ | |
170 success = msim_msg_send(session, msg); | |
171 | |
172 /* Cleanup. */ | |
173 va_end(argp); | |
174 msim_msg_free(msg); | |
175 | |
176 return success; | |
177 } | |
178 | |
179 | |
180 | |
181 | |
182 /** Append a new element to a message. | |
183 * | |
184 * @param name Textual name of element (static string, neither copied nor freed). | |
185 * @param type An MSIM_TYPE_* code. | |
186 * @param data Pointer to data, see below. | |
187 * | |
188 * @return The new message - must be assigned to as with GList*. For example: | |
189 * | |
190 * msg = msim_msg_append(msg, ...) | |
191 * | |
192 * The data parameter depends on the type given: | |
193 * | |
194 * * MSIM_TYPE_INTEGER: Use GUINT_TO_POINTER(x). | |
195 * | |
196 * * MSIM_TYPE_BINARY: Same as integer, non-zero is TRUE and zero is FALSE. | |
197 * | |
198 * * MSIM_TYPE_STRING: gchar *. The data WILL BE FREED - use g_strdup() if needed. | |
199 * | |
200 * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data and GString will be freed. | |
201 * | |
202 * * MSIM_TYPE_DICTIONARY: TODO | |
203 * | |
204 * * MSIM_TYPE_LIST: TODO | |
205 * | |
206 * */ | |
207 MsimMessage *msim_msg_append(MsimMessage *msg, gchar *name, MsimMessageType type, gpointer data) | |
208 { | |
209 MsimMessageElement *elem; | |
210 | |
211 elem = g_new0(MsimMessageElement, 1); | |
212 | |
213 elem->name = name; | |
214 elem->type = type; | |
215 elem->data = data; | |
216 | |
217 return g_list_append(msg, elem); | |
218 } | |
219 | |
220 /** Pack a string using the given GFunc and seperator. | |
221 * Used by msim_msg_debug_string() and msim_msg_pack(). | |
222 */ | |
223 static gchar *msim_msg_pack_using(MsimMessage *msg, GFunc gf, gchar *sep, gchar *begin, gchar *end) | |
224 { | |
225 gchar **strings; | |
226 gchar **strings_tmp; | |
227 gchar *joined; | |
228 gchar *final; | |
229 int i; | |
230 | |
231 g_return_val_if_fail(msg != NULL, NULL); | |
232 | |
233 /* Add one for NULL terminator for g_strjoinv(). */ | |
234 strings = (gchar **)g_new0(gchar *, g_list_length(msg) + 1); | |
235 | |
236 strings_tmp = strings; | |
237 g_list_foreach(msg, gf, &strings_tmp); | |
238 | |
239 joined = g_strjoinv(sep, strings); | |
240 final = g_strconcat(begin, joined, end, NULL); | |
241 g_free(joined); | |
242 | |
243 /* Clean up. */ | |
244 for (i = 0; i < g_list_length(msg); ++i) | |
245 { | |
246 g_free(strings[i]); | |
247 } | |
248 | |
249 g_free(strings); | |
250 | |
251 return final; | |
252 } | |
253 /** Store a human-readable string describing the element. | |
254 * | |
255 * @param data Pointer to an MsimMessageElement. | |
256 * @param user_data | |
257 */ | |
258 static void msim_msg_debug_string_element(gpointer data, gpointer user_data) | |
259 { | |
260 MsimMessageElement *elem; | |
261 gchar *string; | |
262 GString *gs; | |
263 gchar *binary; | |
264 gchar ***items; /* wow, a pointer to a pointer to a pointer */ | |
265 | |
266 elem = (MsimMessageElement *)data; | |
267 items = user_data; | |
268 | |
269 switch (elem->type) | |
270 { | |
271 case MSIM_TYPE_INTEGER: | |
272 string = g_strdup_printf("%s(integer): %d", elem->name, GPOINTER_TO_UINT(elem->data)); | |
273 break; | |
274 | |
275 case MSIM_TYPE_STRING: | |
276 string = g_strdup_printf("%s(string): %s", elem->name, (gchar *)elem->data); | |
277 break; | |
278 | |
279 case MSIM_TYPE_BINARY: | |
280 gs = (GString *)elem->data; | |
281 binary = purple_base64_encode((guchar*)gs->str, gs->len); | |
282 string = g_strdup_printf("%s(binary, %d bytes): %s", elem->name, (int)gs->len, binary); | |
283 g_free(binary); | |
284 break; | |
285 | |
286 case MSIM_TYPE_BOOLEAN: | |
287 string = g_strdup_printf("%s(boolean): %s", elem->name, | |
288 GPOINTER_TO_UINT(elem->data) ? "TRUE" : "FALSE"); | |
289 break; | |
290 | |
291 case MSIM_TYPE_DICTIONARY: | |
292 /* TODO: provide human-readable output of dictionary. */ | |
293 string = g_strdup_printf("%s(dict): TODO", elem->name); | |
294 break; | |
295 | |
296 case MSIM_TYPE_LIST: | |
297 /* TODO: provide human-readable output of list. */ | |
298 string = g_strdup_printf("%s(list): TODO", elem->name); | |
299 break; | |
300 | |
301 default: | |
302 string = g_strdup_printf("%s(unknown type %d)", elem->name, elem->type); | |
303 break; | |
304 } | |
305 | |
306 **items = string; | |
307 ++(*items); | |
308 } | |
309 | |
310 /** Return a human-readable string of the message. | |
311 * | |
312 * @return A string. Caller must g_free(). | |
313 */ | |
314 gchar *msim_msg_debug_string(MsimMessage *msg) | |
315 { | |
316 if (!msg) | |
317 { | |
318 return g_strdup("<MsimMessage: empty>"); | |
319 } | |
320 | |
321 return msim_msg_pack_using(msg, msim_msg_debug_string_element, "\n", "<MsimMessage: \n", ">"); | |
322 } | |
323 | |
324 /** Pack an element into its protocol representation. | |
325 * | |
326 * @param data Pointer to an MsimMessageElement. | |
327 * @param user_data | |
328 */ | |
329 static void msim_msg_pack_element(gpointer data, gpointer user_data) | |
330 { | |
331 MsimMessageElement *elem; | |
332 gchar *string; | |
333 gchar ***items; | |
334 gchar *binary; | |
335 gchar *escaped; | |
336 GString *gs; | |
337 | |
338 elem = (MsimMessageElement *)data; | |
339 items = user_data; | |
340 | |
341 switch (elem->type) | |
342 { | |
343 case MSIM_TYPE_INTEGER: | |
344 string = g_strdup_printf("%s\\%d", elem->name, GPOINTER_TO_UINT(elem->data)); | |
345 break; | |
346 | |
347 case MSIM_TYPE_STRING: | |
348 /* Strings get escaped. */ | |
349 escaped = msim_escape((gchar *)elem->data); | |
350 string = g_strdup_printf("%s\\%s", elem->name, escaped); | |
351 g_free(escaped); | |
352 break; | |
353 | |
354 case MSIM_TYPE_BINARY: | |
355 gs = (GString *)elem->data; | |
356 binary = purple_base64_encode((guchar*)gs->str, gs->len); | |
357 /* Do not escape! */ | |
358 string = g_strdup_printf("%s\\%s", elem->name, binary); | |
359 g_free(binary); | |
360 break; | |
361 | |
362 case MSIM_TYPE_BOOLEAN: | |
363 if (GPOINTER_TO_UINT(elem->data)) | |
364 { | |
365 string = g_strdup_printf("%s\\\\", elem->name); | |
366 } else { | |
367 /* False - leave out. */ | |
368 string = g_strdup(""); | |
369 } | |
370 break; | |
371 | |
372 case MSIM_TYPE_DICTIONARY: | |
373 /* TODO: pack using k=v\034k2=v2\034... */ | |
374 string = g_strdup_printf("%s\\TODO", elem->name); | |
375 break; | |
376 | |
377 case MSIM_TYPE_LIST: | |
378 /* TODO: pack using a|b|c|d|... */ | |
379 string = g_strdup_printf("%s\\TODO", elem->name); | |
380 break; | |
381 | |
382 default: | |
383 g_return_if_fail(FALSE); | |
384 break; | |
385 } | |
386 | |
387 **items = string; | |
388 ++(*items); | |
389 } | |
390 | |
391 | |
392 /** Return a packed string suitable for sending over the wire. | |
393 * | |
394 * @return A string. Caller must g_free(). | |
395 */ | |
396 gchar *msim_msg_pack(MsimMessage *msg) | |
397 { | |
398 g_return_val_if_fail(msg != NULL, NULL); | |
399 | |
400 return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\"); | |
401 } | |
402 |