Logo Search packages:      
Sourcecode: efax-gtk version File versions

main.cpp

/* Copyright (C) 2001 to 2004 Chris Vine

This program is distributed under the General Public Licence, version 2.
For particulars of this and relevant disclaimers see the file
COPYING distributed with the source files.

*/

#include "prog_defs.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>

#include <gtkmm/main.h>
#include <gtkmm/window.h>
#include <glibmm/ustring.h>
#include <glibmm/convert.h>
#include <glibmm/thread.h>
#include <gdk/gdkx.h>  // for GDK_DISPLAY()
#include <gdk/gdk.h>   // for gdk_notify_startup_complete()
#include <X11/Xlib.h>

#include "mainwindow.h"
#include "dialogs.h"
#include "window_icon.h"
#include "fdstream/fdstream.h"

#if GTKMM_VERSION >= 24
#include <gtk/gtkicontheme.h>
#include <gtkmm/icontheme.h>
#include "gtk_icon_info_handle.h"
#endif

#ifdef ENABLE_NLS
#include <locale.h>
#include <libintl.h>
#endif

#define LOCKFILE_NAME "/.efax-gtk-pid"

Prog_config prog_config;

bool is_program_running(void);

bool get_prog_parm(const char*, std::string&, Glib::ustring&, Glib::ustring(*)(const std::string&));

inline bool get_prog_parm(const char* name, std::string& line, Glib::ustring& result) {
  return get_prog_parm(name, line, result, Glib::locale_to_utf8);
}

void get_fonts(void);
void get_window_icon(void);
int mkdir_with_parent(const std::string&);
bool is_arg(const char*, int, char*[]);

int main(int argc, char* argv[]) {

  // set up the locale for gettext() and base locale domain name of this program
#ifdef ENABLE_NLS
  bindtextdomain("efax-gtk", DATADIR "/locale");
  bind_textdomain_codeset("efax-gtk", "UTF-8");
  textdomain("efax-gtk");
  setlocale(LC_ALL,"");
#endif

  if (argc > 1) {
    if (is_arg("--version", argc, argv)) {
      std::string message("efax-gtk-" VERSION "\n");
      message += gettext("Copyright (C) 2001 - 2005 Chris Vine\n"
                   "This program is released under the "
                   "GNU General Public License, version 2\n");
      try {
      message = Glib::locale_from_utf8(message);
      write(1, message.data(), message.size());
      }
      catch (Glib::ConvertError&) {
      std::string err_message("UTF-8 conversion error in main()\n");
      write(2, err_message.data(), err_message.size());
      }
      return 0;
    }
      
    if (is_arg("--help", argc, argv)) {
      std::string message("efax-gtk-" VERSION "\n");
      message += gettext("Usage: efax-gtk [options] [filename]\n"
                   "Options:\n"
                   "\t-r  Start the program in receive standby mode\n"
                   "\t-s  Start the program hidden in the system tray\n"
                   "See the README file which comes with the distribution\n"
                   "for further details\n");
      try {
      message = Glib::locale_from_utf8(message);
      write(1, message.data(), message.size());
      }
      catch  (Glib::ConvertError&) {
      std::string err_message("UTF-8 conversion error in main()\n");
      write(2, err_message.data(), err_message.size());
      }
      return 0;
    }
  }

  Glib::thread_init();
  prog_config.mutex_p = new Glib::Mutex;

  std::string messages(configure_prog(false));

  if(!is_program_running()) {

    Gtk::Main app(argc, argv);

    get_fonts();

    get_window_icon();

    if (!prog_config.GPL_flag) {
      GplDialog gpl_dialog(24);
      int result = gpl_dialog.exec();
      if (result == GplDialog::accepted) {
      std::string file_name(prog_config.working_dir + "/" MAINWIN_SAVE_FILE);
      std::ofstream file(file_name.c_str(), std::ios::out);
      prog_config.GPL_flag = true;
      }
      else beep();
    }
    if (prog_config.GPL_flag) {

      bool start_in_standby = false;
      bool start_hidden = false;
      int opt_result;
      while ((opt_result = getopt(argc, argv, "rs-:")) != -1) {
      switch(opt_result) {
      case 'r':
        start_in_standby = true;
        break;
      case 's':
        start_hidden = true;
        break;
      case '-':
        std::string message(argv[0]);
        message += ": ";
        message += gettext("Invalid option.  Options are:\n");
        message += "  -r\n"
                   "  -s\n"
                   "  --help\n"
                 "  --version\n";
        write(2, message.data(), message.size());
        break;
      }
      }
      const char* filename = 0;
      if (optind < argc) filename = argv[optind];
      
      MainWindow mainwindow(messages, start_hidden, start_in_standby, filename);

      // everything is set up
      // now enter the main program loop
      app.run();
    }
    // remove program lock file
    std::string lockfile(prog_config.working_dir);
    lockfile += LOCKFILE_NAME;
    unlink(lockfile.c_str());
  }
  else {
    // if we have got here then is_program_running() will have detected
    // that there is already an instance of this program running and
    // it will have sent a signal to that instance to present itself
    // on the current workspace.  We now need to tell the window
    // manager that we have completed startup, or the window manager
    // startup notifier will be confused
    Gtk::Main app(argc, argv);
#if GTKMM_VERSION >= 22
    // if we have version 2.2 or higher of gtkmm then we must have
    // version 2.2 or higher of gtk+, so gdk_notify_startup_complete()
    // is available
    gdk_notify_startup_complete();
#else
    // if we are using version 2.0 of gtkmm then we must have version
    // 2.0 of gtk+ so we will do a hack to notify the window manager
    // by starting a dummy window (however we never get into a program
    // loop so it finishes immediately after it has started)
    Gtk::Window window(Gtk::WINDOW_POPUP);
    window.set_size_request(1,1);
    window.show();
    window.hide();
#endif
  }
  delete prog_config.mutex_p;
  return 0;
}

