[pan2] * hotfixes for xfeature * patch for 'match only read' (Cal Peake)



commit 49220459edc5430a58e929277cce9c29d19cab11
Author: Heinrich MÃller <henmull src gnome org>
Date:   Tue Jan 8 20:38:54 2013 +0100

    * hotfixes for xfeature
    * patch for 'match only read' (Cal Peake)

 pan/data-impl/article-filter.cc  |    4 +
 pan/general/compression.h        |    2 +-
 pan/gui/actions.cc               |   19 +++-
 pan/gui/gui.cc                   |    1 +
 pan/gui/gui.h                    |    1 +
 pan/gui/header-pane.cc           |    6 +
 pan/gui/pan-ui.h                 |    1 +
 pan/gui/pan.ui.h                 |    2 +
 pan/gui/pan.ui.ssl.h             |    2 +
 pan/icons/Makefile.am            |    1 +
 pan/tasks/nntp.cc                |  284 +++++++++++++++++++-------------------
 pan/tasks/socket-impl-gio.cc     |    4 +-
 pan/tasks/socket-impl-openssl.cc |    4 +-
 pan/tasks/task-groups.cc         |   20 ++-
 pan/tasks/task-groups.h          |    2 +
 pan/tasks/task-xover.cc          |   27 ++--
 pan/usenet-utils/filter-info.cc  |    7 +-
 pan/usenet-utils/filter-info.h   |    2 +
 18 files changed, 222 insertions(+), 167 deletions(-)
---
diff --git a/pan/data-impl/article-filter.cc b/pan/data-impl/article-filter.cc
index 9a25dbb..effdf69 100644
--- a/pan/data-impl/article-filter.cc
+++ b/pan/data-impl/article-filter.cc
@@ -96,6 +96,10 @@ ArticleFilter :: test_article (const Data        & data,
       pass = data.has_from_header (article.author.to_view());
       break;
 
+    case FilterInfo::IS_READ:
+      pass = data.is_read (&article);
+      break;
+
     case FilterInfo::IS_UNREAD:
       pass = !data.is_read (&article);
       break;
diff --git a/pan/general/compression.h b/pan/general/compression.h
index b4bc715..defa2f2 100644
--- a/pan/general/compression.h
+++ b/pan/general/compression.h
@@ -48,7 +48,7 @@ namespace pan
 
     void ydecode(std::stringstream* in, std::stringstream* out);
 
-    void deflate_gzip (const StringView& line, std::vector<std::string>& fillme);
+    void inflate_gzip (std::stringstream* stream, std::vector<std::string>& fillme);
   }
 }
 
diff --git a/pan/gui/actions.cc b/pan/gui/actions.cc
index 0088820..dd8f7ad 100644
--- a/pan/gui/actions.cc
+++ b/pan/gui/actions.cc
@@ -61,6 +61,7 @@ namespace pan
     { icon_filter_only_attachments, "ICON_ONLY_ATTACHMENTS" },
     { icon_filter_only_cached, "ICON_ONLY_CACHED" },
     { icon_filter_only_me, "ICON_ONLY_ME" },
+    { icon_filter_only_read, "ICON_ONLY_READ" },
     { icon_filter_only_unread, "ICON_ONLY_UNREAD" },
     { icon_filter_only_watched, "ICON_ONLY_WATCHED" },
     { icon_get_dialog, "ICON_GET_DIALOG" },
@@ -283,7 +284,22 @@ namespace pan
   void do_match_only_cached_articles (GtkToggleAction * a) { pan_ui->do_match_only_cached_articles (gtk_toggle_action_get_active(a)); }
   void do_match_only_binary_articles (GtkToggleAction * a) { pan_ui->do_match_only_binary_articles (gtk_toggle_action_get_active(a)); }
   void do_match_only_my_articles (GtkToggleAction * a) { pan_ui->do_match_only_my_articles (gtk_toggle_action_get_active(a)); }
