[pan: 2/7] Add in specific types for article numbers and counts




commit 9d800a4a6fe7cfa25717da7aa1c1ecb747b424e0
Author: Thomas Tanner <thosrtanner googlemail com>
Date:   Wed Jun 22 07:36:35 2022 +0100

    Add in specific types for article numbers and counts

 README.mingw64_msys2            |   4 +-
 pan/data-impl/article-filter.cc |   2 +-
 pan/data-impl/data-impl.h       |  24 ++---
 pan/data-impl/groups.cc         |  28 +++---
 pan/data-impl/headers.cc        |  22 ++---
 pan/data-impl/xover.cc          |   4 +-
 pan/data/data.cc                |   7 +-
 pan/data/data.h                 |  24 ++---
 pan/data/xref.cc                |  12 +--
 pan/data/xref.h                 |  13 +--
 pan/general/Makefile.am         |   2 +
 pan/general/article_number.cc   |  54 +++++++++++
 pan/general/article_number.h    | 193 ++++++++++++++++++++++++++++++++++++++++
 pan/gui/group-pane.cc           |  27 +++---
 pan/gui/group-pane.h            |  10 +--
 pan/gui/gui.cc                  |   4 +-
 pan/gui/pan.cc                  |   6 +-
 pan/gui/post-ui.cc              |   2 +-
 pan/tasks/nntp.cc               |  20 ++---
 pan/tasks/nntp.h                | 107 +++++++++++-----------
 pan/tasks/nzb.cc                |   2 +-
 pan/tasks/task-article.cc       |   6 +-
 pan/tasks/task-upload.cc        |  12 ++-
 pan/tasks/task-xover.cc         |  48 ++++------
 pan/tasks/task-xover.h          |  18 ++--
 pan/tasks/task-xoverinfo.cc     |  41 +--------
 pan/tasks/task-xoverinfo.h      |  26 +++---
 pan/usenet-utils/numbers.cc     |  36 ++++----
 pan/usenet-utils/numbers.h      |  29 +++---
 29 files changed, 495 insertions(+), 288 deletions(-)
---
diff --git a/README.mingw64_msys2 b/README.mingw64_msys2
index 7e6e95f..ce095db 100644
--- a/README.mingw64_msys2
+++ b/README.mingw64_msys2
@@ -5,7 +5,7 @@ See https://www.mingw-w64.org/
     https://www.msys2.org/
 
 Install msys2 as per instructions. You will also need to install
-$ pacman -S mingw-w64-x86_64-pcre mingw-w64-x86_64-gmime
+$ pacman -S mingw-w64-x86_64-pcre mingw-w64-x86_64-gmime autoconf-archive
 
 Also for the sake of your own sanity, add 'export MSYS=winsymlinks:native' to your .bash_profile
 
@@ -21,7 +21,7 @@ You also need some dictionaries to spell check against!
 $ pacman -S mingw-w64-x86_64-hunspell-en
 
 and this (possibly optional, but...)
-$ pacman -S mingw-w64-x86_64-iso-codes (possibly: /mingw64/share/xml, /mingw64/share/locale)
+$ pacman -S mingw-w64-x86_64-iso-codes
 
 Then you can create an msys2 x64 window and run
 
diff --git a/pan/data-impl/article-filter.cc b/pan/data-impl/article-filter.cc
index f424738..37b2f6c 100644
--- a/pan/data-impl/article-filter.cc
+++ b/pan/data-impl/article-filter.cc
@@ -159,7 +159,7 @@ ArticleFilter :: test_article (const Data        & data,
             s += xit->group;
             s += ':';
             char buf[32];
-            g_snprintf (buf, sizeof(buf), "%" G_GUINT64_FORMAT, xit->number);
+            g_snprintf (buf, sizeof(buf), "%" G_GUINT64_FORMAT, static_cast<uint64_t>(xit->number));
             s += buf;
             s += ' ';
           }
diff --git a/pan/data-impl/data-impl.h b/pan/data-impl/data-impl.h
index 9389a5b..f1148cc 100644
--- a/pan/data-impl/data-impl.h
+++ b/pan/data-impl/data-impl.h
@@ -248,22 +248,22 @@ namespace pan
          */
         struct Server {
           Numbers _read;
-          uint64_t _xover_high;
+          Article_Number _xover_high;
           Server(): _xover_high(0) {}
         };
         typedef Loki::AssocVector<Quark,Server> servers_t;
         servers_t _servers;
 
-        unsigned long _article_count;
-        unsigned long _unread_count;
+        Article_Count _article_count;
+        Article_Count _unread_count;
 
         ReadGroup(): _article_count(0), _unread_count(0) {}
 
         Server& operator[](const Quark& s) { return _servers[s]; }
 
-        static void decrement_safe (unsigned long& lhs, unsigned long dec) { lhs = (lhs>dec) ? lhs-dec : 0; }
-        void decrement_unread (unsigned long dec) { decrement_safe (_unread_count, dec); }
-        void decrement_count (unsigned long dec) { decrement_safe (_article_count, dec); }
+        static void decrement_safe (Article_Count &lhs, Article_Count dec) { lhs = lhs>dec ? lhs-dec : 
static_cast<Article_Count>(0); }
+        void decrement_unread (Article_Count dec) { decrement_safe (_unread_count, dec); }
+        void decrement_count (Article_Count dec) { decrement_safe (_article_count, dec); }
 
         Server* find_server (const Quark& s) {
           servers_t::iterator it (_servers.find (s));
@@ -328,8 +328,8 @@ namespace pan
       virtual void get_subscribed_groups (std::vector<Quark>&) const;
       virtual void get_other_groups (std::vector<Quark>&) const;
       virtual void get_group_counts (const Quark    & group,
-                                     unsigned long  & setme_unread,
-                                     unsigned long  & setme_total) const;
+                                     Article_Count  & setme_unread,
+                                     Article_Count  & setme_total) const override;
       virtual char get_group_permission (const Quark & group) const;
       virtual void group_get_servers (const Quark& group, quarks_t&) const;
       virtual void server_get_groups (const Quark& server, quarks_t&) const;
@@ -662,16 +662,16 @@ namespace pan
 
       virtual void xover_unref   (const Quark           & group);
 
-      virtual uint64_t get_xover_high (const Quark & group,
-                                       const Quark & server) const;
+      virtual Article_Number get_xover_high (const Quark & group,
+                                       const Quark & server) const override;
 
       virtual void set_xover_high (const Quark          & group,
                                    const Quark          & server,
-                                   const uint64_t         high);
+                                   const Article_Number   high) override;
 
        virtual void set_xover_low (const Quark          & group,
                                    const Quark          & server,
-                                   const uint64_t         low);
+                                   const Article_Number   low) override;
 
 
     /**
diff --git a/pan/data-impl/groups.cc b/pan/data-impl/groups.cc
index 8a8755e..31ae2c5 100644
--- a/pan/data-impl/groups.cc
+++ b/pan/data-impl/groups.cc
@@ -370,12 +370,12 @@ DataImpl :: load_group_xovers (const DataIO& data_io)
       if (line.pop_token(groupname) && line.pop_token(total) && line.pop_token(unread))
       {
         ReadGroup& g (_read_groups[groupname]);
-        g._article_count = strtoul (total.str, NULL, 10);
-        g._unread_count = strtoul (unread.str, NULL, 10);
+        g._article_count = Article_Count(total);
+        g._unread_count = Article_Count(unread);
 
         while (line.pop_token (xover))
           if (xover.pop_token(servername,':'))
-            g[servername]._xover_high = g_ascii_strtoull (xover.str, NULL, 10);
+            g[servername]._xover_high = Article_Number(xover);
       }
     }
   }
@@ -433,10 +433,10 @@ DataImpl :: save_group_xovers (DataIO& data_io) const
   xgroups_t xgroups;
   foreach_const (read_groups_t, _read_groups, git) {
     const ReadGroup& group (git->second);
-    bool is_xgroup (group._article_count || group._unread_count);
+    bool is_xgroup (static_cast<uint64_t>(group._article_count) != 0 || 
static_cast<uint64_t>(group._unread_count) != 0);
     if (!is_xgroup)
       foreach_const (ReadGroup::servers_t, group._servers, sit)
-        if ((is_xgroup = (sit->second._xover_high!=0)))
+        if ((is_xgroup = (static_cast<uint64_t>(sit->second._xover_high)!=0)))
           break;
     if (is_xgroup)
       xgroups.insert (git->first);
@@ -455,7 +455,7 @@ DataImpl :: save_group_xovers (DataIO& data_io) const
     out.put (' ');
     out << g._unread_count;
     foreach_const (ReadGroup::servers_t, g._servers, i) {
-      if (i->second._xover_high) {
+      if (static_cast<uint64_t>(i->second._xover_high) != 0) {
         out.put (' ');
         out << i->first;
         out.put (':');
@@ -472,11 +472,11 @@ DataImpl :: save_group_xovers (DataIO& data_io) const
 *****
 ****/
 
