/*
 * Program name:  equake
 * Version:	  1.3.8.2
 * Source file:	  equake_applet.c  
 * Description:	  Equake pulls data about earthquakes and displays it in interesting ways
 *
 * Copyright (C) 2016-2018 Jeroen van Aart
 *
 * 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.
 */


/*
 * get rid of warnings "incompatible implicit declaration of built-in function ‘strndup’"
 * also see http://cboard.cprogramming.com/c-programming/119875-using-strndup.html
 */
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <sys/types.h>
#include <pwd.h>
#include <errno.h>

#include <string.h>

#include <mate-panel-applet.h>
#include <gtk/gtk.h>
#include <glib-object.h>

#include "equake_dat.h" /* contains all structures */
#include "equake_func.h" /* contains all function prototypes used in this program */
#include "equake_images.h" /* GdkPixbuf image defines */

void equake_setprefs(struct Equake_Data *equakedata)
{
  FILE *fp;

  /* lets try to open read only, if it succeeds we try to read the preferences */
  fp=fopen(equakedata->configfile, "r");
  if (fp!=NULL)
  {
    /* file exists so we read the preferences */
    fclose(fp);
    equake_getprefs(equakedata);
  }
  /* 
   * we will now save the preferences to the file, in case the file didn't exist yet it will be created with defaults
   * if it did exist it will be recreated with the user's saved settings, any newly created preferences that
   * didn't exist yet since a previous release will be added with a default
   */
  fp=fopen(equakedata->configfile, "w");
  equake_saveprefs(equakedata, fp);
  fclose(fp);
}

void equake_getprefs(struct Equake_Data *equakedata)
{
  FILE *fp;
  char *buf;
  size_t nbytes=100;
  int val;

  fp=fopen(equakedata->configfile, "r");
  if (fp==NULL)
    return ;

  buf=(char*)malloc(nbytes+1);
  if (buf==NULL)
    return;

  if (getline(&buf, &nbytes, fp)!=-1)
  {
    if (strncmp(buf,CONFIGHEADER,nbytes))
    {
      /* 
       * this is a valid config file 
       * read 2 lines, second line contains polltime
       */
      if (getline(&buf, &nbytes, fp)!=-1)
      {
	if (getline(&buf, &nbytes, fp)!=-1)
	{
	  /* here we expect polltime */
          val=atoi(buf);
	  /* we use switch/case in order to make sure poll exactly matches valid values */ 
          switch (val)
	  {
            case 120:
	      equakedata->poll_time=120; /* 2 minutes */
	      equakedata->properties_index[0]=0;
	      break;
	    case 180:
	      equakedata->poll_time=180;
              equakedata->properties_index[0]=1;
	      break;
	    case 240:
	      equakedata->poll_time=240;
              equakedata->properties_index[0]=2;
	      break;
	    case 300:
	      equakedata->poll_time=300;
              equakedata->properties_index[0]=3;
	      break;
	    case 600:
	      equakedata->poll_time=600;
              equakedata->properties_index[0]=4;
	      break;
	    case 900:
	      equakedata->poll_time=900;
              equakedata->properties_index[0]=5;
	      break;
	    case 1200:
	      equakedata->poll_time=1200;
              equakedata->properties_index[0]=6;
	      break;
	    case 1800:
	      equakedata->poll_time=1800;
              equakedata->properties_index[0]=7;
	      break;
	    default:
	      equakedata->poll_time=300; /* 5 minutes will be the default */
              equakedata->properties_index[0]=3;
	      break;
	  }    
	}
      }

      if (getline(&buf, &nbytes, fp)!=-1)
      {
        if (getline(&buf, &nbytes, fp)!=-1)
        {
	  /* will alert? */	  
          val=atoi(buf);
	  if (val==0)
	  {
	    equakedata->will_alert=0;
            equakedata->properties_index[1]=0;
	  }
	  else
	  {
            equakedata->will_alert=1;
            equakedata->properties_index[1]=1;
	  }
	}
      }
      
      if (getline(&buf, &nbytes, fp)!=-1)
      {
        if (getline(&buf, &nbytes, fp)!=-1)
        {
	  /* alert heavy */	  
          val=atoi(buf);
	  switch (val)
	  {
	    case 3:
	      equakedata->alert_heavy=3;
              equakedata->properties_index[2]=0;
	      break;
	    case 4:
              equakedata->alert_heavy=4;
              equakedata->properties_index[2]=1;
              break;
	    case 5:
              equakedata->alert_heavy=5;
              equakedata->properties_index[2]=2;
              break;
	    case 6:
              equakedata->alert_heavy=6;
              equakedata->properties_index[2]=3;
              break;
	    case 7:
              equakedata->alert_heavy=7;
              equakedata->properties_index[2]=4;
              break;
	    case 8:
              equakedata->alert_heavy=8;
              equakedata->properties_index[2]=5;
              break;
	    default:
              equakedata->alert_heavy=ALERTHEAVY;
              equakedata->properties_index[2]=3;
              break;
	  }
	}
      }

      if (getline(&buf, &nbytes, fp)!=-1)
      {
        if (getline(&buf, &nbytes, fp)!=-1)
        {
          /* sigfilemag */
          val=atoi(buf);
	  switch (val)
	  {
	    case 0:
	      equakedata->sigfilemag=0;
              equakedata->properties_index[3]=0;
	      break;
	    case 2:
	      equakedata->sigfilemag=2;
              equakedata->properties_index[3]=1;
	      break;
            case 3:
              equakedata->sigfilemag=3;
              equakedata->properties_index[3]=2;
              break;
            case 4:
              equakedata->sigfilemag=4;
              equakedata->properties_index[3]=3;
              break;
            case 5:
              equakedata->sigfilemag=5;
              equakedata->properties_index[3]=4;
              break;
            case 6:
              equakedata->sigfilemag=6;
              equakedata->properties_index[3]=5;
              break;
            case 7:
              equakedata->sigfilemag=7;
              equakedata->properties_index[3]=6;
              break;
            case 8:
              equakedata->sigfilemag=8;
              equakedata->properties_index[3]=7;
              break;
            default:
              equakedata->sigfilemag=SIGFILEMAG;
              equakedata->properties_index[3]=3;
              break;
	  }
	}
      }

      if (getline(&buf, &nbytes, fp)!=-1)
      {
        if (getline(&buf, &nbytes, fp)!=-1)
        {
          /* minimum magnitude to monitor */
          val=atoi(buf);
          switch (val)
	  {
	    case 2:
	      equakedata->monitormag=2;
              equakedata->properties_index[4]=1;
	      break;
	    case 3:
	      equakedata->monitormag=3;
              equakedata->properties_index[4]=2;
	      break;
	    default:
	      equakedata->monitormag=MONITORMAG;
              equakedata->properties_index[4]=0;
	      break;
	  }
	}
      }
    }
  }
  free(buf);
  fclose(fp);
  return;  
}

