[pan2/xzver_support: 44/47] dsfsdf



commit 1681de597b994b900cbe35400a92529a2a477d22
Author: Heinrich MÃller <henmull src gnome org>
Date:   Sun Jun 10 20:39:51 2012 +0200

    dsfsdf

 pan/gui/gui.cc             |    2 +-
 pan/gui/pan.cc             |    4 +-
 pan/gui/server-ui.cc       |   76 ++++++++++++-
 pan/tasks/Makefile.am      |    2 +-
 pan/tasks/decoder.cc       |   19 ++-
 pan/tasks/encoder.cc       |    2 +-
 pan/tasks/encoder.h        |    2 +-
 pan/tasks/nntp.cc          |   23 +++-
 pan/tasks/nntp.h           |   10 +-
 pan/tasks/task-xover.cc    |  185 +++++++++--------------------
 pan/tasks/task-xover.h     |   13 ++-
 pan/tasks/xzver-decoder.cc |  278 +++++++++++++++++++++++++++++++++++---------
 pan/tasks/xzver-decoder.h  |   67 +++++------
 13 files changed, 435 insertions(+), 248 deletions(-)
---
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index 041397f..c7b430f 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -1505,7 +1505,7 @@ void GUI :: do_delete_article ()
 void GUI :: do_clear_article_cache ()
 {
   _cache.clear ();
-  _encode_cache.clear();
+//  _encode_cache.clear();
 }
 
 void GUI :: do_mark_article_read ()
diff --git a/pan/gui/pan.cc b/pan/gui/pan.cc
index 513aca6..ac74b4e 100644
--- a/pan/gui/pan.cc
+++ b/pan/gui/pan.cc
@@ -861,8 +861,6 @@ main (int argc, char *argv[])
       { usage (); return EXIT_SUCCESS; }
     else if (!strcmp(tok, "--verbose") )
       verbosed = true;
-    else if (!strcmp(tok,"--xzver"))
-      _xzver_support = true;
     else {
       nzb = true;
       nzb_files.push_back (tok);
@@ -1045,7 +1043,7 @@ main (int argc, char *argv[])
 
     if (prefs.get_flag("clear-article-cache-on-shutdown", false)) {
       cache.clear ();
-      encode_cache.clear();
+//      encode_cache.clear();
     }
 
     delete queue_and_gui;
diff --git a/pan/gui/server-ui.cc b/pan/gui/server-ui.cc
index e0d9c8b..b2c8ded 100644
--- a/pan/gui/server-ui.cc
+++ b/pan/gui/server-ui.cc
@@ -52,6 +52,7 @@ using namespace pan;
 
 namespace
 {
+
   struct ServerEditDialog
   {
     Data& data;
@@ -69,7 +70,10 @@ namespace
     GtkWidget * rank_combo;
     GtkWidget * ssl_combo;
     GtkWidget * always_trust_checkbox;
+    GtkWidget * compression_checkbox;
     ServerEditDialog (Data& d, Queue& q, Prefs& p): data(d), queue(q), prefs(p) {}
+    CompressionType compressiontype;
+    
   };
 
   void pan_entry_set_text (GtkWidget * w, const StringView& v)
@@ -98,15 +102,64 @@ namespace
 
   void ssl_changed_cb(GtkComboBox* w, ServerEditDialog* d)
   {
+    if (!gtk_widget_get_realized(d->dialog)) return;
     int ssl(0);
 #ifdef HAVE_GNUTLS
     GtkTreeIter iter;
     if (gtk_combo_box_get_active_iter (w, &iter))
       gtk_tree_model_get (gtk_combo_box_get_model(w), &iter, 1, &ssl, -1);
+    if (ssl==0)
+    {
+      gtk_widget_hide(d->always_trust_checkbox);
+    }
+    else
+    {
+      gtk_widget_show(d->always_trust_checkbox);
+    }
     pan_spin_button_set (d->port_spin, ssl == 0 ? STD_NNTP_PORT : STD_SSL_PORT);
 #endif
   }
 
+  void address_entry_changed_cb   (GtkEditable *editable,
+                                    gpointer     gp)
+  {
+    ServerEditDialog* d (static_cast<ServerEditDialog*>(gp));
+    if (!d) return;
+
+    gchar* text = gtk_editable_get_chars (editable, 0, -1);
+    StringView t(text);
+
+    CompressionType type(NONE);
+
+    // 0 == NONE
+
+    if (t.strstr("astraweb")) // 1
+    {
+      type = XZVER;
+    }
+    if (t.strstr("giganews"))  // 2
+    {
+      type = XFEATURE;
+    }
+    char* others[] = {"newshosting", "easynews","usenetserver" };
+    for (int i= 0; i < G_N_ELEMENTS(others); i++)
+    {
+        if (t.strstr(others[i]))
+        {
+          type = DIABLO; // 3
+          break;
+        }
+    }
+    d->compressiontype = type;
+
+    if (type != NONE)
+      gtk_widget_show(d->compression_checkbox);
+    else
+      gtk_widget_hide(d->compression_checkbox);
+
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->compression_checkbox), type != NONE);
+  }
+
   void
   edit_dialog_populate (Data&, Prefs& prefs, const Quark& server, ServerEditDialog * d)
   {
@@ -117,6 +170,7 @@ namespace
     d->server = server;
 
     int port(STD_NNTP_PORT), max_conn(4), age(31*3), rank(1), ssl(0), trust(0);
+    CompressionType compression(NONE);
     std::string addr, user, cert;
     gchar* pass(NULL);
     if (!server.empty()) {
@@ -128,6 +182,7 @@ namespace
       ssl = d->data.get_server_ssl_support(server);
       cert = d->data.get_server_cert(server);
       d->data.get_server_trust (server, trust);
+      d->data.get_server_compression_type (server, compression);
     }
 
     pan_entry_set_text (d->address_entry, addr);
@@ -136,6 +191,11 @@ namespace
     pan_entry_set_text (d->auth_username_entry, user);
     pan_entry_set_text (d->auth_password_entry, pass);
     d->cert = cert;
+    d->compressiontype = compression;
+    std::cerr<<compression<<"\n";
+
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->compression_checkbox), d->compressiontype != NONE);
+
 
     // set the age combobox
     GtkComboBox * combo (GTK_COMBO_BOX (d->expiration_age_combo));