-uint64_t
+Article_Number
 DataImpl :: get_xover_high (const Quark  & groupname,
                             const Quark  & servername) const
 {
-  uint64_t high (0ul);
+  Article_Number high (0ul);
   const ReadGroup::Server * rgs (find_read_group_server (groupname, servername));
   if (rgs)
     high = rgs->_xover_high;
@@ -486,7 +486,7 @@ DataImpl :: get_xover_high (const Quark  & groupname,
 void
 DataImpl :: set_xover_high (const Quark & group,
                             const Quark & server,
-                            const uint64_t high)
+                            const Article_Number high)
 {
   //std::cerr << LINE_ID << "setting " << get_server_address(server) << ':' << group << " xover high to " << 
high << std::endl;
   ReadGroup::Server& rgs (_read_groups[group][server]);
@@ -587,9 +587,9 @@ DataImpl :: mark_group_read (const Quark& groupname)
   if (rg != 0) {
     foreach (ReadGroup::servers_t, rg->_servers, it) {
       //std::cerr << LINE_ID << " marking read range [0..." << it->second._xover_high << "] in " << 
get_server_address(it->first) << ']' << std::endl;
-      it->second._read.mark_range (0, it->second._xover_high, true);
+      it->second._read.mark_range (static_cast<Article_Number>(0), it->second._xover_high, true);
     }
-    rg->_unread_count = 0;
+    rg->_unread_count = static_cast<Article_Count>(0);
     save_group_xovers (*_data_io);
     fire_group_read (groupname);
   }
@@ -620,12 +620,12 @@ DataImpl :: get_group_description (const Quark& group) const
 
 void
 DataImpl :: get_group_counts (const Quark   & groupname,
-                              unsigned long & unread_count,
-                              unsigned long & article_count) const
+                              Article_Count & unread_count,
+                              Article_Count & article_count) const
 {
   const ReadGroup * g (find_read_group (groupname));
   if (!g)
-    unread_count = article_count = 0ul;
+    unread_count = article_count = static_cast<Article_Count>(0ul);
   else {
     unread_count = g->_unread_count;
     article_count = g->_article_count;
diff --git a/pan/data-impl/headers.cc b/pan/data-impl/headers.cc
index 9906122..f3723c7 100644
--- a/pan/data-impl/headers.cc
+++ b/pan/data-impl/headers.cc
@@ -426,8 +426,8 @@ DataImpl :: load_headers (const DataIO   & data_io,
   GroupHeaders * h (get_group_headers (group));
   assert (h != 0);
 
-  unsigned long article_count (0);
-  unsigned long unread_count (0);
+  Article_Count article_count (0);
+  Article_Count unread_count (0);
   StringView line;
   bool success (false);
   quarks_t servers;
@@ -535,7 +535,7 @@ DataImpl :: load_headers (const DataIO   & data_io,
           if (tok.pop_token(server_tok,':') && tok.pop_token(group_tok,':')) {
             target_it->server = server_tok;
             target_it->group = group_tok.len==1 ? xref_lookup[(int)*group_tok.str] : Quark(group_tok);
-            target_it->number = g_ascii_strtoull (tok.str, NULL, 10);
+            target_it->number = Article_Number(tok);
             const Server * server (find_server (target_it->server));
             if (server && ((!server->article_expiration_age) || (days_old <= 
server->article_expiration_age)))
               ++target_it;
@@ -625,9 +625,9 @@ DataImpl :: load_headers (const DataIO   & data_io,
   if (success) {
     const double seconds = timer.get_seconds_elapsed ();
     Log::add_info_va (
-      _("Loaded %lu articles for \"%s\" in %.1f seconds (%.0f per second)"),
-      article_count, group.c_str(), seconds,
-      article_count/(fabs(seconds)<0.001?0.001:seconds));
+      _("Loaded %llu articles for \"%s\" in %.1f seconds (%.0f per second)"),
+      static_cast<uint64_t>(article_count), group.c_str(), seconds,
+      static_cast<uint64_t>(article_count)/(fabs(seconds)<0.001?0.001:seconds));
   }
 }
 
@@ -908,7 +908,7 @@ DataImpl :: mark_read (const Article  ** articles,
   foreach_const (group_to_changed_mids_t, group_to_changed_mids, it) {
     const Quark& group (it->first);
     ReadGroup& g (_read_groups[group]);
-    const size_t n (it->second.size());
+    const Article_Count n{it->second.size()};
     if (read)
       g.decrement_unread (n);
     else
@@ -1085,8 +1085,8 @@ namespace
   /** used by delete_articles */
   struct PerGroup {
     quarks_t mids;
-    int unread;
-    int count;
+    Article_Count unread;
+    Article_Count count;
     PerGroup(): unread(0), count(0) {}
   };
 }
@@ -1114,8 +1114,8 @@ DataImpl :: group_clear_articles (const Quark& group)
 
   // fire a 'count changed' event.
   ReadGroup& g (_read_groups[group]);
-  g._article_count = 0;
-  g._unread_count = 0;
+  g._article_count = static_cast<Article_Count>(0);
+  g._unread_count = static_cast<Article_Count>(0);
   fire_group_counts (group, g._unread_count, g._article_count);
 }
 
diff --git a/pan/data-impl/xover.cc b/pan/data-impl/xover.cc
index 6bc4703..dfd2fda 100644
--- a/pan/data-impl/xover.cc
+++ b/pan/data-impl/xover.cc
@@ -213,11 +213,11 @@ DataImpl :: xover_unref (const Quark& group)
 void
 DataImpl :: set_xover_low (const Quark   & group,
                            const Quark   & server,
-                           const uint64_t   low)
+                           const Article_Number   low)
 {
   ReadGroup::Server * rgs (find_read_group_server (group, server));
   if (rgs != 0)
-    rgs->_read.mark_range (0, low, true);
+    rgs->_read.mark_range (static_cast<Article_Number>(0), low, true);
 }
 
 const Article*
diff --git a/pan/data/data.cc b/pan/data/data.cc
index 26f1e83..5362fda 100644
--- a/pan/data/data.cc
+++ b/pan/data/data.cc
@@ -50,10 +50,11 @@ Data :: fire_grouplist_rebuilt ()
 }
 
 void
-Data :: fire_group_counts (const Quark& group, unsigned long unread, unsigned long total)
+Data :: fire_group_counts (const Quark& group, Article_Count unread, Article_Count total)
 {
-  for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; )
+  for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; ) {
     (*it++)->on_group_counts (group, unread, total);
+  }
 }
 
 void
@@ -78,7 +79,7 @@ Data :: fire_article_flag_changed (articles_t& a, const Quark& group)
 }
 
 void
-Data :: fire_group_entered (const Quark& group, unsigned long unread, unsigned long total)
+Data :: fire_group_entered (const Quark& group, Article_Count unread, Article_Count total)
 {
   for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; )
     (*it++)->on_group_entered (group, unread, total);
diff --git a/pan/data/data.h b/pan/data/data.h
index d39a842..33749c8 100644
--- a/pan/data/data.h
+++ b/pan/data/data.h
@@ -308,12 +308,12 @@ namespace pan
         virtual void on_group_subscribe (const Quark & group UNUSED,
                                          bool          sub   UNUSED) {}
         virtual void on_group_counts (const Quark& group   UNUSED,
-                                      unsigned long unread UNUSED,
-                                      unsigned long total  UNUSED) {}
+                                      Article_Count unread UNUSED,
+                                      Article_Count total  UNUSED) {}
 
         virtual void on_group_entered (const Quark& group   UNUSED,
-                                      unsigned long unread UNUSED,
-                                      unsigned long total  UNUSED) {}
+                                      Article_Count unread UNUSED,
+                                      Article_Count total  UNUSED) {}
 
         /* listener for article flag, don't call too often */
         virtual void on_article_flag_changed (articles_t& a UNUSED, const Quark& group UNUSED) {}
@@ -330,8 +330,8 @@ namespace pan
       void fire_group_read (const Quark&);
 
       void fire_group_counts (const Quark&,
-                              unsigned long unread,
-                              unsigned long total);
+                              Article_Count unread,
+                              Article_Count total);
 
       void fire_group_subscribe (const Quark&, bool);
 
@@ -343,7 +343,7 @@ namespace pan
     public:
 
       virtual void fire_article_flag_changed (articles_t& a, const Quark& group);
-      virtual void fire_group_entered (const Quark& group, unsigned long unread, unsigned long total);
+      virtual void fire_group_entered (const Quark& group, Article_Count unread, Article_Count total);
 
     /*****************************************************************
     ***
@@ -401,8 +401,8 @@ namespace pan
        * from previous xover sessions.
        */
       virtual void get_group_counts (const Quark   & group,
-                                     unsigned long & setme_unread,
-                                     unsigned long & setme_total) const=0;
+                                     Article_Count & setme_unread,
+                                     Article_Count & setme_total) const=0;
 
       virtual char get_group_permission (const Quark & group) const=0;
 
