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

pan.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2002  Charles Kerr <charles@rebelbase.com>
 *
 * 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; version 2 of the License.
 *
 * 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 <config.h>

#include <string.h>

#include <glib.h>
#include <gtk/gtk.h>

#include <locale.h>

#if defined (HAVE_LIBGTKSPELL)
#include <gtkspell/gtkspell.h>
#endif
#include <gnet.h>

#include <pan/base/acache.h>
#include <pan/base/debug.h>
#include <pan/base/log.h>
#include <pan/base/newsrc-port.h>
#include <pan/base/pan-config.h>
#include <pan/base/pan-i18n.h>
#include <pan/base/serverlist.h>
#include <pan/base/util-file.h>
#include <pan/filters/filter-manager.h>
#include <pan/rules/rule-manager.h>
#include <pan/identities/identity-manager.h>
#include <pan/dialogs/dialogs.h>

#include <gmime/gmime.h>

#include <pan/flagset.h>
#include <pan/group-action.h>
#include <pan/globals.h>
#include <pan/gui.h>
#include <pan/pan.h>
#include <pan/prefs.h>
#include <pan/queue.h>
#include <pan/task-xml.h>
#include <pan/util.h>

extern char *
bind_textdomain_codeset (const char * domainname,
                         const char * codeset);

static int
restore_tasks_dialog (gpointer filename_gpointer);


#ifdef GNOME
/***
****   Session management
***/

/*
** save_session
** saves the current session for later revival
*/
static gint
save_session (GnomeClient         * client,
              gint                  phase,
              GnomeSaveStyle        save_style,
              gint                  is_shutdown,
              GnomeInteractStyle    interact_style,
              gint                  is_fast,
              gpointer              client_data)
{
      gchar **argv;
      guint argc;

      argv = g_new0 (gchar*, 4);
      argc = 1;

      argv[0] = client_data;
      /* add any addtional state info here. */
      gnome_client_set_clone_command (client, argc, argv);
      gnome_client_set_restart_command (client, argc, argv);
      return TRUE;
}

/**
*** session_die: Gracefullly end the session
**/
static void
session_die (GnomeClient *    client,
             gpointer         client_data)
{
      pan_shutdown ();
}
#endif

static void
show_help (void)
{
      GString * str = g_string_new (NULL);
      g_string_append_c (str, '\n');
      g_string_append_printf (str, "Pan %s\n\n", VERSION);
      g_string_append_printf (str, "%s\n", _("  --version        Prints Pan's version number"));
      g_string_append_printf (str, "%s\n", _("  --help           Prints this message and exits"));
      g_string_append_printf (str, "%s\n", _("  --debug          Turns on the most commonly-used options for a bug report"));
      g_string_append_c (str, '\n');
      g_string_append_printf (str, "%s\n", _("  --mute           Debugging tool to send new posts to console, not the server"));
      g_string_append_printf (str, "%s\n", _("  --debug-cache    Print debugging messages for the article cache"));
      g_string_append_printf (str, "%s\n", _("  --debug-sockets  Print debugging messages when talking to the news server"));
      g_string_append_printf (str, "%s\n", _("  --debug-queue    Print debugging messages related to managing tasks"));
      g_string_append_printf (str, "%s\n", _("  --debug-decode   Print debugging messages related to decoding attachments"));
      g_string_append_printf (str, "%s\n", _("  --debug-newsrc   Print debugging messages related to .newsrc files"));
      g_string_append_printf (str, "%s\n", _("  --debug-gnksa    Print debugging messages related to gnksa correctness"));
      g_string_append_printf (str, "%s\n", _("  --debug-trace    Print debugging messages when entering/leaving functions"));
      g_string_append_printf (str, "%s\n", _("  --debug-lock     Print debugging messages related to threaded gui locks"));
      g_string_append_printf (str, "%s\n", _("  --debug-object   Print debugging messages related to refcounted objects"));
      g_string_append_c (str, '\n');
      fprintf (stderr, "%s", str->str);
      g_string_free (str, TRUE);
}

const char* sockread_err_msg = NULL;
const char* sockwrite_err_msg = NULL;

/**
***  Message Logging
**/

static void
log_error_breakpoint (void)
{
      /* this is handy for setting a gdb breakpoint */
}

static void
my_log_handler (const char       * log_domain,
                GLogLevelFlags     log_level,
                const char       * message,
                gpointer           user_data)
{
      LogSeverity severity;

      /* determine the severity to use */
      severity  = LOG_INFO;
      if (log_level & (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR)) {
            log_error_breakpoint ();
            severity = LOG_ERROR;
            if (severity & G_LOG_LEVEL_ERROR)
                  severity |= LOG_URGENT;
      }

      /* add it to the pan log */
      log_add_va (severity, "%s - %s",
            (log_domain ? log_domain : "(Null)"),
            (message ? message : "(Null)"));

#if !defined(G_OS_WIN32)
      fprintf (stderr, "%s - %s\n",
            (log_domain ? log_domain : "(Null)"),
            (message ? message : "(Null)"));
#endif
}