Glib::ustring configure_prog(bool reread) {

  // lock the Prog_config object while we modify it
  Glib::Mutex::Lock lock(*prog_config.mutex_p);

  if (!reread) {

    char* home = std::getenv("HOME");

    if (!home) write_error("Your HOME environmental variable is not defined!\n");
    else {
      prog_config.homedir = home;
      prog_config.working_dir = home;
    }
  }

// now find rc file

  prog_config.found_rcfile = false;
  std::ifstream filein;
  std::string rcfile;
  Glib::ustring return_val;

  if (!prog_config.homedir.empty()) {
    rcfile = prog_config.homedir;
    rcfile += "/." RC_FILE;

#ifdef HAVE_IOS_NOCREATE
    filein.open(rcfile.c_str(), std::ios::in | std::ios::nocreate);
#else
    // we must have Std C++ so we probably don't need a ios::nocreate
    // flag on a read open to ensure uniqueness
    filein.open(rcfile.c_str(), std::ios::in);
#endif

    if (filein) prog_config.found_rcfile = true;
    else filein.clear();
  }

  if (!prog_config.found_rcfile) {

    rcfile = RC_DIR "/" RC_FILE;

#ifdef HAVE_IOS_NOCREATE
    filein.open(rcfile.c_str(), std::ios::in | std::ios::nocreate);
#else
    // we must have Std C++ so we probably don't need a ios::nocreate
    // flag on a read open to ensure uniqueness
    filein.open(rcfile.c_str(), std::ios::in);
#endif

    if (filein) prog_config.found_rcfile = true;
    else filein.clear();
  }

  if (!prog_config.found_rcfile && std::strcmp(RC_DIR, "/etc")) {

    rcfile = "/etc/" RC_FILE;

#ifdef HAVE_IOS_NOCREATE
    filein.open(rcfile.c_str(), std::ios::in | std::ios::nocreate);
#else
    // we must have Std C++ so we probably don't need a ios::nocreate
    // flag on a read open to ensure uniqueness
    filein.open(rcfile.c_str(), std::ios::in);
#endif

    if (filein) prog_config.found_rcfile = true;
    else filein.clear();
  }

  if (!prog_config.found_rcfile) {
    return_val = "Can't find or open file " RC_DIR "/"  RC_FILE ",\n";
    if (std::strcmp(RC_DIR, "/etc")) {
      return_val += "/etc/" RC_FILE ", ";
    }
    if (!prog_config.homedir.empty()) {
      try {
      Glib::ustring temp(Glib::filename_to_utf8(prog_config.homedir));
      return_val +=  "or ";
      return_val += temp;
      return_val += "/." RC_FILE;
      }
      catch (Glib::ConvertError&) {
      write_error("UTF-8 conversion error in configure_prog()\n");
      }
    }
    return_val += "\n";
  }
  
  else {

    // if we are re-reading efax-gtkrc, we need to clear the old settings
    if (reread) {
      prog_config.lock_file = "";
      prog_config.my_name = "";
      prog_config.my_number = "";
      prog_config.parms.clear();
      prog_config.page_size = "";
      prog_config.page_dim = "";
      prog_config.resolution = "";
      prog_config.print_cmd = "";
      prog_config.print_shrink = "";
      prog_config.ps_view_cmd = "";
      prog_config.sock_server_port = "";
      prog_config.fax_received_prog = "";
      prog_config.logfile_name = "";
    }
    // if we are setting up for first time, initialise prog_config.receive_dirname
    else *prog_config.receive_dirname = 0;

// now extract settings from file

    std::string file_read;
    Glib::ustring device;
    Glib::ustring lock_file;
    Glib::ustring modem_class;
    Glib::ustring rings;
    Glib::ustring dialmode;
    Glib::ustring init;
    Glib::ustring reset;
    Glib::ustring capabilities;
    Glib::ustring extra_parms;
    Glib::ustring print_popup;
    Glib::ustring sock_server;
    Glib::ustring sock_popup;
    Glib::ustring sock_client_address;
    Glib::ustring sock_other_addresses;
    Glib::ustring fax_received_popup;
    Glib::ustring fax_received_exec;
    Glib::ustring work_subdir;
    
    while (std::getline(filein, file_read)) {

      if (!file_read.empty() && file_read[0] != '#') { // valid line to check
      // now check for other comment markers
      std::string::size_type pos = file_read.find_first_of('#');
      if (pos != std::string::npos) file_read.resize(pos); // truncate
      
      // look for "NAME:"
      if (get_prog_parm("NAME:", file_read, prog_config.my_name));
      
      // look for "NUMBER:"
      else if (get_prog_parm("NUMBER:", file_read, prog_config.my_number));
      
      // look for "DEVICE:"
      else if (get_prog_parm("DEVICE:", file_read, device));
      
      // look for "LOCK:"
      else if (get_prog_parm("LOCK:", file_read, lock_file,
                         Glib::filename_to_utf8));

      // look for "CLASS:"
      else if (get_prog_parm("CLASS:", file_read, modem_class));

      // look for "PAGE:"
      else if (get_prog_parm("PAGE:", file_read, prog_config.page_size));

      // look for "RES:"
      else if (get_prog_parm("RES:", file_read, prog_config.resolution));
      
      // look for "RINGS:"
      else if (get_prog_parm("RINGS:", file_read, rings));
      
      // look for "DIALMODE:"
      else if (get_prog_parm("DIALMODE:", file_read, dialmode));
      
      // look for "INIT:"
      else if (get_prog_parm("INIT:", file_read, init));
      
      // look for "RESET:"
      else if (get_prog_parm("RESET:", file_read, reset));

      // look for "CAPABILITIES:"
      else if (get_prog_parm("CAPABILITIES:", file_read, capabilities));

      // look for "PARMS:"
      else if (get_prog_parm("PARMS:", file_read, extra_parms));

      // look for "PRINT_CMD:"
      else if (get_prog_parm("PRINT_CMD:", file_read, prog_config.print_cmd));

      // look for "PRINT_SHRINK:"
      else if (get_prog_parm("PRINT_SHRINK:", file_read, prog_config.print_shrink));

      // look for "PRINT_POPUP:"
      else if (get_prog_parm("PRINT_POPUP:", file_read, print_popup));

      // look for "PS_VIEWER:"
      else if (get_prog_parm("PS_VIEWER:", file_read, prog_config.ps_view_cmd));

      // look for "SOCK_SERVER:"
      else if (get_prog_parm("SOCK_SERVER:", file_read, sock_server));

      // look for "SOCK_POPUP:"
      else if (get_prog_parm("SOCK_POPUP:", file_read, sock_popup));

      // look for "SOCK_SERVER_PORT:"
      else if (get_prog_parm("SOCK_SERVER_PORT:", file_read, prog_config.sock_server_port));

      // look for "SOCK_CLIENT_ADDRESS:"
      else if (get_prog_parm("SOCK_CLIENT_ADDRESS:", file_read, sock_client_address));

      // look for "SOCK_OTHER_ADDRESSES:"
      else if (get_prog_parm("SOCK_OTHER_ADDRESSES:", file_read, sock_other_addresses));

      // look for "FAX_RECEIVED_POPUP:"
      else if (get_prog_parm("FAX_RECEIVED_POPUP:", file_read, fax_received_popup));

      // look for "FAX_RECEIVED_EXEC:"
      else if (get_prog_parm("FAX_RECEIVED_EXEC:", file_read, fax_received_exec));

      // look for "FAX_RECEIVED_PROG:"
      else if (get_prog_parm("FAX_RECEIVED_PROG:", file_read, prog_config.fax_received_prog,
                         Glib::filename_to_utf8));

      // look for "LOG_FILE:"
      else if (get_prog_parm("LOG_FILE:", file_read, prog_config.logfile_name,
                         Glib::filename_to_utf8));

      // look for "WORK_SUBDIR:"
      else if (get_prog_parm("WORK_SUBDIR:", file_read, work_subdir,
                         Glib::filename_to_utf8));
      }
    }

    // we have finished reading the configuration file    
    // now enter parameters common to send and receive of faxes   
    prog_config.parms.push_back("efax-0.9a");

    prog_config.parms.push_back("-vew");  // stderr -- errors and warnings
    
    prog_config.parms.push_back("-vin");  // stdin -- information and negotiations
    //prog_config.parms.push_back("-vina");  // this will also report the parameters passed to efax
                                             // uncomment it and comment out preceding line for debugging
    
    std::string temp;

    if (!prog_config.my_number.empty()) {
      temp = "-l";
      temp += prog_config.my_number;
      prog_config.parms.push_back(temp);
    }

    if (!init.empty()) {
      std::string::size_type start = 0;
      std::string::size_type end;
      
      while (start != std::string::npos) {
      temp = "-i";
      end = init.find_first_of(" \t", start);
      if (end != std::string::npos) {
        temp.append(init, start, end - start);
        start = init.find_first_not_of(" \t", end); // prepare for the next iteration
      }
      else {
        temp.append(init, start, init.size() - start);
        start = end;
      }
      prog_config.parms.push_back(temp);
      }
    }
    
    else {
      prog_config.parms.push_back("-iZ");
      prog_config.parms.push_back("-i&FE&D2S7=120");
      prog_config.parms.push_back("-i&C0");
      prog_config.parms.push_back("-iM1L0");
      
    }
    
    if (!reset.empty()) {
      std::string::size_type start = 0;
      std::string::size_type end;
    
      while (start != std::string::npos) {
      temp = "-k";
      end = reset.find_first_of(" \t", start);
      if (end != std::string::npos) {
        temp.append(reset, start, end - start);
        start = reset.find_first_not_of(" \t", end); // prepare for the next iteration
      }
      else {
        temp.append(reset, start, reset.size() - start);
        start = end;
      }
      prog_config.parms.push_back(temp);
      }
    }

    else prog_config.parms.push_back("-kZ");
    
    if (!modem_class.empty()) {
      temp = "-o";
      if (!modem_class.compare("2.0")) temp += '0';
      else if (!modem_class.compare("1")) temp += '1';
      else if (!modem_class.compare("2")) temp += '2';
      else {
      return_val += gettext("Invalid modem class specified\n"
                        "Adopting default of Class 2\n");
        temp += '2';
      }
      prog_config.parms.push_back(temp);
    }
      
    if (device.empty()) {
      if (access("/dev/modem", F_OK) == -1) {
      return_val += gettext("No serial port device specified in " RC_FILE " configuration file\n"
                        "and /dev/modem does not exist\n");
      }
      
      else {
      return_val += gettext("No serial port device specified in " RC_FILE " configuration file\n"
                        "Using default of /dev/modem\n");
      device = "modem";
      }
    }

    if (!device.empty()) {
      std::string locale_device;
      try {
      locale_device = Glib::locale_from_utf8(device);
      }
      catch (Glib::ConvertError&) {
      write_error("UTF-8 conversion error in configure_prog() - device\n");
      }

      if (!locale_device.empty()) {
      if (lock_file.empty()) {
        prog_config.lock_file = "/var/lock";
      }
      else {
        try {
          prog_config.lock_file = Glib::filename_from_utf8(lock_file);
        }
        catch (Glib::ConvertError&) {
          write_error("UTF-8 conversion error in configure_prog() - lock file\n");
          write_error("Defaulting to /var/lock\n");
          prog_config.lock_file = "/var/lock";
        }
      }
      
      prog_config.lock_file += "/LCK..";
      prog_config.lock_file += device;
      
      temp = "-d/dev/";
      temp += locale_device;
      prog_config.parms.push_back(temp);

      temp = "-x";
      temp += prog_config.lock_file;
      prog_config.parms.push_back(temp);
      }
    }

    if (!capabilities.empty()) {
      temp = "-c";
      temp += capabilities;
      prog_config.parms.push_back(temp);
    }

    if (prog_config.resolution.empty()) {
      return_val += gettext("Adopting default fax resolution of 204x196\n");
      prog_config.resolution = "204x196";
    }
    else {
      temp = prog_config.resolution.lowercase();
      if (!temp.compare("fine")) prog_config.resolution = "204x196";
      else if (!temp.compare("standard")) prog_config.resolution = "204x98";
      else {
      return_val += gettext("Invalid fax resolution specified\n"
                        "Adopting default fax resolution of 204x196\n");
      prog_config.resolution = "204x196";
      }
    }
    
    if (rings.empty()) prog_config.rings = '1';
    else if (rings.size() > 1 || rings[0] < '1' || rings[0] > '9') {
      return_val += gettext("Invalid ring number specified\n"
                      "Will answer after one ring\n");
      prog_config.rings = '1';
    }
    else prog_config.rings = rings[0];

    if (prog_config.page_size.empty()) {
      return_val += gettext("Adopting default page size of a4\n");
      prog_config.page_size = "a4";
      prog_config.page_dim = "210x297mm";
    }
    else {
      prog_config.page_size = prog_config.page_size.lowercase();
      if (!prog_config.page_size.compare("a4")) prog_config.page_dim = "210x297mm";
      else if (!prog_config.page_size.compare("letter")) prog_config.page_dim = "216x279mm";
      else if (!prog_config.page_size.compare("legal")) prog_config.page_dim = "216x356mm";
      else {
      return_val += gettext("Invalid page size specified\n"
                        "Adopting default page size of a4\n");
      prog_config.page_size = "a4";
      prog_config.page_dim = "210x297mm";
      }
    }
    
    if (dialmode.empty()) prog_config.tone_dial = true;
    else {
      temp = dialmode.lowercase();
      if (!temp.compare("tone")) prog_config.tone_dial = true;
      else if (!temp.compare("pulse")) prog_config.tone_dial = false;
      else {
      return_val += gettext("Invalid dialmode specified\n"
                        "Adopting default of tone dialling\n");
      prog_config.tone_dial = true;
      }
    }

    if (!extra_parms.empty()) {
      std::string::size_type start = 0;
      std::string::size_type end;
    
      while (start != std::string::npos) {
      end = extra_parms.find_first_of(" \t", start);
      if (end != std::string::npos) {
        temp.assign(extra_parms, start, end - start);
        start = extra_parms.find_first_not_of(" \t", end); // prepare for the next iteration
      }
      else {
        temp.assign(extra_parms, start, extra_parms.size() - start);
        start = end;
      }
      prog_config.parms.push_back(temp);
      }
    }
    if (prog_config.print_cmd.empty()) {
      return_val += gettext("Adopting default printer command of 'lpr'\n");
      prog_config.print_cmd = "lpr";
    }
    
    if (prog_config.print_shrink.empty()) {
      prog_config.print_shrink = "100";
    }
    else if (std::atoi(prog_config.print_shrink.c_str()) < 50 || std::atoi(prog_config.print_shrink.c_str()) > 100) {
      return_val += gettext("Invalid print shrink specified: adopting default value of 100\n");
      prog_config.print_shrink = "100";
    }
    
    temp = print_popup.lowercase();
    if (!temp.compare("no")) prog_config.print_popup = false;
    else prog_config.print_popup = true;

    if (prog_config.ps_view_cmd.empty()) {
      return_val += gettext("Adopting default postscript view command of 'gv'\n");
      prog_config.ps_view_cmd = "gv";
    }

    temp = sock_server.lowercase();
    if (!temp.compare("yes")) prog_config.sock_server = true;
    else prog_config.sock_server = false;

    temp = sock_popup.lowercase();
    if (!temp.compare("yes")) prog_config.sock_popup = true;
    else prog_config.sock_popup = false;

    if (prog_config.sock_server_port.empty()) {
      if (prog_config.sock_server) 
      return_val += gettext("No port for the socket server has been specified, "
                        "so the server will not be started\n");
    }

    else if (std::atoi(prog_config.sock_server_port.c_str()) < 1024
           || std::atoi(prog_config.sock_server_port.c_str()) > 65535) {
      return_val += gettext("Invalid port for the socket server has been specified, "
                      "so the server will not be started.  It needs to be between "
                      "1024 and 65535\n");
      prog_config.sock_server_port = "";
    }

    temp = sock_client_address.lowercase();
    if (!temp.compare("other")) prog_config.other_sock_client_address = true;
    else prog_config.other_sock_client_address = false;

    if (!sock_other_addresses.empty()) {
      std::string::size_type start = 0;
      std::string::size_type end;
    
      while (start != std::string::npos) {
      end = sock_other_addresses.find_first_of(" \t", start);
      if (end != std::string::npos) {
        temp.assign(sock_other_addresses, start, end - start);
        start = sock_other_addresses.find_first_not_of(" \t", end); // prepare for the next iteration
      }
      else {
        temp.assign(sock_other_addresses, start, sock_other_addresses.size() - start);
        start = end;
      }
      prog_config.permitted_clients_list.push_back(temp);
      }
    }

    temp = fax_received_popup.lowercase();
    if (!temp.compare("yes")) prog_config.fax_received_popup = true;
    else prog_config.fax_received_popup = false;

    temp = fax_received_exec.lowercase();
    if (!temp.compare("yes")) prog_config.fax_received_exec = true;
    else prog_config.fax_received_exec = false;

    if (!reread) {  // prog_config.working_dir and prog_config.GPL_flag are not
                    // affected by the settings dialog and so not re-configurable
                    // after the program has initialised itself for the first time
      // CMV 24-07-04
      if (!work_subdir.empty()) {
      prog_config.working_dir += '/';
      prog_config.working_dir += Glib::filename_from_utf8(work_subdir);
      if (mkdir_with_parent(prog_config.working_dir) && errno != EEXIST) {
        return_val += gettext("Invalid WORK_SUBDIR: directory specified. "
                        "WORK_SUBDIR: will be ignored\n");
        prog_config.working_dir = prog_config.homedir;
      }
      }

      std::string file_name(prog_config.working_dir + "/" MAINWIN_SAVE_FILE);
      int result = access(file_name.c_str(), F_OK);
  
      if (!result) prog_config.GPL_flag = true;
      else prog_config.GPL_flag = false;
    }
  }
  return return_val;
}