@@ -670,7 +670,7 @@ namespace pan
        * run on the specified {server,group}, or 0 if it's never
        * been run there.
        */
-      virtual uint64_t get_xover_high (const Quark  & group,
+      virtual Article_Number get_xover_high (const Quark  & group,
                                        const Quark  & server) const = 0;
 
        /**
@@ -681,7 +681,7 @@ namespace pan
         */
        virtual void set_xover_high (const Quark         & group,
                                     const Quark         & server,
-                                    const uint64_t    high) = 0;
+                                    const Article_Number    high) = 0;
 
        /**
         * Used to fold the Newsrc ranges together:
@@ -690,7 +690,7 @@ namespace pan
         */
        virtual void set_xover_low (const Quark         & group,
                                    const Quark         & server,
-                                   const uint64_t   low) = 0;
+                                   const Article_Number   low) = 0;
 
       /** Sets the queue interface */
       virtual void set_queue (Queue* q) = 0;
diff --git a/pan/data/xref.cc b/pan/data/xref.cc
index 1b27886..d2190f5 100644
--- a/pan/data/xref.cc
+++ b/pan/data/xref.cc
@@ -41,7 +41,7 @@ Xref :: insert (const Quark             & server,
     xref.trim ();
   }
 
-  // walk through the xrefs, of format "group1:number group2:number" 
+  // walk through the xrefs, of format "group1:number group2:number"
   targets.reserve (targets.size() + std::count(xref.begin(), xref.end(), ':'));
   StringView s;
   while (xref.pop_token (s)) {
@@ -51,7 +51,7 @@ Xref :: insert (const Quark             & server,
         Target t;
         t.server = server;
         t.group = group_name;
-        t.number = g_ascii_strtoull (s.str, NULL, 10);
+        t.number = Article_Number(s);
         targets.get_container().push_back (t);
       }
     }