void equake_saveprefs(struct Equake_Data *equakedata, FILE *fp)
{
  /* make sure fp is not NULL, even though it's should never be NULL at this point */
  if (fp==NULL)
    return;

  fprintf(fp, "%s\n", CONFIGHEADER);
  fprintf(fp, "%s\n", "# polltime in seconds, will only allow (2, 3, 4, 5, 10, 15, 20, 30) *60 seconds, any other value will default to 5*60 seconds");
  fprintf(fp, "%d\n", equakedata->poll_time);
  fprintf(fp, "%s\n", "# will alert about high magnitude earthquakes, 1=yes, 0=no (if not set or anything else=yes)");
  fprintf(fp, "%d\n", equakedata->will_alert);
  fprintf(fp, "%s\n", "# minimum magnitude to display alert dialog, default is 6 (can be 3, 4, 5, 6, 7, 8, anything else defaults to 6)");
  fprintf(fp, "%d\n", equakedata->alert_heavy);
  fprintf(fp, "%s\n", "# minimum alert to store in signature file (~/.equake_sigfile.eq), default is 4 (can be 2, 3, 4, 5, 6, 7, 8, anything else defaults to 4, 0 turns it off)");
  fprintf(fp, "%d\n", equakedata->sigfilemag);
  fprintf(fp, "%s\n", "# minimum magnitude earthquake to monitor, default is 1 (can be 1, 2 or 3, anything else defaults to 1)");
  fprintf(fp, "%d\n", equakedata->monitormag);
}

static gboolean button_press_callback(GtkWidget *event_box, GdkEventButton *event, gpointer data)
{
  char url[512];

  /* only do something if left mouse button was released */
  if ((event->type==GDK_BUTTON_PRESS) && (event->button==1))
  {
    snprintf(url, URLSIZE, "%s", USGS_WEBSITE);

    display_url(url);

    return 0;
  }
  else
    return -1;
}

static char *ui = "<menuitem name='EquakeUpdate' action='EquakeUpdate' />"
                  "<menuitem name='EquakeDetails' action='EquakeDetails' />"
                  "<menuitem name='EquakeMap' action='EquakeMap' />"
                  "<menuitem name='EquakeDidyoufeelit' action='EquakeDidyouFeelit' />"
                  "<menuitem name='EquakeLasthour' action='EquakeLastHour' />"
                  "<menuitem name='EquakeLastday' action='EquakeLastDay' />"
                  "<menuitem name='EquakeLastweek' action='EquakeLastWeek' />"
                  "<menuitem name='EquakeProperties' action='EquakeProperties' />"
                  "<menuitem name='EquakeAbout' action='EquakeAbout' />";

static const GtkActionEntry equake_menu_actions [] = {
  {"EquakeUpdate", GTK_STOCK_REFRESH, ("_Update"), NULL, NULL, G_CALLBACK (do_update)},
  {"EquakeDetails", GTK_STOCK_INFO, ("_Details"), NULL, NULL, G_CALLBACK (load_details)},
  {"EquakeMap", GTK_STOCK_FIND, ("_Map"), NULL, NULL, G_CALLBACK (load_map)},
  {"EquakeDidyouFeelit", GTK_STOCK_FIND, ("_Did you _feel it"), NULL, NULL, G_CALLBACK (load_didyoufeelit)},
  {"EquakeLastHour", GTK_STOCK_INDEX, ("Last _hour"), NULL, NULL, G_CALLBACK (display_lasthour)},
  {"EquakeLastDay", GTK_STOCK_INDEX, ("Last day"), NULL, NULL, G_CALLBACK (display_lastday)},
  {"EquakeLastWeek", GTK_STOCK_INDEX, ("Last _week (slow)"), NULL, NULL, G_CALLBACK (display_lastweek)},
  {"EquakeProperties", GTK_STOCK_PREFERENCES, ("_Preferences"), NULL, NULL, G_CALLBACK (display_properties_dialog)},
  {"EquakeAbout", GTK_STOCK_ABOUT, ("_About"), NULL, NULL, G_CALLBACK (display_about_dialog)}
};

/*
 * for lack of a main() this pretty much is where we start
 * the function is registered by the macro below
 */
