Logo Search packages:      
Sourcecode: gaby version File versions  Download package

actions.c

/*  Gaby
 *  Copyright (C) 1998-2000 Frederic Peters
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "gaby.h"
#include "files.h"
#include "tables.h"
#include "actions.h"

extern void statusbar_message(gchar *text, void *blah);

#ifdef FOLLOW_MIGUEL
#if 0 /* this doesn't work :( */
static void get_function_by_name(gchar *name, action *a)
{
      char fct[200];
      GModule *self;

      self = g_module_open(NULL, G_MODULE_BIND_LAZY);
      sprintf(fct, "%s_%s", a->what.plugin->name, name);
      
      a->function = NULL;
      g_module_symbol(self, fct, (gpointer)&(a->function));
      
      return;
}
#else
#include "py_gfbn.c"
#endif
#endif

void do_action_plugin(action *act)
{
      ActionPluginData *apd;
      char plugin_name[PATH_MAX];
      
      apd = act->what.plugin;
#ifdef FOLLOW_MIGUEL
      apd->loaded = 1;
      get_function_by_name(act->name, act);
#else /* ! FOLLOW_MIGUEL */
      sprintf(plugin_name, PLUGINS_DIR "/actions/lib%s" SO_EXTENSION,
                              apd->name);
#ifdef DEBUG_GABY
      debug_print("I'll find '%s' in %s.\n", act->name, plugin_name);
#endif
#endif /* ! FOLLOW_MIGUEL */

      debug_print("apd->loaded: %d\n", apd->loaded);
      
      if ( apd->loaded == 0 ) {
            /*
             *  check if glib (and/or libc) is smart enough
             *  to not open 8 times the same module (i
             *  hope this is the case otherwise i'll have
             *  to find an idea (I just hate that :)))
             *
             *  Update : handled by ActionPluginData->loaded
             */
            apd->handle = g_module_open(plugin_name, 0);
            if ( apd->handle == NULL ) {
#ifdef DEBUG_GABY
                  debug_print(_("Unable to find %s\n"), plugin_name);
#endif
                  gaby_errno = CUSTOM_WARNING;
                  gaby_message = g_strdup(_("Unable to find this action plug-in !"));
                  gaby_perror_in_a_box();
                  return;
            }

      }
      if ( apd->get_function_by_name == NULL || apd->loaded == 0 ) {

            g_module_symbol(apd->handle, "get_function_by_name", 
                              (gpointer *)&apd->get_function_by_name);
            apd->get_function_by_name(act->name, act);

            if ( act->function == NULL ) {
#ifdef DEBUG_GABY
                  debug_print("%s was not found in %s.\n", 
                                    act->name, plugin_name);
#endif
                  g_module_close(apd->handle);
                  return;
            }
            apd->loaded++;
      }

      gaby_errno = 0;
      act->function(act->params, &apd->loaded );
      if ( gaby_errno != 0 ) {
            gaby_perror_in_a_box();
      }

      /*
       * I can't free a plugin right now since it could have
       * a dialog box opened waiting the user; this means
       * plug-ins have to decrement act->plugin->loaded
       * themself and from time to time I'll check if
       * act->plugin->loaded == 0 and _then_ I'll close the
       * module.
       *
       * Note that I check for loaded == 0 in case of the 
       * action is already finished.
       */

#ifdef FOLLOW_MIGUEL
      apd->loaded = 1;
#endif
      if ( apd->loaded == 0 ) {
#ifdef DEBUG_GABY
            debug_print("[do_action] woow it was so fast that I may already clean the room\n");
#endif
            g_module_close(apd->handle);
            apd->get_function_by_name = NULL;
            apd->handle = NULL;
      }
}

