comparison libpurple/protocols/myspace/message.c @ 17359:d69bcd74c240

Enhance msim_msg_new() to accept a variadic arguments, like msim_send(), by means of a new function msim_msg_new_v() accepting a va_list(). This simplifies coding, in that you can now easily create a MsimMessage with certain fields, and send it later (instead of doing both at once as with msim_send()).
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Mon, 04 Jun 2007 03:30:55 +0000
parents 641c96277fa6
children 3720176bdac6
comparison
equal deleted inserted replaced
17358:641c96277fa6 17359:d69bcd74c240
25 static void msim_msg_free_element(gpointer data, gpointer user_data); 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); 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); 27 static gchar *msim_msg_pack_using(MsimMessage *msg, GFunc gf, gchar *sep, gchar *begin, gchar *end);
28 static gchar *msim_msg_element_pack(MsimMessageElement *elem); 28 static gchar *msim_msg_element_pack(MsimMessageElement *elem);
29 static GList *msim_msg_get_node(MsimMessage *msg, gchar *name); 29 static GList *msim_msg_get_node(MsimMessage *msg, gchar *name);
30 30 static MsimMessage *msim_msg_new_v(va_list argp);
31 /** Create a new MsimMessage. */ 31
32 MsimMessage *msim_msg_new(void) 32 /** Create a new MsimMessage.
33 { 33 *
34 /* Just an empty list. */ 34 * @param not_empty FALSE if message is empty, TRUE if variadic arguments follow.
35 return NULL; 35 * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
36 } 36 *
37 37 * See msim_msg_append() documentation for details on types.
38 /** Clone an individual element. 38 */
39 * 39 MsimMessage *msim_msg_new(gboolean not_empty, ...)
40 * @param data MsimMessageElement * to clone. 40 {
41 * @param user_data Pointer to MsimMessage * to add cloned element to. 41 va_list argp;
42 */ 42
43 static void msim_msg_clone_element(gpointer data, gpointer user_data) 43 va_start(argp, not_empty);
44 { 44
45 MsimMessageElement *elem; 45 if (not_empty)
46 MsimMessage **new; 46 return msim_msg_new_v(argp);
47 gpointer new_data; 47 else
48
49 elem = (MsimMessageElement *)data;
50 new = (MsimMessage **)user_data;
51
52 switch (elem->type)
53 {
54 case MSIM_TYPE_BOOLEAN:
55 case MSIM_TYPE_INTEGER:
56 new_data = elem->data;
57 break;
58
59 case MSIM_TYPE_RAW:
60 case MSIM_TYPE_STRING:
61 new_data = g_strdup((gchar *)elem->data);
62 break;
63
64 case MSIM_TYPE_BINARY:
65 {
66 GString *gs;
67
68 gs = (GString *)elem->data;
69
70 new_data = g_string_new_len(gs->str, gs->len);
71 }
72 break;
73 /* TODO: other types */
74 default:
75 purple_debug_info("msim", "msim_msg_clone_element: unknown type %d (%c)\n", elem->type, elem->type);
76 g_return_if_fail(NULL);
77 }
78
79 /* Append cloned data. Note that the 'name' field is a static string, so it
80 * never needs to be copied nor freed. */
81 *new = msim_msg_append(*new, elem->name, elem->type, new_data);
82 }
83
84 /** Clone an existing MsimMessage.
85 *
86 * @return Cloned message; caller should free with msim_msg_free().
87 */
88 MsimMessage *msim_msg_clone(MsimMessage *old)
89 {
90 MsimMessage *new;
91
92 if (!old)
93 return NULL; 48 return NULL;
94 49 }
95 new = msim_msg_new(); 50
96 51 /** Create a new message from va_list and its first argument.
97 g_list_foreach(old, msim_msg_clone_element, &new); 52 *
98 53 * @param argp A va_list of variadic arguments, already started with va_start(). Will be va_end()'d.
99 return new; 54 * @return New MsimMessage *, must be freed with msim_msg_free().
100 } 55 *
101 56 * For internal use - users probably want msim_msg_new() or msim_send().
102 /** Free an individual message element. 57 */
103 * 58 static MsimMessage *msim_msg_new_v(va_list argp)
104 * @param data MsimMessageElement * to free. 59 {
105 * @param user_data Not used; required to match g_list_foreach() callback prototype.
106 */
107 static void msim_msg_free_element(gpointer data, gpointer user_data)
108 {
109 MsimMessageElement *elem;
110
111 elem = (MsimMessageElement *)data;
112
113 switch (elem->type)
114 {
115 case MSIM_TYPE_BOOLEAN:
116 case MSIM_TYPE_INTEGER:
117 /* Integer value stored in gpointer - no need to free(). */
118 break;
119
120 case MSIM_TYPE_RAW:
121 case MSIM_TYPE_STRING:
122 /* Always free strings - caller should have g_strdup()'d if
123 * string was static or temporary and not to be freed. */
124 g_free(elem->data);
125 break;
126
127 case MSIM_TYPE_BINARY:
128 /* Free the GString itself and the binary data. */
129 g_string_free((GString *)elem->data, TRUE);
130 break;
131
132 case MSIM_TYPE_DICTIONARY:
133 /* TODO: free dictionary */
134 break;
135
136 case MSIM_TYPE_LIST:
137 /* TODO: free list */
138 break;
139
140 default:
141 purple_debug_info("msim", "msim_msg_free_element: not freeing unknown type %d (%c)\n",
142 elem->type, elem->type);
143 break;
144 }
145
146 g_free(elem);
147 }
148
149 /** Free a complete message. */
150 void msim_msg_free(MsimMessage *msg)
151 {
152 if (!msg)
153 {
154 /* already free as can be */
155 return;
156 }
157
158 g_list_foreach(msg, msim_msg_free_element, NULL);
159 g_list_free(msg);
160 }
161
162 /** Send an existing MsimMessage. */
163 gboolean msim_msg_send(MsimSession *session, MsimMessage *msg)
164 {
165 gchar *raw;
166 gboolean success;
167
168 raw = msim_msg_pack(msg);
169 success = msim_send_raw(session, raw);
170 g_free(raw);
171
172 return success;
173 }
174
175 /**
176 *
177 * Send a message to the server, whose contents is specified using
178 * variable arguments.
179 *
180 * @param session
181 * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
182 *
183 * This function exists for coding convenience: it allows a message to be created
184 * and sent in one line of code. Internally it calls msim_msg_send().
185 *
186 * IMPORTANT: See msim_msg_append() documentation for details on element types.
187 *
188 */
189 gboolean msim_send(MsimSession *session, ...)
190 {
191 va_list argp;
192 gchar *key, *value; 60 gchar *key, *value;
193 MsimMessageType type; 61 MsimMessageType type;
194 gboolean success; 62 GString *gs;
195 MsimMessage *msg; 63 MsimMessage *msg;
196 GString *gs; 64
197 65 /* Begin with an empty message. */
198 msg = msim_msg_new(); 66 msg = NULL;
199 67
200 /* Read key, type, value triplets until NULL. */ 68 /* Read key, type, value triplets until NULL. */
201 va_start(argp, session);
202 do 69 do
203 { 70 {
204 key = va_arg(argp, gchar *); 71 key = va_arg(argp, gchar *);
205 if (!key) 72 if (!key)
206 { 73 {
237 default: 104 default:
238 purple_debug_info("msim", "msim_send: unknown type %d (%c)\n", type, type); 105 purple_debug_info("msim", "msim_send: unknown type %d (%c)\n", type, type);
239 break; 106 break;
240 } 107 }
241 } while(key); 108 } while(key);
109 va_end(argp);
110
111 return msg;
112 }
113
114
115 /** Clone an individual element.
116 *
117 * @param data MsimMessageElement * to clone.
118 * @param user_data Pointer to MsimMessage * to add cloned element to.
119 */
120 static void msim_msg_clone_element(gpointer data, gpointer user_data)
121 {
122 MsimMessageElement *elem;
123 MsimMessage **new;
124 gpointer new_data;
125
126 elem = (MsimMessageElement *)data;
127 new = (MsimMessage **)user_data;
128
129 switch (elem->type)
130 {
131 case MSIM_TYPE_BOOLEAN:
132 case MSIM_TYPE_INTEGER:
133 new_data = elem->data;
134 break;
135
136 case MSIM_TYPE_RAW:
137 case MSIM_TYPE_STRING:
138 new_data = g_strdup((gchar *)elem->data);
139 break;
140
141 case MSIM_TYPE_BINARY:
142 {
143 GString *gs;
144
145 gs = (GString *)elem->data;
146
147 new_data = g_string_new_len(gs->str, gs->len);
148 }
149 break;
150 /* TODO: other types */
151 default:
152 purple_debug_info("msim", "msim_msg_clone_element: unknown type %d (%c)\n", elem->type, elem->type);
153 g_return_if_fail(NULL);
154 }
155
156 /* Append cloned data. Note that the 'name' field is a static string, so it
157 * never needs to be copied nor freed. */
158 *new = msim_msg_append(*new, elem->name, elem->type, new_data);
159 }
160
161 /** Clone an existing MsimMessage.
162 *
163 * @return Cloned message; caller should free with msim_msg_free().
164 */
165 MsimMessage *msim_msg_clone(MsimMessage *old)
166 {
167 MsimMessage *new;
168
169 if (!old)
170 return NULL;
171
172 new = msim_msg_new(FALSE);
173
174 g_list_foreach(old, msim_msg_clone_element, &new);
175
176 return new;
177 }
178
179 /** Free an individual message element.
180 *
181 * @param data MsimMessageElement * to free.
182 * @param user_data Not used; required to match g_list_foreach() callback prototype.
183 */
184 static void msim_msg_free_element(gpointer data, gpointer user_data)
185 {
186 MsimMessageElement *elem;
187
188 elem = (MsimMessageElement *)data;
189
190 switch (elem->type)
191 {
192 case MSIM_TYPE_BOOLEAN:
193 case MSIM_TYPE_INTEGER:
194 /* Integer value stored in gpointer - no need to free(). */
195 break;
196
197 case MSIM_TYPE_RAW:
198 case MSIM_TYPE_STRING:
199 /* Always free strings - caller should have g_strdup()'d if
200 * string was static or temporary and not to be freed. */
201 g_free(elem->data);
202 break;
203
204 case MSIM_TYPE_BINARY:
205 /* Free the GString itself and the binary data. */
206 g_string_free((GString *)elem->data, TRUE);
207 break;
208
209 case MSIM_TYPE_DICTIONARY:
210 /* TODO: free dictionary */
211 break;
212
213 case MSIM_TYPE_LIST:
214 /* TODO: free list */
215 break;
216
217 default:
218 purple_debug_info("msim", "msim_msg_free_element: not freeing unknown type %d (%c)\n",
219 elem->type, elem->type);
220 break;
221 }
222
223 g_free(elem);
224 }
225
226 /** Free a complete message. */
227 void msim_msg_free(MsimMessage *msg)
228 {
229 if (!msg)
230 {
231 /* already free as can be */
232 return;
233 }
234
235 g_list_foreach(msg, msim_msg_free_element, NULL);
236 g_list_free(msg);
237 }
238
239 /** Send an existing MsimMessage. */
240 gboolean msim_msg_send(MsimSession *session, MsimMessage *msg)
241 {
242 gchar *raw;
243 gboolean success;
244
245 raw = msim_msg_pack(msg);
246 success = msim_send_raw(session, raw);
247 g_free(raw);
248
249 return success;
250 }
251
252 /**
253 *
254 * Send a message to the server, whose contents is specified using
255 * variable arguments.
256 *
257 * @param session
258 * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
259 *
260 * This function exists for coding convenience: it allows a message to be created
261 * and sent in one line of code. Internally it calls msim_msg_send().
262 *
263 * IMPORTANT: See msim_msg_append() documentation for details on element types.
264 *
265 */
266 gboolean msim_send(MsimSession *session, ...)
267 {
268 gboolean success;
269 MsimMessage *msg;
270 va_list argp;
271
272 va_start(argp, session);
273 msg = msim_msg_new_v(argp);
242 274
243 /* Actually send the message. */ 275 /* Actually send the message. */
244 success = msim_msg_send(session, msg); 276 success = msim_msg_send(session, msg);
245 277
246 /* Cleanup. */ 278 /* Cleanup. */
247 va_end(argp);
248 msim_msg_free(msg); 279 msim_msg_free(msg);
249 280
250 return success; 281 return success;
251 } 282 }
252 283
585 616
586 g_free(raw); 617 g_free(raw);
587 return NULL; 618 return NULL;
588 } 619 }
589 620
590 msg = msim_msg_new(); 621 msg = msim_msg_new(FALSE);
591 622
592 for (tokens = g_strsplit(raw + 1, "\\", 0), i = 0; 623 for (tokens = g_strsplit(raw + 1, "\\", 0), i = 0;
593 (token = tokens[i]); 624 (token = tokens[i]);
594 i++) 625 i++)
595 { 626 {