void get_fonts(void) {

  // this will get a suitable fixed font for GplDialog and HelpDialog to use with Pango
  const int MAX_FONTS = 10000;
  int num_fonts;
  char** fonts = XListFonts(GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);

  if (fonts) {
    int count;
    std::string inspect_name;
    prog_config.fixed_font = "";

    //try for courier font
    for (count = 0; count < num_fonts; count++) {
      inspect_name = fonts[count];
      std::string::size_type pos = inspect_name.find("courier-medium-r-normal-");
      if (pos != std::string::npos) {
      prog_config.fixed_font = "courier";
      break;
      }
    }

    // unsuccessful -- go for the generic "fixed" font
    if (prog_config.fixed_font.empty()) prog_config.fixed_font = "fixed";
  }
  XFreeFontNames(fonts);
}

bool get_prog_parm(const char* name, std::string& line, Glib::ustring& result,
               Glib::ustring(*convert_func)(const std::string&)) {
// This function looks for a setting named `name' in the string `line'
// and returns the values stated after it in string `result'.  It returns
// `true' if the setting was found.  If there are trailing spaces or tabs,
// string `line' will be modified.  string `result' is only modified if
// the `name' setting is found.  Anything extracted from `line' will be
// converted (when placed into `result') to UTF-8 as maintained by
// Glib::ustring, using the function assigned to function pointer
// convert_func (you would normally use Glib::locale_to_utf8() or
// Glib::filename_to_utf8(), and there is a default inline function
// using Glib::locale_to_utf8()

  const std::string::size_type length = std::strlen(name);
  // we have to use std::string::substr() because libstdc++-2
  // doesn't support the Std-C++ std::string::compare() functions
  if (!line.substr(0, length).compare(name)) {
    // erase any trailing space or tab
    while (line.find_last_of(" \t") == line.size() - 1) line.resize(line.size() - 1);
    if (line.size() > length) {
      // ignore any preceding space or tab from the setting value given
      std::string::size_type pos = line.find_first_not_of(" \t", length); // pos now is set to beginning of setting value
      if (pos != std::string::npos) {
      try {
        result.assign(convert_func(line.substr(pos)));
      }
      catch (Glib::ConvertError&) {
        result = "";
        write_error("UTF-8 conversion error in get_prog_parm()\n");
      }
      }
    }
    return true;
  }
  return false;
}