static gboolean equake_applet_fill(MatePanelApplet *applet, const gchar *iid, gpointer data)
{
  GtkWidget *label, *logo, *hbox, *event_box;
  GdkPixbuf *quake_logo;
  GtkActionGroup *equake_action_group;
  int retval;
  
  struct Equake_Data *equakedata=g_malloc0(sizeof(struct Equake_Data));
  /* 
   * we exit when this alloc returns NULL, since without this continuing the program is pointless
   * in other cases the program doesn't depend on the alloc succeeding right then and there
   * in all other cases the function returns when alloc returns NULL
   * although an exit() is may be preferred I suspect a real out of memory is so rare these days that a quick exit() is excessive
   */
  if(equakedata==NULL)
    exit(-1);

  /* get equake logo from included file equake_images.h in pixbuf format */
  quake_logo=gdk_pixbuf_new_from_inline(-1, equake_icon, FALSE, NULL);
  /* create logo widget */
  logo=gtk_image_new_from_pixbuf(quake_logo);
  /* create eventbox, container and signal to deal with button presses on logo widget */
  event_box=gtk_event_box_new();
  gtk_container_add((GtkContainer *) event_box, logo);
  g_signal_connect(G_OBJECT (event_box), "button_press_event", G_CALLBACK (button_press_callback), logo);

  /* this is the initial value of the label text */
  label=gtk_label_new(LABELTXT);

  /* create a new hbox widget and pack the event_box and label in it */
#if GTK_CHECK_VERSION (3, 0, 0)
  hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
#else
  hbox=gtk_hbox_new(FALSE, 4);
#endif
  gtk_box_pack_start((GtkBox *) hbox, event_box, FALSE, FALSE, 0);
  gtk_box_pack_start((GtkBox *) hbox, label, FALSE, FALSE, 0);
  /* then add it to the applet container */
  gtk_container_add(GTK_CONTAINER(applet), hbox);

  gtk_widget_set_tooltip_text((GtkWidget *) event_box, BUTTONTXT);
  gtk_widget_set_tooltip_text((GtkWidget *) label, NODATA);

  gtk_widget_show_all(GTK_WIDGET(applet));

  equake_action_group=gtk_action_group_new("Equake Applet Actions");
  gtk_action_group_add_actions(equake_action_group, equake_menu_actions, G_N_ELEMENTS (equake_menu_actions), equakedata);

  mate_panel_applet_setup_menu(MATE_PANEL_APPLET (applet), ui, equake_action_group);
  g_object_unref(equake_action_group);
  
  retval=startequake(applet, label, logo, equakedata);

  return retval;
}

MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("MateEquakeAppletFactory", PANEL_TYPE_APPLET, "Mate Equake Applet", equake_applet_fill, NULL);


/*********************************************
 **** WE MERGED THIS WITH equake_applet.c ****
 *********************************************
 *
 * Program name:  equake
 * Version:	  1.03.8.1
 * Source file:	  equake_menu.c  
 * Description:	  Equake pulls data about earthquakes and displays it in interesting ways
 *
 * Copyright (C) 2016-2017 Jeroen van Aart
 *
 * 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.
 */

/* function to update applet after menu item "Update" has been selected */
static void do_update(GtkAction *action, struct Equake_Data *equakedata)
{
  /* lets refresh preferences, if user has changed it, we will now use the new values */
  equake_getprefs(equakedata);

  if (getquakedata(equakedata, HOURLY)>0)
    if (processdata(equakedata, HOURLY)==-1)
      perror("Failed to process data"); /* non fatal error, hopefully */
}

static void load_details(GtkAction *action, struct Equake_Data *equakedata)
{
  char url[URLSIZE];

  if (equakedata->posperiod==HOURLY)
  {
    if (equakedata->quake_history_count>=0)
    {
      if (equakedata->equakeformat[equakedata->pos].src!="")
	snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_ww, equakedata->equakeformat[equakedata->pos].eqid, QUAKEPATH_AF);
    }
    else
      display_dialog("No data available at this time");
    
    display_url(url);
  }
  else
  {
    if (equakedata->quake_history_countdaily>=0)
    {
      if (equakedata->equakeformatday[equakedata->pos].src!="")
        snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_ww, equakedata->equakeformatday[equakedata->pos].eqid, QUAKEPATH_AF);
    }
    else
      display_dialog("No data available at this time");

    display_url(url);
  }
}

static void load_map(GtkAction *action, struct Equake_Data *equakedata)
{
  char url[URLSIZE];

  if (equakedata->posperiod==HOURLY)
  {
    if (equakedata->quake_history_count>=0)
      snprintf(url, URLSIZE, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "http://", MAPURL0, equakedata->equakeformat[equakedata->pos].lat, MAPURL2, equakedata->equakeformat[equakedata->pos].lon, MAPURL2, "Earthquake Magnitude: ", equakedata->equakeformat[equakedata->pos].magnitude, " Region: ", equakedata->equakeformat[equakedata->pos].region, MAPURL2, "Rendered by equake applet", MAPURL2, WEBSITE);

    else
      display_dialog("No data available at this time");

    display_url(url);
  }
  else
  {
    if (equakedata->quake_history_countdaily>=0)
      snprintf(url, URLSIZE, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "http://", MAPURL0, equakedata->equakeformatday[equakedata->pos].lat, MAPURL2, equakedata->equakeformatday[equakedata->pos].lon, MAPURL2, "Earthquake Magnitude: ", equakedata->equakeformatday[equakedata->pos].magnitude, " Region: ", equakedata->equakeformatday[equakedata->pos].region, MAPURL2, "Rendered by equake applet", MAPURL2, WEBSITE);
    else
      display_dialog("No data available at this time");
  
    display_url(url);  
  }
}

