2 * @file cmds.c Commands API
6 /* Copyright (C) 2003-2004 Timothy Ringenbach <omarvo@hotmail.com
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
30 static GList
*cmds
= NULL
;
31 static guint next_id
= 1;
33 typedef struct _PurpleCmd
{
37 PurpleCmdPriority priority
;
46 static gint
cmds_compare_func(const PurpleCmd
*a
, const PurpleCmd
*b
)
48 if (a
->priority
> b
->priority
)
50 else if (a
->priority
< b
->priority
)
55 PurpleCmdId
purple_cmd_register(const gchar
*cmd
, const gchar
*args
,
56 PurpleCmdPriority p
, PurpleCmdFlag f
,
57 const gchar
*prpl_id
, PurpleCmdFunc func
,
58 const gchar
*helpstr
, void *data
)
63 g_return_val_if_fail(cmd
!= NULL
&& *cmd
!= '\0', 0);
64 g_return_val_if_fail(args
!= NULL
, 0);
65 g_return_val_if_fail(func
!= NULL
, 0);
69 c
= g_new0(PurpleCmd
, 1);
71 c
->cmd
= g_strdup(cmd
);
72 c
->args
= g_strdup(args
);
75 c
->prpl_id
= g_strdup(prpl_id
);
77 c
->help
= g_strdup(helpstr
);
80 cmds
= g_list_insert_sorted(cmds
, c
, (GCompareFunc
)cmds_compare_func
);
82 purple_signal_emit(purple_cmds_get_handle(), "cmd-added", cmd
, p
, f
);
87 static void purple_cmd_free(PurpleCmd
*c
)
96 void purple_cmd_unregister(PurpleCmdId id
)
101 for (l
= cmds
; l
; l
= l
->next
) {
105 cmds
= g_list_remove(cmds
, c
);
106 purple_signal_emit(purple_cmds_get_handle(), "cmd-removed", c
->cmd
);
114 * This sets args to a NULL-terminated array of strings. It should
115 * be freed using g_strfreev().
117 static gboolean
purple_cmd_parse_args(PurpleCmd
*cmd
, const gchar
*s
, const gchar
*m
, gchar
***args
)
120 const char *end
, *cur
;
122 *args
= g_new0(char *, strlen(cmd
->args
) + 1);
126 for (i
= 0; cmd
->args
[i
]; i
++) {
128 return (cmd
->flags
& PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
);
130 switch (cmd
->args
[i
]) {
132 if (!(end
= strchr(cur
, ' '))) {
133 end
= cur
+ strlen(cur
);
134 (*args
)[i
] = g_strndup(cur
, end
- cur
);
137 (*args
)[i
] = g_strndup(cur
, end
- cur
);
142 if (!(end
= strchr(cur
, ' '))) {
143 end
= cur
+ strlen(cur
);
144 (*args
)[i
] = purple_markup_slice(m
, g_utf8_pointer_to_offset(s
, cur
), g_utf8_pointer_to_offset(s
, end
));
147 (*args
)[i
] = purple_markup_slice(m
, g_utf8_pointer_to_offset(s
, cur
), g_utf8_pointer_to_offset(s
, end
));
152 (*args
)[i
] = g_strdup(cur
);
153 cur
= cur
+ strlen(cur
);
156 (*args
)[i
] = purple_markup_slice(m
, g_utf8_pointer_to_offset(s
, cur
), g_utf8_strlen(cur
, -1) + 1);
157 cur
= cur
+ strlen(cur
);
163 return (cmd
->flags
& PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS
);
168 static void purple_cmd_strip_current_char(gunichar c
, char *s
, guint len
)
172 bytes
= g_unichar_to_utf8(c
, NULL
);
173 memmove(s
, s
+ bytes
, len
+ 1 - bytes
);
176 static void purple_cmd_strip_cmd_from_markup(char *markup
)
178 guint len
= strlen(markup
);
182 gunichar c
= g_utf8_get_char(s
);
188 } else if (g_unichar_isspace(c
)) {
189 purple_cmd_strip_current_char(c
, s
, len
- (s
- markup
));
192 purple_cmd_strip_current_char(c
, s
, len
- (s
- markup
));
195 s
= g_utf8_next_char(s
);
199 PurpleCmdStatus
purple_cmd_do_command(PurpleConversation
*conv
, const gchar
*cmdline
,
200 const gchar
*markup
, gchar
**error
)
206 gboolean found
= FALSE
, tried_cmd
= FALSE
, right_type
= FALSE
, right_prpl
= FALSE
;
207 const gchar
*prpl_id
;
209 gchar
*cmd
, *rest
, *mrest
;
210 PurpleCmdRet ret
= PURPLE_CMD_RET_CONTINUE
;
213 prpl_id
= purple_account_get_protocol_id(purple_conversation_get_account(conv
));
215 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
)
217 else if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
)
220 return PURPLE_CMD_STATUS_FAILED
;
222 rest
= strchr(cmdline
, ' ');
224 cmd
= g_strndup(cmdline
, rest
- cmdline
);
227 cmd
= g_strdup(cmdline
);
231 mrest
= g_strdup(markup
);
232 purple_cmd_strip_cmd_from_markup(mrest
);
234 for (l
= cmds
; l
; l
= l
->next
) {
237 if (!purple_strequal(c
->cmd
, cmd
))
243 if (!(c
->flags
& PURPLE_CMD_FLAG_IM
))
246 if (!(c
->flags
& PURPLE_CMD_FLAG_CHAT
))
251 if ((c
->flags
& PURPLE_CMD_FLAG_PRPL_ONLY
) &&
252 !purple_strequal(c
->prpl_id
, prpl_id
))
257 /* this checks the allow bad args flag for us */
258 if (!purple_cmd_parse_args(c
, rest
, mrest
, &args
)) {
265 ret
= c
->func(conv
, cmd
, args
, &err
, c
->data
);
266 if (ret
== PURPLE_CMD_RET_CONTINUE
) {
283 return PURPLE_CMD_STATUS_NOT_FOUND
;
286 return PURPLE_CMD_STATUS_WRONG_TYPE
;
288 return PURPLE_CMD_STATUS_WRONG_PRPL
;
290 return PURPLE_CMD_STATUS_WRONG_ARGS
;
292 if (ret
== PURPLE_CMD_RET_OK
) {
293 return PURPLE_CMD_STATUS_OK
;
296 if (ret
== PURPLE_CMD_RET_CONTINUE
)
297 return PURPLE_CMD_STATUS_NOT_FOUND
;
299 return PURPLE_CMD_STATUS_FAILED
;
305 GList
*purple_cmd_list(PurpleConversation
*conv
)
311 for (l
= cmds
; l
; l
= l
->next
) {
314 if (conv
&& (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
))
315 if (!(c
->flags
& PURPLE_CMD_FLAG_IM
))
317 if (conv
&& (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
))
318 if (!(c
->flags
& PURPLE_CMD_FLAG_CHAT
))
321 if (conv
&& (c
->flags
& PURPLE_CMD_FLAG_PRPL_ONLY
) &&
322 !purple_strequal(c
->prpl_id
, purple_account_get_protocol_id(purple_conversation_get_account(conv
))))
325 ret
= g_list_append(ret
, c
->cmd
);
328 ret
= g_list_sort(ret
, (GCompareFunc
)strcmp
);
334 GList
*purple_cmd_help(PurpleConversation
*conv
, const gchar
*cmd
)
340 for (l
= cmds
; l
; l
= l
->next
) {
343 if (cmd
&& !purple_strequal(cmd
, c
->cmd
))
346 if (conv
&& (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
))
347 if (!(c
->flags
& PURPLE_CMD_FLAG_IM
))
349 if (conv
&& (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
))
350 if (!(c
->flags
& PURPLE_CMD_FLAG_CHAT
))
353 if (conv
&& (c
->flags
& PURPLE_CMD_FLAG_PRPL_ONLY
) &&
354 !purple_strequal(c
->prpl_id
, purple_account_get_protocol_id(purple_conversation_get_account(conv
))))
357 ret
= g_list_append(ret
, c
->help
);
360 ret
= g_list_sort(ret
, (GCompareFunc
)strcmp
);
365 gpointer
purple_cmds_get_handle(void)
371 void purple_cmds_init(void)
373 gpointer handle
= purple_cmds_get_handle();
375 purple_signal_register(handle
, "cmd-added",
376 purple_marshal_VOID__POINTER_INT_INT
, NULL
, 3,
377 purple_value_new(PURPLE_TYPE_STRING
),
378 purple_value_new(PURPLE_TYPE_INT
),
379 purple_value_new(PURPLE_TYPE_INT
));
380 purple_signal_register(handle
, "cmd-removed",
381 purple_marshal_VOID__POINTER
, NULL
, 1,
382 purple_value_new(PURPLE_TYPE_STRING
));
385 void purple_cmds_uninit(void)
387 purple_signals_unregister_by_instance(purple_cmds_get_handle());