[pan2/testing: 60/279] first version of upload utility



commit 68b555bf3d7a45ebc04a932383f31c832335f59a
Author: Heinrich Mueller <sphemuel stud informatik uni-erlangen de>
Date:   Thu May 26 22:23:52 2011 +0200

    first version of upload utility

 pan/data/file-queue.cc         |    4 +-
 pan/data/file-queue.h          |    4 +-
 pan/general/file-util.cc       |    2 +-
 pan/general/file-util.h        |    2 +-
 pan/gui/post-ui.cc             |    9 +-
 pan/tasks/encoder.cc           |  232 ++++++++++++++++++++++++++++++++++
 pan/tasks/encoder.h            |  101 +++++++++++++++
 pan/tasks/task-upload.cc       |  274 ++++++++++++++++++++++++++++++++++++++++
 pan/tasks/task-upload.h        |  156 +++++++++++++++++++++++
 pan/tasks/task-weak-ordering.h |    5 +-
 pan/usenet-utils/mime-utils.cc |    6 +-
 pan/usenet-utils/mime-utils.h  |    2 +-
 12 files changed, 782 insertions(+), 15 deletions(-)
---
diff --git a/pan/data/file-queue.cc b/pan/data/file-queue.cc
index 8225cc5..faf09ca 100644
--- a/pan/data/file-queue.cc
+++ b/pan/data/file-queue.cc
@@ -47,10 +47,12 @@ FileQueue :: add (const char* filename,
   static FileData a;
   struct stat sb;
   a.filename = filename;
+  a.basename = g_path_get_basename(filename);
   stat(filename,&sb);
   a.byte_count = sb.st_size;
+  a.part_in_queue = type == END ? _articles_v.size() : 1;
 
-  type == FileQueue::END ?
+  type == END ?
     _articles_v.push_back(a) :
     _articles_v.push_front(a);
 }