static void load_didyoufeelit(GtkAction *action, struct Equake_Data *equakedata)
{
  char url[URLSIZE];

  if (equakedata->posperiod==HOURLY)
  {
    if (equakedata->quake_history_count>=0)
    {
      snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_dyfi_be, equakedata->equakeformat[equakedata->pos].eqid, equakedata->quakepath_dyfi_af);

      display_url(url);
    }
    else
      display_dialog("No data available at this time");
  }
  else
  {
    if (equakedata->quake_history_countdaily>=0)
    {
      snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_dyfi_be, equakedata->equakeformatday[equakedata->pos].eqid, equakedata->quakepath_dyfi_af);

      display_url(url);
    }
    else
      display_dialog("No data available at this time");
  }
}

/* we display a dialog to change preferences, because editing a text file is soo difficult */
static void display_properties_dialog(GtkAction *action, struct Equake_Data *equakedata)
{
  /* destroy dialog if it currently exists since we only want a maximum of one to exist */
  gtk_widget_hide(equakedata->prefsdialog);
  gtk_widget_destroy(equakedata->prefsdialog);

  int polltime, willalert, alertheavy, sigfilemag, monitormag;
  FILE *fp;

  GtkWidget *polltime_select, *willalert_select, *alertheavy_select, *sigfilemag_select, *monitormag_select, *image_about;
  GtkWidget *labelpoll, *labelwillalert, *labelalertheavy, *labelsigfile, *labelmonitormag, *sep;

  equakedata->prefsdialog=gtk_dialog_new_with_buttons(PREFSWINDOW, NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, NULL);

#if GTK_CHECK_VERSION (3, 0, 0)
  sep=gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
#else
  sep=gtk_hseparator_new();
#endif
  labelpoll=gtk_label_new(PREFPOLLTEXT);
  labelwillalert=gtk_label_new(PREFALERTEXT);
  labelalertheavy=gtk_label_new(PREFALERTHEAVYTEXT);
  labelsigfile=gtk_label_new(PREFSIGFILETEXT);
  labelmonitormag=gtk_label_new(PREFMONITORMAGTEXT);

  image_about=gtk_image_new_from_pixbuf(equakedata->equake_about);

  polltime_select=gtk_combo_box_text_new();
  willalert_select=gtk_combo_box_text_new();
  alertheavy_select=gtk_combo_box_text_new();
  sigfilemag_select=gtk_combo_box_text_new();
  monitormag_select=gtk_combo_box_text_new();

  gtk_combo_box_set_title((GtkComboBox*)polltime_select, PREFPOLLTEXT);
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 0, "2");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 1, "3");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 2, "4");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 3, "5");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 4, "10");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 5, "15");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 6, "20");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)polltime_select, 7, "30");

  /* properties_index[] holds default or previous combo box indexes */
  gtk_combo_box_set_active((GtkComboBox*)polltime_select, equakedata->properties_index[0]);

  gtk_combo_box_text_insert_text((GtkComboBoxText*)willalert_select, 0, "No");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)willalert_select, 1, "Yes");

  gtk_combo_box_set_active((GtkComboBox*)willalert_select, equakedata->properties_index[1]);

  gtk_combo_box_text_insert_text((GtkComboBoxText*)alertheavy_select, 0, "3");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)alertheavy_select, 1, "4");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)alertheavy_select, 2, "5");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)alertheavy_select, 3, "6");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)alertheavy_select, 4, "7");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)alertheavy_select, 5, "8");

  gtk_combo_box_set_active((GtkComboBox*)alertheavy_select, equakedata->properties_index[2]);

  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 0, "0");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 1, "2");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 2, "3");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 3, "4");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 4, "5");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 5, "6");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 6, "7");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)sigfilemag_select, 7, "8");

  gtk_combo_box_set_active((GtkComboBox*)sigfilemag_select, equakedata->properties_index[3]);

  gtk_combo_box_text_insert_text((GtkComboBoxText*)monitormag_select, 0, "1");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)monitormag_select, 1, "2");
  gtk_combo_box_text_insert_text((GtkComboBoxText*)monitormag_select, 2, "3");

  gtk_combo_box_set_active((GtkComboBox*)monitormag_select, equakedata->properties_index[4]);


  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), image_about, TRUE, TRUE, 4);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), sep, TRUE, TRUE, 4);

  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), labelpoll, TRUE, FALSE, 4);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), polltime_select, TRUE, FALSE, 8);

  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), labelwillalert, TRUE, TRUE, 4);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), willalert_select, TRUE, TRUE, 8);

  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), labelalertheavy, TRUE, TRUE, 4);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), alertheavy_select, TRUE, TRUE, 8);

  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), labelsigfile, TRUE, TRUE, 4);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), sigfilemag_select, TRUE, TRUE, 8);

  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), labelmonitormag, TRUE, TRUE, 4);
  gtk_box_pack_start((GtkBox *) (GtkDialog *)gtk_dialog_get_content_area(equakedata->prefsdialog), monitormag_select, TRUE, TRUE, 8);


  /*gtk_widget_show_all(dialog);*/
  gtk_widget_show(image_about);
  gtk_widget_show(sep);

  gtk_widget_show(labelpoll);
  gtk_widget_show(polltime_select);

  gtk_widget_show(labelwillalert);
  gtk_widget_show(willalert_select);

  gtk_widget_show(labelalertheavy);
  gtk_widget_show(alertheavy_select);

  gtk_widget_show(labelsigfile);
  gtk_widget_show(sigfilemag_select);

  gtk_widget_show(labelmonitormag);
  gtk_widget_show(monitormag_select);


  while (1)
  {
    /* we enter a recursive loop to await dialog to return with user defined input */
    int result=gtk_dialog_run((GtkDialog*)equakedata->prefsdialog);

    switch (result)
    {
      case GTK_RESPONSE_OK:
        /* lets get the values the user chose */
        polltime=gtk_combo_box_get_active((GtkComboBox*)polltime_select);
        willalert=gtk_combo_box_get_active((GtkComboBox*)willalert_select);
        alertheavy=gtk_combo_box_get_active((GtkComboBox*)alertheavy_select);
        sigfilemag=gtk_combo_box_get_active((GtkComboBox*)sigfilemag_select);
        monitormag=gtk_combo_box_get_active((GtkComboBox*)monitormag_select);
        set_properties_from_dialog(polltime, willalert, alertheavy, sigfilemag, monitormag, equakedata);

        equakedata->properties_index[0]=polltime;
        equakedata->properties_index[1]=willalert;
        equakedata->properties_index[2]=alertheavy;
        equakedata->properties_index[3]=sigfilemag;
        equakedata->properties_index[4]=monitormag;

        /* save preferences */
        fp=fopen(equakedata->configfile, "w");
        equake_saveprefs(equakedata, fp);
        fclose(fp);
        gtk_widget_destroy(equakedata->prefsdialog);
        return;
        break;

      case GTK_RESPONSE_HELP:
        gtk_widget_hide(equakedata->prefsdialog);
        /* lets display some help text for preferences */
        display_dialog(PREFSTEXT);
        gtk_widget_show(equakedata->prefsdialog);
        break;

      default:
        gtk_widget_destroy(equakedata->prefsdialog);
        return;
    }
  }
  gtk_widget_destroy(equakedata->prefsdialog);
}

