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

jppy.c

/* jppy.c
 * Copyright (C) 2006 by Nick Piper.
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include <dlfcn.h>

#include <gtk/gtk.h>

#include <pygtk-2.0/pygobject.h>

#include "../jpilot_src/libplugin.h"

#include "Python.h"

#define _(x) x

#define PLUGIN_NAME "jppy"

static char *python_argv[] = { (char *)"-v" };
static int python_is_working;
PyObject *python_mdict, *python_mod;

static GtkWidget *hwindow;
static GtkWidget *vwindow;

/*
 * This is a mandatory plugin function.
 */
void plugin_version(int *major_version, int *minor_version)
{
   *major_version=0;
   *minor_version=99;
}

/*
 * This is a mandatory plugin function.
 */
int plugin_get_name(char *name, int len)
{
   jp_logf(JP_LOG_DEBUG, "jppy: plugin_get_name\n");
   snprintf(name, len, "%s %d.%d%s", PLUGIN_NAME, 
          JPPY_MAJOR_VERSION,
          JPPY_MINOR_VERSION,
          JPPY_EXTRA_VERSION);
   return 0;
}

/*
 * This is an optional plugin function.
 * This is the name that will show up in the plugins menu in J-Pilot.
 */
int plugin_get_menu_name(char *name, int len)
{
   strncpy(name, _("Jppy"), len);
   return 0;
}

/*
 * This is an optional plugin function.
 * This is the name that will show up in the plugins help menu in J-Pilot.
 * If this function is used then plugin_help must be also.
 */
int plugin_get_help_name(char *name, int len)
{
   strncpy(name, _("About jppy"), len);
   return 0;
}

/*
 * This function is called by J-Pilot when the user selects this plugin
 * from the plugin menu, or from the search window when a search result
 * record is chosen.  In the latter case, unique ID will be set.  This
 * application should go directly to that record in the case.
 */

int plugin_gui(GtkWidget *vbox, GtkWidget *hbox, unsigned int unique_id) {
  vwindow = vbox;
  hwindow = hbox;
  return general_gtk_python_int_function("plugin_gui", vwindow, hwindow, unique_id);
}

int general_gtk_python_int_function(char *python_function_name, 
                            GtkWidget *vbox, GtkWidget *hbox,
                            unsigned int unique_id) {
  PyObject *func, *rslt;
  int answer;
  
  if (!python_is_working) {
    jp_logf(JP_LOG_WARN, "Python is not running, unable to generate GUI!\n");
    return 0;
  }
  
  jp_logf(JP_LOG_DEBUG, "jppy: %s\n", python_function_name);
  
  func = PyDict_GetItemString(python_mdict, python_function_name); /* borrowed reference */
  if (func) {
    if (PyCallable_Check(func)) {
      rslt = PyObject_CallFunction(func, "OO", 
                           pygobject_new((GtkObject *)vwindow),
                           pygobject_new((GtkObject *)hwindow));
      if (rslt) {
      if (PyInt_Check(rslt)) {
        answer = PyInt_AsLong(rslt);
      } else {
        if (rslt == Py_None) {
          answer = 0;
        } else {
          jp_logf(JP_LOG_WARN, "Warning! %s() did not return an integer.\n",python_function_name);
          answer = -1;
        }
      }
      Py_XDECREF(rslt);
      } else {
      PyErr_Print();
      jp_logf(JP_LOG_WARN, "Warning! Failed during python version of %s().\n",python_function_name);
      }
    } else {
      jp_logf(JP_LOG_WARN,"jpilot_user.%s is not a function.\n",python_function_name);
    }
  } else {
    jp_logf(JP_LOG_WARN,"Warning! Failed to locate python version of %s().\n",python_function_name);
  }
  
  return answer;
}

/*
 * This function is called by J-Pilot when the user selects this plugin
 * from the plugin menu, or from the search window when a search result
 * record is chosen.  In the latter case, unique ID will be set.  This
 * application should go directly to that record in the case.
 */
int plugin_gui_cleanup() {
  return general_gtk_python_int_function("plugin_gui_cleanup",vwindow,hwindow,0);
}

int general_int_python_void_function(char *python_function_name) {
  long answer = 0;
  PyObject *func, *rslt;

  if (!python_is_working)
    return 0;

  jp_logf(JP_LOG_DEBUG, "jppy: %s\n", python_function_name);

  func = PyDict_GetItemString(python_mdict, python_function_name); /* borrowed reference */
    
  if (func) {
    if (PyCallable_Check(func)) {
      rslt = PyObject_CallFunction(func, NULL);
      if (rslt) {
      if (PyInt_Check(rslt)) {
        answer = PyInt_AsLong(rslt);
      } else {
        if (rslt == Py_None) {
          answer = 0;
        } else {
          jp_logf(JP_LOG_WARN, "Warning! %s() did not return an integer.\n",python_function_name);
          answer = -1;
        }
      }
      Py_XDECREF(rslt);
      } else {
      PyErr_Print();
      jp_logf(JP_LOG_FATAL, "Warning! Failed during python version of %s().\n",python_function_name);
      }
    } else {
      jp_logf(JP_LOG_FATAL,"jpilot_user.%s is not a function.\n",python_function_name);
    }
  } else {
    jp_logf(JP_LOG_FATAL,"Warning! Failed to locate python version of %s().\n",python_function_name);
  }
 

  return answer;  
}