void do_action_script(action *act)
{
      char *s;
      char cmd[1000];
      FILE *f;
      int i;
      table *t;
      
      if ( strncmp(act->what.script, "#include ", 9) == 0 ) {
            /* #included file */
            s = act->what.script+9;
            sprintf(cmd, "%s/.gaby/actions/%s", g_get_home_dir(), s);
            f = fopen(cmd, "r");
            if ( f == NULL ) {
                  sprintf(cmd, "%s/actions/%s", SCRIPTS_DIR, s);
                  /* we don't check if the file is present ! */
            } else {
                  fclose(f);
            }
      } else {
            /* script in act->script */
#ifdef HAVE_TMPNAM
            /* since POSIX recommands tmpnam(), we use it */
            s = tmpnam(cmd);
#else
            sprintf(cmd, "%s/gabycmd_XXXXXX", g_get_tmp_dir());
            s = mktemp(cmd);
#endif
            
#ifdef DEBUG_GABY
            debug_print("[do_action_script] s : %p, cmd : %s\n", s, cmd);
#endif
            if ( s == NULL )
                  return;
            
            f = fopen(cmd, "w");
            fputs(act->what.script, f);
            fputs("\nrm $0 # added by gaby\n", f);
            fclose(f);
            chmod(s, S_IREAD | S_IWRITE | S_IEXEC );

      }
      
      s = cmd+strlen(cmd);
      s[0] = ' '; s++;
      
      for (i=0; i<act->nb_params; i++) {
            t = act->params[i].table;
            switch ( t->fields[act->params[i].field_no].type) {
                  case T_STRING:
                  case T_STRINGS:
                  case T_MULTIMEDIA:
                  case T_FILE:
                        sprintf(s, "%s", act->params[i].val.str->str );
                        break;
                  case T_INTEGER:
                        sprintf(s, "%d", act->params[i].val.i );
                        break;
                  case T_DECIMAL:
                        sprintf(s, "%f", act->params[i].val.i/100.0);
                        break;
                  case T_REAL:
                        sprintf(s, "%f", act->params[i].val.d );
                        break;
                  default: break;
            }
            s += strlen(s);
            s[0] = ' '; s++;
      }
      
#if 0
      if (fork()) return;
      setsid();
      if(execl("/bin/sh","sh","-c", cmd, NULL)==-1){exit(100);}
      exit(0);
#else
      switch ( system(cmd) ) {
            case -1:
            case 127:   /* this won't work with apps returning 127 as
                         * a "normal" value (not my fault) */
            {
                  gaby_message = g_strdup( 
                        _("A problem occured in the script."));
                  gaby_errno = 3;
            } break;
            /* case 'ok':
             *  we should show in a box what the script printed on stdout
             */
      }

      if ( gaby_errno != 0 )
            gaby_perror_in_a_box();
      
#endif
}