@@ -74,7 +74,7 @@ Xref :: remove_server (const Quark& server)
 void
 Xref :: remove_targets_less_than (const Quark    & server,
                                   const Quark    & group,
-                                  uint64_t         n)
+                                  Article_Number   n)
 {
   std::vector<Target> t;
   t.reserve (targets.size());
@@ -106,7 +106,7 @@ Xref :: has_server (const Quark  & server) const
 bool
 Xref :: find (const Quark    & server,
               Quark          & setme_group,
-              uint64_t       & setme_number) const
+              Article_Number & setme_number) const
 {
   Target tmp;
   tmp.server = server;
@@ -119,7 +119,7 @@ Xref :: find (const Quark    & server,
   return found;
 }
 
-uint64_t
+Article_Number
 Xref :: find_number (const Quark    & server,
                      const Quark    & group) const
 {
@@ -127,7 +127,7 @@ Xref :: find_number (const Quark    & server,
   tmp.server = server;
   tmp.group = group;
   const_iterator it (targets.lower_bound (tmp));
-  return it!=targets.end() && it->server==server && it->group==group ? it->number : 0ul;
+  return it!=targets.end() && it->server==server && it->group==group ? it->number : 
static_cast<Article_Number>(0ull);
 }
 
 void
diff --git a/pan/data/xref.h b/pan/data/xref.h
index 81943e9..2b9df25 100644
--- a/pan/data/xref.h
+++ b/pan/data/xref.h
@@ -24,6 +24,7 @@
 #include <algorithm>
 #include <pan/general/quark.h>
 #include <pan/general/sorted-vector.h>
+#include <pan/general/article_number.h>
 
 namespace pan
 {
@@ -48,7 +49,7 @@ namespace pan
       {
         Quark server;
         Quark group;
-        uint64_t number;
+        Article_Number number;
 
         Target (): number(0ul) { }
         bool operator== (const Target& t) const
@@ -58,7 +59,7 @@ namespace pan
           if (group != t.group) return group < t.group;
           return false;
         }
-        Target (const Quark& sq, const Quark& gq, uint64_t n):
+        Target (const Quark& sq, const Quark& gq, Article_Number n):
           server (sq), group (gq), number (n) { }
       };
 
@@ -71,15 +72,15 @@ namespace pan
     public:
       unsigned long size () const { return targets.size(); }
       bool empty () const { return targets.empty(); }
-      uint64_t find_number (const Quark& server, const Quark& group) const;
-      bool find (const Quark& server, Quark& setme_group, uint64_t& setme_number) const;
+      Article_Number find_number (const Quark& server, const Quark& group) const;
+      bool find (const Quark& server, Quark& setme_group, Article_Number& setme_number) const;
       bool has_server (const Quark& server) const;
       void get_servers (quarks_t& addme) const;
 
     public:
       void clear () { targets.clear(); }
       void remove_server (const Quark& server);
-      void remove_targets_less_than (const Quark& s, const Quark& g, uint64_t less_than_this);
+      void remove_targets_less_than (const Quark& s, const Quark& g, Article_Number less_than_this);
 
     public:
 
@@ -87,7 +88,7 @@ namespace pan
         targets.insert (a, b);
       }
       void insert (const Target& target) { targets.insert (target); }
-      void insert (const Quark& s, const Quark& g, uint64_t n) {targets.insert (Target(s,g,n));} 
+      void insert (const Quark& s, const Quark& g, Article_Number n) {targets.insert (Target(s,g,n));}
       void insert (const Xref& xref) { insert (xref.begin(), xref.end()); }
 
       template<typename ForwardIterator> void assign (ForwardIterator a, ForwardIterator b) {
diff --git a/pan/general/Makefile.am b/pan/general/Makefile.am
index ca0eb68..a41eb5e 100644
--- a/pan/general/Makefile.am
+++ b/pan/general/Makefile.am
@@ -4,6 +4,7 @@ AM_LDFLAGS = @GTK_LIBS@
 noinst_LIBRARIES = libgeneralutils.a
 
 libgeneralutils_a_SOURCES = \
+ article_number.cc \
  debug.cc \
  e-util.cc \
  editor-spawner.cc \
@@ -19,6 +20,7 @@ libgeneralutils_a_SOURCES = \
  compression.cc
 
 noinst_HEADERS = \
+ article_number.h \
  compression.h \
  debug.h \
  defgroup.h \
diff --git a/pan/general/article_number.cc b/pan/general/article_number.cc
new file mode 100644
index 0000000..bb78305
--- /dev/null
+++ b/pan/general/article_number.cc
@@ -0,0 +1,54 @@
+#include "article_number.h"
+
+#include <pan/general/string-view.h>
+
+#include <glib.h>
+
+#include <ostream>
+
+namespace pan {
+
+Article_Count::Article_Count(StringView const &str)
+{
+  if (str.empty())
+  {
+    val_ = 0;
+  }
+  else
+  {
+    char *end;
+    val_ = g_ascii_strtoull(str.str, &end, 10);
+    //Error checking?
+    //*end != 0
+    //val = max and errno set to E_RANGE
+  }
+}
+
+std::ostream &operator<<(std::ostream &os, Article_Count a)
+{
+  return os << static_cast<Article_Count::type>(a);
+}
+
+Article_Number::Article_Number(StringView const &str)
+{
+  if (str.empty())
+  {
+    val_ = 0;
+  }
+  else
+  {
+    char *end;
+    val_ = g_ascii_strtoull(str.str, &end, 10);
+    //Error checking?
+    //*end != 0
+    //val = max and errno set to E_RANGE
+  }
+}
+
+std::ostream &operator<<(std::ostream &os, Article_Number a)
+{
+  return os << static_cast<Article_Number::type>(a);
+}
+
+
+}
diff --git a/pan/general/article_number.h b/pan/general/article_number.h
new file mode 100644
index 0000000..2729319
--- /dev/null
+++ b/pan/general/article_number.h
@@ -0,0 +1,193 @@
+#ifndef article_number_h
+#define article_number_h
+
+#include <stdint.h>
+#include <iosfwd>
+
+namespace pan {
+
+struct StringView;
+
+//This one is a count of articles, and hence not the same as an article number at all
+class Article_Count
+{
+  public:
+    typedef uint64_t type;
+
+    Article_Count() : val_(0) {}
+
+    explicit Article_Count(type x) : val_(x) {}
+
+    explicit Article_Count(StringView const &);
+
+    explicit operator unsigned long long () const { return val_; }
+
+    Article_Count &operator=(Article_Count const &val)
+    {
+      val_ = val.val_;
+      return *this;
+    }
+
+    Article_Count operator+(type n) const
+    {
+      Article_Count res;
+      res.val_ = val_ + n;
+      return res;
+    }
+
+    Article_Count operator-(type n) const
+    {
+      Article_Count res;
+      res.val_ = val_ - n;
+      return res;
+    }
+
+    Article_Count operator-=(Article_Count const &sub) const
+    {
+      return static_cast<Article_Count>(val_ - sub.val_);
+    }
+
+    Article_Count & operator+=(Article_Count const &rhs)
+    {
+        val_ += rhs.val_;
+        return *this;
+    }
+
+    Article_Count & operator+=(type const &rhs)
+    {
+        val_ += rhs;
+        return *this;
+    }
+
+    Article_Count & operator++()
+    {
+      val_ += 1;
+      return *this;
+    }
+
+    Article_Count operator-(Article_Count const &rhs) const
+    {
+      Article_Count res(val_);
+      return res - rhs.val_;
+    }
+
+  private:
+    type val_;
+};
+
+inline bool operator==(Article_Count const &lhs, Article_Count const &rhs)
+{
+  return static_cast<Article_Count::type>(lhs) == static_cast<Article_Count::type>(rhs);
+}
+
+inline bool operator!=(Article_Count const &lhs, Article_Count const &rhs)
+{
+  return static_cast<Article_Count::type>(lhs) != static_cast<Article_Count::type>(rhs);
+}
+
+inline bool operator>=(Article_Count const &lhs, Article_Count const &rhs)
+{
+  return static_cast<Article_Count::type>(lhs) >= static_cast<Article_Count::type>(rhs);
+}
+
+inline bool operator<=(Article_Count const &lhs, Article_Count const &rhs)
+{
+  return static_cast<Article_Count::type>(lhs) <= static_cast<Article_Count::type>(rhs);
+}
+
+inline bool operator<(Article_Count const &lhs, Article_Count const &rhs)
+{
+  return static_cast<Article_Count::type>(lhs) < static_cast<Article_Count::type>(rhs);
+}
+
+inline bool operator>(Article_Count const &lhs, Article_Count const &rhs)
+{
+  return static_cast<Article_Count::type>(lhs) > static_cast<Article_Count::type>(rhs);
+}
+
+std::ostream &operator<<(std::ostream &os, Article_Count a);
+
+/** An article number needs a specific size.
+ * Some groups can have way over 4 billion articles.
+ */
+//typedef uint64_t Article_Number;
+class Article_Number {
+  public:
+    typedef uint64_t type;
+    Article_Number() : val_(0) {}
+    explicit Article_Number(type x) : val_(x) {}
+    explicit Article_Number(StringView const &);
+
+    explicit operator unsigned long long () const { return val_; }
+
+    Article_Number &operator=(Article_Number const &val)
+    {
+      val_ = val.val_;
+      return *this;
+    }
+
+    Article_Number operator+(type n) const
+    {
+      Article_Number res;
+      res.val_ = val_ + n;
+      return res;
+    }
+
+    Article_Number operator-(type n) const
+    {
+      Article_Number res;
+      res.val_ = val_ - n;
+      return res;
+    }
+
+    Article_Count operator-(Article_Number const &rhs) const
+    {
+      Article_Count res(val_);
+      return res - rhs.val_;
+    }
+
+    Article_Number &operator+=(type n)
+    {
+      val_ += n;
+      return *this;
+    }
+
+  private:
+    type val_;
+};
+
+inline bool operator==(Article_Number const &lhs, Article_Number const &rhs)
+{
+  return static_cast<Article_Number::type>(lhs) == static_cast<Article_Number::type>(rhs);
+}
+
+inline bool operator!=(Article_Number const &lhs, Article_Number const &rhs)
+{
+  return static_cast<Article_Number::type>(lhs) != static_cast<Article_Number::type>(rhs);
+}
+
+inline bool operator<(Article_Number const &lhs, Article_Number const &rhs)
+{
+  return static_cast<Article_Number::type>(lhs) < static_cast<Article_Number::type>(rhs);
+}
+
+inline bool operator<=(Article_Number const &lhs, Article_Number const &rhs)
+{
+  return static_cast<Article_Number::type>(lhs) <= static_cast<Article_Number::type>(rhs);
+}
+
+inline bool operator>(Article_Number const &lhs, Article_Number const &rhs)
+{
+  return static_cast<Article_Number::type>(lhs) > static_cast<Article_Number::type>(rhs);
+}
+
+inline bool operator>=(Article_Number const &lhs, Article_Number const &rhs)
+{
+  return static_cast<Article_Number::type>(lhs) >= static_cast<Article_Number::type>(rhs);
+}
+
+std::ostream &operator<<(std::ostream &os, Article_Number a);
+
+}
+
+#endif
diff --git a/pan/gui/group-pane.cc b/pan/gui/group-pane.cc
index 459dd08..134714a 100644
--- a/pan/gui/group-pane.cc
+++ b/pan/gui/group-pane.cc
@@ -48,12 +48,15 @@ namespace
   {
     public:
       Quark groupname;
-      unsigned long unread;
+      Article_Count unread;
 
     public:
       virtual void get_value (int column, GValue* setme) {
         switch (column) {
-          case COL_UNREAD: set_value_ulong (setme, unread); break;
+          //
+          //FIXME Really?
+          //
+          case COL_UNREAD: set_value_ulong (setme, static_cast<uint64_t>(unread)); break;
         }
       }
   };
@@ -370,7 +373,7 @@ namespace
                MyRow *rows(new MyRow [n]), *r(rows);
                g_object_weak_ref (G_OBJECT(store), delete_rows, rows);
 
-               unsigned long unused;
+               Article_Count unused;
                for (size_t i(0); i!=n; ++i, ++r)
                {
                        r->groupname = folders_groupnames[i];
@@ -395,7 +398,7 @@ namespace
       MyRow *rows(new MyRow [n]), *r(rows);
       g_object_weak_ref (G_OBJECT(store), delete_rows, rows);
 
-      unsigned long unused;
+      Article_Count unused;
       for (size_t i(0); i!=n; ++i, ++r) {
         r->groupname = sub[i];
         data.get_group_counts (r->groupname, r->unread, unused);
@@ -420,7 +423,7 @@ namespace
       MyRow *rows(new MyRow[n]), *r(rows);
       g_object_weak_ref (G_OBJECT(store), delete_rows, rows);
 
-      unsigned long unused;
+      Article_Count unused;
       for (size_t i(0); i!=n; ++i, ++r) {
         r->groupname = unsub[i];
         data.get_group_counts (r->groupname, r->unread, unused);
@@ -489,7 +492,7 @@ GroupPane :: refresh_dirty_groups ()
     MyRow * row (find_row (*it));
     if (row)
     {
-      unsigned long unused;
+      Article_Count unused;
       _data.get_group_counts (row->groupname, row->unread, unused);
       _tree_store->row_changed (row);
     }
@@ -514,7 +517,7 @@ GroupPane :: on_group_read (const Quark& groupname)
        _dirty_groups_idle_tag = g_timeout_add (333, dirty_groups_idle, this);
 }
 void
-GroupPane :: on_group_counts (const Quark& groupname, unsigned long, unsigned long)
+GroupPane :: on_group_counts (const Quark& groupname, Article_Count, Article_Count)
 {
   on_group_read (groupname);
 }
@@ -739,16 +742,16 @@ namespace
     GroupPane* pane (static_cast<GroupPane*>(gp));
     PanTreeStore * tree (PAN_TREE_STORE(model));
     MyRow * row (dynamic_cast<MyRow*>(tree->get_row (iter)));
-    const unsigned long& unread (row->unread);
+    const Article_Count & unread (row->unread);
     //const unsigned long& total (row->total);
     const Quark& name (row->groupname);
 
     const bool is_g (is_group(name));
     const bool do_shorten (shorten && is_g);
     std::string group_name (do_shorten ? get_short_name(StringView(name)) : name.to_string());
-    if (is_g && unread) {
+    if (is_g && static_cast<uint64_t>(unread) != 0) {
       char buf[64];
-      g_snprintf (buf, sizeof(buf), " (%lu)", unread);
+      g_snprintf (buf, sizeof(buf), " (%llu)", static_cast<uint64_t>(unread));
       group_name += buf;
     }
 
@@ -765,7 +768,7 @@ namespace
         bg_col = def_bg;
 
     g_object_set (renderer, "text", group_name.c_str(),
-                            "weight", (!is_g || unread ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL),
+                            "weight", (!is_g || static_cast<uint64_t>(unread) != 0 ? PANGO_WEIGHT_BOLD : 
PANGO_WEIGHT_NORMAL),
                             "foreground", fg_col.empty() ? NULL : fg_col.c_str(),
                             "background", bg_col.empty() ? NULL : bg_col.c_str(),
                             NULL);
@@ -834,7 +837,7 @@ GroupPane :: find_next_subscribed_group (bool unread_only)
     gtk_tree_model_iter_nth_child (model, &group_iter, &sub_iter, n);
     const MyRow * row (dynamic_cast<MyRow*>(_tree_store->get_row (&group_iter)));
     const bool is_virtual (is_virtual_group(row->groupname));
-    if (!is_virtual && (row->unread || !unread_only))
+    if (!is_virtual && (static_cast<uint64_t>(row->unread) != 0 || !unread_only))
       return gtk_tree_model_get_path (model, &group_iter);
   }
 
diff --git a/pan/gui/group-pane.h b/pan/gui/group-pane.h
index 362320c..989ec50 100644
--- a/pan/gui/group-pane.h
+++ b/pan/gui/group-pane.h
@@ -37,12 +37,12 @@ namespace pan
   class GroupPane: private Data::Listener, private Prefs::Listener
   {
     protected: // Data::Listener
-      virtual void on_grouplist_rebuilt ();
-      virtual void on_group_read (const Quark& group);
-      virtual void on_group_subscribe (const Quark& group, bool sub);
+      virtual void on_grouplist_rebuilt () override;
+      virtual void on_group_read (const Quark& group) override;
+      virtual void on_group_subscribe (const Quark& group, bool sub) override;
       virtual void on_group_counts (const Quark& group,
-                                    unsigned long unread,
-                                    unsigned long total);
+                                    Article_Count unread,
+                                    Article_Count total) override;
 
     public:
       GroupPane (ActionManager&, Data&, Prefs&, GroupPrefs&);
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index 55110ad..bf1ebe5 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -2041,14 +2041,14 @@ void GUI :: do_read_selected_group ()
 
   // if it's the first time in this group, pop up a download-headers dialog.
   // otherwise if get-new-headers is turned on, queue an xover-new task.
-  unsigned long unread(0), total(0);
+  Article_Count unread(0), total(0);
 
   if (changed && !group.empty()){
     _data.get_group_counts (group, unread, total);
     const bool virtual_group (GroupPane::is_virtual_group(group));
     if (!virtual_group)
     {
-      if (!total)
+      if (static_cast<uint64_t>(total) == 0)
         activate_action ("download-headers");
       else if (_prefs.get_flag("get-new-headers-when-entering-group", true)) {
         if (_prefs.get_flag ("mark-group-read-before-xover", false))
diff --git a/pan/gui/pan.cc b/pan/gui/pan.cc
index 301c86f..b016836 100644
--- a/pan/gui/pan.cc
+++ b/pan/gui/pan.cc
@@ -422,13 +422,13 @@ namespace
       notify_of(ICON_STATUS_ERROR, message.str, _("An error has occurred!"));
     }
 
-    virtual void on_queue_size_changed (Queue&, unsigned long, unsigned long) {}
+    //virtual void on_queue_size_changed (Queue&, unsigned long, unsigned long) {}
 
     /* data::listener */
-    virtual void on_group_entered (const Quark& group, unsigned long unread, unsigned long total)
+    virtual void on_group_entered (const Quark& group, Article_Count unread, Article_Count total) override
     {
 
-      if (unread)
+      if (static_cast<uint64_t>(unread) != 0)
       {
         update_status_icon(ICON_STATUS_NEW_ARTICLES);
         if (n()) return;
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index b7417cc..bc274ac 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -3286,7 +3286,7 @@ PostUI :: prompt_user_for_queueable_files (GtkWindow * parent, const Prefs& pref
       a.subject = subject;
       a.author = author;
       foreach_const (quarks_t, groups, git)
-         a.xref.insert (profile.posting_server, *git,0);
+         a.xref.insert (profile.posting_server, *git, static_cast<Article_Number>(0));
       ui.total = get_total_parts((const char*)cur->data);
       tmp = new TaskUpload((const char*)cur->data,
                         profile.posting_server, _cache, a, ui, msg);
diff --git a/pan/tasks/nntp.cc b/pan/tasks/nntp.cc
index 394d946..2774bdf 100644
--- a/pan/tasks/nntp.cc
+++ b/pan/tasks/nntp.cc
@@ -214,11 +214,11 @@ NNTP :: on_socket_response (Socket * sock UNUSED, const StringView& line_in)
           StringView myline(line);
           myline.pop_token(tok, ' ');
           myline.pop_token(tok, ' ');
-          uint64_t const aqty{strtoull(tok.str, NULL, 10)};
+          Article_Count const aqty{tok};
           myline.pop_token(tok, ' ');
-          uint64_t const alo{strtoull(tok.str, NULL, 10)};
+          Article_Number const alo{tok};
           myline.pop_token(tok, ' ');
-          uint64_t const ahi{strtoull(tok.str, NULL, 10)};
+          Article_Number const ahi{tok};
           myline.pop_token(tok, ' ');
           Quark const group{tok};
           if (_listener) {
@@ -384,8 +384,8 @@ NNTP :: enter_group (const Quark& group)
 
 void
 NNTP :: xover (const Quark   & group,
-               uint64_t        low,
-               uint64_t        high,
+               Article_Number  low,
+               Article_Number  high,
                Listener      * l)
 {
    _listener = l;
@@ -397,8 +397,8 @@ NNTP :: xover (const Quark   & group,
 
 void
 NNTP :: xzver (const Quark   & group,
-               uint64_t        low,
-               uint64_t        high,
+               Article_Number  low,
+               Article_Number  high,
                Listener      * l)
 {
    _listener = l;
@@ -438,7 +438,7 @@ NNTP :: list (Listener * l)
 
 void
 NNTP :: article (const Quark     & group,
-                 uint64_t          article_number,
+                 Article_Number  article_number,
                  Listener        * l)
 {
    _listener = l;
@@ -480,7 +480,7 @@ NNTP :: get_headers (const Quark     & group,
 
 void
 NNTP :: get_headers (const Quark     & group,
-                     uint64_t          article_number,
+                     Article_Number    article_number,
                      Listener        * l)
 {
    _listener = l;
@@ -508,7 +508,7 @@ NNTP :: get_body (const Quark     & group,
 
 void
 NNTP :: get_body (const Quark     & group,
-                  uint64_t          article_number,
+                  Article_Number  article_number,
                   Listener        * l)
 {
    _listener = l;
diff --git a/pan/tasks/nntp.h b/pan/tasks/nntp.h
index 737cac9..04d89e0 100644
--- a/pan/tasks/nntp.h
+++ b/pan/tasks/nntp.h
@@ -29,67 +29,62 @@
 #include <pan/tasks/socket.h>
 #include <pan/data/data.h>
 
-namespace
-{
-   enum
-   {
-      AUTH_REQUIRED              = 480,
-      AUTH_NEED_MORE             = 381,
-      AUTH_ACCEPTED              = 281,
-      AUTH_REJECTED              = 482,
+namespace pan {
 
-      SERVER_READY               = 200,
-      SERVER_READY_NO_POSTING    = 201,
-      SERVER_READY_STREAMING_OK  = 203,
 
-      GOODBYE                    = 205,
+  /**
+   * Asynchronously processes NNTP protocol commands.
+   *
+   * @ingroup tasks
+   */
+  class NNTP: private Socket::Listener
+  {
+    public:
 
-      GROUP_RESPONSE             = 211,
-      GROUP_NONEXISTENT          = 411,
+      enum {
+        AUTH_REQUIRED              = 480,
+        AUTH_NEED_MORE             = 381,
+        AUTH_ACCEPTED              = 281,
+        AUTH_REJECTED              = 482,
 
-      INFORMATION_FOLLOWS        = 215,
+        SERVER_READY               = 200,
+        SERVER_READY_NO_POSTING    = 201,
+        SERVER_READY_STREAMING_OK  = 203,
 
-      XOVER_FOLLOWS              = 224,
-      XOVER_NO_ARTICLES          = 420,
+        GOODBYE                    = 205,
 
-      ARTICLE_FOLLOWS            = 220,
+        GROUP_RESPONSE             = 211,
+        GROUP_NONEXISTENT          = 411,
 
-      NEWGROUPS_FOLLOWS          = 231,
+        INFORMATION_FOLLOWS        = 215,
 
-      ARTICLE_POSTED_OK          = 240,
+        XOVER_FOLLOWS              = 224,
+        XOVER_NO_ARTICLES          = 420,
 
-      FEATURE_ENABLED            = 290,
+        ARTICLE_FOLLOWS            = 220,
 
-      SEND_ARTICLE_NOW           = 340,
-      NO_POSTING                 = 440,
-      POSTING_FAILED             = 441,
-      DUPE_ARTICLE               = 435,  // sent additionally to 441
+        NEWGROUPS_FOLLOWS          = 231,
 
-      TOO_MANY_CONNECTIONS       = 400,
+        ARTICLE_POSTED_OK          = 240,
 
-      NO_GROUP_SELECTED          = 412,
-      NO_SUCH_ARTICLE_NUMBER     = 423,
-      NO_SUCH_ARTICLE            = 430,
+        FEATURE_ENABLED            = 290,
 
-      ERROR_CMD_NOT_UNDERSTOOD   = 500,
-      ERROR_CMD_NOT_SUPPORTED    = 501,
-      NO_PERMISSION              = 502,
-      FEATURE_NOT_SUPPORTED      = 503
-   };
+        SEND_ARTICLE_NOW           = 340,
+        NO_POSTING                 = 440,
+        POSTING_FAILED             = 441,
+        DUPE_ARTICLE               = 435,  // sent additionally to 441
 
-   const char* EOL = ".";
-}
+        TOO_MANY_CONNECTIONS       = 400,
 
-namespace pan
-{
-  /**
-   * Asynchronously processes NNTP protocol commands.
-   *
-   * @ingroup tasks
-   */
-  class NNTP: private Socket::Listener
-  {
-    public:
+        NO_GROUP_SELECTED          = 412,
+        NO_SUCH_ARTICLE_NUMBER     = 423,
+        NO_SUCH_ARTICLE            = 430,
+
+        ERROR_CMD_NOT_UNDERSTOOD   = 500,
+        ERROR_CMD_NOT_SUPPORTED    = 501,
+        NO_PERMISSION              = 502,
+        FEATURE_NOT_SUPPORTED      = 503
+      };
 
       /**
        * Base class for objects that listen for NNTP events.
@@ -141,9 +136,9 @@ namespace pan
          */
         virtual void on_nntp_group (NNTP               * nntp          UNUSED,
                                     const Quark        & group         UNUSED,
-                                    unsigned long        estimated_qty UNUSED,
-                                    uint64_t             low           UNUSED,
-                                    uint64_t             high
+                                    Article_Count        estimated_qty UNUSED,
+                                    Article_Number       low           UNUSED,
+                                    Article_Number       high
                                            UNUSED) {}
 
        };
@@ -174,9 +169,9 @@ namespace pan
       /* Internal only */
       void enter_group (const Quark& group);
       void get_headers (const Quark & group, const char * message_id, Listener  * l);
-      void get_headers (const Quark & group, uint64_t article_number, Listener * l);
+      void get_headers (const Quark & group, Article_Number article_number, Listener * l);
       void get_body (const Quark & group, const char * message_id, Listener  * l);
-      void get_body (const Quark & group, uint64_t article_number, Listener * l);
+      void get_body (const Quark & group, Article_Number article_number, Listener * l);
       /**
        * Lists all available commands.
        */
@@ -200,13 +195,13 @@ namespace pan
        * command is successful or not.
        */
       void xover            (const Quark        & group,
-                             uint64_t             low,
-                             uint64_t             high,
+                             Article_Number       low,
+                             Article_Number       high,
                              Listener           * l);
 
       void xzver            (const Quark        & group,
-                             uint64_t             low,
-                             uint64_t             high,
+                             Article_Number       low,
+                             Article_Number       high,
                              Listener           * l);
 
       /**
@@ -259,7 +254,7 @@ namespace pan
        * to change groups.
        */
       void article          (const Quark        & group,
-                             uint64_t             article_number,
+                             Article_Number     article_number,
                              Listener           * l);
 
       /**
diff --git a/pan/tasks/nzb.cc b/pan/tasks/nzb.cc
index 3677404..da3d7d6 100644
--- a/pan/tasks/nzb.cc
+++ b/pan/tasks/nzb.cc
@@ -169,7 +169,7 @@ namespace
         quarks_t servers;
         mc.gs.group_get_servers (*git, servers);
         foreach_const (quarks_t, servers, sit)
-          mc.a.xref.insert (*sit, *git, 0);
+          mc.a.xref.insert (*sit, *git, static_cast<Article_Number>(0));
       }
       const StringView p (mc.path.empty() ? mc.fallback_path : StringView(mc.path));
       /// TODO get action mark read from prefs (?)
diff --git a/pan/tasks/task-article.cc b/pan/tasks/task-article.cc
index c29c143..80dc69e 100644
--- a/pan/tasks/task-article.cc
+++ b/pan/tasks/task-article.cc
@@ -143,7 +143,7 @@ TaskArticle :: TaskArticle (const ServerRank          & server_rank,
     // `ARTICLE message-id' instead when talking to the server.
     foreach_const (quarks_t, servers, sit)
       foreach_const (quarks_t, groups, git)
-        n.xref.insert (*sit, *git, mid==article.message_id.to_string() ? article.xref.find_number(*sit,*git) 
: 0);
+        n.xref.insert (*sit, *git, mid==article.message_id.to_string() ? article.xref.find_number(*sit,*git) 
: static_cast<Article_Number>(0));
     _needed.push_back (n);
   }
 
@@ -239,9 +239,9 @@ TaskArticle :: use_nntp (NNTP * nntp)
     needed->buf.clear ();
 
     Quark group;
-    uint64_t number (0ul);
+    Article_Number number (0ul);
     needed->xref.find (nntp->_server, group, number);
-    if (number)
+    if (static_cast<uint64_t>(number) != 0)
       nntp->article (group, number, this);
     else
       nntp->article (group, needed->message_id.c_str(), this);
diff --git a/pan/tasks/task-upload.cc b/pan/tasks/task-upload.cc
index 554a4f9..f8f3d60 100644
--- a/pan/tasks/task-upload.cc
+++ b/pan/tasks/task-upload.cc
@@ -304,12 +304,13 @@ TaskUpload :: on_nntp_done (NNTP * nntp,
 
   switch (atoi(response.str))
   {
-    case NO_POSTING:
+    case NNTP::NO_POSTING:
       Log :: add_err_va (_("Posting of file %s (part %d of %d) failed: No posts allowed by server."),
                  _basename.c_str(), it->second.partno,  _total_parts);
       this->stop();
       break;
-    case POSTING_FAILED:
+
+    case NNTP::POSTING_FAILED:
       if (health != OK)     // if we got a dupe, the health is OK, so skip that
       {
         tmp.severity = Log :: PAN_SEVERITY_ERROR;
@@ -319,7 +320,8 @@ TaskUpload :: on_nntp_done (NNTP * nntp,
         _logfile.push_front(tmp);
       }
       break;
-    case ARTICLE_POSTED_OK:
+
+    case NNTP::ARTICLE_POSTED_OK:
       tmp.severity = Log :: PAN_SEVERITY_INFO;
       if (post_ok && !_needed.empty())
       {
@@ -353,10 +355,12 @@ TaskUpload :: on_nntp_done (NNTP * nntp,
         _logfile.clear();
       }
       break;
-    case TOO_MANY_CONNECTIONS:
+
+    case NNTP::TOO_MANY_CONNECTIONS:
       // lockout for 120 secs, but try
       it->second.reset();
       break;
+
     default:
       _needed.erase (it);
       Log::add_entry_list (tmp, _logfile);
diff --git a/pan/tasks/task-xover.cc b/pan/tasks/task-xover.cc
index cdfdeaf..40dc254 100644
--- a/pan/tasks/task-xover.cc
+++ b/pan/tasks/task-xover.cc
@@ -138,7 +138,7 @@ TaskXOver::~TaskXOver()
         }
       _data.xover_unref (_group);
     }
-  _data.fire_group_entered(_group, 1, 0);
+  _data.fire_group_entered(_group, static_cast<Article_Count>(1), static_cast<Article_Count>(0));
 }
 
 void
@@ -196,8 +196,8 @@ TaskXOver::use_nntp(NNTP* nntp)
  ***/
 
 void
-TaskXOver::on_nntp_group(NNTP * nntp, const Quark & group, unsigned long qty,
-    uint64_t low, uint64_t high)
+TaskXOver::on_nntp_group(NNTP * nntp, const Quark & group, Article_Count qty,
+    Article_Number low, Article_Number high)
 {
   const Quark& servername(nntp->_server);
   CompressionType comp;
@@ -213,21 +213,22 @@ TaskXOver::on_nntp_group(NNTP * nntp, const Quark & group, unsigned long qty,
   debug(
       "got GROUP result from " << nntp->_server << " (" << nntp << "): " << " qty " << qty << " low " << low 
<< " high " << high);
 
-  uint64_t l(low), h(high);
+  Article_Number l(low), h(high);
   _data.set_xover_low(group, nntp->_server, low);
   //std::cerr << LINE_ID << " This group's range is [" << low << "..." << high << ']' << std::endl;
 
+  //Is this right for N days? There is a request to fetch last N days.
   if (_mode == ALL || _mode == DAYS)
     l = low;
   else if (_mode == SAMPLE)
     {
-      _sample_size = std::min(_sample_size, high - low);
+      _sample_size = std::min(_sample_size, static_cast<uint64_t>(high - low));
       //std::cerr << LINE_ID << " and I want to sample " <<  _sample_size << " messages..." << std::endl;
       l = std::max(low, high + 1 - _sample_size);
     }
   else
     { // NEW
-      uint64_t xh(_data.get_xover_high(group, nntp->_server));
+      Article_Number xh(_data.get_xover_high(group, nntp->_server));
       //std::cerr << LINE_ID << " current xover high is " << xh << std::endl;
       l = std::max(xh + 1, low);
     }
@@ -235,7 +236,7 @@ TaskXOver::on_nntp_group(NNTP * nntp, const Quark & group, unsigned long qty,
   if (l <= high)
     {
       //std::cerr << LINE_ID << " okay, I'll try to get articles in [" << l << "..." << h << ']' << 
std::endl;
-      add_steps(h - l);
+      add_steps(static_cast<uint64_t>(h - l));
       const int INCREMENT(compression_enabled ? 10000 : 1000);
       MiniTasks_t& minitasks(_server_to_minitasks[servername]);
       //Unfortunately we need to push everything to the front of the list, so
@@ -244,8 +245,8 @@ TaskXOver::on_nntp_group(NNTP * nntp, const Quark & group, unsigned long qty,
       //on resumption we can resume from where we left off. Therefore, we build
       //a list of things to do in reverse order
       std::vector<MiniTask> tasks;
-      tasks.reserve(h - l);
-      for (uint64_t m = l; m <= h; m += INCREMENT)
+      tasks.reserve(static_cast<uint64_t>(h - l));
+      for (Article_Number m = l; m <= h; m += INCREMENT)
         {
           //A note: It may not be necessary to cap the high here, the spec isn't
           //terribly clear about what happens if new articles come into
@@ -288,21 +289,6 @@ namespace
 
     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)
@@ -346,13 +332,13 @@ TaskXOver::on_nntp_line_process(NNTP * nntp, const StringView & line)
 
   unsigned int lines = 0u;
   unsigned long bytes = 0ul;
-  uint64_t number = 0;
+  Article_Number number(0);
   StringView subj, author, date, mid, tmp, xref, l(line);
   std::string ref;
   bool ok = !l.empty();
   ok = ok && l.pop_token(tmp, '\t');
   if (ok)
-    number = view_to_ull(tmp);
+    number = Article_Number(tmp);
   tmp.clear();
   ok = ok && l.pop_token(subj, '\t');
   if (ok)
@@ -401,7 +387,7 @@ TaskXOver::on_nntp_line_process(NNTP * nntp, const StringView & line)
     }
 
   // is this header corrupt?
-  if (!number // missing number
+  if (static_cast<uint64_t>(number) == 0 // missing number
       || subj.empty() // missing subject
       || author.empty() // missing author
       || date.empty() // missing date
@@ -416,9 +402,9 @@ TaskXOver::on_nntp_line_process(NNTP * nntp, const StringView & line)
        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);
+                               nntp->_server.c_str(), nntp->_group.c_str(), static_cast<uint64_t>(number));
 
-       uint64_t& h(_high[nntp->_server]);
+       Article_Number& h(_high[nntp->_server]);
        h = std::max(h, number);
 
        const char * fallback_charset = NULL; // FIXME
@@ -444,8 +430,8 @@ TaskXOver::on_nntp_line_process(NNTP * nntp, const StringView & line)
                ++_articles_so_far;
 
        // emit a status update
-       uint64_t& prev = _last_xover_number[nntp];
-       increment_step(number - prev);
+       Article_Number& prev = _last_xover_number[nntp];
+       increment_step(static_cast<uint64_t>(number) - static_cast<uint64_t>(prev));
        prev = number;
        if (!(_parts_so_far % 500))
                set_status_va(_("%s (%lu parts, %lu articles)"),
diff --git a/pan/tasks/task-xover.h b/pan/tasks/task-xover.h
index 4091a1b..ad5cebc 100644
--- a/pan/tasks/task-xover.h
+++ b/pan/tasks/task-xover.h
@@ -45,15 +45,15 @@ namespace pan
       virtual ~TaskXOver ();
 
     public: // task subclass
-      virtual unsigned long get_bytes_remaining () const;
+      virtual unsigned long get_bytes_remaining () const override;
 
     protected: // task subclass
-      virtual void use_nntp (NNTP * nntp);
+      virtual void use_nntp (NNTP * nntp) override;
 
     private: // NNTP::Listener
-      virtual void on_nntp_line (NNTP*, const StringView&);
-      virtual void on_nntp_done (NNTP*, Health, const StringView&);
-      virtual void on_nntp_group (NNTP*, const Quark&, unsigned long, uint64_t, uint64_t);
+      virtual void on_nntp_line (NNTP*, const StringView&) override;
+      virtual void on_nntp_done (NNTP*, Health, const StringView&) override;
+      virtual void on_nntp_group (NNTP*, const Quark&, Article_Count, Article_Number, Article_Number) 
override;
 
       void on_nntp_line_process (NNTP*, const StringView&);
 
@@ -61,8 +61,8 @@ namespace pan
       struct MiniTask {
         enum Type { GROUP, XOVER };
         Type _type;
-        uint64_t _low, _high;
-        MiniTask (Type type, uint64_t low=0ul, uint64_t high=0ul):
+        Article_Number _low, _high;
+        MiniTask (Type type, Article_Number low=static_cast<Article_Number>(0ul), Article_Number 
high=static_cast<Article_Number>(0ul)):
           _type(type), _low(low), _high(high) {}
       };
       typedef std::deque<MiniTask> MiniTasks_t;
@@ -77,11 +77,11 @@ namespace pan
       uint64_t _sample_size;
       time_t _days_cutoff;
       bool _group_xover_is_reffed;
-      typedef std::map<Quark,uint64_t> server_to_high_t;
+      typedef std::map<Quark,Article_Number> server_to_high_t;
       server_to_high_t _high;
       void update_work (bool subtract_one_from_nntp_count=false);
       std::set<Quark> _servers_that_got_xover_minitasks;
-      std::map<NNTP*,uint64_t> _last_xover_number;
+      std::map<NNTP*, Article_Number> _last_xover_number;
       unsigned long _bytes_so_far;
       unsigned long _parts_so_far;
       unsigned long _articles_so_far;
diff --git a/pan/tasks/task-xoverinfo.cc b/pan/tasks/task-xoverinfo.cc
index 0cd4147..6649779 100644
--- a/pan/tasks/task-xoverinfo.cc
+++ b/pan/tasks/task-xoverinfo.cc
@@ -94,7 +94,7 @@ TaskXOverInfo :: TaskXOverInfo (Data         & data,
 
   // add a ``GROUP'' MiniTask for each server that has this group
   // initialize the _high lookup table to boundaries
-  const MiniTask group_minitask (MiniTask::GROUP);
+  const MiniTask group_minitask (MiniTask::GROUP, static_cast<Article_Number>(0ul), 
static_cast<Article_Number>(0ul));
   quarks_t servers;
   _data.group_get_servers (group, servers);
 
@@ -103,7 +103,7 @@ TaskXOverInfo :: TaskXOverInfo (Data         & data,
     if (_data.get_server_limits(*it))
     {
       _server_to_minitasks[*it].push_front (group_minitask);
-      std::pair<uint64_t,uint64_t>& p (xovers[*it]);
+      std::pair<Article_Number,Article_Number>& p (xovers[*it]);
       p.first = data.get_xover_high (group, *it);
     }
   }
@@ -128,43 +128,6 @@ TaskXOverInfo :: use_nntp (NNTP* nntp)
 ****
 ***/
 
-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
 TaskXOverInfo :: on_nntp_line         (NNTP               * nntp,
                                        const StringView   & line)
diff --git a/pan/tasks/task-xoverinfo.h b/pan/tasks/task-xoverinfo.h
index d144f55..2645bbb 100644
--- a/pan/tasks/task-xoverinfo.h
+++ b/pan/tasks/task-xoverinfo.h
@@ -40,28 +40,32 @@ namespace pan
   {
     public: // life cycle
 
-      typedef std::pair<uint64_t,uint64_t> xover_t;
+      typedef std::pair<Article_Number,Article_Number> xover_t;
 
       TaskXOverInfo (Data& data, const Quark& group, std::map<Quark,xover_t>& xovers);
       virtual ~TaskXOverInfo ();
 
     public: // task subclass
-      virtual unsigned long get_bytes_remaining () const { return 0ul; }
+      virtual unsigned long get_bytes_remaining () const override { return 0ul; }
 
     protected: // task subclass
-      virtual void use_nntp (NNTP * nntp);
+      virtual void use_nntp (NNTP * nntp) override;
 
     private: // NNTP::Listener
-      virtual void on_nntp_line (NNTP*, const StringView&);
-      virtual void on_nntp_done (NNTP*, Health, const StringView&);
-      virtual void on_nntp_group (NNTP*, const Quark&, unsigned long, uint64_t, uint64_t);
+      virtual void on_nntp_line (NNTP*, const StringView&) override;
+      virtual void on_nntp_done (NNTP*, Health, const StringView&) override;
+      virtual void on_nntp_group (NNTP*,
+                                  const Quark&,
+                                  Article_Count,
+                                  Article_Number,
+                                  Article_Number) override;
 
     private: // implementation - minitasks
       struct MiniTask {
         enum Type { GROUP, XOVER };
         Type _type;
-        uint64_t _low, _high;
-        MiniTask (Type type, uint64_t low=0ul, uint64_t high=0ul):
+        Article_Number _low, _high;
+        MiniTask (Type type, Article_Number low, Article_Number high):
           _type(type), _low(low), _high(high) {}
       };
       typedef std::deque<MiniTask> MiniTasks_t;
@@ -72,16 +76,16 @@ namespace pan
       Data& _data;
       const Quark _group;
       std::string _short_group_name;
-      typedef std::map<Quark,uint64_t> server_to_high_t;
+      typedef std::map<Quark, Article_Number> server_to_high_t;
       server_to_high_t _high;
       void update_work (bool subtract_one_from_nntp_count=false);
       std::set<Quark> _servers_that_got_xover_minitasks;
-      std::map<NNTP*,uint64_t> _last_xover_number;
+      std::map<NNTP*, Article_Number> _last_xover_number;
       unsigned long _bytes_so_far;
       unsigned long _parts_so_far;
       unsigned long _articles_so_far;
       unsigned long _total_minitasks;
-      std::map<Quark,xover_t>& _xovers;
+      std::map<Quark, xover_t>& _xovers;
 
 
   };
diff --git a/pan/usenet-utils/numbers.cc b/pan/usenet-utils/numbers.cc
index fa5c1d7..120de08 100644
--- a/pan/usenet-utils/numbers.cc
+++ b/pan/usenet-utils/numbers.cc
@@ -58,13 +58,13 @@ namespace
 };
 
 /**
- * @return the number of articles newly-marked as read 
+ * @return the number of articles newly-marked as read
  */
-uint64_t
+Article_Count
 Numbers :: mark_range (const Range& rr)
 {
    ranges_t::size_type i;
-   uint64_t retval = 0;
+   Article_Count retval{0};
    bool range_found = false;
    ranges_t::size_type low_index (std::lower_bound (_marked.begin(), _marked.end(), rr.low)
                   - _marked.begin());
@@ -86,7 +86,7 @@ Numbers :: mark_range (const Range& rr)
       }
       else if (r.contains (rr)) /* no-op */
       {
-         retval = 0;
+         retval = static_cast<Article_Count>(0);
          range_found = true;
       }
       else if (r.contains (rr.high)) /* change low */
@@ -123,10 +123,10 @@ Numbers :: mark_range (const Range& rr)
    return retval;
 }
 
-uint64_t
+Article_Count
 Numbers :: unmark_range (const Range& ur)
 {
-   uint64_t retval = 0;
+   Article_Count retval{0};
    ranges_t::size_type i;
    ranges_t::size_type low_index (std::lower_bound (_marked.begin(), _marked.end(), ur.low)
                   - _marked.begin());
@@ -173,22 +173,22 @@ Numbers :: unmark_range (const Range& ur)
 ******  MARK (PUBLIC)
 *****/
 
-uint64_t
-Numbers :: mark_range (uint64_t low, uint64_t high, bool add)
+Article_Count
+Numbers :: mark_range (Article_Number low, Article_Number high, bool add)
 {
    const Range r (low, high);
    return add ? mark_range(r) : unmark_range(r);
 }
 
 bool
-Numbers :: mark_one (uint64_t number, bool add)
+Numbers :: mark_one (Article_Number number, bool add)
 {
-   const uint64_t changed_qty (mark_range (number, number, add));
+   const Article_Count changed_qty (mark_range (number, number, add));
 
    if (add)
-      return changed_qty==0;
+      return static_cast<uint64_t>(changed_qty)==0;
    else /* remove */
-      return changed_qty!=0;
+      return static_cast<uint64_t>(changed_qty)!=0;
 }
 
 void
@@ -202,8 +202,8 @@ Numbers :: mark_str (const StringView& str, bool add)
       phigh.pop_token (plow, '-');
       plow.trim ();
       phigh.trim ();
-      const uint64_t low (plow.empty() ? 0 : g_ascii_strtoull (plow.str, NULL, 10));
-      const uint64_t high (phigh.empty() ? low : g_ascii_strtoull (phigh.str, NULL, 10));
+      const Article_Number low{plow};
+      const Article_Number high = phigh.empty() ? low : Article_Number(phigh);
       mark_range (low, high, add);
    }
 }
@@ -219,7 +219,7 @@ Numbers :: clear ()
 *****/
 
 void
-Numbers :: clip (uint64_t low, uint64_t high)
+Numbers :: clip (Article_Number low, Article_Number high)
 {
    r_it it = std::lower_bound (_marked.begin(), _marked.end(), low);
    _marked.erase (_marked.begin(), it);
@@ -238,7 +238,7 @@ Numbers :: clip (uint64_t low, uint64_t high)
 *****/
 
 bool
-Numbers :: is_marked (uint64_t number) const
+Numbers :: is_marked (Article_Number number) const
 {
    r_cit it = std::lower_bound (_marked.begin(), _marked.end(), number);
 
@@ -267,9 +267,9 @@ Numbers :: to_string (std::string & str) const
       Range r (*it);
 
       if (r.low == r.high)
-        bytes = g_snprintf (buf, sizeof(buf), "%" G_GUINT64_FORMAT",", r.low);
+        bytes = g_snprintf (buf, sizeof(buf), "%" G_GUINT64_FORMAT",", static_cast<uint64_t>(r.low));
       else
-         bytes = g_snprintf (buf, sizeof(buf), "%" G_GUINT64_FORMAT"-%" G_GUINT64_FORMAT",", r.low, r.high);
+         bytes = g_snprintf (buf, sizeof(buf), "%" G_GUINT64_FORMAT"-%" G_GUINT64_FORMAT",", 
static_cast<uint64_t>(r.low), static_cast<uint64_t>(r.high));
       temp.append(buf, bytes);
    }
 
diff --git a/pan/usenet-utils/numbers.h b/pan/usenet-utils/numbers.h
index e02882d..acf59d3 100644
--- a/pan/usenet-utils/numbers.h
+++ b/pan/usenet-utils/numbers.h
@@ -23,6 +23,7 @@
 #include <stdint.h>
 #include <vector>
 #include <pan/general/string-view.h>
+#include <pan/general/article_number.h>
 
 class string;
 
@@ -39,35 +40,35 @@ namespace pan
 
       /** Simple two-field struct defining a range. */
       struct Range {
-        uint64_t low;
-        uint64_t high;
+        Article_Number low;
+        Article_Number high;
         bool operator ==(const Range& that) const {
           return low==that.low && high==that.high;
         }
-        Range (): low(0), high(0) {}
-        Range (uint64_t l, uint64_t h): low(l<h?l:h), high(h>l?h:l) {}
-        bool contains (uint64_t point) const {
+        Range (): low(static_cast<Article_Number>(0)), high(static_cast<Article_Number>(0)) {}
+        Range (Article_Number l, Article_Number h): low(l<h?l:h), high(h>l?h:l) {}
+        bool contains (Article_Number point) const {
           return low<=point && point<=high;
         }
         bool contains (const Range& r) const {
           return low<=r.low && r.high<=high;
         }
-        int compare (uint64_t point) const {
+        int compare (Article_Number point) const {
           if (point < low) return -1;
           if (point > high) return 1;
           return 0;
         }
-        bool operator< (uint64_t point) const {
+        bool operator< (Article_Number point) const {
           return high < point;
         }
       };
 
       typedef std::vector<Range> ranges_t;
-      
+
     private:
       ranges_t _marked;
-      uint64_t mark_range (const Range&);
-      uint64_t unmark_range (const Range&);
+      Article_Count mark_range (const Range&);
+      Article_Count unmark_range (const Range&);
 
     public:
       bool operator== (const Numbers& that) const {
@@ -86,7 +87,7 @@ namespace pan
        * @param add true if we're adding the number, false if removing
        * @return the number's previous state in the set.
        */
-      bool mark_one (uint64_t number, bool add=true);
+      bool mark_one (Article_Number number, bool add=true);
 
       /**
        * Add or remove the specified range of numbers from the set.
@@ -97,7 +98,7 @@ namespace pan
        * @param add true if we're adding the numbers, false if removing
        * @return the quantity of numbers whose presence in the set changed.
        */
-      uint64_t mark_range (uint64_t low, uint64_t high, bool add=true);
+      Article_Count mark_range (Article_Number low, Article_Number high, bool add=true);
 
       /**
        * Mark numbers from a text string in to_str() and from_str() fromat.
@@ -109,7 +110,7 @@ namespace pan
       /**
        * @return true if the number is in this set, false otherwise
        */
-      bool is_marked (const uint64_t) const;
+      bool is_marked (const Article_Number) const;
 
       void clear ();
 
@@ -123,7 +124,7 @@ namespace pan
 
     public:
 
-      void clip (const uint64_t low, const uint64_t high);
+      void clip (const Article_Number low, const Article_Number high);
   };
 }
 


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