comparison src/plugin.c @ 12695:0bc110c7ab91

[gaim-migrate @ 15038] Let's display outdated plugins in the plugins dialog, but grey them out. This way, the user can find out which plugins need to be updated. They will also be able to view the website address so they know where to get a new version. Inspired by SF Feature Request #1395058 from Daniel Beardsmore (uilleann). committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Tue, 03 Jan 2006 12:03:02 +0000
parents 70f18c73da9d
children 18e619ed4eaf
comparison
equal deleted inserted replaced
12694:ebed1bbedb04 12695:0bc110c7ab91
26 #include "notify.h" 26 #include "notify.h"
27 #include "prefs.h" 27 #include "prefs.h"
28 #include "prpl.h" 28 #include "prpl.h"
29 #include "request.h" 29 #include "request.h"
30 #include "signals.h" 30 #include "signals.h"
31 #include "util.h"
31 #include "version.h" 32 #include "version.h"
32 33
33 typedef struct 34 typedef struct
34 { 35 {
35 GHashTable *commands; 36 GHashTable *commands;
213 basename = gaim_plugin_get_basename(filename); 214 basename = gaim_plugin_get_basename(filename);
214 plugin = gaim_plugins_find_with_basename(basename); 215 plugin = gaim_plugins_find_with_basename(basename);
215 g_free(basename); 216 g_free(basename);
216 if (plugin != NULL) 217 if (plugin != NULL)
217 { 218 {
218 if (strcmp(filename, plugin->path)) 219 if (!strcmp(filename, plugin->path))
219 gaim_debug_info("plugins", "Not loading %s." 220 return plugin;
221 else if (!gaim_plugin_is_unloadable(plugin))
222 {
223 gaim_debug_info("plugins", "Not loading %s. "
220 "Another plugin with the same name (%s) has already been loaded.\n", 224 "Another plugin with the same name (%s) has already been loaded.\n",
221 filename, plugin->path); 225 filename, plugin->path);
222 return plugin; 226 return plugin;
227 }
228 else
229 {
230 /* The old plugin was a different file and it was unloadable.
231 * There's no guarantee that this new file with the same name
232 * will be loadable, but unless it fails in one of the silent
233 * ways and the first one didn't, it's not any worse. The user
234 * will still see a greyed-out plugin, which is what we want. */
235 gaim_plugin_destroy(plugin);
236 }
223 } 237 }
224 238
225 plugin = gaim_plugin_new(has_file_extension(filename, G_MODULE_SUFFIX), filename); 239 plugin = gaim_plugin_new(has_file_extension(filename, G_MODULE_SUFFIX), filename);
226 240
227 if (plugin->native_plugin) { 241 if (plugin->native_plugin) {
241 plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL); 255 plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL);
242 #else 256 #else
243 plugin->handle = g_module_open(filename, 0); 257 plugin->handle = g_module_open(filename, 0);
244 #endif 258 #endif
245 259
246 #ifdef _WIN32 260 if (plugin->handle == NULL)
247 /* Restore the original error mode */ 261 {
248 SetErrorMode(old_error_mode); 262 const char *error = g_module_error();
263 if (error == NULL)
264 error = "Unknown error";
265 else if (gaim_str_has_prefix(error, filename))
266 {
267 error = error + strlen(filename);
268
269 /* These are just so we don't crash. If we
270 * got this far, they should always be true. */
271 if (*error == ':')
272 error++;
273 if (*error == ' ')
274 error++;
275
276 /* This shouldn't ever be necessary. */
277 if (!*error)
278 error = "Unknown error";
279 }
280 plugin->error = g_strdup(error);
281
282 gaim_debug_error("plugins", "%s is unloadable: %s\n",
283 plugin->path, plugin->error);
284
285 #if GLIB_CHECK_VERSION(2,3,3)
286 plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
287 #else
288 plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY);
249 #endif 289 #endif
250 290
251 if (plugin->handle == NULL) 291 if (plugin->handle == NULL)
252 { 292 {
253 error = g_module_error(); 293 gaim_plugin_destroy(plugin);
254 gaim_debug_error("plugins", "%s is unloadable: %s\n", 294 return NULL;
255 plugin->path, error ? error : "Unknown error."); 295 }
256 296 else
257 gaim_plugin_destroy(plugin); 297 {
258 298 /* We were able to load the plugin with lazy symbol binding.
259 return NULL; 299 * This means we're missing some symbol. Mark it as
300 * unloadable and keep going so we get the info to display
301 * to the user so they know to rebuild this plugin. */
302 plugin->unloadable = TRUE;
303 }
260 } 304 }
261 305
262 if (!g_module_symbol(plugin->handle, "gaim_init_plugin", 306 if (!g_module_symbol(plugin->handle, "gaim_init_plugin",
263 &unpunned)) 307 &unpunned))
264 { 308 {
273 gaim_debug_error("plugins", "Error closing module %s: %s\n", 317 gaim_debug_error("plugins", "Error closing module %s: %s\n",
274 plugin->path, error); 318 plugin->path, error);
275 plugin->handle = NULL; 319 plugin->handle = NULL;
276 320
277 gaim_plugin_destroy(plugin); 321 gaim_plugin_destroy(plugin);
278
279 return NULL; 322 return NULL;
280 } 323 }
281 gaim_init_plugin = unpunned; 324 gaim_init_plugin = unpunned;
282 } 325 }
283 else { 326 else {
284 loader = find_loader_for_plugin(plugin); 327 loader = find_loader_for_plugin(plugin);
285 328
286 if (loader == NULL) { 329 if (loader == NULL) {
287 gaim_plugin_destroy(plugin); 330 gaim_plugin_destroy(plugin);
288
289 return NULL; 331 return NULL;
290 } 332 }
291 333
292 gaim_init_plugin = GAIM_PLUGIN_LOADER_INFO(loader)->probe; 334 gaim_init_plugin = GAIM_PLUGIN_LOADER_INFO(loader)->probe;
293 } 335 }
294 336
295 plugin->error = NULL; 337 #ifdef _WIN32
296 338 /* Restore the original error mode */
297 if (!gaim_init_plugin(plugin) || plugin->info == NULL) { 339 SetErrorMode(old_error_mode);
340 #endif
341
342 if (!gaim_init_plugin(plugin) || plugin->info == NULL)
343 {
298 gaim_plugin_destroy(plugin); 344 gaim_plugin_destroy(plugin);
299
300 return NULL; 345 return NULL;
301 } 346 }
302 347
303 if (plugin->info->magic != GAIM_PLUGIN_MAGIC || 348 if (plugin->info->magic != GAIM_PLUGIN_MAGIC ||
304 plugin->info->major_version != GAIM_MAJOR_VERSION || 349 plugin->info->major_version != GAIM_MAJOR_VERSION ||
305 plugin->info->minor_version > GAIM_MINOR_VERSION) 350 plugin->info->minor_version > GAIM_MINOR_VERSION)
306 { 351 {
307 gaim_debug_error("plugins", "%s is unloadable: API version mismatch %d.%d.x (need %d.%d.x)\n", 352 plugin->error = g_strdup_printf("ABI version mismatch %d.%d.x (need %d.%d.x)",
308 plugin->path, plugin->info->major_version, plugin->info->minor_version, 353 plugin->info->major_version, plugin->info->minor_version,
309 GAIM_MAJOR_VERSION, GAIM_MINOR_VERSION); 354 GAIM_MAJOR_VERSION, GAIM_MINOR_VERSION);
310 gaim_plugin_destroy(plugin); 355 gaim_debug_error("plugins", "%s is unloadable: %s\n", plugin->path, plugin->error);
311 return NULL; 356 plugin->unloadable = TRUE;
357 return plugin;
312 } 358 }
313 359
314 /* If plugin is a PRPL, make sure it implements the required functions */ 360 /* If plugin is a PRPL, make sure it implements the required functions */
315 if ((plugin->info->type == GAIM_PLUGIN_PROTOCOL) && ( 361 if ((plugin->info->type == GAIM_PLUGIN_PROTOCOL) && (
316 (GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon == NULL) || 362 (GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon == NULL) ||
317 (GAIM_PLUGIN_PROTOCOL_INFO(plugin)->login == NULL) || 363 (GAIM_PLUGIN_PROTOCOL_INFO(plugin)->login == NULL) ||
318 (GAIM_PLUGIN_PROTOCOL_INFO(plugin)->close == NULL))) 364 (GAIM_PLUGIN_PROTOCOL_INFO(plugin)->close == NULL)))
319 { 365 {
320 gaim_debug_error("plugins", "%s is unloadable: Does not implement all required functions\n", 366 plugin->error = g_strdup("Does not implement all required functions");
321 plugin->path); 367 gaim_debug_error("plugins", "%s is unloadable: %s\n", plugin->path, plugin->error);
322 gaim_plugin_destroy(plugin); 368 plugin->unloadable = TRUE;
323 return NULL; 369 return plugin;
324 } 370 }
325 371
326 return plugin; 372 return plugin;
327 #else 373 #else
328 return NULL; 374 return NULL;
344 #ifdef GAIM_PLUGINS 390 #ifdef GAIM_PLUGINS
345 GList *dep_list = NULL; 391 GList *dep_list = NULL;
346 GList *l; 392 GList *l;
347 393
348 g_return_val_if_fail(plugin != NULL, FALSE); 394 g_return_val_if_fail(plugin != NULL, FALSE);
349 g_return_val_if_fail(plugin->error == NULL, FALSE);
350 395
351 if (gaim_plugin_is_loaded(plugin)) 396 if (gaim_plugin_is_loaded(plugin))
352 return TRUE; 397 return TRUE;
398
399 if (gaim_plugin_is_unloadable(plugin))
400 return FALSE;
401
402 g_return_val_if_fail(plugin->error == NULL, FALSE);
353 403
354 /* 404 /*
355 * Go through the list of the plugin's dependencies. 405 * Go through the list of the plugin's dependencies.
356 * 406 *
357 * First pass: Make sure all the plugins needed are probed. 407 * First pass: Make sure all the plugins needed are probed.
653 gaim_plugin_is_loaded(const GaimPlugin *plugin) 703 gaim_plugin_is_loaded(const GaimPlugin *plugin)
654 { 704 {
655 g_return_val_if_fail(plugin != NULL, FALSE); 705 g_return_val_if_fail(plugin != NULL, FALSE);
656 706
657 return plugin->loaded; 707 return plugin->loaded;
708 }
709
710 gboolean
711 gaim_plugin_is_unloadable(const GaimPlugin *plugin)
712 {
713 g_return_val_if_fail(plugin != NULL, FALSE);
714
715 return plugin->unloadable;
658 } 716 }
659 717
660 const gchar * 718 const gchar *
661 gaim_plugin_get_id(const GaimPlugin *plugin) { 719 gaim_plugin_get_id(const GaimPlugin *plugin) {
662 g_return_val_if_fail(plugin, NULL); 720 g_return_val_if_fail(plugin, NULL);