GModule* get_interpreter (gchar *which, gchar *argv[])
{
#ifdef FOLLOW_MIGUEL
      static char **initialized = NULL;
      static int nb_init = 0;
      int i;
      char fct_name[200];
      GModule *handle = g_module_open(NULL, G_MODULE_BIND_LAZY);
      int (*init_interpreter) (char *argv[]);
      char message[1000];

      if ( which == NULL ) return NULL;
      for ( i=0; i < strlen(which); i++ ) {
            char a = tolower(which[i]);
            if ( a != which[i] ) which[i] = a;
      }

      for ( i=0; i<nb_init; i++) {
            if ( strcmp(initialized[i], which) == 0 ) 
                  return handle;
      }

      sprintf(fct_name, "%s_init_interpreter", which);
      g_module_symbol(handle, fct_name, (gpointer*)&init_interpreter );
      
      if ( init_interpreter == NULL ) {
            gaby_errno = CUSTOM_ERROR;
            sprintf (message, _("%s is not a valid interpreter"), which);
            gaby_message = g_strdup(message);
            gaby_perror_in_a_box();
            return NULL;
      }
      
      if ( init_interpreter(argv) != 0 ) {
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(_("Interpreter initialization failed"));
            gaby_perror_in_a_box();
            return NULL;
      }

      nb_init++;
      initialized = g_realloc(initialized, nb_init*sizeof(char*));
      initialized[nb_init-1] = g_strdup(which);
      
      return handle;
#else
      static GList *interpreters = NULL;
      char int_name[PATH_MAX];
      GModule *handle;
      GList *tmp;
      int (*init_interpreter) (gchar *argv[]);
      char* (*get_interpreter_name) ();
      char message[1000];
      
      if ( which == NULL )
            return NULL;
      
      tmp = interpreters;
      while ( tmp != NULL ) {
            handle = tmp->data;
            tmp = g_list_next(tmp);
            if ( handle == NULL )
                  continue;
            g_module_symbol(handle, "get_interpreter_name", 
                              (gpointer*)&get_interpreter_name );
            if ( get_interpreter_name == NULL )
                  return handle;
            if ( strcmp(get_interpreter_name(), which) == 0 )
                  return handle;
      }
      
      sprintf(int_name, PLUGINS_DIR "/interpreter/lib%s" SO_EXTENSION, which);
      
      handle = g_module_open(int_name, 0);
      if ( handle == NULL ) {
#ifdef DEBUG_GABY
            debug_print("Unable to open %s\n", int_name);
#endif
            return NULL;
      }

      g_module_symbol(handle, "init_interpreter", 
                              (gpointer*)&init_interpreter );
      if ( init_interpreter == NULL ) {
            sprintf(message, "%s_init_interpreter", which);
            g_module_symbol(handle, message, (gpointer*)&init_interpreter );
      }
 
      if ( init_interpreter == NULL ) {
            g_module_close(handle);
            
            gaby_errno = CUSTOM_ERROR;
            sprintf (message, _("%s is not a valid interpreter"), int_name);
            gaby_message = g_strdup(message);
            gaby_perror_in_a_box();
            
            return NULL;
      }
      
      if ( init_interpreter(argv) != 0 ) {
            g_module_close(handle);
            
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(_("Interpreter initialization failed"));
            gaby_perror_in_a_box();
            
            return NULL;
      }

      g_list_append(interpreters, handle);

      return handle;
#endif
}

void do_action_script_fu (action *act)
{
      GModule *handle;
      gchar script_file[PATH_MAX];
      int (*run_script) (char *file, action *act);
      char message[1000];
      char int_name[100];
      char str[100], *s;
      FILE *f;
      char home_script_dir[PATH_MAX], script_dir[PATH_MAX];
      char *locs[] = { "./", home_script_dir, script_dir, "", NULL };
      int i;

      sprintf(home_script_dir, "%s/.gaby/scripts/", g_get_home_dir() );
      sprintf(script_dir, "%s/actions/", SCRIPTS_DIR);

      strchr(act->what.script, ':')[0] = 0;
      strcpy(int_name, act->what.script);
      act->what.script[strlen(act->what.script)] = ':';

      /* default is to look for scripts-fus in ~/.gaby/scripts and
       * then (if not found), in $(prefix)/share/gaby/scripts/actions/ */
      s = strchr(act->what.script, ':')+1;
#ifdef DEBUG_GABY
      debug_print("[do_action_script_fu] f1 : %s\n", s);
#endif
      if ( s[0] == '/' || ( s[0] == '.' && s[1] == '/') || 
                  ( s[0] == '.' && s[1] == '.' && s[2] == '/') ) {
            /* this catches absolute and relative paths */
            i = 3;
            /*strcpy(script_file, s);*/
      } else {
            i = 0;
      }
      
      do {
            sprintf(script_file, "%s%s", locs[i], s);
            if ( access(script_file, R_OK) == 0 )
                  break;
            i++;
      } while ( locs[i] != NULL );
      
      if ( locs[i] == NULL ) {
            if ( strcmp(act->name, "autoexec") == 0 ||
                  strcmp(act->name, "user-defined action") == 0 ) {
                  /* no error message for autoexec scripts or
                   * gladeform scripts */
                  gaby_errno = FILE_READ_ERROR;
/*                gaby_message = g_strdup(script_file);
                  gaby_perror_in_a_box();*/
            }
            return;
      }
      
      if ( strcasecmp(int_name, "guess") == 0 ) {
            f = fopen(script_file, "r");
            fgets(str, 99, f);
            /* it has to look like '# python\n' (or another interpreter)
             * or to # anything (but typically 'Intepreter'): */
            str[strlen(str)-1] = 0;
            s = strchr(str, ':');
            if ( s == NULL ) s = str;
            strcpy(int_name, ( strchr(s, ' ') == NULL ) ? 
                              s+1 : strchr(s, ' ')+1 );
            fclose(f);
      }
      
      if ( strcasecmp(int_name, "python") != 0 ) {
            sprintf(message, _("You requested %s but the only currently available\nscript fu language is Python."), int_name);
            gaby_errno = CUSTOM_WARNING;
            gaby_message = g_strdup(message);
            gaby_perror_in_a_box();
            return;
      }

      handle = get_interpreter(int_name, NULL);

      if ( handle == NULL ) {
#ifdef DEBUG_GABY
            debug_print("Unable to load %s interpreter\n", int_name);
#endif
            return;
      }

#ifdef DEBUG_GABY
      debug_print("[do_action_script_fu] module handle : %p\n", handle);
#endif

      strcat(int_name, "_run_script");
      
      g_module_symbol(handle, int_name, (gpointer*)&run_script );
      
      if ( run_script == NULL ) return;

      run_script(script_file, act);

#if 0
/* it would theorically be better to have those but gaby segfault with them
 * (using Python) */
      close_interpreter();
      g_module_close(handle);
#endif
      
}