/**
***
**/

PanApp Pan;

int
main (int argc, char *argv[])
{
      int i;
      gulong debug_flags = 0;
      gboolean mute = FALSE;
      const char * log_sources[] = {
            "GLib",
            "GLib-GObject",
            "Gtk",
            "pan",
            "Pan.exe",
            NULL
      };

      /* init the text domain & codeset,
         then force all of the locale segments to update from the
         environment.  Unless we do this they will all default to C. */
      bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
      textdomain (GETTEXT_PACKAGE);
      setlocale (LC_ALL, "");

      /* set some globals */
      sockread_err_msg = _("Error reading from socket.");
      sockwrite_err_msg = _("Error writing to socket.");
      PAN_SENT = pstring_shallow (_("pan.sent"), -1);
      PAN_SENDLATER = pstring_shallow (_("pan.sendlater"), -1);

      /* parse arguments  */
      mute = FALSE;
      debug_flags = 0;
      for (i=0; i<argc; ++i)
      {
            const char * arg = argv[i];

            if (!strcmp(arg,"--mute"))
                  mute = TRUE;
            else if (!strcmp (arg, "--debug-cache"))
                  debug_flags |= DEBUG_ACACHE;
            else if (!strcmp (arg, "--debug-socket-input"))
                  debug_flags |= DEBUG_SOCKET_INPUT;
            else if (!strcmp (arg, "--debug-socket-output"))
                  debug_flags |= DEBUG_SOCKET_OUTPUT;
            else if (!strcmp (arg, "--debug-socket"))
                  debug_flags |= DEBUG_SOCKET_INPUT|DEBUG_SOCKET_OUTPUT;
            else if (!strcmp (arg, "--debug-sockets"))
                  debug_flags |= DEBUG_SOCKET_INPUT|DEBUG_SOCKET_OUTPUT;
            else if (!strcmp (arg, "--debug-queue"))
                  debug_flags |= DEBUG_QUEUE;
            else if (!strcmp (arg, "--debug-decode"))
                  debug_flags |= DEBUG_DECODE;
            else if (!strcmp (arg, "--debug-newsrc"))
                  debug_flags |= DEBUG_NEWSRC;
            else if (!strcmp (arg, "--debug-gnksa"))
                  debug_flags |= DEBUG_GNKSA;
            else if (!strcmp (arg, "--debug-trace"))
                  debug_flags |= DEBUG_TRACE;
            else if (!strcmp (arg, "--debug-lock"))
                  debug_flags |= DEBUG_LOCK;
            else if (!strcmp (arg, "--debug-object"))
                  debug_flags |= DEBUG_PAN_OBJECT;
            else if (!strcmp (arg, "--debug"))
                  debug_flags |= DEBUG_TRACE|DEBUG_DECODE|DEBUG_ACACHE|DEBUG_SOCKET_INPUT|DEBUG_SOCKET_OUTPUT;
            else if (!strcmp (arg, "--version")) {
                  printf ("Pan %s\n", VERSION);
                  return 0;
            }
            else if (!strcmp (arg, "--help") || !strcmp(arg, "-help")) {
                  show_help ();
                  return 0;
            }
      }
      set_debug_level (debug_flags);

      /* init gtk */
      g_set_prgname ("Pan");
      g_thread_init (NULL);
      gnet_init ();
      gdk_threads_init ();
      gtk_init (&argc, &argv);
      g_mime_init (GMIME_INIT_FLAG_UTF8);

      /* route log messages to Pan's log viewer */
      for (i=0; i<G_N_ELEMENTS(log_sources); ++i)
            g_log_set_handler (log_sources[i], G_LOG_LEVEL_MASK,
                               my_log_handler, NULL);

      log_add_va (LOG_INFO, _("Pan %s Started"), VERSION);

      cmap = gdk_colormap_get_system ();
      flagset_init ();
      prefs_init ();
      serverlist_init ();
      filter_manager_init ();
#ifdef HAVE_LIBGTKSPELL
      if (do_spellcheck) {
            const int status = gtkspell_init ();
            do_spellcheck = status >= 0;
            if (!do_spellcheck)
                  log_add_va (LOG_ERROR,
                              _("Spellchecking disabled: gtkspell_init() failed with status %d"),
                              status);
      }
#endif

      /* Connect up to the session manager */
#ifdef GNOME
      if (1) {
            GnomeClient * client = gnome_master_client ();
            g_signal_connect (client, "save_yourself",
                              G_CALLBACK(save_session), argv[0]);
            g_signal_connect (client, "die",
                              G_CALLBACK(session_die), NULL);
      }
#endif

      /* initialize variables in the global app structure */
      Pan.main_t = g_thread_self ();
      pan_mute = mute;
      if (pan_mute)
            g_message ("Running in mute mode: messages will be sent to "
                       "stdout instead of smtp/nntp server");

      queue_init (TRUE, pan_config_get_bool (KEY_REMOVE_FAILED_TASKS, DEFAULT_VALUE_REMOVE_FAILED_TASKS));

      /* if it's a new user, pop up the newuser dialog.
         Otherwise show the main window. */

      if (identity_manager_count () == 0)
      {
            dialog_newuser ();
      }
      else
      {
            gui_construct (NULL);
            gtk_widget_show_all (Pan.window);
      }

      /* Maybe we need to requeue old tasks from the last session.
       * If so, rename the old tasks.xml file so that other startup
       * tasks don't change tasks.xml before we get to it. #111307 */
      if (1) {
            char * tasks_filename = queue_get_tasks_filename ();
            if (g_file_test (tasks_filename, G_FILE_TEST_EXISTS)) {
                  char * scratch_filename = g_strdup_printf ("%s.old", tasks_filename);
                  pan_file_rename (tasks_filename, scratch_filename);
                  gui_queue_add (restore_tasks_dialog, scratch_filename);
            }
            g_free (tasks_filename);
      }

      if (fetch_new_and_bodies_on_startup)
            group_action_subscribed_download_new_and_bodies ();
      else if (fetch_new_on_startup)
            group_action_subscribed_download_new ();

      gdk_threads_enter();
      gtk_main ();
      gdk_threads_leave();

      return 0;
}

