Mercurial > pidgin.yaz
comparison libpurple/cmds.c @ 15374:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | 32c366eeeb99 |
comparison
equal
deleted
inserted
replaced
15373:f79e0f4df793 | 15374:5fe8042783c1 |
---|---|
1 /** | |
2 * @file cmds.c Commands API | |
3 * @ingroup core | |
4 * | |
5 * Copyright (C) 2003-2004 Timothy Ringenbach <omarvo@hotmail.com | |
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 | |
23 #include <string.h> | |
24 | |
25 #include "account.h" | |
26 #include "util.h" | |
27 #include "cmds.h" | |
28 | |
29 static GList *cmds = NULL; | |
30 static guint next_id = 1; | |
31 | |
32 typedef struct _GaimCmd { | |
33 GaimCmdId id; | |
34 gchar *cmd; | |
35 gchar *args; | |
36 GaimCmdPriority priority; | |
37 GaimCmdFlag flags; | |
38 gchar *prpl_id; | |
39 GaimCmdFunc func; | |
40 gchar *help; | |
41 void *data; | |
42 } GaimCmd; | |
43 | |
44 | |
45 static gint cmds_compare_func(const GaimCmd *a, const GaimCmd *b) | |
46 { | |
47 if (a->priority > b->priority) | |
48 return -1; | |
49 else if (a->priority < b->priority) | |
50 return 1; | |
51 else return 0; | |
52 } | |
53 | |
54 GaimCmdId gaim_cmd_register(const gchar *cmd, const gchar *args, | |
55 GaimCmdPriority p, GaimCmdFlag f, | |
56 const gchar *prpl_id, GaimCmdFunc func, | |
57 const gchar *helpstr, void *data) | |
58 { | |
59 GaimCmdId id; | |
60 GaimCmd *c; | |
61 | |
62 g_return_val_if_fail(cmd != NULL && *cmd != '\0', 0); | |
63 g_return_val_if_fail(args != NULL, 0); | |
64 g_return_val_if_fail(func != NULL, 0); | |
65 | |
66 id = next_id++; | |
67 | |
68 c = g_new0(GaimCmd, 1); | |
69 c->id = id; | |
70 c->cmd = g_strdup(cmd); | |
71 c->args = g_strdup(args); | |
72 c->priority = p; | |
73 c->flags = f; | |
74 c->prpl_id = g_strdup(prpl_id); | |
75 c->func = func; | |
76 c->help = g_strdup(helpstr); | |
77 c->data = data; | |
78 | |
79 cmds = g_list_insert_sorted(cmds, c, (GCompareFunc)cmds_compare_func); | |
80 | |
81 return id; | |
82 } | |
83 | |
84 static void gaim_cmd_free(GaimCmd *c) | |
85 { | |
86 g_free(c->cmd); | |
87 g_free(c->args); | |
88 g_free(c->prpl_id); | |
89 g_free(c->help); | |
90 g_free(c); | |
91 } | |
92 | |
93 void gaim_cmd_unregister(GaimCmdId id) | |
94 { | |
95 GaimCmd *c; | |
96 GList *l; | |
97 | |
98 for (l = cmds; l; l = l->next) { | |
99 c = l->data; | |
100 | |
101 if (c->id == id) { | |
102 cmds = g_list_remove(cmds, c); | |
103 gaim_cmd_free(c); | |
104 return; | |
105 } | |
106 } | |
107 } | |
108 | |
109 /** | |
110 * This sets args to a NULL-terminated array of strings. It should | |
111 * be freed using g_strfreev(). | |
112 */ | |
113 static gboolean gaim_cmd_parse_args(GaimCmd *cmd, const gchar *s, const gchar *m, gchar ***args) | |
114 { | |
115 int i; | |
116 const char *end, *cur; | |
117 | |
118 *args = g_new0(char *, strlen(cmd->args) + 1); | |
119 | |
120 cur = s; | |
121 | |
122 for (i = 0; cmd->args[i]; i++) { | |
123 if (!*cur) | |
124 return (cmd->flags & GAIM_CMD_FLAG_ALLOW_WRONG_ARGS); | |
125 | |
126 switch (cmd->args[i]) { | |
127 case 'w': | |
128 if (!(end = strchr(cur, ' '))) { | |
129 end = cur + strlen(cur); | |
130 (*args)[i] = g_strndup(cur, end - cur); | |
131 cur = end; | |
132 } else { | |
133 (*args)[i] = g_strndup(cur, end - cur); | |
134 cur = end + 1; | |
135 } | |
136 break; | |
137 case 'W': | |
138 if (!(end = strchr(cur, ' '))) { | |
139 end = cur + strlen(cur); | |
140 (*args)[i] = gaim_markup_slice(m, g_utf8_pointer_to_offset(s, cur), g_utf8_pointer_to_offset(s, end)); | |
141 cur = end; | |
142 } else { | |
143 (*args)[i] = gaim_markup_slice(m, g_utf8_pointer_to_offset(s, cur), g_utf8_pointer_to_offset(s, end)); | |
144 cur = end +1; | |
145 } | |
146 break; | |
147 case 's': | |
148 (*args)[i] = g_strdup(cur); | |
149 cur = cur + strlen(cur); | |
150 break; | |
151 case 'S': | |
152 (*args)[i] = gaim_markup_slice(m, g_utf8_pointer_to_offset(s, cur), g_utf8_strlen(cur, -1) + 1); | |
153 cur = cur + strlen(cur); | |
154 break; | |
155 } | |
156 } | |
157 | |
158 if (*cur) | |
159 return (cmd->flags & GAIM_CMD_FLAG_ALLOW_WRONG_ARGS); | |
160 | |
161 return TRUE; | |
162 } | |
163 | |
164 static void gaim_cmd_strip_current_char(gunichar c, char *s, guint len) | |
165 { | |
166 int bytes; | |
167 | |
168 bytes = g_unichar_to_utf8(c, NULL); | |
169 memmove(s, s + bytes, len + 1 - bytes); | |
170 } | |
171 | |
172 static void gaim_cmd_strip_cmd_from_markup(char *markup) | |
173 { | |
174 guint len = strlen(markup); | |
175 char *s = markup; | |
176 | |
177 while (*s) { | |
178 gunichar c = g_utf8_get_char(s); | |
179 | |
180 if (c == '<') { | |
181 s = strchr(s, '>'); | |
182 if (!s) | |
183 return; | |
184 } else if (g_unichar_isspace(c)) { | |
185 gaim_cmd_strip_current_char(c, s, len - (s - markup)); | |
186 return; | |
187 } else { | |
188 gaim_cmd_strip_current_char(c, s, len - (s - markup)); | |
189 continue; | |
190 } | |
191 s = g_utf8_next_char(s); | |
192 } | |
193 } | |
194 | |
195 GaimCmdStatus gaim_cmd_do_command(GaimConversation *conv, const gchar *cmdline, | |
196 const gchar *markup, gchar **error) | |
197 { | |
198 GaimCmd *c; | |
199 GList *l; | |
200 gchar *err = NULL; | |
201 gboolean is_im; | |
202 gboolean found = FALSE, tried_cmd = FALSE, right_type = FALSE, right_prpl = FALSE; | |
203 const gchar *prpl_id; | |
204 gchar **args = NULL; | |
205 gchar *cmd, *rest, *mrest; | |
206 GaimCmdRet ret = GAIM_CMD_RET_CONTINUE; | |
207 | |
208 *error = NULL; | |
209 prpl_id = gaim_account_get_protocol_id(gaim_conversation_get_account(conv)); | |
210 | |
211 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) | |
212 is_im = TRUE; | |
213 else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) | |
214 is_im = FALSE; | |
215 else | |
216 return GAIM_CMD_STATUS_FAILED; | |
217 | |
218 rest = strchr(cmdline, ' '); | |
219 if (rest) { | |
220 cmd = g_strndup(cmdline, rest - cmdline); | |
221 rest++; | |
222 } else { | |
223 cmd = g_strdup(cmdline); | |
224 rest = ""; | |
225 } | |
226 | |
227 mrest = g_strdup(markup); | |
228 gaim_cmd_strip_cmd_from_markup(mrest); | |
229 | |
230 for (l = cmds; l; l = l->next) { | |
231 c = l->data; | |
232 | |
233 if (strcmp(c->cmd, cmd) != 0) | |
234 continue; | |
235 | |
236 found = TRUE; | |
237 | |
238 if (is_im) | |
239 if (!(c->flags & GAIM_CMD_FLAG_IM)) | |
240 continue; | |
241 if (!is_im) | |
242 if (!(c->flags & GAIM_CMD_FLAG_CHAT)) | |
243 continue; | |
244 | |
245 right_type = TRUE; | |
246 | |
247 if ((c->flags & GAIM_CMD_FLAG_PRPL_ONLY) && c->prpl_id && | |
248 (strcmp(c->prpl_id, prpl_id) != 0)) | |
249 continue; | |
250 | |
251 right_prpl = TRUE; | |
252 | |
253 /* this checks the allow bad args flag for us */ | |
254 if (!gaim_cmd_parse_args(c, rest, mrest, &args)) { | |
255 g_strfreev(args); | |
256 args = NULL; | |
257 continue; | |
258 } | |
259 | |
260 tried_cmd = TRUE; | |
261 ret = c->func(conv, cmd, args, &err, c->data); | |
262 if (ret == GAIM_CMD_RET_CONTINUE) { | |
263 g_free(err); | |
264 err = NULL; | |
265 g_strfreev(args); | |
266 args = NULL; | |
267 continue; | |
268 } else { | |
269 break; | |
270 } | |
271 | |
272 } | |
273 | |
274 g_strfreev(args); | |
275 g_free(cmd); | |
276 g_free(mrest); | |
277 | |
278 if (!found) | |
279 return GAIM_CMD_STATUS_NOT_FOUND; | |
280 | |
281 if (!right_type) | |
282 return GAIM_CMD_STATUS_WRONG_TYPE; | |
283 if (!right_prpl) | |
284 return GAIM_CMD_STATUS_WRONG_PRPL; | |
285 if (!tried_cmd) | |
286 return GAIM_CMD_STATUS_WRONG_ARGS; | |
287 | |
288 if (ret == GAIM_CMD_RET_OK) { | |
289 return GAIM_CMD_STATUS_OK; | |
290 } else { | |
291 *error = err; | |
292 if (ret == GAIM_CMD_RET_CONTINUE) | |
293 return GAIM_CMD_STATUS_NOT_FOUND; | |
294 else | |
295 return GAIM_CMD_STATUS_FAILED; | |
296 } | |
297 | |
298 } | |
299 | |
300 | |
301 GList *gaim_cmd_list(GaimConversation *conv) | |
302 { | |
303 GList *ret = NULL; | |
304 GaimCmd *c; | |
305 GList *l; | |
306 | |
307 for (l = cmds; l; l = l->next) { | |
308 c = l->data; | |
309 | |
310 if (conv && (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)) | |
311 if (!(c->flags & GAIM_CMD_FLAG_IM)) | |
312 continue; | |
313 if (conv && (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)) | |
314 if (!(c->flags & GAIM_CMD_FLAG_CHAT)) | |
315 continue; | |
316 | |
317 if (conv && (c->flags & GAIM_CMD_FLAG_PRPL_ONLY) && c->prpl_id && | |
318 (strcmp(c->prpl_id, gaim_account_get_protocol_id(gaim_conversation_get_account(conv))) != 0)) | |
319 continue; | |
320 | |
321 ret = g_list_append(ret, c->cmd); | |
322 } | |
323 | |
324 ret = g_list_sort(ret, (GCompareFunc)strcmp); | |
325 | |
326 return ret; | |
327 } | |
328 | |
329 | |
330 GList *gaim_cmd_help(GaimConversation *conv, const gchar *cmd) | |
331 { | |
332 GList *ret = NULL; | |
333 GaimCmd *c; | |
334 GList *l; | |
335 | |
336 for (l = cmds; l; l = l->next) { | |
337 c = l->data; | |
338 | |
339 if (cmd && (strcmp(cmd, c->cmd) != 0)) | |
340 continue; | |
341 | |
342 if (conv && (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)) | |
343 if (!(c->flags & GAIM_CMD_FLAG_IM)) | |
344 continue; | |
345 if (conv && (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)) | |
346 if (!(c->flags & GAIM_CMD_FLAG_CHAT)) | |
347 continue; | |
348 | |
349 if (conv && (c->flags & GAIM_CMD_FLAG_PRPL_ONLY) && c->prpl_id && | |
350 (strcmp(c->prpl_id, gaim_account_get_protocol_id(gaim_conversation_get_account(conv))) != 0)) | |
351 continue; | |
352 | |
353 ret = g_list_append(ret, c->help); | |
354 } | |
355 | |
356 ret = g_list_sort(ret, (GCompareFunc)strcmp); | |
357 | |
358 return ret; | |
359 } | |
360 |