static void first_launch ()
{
      /* little introduction to Gaby and its basic concepts
       * (subtables, views, ...) */
#ifdef USE_GNOME
      ActionPluginData apd = {
            0, "firsttime", NULL, NULL
      };
      action firsttime = {
            "druid", NULL, PLUG_IN, EVENT_STARTUP, { &apd }, 0, NULL, NULL
      };
      do_action_plugin(&firsttime);
      
#else
      gaby_errno = CUSTOM_MESSAGE;
      gaby_message = g_strdup(_("Welcome to Gaby !"));
      gaby_perror_in_a_box();
#endif
}

void launch_autoexec_script()
{
      char str[300];
      action autoexec = {
            "autoexec", NULL, SCRIPT_FU, EVENT_STARTUP, { NULL }, 0, NULL, NULL
      };

      sprintf(str, "guess:autoexec.%s", appname);
      autoexec.what.script = str;
      
      do_action_script_fu(&autoexec);
}

static void tip_of_the_day()
{
#if 0 /* Python is cool but since it won't be unloaded ... */
      action tip = {
            "tip of the day",
            gettext_noop("Tip of the day"),
            SCRIPT_FU,
            EVENT_STARTUP,
            { NULL },
            2,
            NULL,
            NULL
      };
      struct action_param params[] = {
            { P_DIRECT, NULL, 0, { NULL } },
            { P_DIRECT, NULL, 0, { NULL } }
      };

      tip.what.script = g_strdup("python:tips.py");
      tip.params = params;
      params[0].val.str = g_string_new(_(tip.i18n_name));
      params[1].val.str = g_string_new(TIPS_FILE);
      
      do_action_script_fu(&tip);

      g_string_free(params[0].val.str, 1 );
      g_free(tip.what.script);
#else
      char filename[PATH_MAX];
      FILE *f;
      char st[100];
      char tip[2000];
      gboolean space;
      int nb_tips = 0;
      int selected;
      
      sprintf(filename, "%s_%s.txt", TIPS_FILE, language);
      if ( access(filename, R_OK) != 0 ) {
            sprintf(filename, "%s.txt", TIPS_FILE);
      }

      f = fopen(filename, "r");
      if ( f == NULL ) return;

      space = TRUE;
      while ( ! feof(f) ) {
            fgets(st, 99, f);
            if ( (st[0] == '\n' || st[0] == '#' ) && space == FALSE ) {
                  nb_tips++;
                  space = TRUE;
            }
            if ( (st[0] != '\n' && st[0] != '#' ) && space == TRUE ) {
                  space = FALSE;
            }
      }     
            
      srand((unsigned)time(NULL));
      selected = nb_tips * ((float)rand()/(RAND_MAX+1.0));
#ifdef DEBUG_GABY
      debug_print("[tip_of_the_day] Tip selected : %d (on a total of %d)\n",
                  selected, nb_tips);
#endif
      rewind(f);
      
      space = TRUE;
      nb_tips = 0;
      while ( ! feof(f) ) {
            fgets(st, 99, f);
            if ( (st[0] == '\n' || st[0] == '#' ) && space == FALSE ) {
                  nb_tips++;
                  space = TRUE;
            }
            if ( (st[0] != '\n' && st[0] != '#' ) && space == TRUE ) {
                  if ( nb_tips == selected ) break;
                  space = FALSE;
            }
      }
      
      tip[0] = 0;
      do {
            strcat(tip, st);
            fgets(st, 99, f);
      } while ( ! feof(f) && ( st[0] != '\n' && st[0] != '#' ) );
      tip[strlen(tip)-1] = 0;

#ifdef DEBUG_GABY
      debug_print("[tip_of_the_day] And the tip is :\n%s\n", tip);
#endif
      gaby_errno = TIP_OF_THE_DAY;
      gaby_message = g_strdup(tip);
      gaby_perror_in_a_box();
#endif
}