diff --git a/pan/data/file-queue.h b/pan/data/file-queue.h
index 87c1ae7..2c37dbc 100644
--- a/pan/data/file-queue.h
+++ b/pan/data/file-queue.h
@@ -47,14 +47,16 @@ namespace pan {
         {
 
           const char     * filename;
+          const char     * basename;
           unsigned long    byte_count;
+          unsigned long part_in_queue;
           FileData() {}
         };
 
         typedef std::list<FileData>::iterator articles_it;
         typedef std::list<FileData> articles_v;
 
-
+     size_t size() { return _articles_v.size(); }
      articles_it end() { return _articles_v.end(); }
      articles_it begin() { return _articles_v.begin(); }
      bool empty() { return _articles_v.empty(); }
diff --git a/pan/general/file-util.cc b/pan/general/file-util.cc
index a38367e..1a90d89 100644
--- a/pan/general/file-util.cc
+++ b/pan/general/file-util.cc
@@ -49,7 +49,7 @@ using namespace pan;
 ***/
 
 std::string
-file :: get_pan_uulib_dir()
+file :: get_uulib_path()
 {
   char * pch (g_build_filename (file::get_pan_home().c_str(), "uulib-encode-cache", NULL));
   file :: ensure_dir_exists (pch);
diff --git a/pan/general/file-util.h b/pan/general/file-util.h
index 7928ce5..25bde1c 100644
--- a/pan/general/file-util.h
+++ b/pan/general/file-util.h
@@ -58,7 +58,7 @@ namespace pan
      */
     std::string get_pan_home ();
 
-    std::string get_pan_uulib_dir();
+    std::string get_uulib_path();
 
     /**
      * If the specified directory doesn't exist, Pan tries to create it.
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index 2c408e2..b569129 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -727,12 +727,9 @@ PostUI :: maybe_post_message (GMimeMessage * message)
 
     for (; it != _file_queue.end(); it, ++it, ++i) {
       GMimeMessage* msg = new_message_from_ui(POSTING);
-      _queue.add_task (new TaskUpload (*it,profile.posting_server,msg
-                                     ,0,TaskUpload::YENC),
-                                     Queue::BOTTOM);
+      _queue.add_task (new TaskUpload (*it,profile.posting_server,msg), Queue::BOTTOM);
     }
-  //dbg
-//    close_window(true); // dont wait for the upload queue
+    close_window(true); // dont wait for the upload queue
   }
 
 
@@ -1090,7 +1087,9 @@ PostUI :: new_message_from_ui (Mode mode)
   GMimeDataWrapper * content_object = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_DEFAULT);
   g_object_unref (stream);
   GMimePart * part = g_mime_part_new ();
+  //todo ??
   pch = g_strdup_printf ("text/plain; charset=%s", charset.c_str());
+
   GMimeContentType * type = g_mime_content_type_new_from_string (pch);
   g_free (pch);
   g_mime_object_set_content_type ((GMimeObject *) part, type); // part owns type now. type isn't refcounted.
diff --git a/pan/tasks/encoder.cc b/pan/tasks/encoder.cc
new file mode 100644
index 0000000..01db2f4
--- /dev/null
+++ b/pan/tasks/encoder.cc
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2007  Charles Kerr <charles rebelbase com>
+ *
+ * This file
+ * Copyright (C) 2007 Calin Culianu <calin ajvar org>
+ * Copyright (C) 2007 Charles Kerr <charles rebelbase com>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <config.h>
+#include <algorithm>
+#include <cerrno>
+#include <ostream>
+#include <fstream>
+extern "C" {
+#  define PROTOTYPES
+#  include <uulib/uudeview.h>
+#  include <glib/gi18n.h>
+};
+#include <pan/general/debug.h>
+#include <pan/general/file-util.h>
+#include <pan/general/macros.h>
+#include <pan/general/utf8-utils.h>
+#include "encoder.h"
+
+using namespace pan;
+
+Encoder :: Encoder (WorkerPool& pool):
+  _worker_pool (pool),
+  _gsourceid (-1)
+{
+}
+
+Encoder :: ~Encoder()
+{
+  disable_progress_update();
+}
+
+/***
+****
+***/
+
+void
+Encoder :: enqueue (TaskUpload                     * task,
+                    const FileQueue::FileData      & file_data,
+                    TaskUpload::EncodeMode           enc)
+
+{
+  disable_progress_update ();
+
+  this->task = task;
+  this->file_data = file_data;
+  this->encode_mode = encode_mode;
+
+  mark_read = false;
+  percent = 0;
+  current_file.clear ();
+  log_infos.clear();
+  log_errors.clear();
+
+  // gentlemen, start your saving...
+  _worker_pool.push_work (this, task, false);
+}
+
+// save article IN A WORKER THREAD to avoid network stalls
+void
+Encoder :: do_work()
+{
+  const int bufsz = 4096;
+  char buf[bufsz], buf2[bufsz];
+  unsigned long cnt(1);
+  crc32_t crcptr;
+
+  FILE* outfile, * infile ;
+
+  std::string uulib(file :: get_uulib_path());
+
+  std::cerr<<"encoder starting...\n";
+
+  enable_progress_update();
+
+    int res;
+    if (((res = UUInitialize())) != UURET_OK)
+    {
+      log_errors.push_back(_("Error initializing uulib")); // log error
+      this->cancel();
+    } else {
+      UUSetMsgCallback (this, uu_log);
+      UUSetBusyCallback (this, uu_busy_poll, 100);
+
+      char* basename = g_path_get_basename(file_data.filename);
+      g_snprintf(buf,bufsz,"%s/%s.%d", uulib.c_str(), basename, cnt);
+      outfile = fopen(buf,"wb");
+      while (1) {
+        res = UUEncodePartial (outfile, NULL, (char*)file_data.filename, YENC_ENCODED,
+              buf, NULL, 0, cnt, 4000, &crcptr);
+        if (outfile) fclose(outfile);
+        if (res == UURET_OK || res != UURET_CONT) break;
+        g_snprintf(buf,bufsz,"%s/%s.%d", uulib.c_str(), basename, ++cnt);
+        outfile = fopen(buf,"wb");
+      }
+
+      if (res != UURET_OK)
+      {
+        g_snprintf(buf, bufsz,
+                   _("Error encoding %s: %s"),
+                   basename,
+                   (res==UURET_IOERR)
+                   ?  file::pan_strerror (UUGetOption (UUOPT_ERRNO, NULL,
+                                                       NULL, 0))
+                   : UUstrerror(res));
+        log_errors.push_back(buf); // log error
+      }
+    UUCleanUp ();
+    }
+  disable_progress_update();
+}
+
+/***
+****
+***/
+
+void
+Encoder :: uu_log (void* data, char* message, int severity)
+{
+  Encoder *self = static_cast<Encoder *>(data);
+  char * pch (g_locale_to_utf8 (message, -1, 0, 0, 0));
+
+  if (severity >= UUMSG_WARNING)
+    self->file_errors.push_back (pch ? pch : message);
+
+  if (severity >= UUMSG_ERROR)
+    self->log_errors.push_back (pch ? pch : message);
+  else if (severity >= UUMSG_NOTE)
+    self->log_infos.push_back (pch ? pch : message);
+
+  g_free (pch);
+}
+
+double
+Encoder :: get_percentage (const uuprogress& p) const
+{
+  static const double WEIGHT_SCANNING = 30;
+  static const double WEIGHT_ENCODING = 70;
+
+  double base = 0;
+
+  if (p.action != UUACT_SCANNING)
+    base += WEIGHT_SCANNING;
+  else {
+    const double percent = (100.0 + p.percent);
+    return base + (percent / (100.0/WEIGHT_SCANNING));
+  }
+
+  if (p.action != UUACT_ENCODING)
+    base += WEIGHT_ENCODING;
+  else {
+    // uudeview's documentation is wrong:
+    // the total percentage isn't (100*partno-percent)/numparts,
+    // it's (100*(partno-1) + percent)/numparts
+    const double percent = ((100.0 * (p.partno-1)) + p.percent) / p.numparts;
+    return base + (percent / (100.0/WEIGHT_ENCODING));
+  }
+
+  return 0;
+}
+
+int
+Encoder :: uu_busy_poll (void * d, uuprogress *p)
+{
+  Encoder * self (static_cast<Encoder*>(d));
+  self->mut.lock();
+  self->percent = self->get_percentage(*p);
+  self->current_file = p->curfile;
+  self->parts  = (int)p->numparts;
+  self->mut.unlock();
+
+  return self->was_cancelled(); // returning true tells uulib to abort
+}
+
+// this is called in the main thread
+gboolean
+Encoder :: progress_update_timer_func (gpointer decoder)
+{
+  Encoder *self = static_cast<Encoder *>(decoder);
+  Task *task = self->task;
+  if (!task || self->was_cancelled()) return false;
+
+  self->mut.lock();
+  const double percent (self->percent);
+  const std::string f (content_to_utf8 (self->current_file));
+  self->mut.unlock();
+
+  task->set_step(int(percent));
+  task->set_status_va (_("Encoding %s"), f.c_str());
+
+  return true; // keep timer func running
+}
+
+/***
+****
+***/
+
+void
+Encoder :: enable_progress_update ()
+{
+  if (_gsourceid == -1)
+      _gsourceid = g_timeout_add(500, progress_update_timer_func, this);
+}
+
+void
+Encoder :: disable_progress_update ()
+{
+  if (_gsourceid > -1) {
+    g_source_remove (_gsourceid);
+    _gsourceid = -1;
+  }
+}
diff --git a/pan/tasks/encoder.h b/pan/tasks/encoder.h
new file mode 100644
index 0000000..7a73893
--- /dev/null
+++ b/pan/tasks/encoder.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2007 Charles Kerr <charles rebelbase com>
+ *
+ * This file
+ * Copyright (C) 2007 Calin Culianu <calin ajvar org>
+ * Copyright (C) 2007 Charles Kerr <charles rebelbase com>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _Encoder_H_
+#define _Encoder_H_
+
+#include <list>
+#include <string>
+#include <vector>
+#include <pan/general/locking.h>
+#include <pan/general/worker-pool.h>
+#include <pan/tasks/task-upload.h>
+extern "C" {
+#  define PROTOTYPES
+#  include <uulib/uudeview.h>
+#  include <uulib/crc32.h>
+};
+
+namespace pan
+{
+  /**
+   * Encodes attachments (YEnc) for posting to usenet groups.
+   *
+   * @author Heinrich Mueller <eddie_v gmx de>
+   * @author Calin Culianu <calin ajvar org>
+   * @author Charles Kerr <charles rebelbase com>
+   * @ingroup tasks
+   * @see Queue
+   * @see TaskArticle
+   */
+  class Encoder: public WorkerPool::Worker
+  {
+    public:
+
+      Encoder (WorkerPool&);
+
+      ~Encoder ();
+
+      typedef std::vector<std::string> strings_t;
+
+      void enqueue (TaskUpload                     * task,
+                    const FileQueue::FileData      & file_data,
+                    TaskUpload::EncodeMode     enc = TaskUpload::YENC);
+
+    public:
+
+      typedef std::list<std::string> log_t;
+      log_t log_severe, log_errors, log_infos, file_errors;
+      bool mark_read;
+
+    protected: // inherited from WorkerPool::Worker
+
+      void do_work();
+
+    private:
+
+      friend class TaskUpload;
+      TaskUpload * task;
+      TaskUpload::EncodeMode encode_mode;
+      FileQueue::FileData file_data;
+
+      // These are set in the worker thread and polled in the main thread.
+      Mutex mut;
+      volatile double percent;
+      std::string current_file; // the current file we are decoding, with path
+      int parts;
+
+      static void uu_log(void *thiz, char *message, int severity);
+      double get_percentage (const uuprogress& p) const;
+      static int uu_busy_poll(void * self, uuprogress *p);
+      /** tell our task about the decode's progress */
+      static gboolean progress_update_timer_func(gpointer decoder);
+
+      WorkerPool& _worker_pool;
+      int _gsourceid;
+      void disable_progress_update();
+      void enable_progress_update();
+  };
+}
+
+#endif
diff --git a/pan/tasks/task-upload.cc b/pan/tasks/task-upload.cc
new file mode 100644
index 0000000..8d2f7f8
--- /dev/null
+++ b/pan/tasks/task-upload.cc
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2007  Charles Kerr <charles rebelbase com>
+ *
+ * This File:
+ * Copyright (C) 2007 Charles Kerr <charles rebelbase com>
+ * Copyright (C) 2007 Calin Culianu <calin ajvar org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <config.h>
+#include <algorithm>
+#include <cassert>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+
+extern "C" {
+#include <glib/gi18n.h>
+}
+#include <pan/general/debug.h>
+#include <pan/general/file-util.h>
+#include <pan/general/log.h>
+#include <pan/general/macros.h>
+#include <pan/usenet-utils/mime-utils.h>
+#include <pan/data/article-cache.h>
+#include "encoder.h"
+#include "task-upload.h"
+
+using namespace pan;
+
+namespace
+{
+  std::string get_description (const char* name, bool enc)
+  {
+    char buf[1024];
+    if (!enc)
+      snprintf (buf, sizeof(buf), _("Uploading %s"), name);
+    else
+      snprintf (buf, sizeof(buf), _("Encoding %s"), name);
+    return std::string (buf);
+  }
+}
+
+/***
+****
+***/
+
+TaskUpload :: TaskUpload ( const FileQueue::FileData & file_data,
+                           const Quark               & server,
+                           GMimeMessage              * msg,
+                           Progress::Listener        * listener,
+                           const TaskUpload::EncodeMode  enc):
+  Task ("UPLOAD", get_description(file_data.filename, true)),
+  _file_data(file_data),
+  _basename(g_path_get_basename(file_data.filename)),
+  _server(server),
+  _msg(msg),
+  _encoder(0),
+  _encoder_has_run (false),
+  _encode_mode(enc)
+{
+  if (listener != 0)
+    add_listener (listener);
+
+  update_work ();
+}
+
+void
+TaskUpload :: update_work (void)
+{
+  if (!_encoder && !_encoder_has_run)
+  {
+    _state.set_need_encoder();
+  } else if (_encoder_has_run && !_needed.empty())
+  {
+    std::cout<<"need "<<_needed.size()<<std::endl;
+    mut.lock();
+      _cur = *_needed.begin();
+      if (!_needed.empty()) _needed.pop_front();
+    mut.unlock();
+    _state.set_need_nntp(_server);
+    set_status_va (_("Uploading %s"), _file_data.basename);
+  } else if (_needed.empty())
+  {
+    _state.set_completed();
+    set_finished(OK);
+  }
+}
+
+/***
+****
+***/
+
+std::string
+TaskUpload :: generate_yenc_headers(const Needed& n)
+{
+  std::stringstream res;
+  const int bufsz = 2048;
+  char buf[bufsz];
+  //modify msg to our needs
+  const char* subject = g_mime_object_get_header ((GMimeObject*)_msg, "Subject");
+  g_snprintf(buf,bufsz, "%s -- \"%s\" (%d/%d) YEnc",
+             subject, _file_data.basename, //_file_data.part_in_queue, _file_data.size(),
+             n.partno, _parts);
+  g_mime_object_set_header((GMimeObject*)_msg,"Subject", buf);
+
+  //append msg to result
+  res << g_mime_object_to_string((GMimeObject *)_msg);
+
+  //append yenc data to result
+  res<<"\r\n";
+
+  std::ifstream in(const_cast<char*>(n.filename.c_str()),  std::ifstream::in);
+  std::string line;
+  if (in.good())
+    std::getline(in, line);
+  int filesize = __yenc_extract_tag_val_int_base( line.c_str(), " size=", 0 );
+  g_snprintf(buf,bufsz,"=ybegin line=128 size=%s name=%s\r\n",
+             filesize, _basename);
+  res<<buf;
+  while (in.good())
+    res << (char) in.get();
+  res<<"\r\n.\r\n";
+  return res.str();
+}
+
+void
+TaskUpload :: use_nntp (NNTP * nntp)
+{
+    std::cerr<<"use nntp\n";
+    if (_needed.empty())
+      update_work();
+
+    std::string res(generate_yenc_headers(_cur));
+    nntp->post(StringView(res), this);
+    update_work ();
+}
+
+/***
+****
+***/
+
+void
+TaskUpload :: on_nntp_line  (NNTP               * nntp,
+                              const StringView   & line_in)
+{}
+
+void
+TaskUpload :: on_nntp_done  (NNTP             * nntp,
+                              Health             health,
+                              const StringView & response)
+{
+  std::cerr<<"nntp done\n";
+  check_in (nntp, health);
+  increment_step(1);
+  update_work();
+}
+
+/***
+****
+***/
+
+//todo
+unsigned long
+TaskUpload :: get_bytes_remaining () const
+{
+  unsigned long bytes (0);
+  foreach_const (needed_t, _needed, it) // parts not fetched yet...
+    bytes += it->bytes;
+  return bytes;
+}
+
+
+void
+TaskUpload :: use_encoder (Encoder* encoder)
+{
+  if (_state._work != NEED_ENCODER)
+    check_in (encoder);
+
+  _encoder = encoder;
+  init_steps(100);
+  _state.set_working();
+  _encoder->enqueue (this, _file_data, YENC);
+  debug ("encoder thread was free, enqueued work");
+}
+
+void
+TaskUpload :: stop ()
+{
+  if (_encoder)
+      _encoder->cancel();
+}
+
+// called in the main thread by WorkerPool
+void
+TaskUpload :: on_worker_done (bool cancelled)
+{
+  assert(_encoder);
+  if (!_encoder) return;
+
+  if (!cancelled)
+  {
+    // the encoder is done... catch up on all housekeeping
+    // now that we're back in the main thread.
+
+    foreach_const(Encoder::log_t, _encoder->log_severe, it)
+      Log :: add_err(it->c_str());
+    foreach_const(Encoder::log_t, _encoder->log_errors, it)
+      Log :: add_err(it->c_str());
+    foreach_const(Encoder::log_t, _encoder->log_infos, it)
+      Log :: add_info(it->c_str());
+
+    if (!_encoder->log_errors.empty())
+      set_error (_encoder->log_errors.front());
+
+    if (!_encoder->log_severe.empty())
+      _state.set_health (ERR_LOCAL);
+    else {
+      // get parts number from encoder
+      _parts = _encoder->parts;
+      set_step (100);
+      _encoder_has_run = true;
+      /*enqueue all parts into needed_t list.
+        update_work will then assign a pointer to the begin
+        which will be used for an nntp upload.
+        on nntp_done, the list is decreased by one member
+       */
+      static Needed n;
+      const int bufsz(2048);
+      char buf[bufsz];
+      struct stat sb;
+
+      for (int i=1;i<=_parts;i++)
+      {
+        n.partno = i;
+        g_snprintf(buf,bufsz,"%s/%s.%d",
+                   file::get_uulib_path().c_str(),
+                   _file_data.basename, i);
+        n.filename = buf;
+        stat(buf, &sb);
+        n.bytes = sb.st_size;
+        _needed.push_back (n);
+      }
+      init_steps (_parts);
+      set_step (0);
+    }
+  }
+
+  Encoder * d (_encoder);
+  _encoder = 0;
+  update_work ();
+  check_in (d);
+}
+
+TaskUpload :: ~TaskUpload ()
+{
+  // ensure our on_worker_done() doesn't get called after we're dead
+  if (_encoder)
+      _encoder->cancel_silently();
+}
diff --git a/pan/tasks/task-upload.h b/pan/tasks/task-upload.h
new file mode 100644
index 0000000..139af7b
--- /dev/null
+++ b/pan/tasks/task-upload.h
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  Charles Kerr <charles rebelbase com>
+ *
+ * This file
+ * Copyright (C) 2007 Charles Kerr <charles rebelbase com>
+ * Copyright (C) 2007 Calin Culianu <calin ajvar org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _TaskUpload_h_
+#define _TaskUpload_h_
+
+#include <pan/general/worker-pool.h>
+#include <pan/data/article.h>
+#include <pan/data/article-cache.h>
+#include <pan/data/data.h>
+#include <pan/data/file-queue.h>
+#include <pan/data/xref.h>
+#include <pan/tasks/nntp.h>
+#include <pan/tasks/task.h>
+#include <deque>
+
+namespace pan
+{
+  struct Encoder;
+
+  /**
+   * Task for uploading binary data to usenet
+   * @ingroup tasks
+   */
+  class TaskUpload: public Task,
+                     private NNTP::Listener,
+                     private WorkerPool::Worker::Listener
+  {
+    public: // life cycle
+
+      enum EncodeMode
+      {
+        YENC = 0,
+        BASE64,
+        PLAIN
+      };
+
+      TaskUpload ( const FileQueue::FileData & file_data,
+                   const Quark               & server,
+                   GMimeMessage              * msg,
+                   Progress::Listener        * listener=0,
+                   TaskUpload::EncodeMode enc     = YENC);
+      virtual ~TaskUpload ();
+
+    public: // Task subclass
+      unsigned long get_bytes_remaining () const;
+      void stop ();
+
+      /** only call this for tasks in the NEED_DECODE state
+       * attempts to acquire the saver thread and start saving
+       * returns false if failed or true if the save process started
+       * (intended to be used with the Queue class). If true is returned,
+       * a side-effect is that the task is now in the DECODING state.
+       */
+      virtual void use_encoder (Encoder*);
+
+    private: // Task subclass
+      virtual void use_nntp (NNTP * nntp);
+
+    private: // NNTP::Listener subclass
+      virtual void on_nntp_line  (NNTP*, const StringView&);
+      virtual void on_nntp_done  (NNTP*, Health, const StringView&);
+
+    private: // WorkerPool::Listener interface
+      void on_worker_done (bool cancelled);
+
+    protected:
+      const Quark _server;
+
+    private: // implementation
+      friend class Encoder;
+      Encoder * _encoder;
+      bool _encoder_has_run;
+      FileQueue::FileData _file_data;
+      const char* _basename;
+      TaskUpload::EncodeMode _encode_mode;
+      GMimeMessage * _msg;
+      int _parts; // filled in by encoder
+      Mutex mut;
+
+    private:
+      struct Needed {
+        std::string filename;
+        unsigned long bytes;
+        int partno;
+        Needed (): partno(0) {}
+      };
+      typedef std::deque<Needed> needed_t;
+      needed_t _needed;
+      Needed _cur;
+
+      virtual std::string generate_yenc_headers(const Needed& n);
+
+      void update_work (void);
+  };
+
+namespace
+{
+
+     const char*
+   __yenc_extract_tag_val_char (const char * line, const char *tag)
+   {
+      const char * retval = NULL;
+
+      const char * tmp = strstr (line, tag);
+      if (tmp != NULL) {
+         tmp += strlen (tag);
+         if (*tmp != '\0')
+            retval = tmp;
+      }
+
+      return retval;
+   }
+
+  guint
+   __yenc_extract_tag_val_int_base (const char * line,
+                                    const char * tag,
+                                    int          base)
+   {
+      guint retval = 0;
+
+      const char * tmp = __yenc_extract_tag_val_char (line, tag);
+      if (tmp != NULL) {
+         char * tail = NULL;
+         retval = strtoul (tmp, &tail, base);
+         if (tmp == tail)
+            retval = 0;
+      }
+
+      return retval;
+   }
+}
+
+}
+
+#endif
diff --git a/pan/tasks/task-weak-ordering.h b/pan/tasks/task-weak-ordering.h
index 6f6d2fd..dad898f 100644
--- a/pan/tasks/task-weak-ordering.h
+++ b/pan/tasks/task-weak-ordering.h
@@ -42,7 +42,8 @@ namespace pan
       POST ("POST"),
       SAVE ("SAVE"),
       XOVER ("XOVER"),
-      XZVER_TEST ("XZVER_TEST") {}
+      XZVER_TEST ("XZVER_TEST")
+      {}
 
     int get_rank_for_type (const Quark& type) const
     {
@@ -55,7 +56,7 @@ namespace pan
       else if (type==SAVE)
         rank = 2;
       else
-        assert (0 && "what is this type?");
+        rank = 2;
 
       return rank;
     }
diff --git a/pan/usenet-utils/mime-utils.cc b/pan/usenet-utils/mime-utils.cc
index 52de825..c2d7d17 100644
--- a/pan/usenet-utils/mime-utils.cc
+++ b/pan/usenet-utils/mime-utils.cc
@@ -155,7 +155,7 @@ namespace
     * @param filename if parse is successful, is set with the
     *        starting character of the filename.
     * @param line_len if parse is successful, is set with the line length
-    * @param part is parse is successful & set to the cuurent attachements
+    * @param part if parse is successful this is set to the current attachement's
     *       part number
     * @return 0 on success, -1 on failure
     */
@@ -171,10 +171,10 @@ namespace
 
       // part is optional
       int part_num = __yenc_extract_tag_val_int (b, YENC_TAG_PART);
-	
+
       int a_sz = __yenc_extract_tag_val_int( b, YENC_TAG_SIZE );
       pan_return_val_if_fail( a_sz != 0, -1 );
-	
+
       const char * fname = __yenc_extract_tag_val_char (b, YENC_TAG_NAME);
       pan_return_val_if_fail( fname, -1 );
 
diff --git a/pan/usenet-utils/mime-utils.h b/pan/usenet-utils/mime-utils.h
index fbfa71c..e4e9714 100644
--- a/pan/usenet-utils/mime-utils.h
+++ b/pan/usenet-utils/mime-utils.h
@@ -31,7 +31,7 @@ namespace pan
 {
   /**
    * Utilities to build and parse GMimeMesasges.
-   * 
+   *
    * Most of nastiness this is to handle Usenet's use of chainging together
    * multiple articles as parts of a whole.  This code tries to build
    * a multipart GMimeMessage from multiple posts when necessary, and to



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