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

bibletime.cpp

/*
** Copyright (C) 2003-2006 Teus Benschop.
**  
** 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 "libraries.h"
#include "utilities.h"
#include <libgen.h>
#include <glib.h>
#include <config.h>
#include "bibletime.h"
#include "bible.h"
#include "gwrappers.h"
#include "shell.h"
#include "books.h"
#include "session.h"


#define STAGE_ZERO 0
#define STAGE_COMMUNICATE 1
#define STAGE_WAIT_RETRY 1000
#define STAGE_RETRY 1200


#define BIBLETIME "bibletime"


BibleTime::BibleTime (bool dummy)
/*
This communicates with BibleTime. It uses KDE's DCOP protocol.
It centralizes all communication with BibleTime so that all happens synchronized,
and two different commands, occurring at the same time, will not disturb each
other.
*/
{
  connected = false;
  stage = STAGE_ZERO;
  thread_run = true;
  bibletime_got_reference = false;
  send_now = false;
  update_modules = true;
  search_now = false;
  reloadmodules_now = false;
  g_thread_create (GThreadFunc (thread_start), gpointer (this), false, NULL);
}


BibleTime::~BibleTime ()
{
  // Indicate to the thread we want to stop.
  thread_run = false;
  // Wait until thread has exited.
  while (thread_running)
    g_usleep (10000);
}


void BibleTime::log (const ustring & message)
{
  if (message != previous_message) {
    gw_message ("BibleTime: " + message);
    previous_message = message;
  }
}


void BibleTime::sendreference (const ustring& book, const ustring& chapter, const ustring& verse)
{
  // Stores the reference to be sent to BibleTime. 
  // The scheduler will take care of that shortly after.
  send_book = book;
  send_chapter = chapter;
  send_verse = verse;
  send_now = true;
}


bool BibleTime::getreference (ustring& book, ustring& chapter, ustring& verse)
{
  book = bibletime_book;
  chapter = bibletime_chapter;
  verse = bibletime_verse;
  return bibletime_got_reference;
}


void BibleTime::thread_start (gpointer data)
{
  ((BibleTime*) data)->thread_main();
}


void BibleTime::thread_main ()
{
  thread_running = true;
  while (thread_run) {
    switch (stage)
      {
      case STAGE_ZERO:
      {
        // Check if BibleTime is running.
        if (!program_is_running (BIBLETIME)) {
          log ("Program is not running");
          stage = STAGE_WAIT_RETRY;
          break;
        }
        // Check if dcop protocol is working, and get bibletime's name.
        bibledit_dcop_name.clear();
        FILE *stream;
        ustring command = "dcop";
        stream = popen (command.c_str (), "r");
        char buf[1024];
        while (fgets (buf, sizeof (buf), stream)) {
          command = buf;
          command = trim (command);
          if (command.find (BIBLETIME) != string::npos) {
            bibledit_dcop_name = command;
          }
        }
        pclose (stream);
        // Was bibledit's dcop name found?
        if (bibledit_dcop_name.empty()) {
          log ("No DCOP connection possible");
          stage = STAGE_WAIT_RETRY;
          break;
        }
        // Ok, connection is possible.
        log ("Connected");
        connected = true;
        stage = STAGE_COMMUNICATE;
      }
      case STAGE_COMMUNICATE:
      {
        bibletime_got_reference = getreference_internal ();
        sendreference_internal ();
        if (update_modules) {
          get_modules ();
          update_modules = false;
        }
        if (search_now) {
          search_internal ();
          search_now = false;
        }
        if (reloadmodules_now) {
          reloadmodules_internal ();
          reloadmodules_now = false;
        }
        break;
      }
      case STAGE_WAIT_RETRY:
      {
        stage++;
        break;
      }
      case STAGE_RETRY:
      {
        stage = STAGE_ZERO;
        break;
      }
      default:
      {
        stage++;
      }
    }
    g_usleep (300000);
  }
  thread_running = false;
}


void BibleTime::sendreference_internal ()
{
  // Sends the reference to BibleTime.
  if (connected) {
    if (send_now) {
      unsigned id = books_english_to_id (send_book);
      // If the project is closed, then the id is 0. Deal with that here.
      // Solves a crash bug.
      if (!id)
        return;
      ustring osisbook = books_id_to_osis (id);
      ustring command = dcop_command();
      command.append ("syncAllVerseBasedModules ");
      command.append (osisbook);
      command.append (".");
      command.append (send_chapter);
      command.append (".");
      command.append (send_verse);
      Session session (0);
      if (session.debug ()) log (command);
      bool spawned;
      gint exit_status;
      spawned = g_spawn_command_line_sync (command.c_str(), NULL, NULL, &exit_status, NULL);
      check_exit (spawned, exit_status);
      send_now = false;
    }
  }
}


