[pan2: 141/268] fixed a few things...



commit 9230b69473dcd9d6215371b522136578d5d8996e
Author: Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
Date:   Mon Jul 25 12:24:31 2011 +0200

    fixed a few things...

 pan/data-impl/my-tree.cc       |   39 +-
 pan/data-impl/rules-filter.cc  |    2 +-
 pan/data-impl/rules-filter.h   |    1 +
 pan/data/encode-cache.cc       |    2 +-
 pan/gui/header-pane.cc         |   28 +-
 pan/gui/post-ui.cc             |  371 ++-
 pan/gui/post-ui.h              |   12 +-
 pan/gui/post.ui.h              |    5 +-
 pan/gui/prefs-ui.cc            |    4 +-
 pan/tasks/encoder.cc           |   35 +-
 pan/tasks/encoder.h            |    6 +-
 pan/tasks/queue.cc             |   12 +
 pan/tasks/queue.h              |    2 +-
 pan/tasks/task-multipost.cc    |   65 +-
 pan/tasks/task-multipost.h     |   32 +-
 pan/tasks/task-upload.cc       |   14 +-
 pan/tasks/task-upload.h        |   22 +-
 pan/tasks/task.h               |    2 +-
 pan/tasks/upload-queue.cc      |   46 +-
 pan/tasks/upload-queue.h       |   31 +-
 pan/usenet-utils/mime-utils.cc |   10 +-
 po/am.po                       | 3250 ------------------
 po/ar.po                       | 3284 ------------------
 po/az.po                       | 3020 ----------------
 po/bg.po                       | 2888 ----------------
 po/ca.po                       | 5176 ----------------------------
 po/cs.po                       | 2845 ----------------
 po/da.po                       | 2838 ----------------
 po/de.po                       | 2870 ----------------
 po/dz.po                       | 3090 -----------------
 po/el.po                       | 7142 --------------------------------------
 po/en_CA.po                    | 3198 -----------------
 po/en_GB.po                    | 5046 ---------------------------
 po/es.po                       | 2869 ----------------
 po/et.po                       | 7374 ----------------------------------------
 po/eu.po                       | 2847 ----------------
 po/fi.po                       | 2918 ----------------
 po/fr.po                       | 2874 ----------------
 po/ga.po                       | 3360 ------------------
 po/gl.po                       | 6121 ---------------------------------
 po/hr.po                       | 5360 -----------------------------
 po/hu.po                       | 6925 -------------------------------------
 po/it.po                       | 5355 -----------------------------
 po/ja.po                       | 7156 --------------------------------------
 po/ko.po                       | 4977 ---------------------------
 po/lt.po                       | 6129 ---------------------------------
 po/lv.po                       | 5132 ----------------------------
 po/ms.po                       | 5444 -----------------------------
 po/nb.po                       | 2910 ----------------
 po/nl.po                       | 5429 -----------------------------
 po/oc.po                       | 2773 ---------------
 po/pl.po                       | 5391 -----------------------------
 po/pt.po                       | 2855 ----------------
 po/pt_BR.po                    | 5281 ----------------------------
 po/ro.po                       | 5385 -----------------------------
 po/ru.po                       | 5277 ----------------------------
 po/sk.po                       | 5247 ----------------------------
 po/sl.po                       | 2841 ----------------
 po/sq.po                       | 5419 -----------------------------
 po/sr.po                       | 5367 -----------------------------
 po/sr Latn po                  | 5371 -----------------------------
 po/sv.po                       | 3752 --------------------
 po/tr.po                       | 6326 ----------------------------------
 po/uk.po                       | 5331 -----------------------------
 po/vi.po                       | 3177 -----------------
 po/zh_CN.po                    | 6230 ---------------------------------
 po/zh_TW.po                    | 5292 ----------------------------
 uulib/uuencode.c               |   31 +-
 68 files changed, 488 insertions(+), 209426 deletions(-)
