[pan2/download-meter] bla



commit b29259cb810797b84c74d56938dc59dfc6559d41
Author: Heinrich MÃller <henmull src gnome org>
Date:   Tue Sep 25 17:48:05 2012 +0200

    bla

 pan/gui/dl-prefs.cc        |  198 +++++++++++++++++++++++++++
 pan/gui/dl-prefs.h         |   58 ++++++++
 pan/gui/download-meter.h   |   87 ++++++++++++
 pan/tasks/xzver-decoder.cc |  325 ++++++++++++++++++++++++++++++++++++++++++++
 pan/tasks/xzver-decoder.h  |  102 ++++++++++++++
 5 files changed, 770 insertions(+), 0 deletions(-)
---
diff --git a/pan/gui/dl-prefs.cc b/pan/gui/dl-prefs.cc
new file mode 100644
index 0000000..647c6c7
--- /dev/null
+++ b/pan/gui/dl-prefs.cc
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  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>
+extern "C" {
+  #include <glib/gi18n.h>
+  #include "gtk-compat.h"
+}
+#include <pan/general/debug.h>
+#include <pan/general/macros.h>
+#include <pan/icons/pan-pixbufs.h>
+#include "hig.h"
+#include "pad.h"
+#include "pan-file-entry.h"
+#include "dl-prefs.h"
+#include "url.h"
+#include "gtk-compat.h"
+
+using namespace pan;
+
+namespace pan
+{
+
+  namespace
+  {
+    #define PREFS_KEY "prefs-key"
+    #define PREFS_VAL "prefs-val"
+
+    void toggled_cb (GtkToggleButton * toggle, gpointer prefs_gpointer)
+    {
+      const char * key = (const char*) g_object_get_data (G_OBJECT(toggle), PREFS_KEY);
+      if (key)
+        static_cast<Prefs*>(prefs_gpointer)->set_flag (key, gtk_toggle_button_get_active(toggle));
+    }
+
+
+
+    GtkWidget* new_check_button (const char* mnemonic, const char* key, bool fallback, Prefs& prefs)
+    {
+      GtkWidget * t = gtk_check_button_new_with_mnemonic (mnemonic);
+      g_object_set_data_full (G_OBJECT(t), PREFS_KEY, g_strdup(key), g_free);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(t), prefs.get_flag (key, fallback));
+      g_signal_connect (t, "toggled", G_CALLBACK(toggled_cb), &prefs);
+      return t;
+    }
+
+    void response_cb (GtkDialog * dialog, int, gpointer)
+    {
+      gtk_widget_destroy (GTK_WIDGET(dialog));
+    }
+
+    void delete_dialog (gpointer castme)
+    {
+      DLMeterDialog* meterdialog(static_cast<DLMeterDialog*>(castme));
+      const bool enabled (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(meterdialog->get_enable())));
+      meterdialog->meter().set_enabled(enabled);
+
+      delete meterdialog;
+    }
+
+    void spin_value_changed_cb( GtkSpinButton *spin, gpointer data)
+    {
+      const char * key = (const char*) g_object_get_data (G_OBJECT(spin), PREFS_KEY);
+      Prefs *prefs = static_cast<Prefs*>(data);
+      prefs->set_int(key, gtk_spin_button_get_value_as_int(spin));
+    }
+
+    GtkWidget* new_spin_button (const char *key, int low, int high, Prefs &prefs)
+    {
+      guint tm = prefs.get_int(key, 5 );
+      GtkAdjustment *adj = (GtkAdjustment*) gtk_adjustment_new(tm, low, high, 1.0, 1.0, 0.0);
+      GtkWidget *w = gtk_spin_button_new( adj, 1.0, 0);
+      g_object_set_data_full(G_OBJECT(w), PREFS_KEY, g_strdup(key), g_free);
+      g_signal_connect (w, "value_changed", G_CALLBACK(spin_value_changed_cb), &prefs);
+      return w;
+    }
+
+    void set_prefs_string_from_combobox (GtkComboBox * c, gpointer user_data)
+    {
+      Prefs * prefs (static_cast<Prefs*>(user_data));
+      const char * key = (const char*) g_object_get_data (G_OBJECT(c), PREFS_KEY);
+
+      const int column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(c), "column"));
+      const int row (gtk_combo_box_get_active (c));
+      GtkTreeModel * m = gtk_combo_box_get_model (c);
+      GtkTreeIter i;
+      if (gtk_tree_model_iter_nth_child (m, &i, 0, row)) {
+        char * val (0);
+        gtk_tree_model_get (m, &i, column, &val, -1);
+        prefs->set_string (key, val);
+        g_free (val);
+      }
+    }
+
+    GtkWidget* new_bytes_combo_box (Prefs& prefs,
+                                    const char * mode_key)
+      {
+
+        const char* strings[2][2] =
+        {
+          {N_("MB"), "mb"},
+          {N_("GB"), "gb"}
+        };
+
+        const std::string mode (prefs.get_string (mode_key, "mb"));
+        GtkListStore * store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+
+        int sel_index (0);
+        for (size_t i=0; i<G_N_ELEMENTS(strings); ++i) {
+          GtkTreeIter iter;
+          gtk_list_store_append (store, &iter);
+          gtk_list_store_set (store, &iter, 0, strings[i][0], 1, strings[i][1], -1);
+          if (mode == strings[i][1])
+            sel_index = i;
+        }
+
+        GtkWidget * c = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
+        GtkCellRenderer * renderer (gtk_cell_renderer_text_new ());
+        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (c), renderer, true);
+        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (c), renderer, "text", 0, NULL);
+        gtk_combo_box_set_active (GTK_COMBO_BOX(c), sel_index);
+        g_object_set_data_full (G_OBJECT(c), PREFS_KEY, g_strdup(mode_key), g_free);
+        g_object_set_data (G_OBJECT(c), "column", GINT_TO_POINTER(1));
+        g_signal_connect (c, "changed", G_CALLBACK(set_prefs_string_from_combobox), &prefs);
+
+        gtk_widget_show_all(c);
+
+        return c;
+      }
+
+      void reset_dl_limit_cb (GtkButton *, gpointer user_data)
+      {
+        DLMeterDialog* pd (static_cast<DLMeterDialog*>(user_data));
+        pd->meter().reset();
+      }
+  }
+
+  DLMeterDialog :: DLMeterDialog (Prefs& prefs, DownloadMeter& meter, GtkWindow* parent):
+    _prefs (prefs), _meter(meter)
+  {
+
+    GtkWidget * dialog = gtk_dialog_new_with_buttons (_("Pan: Download Meter Preferences"), parent,
+                                                      GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                                      NULL);
+    gtk_window_set_role (GTK_WINDOW(dialog), "pan-dl-preferences-dialog");
+    g_signal_connect (dialog, "response", G_CALLBACK(response_cb), this);
+    g_signal_connect_swapped (dialog, "destroy", G_CALLBACK(delete_dialog), this);
+
+    // Behavior
+    int row (0);
+    GtkWidget *h, *w, *l, *b, *t;
+    t = HIG :: workarea_create ();
+    HIG::workarea_add_section_title (t, &row, _("Download Limit reached"));
+
+      HIG :: workarea_add_section_spacer (t, row, 2);
+      w = _enable = new_check_button (_("Enable"), "dl-limit-enable", true, prefs);
+      HIG :: workarea_add_wide_control (t, &row, w);
+      w = new_check_button (_("Warn"), "warn-dl-limit-reached", true, prefs);
+      HIG :: workarea_add_wide_control (t, &row, w);
+      w = new_check_button (_("Disconnect from server"), "disconnect-on-dl-limit-reached", true, prefs);
+      HIG :: workarea_add_wide_control (t, &row, w);
+      w = new_spin_button ("dl-limit", 1, 1024, prefs);
+      HIG :: workarea_add_wide_control (t, &row, w);
+      w = new_bytes_combo_box(prefs, "dl-limit-type");
+      g_signal_connect (w, "changed", G_CALLBACK(reset_dl_limit_cb), this);
+      HIG :: workarea_add_wide_control (t, &row, w);
+      w = gtk_button_new_with_label (_("Reset"));
+      g_signal_connect (w, "clicked", G_CALLBACK(reset_dl_limit_cb), this);
+      HIG :: workarea_add_wide_control (t, &row, w);
+
+    HIG :: workarea_finish (t, &row);
+
+    gtk_widget_show_all(t);
+
+    gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area( GTK_DIALOG(dialog))), t, true, true, 0);
+
+    _root = dialog;
+
+  }
+
+}
diff --git a/pan/gui/dl-prefs.h b/pan/gui/dl-prefs.h
new file mode 100644
index 0000000..1068976
--- /dev/null
+++ b/pan/gui/dl-prefs.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  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
+ */
+
+#ifndef DL_PREFS_UI_H
+#define DL_PREFS_UI_H
+
+#include "gtk-compat.h"
+#include <pan/gui/prefs.h>
+#include <pan/gui/download-meter.h>
+
+namespace pan
+{
+
+  class DLMeterDialog
+  {
+
+    public:
+
+    public:
+      DLMeterDialog (Prefs&, DownloadMeter&, GtkWindow*) ;
+      ~DLMeterDialog () { }
+
+      Prefs& prefs () { return _prefs; }
+
+      DownloadMeter& meter () { return _meter; }
+
+      GtkWidget* root() { return _root; }
+
+      uint64_t get_limit () { return _meter.get_limit(); }
+
+      GtkWidget* get_enable () { return _enable; }
+
+    private:
+      Prefs& _prefs;
+      GtkWidget* _root;
+      DownloadMeter& _meter;
+      GtkWidget* _enable;
+
+  };
+}
+
+#endif
diff --git a/pan/gui/download-meter.h b/pan/gui/download-meter.h
new file mode 100644
index 0000000..8cb5281
--- /dev/null
+++ b/pan/gui/download-meter.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  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
+ */
+
+#ifndef _DOWNLOAD_METER_H_
+#define _DOWNLOAD_METER_H_
+
+#include <pan/gui/prefs.h>
+#include <pan/gui/progress-view.h>
+#include <pan/general/progress.h>
+#include <pan/data/data.h>
+
+namespace pan
+{
+
+  class DownloadMeter
+  {
+
+    public:
+
+      DownloadMeter (Prefs&, Data&);
+      virtual ~DownloadMeter() {}
+
+
+      void add (uint64_t bytes);
+      void reset ();
+      void set_enabled ( bool val) { _enabled = val; }
+
+      struct Listener {
+          Listener () {}
+          virtual ~Listener () {}
+          virtual void on_xfer_bytes (uint64_t&) {}
+          virtual void on_reset_xfer_bytes () {}
+        };
+
+    private:
+
+      typedef std::set<Listener*> listeners_t;
+      typedef DownloadMeter::listeners_t::const_iterator lit;
+      listeners_t _listeners;
+
+      uint64_t _val[5];// byte, kb, mb, gb, tb
+
+      ProgressView* _view;
+      Progress* _progress;
+      int _limit;
+      GtkWidget* _widget;
+      GtkWidget* _button;
+      bool _enabled;
+
+    public:
+
+      void add_listener (Listener * l)    { _listeners.insert(l); }
+      void remove_listener (Listener * l) { _listeners.erase(l);  }
+
+      ProgressView* get_view() { return _view; }
+
+      GtkWidget* get_widget () { return _widget; }
+
+      GtkWidget* get_button () { return _button; }
+
+      int get_limit() { return _limit; }
+      void set_limit (int& l) { _limit = l; }
+
+      virtual void fire_xfer_bytes (uint64_t bytes);
+
+      virtual void fire_reset_xfer_bytes ();
+
+  };
+
+}
+#endif
diff --git a/pan/tasks/xzver-decoder.cc b/pan/tasks/xzver-decoder.cc
new file mode 100644
index 0000000..9271501
--- /dev/null
+++ b/pan/tasks/xzver-decoder.cc
@@ -0,0 +1,325 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2007  Charles Kerr <charles rebelbase com>
+ *
+ * This file
+ * Copyright (C) 2007 Calin Culianu <calin ajvar org>
+ * Copyright (C) 2007 Charles Kerr <charles rebelbase com>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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 <config.h>
+#include <cerrno>
+#include <ostream>
+#include <fstream>
+extern "C" {
+#  define PROTOTYPES
+#  include <uulib/uudeview.h>
+#  include <glib/gi18n.h>
+};
+#include <pan/general/worker-pool.h>
+#include <pan/general/debug.h>
+#include <pan/general/file-util.h>
+#include <pan/general/macros.h>
+#include <pan/general/utf8-utils.h>
+#include "xzver-decoder.h"
+
+using namespace pan;
+
+/***
+****
+***/
+
+using namespace pan;
+
+XZVERDecoder :: XZVERDecoder (WorkerPool& pool) :
+  Decoder(pool)
+{
+  _cnt = 0;
+}
+
+XZVERDecoder :: ~XZVERDecoder()
+{
+  disable_progress_update();
+}
+
+void
+XZVERDecoder :: enqueue (TaskXOver  * task, TaskXOver::DataStream* stream, Data* data)
+{
+
+  _cnt = 0;
+
+  disable_progress_update ();
+
+  this->xtask = task;
+  this->stream = stream;
+  this->data = data;
+  this->nntp = new NNTP(stream->server, "", "", 0);
+  this->nntp->_group = stream->group;
+
+  log_infos.clear();
+  log_errors.clear();
+
+  // gentlemen, start your saving...
+  _worker_pool.push_work (this, task, false);
+}
+
+namespace
+{
+  char* build_cachename (char* buf, size_t len, const char* name)
+  {
+    const char * home(file::get_pan_home().c_str());
+    g_snprintf(buf,len,"%s%c%s%c%s",home, G_DIR_SEPARATOR, "encode-cache", G_DIR_SEPARATOR, name);
+    return buf;
+  }
+}
+
+namespace
+{
+  unsigned long view_to_ul (const StringView& view)
+  {
+    unsigned long ul = 0ul;
+
+    if (!view.empty()) {
+      errno = 0;
+      ul = strtoul (view.str, 0, 10);
+      if (errno)
+        ul = 0ul;
+    }
+
+    return ul;
+  }
+  uint64_t view_to_ull (const StringView& view)
+  {
+    uint64_t ul = 0ul;
+
+    if (!view.empty()) {
+      errno = 0;
+      ul = g_ascii_strtoull (view.str, 0, 10);
+      if (errno)
+        ul = 0ul;
+    }
+
+    return ul;
+  }
+
+  bool header_is_nonencoded_utf8 (const StringView& in)
+  {
+    const bool is_nonencoded (!in.strstr("=?"));
+    const bool is_utf8 (g_utf8_validate (in.str, in.len, 0));
+    return is_nonencoded && is_utf8;
+  }
+}
+
+void
+XZVERDecoder :: on_nntp_batch_process (StringView   & line)
+{
+  unsigned int lines=0u;
+  unsigned long bytes=0ul;
+  uint64_t number=0;
+
+  StringView subj, author, date, mid, tmp, xref;
+  StringView& l = line;
+  std::string ref;
+
+  bool ok = !l.empty();
+  ok = ok && l.pop_token (tmp, '\t');    if (ok) number = view_to_ull (tmp); tmp.clear();
+  ok = ok && l.pop_token (subj, '\t');   if (ok) subj.trim ();
+  ok = ok && l.pop_token (author, '\t'); if (ok) author.trim ();
+  ok = ok && l.pop_token (date, '\t');   if (ok) date.trim ();
+  ok = ok && l.pop_token (mid, '\t');    if (ok) mid.trim ();
+
+  //handle multiple "References:"-message-ids correctly.
+  ok = ok && l.pop_token (tmp, '\t');
+  do
+  {
+    if (tmp.empty()) continue;
+    if (tmp.front() == '<')
+    {
+      tmp.trim();
+      ref += tmp;
+      tmp.clear();
+    } else break;
+  } while ((ok = ok && l.pop_token (tmp, '\t'))) ;
+
+                                         if (ok) bytes = view_to_ul (tmp); tmp.clear();
+  ok = ok && l.pop_token (tmp, '\t');    if (ok) lines = view_to_ul (tmp);
+  ok = ok && l.pop_token (xref, '\t');   if (ok) xref.trim ();
+
+  if (xref.len>6 && !strncmp(xref.str,"Xref: ", 6)) {
+    xref = xref.substr (xref.str+6, 0);
+    xref.trim ();
+  }
+
+  // is this header corrupt?
+  if (!number // missing number
+      || subj.empty() // missing subject
+      || author.empty() // missing author
+      || date.empty() // missing date
+      || mid.empty() // missing mid
+      || mid.front()!='<') // corrupt mid
+      /// Concerning bug : https://bugzilla.gnome.org/show_bug.cgi?id=650042
+      /// Even if we didn't get a proper reference here, continue.
+      //|| (!ref.empty() && ref.front()!='<'))
+    return;
+
+  // if news server doesn't provide an xref, fake one
+  char * buf (0);
+  if (xref.empty())
+    xref = buf = g_strdup_printf ("%s %s:%"G_GUINT64_FORMAT,
+                                  nntp->_server.c_str(),
+                                  nntp->_group.c_str(),
+                                  number);
+
+  const char * fallback_charset = NULL; // FIXME
+  const time_t time_posted = g_mime_utils_header_decode_date (date.str, NULL);
+
+  data->xover_add (
+    nntp->_server, nntp->_group,
+    (header_is_nonencoded_utf8(subj) ? subj : header_to_utf8(subj,fallback_charset).c_str()),
+    (header_is_nonencoded_utf8(author) ? author : header_to_utf8(author,fallback_charset).c_str()),
+    time_posted, mid, StringView(ref), bytes, lines, xref);
+
+  high = std::max (high, number);
+
+  g_free (buf);
+}
+
+void
+XZVERDecoder :: find_lines()
+{
+  StringView ret;
+
+  while(!s_stream.eof())
+  {
+    std::string out;
+    getline(s_stream, out);
+    ret.assign(out);
+    xtask->on_nntp_line_process(nntp, ret);
+    _cnt++;
+  }
+
+}
+
+
+// save article IN A WORKER THREAD to avoid network stalls
+void
+XZVERDecoder :: do_work()
+{
+
+  const int bufsz = 4096;
+  char buf[bufsz];
+
+  disable_progress_update();
+
+  int res;
+  if (((res = UUInitialize())) != UURET_OK)
+    log_errors.push_back(_("Error initializing uulib")); // log error
+  else
+  {
+    build_cachename(buf,sizeof(buf), "xzver_test");
+    std::ofstream test (buf);
+    test << stream->stream->str();
+    test.close();
+
+    // TODO mod uulib to use streams!
+
+    UUSetOption (UUOPT_DESPERATE, 0, NULL);
+    UUSetOption (UUOPT_IGNMODE, 1, NULL); // don't save file as executable
+    UULoadFile (buf, 0, 0);
+    UUDecodeFile (UUGetFileListItem (0), build_cachename(buf,sizeof(buf), "xzver_decoded"));
+    UUCleanUp ();
+  }
+
+//  disable_progress_update();
+
+  _strm.zalloc = Z_NULL;
+  _strm.zfree = Z_NULL;
+  _strm.opaque = Z_NULL;
+  _strm.avail_in = 0;
+  _strm.next_in = Z_NULL;
+
+  _zret = inflateInit2(&_strm,-MAX_WBITS); //raw inflate
+  if (_zret != Z_OK)
+  {
+    log_errors.push_back(_("Error initializing zlib deflate"));
+    return;
+  }
+
+  std::ifstream headers;
+  FILE * in = fopen(build_cachename(buf,sizeof(buf), "xzver_decoded"), "rb");
+
+  if (!in)
+  {
+      char tmpbuf[2048];
+      g_snprintf(tmpbuf, sizeof(tmpbuf), _("Error opening header file %s"), buf);
+      log_errors.push_back(tmpbuf);
+      return;
+  }
+
+  int ret;
+  char fbuf[CHUNK];
+  StringView line;
+
+  do
+  {
+    size_t len = fread(fbuf, sizeof(char), CHUNK, in);
+    if (len==0 || ferror(in)) break;
+    ret = inflate_xzver (len, fbuf);
+  } while (!feof(in) && _zret == Z_OK);
+
+  find_lines();
+
+  if (in) fclose(in);
+  (void)inflateEnd(&_strm);
+
+  xtask->setHigh(nntp->_server, high);
+
+}
+
+int
+XZVERDecoder :: inflate_xzver (size_t len, char* buf)
+{
+
+  InflateChunk ret;
+
+  _strm.avail_in = len;
+  _strm.next_in = (unsigned char*)buf;
+
+  /* run inflate() on input until output buffer not full */
+  do {
+      _strm.avail_out = CHUNK;
+      _strm.next_out = ret.tmpbuf;
+      _zret = inflate(&_strm, Z_NO_FLUSH);
+      assert(_zret != Z_STREAM_ERROR);  /* state not clobbered */
+      switch (_zret) {
+      case Z_NEED_DICT:
+          _zret = Z_DATA_ERROR;     /* and fall through */
+      case Z_DATA_ERROR:
+      case Z_MEM_ERROR:
+          (void)inflateEnd(&_strm);
+          return _zret;
+      }
+
+      s_stream<<ret.tmpbuf;
+
+  } while (_strm.avail_out == 0);
+
+  return _zret == Z_STREAM_END ? Z_OK : Z_STREAM_ERROR;
+
+}
+
+
diff --git a/pan/tasks/xzver-decoder.h b/pan/tasks/xzver-decoder.h
new file mode 100644
index 0000000..4515f0f
--- /dev/null
+++ b/pan/tasks/xzver-decoder.h
@@ -0,0 +1,102 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2007 Charles Kerr <charles rebelbase com>
+ *
+ * This file
+ * Copyright (C) 2007 Calin Culianu <calin ajvar org>
+ * Copyright (C) 2007 Charles Kerr <charles rebelbase com>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ */
+#ifndef _XZVERDecoder_H_
+#define _XZVERDecoder_H_
+
+#include <list>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <fstream>
+
+#include <pan/general/locking.h>
+#include <pan/general/worker-pool.h>
+#include <pan/tasks/task-xover.h>
+#include <pan/tasks/decoder.h>
+extern "C" {
+#  define PROTOTYPES
+#  include <uulib/uudeview.h>
+};
+
+namespace pan
+{
+  #define CHUNK 16384
+
+  class Decoder;
+
+  /**
+   * Decodes XZVER yenc-encoded and zlib-deflated
+   * headers to process with TaskXOver
+   * @author Heinrich Mueller <heinrich mueller82 gmail com>
+   * @author Calin Culianu <calin ajvar org>
+   * @author Charles Kerr <charles rebelbase com>
+   * @ingroup tasks
+   * @see Queue
+   * @see TaskXOver
+   */
+  class XZVERDecoder: public Decoder
+  {
+    public:
+
+      struct InflateChunk
+      {
+        int ret;
+        unsigned char tmpbuf[CHUNK]; // dbg
+      };
+
+      XZVERDecoder (WorkerPool&);
+
+      ~XZVERDecoder ();
+
+      typedef std::vector<std::string> strings_t;
+
+      void enqueue (TaskXOver * task, TaskXOver::DataStream*, Data*);
+
+    protected: // inherited from WorkerPool::Worker
+
+      void do_work();
+      TaskXOver * xtask;
+      TaskXOver::DataStream* stream;
+
+      z_stream _strm;
+      int _zret;
+      NNTP* nntp;
+      int _cnt;
+      Data* data;
+      uint64_t high;
+      GString * out;
+      unsigned char outbuf[4096];
+
+      int inflate_xzver (size_t len, char* buf);
+      void on_nntp_batch_process (StringView&);
+      void find_lines();
+
+      std::stringstream s_stream; // output for inflate
+
+  };
+}
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]