| 39 } PurpleCmd; |
39 } PurpleCmd; |
| 40 |
40 |
| 41 |
41 |
| 42 static gint cmds_compare_func(const PurpleCmd *a, const PurpleCmd *b) |
42 static gint cmds_compare_func(const PurpleCmd *a, const PurpleCmd *b) |
| 43 { |
43 { |
| 44 if (a->priority > b->priority) |
44 return b->priority - a->priority; |
| 45 return -1; |
|
| 46 else if (a->priority < b->priority) |
|
| 47 return 1; |
|
| 48 else return 0; |
|
| 49 } |
45 } |
| 50 |
46 |
| 51 PurpleCmdId purple_cmd_register(const gchar *cmd, const gchar *args, |
47 PurpleCmdId purple_cmd_register(const gchar *cmd, const gchar *args, |
| 52 PurpleCmdPriority p, PurpleCmdFlag f, |
48 PurpleCmdPriority p, PurpleCmdFlag f, |
| 53 const gchar *protocol_id, PurpleCmdFunc func, |
49 const gchar *protocol_id, PurpleCmdFunc func, |
| 92 g_free(c->protocol_id); |
88 g_free(c->protocol_id); |
| 93 g_free(c->help); |
89 g_free(c->help); |
| 94 g_free(c); |
90 g_free(c); |
| 95 } |
91 } |
| 96 |
92 |
| |
93 static gint |
| |
94 purple_cmd_cmp_id(gconstpointer cmd, gconstpointer id) |
| |
95 { |
| |
96 return ((PurpleCmd *)cmd)->id - GPOINTER_TO_UINT(id); |
| |
97 } |
| |
98 |
| 97 void purple_cmd_unregister(PurpleCmdId id) |
99 void purple_cmd_unregister(PurpleCmdId id) |
| 98 { |
100 { |
| 99 PurpleCmd *c; |
101 PurpleCmd *c; |
| 100 GList *l; |
102 GList *l; |
| 101 |
103 PurpleCommandsUiOps *ops; |
| 102 for (l = cmds; l; l = l->next) { |
104 |
| 103 c = l->data; |
105 l = g_list_find_custom(cmds, GUINT_TO_POINTER(id), purple_cmd_cmp_id); |
| 104 |
106 if (!l) { |
| 105 if (c->id == id) { |
107 return; |
| 106 PurpleCommandsUiOps *ops = purple_cmds_get_ui_ops(); |
108 } |
| 107 if (ops && ops->unregister_command) |
109 |
| 108 ops->unregister_command(c->cmd, c->protocol_id); |
110 c = l->data; |
| 109 |
111 |
| 110 cmds = g_list_delete_link(cmds, l); |
112 ops = purple_cmds_get_ui_ops(); |
| 111 purple_signal_emit(purple_cmds_get_handle(), "cmd-removed", c->cmd); |
113 if (ops && ops->unregister_command) { |
| 112 purple_cmd_free(c); |
114 ops->unregister_command(c->cmd, c->protocol_id); |
| 113 return; |
115 } |
| 114 } |
116 |
| 115 } |
117 cmds = g_list_delete_link(cmds, l); |
| |
118 purple_signal_emit(purple_cmds_get_handle(), "cmd-removed", c->cmd); |
| |
119 purple_cmd_free(c); |
| 116 } |
120 } |
| 117 |
121 |
| 118 /* |
122 /* |
| 119 * This sets args to a NULL-terminated array of strings. It should |
123 * This sets args to a NULL-terminated array of strings. It should |
| 120 * be freed using g_strfreev(). |
124 * be freed using g_strfreev(). |
| 199 } |
203 } |
| 200 s = g_utf8_next_char(s); |
204 s = g_utf8_next_char(s); |
| 201 } |
205 } |
| 202 } |
206 } |
| 203 |
207 |
| |
208 static gboolean |
| |
209 is_right_type(PurpleCmd *cmd, PurpleConversation *conv) |
| |
210 { |
| |
211 return (PURPLE_IS_IM_CONVERSATION(conv) && (cmd->flags & PURPLE_CMD_FLAG_IM)) |
| |
212 || (PURPLE_IS_CHAT_CONVERSATION(conv) && (cmd->flags & PURPLE_CMD_FLAG_CHAT)); |
| |
213 } |
| |
214 |
| |
215 static gboolean |
| |
216 is_right_protocol(PurpleCmd *cmd, PurpleConversation *conv) |
| |
217 { |
| |
218 const gchar *protocol_id = purple_account_get_protocol_id(purple_conversation_get_account(conv)); |
| |
219 |
| |
220 return !(cmd->flags & PURPLE_CMD_FLAG_PROTOCOL_ONLY) |
| |
221 || purple_strequal(cmd->protocol_id, protocol_id); |
| |
222 } |
| |
223 |
| 204 PurpleCmdStatus purple_cmd_do_command(PurpleConversation *conv, const gchar *cmdline, |
224 PurpleCmdStatus purple_cmd_do_command(PurpleConversation *conv, const gchar *cmdline, |
| 205 const gchar *markup, gchar **error) |
225 const gchar *markup, gchar **error) |
| 206 { |
226 { |
| 207 PurpleCmd *c; |
|
| 208 GList *l; |
|
| 209 gchar *err = NULL; |
227 gchar *err = NULL; |
| 210 gboolean is_im = TRUE; |
|
| 211 gboolean found = FALSE, tried_cmd = FALSE, right_type = FALSE, right_protocol = FALSE; |
228 gboolean found = FALSE, tried_cmd = FALSE, right_type = FALSE, right_protocol = FALSE; |
| 212 const gchar *protocol_id; |
|
| 213 gchar **args = NULL; |
|
| 214 gchar *cmd, *rest, *mrest; |
229 gchar *cmd, *rest, *mrest; |
| 215 PurpleCmdRet ret = PURPLE_CMD_RET_CONTINUE; |
230 PurpleCmdRet ret = PURPLE_CMD_RET_CONTINUE; |
| 216 |
231 |
| 217 *error = NULL; |
232 *error = NULL; |
| 218 protocol_id = purple_account_get_protocol_id(purple_conversation_get_account(conv)); |
|
| 219 |
|
| 220 if (PURPLE_IS_CHAT_CONVERSATION(conv)) |
|
| 221 is_im = FALSE; |
|
| 222 |
233 |
| 223 rest = strchr(cmdline, ' '); |
234 rest = strchr(cmdline, ' '); |
| 224 if (rest) { |
235 if (rest) { |
| 225 cmd = g_strndup(cmdline, rest - cmdline); |
236 cmd = g_strndup(cmdline, rest - cmdline); |
| 226 rest++; |
237 rest++; |
| 230 } |
241 } |
| 231 |
242 |
| 232 mrest = g_strdup(markup); |
243 mrest = g_strdup(markup); |
| 233 purple_cmd_strip_cmd_from_markup(mrest); |
244 purple_cmd_strip_cmd_from_markup(mrest); |
| 234 |
245 |
| 235 for (l = cmds; l; l = l->next) { |
246 for (GList *l = cmds; l; l = l->next) { |
| 236 c = l->data; |
247 PurpleCmd *c = l->data; |
| |
248 gchar **args = NULL; |
| 237 |
249 |
| 238 if (!purple_strequal(c->cmd, cmd)) |
250 if (!purple_strequal(c->cmd, cmd)) |
| 239 continue; |
251 continue; |
| 240 |
252 |
| 241 found = TRUE; |
253 found = TRUE; |
| 242 |
254 |
| 243 if (is_im) |
255 if (!is_right_type(c, conv)) { |
| 244 if (!(c->flags & PURPLE_CMD_FLAG_IM)) |
256 continue; |
| 245 continue; |
257 } |
| 246 if (!is_im) |
|
| 247 if (!(c->flags & PURPLE_CMD_FLAG_CHAT)) |
|
| 248 continue; |
|
| 249 |
258 |
| 250 right_type = TRUE; |
259 right_type = TRUE; |
| 251 |
260 |
| 252 if ((c->flags & PURPLE_CMD_FLAG_PROTOCOL_ONLY) && |
261 if (!is_right_protocol(c, conv)) { |
| 253 !purple_strequal(c->protocol_id, protocol_id)) |
262 continue; |
| 254 continue; |
263 } |
| 255 |
264 |
| 256 right_protocol = TRUE; |
265 right_protocol = TRUE; |
| 257 |
266 |
| 258 /* this checks the allow bad args flag for us */ |
267 /* this checks the allow bad args flag for us */ |
| 259 if (!purple_cmd_parse_args(c, rest, mrest, &args)) { |
268 if (!purple_cmd_parse_args(c, rest, mrest, &args)) { |
| 260 g_strfreev(args); |
269 g_strfreev(args); |
| 261 args = NULL; |
|
| 262 continue; |
270 continue; |
| 263 } |
271 } |
| 264 |
272 |
| 265 tried_cmd = TRUE; |
273 tried_cmd = TRUE; |
| 266 ret = c->func(conv, cmd, args, &err, c->data); |
274 ret = c->func(conv, cmd, args, &err, c->data); |
| |
275 g_strfreev(args); |
| 267 if (ret == PURPLE_CMD_RET_CONTINUE) { |
276 if (ret == PURPLE_CMD_RET_CONTINUE) { |
| 268 g_free(err); |
277 g_free(err); |
| 269 err = NULL; |
278 err = NULL; |
| 270 g_strfreev(args); |
279 continue; |
| 271 args = NULL; |
280 } |
| 272 continue; |
281 |
| 273 } else { |
282 break; |
| 274 break; |
283 } |
| 275 } |
284 |
| 276 |
|
| 277 } |
|
| 278 |
|
| 279 g_strfreev(args); |
|
| 280 g_free(cmd); |
285 g_free(cmd); |
| 281 g_free(mrest); |
286 g_free(mrest); |
| 282 |
287 |
| 283 if (!found) |
288 if (!found) |
| 284 return PURPLE_CMD_STATUS_NOT_FOUND; |
289 return PURPLE_CMD_STATUS_NOT_FOUND; |
| 288 if (!right_protocol) |
293 if (!right_protocol) |
| 289 return PURPLE_CMD_STATUS_WRONG_PROTOCOL; |
294 return PURPLE_CMD_STATUS_WRONG_PROTOCOL; |
| 290 if (!tried_cmd) |
295 if (!tried_cmd) |
| 291 return PURPLE_CMD_STATUS_WRONG_ARGS; |
296 return PURPLE_CMD_STATUS_WRONG_ARGS; |
| 292 |
297 |
| 293 if (ret == PURPLE_CMD_RET_OK) { |
298 if (ret != PURPLE_CMD_RET_OK) { |
| 294 return PURPLE_CMD_STATUS_OK; |
|
| 295 } else { |
|
| 296 *error = err; |
299 *error = err; |
| 297 if (ret == PURPLE_CMD_RET_CONTINUE) |
300 if (ret == PURPLE_CMD_RET_CONTINUE) |
| 298 return PURPLE_CMD_STATUS_NOT_FOUND; |
301 return PURPLE_CMD_STATUS_NOT_FOUND; |
| 299 else |
302 else |
| 300 return PURPLE_CMD_STATUS_FAILED; |
303 return PURPLE_CMD_STATUS_FAILED; |
| 301 } |
304 } |
| 302 |
305 |
| |
306 return PURPLE_CMD_STATUS_OK; |
| 303 } |
307 } |
| 304 |
308 |
| 305 gboolean purple_cmd_execute(PurpleCmdId id, PurpleConversation *conv, |
309 gboolean purple_cmd_execute(PurpleCmdId id, PurpleConversation *conv, |
| 306 const gchar *cmdline) |
310 const gchar *cmdline) |
| 307 { |
311 { |
| 309 PurpleCmdRet ret = PURPLE_CMD_RET_CONTINUE; |
313 PurpleCmdRet ret = PURPLE_CMD_RET_CONTINUE; |
| 310 GList *l = NULL; |
314 GList *l = NULL; |
| 311 gchar *err = NULL; |
315 gchar *err = NULL; |
| 312 gchar **args = NULL; |
316 gchar **args = NULL; |
| 313 |
317 |
| 314 for(l = cmds; l; l = l->next) { |
318 l = g_list_find_custom(cmds, GUINT_TO_POINTER(id), purple_cmd_cmp_id); |
| 315 cmd = (PurpleCmd*)l->data; |
319 if (!l) { |
| 316 |
|
| 317 if(cmd->id == id) { |
|
| 318 break; |
|
| 319 } |
|
| 320 cmd = NULL; |
|
| 321 } |
|
| 322 if(cmd == NULL) { |
|
| 323 return FALSE; |
320 return FALSE; |
| 324 } |
321 } |
| 325 |
322 |
| 326 if (PURPLE_IS_IM_CONVERSATION(conv)) { |
323 cmd = l->data; |
| 327 if (!(cmd->flags & PURPLE_CMD_FLAG_IM)) |
324 |
| 328 return FALSE; |
325 if (!is_right_type(cmd, conv)) { |
| 329 } |
|
| 330 else if (PURPLE_IS_CHAT_CONVERSATION(conv)) { |
|
| 331 if (!(cmd->flags & PURPLE_CMD_FLAG_CHAT)) |
|
| 332 return FALSE; |
|
| 333 } |
|
| 334 else |
|
| 335 return FALSE; |
326 return FALSE; |
| |
327 } |
| 336 |
328 |
| 337 /* XXX: Don't worry much about the markup version of the command |
329 /* XXX: Don't worry much about the markup version of the command |
| 338 line, there's not a single use case... */ |
330 line, there's not a single use case... */ |
| 339 /* this checks the allow bad args flag for us */ |
331 /* this checks the allow bad args flag for us */ |
| 340 if (!purple_cmd_parse_args(cmd, cmdline, cmdline, &args)) { |
332 if (!purple_cmd_parse_args(cmd, cmdline, cmdline, &args)) { |
| 351 } |
343 } |
| 352 |
344 |
| 353 GList *purple_cmd_list(PurpleConversation *conv) |
345 GList *purple_cmd_list(PurpleConversation *conv) |
| 354 { |
346 { |
| 355 GList *ret = NULL; |
347 GList *ret = NULL; |
| 356 PurpleCmd *c; |
348 |
| 357 GList *l; |
349 for (GList *l = cmds; l; l = l->next) { |
| 358 |
350 PurpleCmd *c = l->data; |
| 359 for (l = cmds; l; l = l->next) { |
351 |
| 360 c = l->data; |
352 if (conv && (!is_right_type(c, conv) || !is_right_protocol(c, conv))) { |
| 361 |
353 continue; |
| 362 if (conv && PURPLE_IS_IM_CONVERSATION(conv)) |
354 } |
| 363 if (!(c->flags & PURPLE_CMD_FLAG_IM)) |
|
| 364 continue; |
|
| 365 if (conv && PURPLE_IS_CHAT_CONVERSATION(conv)) |
|
| 366 if (!(c->flags & PURPLE_CMD_FLAG_CHAT)) |
|
| 367 continue; |
|
| 368 |
|
| 369 if (conv && (c->flags & PURPLE_CMD_FLAG_PROTOCOL_ONLY) && |
|
| 370 !purple_strequal(c->protocol_id, purple_account_get_protocol_id(purple_conversation_get_account(conv)))) |
|
| 371 continue; |
|
| 372 |
355 |
| 373 ret = g_list_append(ret, c->cmd); |
356 ret = g_list_append(ret, c->cmd); |
| 374 } |
357 } |
| 375 |
358 |
| 376 ret = g_list_sort(ret, (GCompareFunc)strcmp); |
359 ret = g_list_sort(ret, (GCompareFunc)strcmp); |
| 380 |
363 |
| 381 |
364 |
| 382 GList *purple_cmd_help(PurpleConversation *conv, const gchar *cmd) |
365 GList *purple_cmd_help(PurpleConversation *conv, const gchar *cmd) |
| 383 { |
366 { |
| 384 GList *ret = NULL; |
367 GList *ret = NULL; |
| 385 PurpleCmd *c; |
368 |
| 386 GList *l; |
369 for (GList *l = cmds; l; l = l->next) { |
| 387 |
370 PurpleCmd *c = l->data; |
| 388 for (l = cmds; l; l = l->next) { |
|
| 389 c = l->data; |
|
| 390 |
371 |
| 391 if (cmd && !purple_strequal(cmd, c->cmd)) |
372 if (cmd && !purple_strequal(cmd, c->cmd)) |
| 392 continue; |
373 continue; |
| 393 |
374 |
| 394 if (conv && PURPLE_IS_IM_CONVERSATION(conv)) |
375 if (conv && (!is_right_type(c, conv) || !is_right_protocol(c, conv))) { |
| 395 if (!(c->flags & PURPLE_CMD_FLAG_IM)) |
376 continue; |
| 396 continue; |
377 } |
| 397 if (conv && PURPLE_IS_CHAT_CONVERSATION(conv)) |
|
| 398 if (!(c->flags & PURPLE_CMD_FLAG_CHAT)) |
|
| 399 continue; |
|
| 400 |
|
| 401 if (conv && (c->flags & PURPLE_CMD_FLAG_PROTOCOL_ONLY) && |
|
| 402 !purple_strequal(c->protocol_id, purple_account_get_protocol_id(purple_conversation_get_account(conv)))) |
|
| 403 continue; |
|
| 404 |
378 |
| 405 ret = g_list_append(ret, c->help); |
379 ret = g_list_append(ret, c->help); |
| 406 } |
380 } |
| 407 |
381 |
| 408 ret = g_list_sort(ret, (GCompareFunc)strcmp); |
382 ret = g_list_sort(ret, (GCompareFunc)strcmp); |