/*
 * This is a plugin callback function that is executed when J-Pilot starts up.
 * base_dir is where J-Pilot is compiled to be installed at (e.g. /usr/local/)
 */
int plugin_startup(jp_startup_info *info)
{
  char *home, default_path[]=".";
  PyObject *obj;

  char python_line[255];

  jp_init();
  jp_logf(JP_LOG_INFO, "jppy: Starting...\n");

  if (!dlopen (PYTHON_SHARED_LIB, RTLD_NOW | RTLD_GLOBAL)) {
    jp_logf(JP_LOG_FATAL, "\n%s\n", dlerror());
    python_is_working = 0;
    return 0;
  }
  jp_logf(JP_LOG_DEBUG, "jppy: Opened python library\n");
  
  Py_SetProgramName("jpilot");
  Py_Initialize();
  PySys_SetArgv(1, python_argv);

  jp_logf(JP_LOG_DEBUG, "jppy: Initialized python\n");

  init_pygobject();

  jp_logf(JP_LOG_DEBUG, "jppy: Initialized pygobject\n");

  PyRun_SimpleString("import os");  
  PyRun_SimpleString("import sys");

  jp_logf(JP_LOG_DEBUG, "jppy: Imported os, sys\n");

  PyRun_SimpleString("sys.path.insert(0,'%s/.jpilot/python' % (os.getenv('JPILOT_HOME') or os.getenv('HOME')))");
  snprintf(python_line, 254, "sys.path.insert(0,'%s')", JPILOT_PLUGIN_PREFIX);
  PyRun_SimpleString(python_line);

  jp_logf(JP_LOG_DEBUG, "jppy: sys.path set\n");

/*   sprintf(pycmd,"sys.stdout = os.fdopen(%d)",pipe_out); */
/*   PyRun_SimpleString(pycmd); */
/*   sprintf(pycmd,"sys.stdin = os.fdopen(%d)",pipe_in); */
/*   PyRun_SimpleString(pycmd); */

  python_mod = PyImport_Import(PyString_FromString("jpilot_user"));
  if (python_mod == NULL) {
    PyErr_Print();
    jp_logf(JP_LOG_WARN,"Failed to import your jpilot_user.py, going to use jpilot_site.py\n");
    python_mod = PyImport_Import(PyString_FromString("jpilot_site"));
  } else {
    jp_logf(JP_LOG_DEBUG, "jppy: Imported jpilot_user as python_mod\n");
  }
  if (python_mod == NULL) {
    PyErr_Print();
    jp_logf(JP_LOG_WARN,"Failed to import your jpilot_site.py\n");
    jp_logf(JP_LOG_INFO,"Python will not be used this run.\n");
    python_is_working = 0;
    Py_XDECREF(PyString_FromString("jpilot_user"));
    Py_Finalize();
  } else {
    jp_logf(JP_LOG_INFO, "jppy: imported jpilot_user.\n");
    python_is_working = 1;
    python_mdict = PyModule_GetDict(python_mod);
  }
 
  if (python_is_working) {
    general_int_python_void_function("plugin_startup");
    python_is_working = 1;
    jp_logf(JP_LOG_INFO, "jppy: Ready.\n");
  } else {
    jp_logf(JP_LOG_INFO, "jppy: Not ready.\n");
  }
}




/*
 * This is a plugin callback function that is executed before a sync occurs, BEFORE
 * connecting to the palm
 * Any sync preparation can be done here.
 */
int plugin_pre_sync_pre_connect(void)
{
   return general_int_python_void_function("plugin_pre_sync_pre_connect");
}

/*
 * This is a plugin callback function that is executed before a sync occurs.
 * Any sync preparation can be done here.
 */
int plugin_pre_sync(void)
{
   return general_int_python_void_function("plugin_pre_sync");
}

/*
 * This is a plugin callback function that is executed during a sync.
 * Notice that I don't need to sync the jppy application.  Since I used
 * the plugin_get_db_name call to tell J-Pilot what to sync for me.  It will
 * be done automatically.
 */