void beep(void) {
  XBell(GDK_DISPLAY(), 0);
}

void get_window_icon(void) {

  bool have_icon = false;

#if GTKMM_VERSION >= 24
  Glib::RefPtr<Gtk::IconTheme> icon_theme_r = Gtk::IconTheme::get_default();

  // use the C function to look-up the icon - the gtkmm wrapper does not
  // check whether look-up succeeded.  In addition, Gtk::IconInfo::get_filename()
  // incorrectly returns a Glib::ustring object instead of a std::string object,
  // without converting its contents to a valid UTF-8 encoded string

  Gtk_icon_info_scoped_handle icon_info_h(
                        gtk_icon_theme_lookup_icon(icon_theme_r->gobj(),
                                           "stock_send-fax",
                                           24, GtkIconLookupFlags(0)));
  if (icon_info_h.get()) {
      
    // we could use Glib::convert_const_gchar_ptr_to_stdstring, but this is not
    // part of the publicly documented interface
    const char* icon_path_p = (const char*)gtk_icon_info_get_filename(icon_info_h.get());
    if (icon_path_p) {
      try {
      prog_config.window_icon_r = Gdk::Pixbuf::create_from_file(std::string(icon_path_p));
      have_icon = true;
      }
      catch (Gdk::PixbufError&) {
      write_error("Pixbuf error in get_window_icon()\n");
      }
    }
  }
#endif

  if (!have_icon) {
    prog_config.window_icon_r = Gdk::Pixbuf::create_from_xpm_data(window_icon_xpm);
  }
}