-  void do_match_only_unread_articles (GtkToggleAction * a) { pan_ui->do_match_only_unread_articles (gtk_toggle_action_get_active(a)); }
+  void do_match_only_unread_articles (GtkToggleAction * a)
+  {
+    const bool active (gtk_toggle_action_get_active(a));
+    toggle_action_set_active("match-only-unread-articles", active);
+    if (active)
+      toggle_action_set_active("match-only-read-articles", !active);
+    pan_ui->do_match_only_unread_articles(true);
+  }
+  void do_match_only_read_articles (GtkToggleAction * a)
+  {
+    const bool active (gtk_toggle_action_get_active(a));
+    toggle_action_set_active("match-only-read-articles", active);
+    if (active)
+      toggle_action_set_active("match-only-unread-articles", !active);
+    pan_ui->do_match_only_read_articles(true);
+  }
 
     GtkActionEntry entries[] =
     {
@@ -725,6 +741,7 @@ namespace pan
     { "show-toolbar", NULL, N_("Show _Toolbar"), NULL, NULL, G_CALLBACK(do_show_toolbar), true },
     { "shorten-group-names", GTK_STOCK_ZOOM_OUT, N_("Abbreviate Group Names"), "B", NULL, G_CALLBACK(do_shorten_group_names), false },
 
+    { "match-only-read-articles", "ICON_ONLY_READ", N_("Match Only _Read Articles"), NULL, N_("Match Only Read Articles"), G_CALLBACK(do_match_only_read_articles), false },
     { "match-only-unread-articles", "ICON_ONLY_UNREAD", N_("Match Only _Unread Articles"), NULL, N_("Match Only Unread Articles"), G_CALLBACK(do_match_only_unread_articles), false },
     { "match-only-cached-articles", "ICON_ONLY_CACHED", N_("Match Only _Cached Articles"), NULL, N_("Match Only Cached Articles"), G_CALLBACK(do_match_only_cached_articles), false },
     { "match-only-binary-articles", "ICON_ONLY_ATTACHMENTS", N_("Match Only _Complete Articles"), NULL, N_("Match Only Complete Articles"), G_CALLBACK(do_match_only_binary_articles), false },
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index 8d4cd61..9c87c0a 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -1867,6 +1867,7 @@ void GUI :: do_shorten_group_names (bool b)
   _group_pane->set_name_collapse (b);
 }
 
+void GUI :: do_match_only_read_articles   (bool) { _header_pane->refilter (); }
 void GUI :: do_match_only_unread_articles (bool) { _header_pane->refilter (); }
 void GUI :: do_match_only_cached_articles (bool) { _header_pane->refilter (); }
 void GUI :: do_match_only_binary_articles (bool) { _header_pane->refilter (); }
diff --git a/pan/gui/gui.h b/pan/gui/gui.h
index 1d44935..e67fd07 100644
--- a/pan/gui/gui.h
+++ b/pan/gui/gui.h
@@ -183,6 +183,7 @@ namespace pan
       virtual void do_match_only_binary_articles (bool);
       virtual void do_match_only_my_articles (bool);
       virtual void do_match_only_unread_articles (bool);
+      virtual void do_match_only_read_articles (bool);
       virtual void do_enable_toggle_rules (bool enable);
       virtual void do_match_on_score_state (int);
       virtual void do_show_matches (const Data::ShowType);
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index 7b571fc..46bf9c4 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -1418,6 +1418,12 @@ HeaderPane :: rebuild_filter (const std::string& text, int mode)
     f._aggregates.push_back (entry_filter);
   }
 