static void set_properties_from_dialog(int polltime, int willalert, int alertheavy, int sigfilemag, int monitormag, struct Equake_Data *equakedata)
{
  switch (polltime)
  {
    case 0:
      equakedata->poll_time=120; /* 2 minutes */
      break;
    case 1:
      equakedata->poll_time=180;
      break;
    case 2:
      equakedata->poll_time=240;
      break;
    case 3:
      equakedata->poll_time=300;
      break;
    case 4:
      equakedata->poll_time=600;
      break;
    case 5:
      equakedata->poll_time=900;
      break;
    case 6:
      equakedata->poll_time=1200;
      break;
    case 7:
      equakedata->poll_time=1800;
      break;
    default:
      equakedata->poll_time=300; /* 5 minutes will be the default */
      break;
  }

  switch (willalert)
  {
    case 0:
      equakedata->will_alert=0;
      break;
    default:
      equakedata->will_alert=1;
      break;
  }

  switch (alertheavy)
  {
    case 0:
      equakedata->alert_heavy=3;
      break;
    case 1:
      equakedata->alert_heavy=4;
      break;
    case 2:
      equakedata->alert_heavy=5;
      break;
    case 3:
      equakedata->alert_heavy=6;
      break;
    case 4:
      equakedata->alert_heavy=7;
      break;
    case 5:
      equakedata->alert_heavy=8;
      break;
    default:
      equakedata->alert_heavy=ALERTHEAVY;
      break;
  }

  switch (sigfilemag)
  {
    case 0:
      equakedata->sigfilemag=0;
      break;
    case 1:
      equakedata->sigfilemag=2;
      break;
    case 2:
      equakedata->sigfilemag=3;
      break;
    case 3:
      equakedata->sigfilemag=4;
      break;
    case 4:
      equakedata->sigfilemag=5;
      break;
    case 5:
      equakedata->sigfilemag=6;
      break;
    case 6:
      equakedata->sigfilemag=7;
      break;
    case 7:
      equakedata->sigfilemag=8;
      break;
    default:
      equakedata->sigfilemag=SIGFILEMAG;
      break;
  }

  switch (monitormag)
  {
    case 1:
      equakedata->monitormag=2;
      break;
    case 2:
      equakedata->monitormag=3;
      break;
    default:
      equakedata->monitormag=MONITORMAG;
      break;
  }
}

static void display_about_dialog(GtkAction *action, struct Equake_Data *equakedata)
{
  GtkWidget *about;
  static const gchar *auth[]={AUTHOR, NULL};

  about=gtk_about_dialog_new();
  if(about!=NULL)
  {
    gtk_about_dialog_set_logo((GtkAboutDialog*)about, equakedata->equake_about);
    gtk_about_dialog_set_version((GtkAboutDialog*)about,VERSION);
    gtk_about_dialog_set_copyright((GtkAboutDialog*)about,COPYRIGHT);
    gtk_about_dialog_set_comments((GtkAboutDialog*)about,COMMENTS);
    gtk_about_dialog_set_license((GtkAboutDialog*)about,LICENSE);
    gtk_about_dialog_set_website((GtkAboutDialog*)about,WEBSITE);
    gtk_about_dialog_set_website_label((GtkAboutDialog*)about,WEBSITELABEL);
    gtk_about_dialog_set_authors((GtkAboutDialog*)about, auth);

    g_signal_connect_swapped(about, "response", G_CALLBACK (gtk_widget_destroy), about);
    gtk_widget_show_all((GtkWidget*)about);
  }
}

/* 
 * displays last hour/day/week, will first load data for last hour/day/week
 * then just runs display_lasthour/day/week to display it in a dialog
 */
static void display_lastweek(GtkAction *action, struct Equake_Data *equakedata)
{
  if (getquakedata(equakedata, WEEKLY)>0)
  {
    if (processdata(equakedata, WEEKLY)==-1)
    {
      perror("Failed to process data"); /* non fatal error, hopefully */
      display_dialog("No data available at this time");
      return;
    }
    display_lastperiod(action, equakedata, WEEKLY);
  }
}