---
diff --git a/pan/data-impl/my-tree.cc b/pan/data-impl/my-tree.cc
index b0e6989..85b6f28 100644
--- a/pan/data-impl/my-tree.cc
+++ b/pan/data-impl/my-tree.cc
@@ -89,10 +89,16 @@ DataImpl :: MyTree :: set_rules (const Data::ShowType    show_type,
                                  const RulesInfo * rules )
 {
 
-  if (rules)
+  if (rules) {
+//    std::cerr<<"set rules "<<rules<<std::endl;
     _rules = *rules;
+  }
   else
+  {
+//    std::cerr<<"rules clear my_tree\n";
     _rules.clear ();
+  }
+
   _show_type = show_type;
 
   const GroupHeaders * h (_data.get_group_headers (_group));
@@ -153,6 +159,7 @@ DataImpl :: MyTree :: MyTree (DataImpl              & data_impl,
 
   set_filter (show_type, filter);
   set_rules (show_type, rules);
+
 }
 
 DataImpl :: MyTree :: ~MyTree ()
@@ -189,6 +196,8 @@ void
 DataImpl :: MyTree :: apply_rules (const_nodes_v& candidates)
 {
 
+//  std::cerr<<"apply rules mytree\n";
+
   NodeMidCompare compare;
   const_nodes_v pass;
   pass.reserve (candidates.size());
@@ -197,13 +206,10 @@ DataImpl :: MyTree :: apply_rules (const_nodes_v& candidates)
   foreach (const_nodes_v, candidates, it) {
     if (!(*it)->_article)
       continue;
-    if (_data._rules_filter.test_article (_data, _rules, _group, *(*it)->_article))
+    if (!_data._rules_filter.test_article (_data, _rules, _group, *(*it)->_article))
       pass.push_back (*it);
   }
 
-  //std::cerr << LINE_ID << " " << pass.size() << " of "
-  //          << (pass.size() + fail.size()) << " articles pass\n";
-
   //  maybe include threads or subthreads...
   if (_show_type == Data::SHOW_THREADS)
   {
@@ -228,12 +234,18 @@ DataImpl :: MyTree :: apply_rules (const_nodes_v& candidates)
     pass.clear ();
     foreach (unique_nodes_t, d, it) {
       Article * a ((*it)->_article);
-      _data._rules_filter.test_article (_data, _rules, _group, *a);
+      if (!_data._rules_filter.test_article (_data, _rules, _group, *a))
+        pass.push_back (*it);
     }
   }
   cache_articles(_data._rules_filter._cached);
   download_articles(_data._rules_filter._downloaded);
   _data._rules_filter.finalize(_data);
+
+  quarks_t mids;
+  foreach_const (const_nodes_v, pass, it)
+    mids.insert (mids.end(), (*it)->_mid);
+  remove_articles (mids);
 }
 
 void
@@ -441,19 +453,15 @@ DataImpl :: MyTree :: accumulate_descendants (unique_nodes_t& descendants,
 void
 DataImpl :: MyTree :: articles_changed (const quarks_t& mids, bool do_refilter)
 {
+//  std::cerr<<"articles changed\n";
+
   const_nodes_v nodes;
   _data.find_nodes (mids, _data.get_group_headers(_group)->_nodes, nodes);
   apply_rules (nodes);
 
   if (do_refilter)
-  {
-
-     // refilter... this may cause articles to be shown or hidden
     apply_filter (nodes);
 
-  }
-
-
   // fire an update event for any of those mids in our tree...
   nodes_v my_nodes;
   _data.find_nodes (mids, _nodes, my_nodes);
@@ -469,11 +477,12 @@ DataImpl :: MyTree :: articles_changed (const quarks_t& mids, bool do_refilter)
 void
 DataImpl :: MyTree :: add_articles (const quarks_t& mids)
 {
+//  std::cerr<<"add articles\n";
+
   const_nodes_v nodes;
   _data.find_nodes (mids, _data.get_group_headers(_group)->_nodes, nodes);
-  apply_filter (nodes);
   apply_rules (nodes);
-
+  apply_filter (nodes);
 
 }
 
@@ -489,6 +498,8 @@ DataImpl :: MyTree :: TwoNodes
 void
 DataImpl :: MyTree :: add_articles (const const_nodes_v& nodes_in)
 {
+//  std::cerr<<"add articles nodes\n";
+
   NodeMidCompare compare;
 
   ///
diff --git a/pan/data-impl/rules-filter.cc b/pan/data-impl/rules-filter.cc
index 97ea757..dfd8e1a 100644
--- a/pan/data-impl/rules-filter.cc
+++ b/pan/data-impl/rules-filter.cc
@@ -32,7 +32,7 @@ void
 RulesFilter :: finalize (Data& data)
 {
 
-  std::cerr<<"finalize "<<_delete.size()<<std::endl;
+//  std::cerr<<"finalize "<<_delete.size()<<std::endl;
 
   data.delete_articles (_delete);
   _delete.clear();
diff --git a/pan/data-impl/rules-filter.h b/pan/data-impl/rules-filter.h
index 2913fb6..0bf6ea8 100644
--- a/pan/data-impl/rules-filter.h
+++ b/pan/data-impl/rules-filter.h
@@ -28,6 +28,7 @@
 #include <pan/data/article.h>
 #include <pan/data/data.h>
 
+
 namespace pan
 {
   /**
diff --git a/pan/data/encode-cache.cc b/pan/data/encode-cache.cc
index ff07772..e334ea7 100644
--- a/pan/data/encode-cache.cc
+++ b/pan/data/encode-cache.cc
@@ -144,7 +144,7 @@ void EncodeCache :: finalize (std::string message_id)
   _mid_to_info[message_id]._size = sb.st_size;
   fire_added (message_id);
   _current_bytes += sb.st_size;
-  resize();
+  //resize(); ///TODO mt debug!
 }
 
 void
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index 9aabbd0..07d079a 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -31,6 +31,7 @@ extern "C" {
 #include <pan/general/macros.h>
 #include <pan/general/quark.h>
 #include <pan/usenet-utils/filter-info.h>
+#include <pan/usenet-utils/rules-info.h>
 #include <pan/data/article.h>
 #include <pan/data/data.h>
 #include <pan/icons/pan-pixbufs.h>
@@ -1025,14 +1026,6 @@ namespace
 
 }
 
-//{ N_("Disabled"),"never" },
-//{ N_("Only new (Score == 0)"),"new" },
-//{ N_("9999 or more"), "watched" },
-//{ N_("5000 to 9998"), "high" },
-//{ N_("1 to 4999"),    "medium" },
-//{ N_("-9998 to -1"),  "low" },
-//{ N_("-9999 or less"),"ignored" }};
-
 #define RANGE 4998
 std::pair<int,int>
 HeaderPane :: get_int_from_rules_str(std::string val)
@@ -1054,6 +1047,7 @@ HeaderPane :: rebuild_rules (bool enable)
 
   if (!enable)
   {
+    std::cerr<<"clear rules\n";
     _rules.clear();
     return;
   }
@@ -1243,9 +1237,13 @@ HeaderPane :: rules(bool enable)
 
     if (_rules._aggregates.empty()) {
       _atree->set_rules();
+      std::cerr<<"rules, aggr empty\n";
     }
     else
+    {
+      std::cerr<<"rules, aggr NOT empty, size "<<_rules._aggregates.size()<< "\n";
       _atree->set_rules(_show_type, &_rules);
+    }
 
     _wait.watch_cursor_off ();
   }
@@ -1726,7 +1724,7 @@ HeaderPane :: HeaderPane (ActionManager       & action_manager,
   _root = scroll;
 
   search_activate (this); // calls rebuild_filter
-  rules();
+  rules(_prefs._rules_enabled);
 
   _data.add_listener (this);
   _prefs.add_listener (this);
@@ -2146,14 +2144,16 @@ HeaderPane :: on_queue_task_removed (Queue&, Task& task, int)
   if (ta)
     rebuild_article_action (ta->get_article().message_id);
 }
+
 void
 HeaderPane :: on_cache_added (const Quark& message_id)
 {
-    /// SLOOOOW!
-//  quarks_t q;
-//  q.insert(message_id);
-//  _data.rescore_articles ( _group, q );
-//  rebuild_article_action (message_id);
+  /// SLOOOOW!
+  quarks_t q;
+  q.insert(message_id);
+  _data.rescore_articles ( _group, q );
+  rebuild_article_action (message_id);
+
 }
 void
 HeaderPane :: on_cache_removed (const quarks_t& message_ids)
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index 8bd16f2..e95f09c 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -98,12 +98,24 @@ inline int close(int fd) {return _close(fd);}
 #endif
 
   bool remember_charsets (true);
+  bool inline_or_bulk (false); // false == bulk
+  bool master_reply (true);
 
   void on_remember_charset_toggled (GtkToggleAction * toggle, gpointer)
   {
     remember_charsets = gtk_toggle_action_get_active (toggle);
   }
 
+  void on_inline_toggled (GtkToggleAction * toggle, gpointer)
+  {
+    inline_or_bulk = gtk_toggle_action_get_active (toggle);
+  }
+
+  void on_mr_toggled (GtkToggleAction * toggle, gpointer)
+  {
+    master_reply = gtk_toggle_action_get_active (toggle);
+  }
+
   void on_spellcheck_toggled (GtkToggleAction * toggle, gpointer post_g)
   {
     const bool enabled = gtk_toggle_action_get_active (toggle);
@@ -114,7 +126,7 @@ inline int close(int fd) {return _close(fd);}
 namespace
 {
   int
-  find_task_index (GtkListStore * list, TaskUpload * task)
+  find_task_index (GtkListStore * list, Task * task)
   {
     GtkTreeIter iter;
     int index (0);
@@ -141,17 +153,25 @@ namespace
 void
 PostUI:: update_filequeue_label (GtkTreeSelection *selection)
 {
-    PostUI::tasks_t tasks(get_selected_files());
+    tasks_t tasks(get_selected_files());
 
     if (tasks.empty())
+    {
       _upload_queue.get_all_tasks(tasks);
+    }
+
 
     char str[512];
     long kb(0);
     foreach (PostUI::tasks_t, tasks, it)
     {
-      TaskUpload * task (*it);
-      kb += task->_bytes/1024;
+      TaskUpload * task (dynamic_cast<TaskUpload*>(*it));
+      if (task) kb += task->_bytes/1024;
+      else
+      {
+        TaskMultiPost * task (dynamic_cast<TaskMultiPost*>(*it));
+        if (task) kb += task->_bytes/1024;
+      }
     }
     g_snprintf(str,sizeof(str), _("Upload Queue : %ld Tasks, %ld KB (~ %.2f MB) total ."), tasks.size(), kb, kb/1024.0f);
     gtk_label_set_text (GTK_LABEL(_filequeue_label), str);
@@ -171,7 +191,7 @@ PostUI :: update_filequeue_tab()
    GtkTreeIter iter;
    int i(0);
    TaskUpload * task;
-   while (task = _upload_queue[i++])
+   while (task = dynamic_cast<TaskUpload*>(_upload_queue[i++]))
    {
        gtk_list_store_insert (store, &iter, i);
        gtk_list_store_set (store, &iter,
@@ -194,7 +214,7 @@ PostUI :: on_queue_tasks_added (UploadQueue& queue, int index, int count)
   for (int i=0; i<count; ++i)
   {
     const int pos (index + i);
-    TaskUpload * task (_upload_queue[pos]);
+    TaskUpload * task (dynamic_cast<TaskUpload*>(_upload_queue[pos]));
     if (!task) continue;
     GtkTreeIter iter;
     gtk_list_store_insert (store, &iter, pos);
@@ -211,7 +231,7 @@ PostUI :: on_queue_tasks_added (UploadQueue& queue, int index, int count)
 }
 
 void
-PostUI :: on_queue_task_removed (UploadQueue&, TaskUpload& task, int index)
+PostUI :: on_queue_task_removed (UploadQueue&, Task& task, int index)
 {
   GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(_filequeue_store)));
 
@@ -225,7 +245,7 @@ PostUI :: on_queue_task_removed (UploadQueue&, TaskUpload& task, int index)
 }
 
 void
-PostUI :: on_queue_task_moved (UploadQueue&, TaskUpload&, int new_index, int old_index)
+PostUI :: on_queue_task_moved (UploadQueue&, Task&, int new_index, int old_index)
 {
   GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(_filequeue_store));
   GtkListStore* store = GTK_LIST_STORE(model);
@@ -383,7 +403,7 @@ namespace
     { "rot13", GTK_STOCK_REFRESH, N_("_Rot13"), 0, N_("Rot13 Selected Text"), G_CALLBACK(do_rot13) },
     { "run-editor", GTK_STOCK_JUMP_TO, N_("Run _Editor"), "<control>e", N_("Run Editor"), G_CALLBACK(do_edit) },
     { "manage-profiles", GTK_STOCK_EDIT, N_("Edit P_osting Profiles"), 0, 0, G_CALLBACK(do_profiles) },
-    { "add-files", GTK_STOCK_OPEN, N_("Add _Files to Queue"), "<control>O", N_("Add Files to Queue"), G_CALLBACK(do_add_files) },
+    { "add-files", GTK_STOCK_ADD, N_("Add _Files to Queue"), "<control>O", N_("Add Files to Queue"), G_CALLBACK(do_add_files) },
   };
 
   void do_remove_files       (GtkAction*, gpointer p) {static_cast<PostUI*>(p)->remove_files(); }
@@ -441,19 +461,17 @@ namespace
     { "plain", NULL,
       N_("No encoding (plain)"), "",
       N_("No encoding (plain)"),
-      G_CALLBACK(do_select_encode) },
-
-    { "base64", NULL,
-      N_("BASE64-Encode"), "",
-      N_("BASE64-Encode"),
       G_CALLBACK(do_select_encode) }
+
   };
 
-  GtkToggleActionEntry toggle_entries[] =
+  const GtkToggleActionEntry toggle_entries[] =
   {
     { "wrap", GTK_STOCK_JUSTIFY_FILL, N_("_Wrap Text"), 0, N_("Wrap Text"), G_CALLBACK(do_wrap), true },
     { "always-run-editor", 0, N_("Always Run Editor"), 0, 0, G_CALLBACK(do_edit2), false },
     { "remember-charset", 0, N_("Remember Character Encoding for this Group"), 0, 0, G_CALLBACK(on_remember_charset_toggled), true },
+    { "inline-or-bulk", 0, N_("Attachments are inlined with Message"), 0, 0, G_CALLBACK(on_inline_toggled), false },
+    { "master-reply", 0, N_("All Attachments are threaded replies to message"), 0, 0, G_CALLBACK(on_mr_toggled), true },
     { "spellcheck", 0, N_("Check _Spelling"), 0, 0, G_CALLBACK(on_spellcheck_toggled), true }
   };
 
@@ -578,6 +596,7 @@ PostUI :: add_actions (GtkWidget * box)
                                 _prefs.get_flag ("spellcheck-enabled", DEFAULT_SPELLCHECK_FLAG));
   gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (gtk_action_group_get_action (_agroup, "wrap")),
                                 _prefs.get_flag ("compose-wrap-enabled", true));
+  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (gtk_action_group_get_action (_agroup, "inline-or-bulk")), false);
   gtk_ui_manager_insert_action_group (_uim, _agroup, 0);
 
    //add popup actions
@@ -812,7 +831,7 @@ void
 PostUI :: send_and_save_now ()
 {
 
-  PostUI::tasks_t tasks;
+  tasks_t tasks;
   _upload_queue.get_all_tasks(tasks);
 
   if (!check_charset())
@@ -943,7 +962,7 @@ PostUI :: on_progress_finished (Progress&, int status) // posting finished
   {
     --_running_uploads;
     int no = status;
-    TaskUpload * ptr = _upload_queue[no];
+    TaskUpload * ptr = dynamic_cast<TaskUpload*>(_upload_queue[no]);
 
     if (!_save_file.empty())
     {
@@ -1075,12 +1094,13 @@ PostUI :: maybe_post_message (GMimeMessage * message)
       << "<nzb xmlns=\"http://www.newzbin.com/DTD/2003/nzb\";>\n";
     }
 
-    PostUI::tasks_t tasks;
+    std::vector<Task*> tasks;
     _upload_queue.get_all_tasks(tasks);
     int cnt(0);
     char buf[2048];
     struct stat sb;
-    _running_uploads = tasks.size()+1;
+    _running_uploads = tasks.size();
+    if (master_reply) ++_running_uploads;
 
     // generate domain name for upload if the flag is set / a save-file is set
     bool custom_mid(_prefs.get_flag(MESSAGE_ID_PREFS_KEY,false) || !_save_file.empty());
@@ -1099,59 +1119,95 @@ PostUI :: maybe_post_message (GMimeMessage * message)
     std::string last_mid;
     std::string first_mid;
 
-    // master article, other attach
-    const Profile profile (get_current_profile ());
-    std::string out;
-    generate_unique_id(domain, 1,out);
-    first_mid = out;
-    Article a(tasks[0]->_article);
-
-    TaskUpload::UploadInfo f;
-    f.total=1;
-    TaskUpload::Needed n;
-    n.mid = out;
-    TaskUpload * tmp = new TaskUpload(a.subject.to_string(),profile.posting_server,_cache,a,f,new_message_from_ui(UPLOADING));
-    tmp->_needed.insert(std::pair<int, TaskUpload::Needed>(1,n));
-    tmp->_queue_pos = -1;
-    _queue.add_task (tmp, Queue::BOTTOM);
-    tmp->add_listener(this);
+    Article a;
+    TaskUpload * tmp (dynamic_cast<TaskUpload*>(tasks[0]));
+    if (tmp) a = tmp->_article;
 
-    /* init taskupload variables before adding the tasks to the queue for processing */
-    foreach (PostUI::tasks_t, tasks, it)
+    if (master_reply)
     {
+      std::cerr<<"adding master reply to queue\n";
 
-      TaskUpload * t (*it);
+      // master article, other attachments are threaded as replies to this
+      const Profile profile (get_current_profile ());
+      std::string out;
+      generate_unique_id(domain, 1,out);
+      first_mid = out;
 
-      const char* basename = t->_basename.c_str();
+
+      TaskUpload::UploadInfo f;
+      f.total=1;
       TaskUpload::Needed n;
+      n.mid = out;
+
+      if (!inline_or_bulk)
+      {
+        TaskUpload * tmp = new TaskUpload(a.subject.to_string(),profile.posting_server,_cache,a,f,new_message_from_ui(UPLOADING));
+        tmp->_needed.insert(std::pair<int, TaskUpload::Needed>(1,n));
+        tmp->_queue_pos = -1;
+        _queue.add_task (tmp, Queue::BOTTOM);
+        tmp->add_listener(this);
+      }
+    }
 
-      // generate domain for rng numbers
-      int total = get_total_parts(t->_filename.c_str());
+    /* init taskupload variables before adding the tasks to the queue for processing */
 
-      foreach (std::set<int>, t->_wanted, pit)
+    if (!inline_or_bulk) // bulk upload
+    {
+      std::cerr<<"adding "<<tasks.size()<<" tasks."<<std::endl;
+
+      foreach (PostUI::tasks_t, tasks, it)
       {
-        if (custom_mid)
+
+        TaskUpload * t (dynamic_cast<TaskUpload*>(*it));
+
+        const char* basename = t->_basename.c_str();
+        TaskUpload::Needed n;
+
+        // generate domain for rng numbers
+        int total = get_total_parts(t->_filename.c_str());
+
+        foreach (std::set<int>, t->_wanted, pit)
         {
-            std::string out;
-            generate_unique_id(domain, *pit,out);
-            n.mid = out;
-            if (first_mid.empty()) first_mid = out;
+          if (custom_mid)
+          {
+              std::string out;
+              generate_unique_id(domain, *pit,out);
+              n.mid = out;
+              if (first_mid.empty()) first_mid = out;
+          }
+
+          g_snprintf(buf,sizeof(buf),"%s.%d", basename, *pit);
+          n.message_id = buf;
+          n.partno = *pit;
+          n.last_mid = last_mid;
+          t->_first_mid = first_mid;
+          last_mid = n.mid;
+          t->_needed.insert(std::pair<int,TaskUpload::Needed>(*pit,n));
         }
+        t->build_needed_tasks();
+        t->_save_file = _save_file;
+        t->_queue_pos = cnt++;
 
-        g_snprintf(buf,sizeof(buf),"%s.%d", basename, *pit);
-        n.message_id = buf;
-        n.partno = *pit;
-        n.last_mid = last_mid;
-        t->_first_mid = first_mid;
-        last_mid = n.mid;
-        t->_needed.insert(std::pair<int,TaskUpload::Needed>(*pit,n));
+        _queue.add_task (*it, Queue::BOTTOM);
+        t->add_listener(this);
       }
-      t->build_needed_tasks();
-      t->_save_file = _save_file;
-      t->_queue_pos = cnt++;
-
-      _queue.add_task (*it, Queue::BOTTOM);
-      t->add_listener(this);
+    }
+    else    // attachments are all inlined in ONE big gmimemultipart
+    {
+      _running_uploads = 1;
+      quarks_t filenames;
+      GMimeMessage* msg(new_message_from_ui(UPLOADING));
+      GMimeMultipart * multi (g_mime_multipart_new_with_subtype("mixed"));
+      g_mime_multipart_insert(multi,0,GMIME_OBJECT(msg));
+
+      TaskMultiPost * mp = new TaskMultiPost(filenames, profile.posting_server, a, multi, this);
+      foreach (PostUI::tasks_t, tasks, it)
+      {
+        TaskUpload * t (dynamic_cast<TaskUpload*>(*it));
+        mp->_filenames.insert(Quark(t->_filename.c_str()));
+      }
+      mp->dbg();
+      _upload_queue.clear();
     }
 
   }
@@ -1433,17 +1489,29 @@ namespace
 GMimeMessage*
 PostUI :: new_message_from_ui (Mode mode, bool copy_body)
 {
-  GMimeMessage * msg (g_mime_message_new (false));
+  GMimeMessage * msg(0);
+  if (mode!=MULTI)
+    msg = g_mime_message_new (false);
+  else
+    msg = (GMimeMessage*)g_mime_multipart_new_with_subtype("mixed");
 
   // headers from the ui: From
   const Profile profile (get_current_profile ());
   std::string s;
   profile.get_from_header (s);
-  g_mime_message_set_sender (msg, s.c_str());
+  if (mode!=MULTI)
+    g_mime_message_set_sender (msg, s.c_str());
+  else
+    g_mime_object_set_header ((GMimeObject *) msg, "From", s.c_str());
 
   // headers from the ui: Subject
   const char * cpch (gtk_entry_get_text (GTK_ENTRY(_subject_entry)));
-  if (cpch) g_mime_message_set_subject (msg, cpch);
+  if (cpch) {
+    if (mode!=MULTI)
+      g_mime_message_set_subject (msg, cpch);
+    else
+      g_mime_object_set_header ((GMimeObject *) msg, "Subject", cpch);
+  }
 
   // headers from the ui: To
   const StringView to (gtk_entry_get_text (GTK_ENTRY(_to_entry)));
@@ -1490,11 +1558,11 @@ PostUI :: new_message_from_ui (Mode mode, bool copy_body)
   g_free (pch);
 
   // User-Agent
-  if ((mode==POSTING || mode == UPLOADING) && _prefs.get_flag (USER_AGENT_PREFS_KEY, true))
+  if ((mode==POSTING || mode == UPLOADING || mode == MULTI) && _prefs.get_flag (USER_AGENT_PREFS_KEY, true))
     g_mime_object_set_header ((GMimeObject *) msg, "User-Agent", get_user_agent());
 
   // Message-ID for single text-only posts
-  if ((mode==POSTING || mode==UPLOADING) && _prefs.get_flag (MESSAGE_ID_PREFS_KEY, false)) {
+  if ((mode==POSTING || mode==UPLOADING || mode == MULTI) && _prefs.get_flag (MESSAGE_ID_PREFS_KEY, false)) {
     const std::string message_id = !profile.fqdn.empty()
       ? GNKSA::generate_message_id (profile.fqdn)
       : GNKSA::generate_message_id_from_email_address (profile.address);
@@ -1502,36 +1570,138 @@ PostUI :: new_message_from_ui (Mode mode, bool copy_body)
   }
 
     // body & charset
-    std::string body;
-    if (copy_body) body = get_body();
-    GMimeStream * stream = g_mime_stream_mem_new_with_buffer (body.c_str(), body.size());
-    const std::string charset ((mode==POSTING && !_charset.empty()) ? _charset : "UTF-8");
-    if (charset != "UTF-8") {
-      // add a wrapper to convert from UTF-8 to $charset
-      GMimeStream * tmp = g_mime_stream_filter_new (stream);
+    if (mode != MULTI)
+    {
+      std::string body;
+      if (copy_body) body = get_body();
+      GMimeStream * stream = g_mime_stream_mem_new_with_buffer (body.c_str(), body.size());
+      const std::string charset ((mode==POSTING && !_charset.empty()) ? _charset : "UTF-8");
+      if (charset != "UTF-8") {
+        // add a wrapper to convert from UTF-8 to $charset
+        GMimeStream * tmp = g_mime_stream_filter_new (stream);
+        g_object_unref (stream);
+        GMimeFilter * filter = g_mime_filter_charset_new ("UTF-8", charset.c_str());
+        g_mime_stream_filter_add (GMIME_STREAM_FILTER(tmp), filter);
+        g_object_unref (filter);
+        stream = tmp;
+      }
+      GMimeDataWrapper * content_object = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_DEFAULT);
       g_object_unref (stream);
-      GMimeFilter * filter = g_mime_filter_charset_new ("UTF-8", charset.c_str());
-      g_mime_stream_filter_add (GMIME_STREAM_FILTER(tmp), filter);
-      g_object_unref (filter);
-      stream = tmp;
+      GMimePart * part = g_mime_part_new ();
+      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.
+      g_mime_part_set_content_object (part, content_object);
+      g_mime_part_set_content_encoding (part, GMIME_CONTENT_ENCODING_8BIT);
+      g_object_unref (content_object);
+      g_mime_message_set_mime_part (msg, GMIME_OBJECT(part));
+      g_object_unref (part);
     }
-    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 ();
-    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.
-    g_mime_part_set_content_object (part, content_object);
-    g_mime_part_set_content_encoding (part, GMIME_CONTENT_ENCODING_8BIT);
-    g_object_unref (content_object);
-    g_mime_message_set_mime_part (msg, GMIME_OBJECT(part));
-    g_object_unref (part);
+  return msg;
+}
+
+GMimeMultipart*
+PostUI :: new_multipart_from_ui (bool copy_body)
+{
+  GMimeMultipart * msg(g_mime_multipart_new_with_subtype("mixed"));
+
+  // headers from the ui: From
+  const Profile profile (get_current_profile ());
+  std::string s;
+  profile.get_from_header (s);
+  g_mime_object_set_header ((GMimeObject *) msg, "From", s.c_str());
+
+  // headers from the ui: Subject
+  const char * cpch (gtk_entry_get_text (GTK_ENTRY(_subject_entry)));
+  if (cpch)
+    g_mime_object_set_header ((GMimeObject *) msg, "Subject", cpch);
+
+  // headers from the ui: To
+  const StringView to (gtk_entry_get_text (GTK_ENTRY(_to_entry)));
+  if (!to.empty())
+    pan_g_mime_message_add_recipients_from_string ((GMimeMessage*)msg, GMIME_RECIPIENT_TYPE_TO, to.str);
+
+  // headers from the ui: Newsgroups
+  const StringView groups (gtk_entry_get_text (GTK_ENTRY(_groups_entry)));
+  if (!groups.empty())
+    g_mime_object_set_header ((GMimeObject *) msg, "Newsgroups", groups.str);
+
+  // headers from the ui: Followup-To
+  const StringView followupto (gtk_entry_get_text (GTK_ENTRY(_followupto_entry)));
+  if (!followupto.empty())
+    g_mime_object_set_header ((GMimeObject *) msg, "Followup-To", followupto.str);
+
+  // headers from the ui: Reply-To
+  const StringView replyto (gtk_entry_get_text (GTK_ENTRY(_replyto_entry)));
+  if (!replyto.empty())
+    g_mime_object_set_header ((GMimeObject *) msg, "Reply-To", replyto.str);
+
+  // build headers from the 'more headers' entry field
+  std::map<std::string,std::string> headers;
+  GtkTextBuffer * buf (_headers_buf);
+  GtkTextIter start, end;
+  gtk_text_buffer_get_bounds (buf, &start, &end);
+  char * pch = gtk_text_buffer_get_text (buf, &start, &end, false);
+  StringView key, val, v(pch);
+  v.trim ();
+  while (v.pop_token (val, '\n') && val.pop_token(key,':')) {
+    key.trim ();
+    val.eat_chars (1);
+    val.trim ();
+    std::string key_str (key.to_string());
+    if (extra_header_is_editable (key, val))
+      g_mime_object_set_header ((GMimeObject *) msg, key.to_string().c_str(),
+                                val.to_string().c_str());
+  }
+  g_free (pch);
+
+  // User-Agent
+  if (_prefs.get_flag (USER_AGENT_PREFS_KEY, true))
+    g_mime_object_set_header ((GMimeObject *) msg, "User-Agent", get_user_agent());
+
+  // Message-ID for single text-only posts
+  if (_prefs.get_flag (MESSAGE_ID_PREFS_KEY, false)) {
+    const std::string message_id = !profile.fqdn.empty()
+      ? GNKSA::generate_message_id (profile.fqdn)
+      : GNKSA::generate_message_id_from_email_address (profile.address);
+    pan_g_mime_message_set_message_id ((GMimeMessage*)msg, message_id.c_str());
+  }
+
+    // body & charset
+      std::string body;
+      if (copy_body) body = get_body();
+      GMimeStream * stream = g_mime_stream_mem_new_with_buffer (body.c_str(), body.size());
+      const std::string charset (_charset.empty() ? _charset : "UTF-8");
+      if (charset != "UTF-8") {
+        // add a wrapper to convert from UTF-8 to $charset
+        GMimeStream * tmp = g_mime_stream_filter_new (stream);
+        g_object_unref (stream);
+        GMimeFilter * filter = g_mime_filter_charset_new ("UTF-8", charset.c_str());
+        g_mime_stream_filter_add (GMIME_STREAM_FILTER(tmp), filter);
+        g_object_unref (filter);
+        stream = tmp;
+      }
+      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 ();
+      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.
+      g_mime_part_set_content_object (part, content_object);
+      g_mime_part_set_content_encoding (part, GMIME_CONTENT_ENCODING_8BIT);
+      g_object_unref (content_object);
+      g_mime_message_set_mime_part ((GMimeMessage*)msg, GMIME_OBJECT(part));
+      g_object_unref (part);
 
   return msg;
 }
 
+
 void
 PostUI :: save_draft ()
 {
@@ -2719,21 +2889,12 @@ PostUI :: select_encode (GtkAction* a)
         tmp = TaskUpload::YENC;
     if (!strcmp(name, "plain"))
         tmp = TaskUpload::PLAIN;
-    if (!strcmp(name, "base64"))
-        tmp = TaskUpload::BASE64;
 
     struct stat sb;
     foreach(tasks_t, tasks, it)
     {
-      const char* f = (*it)->_filename.c_str();
-      int total(get_total_parts (f));
-
-      (*it)->_encode_mode = tmp;
-      (*it)->_total_parts = total;
-      (*it)->_wanted.clear();
-      for (int i=1;i<=total;++i)
-        (*it)->_wanted.insert(i);
-
+      TaskUpload * tmp2 (dynamic_cast<TaskUpload*>(*it));
+      if (tmp2) tmp2->_encode_mode = tmp;
     }
     update_filequeue_tab();
 }
@@ -2743,7 +2904,8 @@ PostUI :: get_total_parts(const char* file)
 {
     struct stat sb;
     stat (file,&sb);
-    int max (std::max(1,(int)std::ceil((double)sb.st_size / (1024*_prefs.get_int("upload-option-kbpf",512)))));
+    int max (std::max(1,(int)std::ceil((double)sb.st_size /
+                                       _prefs.get_int("upload-option-bpf",512*1024))));
     return max;
 }
 
@@ -2797,7 +2959,7 @@ PostUI :: select_parts ()
 {
 
   PostUI::tasks_t set(get_selected_files());
-  _upload_ptr = set[0];
+  _upload_ptr = dynamic_cast<TaskUpload*>(set[0]);
 
   if (!_upload_ptr) return;
 
@@ -2818,7 +2980,7 @@ PostUI :: select_parts ()
   gtk_window_set_role (GTK_WINDOW(w), "pan-parts-window");
   gtk_window_set_title (GTK_WINDOW(w), _("Select Parts"));
   int x,y;
-  x = _prefs.get_int("post-ui-width", -1);
+  x = _prefs.get_int("post-ui-width", 450); // FIXME BUG: Native Windows wider or taller than 65535 pixels are not supported
   y = _prefs.get_int("post-ui-height", 450);
   gtk_window_set_default_size (GTK_WINDOW(w), x, y);
   // populate the window
@@ -3043,7 +3205,7 @@ PostUI :: prompt_user_for_queueable_files (GtkWindow * parent, const Prefs& pref
 
         TaskUpload::UploadInfo ui;
         // query lines per file value
-        ui.kbpf = _prefs.get_int("upload-option-kbpf",512);
+        ui.bpf = _prefs.get_int("upload-option-bpf",512*1024);
 
         std::string author;
         profile.get_from_header(author);
@@ -3075,8 +3237,7 @@ PostUI :: prompt_user_for_queueable_files (GtkWindow * parent, const Prefs& pref
           // yEnc encoding is the default, user can change that with popup-menu
           ui.total = get_total_parts((const char*)cur->data);
           TaskUpload* tmp = new TaskUpload(std::string((const char*)cur->data),
-                            profile.posting_server, _cache,
-                            a, ui, msg ,0, TaskUpload::YENC, TaskUpload::BULK );
+                            profile.posting_server, _cache, a, ui, msg);
 
           // insert wanted parts to upload
           for (int i=1;i<=ui.total; ++i)
diff --git a/pan/gui/post-ui.h b/pan/gui/post-ui.h
index b67867e..f76c0cb 100644
--- a/pan/gui/post-ui.h
+++ b/pan/gui/post-ui.h
@@ -25,6 +25,7 @@
 #include <pan/general/progress.h>
 #include <pan/tasks/queue.h>
 #include <pan/tasks/upload-queue.h>
+#include <pan/tasks/task-multipost.h>
 #include <pan/usenet-utils/text-massager.h>
 #include <pan/data/encode-cache.h>
 #include "group-prefs.h"
@@ -47,7 +48,9 @@ namespace pan
   {
     public:
 
-      typedef std::vector<TaskUpload*> tasks_t;
+      typedef std::vector<Task*> tasks_t;
+      typedef std::vector<TaskUpload*> bulk_tasks_t;
+      typedef std::vector<TaskMultiPost*> inline_tasks_t;
 
       static PostUI* create_window (GtkWindow*, Data&, Queue&, GroupServer&, Profiles&,
                                     GMimeMessage*, Prefs&, GroupPrefs&, EncodeCache&);
@@ -167,15 +170,16 @@ namespace pan
     private:
       friend class UploadQueue;
       virtual void on_queue_tasks_added (UploadQueue&, int index, int count);
-      virtual void on_queue_task_removed (UploadQueue&, TaskUpload&, int index);
-      virtual void on_queue_task_moved (UploadQueue&, TaskUpload&, int new_index, int old_index);
+      virtual void on_queue_task_removed (UploadQueue&, Task&, int index);
+      virtual void on_queue_task_moved (UploadQueue&, Task&, int new_index, int old_index);
 
     private:
       void add_actions (GtkWidget* box);
       void apply_profile_to_body ();
       void apply_profile_to_headers ();
-      enum Mode { DRAFTING, POSTING, UPLOADING };
+      enum Mode { DRAFTING, POSTING, UPLOADING, MULTI };
       GMimeMessage * new_message_from_ui (Mode mode, bool copy_body=true);
+      GMimeMultipart* new_multipart_from_ui (bool copy_body=true);
       Profile get_current_profile ();
       bool check_message (const Quark& server, GMimeMessage*, bool binpost=false);
       bool check_charset ();
diff --git a/pan/gui/post.ui.h b/pan/gui/post.ui.h
index 7b8494e..5f4aaa7 100644
--- a/pan/gui/post.ui.h
+++ b/pan/gui/post.ui.h
@@ -19,6 +19,9 @@ const char * fallback_post_ui =
 "      <menuitem action='set-charset' />\n"
 "      <menuitem action='remember-charset' />\n"
 "      <separator />\n"
+"      <menuitem action='inline-or-bulk' />\n"
+"      <menuitem action='master-reply' />\n"
+"      <separator />\n"
 "      <menuitem action='run-editor' />\n"
 "      <menuitem action='always-run-editor' />\n"
 "      <separator />\n"
@@ -59,7 +62,7 @@ const char * fallback_post_ui =
 "    <separator />\n"
 "    <menuitem action='yenc' />\n"
 "    <menuitem action='plain' />\n"
-"    <menuitem action='base64' />\n"
+"    <separator />\n"
 "  </popup>\n"
 "\n"
 "</ui>\n";
diff --git a/pan/gui/prefs-ui.cc b/pan/gui/prefs-ui.cc
index c79f1eb..0eb21a5 100644
--- a/pan/gui/prefs-ui.cc
+++ b/pan/gui/prefs-ui.cc
@@ -701,8 +701,8 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
   HIG :: workarea_add_section_title (t, &row, _("Encoding Options"));
   HIG :: workarea_add_section_spacer (t, row, 4);
   // 16 MiB blocks max, 512 kb min
-  w = new_spin_button ("upload-option-kbpf", 512, 1024*16, prefs);
-  l = gtk_label_new(_("Default KB per File (for Encoder). "));
+  w = new_spin_button ("upload-option-bpf", 512*1024, 1024*1024*16, prefs);
+  l = gtk_label_new(_("Default Bytes per File (for Encoder). "));
   gtk_misc_set_alignment (GTK_MISC(l), 0.0, 0.5);
   HIG::workarea_add_row (t, &row, w, l);
 
diff --git a/pan/tasks/encoder.cc b/pan/tasks/encoder.cc
index bfeb49a..a186ee8 100644
--- a/pan/tasks/encoder.cc
+++ b/pan/tasks/encoder.cc
@@ -66,7 +66,7 @@ Encoder :: enqueue (TaskUpload                      * task,
                     std::string                     & filename,
                     std::string                     & basename,
                     std::string                     & subject,
-                    int                               kbpf,
+                    int                               bpf,
                     const TaskUpload::EncodeMode      enc)
 
 {
@@ -79,7 +79,7 @@ Encoder :: enqueue (TaskUpload                      * task,
   this->needed = &task->_needed;
   this->cache = cache;
   this->article = article;
-  this->kbpf = kbpf;
+  this->bpf = bpf;
   this->subject = subject;
 
   percent = 0;
@@ -91,6 +91,29 @@ Encoder :: enqueue (TaskUpload                      * task,
   _worker_pool.push_work (this, task, false);
 }
 
+bool
+Encoder :: write_file (const char *fn)
+{
+
+  char buf[2048];
+
+  FILE * fp = cache->get_fp_from_mid(fn);
+  if (!fp)
+  {
+    g_snprintf(buf, sizeof(buf), _("Error loading %s from cache."), fn);
+    log_errors.push_back(buf); // log error
+    return false;
+  }
+
+  // write data from file on hdd to cache directory (plain copy)
+  char c[2048];
+  std::ifstream in(filename.c_str(), std::ios::in);
+  while (in.getline(c,2048))
+    fwrite (c, strlen(c), sizeof (char), fp);
+
+  return true;
+}
+
 void
 Encoder :: do_work()
 {
@@ -114,7 +137,7 @@ Encoder :: do_work()
     log_errors.push_back(_("Error initializing uulib")); // log error
   } else {
     UUSetMsgCallback (this, uu_log);
-    UUSetBusyCallback (this, uu_busy_poll, 200);
+    UUSetBusyCallback (this, uu_busy_poll, 90);
 
     /* build real subject line for article*/
     tmp->subject = subject;
@@ -134,9 +157,6 @@ Encoder :: do_work()
           case TaskUpload::PLAIN:
               enc = PT_ENCODED;
               break;
-          case TaskUpload::BASE64:
-              enc = B64ENCODED;
-              break;
           default:
               enc = YENC_ENCODED;
               break;
@@ -150,8 +170,7 @@ Encoder :: do_work()
         continue;
       }
 
-//      std::cerr<<"encode "<<kbpf*1024<<" bytes, "<<kbpf<<" kb \n";
-      res = UUEncodePartial_byFSize (fp, NULL, (char*)filename.c_str(), enc , (char*)basename.c_str(), 0, 0, cnt, kbpf*1024 ,&crc);
+      res = UUEncodePartial_byFSize (fp, NULL, (char*)filename.c_str(), enc , (char*)basename.c_str(), 0, 0, cnt, bpf ,&crc);
 
       if (fp) fclose(fp);
 _no_encode:
diff --git a/pan/tasks/encoder.h b/pan/tasks/encoder.h
index d0992ef..a9e5f28 100644
--- a/pan/tasks/encoder.h
+++ b/pan/tasks/encoder.h
@@ -66,7 +66,7 @@ namespace pan
                     std::string                     & filename,
                     std::string                     & basename,
                     std::string                     & subject,
-                    int                               kbpf,
+                    int                               bpf,
                     const TaskUpload::EncodeMode      enc = TaskUpload::YENC);
 
     public:
@@ -85,7 +85,7 @@ namespace pan
       TaskUpload * task;
       TaskUpload::EncodeMode encode_mode;
       std::string   basename, filename, subject;
-      int kbpf;
+      int bpf;
       EncodeCache * cache;
       TaskUpload::needed_t * needed;
       Article * article;
@@ -105,6 +105,8 @@ namespace pan
       int _gsourceid;
       void disable_progress_update();
       void enable_progress_update();
+
+      bool write_file (const char *fn);
   };
 }
 
diff --git a/pan/tasks/queue.cc b/pan/tasks/queue.cc
index 8d5aeae..fc09484 100644
--- a/pan/tasks/queue.cc
+++ b/pan/tasks/queue.cc
@@ -646,6 +646,10 @@ Queue :: get_all_task_states (task_states_t& setme)
   need_decode.clear();
   need_decode.reserve(setme.tasks.capacity());
 
+  std::vector<Task *> & need_encode = setme._need_encode.get_container();
+  need_encode.clear();
+  need_encode.reserve(setme.tasks.capacity());
+
   foreach(TaskSet, _tasks, it) {
     setme.tasks.push_back(*it);
     if ((*it)->get_state()._work == Task::NEED_DECODER)
@@ -653,6 +657,13 @@ Queue :: get_all_task_states (task_states_t& setme)
   }
   setme._need_decode.sort();
 
+  foreach(TaskSet, _tasks, it) {
+    setme.tasks.push_back(*it);
+    if ((*it)->get_state()._work == Task::NEED_ENCODER)
+      need_encode.push_back(*it);
+  }
+  setme._need_encode.sort();
+
   setme._queued.get_container() = setme.tasks;
   setme._queued.sort ();
 
@@ -671,6 +682,7 @@ Queue :: get_all_task_states (task_states_t& setme)
   running.insert (running.end(), tmp.begin(), tmp.end());
 
   setme._decoding = _decoder_task;
+  setme._encoding = _encoder_task;
 }
 
 void
diff --git a/pan/tasks/queue.h b/pan/tasks/queue.h
index b97d2c9..293cf5f 100644
--- a/pan/tasks/queue.h
+++ b/pan/tasks/queue.h
@@ -107,7 +107,7 @@ namespace pan
 
     public:
       enum TaskState { QUEUED, RUNNING, DECODING, ENCODING, STOPPED, REMOVING,
-                       QUEUED_FOR_DECODE, QUEUED_FOR_ENCODE};
+                       QUEUED_FOR_DECODE, QUEUED_FOR_ENCODE, PAUSED};
 
       /**
        * An ordered collection of tasks and their corresponding TaskState s.
diff --git a/pan/tasks/task-multipost.cc b/pan/tasks/task-multipost.cc
index cfd8f87..87fc657 100644
--- a/pan/tasks/task-multipost.cc
+++ b/pan/tasks/task-multipost.cc
@@ -45,9 +45,7 @@ namespace
   std::string get_description (const char* name)
   {
     char buf[4096];
-    char * freeme = g_path_get_basename(name);
-    snprintf (buf, sizeof(buf), _("Uploading %s"), freeme);
-    g_free(freeme);
+    snprintf (buf, sizeof(buf), _("Uploading \"%s\""), name);
     return buf;
   }
 
@@ -65,32 +63,31 @@ namespace
 ****
 ***/
 
-TaskMultiPost :: TaskMultiPost (const std::string   & filename,
-                          const Quark               & server,
-                          Article                     article,
-                          GMimeMessage *              msg,
-                          Progress::Listener        * listener):
-  Task ("UPLOAD", get_description(filename.c_str())),
-  _filename(filename),
-  _basename (g_get_basename(filename.c_str())),
+TaskMultiPost :: TaskMultiPost (quarks_t            & filenames,
+                                const Quark         & server,
+                                Article               article,
+                                GMimeMultipart      * msg,
+                                Progress::Listener  * listener):
+   Task ("UPLOAD", get_description(article.subject.to_string().c_str())),
+  _filenames(filenames),
   _server(server),
   _article(article),
   _subject (article.subject.to_string()),
   _author(article.author.to_string()),
-  _msg (msg)
-{
-
-
-//  struct stat sb;
-//  stat(filename.c_str(),&sb);
-//  _bytes = sb.st_size;
+  _files_left(1),
+  _msg(msg)
 
+{
+  g_mime_multipart_set_boundary(_msg, "$pan_multipart_msg$");
+  build_needed_tasks();
+  //  _state.set_paused();
+  update_work();
 }
 
 void
 TaskMultiPost :: build_needed_tasks()
 {
-
+  _files_left = _needed.size();
   foreach (needed_t, _needed, it)
   {
     _mids.push_back(Quark(it->second.message_id));
@@ -105,21 +102,21 @@ TaskMultiPost :: update_work (NNTP* checkin_pending)
   int working(0);
   foreach (needed_t, _needed, nit)
   {
-    TaskUpload::Needed& n (nit->second);
+    TaskMultiPost::Needed& n (nit->second);
     if (n.nntp && n.nntp!=checkin_pending)
       ++working;
   }
 
-  /* only need encode if mode is NOT plain */
   if (working)
   {
     _state.set_working();
   }
-  else if (!working)
+  else if (_files_left==0)
   {
+//    prepare_msg();
     _state.set_need_nntp(_server);
   }
-  else if (_needed.empty())
+  else if (!working && _files_left == 0)
   {
     _state.set_completed();
     set_finished(OK);
@@ -130,7 +127,9 @@ TaskMultiPost :: update_work (NNTP* checkin_pending)
 void
 TaskMultiPost :: use_nntp (NNTP * nntp)
 {
-  nntp->post(StringView(""), this);
+  char * pch = g_mime_object_to_string ((GMimeObject *) _msg);
+  nntp->post(pch, this);
+  g_free(pch);
 
   update_work ();
 }
@@ -161,10 +160,7 @@ TaskMultiPost :: on_nntp_done (NNTP * nntp,
 unsigned long
 TaskMultiPost :: get_bytes_remaining () const
 {
-  unsigned long bytes (0);
-  foreach_const (needed_t, _needed, it)
-    bytes += (unsigned long)it->second.bytes;
-  return bytes;
+  return 0;
 }
 
 
@@ -176,6 +172,19 @@ TaskMultiPost :: stop ()
 
 TaskMultiPost :: ~TaskMultiPost ()
 {
+  g_object_unref(_msg);
 
+}
 
+
+
+
+
+void
+TaskMultiPost :: dbg()
+{
+  std::cerr<<g_mime_object_to_string((GMimeObject*)_msg)<<std::endl;
+  std::cerr<<"\n////////////////////////////////////\n";
+  foreach_const (quarks_t, _filenames, it)
+    std::cerr<<*it<<std::endl;
 }
diff --git a/pan/tasks/task-multipost.h b/pan/tasks/task-multipost.h
index b17c276..34f12ee 100644
--- a/pan/tasks/task-multipost.h
+++ b/pan/tasks/task-multipost.h
@@ -57,13 +57,24 @@ namespace pan
 
       typedef std::vector<Quark> mid_sequence_t;
 
-      typedef std::map<int, TaskUpload::Needed> needed_t;
+      struct Needed {
+        unsigned long bytes;
+        int partno;
+        NNTP* nntp;
+        std::string message_id;
+        std::string cachename;
+        Xref xref;
+        Needed (): nntp(0), bytes(0) , partno(1) {}
+        void reset() { nntp = 0; }
+      };
+
+      typedef std::map<int, TaskMultiPost::Needed> needed_t;
 
       // life cycle
-      TaskMultiPost ( const std::string         & filename,
+      TaskMultiPost ( quarks_t                  & filenames,
                       const Quark               & server,
                       Article                     article,
-                      GMimeMessage *              msg,
+                      GMimeMultipart *              msg,
                       Progress::Listener        * listener= 0);
 
       virtual ~TaskMultiPost ();
@@ -71,7 +82,6 @@ namespace pan
     public: // Task subclass
       unsigned long get_bytes_remaining () const;
       void stop ();
-      const std::string& get_basename()  { return  _basename; }
 
       /** only call this for tasks in the NEED_ENCODE state
        * attempts to acquire the encoder thread and start encoding
@@ -92,19 +102,22 @@ namespace pan
 
     private: // implementation
       friend class PostUI;
-      friend class Queue;
+      friend class UploadQueue;
 
-      std::string _filename;
+      quarks_t _filenames;
       std::string _basename;
       std::string _subject, _master_subject, _author;
       std::string _save_file;
-      int _total_parts, _needed_parts;
       unsigned long _bytes;
       Article _article;
       unsigned long _all_bytes;
+      std::string mid;
+
+
+      void dbg() ;
 
       Article::mid_sequence_t _mids;
-      TaskUpload::needed_t _needed;
+      TaskMultiPost::needed_t _needed;
 
       void update_work (NNTP * checkin_pending = 0);
 
@@ -114,7 +127,8 @@ namespace pan
 
     private:
       std::set<int> _wanted;
-      GMimeMessage * _msg;
+      GMimeMultipart * _msg;
+      long _files_left;
 
   };
 }
diff --git a/pan/tasks/task-upload.cc b/pan/tasks/task-upload.cc
index f4c7ec6..58b1a89 100644
--- a/pan/tasks/task-upload.cc
+++ b/pan/tasks/task-upload.cc
@@ -74,8 +74,7 @@ TaskUpload :: TaskUpload (const std::string         & filename,
                           UploadInfo                  format,
                           GMimeMessage *              msg,
                           Progress::Listener        * listener,
-                          const TaskUpload::EncodeMode  enc,
-                          const TaskUpload::AttachMode  att):
+                          const TaskUpload::EncodeMode  enc):
   Task ("UPLOAD", get_description(filename.c_str())),
   _filename(filename),
   _basename (g_get_basename(filename.c_str())),
@@ -88,13 +87,12 @@ TaskUpload :: TaskUpload (const std::string         & filename,
   _encoder_has_run (false),
   _encode_mode(enc),
   _all_bytes(0),
-  _kbpf(format.kbpf),
+  _bpf(format.bpf),
   _queue_pos(0),
   _msg (msg),
   _total_parts(format.total),
   _save_file(format.save_file),
-  _first(true),
-  _att_mode(att)
+  _first(true)
 {
 
   const char * tmp (g_mime_object_get_header ((GMimeObject *)_msg, "References"));
@@ -164,7 +162,7 @@ TaskUpload :: update_work (NNTP* checkin_pending)
   }
   else if (_encoder_has_run && !_needed.empty())
   {
-      _state.set_need_nntp(_server);
+    _state.set_need_nntp(_server);
   }
   else if (_needed.empty())
   {
@@ -390,7 +388,7 @@ TaskUpload :: use_encoder (Encoder* encoder)
   init_steps(100);
   _state.set_working();
 
-  _encoder->enqueue (this, &_cache, &_article, _filename, _basename, _master_subject, _kbpf, _encode_mode);
+  _encoder->enqueue (this, &_cache, &_article, _filename, _basename, _master_subject, _bpf, _encode_mode);
   debug ("encoder thread was free, enqueued work");
 }
 
@@ -448,7 +446,7 @@ TaskUpload :: ~TaskUpload ()
       _encoder->cancel_silently();
 
   g_object_unref (G_OBJECT(_msg));
-  if (_att_mode==BULK && _queue_pos != -1)
+  if ( _queue_pos != -1)
   {
     _cache.release(_mids);
     _cache.resize();
diff --git a/pan/tasks/task-upload.h b/pan/tasks/task-upload.h
index 319dcf4..22bafe9 100644
--- a/pan/tasks/task-upload.h
+++ b/pan/tasks/task-upload.h
@@ -61,7 +61,7 @@ namespace pan
       {
         std::string  save_file;
         std::string  mid;
-        int kbpf;
+        int bpf;
         int total;
       };
 
@@ -85,15 +85,8 @@ namespace pan
 
       enum EncodeMode
       {
-        BASE64=0,
-        PLAIN=1,
-        YENC=2,
-      };
-
-      enum AttachMode
-      {
-        BULK,
-        INLINE
+        PLAIN,
+        YENC
       };
 
       // life cycle
@@ -104,8 +97,7 @@ namespace pan
                    UploadInfo                  format,
                    GMimeMessage *              msg=0,
                    Progress::Listener        * listener= 0,
-                   const EncodeMode enc= YENC,
-                   const AttachMode att= BULK);
+                   const EncodeMode enc= YENC);
 
       virtual ~TaskUpload ();
 
@@ -121,9 +113,6 @@ namespace pan
             case YENC:
               res += "yEnc";
               break;
-            case BASE64:
-              res += "BASE64";
-              break;
             case PLAIN:
               break;
             default:
@@ -167,7 +156,6 @@ namespace pan
       std::string _filename;
       std::string _basename;
       EncodeMode _encode_mode;
-      AttachMode _att_mode;
       std::string _subject, _master_subject, _author;
       std::string _save_file;
       int _total_parts, _needed_parts;
@@ -179,7 +167,7 @@ namespace pan
       std::vector<Article*> _upload_list;
       Article::mid_sequence_t _mids;
       int _queue_pos;
-      int _kbpf;
+      int _bpf;
       needed_t _needed;
       std::string _references; // original references, not to be touched!
       std::string _first_mid;
diff --git a/pan/tasks/task.h b/pan/tasks/task.h
index 7082262..a445d68 100644
--- a/pan/tasks/task.h
+++ b/pan/tasks/task.h
@@ -58,7 +58,7 @@ namespace pan
             NEED_ENCODER,
             /** Task is running */
             WORKING,
-
+            /** Task is paused, woken up if 'current_connections < max_connections' */
             PAUSED
          };
 
diff --git a/pan/tasks/upload-queue.cc b/pan/tasks/upload-queue.cc
index d77d2a2..da971ad 100644
--- a/pan/tasks/upload-queue.cc
+++ b/pan/tasks/upload-queue.cc
@@ -38,23 +38,10 @@ UploadQueue :: UploadQueue ()
 }
 
 UploadQueue :: ~UploadQueue ()
-{
-
-  //deletion is done by main queue in PostUI.
-
-//  const tasks_t tmp (_tasks.begin(), _tasks.end());
-//  foreach_const (tasks_t, tmp, it) {
-//    TaskUpload * task  (*it);
-//    remove_task (task);
-//  }
-//
-//  foreach (TaskSet, _tasks, it)
-//    delete *it;
-//
-}
+{}
 
 void
-UploadQueue :: get_all_tasks (tasks_t& setme)
+UploadQueue :: get_all_tasks (std::vector<Task*>& setme)
 {
   setme.clear();
   setme.reserve(_tasks.size());
@@ -68,7 +55,7 @@ UploadQueue :: clear()
 {
   const tasks_t tmp (_tasks.begin(), _tasks.end());
   foreach_const (tasks_t, tmp, it) {
-    TaskUpload * task  (*it);
+    Task * task  (*it);
     remove_task (task);
   }
 
@@ -77,7 +64,7 @@ UploadQueue :: clear()
 }
 
 void
-UploadQueue :: add_task (TaskUpload * task, AddMode mode)
+UploadQueue :: add_task (Task * task, AddMode mode)
 {
   tasks_t tasks;
   tasks.push_back (task);
@@ -103,7 +90,7 @@ UploadQueue :: remove_tasks (const tasks_t& tasks)
 }
 
 void
-UploadQueue :: remove_task (TaskUpload * task)
+UploadQueue :: remove_task (Task * task)
 {
   const int index (_tasks.index_of (task));
   pan_return_if_fail (index != -1);
@@ -115,7 +102,7 @@ void
 UploadQueue :: move_up (const tasks_t& tasks)
 {
   foreach_const (tasks_t, tasks, it) {
-    TaskUpload * task (*it);
+    Task * task (*it);
     const int old_pos (_tasks.index_of (task));
     _tasks.move_up (old_pos);
   }
@@ -125,7 +112,7 @@ void
 UploadQueue :: move_down (const tasks_t& tasks)
 {
   foreach_const_r (tasks_t, tasks, it) {
-    TaskUpload * task (*it);
+    Task * task (*it);
     const int old_pos (_tasks.index_of (task));
     _tasks.move_down (old_pos);
   }
@@ -135,7 +122,7 @@ void
 UploadQueue :: move_top (const tasks_t& tasks)
 {
   foreach_const_r (tasks_t, tasks, it) {
-    TaskUpload * task (*it);
+    Task * task (*it);
     const int old_pos (_tasks.index_of (task));
     _tasks.move_top (old_pos);
   }
@@ -145,7 +132,7 @@ void
 UploadQueue :: move_bottom (const tasks_t& tasks)
 {
   foreach_const (tasks_t, tasks, it) {
-    TaskUpload * task (*it);
+    Task * task (*it);
     const int old_pos (_tasks.index_of (task));
     _tasks.move_bottom (old_pos);
   }
@@ -153,12 +140,7 @@ UploadQueue :: move_bottom (const tasks_t& tasks)
 
 void
 UploadQueue :: select_encode (const tasks_t& tasks)
-{
-//  foreach_const (tasks_t, tasks, it) {
-//    TaskUpload * task (*it);
-//
-//  }
-}
+{}
 
 void
 UploadQueue :: fire_tasks_added (int pos, int count)
@@ -167,13 +149,13 @@ UploadQueue :: fire_tasks_added (int pos, int count)
     (*it++)->on_queue_tasks_added (*this, pos, count);
 }
 void
-UploadQueue :: fire_task_removed (TaskUpload*& task, int pos)
+UploadQueue :: fire_task_removed (Task*& task, int pos)
 {
   for (lit it(_listeners.begin()), end(_listeners.end()); it!=end; )
     (*it++)->on_queue_task_removed (*this, *task, pos);
 }
 void
-UploadQueue :: fire_task_moved (TaskUpload*& task, int new_pos, int old_pos)
+UploadQueue :: fire_task_moved (Task*& task, int new_pos, int old_pos)
 {
   for (lit it(_listeners.begin()), end(_listeners.end()); it!=end; )
     (*it++)->on_queue_task_moved (*this, *task, new_pos, old_pos);
@@ -186,13 +168,13 @@ UploadQueue :: on_set_items_added (TaskSet& container UNUSED, TaskSet::items_t&
 }
 
 void
-UploadQueue :: on_set_item_removed (TaskSet& container UNUSED, TaskUpload*& task, int pos)
+UploadQueue :: on_set_item_removed (TaskSet& container UNUSED, Task*& task, int pos)
 {
   fire_task_removed (task, pos);
 }
 
 void
-UploadQueue :: on_set_item_moved (TaskSet& container UNUSED, TaskUpload*& task, int new_pos, int old_pos)
+UploadQueue :: on_set_item_moved (TaskSet& container UNUSED, Task*& task, int new_pos, int old_pos)
 {
   fire_task_moved (task, new_pos, old_pos);
 }
diff --git a/pan/tasks/upload-queue.h b/pan/tasks/upload-queue.h
index 38bd357..fe5da68 100644
--- a/pan/tasks/upload-queue.h
+++ b/pan/tasks/upload-queue.h
@@ -32,6 +32,7 @@
 #include <pan/tasks/socket.h>
 #include <pan/tasks/adaptable-set.h>
 #include <pan/tasks/task-upload.h>
+#include <pan/tasks/task-multipost.h>
 #include <pan/tasks/encoder.h>
 #include <pan/tasks/task-weak-ordering.h>
 
@@ -43,16 +44,16 @@ namespace pan
   struct Encoder;
 
   class UploadQueue:
-        private AdaptableSet<TaskUpload*, TaskWeakOrdering>::Listener
+        private AdaptableSet<Task*, TaskWeakOrdering>::Listener
   {
     public:
 
-      typedef AdaptableSet<TaskUpload*, TaskWeakOrdering> TaskSet;
+      typedef AdaptableSet<Task*, TaskWeakOrdering> TaskSet;
 
       UploadQueue ();
       virtual ~UploadQueue ();
 
-      typedef std::vector<TaskUpload*> tasks_t;
+      typedef std::vector<Task*> tasks_t;
       void remove_tasks  (const tasks_t&);
       void move_up       (const tasks_t&);
       void move_down     (const tasks_t&);
@@ -64,26 +65,26 @@ namespace pan
       enum AddMode { TOP, BOTTOM };
       void add_tasks     (const tasks_t&, AddMode=BOTTOM);
 
-      void add_task (TaskUpload*, AddMode=BOTTOM);
-      void remove_task (TaskUpload*);
+      void add_task (Task*, AddMode=BOTTOM);
+      void remove_task (Task*);
 
       void clear();
 
-      void get_all_tasks (tasks_t& setme);
+      void get_all_tasks  (std::vector<Task*>& setme);
 
     protected:
       virtual void fire_tasks_added  (int index, int count);
-      virtual void fire_task_removed (TaskUpload*&, int index);
-      virtual void fire_task_moved   (TaskUpload*&, int index, int old_index);
+      virtual void fire_task_removed (Task*&, int index);
+      virtual void fire_task_moved   (Task*&, int index, int old_index);
 
     public:
 
       struct Listener {
         virtual ~Listener () {}
-        virtual void on_queue_task_active_changed (UploadQueue&, TaskUpload&, bool active) {}
+        virtual void on_queue_task_active_changed (UploadQueue&, Task&, bool active) {}
         virtual void on_queue_tasks_added (UploadQueue&, int index, int count) = 0;
-        virtual void on_queue_task_removed (UploadQueue&, TaskUpload&, int index) = 0;
-        virtual void on_queue_task_moved (UploadQueue&, TaskUpload&, int new_index, int old_index) = 0;
+        virtual void on_queue_task_removed (UploadQueue&, Task&, int index) = 0;
+        virtual void on_queue_task_moved (UploadQueue&, Task&, int new_index, int old_index) = 0;
         virtual void on_queue_connection_count_changed (UploadQueue&, int count) {}
         virtual void on_queue_size_changed (UploadQueue&, int active, int total) {}
         virtual void on_queue_online_changed (UploadQueue&, bool online) {}
@@ -99,14 +100,14 @@ namespace pan
       listeners_t _listeners;
 
     public:
-      TaskUpload* operator[](size_t i) { if (i>=_tasks.size() || i<0) return NULL; return _tasks[i]; }
-      const TaskUpload* operator[](size_t i) const { if (i>=_tasks.size() || i<0) return NULL; return _tasks[i]; }
+      Task* operator[](size_t i) { if (i>=_tasks.size() || i<0) return NULL; return _tasks[i]; }
+      const Task* operator[](size_t i) const { if (i>=_tasks.size() || i<0) return NULL; return _tasks[i]; }
 
     private:
       TaskSet _tasks;
       virtual void on_set_items_added  (TaskSet&, TaskSet::items_t&, int index);
-      virtual void on_set_item_removed (TaskSet&, TaskUpload*&, int index);
-      virtual void on_set_item_moved   (TaskSet&, TaskUpload*&, int index, int old_index);
+      virtual void on_set_item_removed (TaskSet&, Task*&, int index);
+      virtual void on_set_item_moved   (TaskSet&, Task*&, int index, int old_index);
   };
 }
 
diff --git a/pan/usenet-utils/mime-utils.cc b/pan/usenet-utils/mime-utils.cc
index f013f3c..4b24ff6 100644
--- a/pan/usenet-utils/mime-utils.cc
+++ b/pan/usenet-utils/mime-utils.cc
@@ -844,12 +844,12 @@ namespace
           g_mime_multipart_remove_at (mp, index);
           g_object_unref (part);
 
-          //workaround gmime insert bug
-          //g_mime_multipart_insert (mp,index,newpart);
-          {
-            ptr_array_insert(mp->children, index, newpart);
+          //should be fixed meanwhile (!) workaround gmime insert bug
+          g_mime_multipart_insert (mp,index,newpart);
+//          {
+//            ptr_array_insert(mp->children, index, newpart);
             g_object_ref(newpart);
-          }
+//          }
         }
         else if(GMIME_IS_MESSAGE(parent))
         {
diff --git a/uulib/uuencode.c b/uulib/uuencode.c
index 4eebc69..73f1bdc 100644
--- a/uulib/uuencode.c
+++ b/uulib/uuencode.c
@@ -495,7 +495,7 @@ UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc3
               switch ((char) ((int) itemp[index] + 42))
                 {
                 case '\0':
-                case '\t':
+//                case '\t':  yEnc 1.3 draft
                 case '\n':
                 case '\r':
                 case '=':
@@ -883,7 +883,7 @@ UUEncodeStream_byFSize (FILE *outfile, FILE *infile, int encoding, long bpf, crc
     long rest = bpf;
     long current = 0;
 
-    while (!feof (infile) && rest > 0)
+    while (rest > 0)
     {
       current = rest > 128 ? 128 : rest;
 
@@ -897,9 +897,8 @@ UUEncodeStream_byFSize (FILE *outfile, FILE *infile, int encoding, long bpf, crc
         {
           return UURET_IOERR;
         }
-      }
 
-      rest -= count;
+      }
 
       if (pcrc)
         *pcrc = crc32(*pcrc, itemp, count);
@@ -933,16 +932,18 @@ UUEncodeStream_byFSize (FILE *outfile, FILE *infile, int encoding, long bpf, crc
               optr = otemp;
             }
 
-          switch ((char) ((int) itemp[index] + 42))
+          char tmp = (char) ((int) itemp[index] + 42);
+
+          switch (tmp)
             {
             case '\0':
-            case '\t':
+//          case '\t':  yEnc 1.3 draft
             case '\n':
             case '\r':
             case '=':
             case '\033':
               *optr++ = '=';
-              *optr++ = (char) ((int) itemp[index] + 42 + 64);
+              *optr++ = tmp + 64;
               llen += 2;
               break;
 
@@ -950,24 +951,22 @@ UUEncodeStream_byFSize (FILE *outfile, FILE *infile, int encoding, long bpf, crc
               if (llen == 0)
                 {
                   *optr++ = '=';
-                  *optr++ = (char) ((int) itemp[index] + 42 + 64);
+                  *optr++ =  tmp + 64;
                   llen += 2;
-                }
-              else
-                {
-                  *optr++ = (char) ((int) itemp[index] + 42);
-                  llen++;
-                }
-              break;
+                  break;
+              }
 
             default:
-              *optr++ = (char) ((int) itemp[index] + 42);
+              *optr++ = tmp;
               llen++;
               break;
             }
         }
+
+        rest -= count;
     }
 
+
     /*
      * write last line
      */



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