Yattm - unified GTK instant-messaging client logo
   [Generated for version 0.2-17 - Mon Jan 6 19:01:23 GMT+1 2003]

Home - Main Page - Data Structures - File List - Data Fields - Globals

plugin.c

Go to the documentation of this file.
00001 /*
00002  * Yattm 
00003  *
00004  * Copyright (C) 1999, Torrey Searle <tsearle@uci.edu>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #  include <config.h>
00024 #endif
00025 
00026 #include "intl.h"
00027 #ifdef __MINGW32__
00028 typedef long __off32_t;
00029 #endif
00030 #include <sys/types.h>
00031 #include <dirent.h> /* Routines to read directories to find modules */
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #include "globals.h"
00035 #include "defaults.h"
00036 #include "service.h"
00037 #include "plugin.h"
00038 #include "nomodule.h"
00039 #include "value_pair.h"
00040 
00041 char *PLUGIN_TYPE_TXT[]={"SERVICE", "UTILITY", "SOUND", "LOG", "GUI", "UNKNOWN"};
00042 char *PLUGIN_STATUS_TXT[]={"Not Loaded", 
00043                "Loaded", 
00044                "Cannot Load"};
00045 
00046 PLUGIN_INFO Plugin_Cannot_Load = {PLUGIN_UNKNOWN, 
00047                   "Unknown",
00048                   "Unknown", 
00049                   "Unknown", 
00050                   "Unknown", NULL, NULL, NULL, NULL};
00051 
00052 gint compare_plugin_loaded_service(gconstpointer a, gconstpointer b) {
00053     const eb_PLUGIN_INFO *epi=a;
00054     if(epi->service && epi->status==PLUGIN_LOADED && !strcmp( epi->service, (char *)b))
00055         return(0);
00056     return(1);
00057 }
00058 
00059 gint compare_plugin_name(gconstpointer a, gconstpointer b) {
00060     const eb_PLUGIN_INFO *epi=a;
00061     if(epi->name && !strcmp( epi->name, (char *)b))
00062         return(0);
00063     return(1);
00064 }
00065 
00066 gint compare_plugin_handle(gconstpointer a, gconstpointer b) {
00067     const eb_PLUGIN_INFO *epi=a;
00068     if( epi->Module && epi->Module == (lt_dlhandle )b)
00069         return(0);
00070     return(1);
00071 }
00072 
00073 
00074 eb_PLUGIN_INFO *FindLoadedPluginByService(char *service)
00075 {
00076     GList *plugins=GetPref(EB_PLUGIN_LIST);
00077     GList *PluginData = g_list_find_custom(plugins, service, compare_plugin_loaded_service);
00078     if(PluginData)
00079         return(PluginData->data);
00080     return(NULL);
00081 }
00082 
00083 eb_PLUGIN_INFO *FindPluginByName(char *name)
00084 {
00085     GList *plugins=GetPref(EB_PLUGIN_LIST);
00086     GList *PluginData = g_list_find_custom(plugins, name, compare_plugin_name);
00087     if(PluginData)
00088         return(PluginData->data);
00089     return(NULL);
00090 }
00091 
00092 eb_PLUGIN_INFO *FindPluginByHandle(lt_dlhandle *Module)
00093 {
00094     GList *plugins=GetPref(EB_PLUGIN_LIST);
00095     GList *PluginData = g_list_find_custom(plugins, Module, compare_plugin_handle);
00096     if(PluginData)
00097         return(PluginData->data);
00098     return(NULL);
00099 }
00100 
00101 /* Will add/update info about a plugin */
00102 void SetPluginInfo(PLUGIN_INFO *pi, char *name, lt_dlhandle Module, PLUGIN_STATUS status, const char *status_desc, char *service, gboolean force)
00103 {
00104     GList *plugins=NULL;
00105     eb_PLUGIN_INFO *epi=NULL;
00106 
00107     epi=FindPluginByName(name);
00108     if(!epi) {
00109         epi=g_new0(eb_PLUGIN_INFO, 1);
00110         plugins=GetPref(EB_PLUGIN_LIST);
00111         plugins=g_list_append(plugins, epi);
00112         SetPref(EB_PLUGIN_LIST, plugins);
00113     }
00114     else if(force==TRUE || epi->status!=PLUGIN_LOADED) {
00115         if(epi->service)
00116             free(epi->service);
00117         free(epi->name);
00118         free(epi->pi.brief_desc);
00119         free(epi->pi.full_desc);
00120         free(epi->pi.version);
00121         free(epi->pi.date);
00122     }
00123     else    /* A plugin is already succesfully load */
00124         return;
00125     epi->status=status;
00126     epi->status_desc=status_desc;
00127     if(!pi)
00128         pi=&Plugin_Cannot_Load;
00129     epi->pi.type=pi->type;
00130     epi->pi.brief_desc=strdup(pi->brief_desc);
00131     epi->pi.full_desc=strdup(pi->full_desc);
00132     epi->pi.version=strdup(pi->version);
00133     epi->pi.date=strdup(pi->date);
00134     epi->pi.init=pi->init;
00135     epi->pi.finish=pi->finish;
00136     epi->pi.prefs=pi->prefs;
00137     epi->name=strdup(name);
00138     if(service)
00139         epi->service=strdup(service);
00140     epi->Module=Module;
00141 }
00142 
00143 /* Find names which end in .la, the expected module extension */
00144 int select_module_entry(const struct dirent *dent) {
00145     int len=0;
00146     char *ext;
00147 
00148     len=strlen(dent->d_name);
00149     if(len<4)
00150        return(0);
00151     ext=(char *)dent->d_name;
00152     ext+=(len-3);
00153     eb_debug(DBG_CORE, "select_module_entry: %s[%s]\n", dent->d_name, ext);
00154     if(!strncmp(ext, ".la", 3))
00155        return(1);
00156     return(0);
00157 }
00158 
00159 int unload_module(eb_PLUGIN_INFO *epi)
00160 {
00161     int error=0;
00162     char buf[1024];
00163 
00164     eb_debug(DBG_CORE, ">Unloading plugin %s\n", epi->name);
00165     /* This is a service plugin, special handling required */
00166     if(epi->pi.finish) {
00167         eb_debug(DBG_CORE, "Calling plugins finish function\n");
00168         error=epi->pi.finish();
00169         if(error) {
00170             sprintf(buf, _("Unable to unload plugin %s, still in use?\n"), epi->name);
00171             do_error_dialog(buf, _("Error"));
00172             eb_debug(DBG_CORE, "<Plugin failed to unload\n");
00173             return(-1);
00174         }
00175     }
00176     if(epi->service) {
00177         struct service SERVICE_INFO = { strdup(epi->service), -1, FALSE, FALSE, FALSE, FALSE, NULL };
00178 
00179         SERVICE_INFO.sc=eb_nomodule_query_callbacks();
00180         add_service(&SERVICE_INFO);
00181     }
00182     epi->status=PLUGIN_NOT_LOADED;
00183     epi->pi.prefs=NULL;
00184     eb_debug(DBG_CORE, "Closing plugin\n");
00185     if(lt_dlclose(epi->Module)) {
00186         fprintf(stderr, "Error closing plugin: %s\n", lt_dlerror());
00187     }
00188     eb_debug(DBG_CORE, "<Plugin unloaded\n");
00189     return(0);
00190 
00191 }
00192 
00193 void unload_modules(void) {
00194     GList *plugins=GetPref(EB_PLUGIN_LIST);
00195     for(plugins=GetPref(EB_PLUGIN_LIST); plugins; plugins=plugins->next) {
00196         unload_module(plugins->data);
00197     }
00198 }
00199 
00200 int load_module(char *path, char *name)
00201 {
00202     char full_path[1024];
00203     lt_dlhandle Module;
00204     PLUGIN_INFO *plugin_info=NULL;
00205     eb_PLUGIN_INFO *epi=NULL;
00206 
00207     sprintf(full_path, "%s/%s", path, name);
00208     eb_debug(DBG_CORE, "Opening module: %s\n", full_path);
00209     Module = lt_dlopen(full_path);
00210     eb_debug(DBG_CORE, "Module: %p\n", Module);
00211 
00212     /* Find out if this plugin is already loaded */
00213     if(!Module) {
00214         /* Only update status on a plugin that is not already loaded */
00215         SetPluginInfo(NULL, full_path, NULL, PLUGIN_CANNOT_LOAD, lt_dlerror(), NULL, FALSE);
00216         return(-1);
00217     }
00218     plugin_info = (PLUGIN_INFO *)lt_dlsym(Module, "plugin_info");
00219     if(!plugin_info) {
00220         lt_dlclose(Module);
00221         /* Only update status on a plugin that is not already loaded */
00222         SetPluginInfo(NULL, full_path, NULL, PLUGIN_CANNOT_LOAD, _("Cannot resolve symbol plugin_info"), NULL, FALSE);
00223         return(-1);
00224     }
00225     epi=FindPluginByName(full_path);
00226     if(epi && epi->status==PLUGIN_LOADED) {
00227         lt_dlclose(Module);
00228         eb_debug(DBG_CORE, "Not loading already loaded module %s\n", name);
00229         return(-1);
00230     }
00231     switch(plugin_info->type) {
00232     case PLUGIN_SERVICE:
00233         load_service_plugin(Module, plugin_info, full_path);
00234         break;
00235     case PLUGIN_UTILITY:
00236         load_utility_plugin(Module, plugin_info, full_path);
00237         break;
00238     case PLUGIN_SOUND:
00239         load_sound_plugin(Module, plugin_info, full_path);
00240         break;
00241     case PLUGIN_LOG:
00242         load_log_plugin(Module, plugin_info, full_path);
00243         break;
00244     case PLUGIN_GUI:
00245         load_gui_plugin(Module, plugin_info, full_path);
00246         break;
00247     default:
00248         break;
00249     }
00250     return(0);
00251 }
00252 
00253 /* This is really a modules loader now */
00254 void load_modules()
00255 {
00256     /* UNUSED struct dirent **namelist=NULL; */
00257     char buf[1024], *modules_path=NULL, *cur_path=NULL;
00258     char *tok_buf=NULL, *tok_buf_old=NULL;
00259     int n=0, success=0;
00260     struct dirent *dp;
00261     DIR *dirp;
00262 
00263     eb_debug(DBG_CORE, ">Entering\n");
00264     modules_path=g_strdup(cGetLocalPref("modules_path"));
00265     tok_buf = g_new0(char, strlen(modules_path)+1);
00266     /* Save the old pointer, because strtok_r will change it */
00267     tok_buf_old=tok_buf;
00268     lt_dlinit();
00269     lt_dlsetsearchpath(modules_path);
00270 
00271     /* Use a thread-safe strtok */
00272 #ifdef HAVE_STRTOK_R
00273     cur_path=strtok_r(modules_path, ":", &tok_buf);
00274 #else
00275     cur_path=strtok(modules_path, ":");
00276 #endif
00277     if(!cur_path)
00278         cur_path=MODULE_DIR;
00279     do {
00280         if((dirp = opendir(cur_path)) == NULL)
00281         {
00282             sprintf(buf, _("Cannot open module directory \"%s\""), cur_path);
00283             do_error_dialog(buf, _("Warning"));
00284             buf[0] = '\0';
00285             break;
00286         }
00287         n = 0;
00288         while((dp = readdir(dirp)) != NULL)
00289         {
00290             if( dp == NULL )
00291             {
00292                 sprintf(buf, _("Looking for modules in %s"), cur_path);
00293                 perror(buf);
00294                 continue;
00295             }
00296             else if( select_module_entry( dp ) )
00297             {
00298                 n++;
00299                 success = load_module(cur_path, dp->d_name);
00300             }
00301         }
00302         if( n == 0 )
00303         {
00304             eb_debug(DBG_CORE, "<No modules found in %s, returning.\n", cur_path);
00305         }
00306         else
00307         {
00308             eb_debug(DBG_CORE, "Loaded %d modules from %s.\n", n, cur_path);
00309         }
00310         closedir(dirp);
00311 #ifdef HAVE_STRTOK_R
00312     } while((cur_path=strtok_r(NULL, ":", &tok_buf)));
00313 #else
00314     } while((cur_path=strtok(NULL, ":")));
00315 #endif
00316 
00317     g_free(modules_path);
00318     g_free(tok_buf_old);
00319     eb_debug(DBG_CORE, "Adding idle_check\n");
00320     add_idle_check();
00321     eb_debug(DBG_CORE, "<End services_init\n");
00322 }
00323 
00324 int load_service_plugin(lt_dlhandle Module, PLUGIN_INFO *info, char *name)
00325 {
00326     struct service *Service_Info=NULL;
00327     struct service_callbacks *(*query_callbacks)();
00328     int service_id=-1;
00329     eb_PLUGIN_INFO *epi=NULL;
00330     GList *user_prefs=NULL;
00331 
00332     Service_Info = lt_dlsym(Module, "SERVICE_INFO");
00333     eb_debug(DBG_CORE, "SERVICE_INFO: %p\n", Service_Info);
00334     if(!Service_Info) {
00335         SetPluginInfo(info, name, NULL, PLUGIN_CANNOT_LOAD, _("Unable to resolve symbol SERVICE_INFO"), NULL, FALSE);
00336         lt_dlclose(Module);
00337         return(-1);
00338     }
00339     /* Don't load this module if there's a service of this type already loaded */
00340     epi=FindLoadedPluginByService(Service_Info->name);
00341     if(epi && epi->status==PLUGIN_LOADED) {
00342         fprintf(stderr, _("Not loading module %s, a module for that service is already loaded!\n"), name);
00343         SetPluginInfo(info, name, NULL, PLUGIN_CANNOT_LOAD, _("Service provided by an already loaded plugin"), Service_Info->name, FALSE);
00344         lt_dlclose(Module);
00345         return(-1);
00346     }
00347     /* No more hard-coded service_id numbers */
00348     query_callbacks = lt_dlsym(Module, "query_callbacks");
00349     if(!query_callbacks) {
00350         SetPluginInfo(info, name, NULL, PLUGIN_CANNOT_LOAD, "Unable to resolve symbol query_callbacks", Service_Info->name, FALSE);
00351         lt_dlclose(Module);
00352         return(-1);
00353     }
00354     if(info->init) {
00355         eb_debug(DBG_CORE, "Executing init for %s\n", info->brief_desc);
00356         info->init();
00357     }
00358     if(info->prefs) {
00359         user_prefs=GetPref(name);
00360         if(user_prefs) {
00361             eb_update_from_value_pair(info->prefs, user_prefs);
00362         }
00363         eb_debug(DBG_MOD, "prefs name: %s\n", info->prefs->widget.entry.name);
00364     }
00365     Service_Info->sc=query_callbacks();
00366     /* The callbacks are defined by the SERVICE_INFO struct in each module */
00367     service_id = add_service(Service_Info);
00368     SetPluginInfo(info, name, Module, PLUGIN_LOADED, "", Service_Info->name, TRUE);
00369     eb_debug(DBG_CORE, "Added module:%s, service: %s\n", name, eb_services[service_id].name);
00370     eb_debug(DBG_CORE, "eb_services[%i].sc->read_local_account_config: %p\n", service_id, eb_services[service_id].sc->read_local_account_config);
00371     return(0);
00372 }
00373 
00374 int load_utility_plugin(lt_dlhandle Module, PLUGIN_INFO *info, char *name)
00375 {
00376     char buf[1024];
00377     GList *user_prefs=NULL;
00378 
00379     eb_debug(DBG_CORE, ">\n");
00380     if(!info->init) {
00381         SetPluginInfo(info, name, NULL, PLUGIN_CANNOT_LOAD, _("No init function defined"), NULL, FALSE);
00382         lt_dlclose(Module);
00383         sprintf(buf, _("init function not defined for utility module %s, unloading module\n"), name);
00384         do_error_dialog(buf, _("Warning"));
00385         return(-1);
00386     }
00387     eb_debug(DBG_CORE, "Executing init for %s\n", info->brief_desc);
00388     info->init();
00389     if(info->prefs) {
00390         user_prefs=GetPref(name);
00391         if(user_prefs) {
00392             eb_update_from_value_pair(info->prefs, user_prefs);
00393         }
00394         eb_debug(DBG_MOD, "prefs name: %s\n", info->prefs->widget.entry.name);
00395     }
00396     SetPluginInfo(info, name, Module, PLUGIN_LOADED, "", NULL, TRUE);
00397     eb_debug(DBG_CORE, "<\n");
00398     return(0);
00399 }
00400 
00401 int load_log_plugin(lt_dlhandle Module, PLUGIN_INFO *info, char *name)
00402 {
00403     return(1);
00404 }
00405 
00406 int load_sound_plugin(lt_dlhandle Module, PLUGIN_INFO *info, char *name)
00407 {
00408     return(1);
00409 }
00410 
00411 int load_gui_plugin(lt_dlhandle Module, PLUGIN_INFO *info, char *name)
00412 {
00413     return(1);
00414 }
00415 
00416 /* Make sure that all the plugin_api accessible menus are initialized */
00417 int init_menu(char *menu_name, menu_func redraw_menu, ebmType type)
00418 {
00419     menu_data *md=NULL;
00420 
00421     md=g_new0(menu_data, 1);
00422     md->menu_items=NULL;
00423     md->redraw_menu=redraw_menu;
00424     md->type=type;
00425     SetPref(menu_name, md);
00426     return(0);
00427 }
00428 
00429 /* Set up information about how menus are redrawn and what kind of data should be sent to callbacks */
00430 int init_menus()
00431 {
00432     init_menu(EB_PROFILE_MENU, rebuild_profile_menu, ebmPROFILEDATA);
00433     init_menu(EB_IMPORT_MENU, rebuild_import_menu, ebmIMPORTDATA);
00434     /* The chat window menu is dynamically redrawn */
00435     init_menu(EB_CHAT_WINDOW_MENU, NULL, ebmCONTACTDATA);
00436     init_menu(EB_CONTACT_MENU, NULL, ebmCONTACTDATA);
00437     return(0);
00438 }

Contact: Andy Maloney     [Documentation generated by doxygen]