static void display_lastday(GtkAction *action, struct Equake_Data *equakedata)
{
  if (getquakedata(equakedata, DAILY)>0)
  {
    if (processdata(equakedata, DAILY)==-1)
    {
      perror("Failed to process data"); /* non fatal error, hopefully */
      display_dialog("No data available at this time");
      return;
    }
    display_lastperiod(action, equakedata, DAILY);
  }
}

static void display_lasthour(GtkAction *action, struct Equake_Data *equakedata)
{
  if (getquakedata(equakedata, HOURLY)>0)
  {
    if (processdata(equakedata, HOURLY)==-1)
    {
      perror("Failed to process data"); /* non fatal error, hopefully */
      display_dialog("No data available at this time");
      return;
    }
    display_lastperiod(action, equakedata, HOURLY);
  }
}

/*
 * fill text to be display in window depending on the period
 * such as hourly or daily, hourly is the default 
 */
static void fill_text_period(struct Equake_Data *equakedata, char *running, char *periodtext, int period)
{
  int n;
  char url[URLSIZE], mapurl[URLSIZE];
  double mag;

  if (period==DAILY)
  {
    for (n=0;n<=equakedata->quake_history_countdaily;n++)
    {
      /* create url to be displayed */
      snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_ww, equakedata->equakeformatday[n].eqid, QUAKEPATH_AF);
      /* create map url */
      snprintf(mapurl, URLSIZE, "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", equakedata->portname, MAPURL1, equakedata->equakeformatday[n].lat, MAPURL2, equakedata->equakeformatday[n].lon, MAPURL2, "Earthquake Magnitude: ", equakedata->equakeformatday[n].magnitude, " Region: ", equakedata->equakeformatday[n].region, MAPURL2, "Rendered by equake applet", MAPURL2, WEBSITE);
      
      /* convert magnitude to double */
      if(equakedata->equakeformatday[n].magnitude!=NULL)
        mag=atof(equakedata->equakeformatday[n].magnitude);
      else
	mag=0;

      /* if magnitude is bigger or equal to DAILYHEAVY make magnitude bold */
      if (mag>=DAILYHEAVY)
          snprintf(running, strlen(equakedata->bufferdaily), "<b>Earthquake Magnitude: %s\nDate: %s\nDate Local: %s\nLocation: %s\nLatitude: %s; Longitude: %s\nDepth: %s km\nurl: <a href=\"%s\" title=\"%s\">%s</a>\n<a href=\"%s\" title=\"Detailed Map %s\">Detailed Map %s</a></b>\n\n", equakedata->equakeformatday[n].magnitude, equakedata->equakeformatday[n].datetime, equakedata->equakeformatday[n].datetime_local, equakedata->equakeformatday[n].region, equakedata->equakeformatday[n].lat, equakedata->equakeformatday[n].lon, equakedata->equakeformatday[n].depth, url, url, url, mapurl, equakedata->equakeformatday[n].region, equakedata->equakeformatday[n].region);
      else
        snprintf(running, strlen(equakedata->bufferdaily), "Earthquake Magnitude: %s\nDate: %s\nDate Local: %s\nLocation: %s\nLatitude: %s; Longitude: %s\nDepth: %s km\nurl: <a href=\"%s\" title=\"%s\">%s</a>\n<a href=\"%s\" title=\"Detailed Map %s\">Detailed Map %s</a>\n\n", equakedata->equakeformatday[n].magnitude, equakedata->equakeformatday[n].datetime, equakedata->equakeformatday[n].datetime_local, equakedata->equakeformatday[n].region, equakedata->equakeformatday[n].lat, equakedata->equakeformatday[n].lon, equakedata->equakeformatday[n].depth, url, url, url, mapurl, equakedata->equakeformatday[n].region, equakedata->equakeformatday[n].region);
     
      strncat(periodtext, running, strlen(running));
    }
  } 
  else
  {
    if (period==WEEKLY)
    {
      for (n=0;n<=equakedata->quake_history_countweekly;n++)
      {
        /* create url to be displayed */
        snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_ww, equakedata->equakeformatweek[n].eqid, QUAKEPATH_AF);
        /* create map url */
	snprintf(mapurl, URLSIZE, "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", equakedata->portname, MAPURL1, equakedata->equakeformatweek[n].lat, MAPURL2, equakedata->equakeformatweek[n].lon, MAPURL2, "Earthquake Magnitude: ", equakedata->equakeformatweek[n].magnitude, " Region: ", equakedata->equakeformatweek[n].region, MAPURL2, "Rendered by equake applet", MAPURL2, WEBSITE);

        /* convert magnitude to double */
        if(equakedata->equakeformatweek[n].magnitude!=NULL)
          mag=atof(equakedata->equakeformatweek[n].magnitude);
        else
	  mag=0;

        /* if magnitude is bigger or equal to DAILYHEAVY make magnitude bold */
        if (mag>=DAILYHEAVY)
          snprintf(running, strlen(equakedata->bufferweekly), "<b>Earthquake Magnitude: %s\nDate: %s\nDate Local: %s\nLocation: %s\nLatitude: %s; Longitude: %s\nDepth: %s km\nurl: <a href=\"%s\" title=\"%s\">%s</a>\n<a href=\"%s\" title=\"Detailed Map %s\">Detailed Map %s</a></b>\n\n", equakedata->equakeformatweek[n].magnitude, equakedata->equakeformatweek[n].datetime, equakedata->equakeformatweek[n].datetime_local, equakedata->equakeformatweek[n].region, equakedata->equakeformatweek[n].lat, equakedata->equakeformatweek[n].lon, equakedata->equakeformatweek[n].depth, url, url, url, mapurl, equakedata->equakeformatweek[n].region, equakedata->equakeformatweek[n].region);
        else
          snprintf(running, strlen(equakedata->bufferweekly), "Earthquake Magnitude: %s\nDate: %s\nDate Local: %s\nLocation: %s\nLatitude: %s; Longitude: %s\nDepth: %s km\nurl: <a href=\"%s\" title=\"%s\">%s</a>\n<a href=\"%s\" title=\"Detailed Map %s\">Detailed Map %s</a>\n\n", equakedata->equakeformatweek[n].magnitude, equakedata->equakeformatweek[n].datetime, equakedata->equakeformatweek[n].datetime_local, equakedata->equakeformatweek[n].region, equakedata->equakeformatweek[n].lat, equakedata->equakeformatweek[n].lon, equakedata->equakeformatweek[n].depth, url, url, url, mapurl, equakedata->equakeformatweek[n].region, equakedata->equakeformatweek[n].region);

        strncat(periodtext, running, strlen(running));
      }
    }
    else
    {
      for (n=0;n<=equakedata->quake_history_count;n++)
      {
        /* create url to be displayed */
        snprintf(url, URLSIZE, "%s://%s%s%s%s", equakedata->portname, equakedata->quakeserver, equakedata->quakepath_ww, equakedata->equakeformat[n].eqid, QUAKEPATH_AF);
        /* create map url */
	snprintf(mapurl, URLSIZE, "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", equakedata->portname, MAPURL1, equakedata->equakeformat[n].lat, MAPURL2, equakedata->equakeformat[n].lon, MAPURL2, "Earthquake Magnitude: ", equakedata->equakeformat[n].magnitude, " Region: ", equakedata->equakeformat[n].region, MAPURL2, "Rendered by equake applet", MAPURL2, WEBSITE);
	
        /* convert magnitude to double */
        if(equakedata->equakeformat[n].magnitude!=NULL)
    	  mag=atof(equakedata->equakeformat[n].magnitude);
        else
  	  mag=0;

	/* if magnitude is bigger or equal to DAILYHEAVY make magnitude bold */
	if (mag>=DAILYHEAVY)
	  snprintf(running, strlen(equakedata->buffer), "<b>Earthquake Magnitude: %s\nDate: %s\nDate Local: %s\nLocation: %s\nLatitude: %s; Longitude: %s\nDepth: %s km\nurl: <a href=\"%s\" title=\"%s\">%s</a>\n<a href=\"%s\" title=\"Detailed Map %s\">Detailed Map %s</a></b>\n\n", equakedata->equakeformat[n].magnitude, equakedata->equakeformat[n].datetime, equakedata->equakeformat[n].datetime_local, equakedata->equakeformat[n].region, equakedata->equakeformat[n].lat, equakedata->equakeformat[n].lon, equakedata->equakeformat[n].depth, url, url, url, mapurl, equakedata->equakeformat[n].region, equakedata->equakeformat[n].region);
	else
	  snprintf(running, strlen(equakedata->buffer), "Earthquake Magnitude: %s\nDate: %s\nDate Local: %s\nLocation: %s\nLatitude: %s; Longitude: %s\nDepth: %s km\nurl: <a href=\"%s\" title=\"%s\">%s</a>\n<a href=\"%s\" title=\"Detailed Map %s\">Detailed Map %s</a>\n\n", equakedata->equakeformat[n].magnitude, equakedata->equakeformat[n].datetime, equakedata->equakeformat[n].datetime_local, equakedata->equakeformat[n].region, equakedata->equakeformat[n].lat, equakedata->equakeformat[n].lon, equakedata->equakeformat[n].depth, url, url, url, mapurl, equakedata->equakeformat[n].region, equakedata->equakeformat[n].region);
       
        strncat(periodtext, running, strlen(running));
      }
    }
  }
}