/**
 * pan_shutdown:
 *
 * Shutdown Pan, closing all TCP connections and saving all preferences
 **/
void
pan_shutdown (void)
{
      queue_shutdown ();

      pan_config_sync ();
      identity_manager_shutdown_module ();
      serverlist_shutdown ();
      acache_shutdown ();
      rule_manager_shutdown_module ();
      log_shutdown_module ();

      gtk_main_quit ();
}

/***
****
****
***/

static void
restore_tasks_dialog_response_cb (GtkDialog * dialog, int response, gpointer user_data)
{
      char * filename = (char*) user_data;

      if (response == GTK_RESPONSE_ACCEPT)
      {
            GPtrArray * tasks = g_ptr_array_new ();
            task_xml_read (filename, tasks);
            if (tasks->len)
            {
                  guint i;
                  GSList * l = NULL;
                  for (i=0; i<tasks->len; ++i)
                        l = g_slist_prepend (l, g_ptr_array_index(tasks,i));
                  l = g_slist_reverse (l);
                  queue_insert_tasks (l, -1);
                  log_add_va (LOG_INFO, _("Restored %d tasks from last session"), (int)tasks->len);
            }
            g_ptr_array_free (tasks, TRUE);
      }

      unlink (filename);
      g_free (filename);
      gtk_widget_destroy (GTK_WIDGET(dialog));
}

static int
restore_tasks_dialog (gpointer filename_gpointer)
{
      GtkWidget * w;
      GtkWidget *label, *image, *button, *hbox, *align;
      char * filename = (char*) filename_gpointer;

      pan_lock ();
      w = gtk_message_dialog_new (GTK_WINDOW(Pan.window),
                                  GTK_DIALOG_DESTROY_WITH_PARENT,
                                  GTK_MESSAGE_QUESTION,
                                  GTK_BUTTONS_NONE,
                            _("Some tasks were still queued the last time Pan exited.  Do you want to resume those tasks?"));
      gtk_dialog_add_buttons (GTK_DIALOG(w),
                              GTK_STOCK_NO, GTK_RESPONSE_REJECT,
                              NULL);

      /* use the revert icon, but "resume" is a better word to use here */
      button = gtk_button_new ();
      label = gtk_label_new_with_mnemonic (_("_Resume"));
      gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
      image = gtk_image_new_from_stock (GTK_STOCK_REVERT_TO_SAVED, GTK_ICON_SIZE_BUTTON);
      hbox = gtk_hbox_new (FALSE, 2);
      align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
      gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
      gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
      gtk_container_add (GTK_CONTAINER (button), align);
      gtk_container_add (GTK_CONTAINER (align), hbox);
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
      gtk_dialog_add_action_widget (GTK_DIALOG(w), button, GTK_RESPONSE_ACCEPT);
      gtk_dialog_set_default_response (GTK_DIALOG(w), GTK_RESPONSE_ACCEPT);
      gtk_widget_grab_focus (button);

      g_signal_connect (w, "response", G_CALLBACK(restore_tasks_dialog_response_cb), filename);

      gtk_widget_show_all (w);
      pan_unlock ();

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index