@@ -221,6 +281,8 @@ namespace
       trust = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->always_trust_checkbox)) ? 1 : 0;
 #endif
 
+      int header_comp = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->compression_checkbox)) ? 1 : 0;
+
       const char * err_msg (0);
       if (addr.empty())
         err_msg = _("Please specify the server's address.");
@@ -245,7 +307,7 @@ namespace
         d->data.set_server_ssl_support(d->server, ssl);
         d->data.set_server_cert(d->server,cert);
         d->data.set_server_trust(d->server,trust);
-
+        d->data.set_server_compression_type(d->server, header_comp);
         d->data.save_server_info(d->server);
 
         d->queue.upkeep ();
@@ -321,6 +383,7 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, Prefs& prefs, GtkWindow
     GtkWidget * w = d->address_entry = gtk_entry_new ();
     gtk_widget_set_tooltip_text( w, _("The news server's actual address, e.g. \"news.mynewsserver.com\""));
     HIG::workarea_add_row (t, &row, _("_Address:"), w, NULL);
+    g_signal_connect (w, "changed", G_CALLBACK(address_entry_changed_cb), d);
 
     GtkAdjustment * a = GTK_ADJUSTMENT (gtk_adjustment_new (1.0, 1.0, ULONG_MAX, 1.0, 1.0, 0.0));
     w = d->port_spin = gtk_spin_button_new (GTK_ADJUSTMENT(a), 1.0, 0u);
@@ -397,6 +460,10 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, Prefs& prefs, GtkWindow
     gtk_widget_set_tooltip_text( e, _("Fallback servers are used for articles that can't be found on the primaries.  One common approach is to use free servers as primaries and subscription servers as fallbacks."));
     HIG::workarea_add_row (t, &row, e, w);
 
+    // header compression options
+    d->compression_checkbox = w = gtk_check_button_new_with_label (_("Enable header compression for speedup"));
+    HIG::workarea_add_row (t, &row, e, w);
+
     // ssl 3.0 option
 #ifdef HAVE_GNUTLS
     // select ssl/plaintext
@@ -441,6 +508,13 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, Prefs& prefs, GtkWindow
   d->server = server;
   edit_dialog_populate (data, prefs, server, d);
   gtk_widget_show_all (d->dialog);
+
+  // perhaps hide compression checkbox
+  if (d->compressiontype==NONE)
+  {
+    gtk_widget_hide(d->compression_checkbox);
+  }
+
   return d->dialog;
 }
 
diff --git a/pan/tasks/Makefile.am b/pan/tasks/Makefile.am
index 9841de8..edf1e1b 100644
--- a/pan/tasks/Makefile.am
+++ b/pan/tasks/Makefile.am
@@ -1,6 +1,6 @@
 AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @GNUTLS_CFLAGS@ @GTK_CFLAGS@ @ZLIB_CFLAGS@
 
-AM_LDFLAGS = ../../uulib/libuu.a @GNUTLS_LIBS@ @ZLIB_LIBS@ @GTK_LIBS@
+AM_LDFLAGS = ../../uulib/libuu.a @GNUTLS_LIBS@ @ZLIB_LIBS@
 
 noinst_LIBRARIES = libtasks.a
 