static void display_period_window(char *text, int period)
{
  int screenheight;
  GtkWidget *scrolled_window, *window, *label, *button;
  GdkScreen *screen;

  /* get screen height */
  screen=gdk_screen_get_default();
  screenheight=gdk_screen_get_height(screen);

  /* allocate memory for the GtkRequisition funtion below */
  GtkRequisition *requisition=alloca(sizeof(GtkRequisition));
  if (requisition==NULL)
    return;
 
  /*
   * we're creating a window in which we place a scrolled window with a label
   * the label displays the text, since the text can at times be long it makes sense
   * to use a scrolled window, using a label allows us to use clickable urls
   */

  /* create the window */
  window=gtk_dialog_new();
  
  if (period==DAILY)
    gtk_window_set_title((GtkWindow *)window, RECDAYTXT);
  else if (period==WEEKLY)
    gtk_window_set_title((GtkWindow *)window, RECWEEKTXT);
  else
    gtk_window_set_title((GtkWindow *)window, RECHOURTXT);

  gtk_container_set_border_width((GtkContainer *)window, 0);

  /* scrolled window */
  scrolled_window=gtk_scrolled_window_new(NULL,NULL);
  gtk_container_set_border_width((GtkContainer *)scrolled_window, 10);
  gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)scrolled_window, GTK_SHADOW_IN);
  gtk_scrolled_window_set_policy((GtkScrolledWindow *)scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_box_pack_start((GtkBox *) (GtkDialog *) (gtk_dialog_get_content_area(window)), scrolled_window, TRUE, TRUE, 0);
  gtk_widget_show(scrolled_window);

  /* label */
  label=gtk_label_new(text);
  gtk_label_set_use_markup((GtkLabel *)label, TRUE);
  
  gtk_label_set_selectable((GtkLabel *)label, TRUE);
  gtk_label_set_line_wrap((GtkLabel *)label, FALSE);
  gtk_container_add((GtkContainer *)scrolled_window, label);
  gtk_widget_show(label);

  button=gtk_dialog_add_button((GtkDialog *)window, "close", GTK_RESPONSE_CLOSE);
  /*button=gtk_button_new_with_label("close");*/
  g_signal_connect_swapped(button, "response", (GCallback *)gtk_widget_destroy, window);

  /* this makes it so the button is the default. */
  gtk_widget_set_can_default(button, TRUE);
  /*gtk_box_pack_start(GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);*/
  /*gtk_box_pack_start(GTK_BOX (GTK_DIALOG (gtk_dialog_get_action_area(window))), button, TRUE, TRUE, 0);*/
  
  /* This grabs this button to be the default button. Simply hitting
   * the "Enter" key will cause this button to activate. */
  gtk_widget_grab_default(button);
  gtk_widget_show(button);

  /*gtk_widget_size_request(label, requisition);*/
  gtk_widget_get_preferred_size(label, NULL, requisition);

  /* make window not larger than screen height and keep 50 pixels headroom in case of larger/multiple panels */
  if (period!=HOURLY)
    gtk_widget_set_size_request(window, requisition->width+60, screenheight-100);
  else if ((requisition->height+100)<(screenheight-100))
    gtk_widget_set_size_request(window, requisition->width+60, requisition->height+100);
  else
    gtk_widget_set_size_request(window, requisition->width+60, screenheight-100);
  
  gtk_widget_show(window);
  gtk_dialog_run((GtkDialog*)window);
  gtk_widget_destroy(window);
  /*gtk_main();*/
}

