Mercurial > pidgin
annotate plugins/tcl/tcl_signals.c @ 11111:f03dce7ea408
[gaim-migrate @ 13163]
Patch #1234440, from sadrul
"Mark blocked users in the buddy-list"
Patch #1234197, from sadrul
"New API fn gaim_privacy_check"
Plus changes by me. (Read as: blame me if it's busted, thank sadrul if it works)
Basically, all this stuff boils down to the following:
We composite a new blocked.png onto the prpl icon in the buddy list if the user is blocked.
MSN was the only prpl that used the old blocked.png. However, it looks bad to overlay both icons, so I removed the use of blocked.png from the MSN prpl. As an MSN user, I think the result is intuitive.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Sun, 17 Jul 2005 23:36:34 +0000 |
parents | 9eb235c6dc0a |
children | 8d1cf3f847b1 |
rev | line source |
---|---|
6694 | 1 /** |
2 * @file tcl_signals.c Gaim Tcl signal API | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2003 Ethan Blanton <eblanton@cs.purdue.edu> | |
7 * | |
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. | |
12 * | |
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. | |
17 * | |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 #include <tcl.h> | |
23 #include <stdarg.h> | |
24 | |
25 #include "tcl_gaim.h" | |
26 | |
27 #include "internal.h" | |
28 #include "connection.h" | |
29 #include "conversation.h" | |
30 #include "signals.h" | |
31 #include "debug.h" | |
32 #include "value.h" | |
33 #include "core.h" | |
34 | |
35 static GList *tcl_callbacks; | |
36 | |
37 static void *tcl_signal_callback(va_list args, struct tcl_signal_handler *handler); | |
10597 | 38 static Tcl_Obj *new_cb_namespace (); |
6694 | 39 |
40 void tcl_signal_init() | |
41 { | |
42 tcl_callbacks = NULL; | |
43 } | |
44 | |
45 void tcl_signal_handler_free(struct tcl_signal_handler *handler) | |
46 { | |
47 if (handler == NULL) | |
48 return; | |
49 | |
10597 | 50 Tcl_DecrRefCount(handler->signal); |
51 Tcl_DecrRefCount(handler->namespace); | |
6694 | 52 g_free(handler); |
53 } | |
54 | |
55 void tcl_signal_cleanup(Tcl_Interp *interp) | |
56 { | |
57 GList *cur; | |
58 struct tcl_signal_handler *handler; | |
59 | |
60 for (cur = tcl_callbacks; cur != NULL; cur = g_list_next(cur)) { | |
61 handler = cur->data; | |
62 if (handler->interp == interp) { | |
63 tcl_signal_handler_free(handler); | |
64 cur->data = NULL; | |
65 } | |
66 } | |
67 tcl_callbacks = g_list_remove_all(tcl_callbacks, NULL); | |
68 } | |
69 | |
70 gboolean tcl_signal_connect(struct tcl_signal_handler *handler) | |
71 { | |
10597 | 72 GString *proc; |
73 | |
74 gaim_signal_get_values(handler->instance, | |
75 Tcl_GetString(handler->signal), | |
76 &handler->returntype, &handler->nargs, | |
77 &handler->argtypes); | |
6694 | 78 |
10597 | 79 tcl_signal_disconnect(handler->interp, Tcl_GetString(handler->signal), |
80 handler->interp); | |
81 | |
82 if (!gaim_signal_connect_vargs(handler->instance, | |
83 Tcl_GetString(handler->signal), | |
84 (void *)handler->interp, | |
85 GAIM_CALLBACK(tcl_signal_callback), | |
86 (void *)handler)) | |
6694 | 87 return FALSE; |
88 | |
10597 | 89 Tcl_IncrRefCount(handler->signal); |
90 handler->namespace = new_cb_namespace (); | |
91 Tcl_IncrRefCount(handler->namespace); | |
92 proc = g_string_new(""); | |
93 g_string_append_printf(proc, "namespace eval %s { proc cb { %s } { %s } }", | |
94 Tcl_GetString(handler->namespace), | |
95 Tcl_GetString(handler->args), | |
96 Tcl_GetString(handler->proc)); | |
97 if (Tcl_Eval(handler->interp, proc->str) != TCL_OK) { | |
98 Tcl_DecrRefCount(handler->namespace); | |
99 g_string_free(proc, TRUE); | |
6694 | 100 return FALSE; |
10597 | 101 } |
102 g_string_free(proc, TRUE); | |
6694 | 103 |
104 tcl_callbacks = g_list_append(tcl_callbacks, (gpointer)handler); | |
105 | |
106 return TRUE; | |
107 } | |
108 | |
109 void tcl_signal_disconnect(void *instance, const char *signal, Tcl_Interp *interp) | |
110 { | |
111 GList *cur; | |
112 struct tcl_signal_handler *handler; | |
113 gboolean found = FALSE; | |
10597 | 114 GString *cmd; |
6694 | 115 |
116 for (cur = tcl_callbacks; cur != NULL; cur = g_list_next(cur)) { | |
117 handler = cur->data; | |
118 if (handler->interp == interp && handler->instance == instance | |
10597 | 119 && !strcmp(signal, Tcl_GetString(handler->signal))) { |
6694 | 120 gaim_signal_disconnect(instance, signal, handler->interp, |
121 GAIM_CALLBACK(tcl_signal_callback)); | |
10597 | 122 cmd = g_string_sized_new(64); |
123 g_string_printf(cmd, "namespace delete %s", | |
124 Tcl_GetString(handler->namespace)); | |
125 Tcl_EvalEx(interp, cmd->str, -1, TCL_EVAL_GLOBAL); | |
6694 | 126 tcl_signal_handler_free(handler); |
10597 | 127 g_string_free(cmd, TRUE); |
6694 | 128 cur->data = NULL; |
129 found = TRUE; | |
130 break; | |
131 } | |
132 } | |
133 if (found) | |
134 tcl_callbacks = g_list_remove_all(tcl_callbacks, NULL); | |
135 } | |
136 | |
137 static void *tcl_signal_callback(va_list args, struct tcl_signal_handler *handler) | |
138 { | |
10597 | 139 GString *name, *val; |
6694 | 140 GaimBlistNode *node; |
141 int error, i; | |
142 void *retval = NULL; | |
10597 | 143 Tcl_Obj *cmd, *arg, *result; |
144 void **vals; /* Used for inout parameters */ | |
145 char ***strs; | |
6694 | 146 |
10597 | 147 vals = g_new0(void *, handler->nargs); |
148 strs = g_new0(char **, handler->nargs); | |
149 name = g_string_sized_new(32); | |
6694 | 150 val = g_string_sized_new(32); |
10597 | 151 |
152 cmd = Tcl_NewListObj(0, NULL); | |
153 Tcl_IncrRefCount(cmd); | |
154 | |
155 arg = Tcl_DuplicateObj(handler->namespace); | |
156 Tcl_AppendStringsToObj(arg, "::cb", NULL); | |
157 Tcl_ListObjAppendElement(handler->interp, cmd, arg); | |
6694 | 158 |
159 for (i = 0; i < handler->nargs; i++) { | |
10597 | 160 if (gaim_value_is_outgoing(handler->argtypes[i])) |
161 g_string_printf(name, "%s::arg%d", | |
162 Tcl_GetString(handler->namespace), i); | |
6694 | 163 |
164 switch(gaim_value_get_type(handler->argtypes[i])) { | |
165 case GAIM_TYPE_UNKNOWN: /* What? I guess just pass the word ... */ | |
166 /* treat this as a pointer, but complain first */ | |
167 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "unknown GaimValue type %d\n", | |
168 gaim_value_get_type(handler->argtypes[i])); | |
169 case GAIM_TYPE_POINTER: | |
170 case GAIM_TYPE_OBJECT: | |
171 case GAIM_TYPE_BOXED: | |
172 /* These are all "pointer" types to us */ | |
173 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
10597 | 174 vals[i] = va_arg(args, void **); |
175 Tcl_LinkVar(handler->interp, name->str, | |
176 vals[i], TCL_LINK_INT); | |
177 arg = Tcl_NewStringObj(name->str, -1); | |
6694 | 178 } else { |
10597 | 179 arg = Tcl_NewIntObj((int)va_arg(args, void *)); |
6694 | 180 } |
181 break; | |
182 case GAIM_TYPE_BOOLEAN: | |
183 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
10597 | 184 vals[i] = va_arg(args, gboolean *); |
185 Tcl_LinkVar(handler->interp, name->str, | |
186 (char *)&vals[i], TCL_LINK_BOOLEAN); | |
187 arg = Tcl_NewStringObj(name->str, -1); | |
6694 | 188 } else { |
10597 | 189 arg = Tcl_NewBooleanObj(va_arg(args, gboolean)); |
6694 | 190 } |
191 break; | |
192 case GAIM_TYPE_CHAR: | |
193 case GAIM_TYPE_UCHAR: | |
194 case GAIM_TYPE_SHORT: | |
195 case GAIM_TYPE_USHORT: | |
196 case GAIM_TYPE_INT: | |
197 case GAIM_TYPE_UINT: | |
198 case GAIM_TYPE_LONG: | |
199 case GAIM_TYPE_ULONG: | |
200 case GAIM_TYPE_ENUM: | |
201 /* I should really cast these individually to | |
202 * preserve as much information as possible ... | |
203 * but heh */ | |
204 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
10597 | 205 vals[i] = va_arg(args, int *); |
206 Tcl_LinkVar(handler->interp, name->str, | |
207 vals[i], TCL_LINK_INT); | |
208 arg = Tcl_NewStringObj(name->str, -1); | |
6694 | 209 } else { |
10597 | 210 arg = Tcl_NewIntObj(va_arg(args, int)); |
211 } | |
212 case GAIM_TYPE_INT64: | |
213 case GAIM_TYPE_UINT64: | |
10625 | 214 /* Tcl < 8.4 doesn't have wide ints, so we have ugly |
215 * ifdefs in here */ | |
10597 | 216 if (gaim_value_is_outgoing(handler->argtypes[i])) { |
10625 | 217 vals[i] = (void *)va_arg(args, gint64 *); |
218 #if (TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >= 4) | |
10597 | 219 Tcl_LinkVar(handler->interp, name->str, |
220 vals[i], TCL_LINK_WIDE_INT); | |
10625 | 221 #else |
222 /* This is going to cause weirdness at best, | |
223 * but what do you want ... we're losing | |
224 * precision */ | |
225 Tcl_LinkVar(handler->interp, name->str, | |
226 vals[i], TCL_LINK_INT); | |
227 #endif /* Tcl >= 8.4 */ | |
10597 | 228 arg = Tcl_NewStringObj(name->str, -1); |
229 } else { | |
10625 | 230 #if (TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >= 4) |
231 arg = Tcl_NewWideIntObj(va_arg(args, gint64)); | |
232 #else | |
233 arg = Tcl_NewIntObj((int)va_arg(args, int)); | |
234 #endif /* Tcl >= 8.4 */ | |
6694 | 235 } |
236 break; | |
237 case GAIM_TYPE_STRING: | |
238 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
10597 | 239 strs[i] = va_arg(args, char **); |
240 if (strs[i] == NULL || *strs[i] == NULL) { | |
241 vals[i] = ckalloc(1); | |
242 *(char *)vals[i] = '\0'; | |
6694 | 243 } else { |
10597 | 244 vals[i] = ckalloc(strlen(*strs[i]) + 1); |
245 strcpy(vals[i], *strs[i]); | |
6694 | 246 } |
10597 | 247 Tcl_LinkVar(handler->interp, name->str, |
248 (char *)&vals[i], TCL_LINK_STRING); | |
249 arg = Tcl_NewStringObj(name->str, -1); | |
6694 | 250 } else { |
10597 | 251 arg = Tcl_NewStringObj(va_arg(args, char *), -1); |
6694 | 252 } |
253 break; | |
254 case GAIM_TYPE_SUBTYPE: | |
255 switch (gaim_value_get_subtype(handler->argtypes[i])) { | |
256 case GAIM_SUBTYPE_UNKNOWN: | |
257 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "subtype unknown\n"); | |
258 case GAIM_SUBTYPE_ACCOUNT: | |
259 case GAIM_SUBTYPE_CONNECTION: | |
260 case GAIM_SUBTYPE_CONVERSATION: | |
261 case GAIM_SUBTYPE_CONV_WINDOW: | |
262 case GAIM_SUBTYPE_PLUGIN: | |
263 /* pointers again */ | |
264 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
10597 | 265 vals[i] = va_arg(args, void **); |
266 Tcl_LinkVar(handler->interp, name->str, | |
267 vals[i], TCL_LINK_INT); | |
268 arg = Tcl_NewStringObj(name->str, -1); | |
6694 | 269 } else { |
10597 | 270 arg = Tcl_NewIntObj((int)va_arg(args, void *)); |
6694 | 271 } |
272 break; | |
273 case GAIM_SUBTYPE_BLIST: | |
274 case GAIM_SUBTYPE_BLIST_BUDDY: | |
275 case GAIM_SUBTYPE_BLIST_GROUP: | |
276 case GAIM_SUBTYPE_BLIST_CHAT: | |
277 /* We're going to switch again for code-deduping */ | |
278 if (gaim_value_is_outgoing(handler->argtypes[i])) | |
279 node = *va_arg(args, GaimBlistNode **); | |
280 else | |
281 node = va_arg(args, GaimBlistNode *); | |
282 switch (node->type) { | |
283 case GAIM_BLIST_GROUP_NODE: | |
6700 | 284 g_string_printf(val, "group {%s}", ((GaimGroup *)node)->name); |
6694 | 285 break; |
6735 | 286 case GAIM_BLIST_CONTACT_NODE: |
287 /* g_string_printf(val, "contact {%s}", Contact Name? ); */ | |
288 break; | |
6694 | 289 case GAIM_BLIST_BUDDY_NODE: |
6700 | 290 g_string_printf(val, "buddy {%s} %lu", ((GaimBuddy *)node)->name, |
291 (unsigned long)((GaimBuddy *)node)->account); | |
6694 | 292 break; |
293 case GAIM_BLIST_CHAT_NODE: | |
7118
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
6735
diff
changeset
|
294 g_string_printf(val, "chat {%s} %lu", ((GaimChat *)node)->alias, |
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
6735
diff
changeset
|
295 (unsigned long)((GaimChat *)node)->account); |
6694 | 296 break; |
297 case GAIM_BLIST_OTHER_NODE: | |
298 g_string_printf(val, "other"); | |
299 break; | |
300 } | |
10597 | 301 arg = Tcl_NewStringObj(val->str, -1); |
6694 | 302 break; |
303 } | |
304 } | |
10597 | 305 Tcl_ListObjAppendElement(handler->interp, cmd, arg); |
6694 | 306 } |
307 | |
308 /* Call the friggin' procedure already */ | |
10597 | 309 if ((error = Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL)) != TCL_OK) { |
6694 | 310 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "error evaluating callback: %s\n", |
311 Tcl_GetString(Tcl_GetObjResult(handler->interp))); | |
312 } else { | |
313 result = Tcl_GetObjResult(handler->interp); | |
314 /* handle return values -- strings and words only */ | |
315 if (handler->returntype) { | |
316 if (gaim_value_get_type(handler->returntype) == GAIM_TYPE_STRING) { | |
317 retval = (void *)g_strdup(Tcl_GetString(result)); | |
318 } else { | |
319 if ((error = Tcl_GetIntFromObj(handler->interp, result, (int *)&retval)) != TCL_OK) { | |
320 gaim_debug(GAIM_DEBUG_ERROR, "tcl", "Error retrieving procedure result: %s\n", | |
321 Tcl_GetString(Tcl_GetObjResult(handler->interp))); | |
322 retval = NULL; | |
323 } | |
324 } | |
325 } | |
326 } | |
327 | |
328 /* And finally clean up */ | |
329 for (i = 0; i < handler->nargs; i++) { | |
10597 | 330 g_string_printf(name, "%s::arg%d", |
331 Tcl_GetString(handler->namespace), i); | |
332 if (gaim_value_is_outgoing(handler->argtypes[i])) | |
333 Tcl_UnlinkVar(handler->interp, name->str); | |
334 /* We basically only have to deal with strings on the | |
335 * way out */ | |
6694 | 336 switch (gaim_value_get_type(handler->argtypes[i])) { |
337 case GAIM_TYPE_STRING: | |
338 if (gaim_value_is_outgoing(handler->argtypes[i])) { | |
10597 | 339 if (vals[i] != NULL && *(char **)vals[i] != NULL) { |
340 g_free(*strs[i]); | |
341 *strs[i] = g_strdup(vals[i]); | |
6694 | 342 } |
10597 | 343 ckfree(vals[i]); |
6694 | 344 } |
345 break; | |
346 default: | |
347 /* nothing */ | |
348 ; | |
349 } | |
350 } | |
351 | |
352 g_string_free(name, TRUE); | |
10504 | 353 g_string_free(val, TRUE); |
10597 | 354 g_free(vals); |
355 g_free(strs); | |
356 | |
6694 | 357 |
358 return retval; | |
359 } | |
10597 | 360 |
361 static Tcl_Obj *new_cb_namespace () | |
362 { | |
363 static int cbnum; | |
364 char name[32]; | |
365 | |
366 g_snprintf (name, sizeof(name), "::gaim::_callback::cb_%d", cbnum++); | |
367 return Tcl_NewStringObj (name, -1); | |
368 } |