+  if (_action_manager.is_action_active("match-only-read-articles")) {
+//std::cerr << LINE_ID << " AND is read" << std::endl;
+    FilterInfo tmp;
+    tmp.set_type_is_read ();
+    f._aggregates.push_back (tmp);
+  }
   if (_action_manager.is_action_active("match-only-unread-articles")) {
 //std::cerr << LINE_ID << " AND is unread" << std::endl;
     FilterInfo tmp;
diff --git a/pan/gui/pan-ui.h b/pan/gui/pan-ui.h
index e9eca00..765c45e 100644
--- a/pan/gui/pan-ui.h
+++ b/pan/gui/pan-ui.h
@@ -123,6 +123,7 @@ namespace pan
     virtual void do_show_toolbar (bool) = 0;
     virtual void do_shorten_group_names (bool) = 0;
 
+    virtual void do_match_only_read_articles (bool) = 0;
     virtual void do_match_only_unread_articles (bool) = 0;
     virtual void do_match_only_cached_articles (bool) = 0;
     virtual void do_match_only_binary_articles (bool) = 0;
diff --git a/pan/gui/pan.ui.h b/pan/gui/pan.ui.h
index a24fd70..57a5efd 100644
--- a/pan/gui/pan.ui.h
+++ b/pan/gui/pan.ui.h
@@ -51,6 +51,7 @@ const char * fallback_ui_file =
 "        <menuitem action='show-matching-subthreads' />\n"
 "        <separator />\n"
 "        <menuitem action='match-only-unread-articles' />\n"
+"        <menuitem action='match-only-read-articles' />\n"
 "        <menuitem action='match-only-cached-articles' />\n"
 "        <menuitem action='match-only-binary-articles' />\n"
 "        <menuitem action='match-only-my-articles' />\n"
@@ -179,6 +180,7 @@ const char * fallback_ui_file =
 "    <placeholder name='header-pane-filter' />\n"
 "    <separator />\n"
 "    <toolitem action='match-only-unread-articles' />\n"
+"    <toolitem action='match-only-read-articles' />\n"
 "    <toolitem action='match-only-cached-articles' />\n"
 "    <toolitem action='match-only-binary-articles' />\n"
 "    <toolitem action='match-only-my-articles' />\n"
diff --git a/pan/gui/pan.ui.ssl.h b/pan/gui/pan.ui.ssl.h
index ce1e573..e90c406 100644
--- a/pan/gui/pan.ui.ssl.h
+++ b/pan/gui/pan.ui.ssl.h
@@ -50,6 +50,7 @@ const char * fallback_ui_file =
 "        <menuitem action='show-matching-subthreads' />\n"
 "        <separator />\n"
 "        <menuitem action='match-only-unread-articles' />\n"
+"        <menuitem action='match-only-read-articles' />\n"
 "        <menuitem action='match-only-cached-articles' />\n"
 "        <menuitem action='match-only-binary-articles' />\n"
 "        <menuitem action='match-only-my-articles' />\n"
@@ -178,6 +179,7 @@ const char * fallback_ui_file =
 "    <placeholder name='header-pane-filter' />\n"
 "    <separator />\n"
 "    <toolitem action='match-only-unread-articles' />\n"
+"    <toolitem action='match-only-read-articles' />\n"
 "    <toolitem action='match-only-cached-articles' />\n"
 "    <toolitem action='match-only-binary-articles' />\n"
 "    <toolitem action='match-only-my-articles' />\n"
diff --git a/pan/icons/Makefile.am b/pan/icons/Makefile.am
index 1209d7e..7804d3c 100644
--- a/pan/icons/Makefile.am
+++ b/pan/icons/Makefile.am
@@ -18,6 +18,7 @@ stock_images = \
 	icon_filter_only_attachments.png \
 	icon_filter_only_cached.png \
 	icon_filter_only_me.png \
+	icon_filter_only_read.png \
 	icon_filter_only_unread.png \
 	icon_filter_only_watched.png \
 	icon_get_dialog.png \
diff --git a/pan/tasks/nntp.cc b/pan/tasks/nntp.cc
index 92e2834..0d52cc5 100644
--- a/pan/tasks/nntp.cc
+++ b/pan/tasks/nntp.cc
@@ -76,34 +76,20 @@ NNTP :: on_socket_response (Socket * sock UNUSED, const StringView& line_in)
    enum State { CMD_FAIL, CMD_DONE, CMD_MORE, CMD_NEXT, CMD_RETRY };
    State state;
    StringView line (line_in);
-
-   //check for compression
-   _compression = strcasestr (line.str, COMPRESS_GZIP);
+   std::string old_line = line;
 
    // strip off trailing \r\n
    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;
-   if (_compression)
-   {
-      //check if we're done
-      if (strcasestr (line_in.str, ".\r\n") != 0)
-      {
-        if (_listener)
-          _listener->on_nntp_line (this, line);
-        line = ".";
-        state = CMD_DONE;
-      }
-   }
-   else if (_nntp_response_text)
+   if (_nntp_response_text)
    {
       if (line.len==1 && line.str[0]=='.') // end-of-list
       {
          state = CMD_DONE;
          _nntp_response_text = false;
       }
-      else
+      else if (!_compression)
       {
          state = CMD_MORE;
 
@@ -114,144 +100,164 @@ NNTP :: on_socket_response (Socket * sock UNUSED, const StringView& line_in)
          if (_listener)
             _listener->on_nntp_line (this, line);
       }
+
+      if (_compression)
+      {
+        state = CMD_MORE;
+        assert (_listener != 0);
+        if (_listener)
+          _listener->on_nntp_line (this, line_in);
+        if (line_in.len >= 3 && line_in.strstr(".\r\n"))
+        {
+          _compression = false;
+          _nntp_response_text = false;
+          line = ".";
+        }
+      }
    }
-   else switch (atoi (line.str))
+   else
    {
-      case SERVER_READY:
-      case SERVER_READY_NO_POSTING:
-      case SERVER_READY_STREAMING_OK:
-         state = CMD_DONE;
-         break;
+     //check for compression
+     _compression = strcasestr (line_in.str, COMPRESS_GZIP);
+
+     switch (atoi (line.str))
+     {
+        case SERVER_READY:
+        case SERVER_READY_NO_POSTING:
+        case SERVER_READY_STREAMING_OK:
+           state = CMD_DONE;
+           break;
+
+        case ARTICLE_POSTED_OK:
+        case GOODBYE:
+        case XOVER_NO_ARTICLES:
+           state = CMD_DONE;
+           break;
+
+        case AUTH_REQUIRED: { // must send username
+           if (!_username.empty()) {
+             _commands.push_front (_previous_command);
+             _socket->write_command_va (this, "AUTHINFO USER %s\r\n", _username.c_str());
+             state = CMD_NEXT;
+           } else {
+             std::string host;
+             _socket->get_host (host);
+             Log::add_err_va (_("%s requires a username, but none is set."), host.c_str());
+             state = CMD_FAIL;
+           }
+           break;
+        }
 
-      case ARTICLE_POSTED_OK:
-      case GOODBYE:
-      case XOVER_NO_ARTICLES:
-         state = CMD_DONE;
-         break;
+        case AUTH_NEED_MORE: { // must send password
+          if (!_password.empty()) {
+             _socket->write_command_va (this, "AUTHINFO PASS %s\r\n", _password.c_str());
+             state = CMD_NEXT;
+          } else {
+             std::string host;
+             _socket->get_host (host);
+             Log::add_err_va (_("%s requires a password, but none is set."), host.c_str());
+             state = CMD_FAIL;
+          }
+          break;
+        }
 
-      case AUTH_REQUIRED: { // must send username
-         if (!_username.empty()) {
-           _commands.push_front (_previous_command);
-           _socket->write_command_va (this, "AUTHINFO USER %s\r\n", _username.c_str());
+        case AUTH_ACCEPTED:
+           // try to enable compression xfeature
+           _socket->write_command (ENABLE_COMPRESS_GZIP, this);
            state = CMD_NEXT;
-         } else {
-           std::string host;
-           _socket->get_host (host);
-           Log::add_err_va (_("%s requires a username, but none is set."), host.c_str());
-           state = CMD_FAIL;
-         }
-         break;
-      }
+           break;
+
+        case FEATURE_ENABLED:
+           state= CMD_DONE;
+           break;
+
+        case GROUP_RESPONSE: {
+           // response is of form "211 qty low high group_name"
+           StringView tok, myline (line);
+           myline.pop_token (tok, ' ');
+           myline.pop_token (tok, ' ');
+           const unsigned long aqty (strtoul (tok.str, NULL, 10));
+           myline.pop_token (tok, ' ');
+           const unsigned long alo (strtoul (tok.str, NULL, 10));
+           myline.pop_token (tok, ' ');
+           const unsigned long ahi (strtoul (tok.str, NULL, 10));
+           myline.pop_token (tok, ' ');
+           const pan::Quark group (tok);
+           if (_listener)
+              _listener->on_nntp_group (this, group, aqty, alo, ahi);
+           _group = group;
+            state = CMD_DONE;
+           break;
+        }
 
-      case AUTH_NEED_MORE: { // must send password
-        if (!_password.empty()) {
-           _socket->write_command_va (this, "AUTHINFO PASS %s\r\n", _password.c_str());
+        case SEND_ARTICLE_NOW:
+           // ready to get article; send it now
+           _socket->write_command (_post, this);
            state = CMD_NEXT;
-        } else {
+           break;
+
+        case NO_POSTING:
+        case POSTING_FAILED:
+          // if we hit a dupe, we silently continue
+          if (line.strstr("435"))
+          {
+            state = CMD_DONE;
+            break;
+          }
+        case GROUP_NONEXISTENT:
+           state = CMD_FAIL;
+           break;
+
+        case XOVER_FOLLOWS:
+        case ARTICLE_FOLLOWS:
+        case NEWGROUPS_FOLLOWS:
+        case INFORMATION_FOLLOWS:
+           state = CMD_MORE;
+           _nntp_response_text = true;
+           break;
+
+        case AUTH_REJECTED:
+        case NO_GROUP_SELECTED:
+        case ERROR_CMD_NOT_UNDERSTOOD:
+        case ERROR_CMD_NOT_SUPPORTED:
+        case NO_PERMISSION:
+        case FEATURE_NOT_SUPPORTED: {
+           std::string cmd (_previous_command);
+           if (cmd.size()>=2 && cmd[cmd.size()-1]=='\n' && cmd[cmd.size()-2]=='\r')
+             cmd.resize (cmd.size()-2);
            std::string host;
            _socket->get_host (host);
-           Log::add_err_va (_("%s requires a password, but none is set."), host.c_str());
+           Log::add_err_va (_("Sending \"%s\" to %s returned an error: %s"),
+                            cmd.c_str(),
+                            host.c_str(),
+                            line.to_string().c_str());
            state = CMD_FAIL;
+           break;
         }
-        break;
-      }
 
-      case AUTH_ACCEPTED:
-         // try to enable compression xfeature
-         _socket->write_command (ENABLE_COMPRESS_GZIP, this);
-         state = CMD_NEXT;
-         break;
-
-      case FEATURE_ENABLED:
-         state= CMD_DONE;
-         break;
-
-      case GROUP_RESPONSE: {
-         // response is of form "211 qty low high group_name"
-         StringView tok, myline (line);
-         myline.pop_token (tok, ' ');
-         myline.pop_token (tok, ' ');
-         const unsigned long aqty (strtoul (tok.str, NULL, 10));
-         myline.pop_token (tok, ' ');
-         const unsigned long alo (strtoul (tok.str, NULL, 10));
-         myline.pop_token (tok, ' ');
-         const unsigned long ahi (strtoul (tok.str, NULL, 10));
-         myline.pop_token (tok, ' ');
-         const pan::Quark group (tok);
-         if (_listener)
-            _listener->on_nntp_group (this, group, aqty, alo, ahi);
-         _group = group;
-          state = CMD_DONE;
-         break;
-      }
+        case NO_SUCH_ARTICLE_NUMBER:
+        case NO_SUCH_ARTICLE:
+           state = CMD_FAIL;
+           break;
 
-      case SEND_ARTICLE_NOW:
-         // ready to get article; send it now
-         _socket->write_command (_post, this);
-         state = CMD_NEXT;
-         break;
+        case TOO_MANY_CONNECTIONS:
+           state = CMD_RETRY;
+           break;
 
-      case NO_POSTING:
-      case POSTING_FAILED:
-        // if we hit a dupe, we silently continue
-        if (line.strstr("435"))
-        {
-          state = CMD_DONE;
-          break;
+        default: {
+           std::string cmd (_previous_command);
+           if (cmd.size()>=2 && cmd[cmd.size()-1]=='\n' && cmd[cmd.size()-2]=='\r')
+             cmd.resize (cmd.size()-2);
+           std::string host;
+           _socket->get_host (host);
+           Log::add_err_va (_("Sending \"%s\" to %s returned an unrecognized response: \"%s\""),
+                            _previous_command.c_str(),
+                            host.c_str(),
+                            line.to_string().c_str());
+           state = CMD_FAIL;
+           break;
         }
-      case GROUP_NONEXISTENT:
-         state = CMD_FAIL;
-         break;
-
-      case XOVER_FOLLOWS:
-      case ARTICLE_FOLLOWS:
-      case NEWGROUPS_FOLLOWS:
-      case INFORMATION_FOLLOWS:
-         state = CMD_MORE;
-         _nntp_response_text = true;
-         break;
-
-      case AUTH_REJECTED:
-      case NO_GROUP_SELECTED:
-      case ERROR_CMD_NOT_UNDERSTOOD:
-      case ERROR_CMD_NOT_SUPPORTED:
-      case NO_PERMISSION:
-      case FEATURE_NOT_SUPPORTED: {
-         std::string cmd (_previous_command);
-         if (cmd.size()>=2 && cmd[cmd.size()-1]=='\n' && cmd[cmd.size()-2]=='\r')
-           cmd.resize (cmd.size()-2);
-         std::string host;
-         _socket->get_host (host);
-         Log::add_err_va (_("Sending \"%s\" to %s returned an error: %s"),
-                          cmd.c_str(),
-                          host.c_str(),
-                          line.to_string().c_str());
-         state = CMD_FAIL;
-         break;
-      }
-
-      case NO_SUCH_ARTICLE_NUMBER:
-      case NO_SUCH_ARTICLE:
-         state = CMD_FAIL;
-         break;
-
-      case TOO_MANY_CONNECTIONS:
-         state = CMD_RETRY;
-         break;
-
-      default: {
-         std::string cmd (_previous_command);
-         if (cmd.size()>=2 && cmd[cmd.size()-1]=='\n' && cmd[cmd.size()-2]=='\r')
-           cmd.resize (cmd.size()-2);
-         std::string host;
-         _socket->get_host (host);
-         Log::add_err_va (_("Sending \"%s\" to %s returned an unrecognized response: \"%s\""),
-                          _previous_command.c_str(),
-                          host.c_str(),
-                          line.to_string().c_str());
-         state = CMD_FAIL;
-         break;
-      }
+     }
    }
 
    if ((state == CMD_DONE) && !_commands.empty())
diff --git a/pan/tasks/socket-impl-gio.cc b/pan/tasks/socket-impl-gio.cc
index b81c0cb..252d590 100644
--- a/pan/tasks/socket-impl-gio.cc
+++ b/pan/tasks/socket-impl-gio.cc
@@ -338,8 +338,8 @@ GIOChannelSocket :: do_read ()
       debug_v ("read [" << g->str << "]"); // verbose debug, if --debug --debug was on the command-line
       increment_xfer_byte_count (g->len);
 
-      if (g_str_has_suffix (g->str, "\r\n"))
-        g_string_truncate (g, g->len-2);
+      //if (g_str_has_suffix (g->str, "\r\n"))
+      //  g_string_truncate (g, g->len-2);
 
       more = _listener->on_socket_response (this, StringView (g->str, g->len));
       _listener->on_socket_bytes_transferred(g->len, this);
diff --git a/pan/tasks/socket-impl-openssl.cc b/pan/tasks/socket-impl-openssl.cc
index 229788e..2b33479 100644
--- a/pan/tasks/socket-impl-openssl.cc
+++ b/pan/tasks/socket-impl-openssl.cc
@@ -623,8 +623,8 @@ GIOChannelSocketGnuTLS :: do_read ()
 
       debug_v ("read [" << g->str << "]");
       increment_xfer_byte_count (g->len);
-      if (g_str_has_suffix (g->str, "\r\n"))
-        g_string_truncate (g, g->len-2);
+      //if (g_str_has_suffix (g->str, "\r\n"))
+      //  g_string_truncate (g, g->len-2);
       more = _listener->on_socket_response (this, StringView (g->str, g->len));
       //_listener->on_socket_bytes_transferred(g->len, this);
     }
diff --git a/pan/tasks/task-groups.cc b/pan/tasks/task-groups.cc
index d8fae9a..271c082 100644
--- a/pan/tasks/task-groups.cc
+++ b/pan/tasks/task-groups.cc
@@ -21,6 +21,7 @@
 #include <cassert>
 extern "C" {
   #include <glib/gi18n.h>
+  #include <stdlib.h>
 }
 #include <pan/general/debug.h>
 #include <pan/general/macros.h>
@@ -74,18 +75,12 @@ TaskGroups :: use_nntp (NNTP * nntp)
     assert (0);
 }
 
-
 void
 TaskGroups :: on_nntp_line (NNTP               * nntp,
                             const StringView   & line)
 {
   if (nntp->_compression)
-  {
-      std::vector<std::string> lines;
-      compression::deflate_gzip (line, lines);
-      foreach (std::vector<std::string>, lines, it)
-        on_nntp_line_process (nntp, *it);
-  }
+    stream << line;
   else on_nntp_line_process (nntp, line);
 }
 void
@@ -143,7 +138,7 @@ TaskGroups :: on_nntp_line_process (NNTP               * nntp UNUSED,
 void
 TaskGroups :: on_nntp_done (NNTP              * nntp,
                             Health              health,
-                            const StringView  & response UNUSED)
+                            const StringView  & response)
 {
   debug ("groups task got an on_nntp_done() from " << nntp->_server);
 
@@ -153,6 +148,15 @@ TaskGroups :: on_nntp_done (NNTP              * nntp,
   }
   else // health is OK or FAIL
   {
+    if (response == ".")
+    {
+      std::vector<std::string> lines;
+      compression::inflate_gzip (&stream, lines);
+      foreach (std::vector<std::string>, lines, it)
+        on_nntp_line_process (nntp, *it);
+      stream.str().clear();
+    }
+
     if (_step == LIST_NEWSGROUPS)
     {
       int i (0);
diff --git a/pan/tasks/task-groups.h b/pan/tasks/task-groups.h
index 4a27c78..b7886eb 100644
--- a/pan/tasks/task-groups.h
+++ b/pan/tasks/task-groups.h
@@ -60,6 +60,8 @@ namespace pan
 
       enum Step { LIST, LIST_NEWSGROUPS, DONE };
       Step _step;
+
+      std::stringstream stream;
   };
 };
 
diff --git a/pan/tasks/task-xover.cc b/pan/tasks/task-xover.cc
index 0dd37a4..912fa3b 100644
--- a/pan/tasks/task-xover.cc
+++ b/pan/tasks/task-xover.cc
@@ -172,9 +172,7 @@ TaskXOver::use_nntp(NNTP* nntp)
       case MiniTask::XOVER:
         debug("XOVER " << mt._low << '-' << mt._high << " to " << server);
         _last_xover_number[nntp] = mt._low;
-        if (comp == HEADER_COMPRESS_XFEATURE)
-          nntp->xfeat(_group, mt._low, mt._high, this);
-        else if (comp == HEADER_COMPRESS_XZVER || comp == HEADER_COMPRESS_DIABLO)
+        if (comp == HEADER_COMPRESS_XZVER || comp == HEADER_COMPRESS_DIABLO)
           nntp->xzver(_group, mt._low, mt._high, this);
         else
           nntp->xover(_group, mt._low, mt._high, this);
@@ -318,17 +316,14 @@ TaskXOver::on_nntp_line(NNTP * nntp, const StringView & line)
   _data.get_server_compression_type(server, comp);
 
   if (comp != HEADER_COMPRESS_NONE)
-    {
-      int sock_id = nntp->_socket->get_id();
-      if (_streams.count(sock_id) == 0)
-        _streams[sock_id] = new std::stringstream();
-      *_streams[sock_id] << line << "\r\n";
-    }
+  {
+    int sock_id = nntp->_socket->get_id();
+    if (_streams.count(sock_id) == 0)
+      _streams[sock_id] = new std::stringstream();
+    *_streams[sock_id] << line << "\r\n";
+  }
   else
-    {
-      on_nntp_line_process(nntp, line);
-    }
-
+    on_nntp_line_process(nntp, line);
 }
 
 void
@@ -464,8 +459,14 @@ TaskXOver::on_nntp_done(NNTP * nntp, Health health, const StringView & response)
     {
       std::stringstream* buffer = _streams[nntp->_socket->get_id()];
       std::stringstream out, out2;
+      if (comp == HEADER_COMPRESS_XZVER || comp == HEADER_COMPRESS_DIABLO)
+      {
       compression::ydecode(buffer, &out);
       compression::inflate_zlib(&out, &out2, comp);
+      }
+      else
+        compression::inflate_zlib(buffer, &out2, comp);
+
       char buf1[4096];
       while (!out2.getline(buf1, sizeof(buf1)).eof())
         {
diff --git a/pan/usenet-utils/filter-info.cc b/pan/usenet-utils/filter-info.cc
index f83b939..21e525c 100644
--- a/pan/usenet-utils/filter-info.cc
+++ b/pan/usenet-utils/filter-info.cc
@@ -142,6 +142,11 @@ FilterInfo :: set_type_score_le (unsigned long le)
    set_type_le (SCORE_GE, le);
 }
 void
+FilterInfo :: set_type_is_read ()
+{
+   set_type_is (IS_READ);
+}
+void
 FilterInfo :: set_type_is_unread ()
 {
    set_type_is (IS_UNREAD);
@@ -182,7 +187,7 @@ FilterInfo :: describe () const
   {
     ret = _("the article was posted by you");
   }
-  else if (_type==IS_UNREAD && _negate)
+  else if (_type==IS_READ)
   {
     ret = _("the article has been read");
   }
diff --git a/pan/usenet-utils/filter-info.h b/pan/usenet-utils/filter-info.h
index 408b6ae..32e3967 100644
--- a/pan/usenet-utils/filter-info.h
+++ b/pan/usenet-utils/filter-info.h
@@ -43,6 +43,7 @@ namespace pan
         IS_BINARY,
         IS_CACHED,
         IS_POSTED_BY_ME,
+        IS_READ,
         IS_UNREAD,
         BYTE_COUNT_GE,
         CROSSPOST_COUNT_GE,
@@ -103,6 +104,7 @@ namespace pan
       void set_type_line_count_ge (unsigned long ge);
       void set_type_score_ge (unsigned long ge);
       void set_type_score_le (unsigned long le);
+      void set_type_is_read ();
       void set_type_is_unread ();
       void set_type_posted_by_me ();
       void set_type_text (const Quark& header,const TextMatch::Description&);



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