static void display_lastperiod(GtkAction *action, struct Equake_Data *equakedata, int period)
{
  /* 
    allocate memory depending on the period, hourly is default
    possibly TODO: only allocate memory depending on period, however code which did this crashed with period==WEEKLY 
    inside loop of fill_text_period(), allocating memory all at once here does not make it crash
  */
  char *lastday=alloca(sizeof(equakedata->bufferdaily)+1); /* there's not more memory needed than what's in the buffer and normally much less */
  if (lastday==NULL)
    return;
  char *runningday=alloca(sizeof(equakedata->bufferdaily)+1);
  if (runningday==NULL)
    return;

  char *lastweek=alloca(sizeof(equakedata->bufferweekly)+1);
  if (lastweek==NULL)
    return;
  char *runningweek=alloca(sizeof(equakedata->bufferweekly)+1);
  if (runningweek==NULL)
    return;

  memset(lastday, 0, sizeof(lastday));
  memset(runningday, 0, sizeof(runningday));
  memset(lastweek, 0, sizeof(lastweek));
  memset(runningweek, 0, sizeof(runningweek));

  char *lasthour=alloca(sizeof(equakedata->buffer)+1); /* there's not more memory needed than what's in the buffer and normally much less */
  if (lasthour==NULL)
    return;
  char *running=alloca(sizeof(equakedata->buffer)+1);
  if (running==NULL)
    return;

  memset(lasthour, 0, sizeof(lasthour));
  memset(running, 0, sizeof(running));

  if ((period==DAILY) && (equakedata->quake_history_countdaily<0))
  {
    display_dialog("No data available at this time");
    return;
  }
  else
  {
    if ((period==WEEKLY) && (equakedata->quake_history_countweekly<0))
    {
      display_dialog("No data available at this time");
      return;
    }
    else
    {
      if ((period!=WEEKLY) && (period!=DAILY) && (equakedata->quake_history_count<0))
      {
        display_dialog("No data available at this time");
        return;
      }
    }
  }

  if (period==DAILY)
  {
    fill_text_period(equakedata, runningday, lastday, period);
    display_period_window(lastday, period);
  }
  else
  {
    if (period==WEEKLY)
    {
      fill_text_period(equakedata, runningweek, lastweek, period);
      display_period_window(lastweek, period);
    }
    else
    {
      fill_text_period(equakedata, running, lasthour, period);
      display_period_window(lasthour, period);
    }
  }
}

static void display_dialog(char *t)
{
  GtkWidget *dialog;

  dialog=gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", t);
  if(dialog)
  {
    gtk_dialog_run(GTK_DIALOG (dialog));
    gtk_widget_destroy(dialog);
  }

}

/*
 * copied from http://git.xfce.org/xfce/libxfce4ui/tree/libxfce4ui/xfce-dialogs.c#n66
 * and slightly adapted
 * we'll use this as a somewhat failsafe way to try to open a web browser
 */
static void display_url(char *url)
{
  GError *error=NULL;
  gchar *path;
  gchar *cmd;
  gboolean result=FALSE;

  path=g_find_program_in_path("exo-open");
  if (G_LIKELY(path!=NULL))
  {
    cmd=g_strdup_printf("%s --launch WebBrowser '%s'", path, url);

    result=g_spawn_command_line_async(cmd, NULL);

    g_free (path);
    g_free (cmd);
  }
  else
  {
    /* 
     * not very likely to happen, but it is possible exo is not installed 
     * this may fail if gvfs is not present, which is likely when gnome was not installed or is not running
     */
    result=gtk_show_uri(NULL, url, gtk_get_current_event_time (), &error);
  }

  if (!result)
  {
    display_dialog(NOBROWSER);
    g_error_free(error);
  }
}
