| 34 * @param not_empty FALSE if message is empty, TRUE if variadic arguments follow. |
34 * @param not_empty FALSE if message is empty, TRUE if variadic arguments follow. |
| 35 * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL. |
35 * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL. |
| 36 * |
36 * |
| 37 * See msim_msg_append() documentation for details on types. |
37 * See msim_msg_append() documentation for details on types. |
| 38 */ |
38 */ |
| 39 MsimMessage *msim_msg_new(gboolean not_empty, ...) |
39 MsimMessage * |
| |
40 msim_msg_new(gboolean not_empty, ...) |
| 40 { |
41 { |
| 41 va_list argp; |
42 va_list argp; |
| 42 |
43 |
| 43 va_start(argp, not_empty); |
44 va_start(argp, not_empty); |
| 44 |
45 |
| 53 * @param argp A va_list of variadic arguments, already started with va_start(). Will be va_end()'d. |
54 * @param argp A va_list of variadic arguments, already started with va_start(). Will be va_end()'d. |
| 54 * @return New MsimMessage *, must be freed with msim_msg_free(). |
55 * @return New MsimMessage *, must be freed with msim_msg_free(). |
| 55 * |
56 * |
| 56 * For internal use - users probably want msim_msg_new() or msim_send(). |
57 * For internal use - users probably want msim_msg_new() or msim_send(). |
| 57 */ |
58 */ |
| 58 static MsimMessage *msim_msg_new_v(va_list argp) |
59 static MsimMessage * |
| |
60 msim_msg_new_v(va_list argp) |
| 59 { |
61 { |
| 60 gchar *key, *value; |
62 gchar *key, *value; |
| 61 MsimMessageType type; |
63 MsimMessageType type; |
| 62 GString *gs; |
64 GString *gs; |
| 63 MsimMessage *msg; |
65 MsimMessage *msg; |
| 115 /** Clone an individual element. |
117 /** Clone an individual element. |
| 116 * |
118 * |
| 117 * @param data MsimMessageElement * to clone. |
119 * @param data MsimMessageElement * to clone. |
| 118 * @param user_data Pointer to MsimMessage * to add cloned element to. |
120 * @param user_data Pointer to MsimMessage * to add cloned element to. |
| 119 */ |
121 */ |
| 120 static void msim_msg_clone_element(gpointer data, gpointer user_data) |
122 static void |
| |
123 msim_msg_clone_element(gpointer data, gpointer user_data) |
| 121 { |
124 { |
| 122 MsimMessageElement *elem; |
125 MsimMessageElement *elem; |
| 123 MsimMessage **new; |
126 MsimMessage **new; |
| 124 gpointer new_data; |
127 gpointer new_data; |
| 125 |
128 |
| 179 /** Free an individual message element. |
183 /** Free an individual message element. |
| 180 * |
184 * |
| 181 * @param data MsimMessageElement * to free. |
185 * @param data MsimMessageElement * to free. |
| 182 * @param user_data Not used; required to match g_list_foreach() callback prototype. |
186 * @param user_data Not used; required to match g_list_foreach() callback prototype. |
| 183 */ |
187 */ |
| 184 static void msim_msg_free_element(gpointer data, gpointer user_data) |
188 static void |
| |
189 msim_msg_free_element(gpointer data, gpointer user_data) |
| 185 { |
190 { |
| 186 MsimMessageElement *elem; |
191 MsimMessageElement *elem; |
| 187 |
192 |
| 188 elem = (MsimMessageElement *)data; |
193 elem = (MsimMessageElement *)data; |
| 189 |
194 |
| 235 g_list_foreach(msg, msim_msg_free_element, NULL); |
241 g_list_foreach(msg, msim_msg_free_element, NULL); |
| 236 g_list_free(msg); |
242 g_list_free(msg); |
| 237 } |
243 } |
| 238 |
244 |
| 239 /** Send an existing MsimMessage. */ |
245 /** Send an existing MsimMessage. */ |
| 240 gboolean msim_msg_send(MsimSession *session, MsimMessage *msg) |
246 gboolean |
| |
247 msim_msg_send(MsimSession *session, MsimMessage *msg) |
| 241 { |
248 { |
| 242 gchar *raw; |
249 gchar *raw; |
| 243 gboolean success; |
250 gboolean success; |
| 244 |
251 |
| 245 raw = msim_msg_pack(msg); |
252 raw = msim_msg_pack(msg); |
| 285 |
293 |
| 286 /** Create a new MsimMessageElement * - must be g_free()'d. |
294 /** Create a new MsimMessageElement * - must be g_free()'d. |
| 287 * |
295 * |
| 288 * For internal use; users probably want msim_msg_append() or msim_msg_insert_before(). |
296 * For internal use; users probably want msim_msg_append() or msim_msg_insert_before(). |
| 289 */ |
297 */ |
| 290 static MsimMessageElement *msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data) |
298 static MsimMessageElement * |
| |
299 msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data) |
| 291 { |
300 { |
| 292 MsimMessageElement *elem; |
301 MsimMessageElement *elem; |
| 293 |
302 |
| 294 elem = g_new0(MsimMessageElement, 1); |
303 elem = g_new0(MsimMessageElement, 1); |
| 295 |
304 |
| 326 * * MSIM_TYPE_DICTIONARY: TODO |
335 * * MSIM_TYPE_DICTIONARY: TODO |
| 327 * |
336 * |
| 328 * * MSIM_TYPE_LIST: TODO |
337 * * MSIM_TYPE_LIST: TODO |
| 329 * |
338 * |
| 330 * */ |
339 * */ |
| 331 MsimMessage *msim_msg_append(MsimMessage *msg, const gchar *name, MsimMessageType type, gpointer data) |
340 MsimMessage * |
| |
341 msim_msg_append(MsimMessage *msg, const gchar *name, |
| |
342 MsimMessageType type, gpointer data) |
| 332 { |
343 { |
| 333 return g_list_append(msg, msim_msg_element_new(name, type, data)); |
344 return g_list_append(msg, msim_msg_element_new(name, type, data)); |
| 334 } |
345 } |
| 335 |
346 |
| 336 /** Insert a new element into a message, before the given element name. |
347 /** Insert a new element into a message, before the given element name. |
| 338 * @param name_before Name of the element to insert the new element before. If |
349 * @param name_before Name of the element to insert the new element before. If |
| 339 * could not be found or NULL, new element will be inserted at end. |
350 * could not be found or NULL, new element will be inserted at end. |
| 340 * |
351 * |
| 341 * See msim_msg_append() for usage of other parameters, and an important note about return value. |
352 * See msim_msg_append() for usage of other parameters, and an important note about return value. |
| 342 */ |
353 */ |
| 343 MsimMessage *msim_msg_insert_before(MsimMessage *msg, const gchar *name_before, const gchar *name, MsimMessageType type, gpointer data) |
354 MsimMessage * |
| |
355 msim_msg_insert_before(MsimMessage *msg, const gchar *name_before, |
| |
356 const gchar *name, MsimMessageType type, gpointer data) |
| 344 { |
357 { |
| 345 MsimMessageElement *new_elem; |
358 MsimMessageElement *new_elem; |
| 346 GList *node_before; |
359 GList *node_before; |
| 347 |
360 |
| 348 new_elem = msim_msg_element_new(name, type, data); |
361 new_elem = msim_msg_element_new(name, type, data); |
| 353 } |
366 } |
| 354 |
367 |
| 355 /** Pack a string using the given GFunc and seperator. |
368 /** Pack a string using the given GFunc and seperator. |
| 356 * Used by msim_msg_dump() and msim_msg_pack(). |
369 * Used by msim_msg_dump() and msim_msg_pack(). |
| 357 */ |
370 */ |
| 358 gchar *msim_msg_pack_using(MsimMessage *msg, GFunc gf, const gchar *sep, const gchar *begin, const gchar *end) |
371 gchar * |
| |
372 msim_msg_pack_using(MsimMessage *msg, GFunc gf, const gchar *sep, |
| |
373 const gchar *begin, const gchar *end) |
| 359 { |
374 { |
| 360 gchar **strings; |
375 gchar **strings; |
| 361 gchar **strings_tmp; |
376 gchar **strings_tmp; |
| 362 gchar *joined; |
377 gchar *joined; |
| 363 gchar *final; |
378 gchar *final; |
| 473 * |
490 * |
| 474 * Returns a string suitable for inclusion in a raw protocol message, not necessarily |
491 * Returns a string suitable for inclusion in a raw protocol message, not necessarily |
| 475 * optimal for human consumption. For example, strings are escaped. Use |
492 * optimal for human consumption. For example, strings are escaped. Use |
| 476 * msim_msg_get_string() if you want a string, which in some cases is same as this. |
493 * msim_msg_get_string() if you want a string, which in some cases is same as this. |
| 477 */ |
494 */ |
| 478 static gchar *msim_msg_pack_element_data(MsimMessageElement *elem) |
495 static gchar * |
| |
496 msim_msg_pack_element_data(MsimMessageElement *elem) |
| 479 { |
497 { |
| 480 switch (elem->type) |
498 switch (elem->type) |
| 481 { |
499 { |
| 482 case MSIM_TYPE_INTEGER: |
500 case MSIM_TYPE_INTEGER: |
| 483 return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data)); |
501 return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data)); |
| 525 * Called by msim_msg_pack(). Will pack the MsimMessageElement into |
543 * Called by msim_msg_pack(). Will pack the MsimMessageElement into |
| 526 * a part of the protocol string and append it to the array. Caller |
544 * a part of the protocol string and append it to the array. Caller |
| 527 * is responsible for creating array to correct dimensions, and |
545 * is responsible for creating array to correct dimensions, and |
| 528 * freeing each string element of the array added by this function. |
546 * freeing each string element of the array added by this function. |
| 529 */ |
547 */ |
| 530 static void msim_msg_pack_element(gpointer data, gpointer user_data) |
548 static void |
| |
549 msim_msg_pack_element(gpointer data, gpointer user_data) |
| 531 { |
550 { |
| 532 MsimMessageElement *elem; |
551 MsimMessageElement *elem; |
| 533 gchar *string, *data_string; |
552 gchar *string, *data_string; |
| 534 gchar ***items; |
553 gchar ***items; |
| 535 |
554 |
| 583 |
602 |
| 584 /** Return a packed string suitable for sending over the wire. |
603 /** Return a packed string suitable for sending over the wire. |
| 585 * |
604 * |
| 586 * @return A string. Caller must g_free(). |
605 * @return A string. Caller must g_free(). |
| 587 */ |
606 */ |
| 588 gchar *msim_msg_pack(MsimMessage *msg) |
607 gchar * |
| |
608 msim_msg_pack(MsimMessage *msg) |
| 589 { |
609 { |
| 590 g_return_val_if_fail(msg != NULL, NULL); |
610 g_return_val_if_fail(msg != NULL, NULL); |
| 591 |
611 |
| 592 return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\"); |
612 return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\"); |
| 593 } |
613 } |
| 768 * |
789 * |
| 769 * Note: useful fields of MsimMessageElement are 'data' and 'type', which |
790 * Note: useful fields of MsimMessageElement are 'data' and 'type', which |
| 770 * you can access directly. But it is often more convenient to use |
791 * you can access directly. But it is often more convenient to use |
| 771 * another msim_msg_get_* that converts the data to what type you want. |
792 * another msim_msg_get_* that converts the data to what type you want. |
| 772 */ |
793 */ |
| 773 MsimMessageElement *msim_msg_get(MsimMessage *msg, const gchar *name) |
794 MsimMessageElement * |
| |
795 msim_msg_get(MsimMessage *msg, const gchar *name) |
| 774 { |
796 { |
| 775 GList *node; |
797 GList *node; |
| 776 |
798 |
| 777 node = msim_msg_get_node(msg, name); |
799 node = msim_msg_get_node(msg, name); |
| 778 if (node) |
800 if (node) |
| 789 * |
811 * |
| 790 * Note that msim_msg_pack_element_data() is similar, but returns a string |
812 * Note that msim_msg_pack_element_data() is similar, but returns a string |
| 791 * for inclusion into a raw protocol string (escaped and everything). |
813 * for inclusion into a raw protocol string (escaped and everything). |
| 792 * This function unescapes the string for you, if needed. |
814 * This function unescapes the string for you, if needed. |
| 793 */ |
815 */ |
| 794 gchar *msim_msg_get_string(MsimMessage *msg, const gchar *name) |
816 gchar * |
| |
817 msim_msg_get_string(MsimMessage *msg, const gchar *name) |
| 795 { |
818 { |
| 796 MsimMessageElement *elem; |
819 MsimMessageElement *elem; |
| 797 |
820 |
| 798 elem = msim_msg_get(msg, name); |
821 elem = msim_msg_get(msg, name); |
| 799 if (!elem) |
822 if (!elem) |
| 828 * |
851 * |
| 829 * Useful to obtain an element's data if you know it should be an integer, |
852 * Useful to obtain an element's data if you know it should be an integer, |
| 830 * even if it is not stored as an MSIM_TYPE_INTEGER. MSIM_TYPE_STRING will |
853 * even if it is not stored as an MSIM_TYPE_INTEGER. MSIM_TYPE_STRING will |
| 831 * be converted handled correctly, for example. |
854 * be converted handled correctly, for example. |
| 832 */ |
855 */ |
| 833 guint msim_msg_get_integer(MsimMessage *msg, const gchar *name) |
856 guint |
| |
857 msim_msg_get_integer(MsimMessage *msg, const gchar *name) |
| 834 { |
858 { |
| 835 MsimMessageElement *elem; |
859 MsimMessageElement *elem; |
| 836 |
860 |
| 837 elem = msim_msg_get(msg, name); |
861 elem = msim_msg_get(msg, name); |
| 838 |
862 |
| 860 * |
884 * |
| 861 * @param binary_length A pointer to an integer, which will be set to the binary data length. |
885 * @param binary_length A pointer to an integer, which will be set to the binary data length. |
| 862 * |
886 * |
| 863 * @return TRUE if successful, FALSE if not. |
887 * @return TRUE if successful, FALSE if not. |
| 864 */ |
888 */ |
| 865 gboolean msim_msg_get_binary(MsimMessage *msg, const gchar *name, gchar **binary_data, gsize *binary_length) |
889 gboolean |
| |
890 msim_msg_get_binary(MsimMessage *msg, const gchar *name, |
| |
891 gchar **binary_data, gsize *binary_length) |
| 866 { |
892 { |
| 867 MsimMessageElement *elem; |
893 MsimMessageElement *elem; |
| 868 |
894 |
| 869 elem = msim_msg_get(msg, name); |
895 elem = msim_msg_get(msg, name); |
| 870 |
896 |