void launch_startup_scripts(gboolean first_time)
{
      action *act;
      ActionPluginData *apd;
      gchar plugin_name[PATH_MAX];
      int i;
      gboolean flag;
      GList *actions = g_list_first(list_actions);
      /* most of this stuff is shared with do_action, a merge ? */

      launch_autoexec_script();

      if ( actions == NULL ) return;
      actions = g_list_first(actions);
      
      while ( actions != NULL ) {
            act = actions->data;
            actions = g_list_next(actions);
            if ( act == NULL ) continue;
            if ( ! ( act->event & EVENT_STARTUP ) ) continue;
            if ( act->type == SCRIPT )
                  do_action_script(act);
            else if ( act->type == SCRIPT_FU )
                  do_action_script_fu(act);
            else if ( act->type == PLUG_IN ) {
                  /* we don't accept P_FIELD */
                  flag = FALSE;
                  for ( i=0; i<act->nb_params; i++) {
                        if ( act->params[i].type == P_FIELD ) {
                              flag = TRUE;
                              break;
                        }
                  }
                  if ( flag ) continue;
                  apd = act->what.plugin;
                  debug_print("[launch_startup_scripts] loading %s\n", apd->name);
                  sprintf(plugin_name,
                        PLUGINS_DIR "/actions/lib%s" SO_EXTENSION,
                        apd->name);
                  if ( apd->loaded == 0 ) {
                        apd->handle = g_module_open(plugin_name, 0);
                        if ( apd->handle == NULL ) {
                              continue;
                        }
                              
                        g_module_symbol(apd->handle, 
                              "get_function_by_name", 
                              (gpointer *)&apd->get_function_by_name);
                        if ( apd->get_function_by_name == NULL ) {
                              g_module_close(apd->handle);
                              apd->handle = NULL;
                              continue;
                        }
                        apd->get_function_by_name(act->name, act);

                        if ( act->function == NULL ) {
                              g_module_close(apd->handle);
                              apd->handle = NULL;
                              continue;
                        }
                        apd->loaded++;
                  }
                  
                  debug_print("[launch_startup_scripts] executing function\n");
                  act->function(act->params, &apd->loaded );

                  if ( apd->loaded == 0 ) {
                        g_module_close(apd->handle);
                        apd->handle = NULL;
                  }
            }
      }
      
      if ( first_time ) {
            first_launch();
      } else {
            if ( get_config_bool("common", "misc", "tips", TRUE) == TRUE )
                  tip_of_the_day();
      }
}


Generated by  Doxygen 1.6.0   Back to index