int mkdir_with_parent(const std::string& dir) {

  // this function must be passed an absolute path name
  // on success it returns 0, and on failure it returns -1.  If -1 is returned
  // for any reason other than that an absolute pathname was not passed
  // then errno will be set by Unix mkdir()

  // function provided by CMV 24-07-04

  int return_val = 0;

  if (dir[0] != '/') return_val = -1;

  else {
    std::string::size_type pos = 0;
    while (pos != std::string::npos && (!return_val || errno == EEXIST)) {
      pos = dir.find('/', ++pos);
      if (pos != std::string::npos) {
      return_val = mkdir(dir.substr(0, pos).c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
      }
      else {
      return_val = mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
      }
    }
  }
  return return_val;
}

bool is_arg(const char* arg, int argc, char* argv[]) {

  bool return_val;
  int count;
  for (return_val = false, count = 1; !return_val && count < argc; count++) {
    if (!std::strcmp(argv[count], arg)) return_val = true;
  }
  return return_val;
}

bool is_program_running(void) {

  bool return_val = false;
  int count = 0;

  std::string lockfile(prog_config.working_dir);
  lockfile += LOCKFILE_NAME;

  // do an atomic exclusive write open on the lockfile
  // we do not need to check for EINTR on the open as we do not catch
  // any signals at this stage
  int new_lock_fd = open(lockfile.c_str(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  while (count < 2 && new_lock_fd == -1) {      // check to see why we could not open new_lock
    if (access(lockfile.c_str(), F_OK) == -1) { // file doesn't exist, so there must be a problem with permissions

      std::cerr << "Cannot create lockfile " << lockfile << std::endl;
    }

    else {   // the lockfile already exists - see if it is stale
      ifstream existing_lock(lockfile.c_str(), ios::in);
      if(!existing_lock) { // can't open lock file
      std::cerr << "Not able to access existing lockfile " << lockfile << std::endl;
      // get rid of the old lockfile if we can
      unlink(lockfile.c_str());
      }
      else { // lock file already exists and we can open it - check if stale
      pid_t existing_lock_pid;
      existing_lock >> existing_lock_pid;
      if (existing_lock && (kill(existing_lock_pid, 0)) < 0) { // stale lock
        unlink(lockfile.c_str());    // delete stale lock file
        new_lock_fd = open(lockfile.c_str(), O_WRONLY | O_CREAT | O_EXCL,
                       S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        count++;                     // signal we can only have one more try if this open fails
      }
      else {                         // active lock - send efax-gtk a signal
        std::cout << "Active lock - bringing up existing instance of efax-gtk" << std::endl;
        count = 2;                   // break out of the loop
        kill(existing_lock_pid, SIGUSR2);
        return_val = true;
      }
      }
    }
  }
  if (count < 2 && new_lock_fd >= 0)  {// we have successfully created a lock file - now write our pid to it

    Attachable::Out new_lock;
    new_lock.attach(new_lock_fd);
    new_lock << std::setfill('0') << std::setw(10) << getpid() << std::endl;
    new_lock.close();
  }
  return return_val;
}

Generated by  Doxygen 1.6.0   Back to index