bool BibleTime::getreference_internal ()
// Get the reference from BibleTime. Store it.
{
  // Variabele whether we got a reference.
  bool returnvalue = bibletime_got_reference;
  // Only communicate when BibleTime is connected.
  if (connected) {
    // Store BibleTime's reply.
    ustring result;
    // Execute command to elicit a reply.
    ustring command = dcop_command();
    command.append ("getCurrentReference");
    FILE *stream;
    stream = popen (command.c_str (), "r");
    char buf[10240];
    while (fgets (buf, sizeof (buf), stream)) {
      result = buf;
    }
    int exit_status = pclose (stream);
    check_exit (true, exit_status);
    // Only proceed if we have a different value than before.
    if (result != bibletime_reply) {
      bibletime_reply = result;
      // Clean up the reply and see whether we have either a Bible or a Commentary.
      result = trim (result);
      #define BIBLETIME_BIBLE "[BIBLE]"
      #define BIBLETIME_COMMENTARY "[COMMENTARY]"
      size_t offset;
      offset = result.find (BIBLETIME_BIBLE);
      if (offset != string::npos) {
        offset += strlen (BIBLETIME_BIBLE);
      } else {
        offset = result.find (BIBLETIME_COMMENTARY);
        if (offset != string::npos) {
          offset += strlen (BIBLETIME_COMMENTARY);
        }
      }
      #undef BIBLETIME_BIBLE
      #undef BIBLETIME_COMMENTARY
      // In case of Bible/commentary, transform the reference to our format.
      if (offset != string::npos) {
        result.erase (0, offset);
        result = trim (result);
        returnvalue = reference_discover ("", "", "", result, bibletime_book, bibletime_chapter, bibletime_verse);
      }
    }
  } 
  return returnvalue;
}


vector<ustring> BibleTime::getbibles ()
{
  update_modules = true;
  return bibles;
}


vector<ustring> BibleTime::getcommentaries ()
{
  update_modules = true;
  return commentaries;
}


void BibleTime::get_modules ()
{
  // Clear current modules.
  bibles.clear();
  commentaries.clear();
  // Get the Bibles from BibleTime.
  ustring command = dcop_command ();
  command.append ("getModulesOfType BIBLES");
  FILE *stream;
  stream = popen (command.c_str (), "r");
  char buf[1024];
  while (fgets (buf, sizeof (buf), stream)) {
    ustring result = buf;
    result = trim (result);
    if (!result.empty())
      bibles.push_back (trim (result));
  }
  pclose (stream);
  // Get the Commentaries from BibleTime.
  command = dcop_command ();
  command.append ("getModulesOfType COMMENTARIES");
  stream = popen (command.c_str (), "r");
  while (fgets (buf, sizeof (buf), stream)) {
    ustring result = buf;
    result = trim (result);
    if (!result.empty())
      commentaries.push_back (trim (result));
  }
  pclose (stream);
}


ustring BibleTime::dcop_command ()
{
  ustring command;
  command = "dcop ";
  command.append (bibledit_dcop_name);
  command.append (" BibleTimeInterface ");
  return command; 
}


vector<ustring> BibleTime::search_in_default_bible (const ustring& searchtext)
{
  return search ("", searchtext, 0);;
}


vector<ustring> BibleTime::search_in_open_modules (const ustring& searchtext)
{
  return search ("", searchtext, 1);
}


vector<ustring> BibleTime::search_in_module (const ustring& modulename, const ustring& searchtext)
{
  return search (modulename, searchtext, 2);
}


vector<ustring> BibleTime::search (const ustring& modulename, const ustring& searchtext, int selector)
{
  // Create the command to send to BibleTime in order to search.
  search_command = dcop_command ();
  switch (selector) {
    case 0 :
      search_command.append ("searchInDefaultBible");
      break;
    case 1 :
      search_command.append ("searchInOpenModules");
      break;
    case 2 :
      search_command.append ("searchInModule ");
      search_command.append (modulename);
      break;
  }

  // Add searchtext to the command.  
  // Escape certain characters in the text, because it goes through the shell.
  gchar * escaped_text;
  escaped_text = g_strescape (searchtext.c_str(), "");
  ustring localsearchtext = escaped_text;
  g_free (escaped_text);
  search_command.append (" ");
  search_command.append (localsearchtext);
  
  // Signal the thread that we can search. Wait until it has done the job.
  search_now = true;
  while (search_now)
    g_usleep (100000);
  
  return search_results;
}


void BibleTime::search_internal ()
{
  // Clear current results.
  search_results.clear();
  // Get the search results from BibleTime.
  FILE *stream;
  stream = popen (search_command.c_str (), "r");
  char buf[1024];
  while (fgets (buf, sizeof (buf), stream)) {
    ustring result = buf;
    result = trim (result);
    if (!result.empty())
      search_results.push_back (trim (result));
  }
  pclose (stream);
}


void BibleTime::check_exit (bool spawned, int exitstatus)
{
  if (!spawned || (exitstatus != 0)) {
    connected = false;
    stage = STAGE_ZERO;
    log ("Error while communicating");
  }
}


void BibleTime::reloadmodules ()
{
  reloadmodules_now = true;
}


void BibleTime::reloadmodules_internal ()
{
  ustring command = dcop_command();
  command.append ("reloadModules ");
  gint exit_status;
  g_spawn_command_line_sync (command.c_str(), NULL, NULL, &exit_status, NULL);
  reloadmodules_now = false;
}

Generated by  Doxygen 1.6.0   Back to index