int plugin_sync(int sd)
{
  long answer = 0;
  char *python_function_name;
  PyObject *func, *rslt;

  if (!python_is_working)
    return 0;

  python_function_name = "plugin_sync";

  jp_logf(JP_LOG_DEBUG, "jppy: %s\n", python_function_name);
  
  func = PyDict_GetItemString(python_mdict, python_function_name); /* borrowed reference */
  if (func) {
    if (PyCallable_Check(func)) {
      rslt = PyObject_CallFunction(func, "(i)", sd);
      if (rslt) {
      if (PyInt_Check(rslt)) {
        answer = PyInt_AsLong(rslt);
      } else {
        if (rslt == Py_None) {
          answer = 0;
        } else {
          jp_logf(JP_LOG_WARN, "Warning! %s() did not return an integer.\n",python_function_name);
          answer = -1;
        }
      }
      Py_XDECREF(rslt);
      } else {
      PyErr_Print();
      jp_logf(JP_LOG_FATAL, "Warning! Failed during python version of %s().\n",python_function_name);
      }
    } else {
      jp_logf(JP_LOG_FATAL,"jpilot_user.%s is not a function.\n",python_function_name);
    }
  } else {
    jp_logf(JP_LOG_FATAL,"Warning! Failed to locate python version of %s().\n",python_function_name);
  }

  return answer;
}


static int add_search_result(const char *line, int unique_id, struct search_result **sr)
{
   struct search_result *temp_sr;

   jp_logf(JP_LOG_DEBUG, "jppy: add_search_result for [%s]\n", line);
   temp_sr=malloc(sizeof(struct search_result));
   if (!temp_sr) {
      return -1;
   }
   temp_sr->next=NULL;
   temp_sr->unique_id=unique_id;
   temp_sr->line=strdup(line);
   if (!(*sr)) {
      (*sr)=temp_sr;
   } else {
      (*sr)->next=temp_sr;
   }

   return 0;
}

/*
 * This function is called when the user does a search.  It should return
 * records which match the search string.
 */
int plugin_search(const char *search_string, int case_sense, struct search_result **sr)
{
  int count;
  char *python_function_name;
  PyObject *func, *rslt, *hit, *pyline, *pyid;
  int i;

  /* disabled until python has faster access to the records, making it useful */

  return 0; 
  
   *sr=NULL;

  if (!python_is_working)
    return 0;

  python_function_name = "plugin_search";

  func = PyDict_GetItemString(python_mdict, python_function_name); /* borrowed reference */
  if (func) {
    if (PyCallable_Check(func)) {
      rslt = PyObject_CallFunction(func, "(si)", search_string, case_sense);
      if (rslt) {
      if (PySequence_Check(rslt)) {
        count = PySequence_Length(rslt);
        for (i=0;i<count;i++) {
          hit = PySequence_GetItem(rslt, i);
          if (PySequence_Check(hit)) {
            pyline = PySequence_GetItem(hit, 1);
            pyid   = PySequence_GetItem(hit, 0);

            printf("%d\n",  PyLong_AsLong(pyid));

            add_search_result(PyString_AsString(pyline), PyLong_AsLong(pyid), sr);
            Py_XDECREF(pyline);
            Py_XDECREF(pyid);       
          } else {
            jp_logf(JP_LOG_WARN, "Warning! %s() returned a sequence of non-sequences.\n",python_function_name);
          }
          Py_XDECREF(hit);
        }
      } else {
        jp_logf(JP_LOG_WARN, "Warning! %s() didn't return a sequence.\n",python_function_name);
      }
      Py_XDECREF(rslt);
      } else {
      PyErr_Print();
      jp_logf(JP_LOG_WARN, "Warning! Failed during python version of %s().\n",python_function_name);
      }
    } else {
      jp_logf(JP_LOG_WARN,"jpilot_user.%s is not a function.\n",python_function_name);
    }
  } else {
    PyErr_Print();
    jp_logf(JP_LOG_WARN,"Warning! Failed to locate python version of %s().\n",python_function_name);
  }
 
  return count;   
}

int plugin_help(char **text, int *width, int *height)
{
   /* We could also pass back *text=NULL
    * and implement whatever we wanted to here.
    */
   *text = strdup(
         /*-------------------------------------------*/
         "jppy plugin for J-Pilot was written by\n"
         "Nick Piper (c) 2006\n"
         "nick@nickpiper.co.uk\n"
         );
   *height = 200;
   *width = 300;
   
   return 0;
}
       
/*
 * This is a plugin callback function called after a sync.
 */
int plugin_post_sync(void)
{
   jp_logf(JP_LOG_DEBUG, "jppy: plugin_post_sync\n");
   return general_int_python_void_function("plugin_post_sync");
}

/*
 * This is a plugin callback function called during program exit.
 */
int plugin_exit_cleanup(void)
{
   jp_logf(JP_LOG_DEBUG, "jppy: plugin_exit_cleanup\n");

   if (python_is_working) {
     Py_XDECREF(python_mod);
     Py_XDECREF(PyString_FromString("jpilot_user"));
     Py_Finalize(); 
   }
  
   return 0;
}


Generated by  Doxygen 1.6.0   Back to index