diff --git a/pan/tasks/decoder.cc b/pan/tasks/decoder.cc
index 6b35f8a..b3c0864 100644
--- a/pan/tasks/decoder.cc
+++ b/pan/tasks/decoder.cc
@@ -290,9 +290,10 @@ int
 Decoder :: uu_busy_poll (void * d, uuprogress *p)
 {
   Decoder * self (static_cast<Decoder*>(d));
+  if (!self) return true;
   self->mut.lock();
-  self->percent = self->get_percentage(*p);
-  self->current_file = p->curfile;
+    self->percent = self->get_percentage(*p);
+    self->current_file = p->curfile;
   self->mut.unlock();
 
   return self->was_cancelled(); // returning true tells uulib to abort
@@ -303,17 +304,21 @@ gboolean
 Decoder :: progress_update_timer_func (gpointer decoder)
 {
   Decoder *self = static_cast<Decoder *>(decoder);
+  if (!self) return false;
   Task *task = self->task;
   if (!task || self->was_cancelled()) return false;
 
   self->mut.lock();
-  const double percent (self->percent);
-  const std::string f (content_to_utf8 (self->current_file));
+    const double percent (self->percent);
+    if (!self->current_file.empty())
+    {
+      const std::string f (content_to_utf8 (self->current_file));
+      if (!f.empty())
+        task->set_status_va (_("Decoding %s"), f.c_str());
+    }
+    task->set_step(int(percent));
   self->mut.unlock();
 
-  task->set_step(int(percent));
-  task->set_status_va (_("Decoding %s"), f.c_str());
-
   return true; // keep timer func running
 }
 
diff --git a/pan/tasks/encoder.cc b/pan/tasks/encoder.cc
index 887ef76..21900c3 100644
--- a/pan/tasks/encoder.cc
+++ b/pan/tasks/encoder.cc
@@ -262,9 +262,9 @@ Encoder :: progress_update_timer_func (gpointer decoder)
   self->mut.lock();
     const double percent (self->percent);
     const std::string f (content_to_utf8 (self->current_file));
+    task->set_step(int(percent));
   self->mut.unlock();
 
-  task->set_step(int(percent));
   task->set_status_va (_("Encoding %s"), f.c_str());
 
   return true; // keep timer func running
diff --git a/pan/tasks/encoder.h b/pan/tasks/encoder.h
index 89eb821..3ed5ac2 100644
--- a/pan/tasks/encoder.h
+++ b/pan/tasks/encoder.h
@@ -48,7 +48,7 @@ namespace pan
    * @author Charles Kerr <charles rebelbase com>
    * @ingroup tasks
    * @see Queue
-   * @see TaskArticle
+   * @see TaskUpload
    */
   class Encoder: public WorkerPool::Worker
   {
diff --git a/pan/tasks/nntp.cc b/pan/tasks/nntp.cc
index 557fa20..822bdb5 100644
--- a/pan/tasks/nntp.cc
+++ b/pan/tasks/nntp.cc
@@ -63,7 +63,6 @@ NNTP :: fire_done_func (Health health, const StringView& response)
       debug ("I (" << (void*)this << ") am setting my _listener to 0");
       _listener = 0;
       l->on_nntp_done (this, health, response);
-      _xzver = false;
    }
 }
 
@@ -79,7 +78,7 @@ NNTP :: on_socket_response (Socket * sock UNUSED, const StringView& line_in)
    StringView line (line_in);
 
    // strip off trailing \r\n
-   if (line.len>=2 && line.str[line.len-2]=='\r' && line.str[line.len-1]=='\n' && !_xzver)
+   if (line.len>=2 && line.str[line.len-2]=='\r' && line.str[line.len-1]=='\n')
      line.truncate (line.len-2);
 
 //    std::cerr <<"_nntp_response_text: " << _nntp_response_text<<std::endl;
@@ -94,7 +93,7 @@ NNTP :: on_socket_response (Socket * sock UNUSED, const StringView& line_in)
       {
          state = CMD_MORE;
 
-         if (line.len>=2 && line.str[0]=='.' && line.str[1]=='.' && !_xzver) // rfc 977: 2.4.1
+         if (line.len>=2 && line.str[0]=='.' && line.str[1]=='.') // rfc 977: 2.4.1
             line.rtruncate (line.len-1);
 
          assert (_listener != 0);
@@ -332,7 +331,6 @@ NNTP :: xzver (const Quark   & group,
                Listener      * l)
 {
    _listener = l;
-   _xzver = true;
 
    if (group != _group)
       _commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
@@ -343,6 +341,23 @@ NNTP :: xzver (const Quark   & group,
 }
 
 void
+NNTP :: xfeat (const Quark   & group,
+               uint64_t        low,
+               uint64_t        high,
+               Listener      * l)
+{
+   _listener = l;
+
+   if (group != _group)
+      _commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
+
+   _commands.push_back ("XFEATURE COMPRESS GZIP");
+   _commands.push_back (build_command ("XOVER %"G_GUINT64_FORMAT"-%"G_GUINT64_FORMAT"\r\n", low, high));
+
+   write_next_command ();
+}
+
+void
 NNTP :: xover_count_only (const Quark   & group,
                           Listener      * l)
 {
diff --git a/pan/tasks/nntp.h b/pan/tasks/nntp.h
index 178d376..73793af 100644
--- a/pan/tasks/nntp.h
+++ b/pan/tasks/nntp.h
@@ -153,8 +153,7 @@ namespace pan
           _listener(0),
           _username(username),
           _password(password),
-          _nntp_response_text(false),
-          _xzver(false)
+          _nntp_response_text(false)
        {}
 
        virtual ~NNTP ()
@@ -200,6 +199,11 @@ namespace pan
                              uint64_t             high,
                              Listener           * l);
 
+      void xfeat            (const Quark        & group,
+                             uint64_t             low,
+                             uint64_t             high,
+                             Listener           * l);
+
       /**
        * Executes an XOVER command: "XOVER" to count
        * the xover numbers internally
@@ -330,8 +334,6 @@ namespace pan
       /** True if the server told us that we're getting a list back. */
       bool _nntp_response_text;
 
-      bool _xzver;
-
       typedef std::deque<std::string> strings_t;
       strings_t _commands;
       std::string _previous_command;
diff --git a/pan/tasks/task-xover.cc b/pan/tasks/task-xover.cc
index 18403ed..26e7bc2 100644
--- a/pan/tasks/task-xover.cc
+++ b/pan/tasks/task-xover.cc
@@ -12,7 +12,7 @@
  * 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
+ * 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
  */
@@ -45,6 +45,7 @@ using namespace pan;
 
 namespace
 {
+
    std::string
    get_short_name (const StringView& in)
    {
@@ -113,17 +114,11 @@ TaskXOver :: TaskXOver (Data         & data,
   _articles_so_far (0ul),
   _total_minitasks (0),
   _running_minitasks (0),
-  _xzver (false),//_xzver_support),
   _decoder(0),
-  _decoder_has_run (false),
-  _extract_done(false)
+  _decoder_has_run (false)
 {
 
-  if (_xzver)
-  {
-    char buf[4096];
-    _headers.open(build_cachename(buf,sizeof(buf), "xzver_test"), std::ios::out | std::ios::binary);
-  }
+
 
   debug ("ctor for " << group);
 
@@ -146,6 +141,12 @@ TaskXOver :: TaskXOver (Data         & data,
   update_work ();
 }
 
+void
+TaskXOver :: setHigh(const Quark& server, uint64_t& h)
+{
+  _high[server] = h;
+}
+
 TaskXOver :: ~TaskXOver ()
 {
   if (_group_xover_is_reffed) {
@@ -155,6 +156,8 @@ TaskXOver :: ~TaskXOver ()
   }
   if (_decoder)
     _decoder->cancel_silently();
+
+  _data.fire_group_entered(_group, 1, 0);
 }
 
 void
@@ -162,6 +165,10 @@ TaskXOver :: use_nntp (NNTP* nntp)
 {
   const Quark& server (nntp->_server);
   debug ("got an nntp from " << nntp->_server);
+  CompressionType type;
+  _data.get_server_compression_type(nntp->_server, type);
+
+  _compression_enabled = type != NONE;
 
   // if this is the first nntp we've gotten, ref the xover data
   if (!_group_xover_is_reffed) {
@@ -172,7 +179,7 @@ TaskXOver :: use_nntp (NNTP* nntp)
   MiniTasks_t& minitasks (_server_to_minitasks[server]);
   if (minitasks.empty())
   {
-    debug ("That's interesting, I got a socket for " << server << " but have no use for it!");
+    debug ("That's interesting, I got a socket for " << server << " but _have no use for it!");
     _state._servers.erase (server);
     check_in (nntp, OK);
   }
@@ -189,8 +196,16 @@ TaskXOver :: use_nntp (NNTP* nntp)
       case MiniTask::XOVER:
         debug ("XOVER " << mt._low << '-' << mt._high << " to " << server);
         _last_xover_number[nntp] = mt._low;
-        if (_xzver)
-          nntp->xzver (_group, mt._low, mt._high, this);
+        if (_compression_enabled)
+        {
+          char buf[4096];
+          _headers.open(build_cachename(buf,sizeof(buf), "xzver_test"), std::ios::out | std::ios::binary);
+//          if (type == XZVER)
+            nntp->xzver (_group, mt._low, mt._high, this);
+//          if (type == XFEATURE)
+//            nntp->xfeat (_group, mt._low, mt._high, this);
+          // TODO diablo
+        }
         else
           nntp->xover (_group, mt._low, mt._high, this);
         --_running_minitasks;
@@ -245,12 +260,12 @@ TaskXOver :: on_nntp_group (NNTP          * nntp,
 
   if (l <= high)
   {
-    std::cerr << LINE_ID << " okay, I'll try to get articles in [" << l << "..." << h << ']' << std::endl;
+//    std::cerr << LINE_ID << " okay, I'll try to get articles in [" << l << "..." << h << ']' << std::endl;
 
     add_steps (h-l);
 
     MiniTasks_t& minitasks (_server_to_minitasks[servername]);
-    if (_xzver)
+    if (_compression_enabled)
     {
       MiniTask mt (MiniTask::XOVER, l, h);
       minitasks.push_front (mt);
@@ -318,12 +333,13 @@ void
 TaskXOver :: on_nntp_line         (NNTP               * nntp,
                                    const StringView   & line)
 {
-    if (_xzver ) {
+    if (_compression_enabled) {
       if (line.strstr("=ybegin line=128"))
+      {
         _headers << line.str << " name=xzver_decoded\n";
+      }
       else
         _headers << line.str <<"\n";
-      increment_step(1);
     }
     else
     {
@@ -336,6 +352,8 @@ TaskXOver :: on_nntp_line_process (NNTP               * nntp,
                                    const StringView   & line)
 {
 
+  _dbg<<line.str<<"\n";
+
   pan_return_if_fail (nntp != 0);
   pan_return_if_fail (!nntp->_server.empty());
   pan_return_if_fail (!nntp->_group.empty());
@@ -356,6 +374,7 @@ TaskXOver :: on_nntp_line_process (NNTP               * nntp,
 
   //handle multiple "References:"-message-ids correctly.
   ok = ok && l.pop_token (tmp, '\t');
+  ref += tmp;
   do
   {
     if (tmp.empty()) continue;
@@ -382,8 +401,10 @@ TaskXOver :: on_nntp_line_process (NNTP               * nntp,
       || author.empty() // missing author
       || date.empty() // missing date
       || mid.empty() // missing mid
-      || mid.front()!='<' // corrupt mid
-      || (!ref.empty() && ref[0] != '<'))
+      || 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
@@ -394,11 +415,6 @@ TaskXOver :: on_nntp_line_process (NNTP               * nntp,
                                   nntp->_group.c_str(),
                                   number);
 
-  uint64_t& h (_high[nntp->_server]);
-  h = std::max (h, number);
-
-//  std::cerr<<h<<" "<<number<<"\n";
-
   const char * fallback_charset = NULL; // FIXME
 
   // are we done?
@@ -419,11 +435,12 @@ TaskXOver :: on_nntp_line_process (NNTP               * nntp,
   if (article)
     ++_articles_so_far;
 
-  // emit a status update
+//   emit a status update
   uint64_t& prev = _last_xover_number[nntp];
+  uint64_t& h (_high[nntp->_server]);
+  h = std::max (h, number);
 
   increment_step (number - prev);
-//  std::cerr<<"stepping "<<number<<" "<<prev<<" "<<get_steps()<<" "<<get_step()<<" "<<get_progress_of_100()<<"\n";
   prev = number;
   if (!(_parts_so_far % 500))
     set_status_va (_("%s (%lu parts, %lu articles)"), _short_group_name.c_str(), _parts_so_far, _articles_so_far);
@@ -437,8 +454,12 @@ TaskXOver :: on_nntp_done (NNTP              * nntp,
                            Health              health,
                            const StringView  & response UNUSED)
 {
-  if (_running_minitasks == 0) //process_headers(nntp);
+  if (_running_minitasks == 0 && _compression_enabled)
+  {
     _backup_nntp = new NNTP(nntp->_server, nntp->get_username(), "", 0);
+    _backup_nntp->_group = nntp->_group;
+  }
+
   update_work (true);
   check_in (nntp, health);
 }
@@ -460,20 +481,20 @@ TaskXOver :: update_work (bool subtract_one_from_nntp_count)
     _state.set_need_nntp (servers);
   else if (nntp_count)
     _state.set_working ();
-  else if (!_decoder && !_decoder_has_run && _xzver) {
+  else if (!_decoder && !_decoder_has_run && _compression_enabled) {
+    std::cerr<<"decode\n";
     _headers.close();
     _state.set_need_xzverdecoder ();
-    set_step(0);
-  } else if (_decoder_has_run && !_extract_done && _xzver) {
-    _state.set_working();
-    process_headers(_backup_nntp);
-  } else if (_decoder_has_run && _extract_done && _xzver) {
+  } else if (_decoder_has_run) {
+    std::cerr<<"finished\n";
     _state.set_completed();
     set_finished (OK);
-  } else if (!_xzver)
+    _dbg.close();
+  } else if (!_compression_enabled)
   {
     _state.set_completed();
     set_finished (OK);
+    _dbg.close();
   } else assert(0 && "hm, missed a state.");
 }
 
@@ -484,10 +505,9 @@ TaskXOver:: use_decoder (Decoder* decoder)
     check_in (decoder);
 
   _decoder = static_cast<XZVERDecoder*>(decoder);
-  init_steps(100);
   _state.set_working();
-  _decoder->enqueue (this);
-  set_status_va (_("Decoding XZVER Headers"));
+
+  _decoder->enqueue (this, &_high[_backup_nntp->_server], _backup_nntp, &_data);
   debug ("decoder thread was free, enqueued work");
 }
 
@@ -498,96 +518,6 @@ TaskXOver :: stop ()
       _decoder->cancel();
 }
 
-namespace
-{
-  #define CHUNK 16384
-
-  int inflate_xzver(FILE *source, FILE *dest)
-  {
-    int ret;
-    unsigned have;
-    z_stream strm;
-    unsigned char in[CHUNK];
-    unsigned char out[CHUNK];
-
-    /* allocate inflate state */
-    strm.zalloc = Z_NULL;
-    strm.zfree = Z_NULL;
-    strm.opaque = Z_NULL;
-    strm.avail_in = 0;
-    strm.next_in = Z_NULL;
-    ret = inflateInit2(&strm,-15); //raw inflate
-    if (ret != Z_OK)
-        return ret;
-
-    /* decompress until deflate stream ends or end of file */
-    do {
-        strm.avail_in = fread(in, 1, CHUNK, source);
-        if (ferror(source)) {
-            (void)inflateEnd(&strm);
-            return Z_ERRNO;
-        }
-        if (strm.avail_in == 0)
-            break;
-        strm.next_in = in;
-
-        /* run inflate() on input until output buffer not full */
-        do {
-            strm.avail_out = CHUNK;
-            strm.next_out = out;
-            ret = inflate(&strm, Z_NO_FLUSH);
-            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
-            switch (ret) {
-            case Z_NEED_DICT:
-                ret = Z_DATA_ERROR;     /* and fall through */
-            case Z_DATA_ERROR:
-            case Z_MEM_ERROR:
-                (void)inflateEnd(&strm);
-                return ret;
-            }
-            have = CHUNK - strm.avail_out;
-            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
-                (void)inflateEnd(&strm);
-                return Z_ERRNO;
-            }
-        } while (strm.avail_out == 0);
-
-        /* done when inflate() says it's done */
-    } while (ret != Z_STREAM_END);
-
-    /* clean up and return */
-    (void)inflateEnd(&strm);
-    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
-  }
-}
-
-void
-TaskXOver :: process_headers (NNTP* nntp)
-{
-  char buf[4096];
-
-  build_cachename(buf,sizeof(buf), "xzver_decoded");
-
-  /* raw zlib inflate */
-  FILE * in = fopen (buf, "rb");
-  FILE * out = fopen (build_cachename(buf,sizeof(buf), "xzver_out"), "wb");
-  int res(Z_OK);
-  if (in && out) res = inflate_xzver (in,out);
-
-  /* feed to on_nntp_line */
-  if (in) fclose(in);
-  if (out) fclose(out);
-  if (res==Z_OK)
-  {
-    std::ifstream f(buf, std::ios::in);
-    char buf[4096];
-    while (f.getline(buf,sizeof(buf))) on_nntp_line_process(nntp,StringView(buf));
-  }
-  _extract_done = true;
-  update_work();
-}
-
-
 unsigned long
 TaskXOver :: get_bytes_remaining () const
 {
@@ -609,8 +539,6 @@ TaskXOver :: on_worker_done (bool cancelled)
   assert(_decoder);
   if (!_decoder) return;
 
-  std::cerr<<"worker done\n";
-
   if (!cancelled)
   {
     // the decoder is done... catch up on all housekeeping
@@ -641,7 +569,6 @@ TaskXOver :: on_worker_done (bool cancelled)
       _state.set_health (ERR_LOCAL);
     else {
       _state.set_completed();
-      set_step (100);
       _decoder_has_run = true;
     }
   }
diff --git a/pan/tasks/task-xover.h b/pan/tasks/task-xover.h
index 8f8051e..8f1d7f2 100644
--- a/pan/tasks/task-xover.h
+++ b/pan/tasks/task-xover.h
@@ -23,6 +23,7 @@
 #include <map>
 #include <vector>
 #include <sstream>
+#include <zlib.h>
 
 #include <pan/data/data.h>
 #include <pan/tasks/task.h>
@@ -98,15 +99,21 @@ namespace pan
       unsigned long _articles_so_far;
       unsigned long _lines_so_far;
       unsigned long _total_minitasks;
-      int           _running_minitasks;
-      bool _xzver;
+      unsigned long _running_minitasks;
+      bool _compression_enabled;
       std::ofstream _headers;
       NNTP * _backup_nntp;
+      CompressionType _compressiontype;
+
 
       friend class XZVERDecoder;
       XZVERDecoder * _decoder;
       bool _decoder_has_run;
-      bool _extract_done;
+
+      std::ofstream _dbg;
+
+    public:
+      void setHigh(const Quark& server, uint64_t& h);
   };
 }
 
diff --git a/pan/tasks/xzver-decoder.cc b/pan/tasks/xzver-decoder.cc
index d2be871..87eb7ff 100644
--- a/pan/tasks/xzver-decoder.cc
+++ b/pan/tasks/xzver-decoder.cc
@@ -48,6 +48,8 @@ using namespace pan;
 XZVERDecoder :: XZVERDecoder (WorkerPool& pool) :
   Decoder(pool)
 {
+//  out = g_string_sized_new (CHUNK*1024);
+  _cnt = 0;
 }
 
 XZVERDecoder :: ~XZVERDecoder()
@@ -56,16 +58,17 @@ XZVERDecoder :: ~XZVERDecoder()
 }
 
 void
-XZVERDecoder :: enqueue (TaskXOver          * task)
+XZVERDecoder :: enqueue (TaskXOver  * task, uint64_t* h, NNTP * nntp, Data* data)
 {
+  _cnt = 0;
+
   disable_progress_update ();
 
   this->xtask = task;
+  this->nntp = nntp;
+  this->data = data;
+  this->high = *h;
 
-  mark_read = false;
-  percent = 0;
-  num_scanned_files = 0;
-  current_file.clear ();
   log_infos.clear();
   log_errors.clear();
 
@@ -83,6 +86,145 @@ namespace
   }
 }
 
+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_line()
+{
+  StringView ret;
+//  char * buf = out->str;
+//  int pos(0), _apos(0);
+//  while (*buf) {
+//    if (*buf == '\n')
+//    {
+//      int _pos(std::min(pos+1,(int)out->len));
+//      ret.assign(out->str, _pos);
+//      g_string_erase (out, 0, _pos);
+//      xtask->on_nntp_line_process(nntp, ret);
+//      _cnt++;
+//    }
+//    ++pos; ++buf;
+//  }
+  while(!stream.eof())
+  {
+    std::string out;
+    getline(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()
@@ -90,81 +232,103 @@ XZVERDecoder :: do_work()
   const int bufsz = 4096;
   char buf[bufsz];
 
-  enable_progress_update();
+  disable_progress_update();
 
   int res;
   if (((res = UUInitialize())) != UURET_OK)
     log_errors.push_back(_("Error initializing uulib")); // log error
   else
   {
-    UUSetMsgCallback (this, uu_log);
-    UUSetOption (UUOPT_DESPERATE, 0, NULL); // keep incompletes; they're useful to par2
+//    UUSetMsgCallback (this, uu_log);
+    UUSetOption (UUOPT_DESPERATE, 0, NULL);
     UUSetOption (UUOPT_IGNMODE, 1, NULL); // don't save file as executable
-    UUSetBusyCallback (this, uu_busy_poll, 500); // .5 secs busy poll?
+//    UUSetBusyCallback (this, uu_busy_poll, 500); // .5 secs busy poll?
     UULoadFile (build_cachename(buf,sizeof(buf), "xzver_test"), 0, 1);
     UUDecodeFile (UUGetFileListItem (0), build_cachename(buf,sizeof(buf), "xzver_decoded"));
     UUCleanUp ();
   }
 
-  disable_progress_update();
-}
+//  disable_progress_update();
 
-/***
-****
-***/
+  _strm.zalloc = Z_NULL;
+  _strm.zfree = Z_NULL;
+  _strm.opaque = Z_NULL;
+  _strm.avail_in = 0;
+  _strm.next_in = Z_NULL;
 
-void
-XZVERDecoder :: uu_log (void* data, char* message, int severity)
-{
-  XZVERDecoder *self = static_cast<XZVERDecoder *>(data);
-  char * pch (g_locale_to_utf8 (message, -1, 0, 0, 0));
+  _zret = inflateInit2(&_strm,-MAX_WBITS); //raw inflate
+  if (_zret != Z_OK)
+  {
+    log_errors.push_back(_("Error initializing zlib deflate"));
+    return;
+  }
 
-  if (severity >= UUMSG_WARNING)
-    self->file_errors.push_back (pch ? pch : message);
+  std::ifstream headers;
+  FILE * in = fopen(build_cachename(buf,sizeof(buf), "xzver_decoded"), "rb");
 
-  if (severity >= UUMSG_ERROR)
-    self->log_errors.push_back (pch ? pch : message);
-  else if (severity >= UUMSG_NOTE)
-    self->log_infos.push_back (pch ? pch : message);
+  if (!in)
+  {
+      char tmpbuf[2048];
+      g_snprintf(tmpbuf, sizeof(tmpbuf), _("Error opening header file %s"), buf);
+      log_errors.push_back(tmpbuf);
+      return;
+  }
+
+  int ret;
+  unsigned 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);
+//    find_line();
+  } while (!feof(in) && _zret == Z_OK);
+
+  find_line();
+
+//  std::cerr<<"final "<<out->len<<"\n";
+
+  if (in) fclose(in);
+  (void)inflateEnd(&_strm);
+
+  std::cerr<<"count "<<_cnt<<"\n";
+
+  xtask->setHigh(nntp->_server, high);
 
-  g_free (pch);
 }
 
-double
-XZVERDecoder :: get_percentage (const uuprogress& p) const
+int
+XZVERDecoder :: inflate_xzver (size_t len, unsigned char* buf)
 {
-  // These should add up to 100.
-  // We can tweak these as needed.  Calin sees more time spent
-  // in COPYING, but I'm seeing it in DECODING, so I've split
-  // the difference here and given them the same weight.
-  static const double WEIGHT_SCANNING = 10;
-  static const double WEIGHT_DECODING = 45;
-  static const double WEIGHT_COPYING = 45;
-
-  double base = 0;
-
-  if (p.action != UUACT_SCANNING)
-    base += WEIGHT_SCANNING;
-  else {
-    const double percent = (100.0 + p.percent);
-    return base + (percent / (100.0/WEIGHT_SCANNING));
-  }
 
-  if (p.action != UUACT_DECODING)
-    base += WEIGHT_DECODING;
-  else {
-    const double percent = ((100.0) + p.percent);
-    return base + (percent / (100.0/WEIGHT_DECODING));
-  }
+  InflateChunk ret;
 
-  if (p.action != UUACT_COPYING)
-    base += WEIGHT_COPYING;
-  else {
-    const double percent = p.percent;
-    return base + (percent / (100.0/WEIGHT_COPYING));
-  }
+  _strm.avail_in = len;
+  _strm.next_in = 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;
+      }
+//      g_string_append_len(out, (char*)ret.tmpbuf, CHUNK - _strm.avail_out);
+      stream<<ret.tmpbuf;
+
+  } while (_strm.avail_out == 0);
+
+  return _zret == Z_STREAM_END ? Z_OK : Z_STREAM_ERROR;
 
-  return 0;
 }
 
 
diff --git a/pan/tasks/xzver-decoder.h b/pan/tasks/xzver-decoder.h
index 838d9cb..00ea32f 100644
--- a/pan/tasks/xzver-decoder.h
+++ b/pan/tasks/xzver-decoder.h
@@ -27,7 +27,11 @@
 
 #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>
@@ -39,67 +43,58 @@ extern "C" {
 
 namespace pan
 {
+  #define CHUNK 16384
 
   class Decoder;
 
   /**
-   * Decodes attachments in a worker thread.
-   *
+   * 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 TaskArticle
+   * @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);
-
-//    public:
-//
-//      typedef std::list<std::string> log_t;
-//      log_t log_severe, log_errors, log_infos, file_errors;
-//      bool mark_read;
-//      Health health;
+      void enqueue (TaskXOver * task, uint64_t*, NNTP*, Data*);
 
     protected: // inherited from WorkerPool::Worker
 
       void do_work();
       TaskXOver * xtask;
 
-//    private:
-//
-//      TaskArticle * task;
-//      std::string save_path;
-//      strings_t input_files;
-//      TaskArticle::SaveMode save_mode;
-//      TaskArticle::SaveOptions options;
-//      StringView attachment_filename;
-//
-//      // These are set in the worker thread and polled in the main thread.
-//      Mutex mut;
-//      volatile double percent;
-//      std::string current_file; // the current file we are decoding, with path
-//      volatile int num_scanned_files;
-//
-      static void uu_log(void *thiz, char *message, int severity);
-      double get_percentage (const uuprogress& p) const;
-//      static int uu_busy_poll(void * self, uuprogress *p);
-//      /** tell our task about the decode's progress */
-//      static gboolean progress_update_timer_func(gpointer decoder);
-//
-//      WorkerPool& _worker_pool;
-//      int _gsourceid;
-//      void disable_progress_update();
-//      void enable_progress_update();
+      z_stream _strm;
+      int _zret;
+      NNTP* nntp;
+      int _cnt;
+      Data* data;
+      uint64_t high;
+      GString * out;
+      unsigned char outbuf[4096];
+
+      std::stringstream stream;
+
+      int inflate_xzver (size_t len, unsigned char* buf);
+      void on_nntp_batch_process (StringView&);
+      void find_line();
+
   };
 }
 



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