[pan2: 54/268] [!] encodecache fixed (for good i hope) [*] added save option for upload queues



commit 01b704533d8d61ed129276cb7c67718974f74552
Author: Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
Date:   Tue Jun 7 16:34:40 2011 +0200

    [!] encodecache fixed (for good i hope)
    [*] added save option for upload queues

 pan/data/encode-cache.cc           |   11 +-
 pan/data/encode-cache.o            |  Bin 889992 -> 872312 bytes
 pan/gui/my-valgrind.sh             |    2 +-
 pan/gui/post-ui.cc                 |   68 +++++-
 pan/gui/post-ui.h                  |    3 +
 pan/gui/prefs-ui.cc                |   11 +-
 pan/tasks/encoder.cc               |   67 +++---
 pan/tasks/encoder.h                |    5 +
 pan/tasks/nzb.cc                   |   29 +--
 pan/tasks/task-upload.cc           |   65 +++---
 pan/tasks/task-upload.h            |    6 +-
 pan/usenet-utils/Makefile.am       |    3 +-
 pan/usenet-utils/MersenneTwister.h |  461 ++++++++++++++++++++++++++++++++++++
 uulib/uudeview.h                   |    4 +-
 uulib/uuencode.c                   |   26 ++-
 15 files changed, 651 insertions(+), 110 deletions(-)
---
diff --git a/pan/data/encode-cache.cc b/pan/data/encode-cache.cc
index 1de3acf..a12b86e 100644
--- a/pan/data/encode-cache.cc
+++ b/pan/data/encode-cache.cc
@@ -123,7 +123,6 @@ EncodeCache :: EncodeCache (const StringView& path, size_t max_megs):
       {
          struct stat stat_p;
          g_snprintf (filename, sizeof(filename), "%s%c%s", _path.c_str(), G_DIR_SEPARATOR, fname);
-         std::cerr<<"loaded "<<filename<<std::endl;
          if (!stat (filename, &stat_p))
          {
            MsgInfo info;
@@ -135,8 +134,6 @@ EncodeCache :: EncodeCache (const StringView& path, size_t max_megs):
          }
       }
       g_dir_close (dir);
-      std::cerr <<"loaded " << _mid_to_info.size() << " articles into encode-cache from "
-      << _path<<", size is : "<<_current_bytes<<" , max is "<<_max_megs * 1024 * 1024<<std::endl;
       if (_current_bytes>_max_megs*1024*1024) resize();
    }
 }
@@ -229,6 +226,7 @@ void EncodeCache :: finalize (const Quark& message_id)
   _mid_to_info[message_id]._size = sb.st_size;
   fire_added (message_id);
   _current_bytes += sb.st_size;
+  // resize();
 }
 
 void
@@ -241,7 +239,6 @@ EncodeCache :: reserve (const mid_sequence_t& mids)
 void
 EncodeCache :: release (const mid_sequence_t& mids)
 {
-  std::cerr<<"ec release"<<std::endl;
   foreach_const (mid_sequence_t, mids, it)
     if (!--_locks[*it])
       _locks.erase (*it);
@@ -308,9 +305,9 @@ EncodeCache :: resize (guint64 max_bytes)
     }
   }
 
-  std::cerr<< "cache expired " << removed.size() << " articles, "
-         "has " << _mid_to_info.size() << " active "
-         "and " << _locks.size() << " locked.\n";
+//  std::cerr<< "cache expired " << removed.size() << " articles, "
+//         "has " << _mid_to_info.size() << " active "
+//         "and " << _locks.size() << " locked.\n";
 
   if (!removed.empty())
     fire_removed (removed);
diff --git a/pan/data/encode-cache.o b/pan/data/encode-cache.o
index 710d05b..80ba07b 100644
Binary files a/pan/data/encode-cache.o and b/pan/data/encode-cache.o differ
diff --git a/pan/gui/my-valgrind.sh b/pan/gui/my-valgrind.sh
index 21ae2fd..cc5fe47 100755
--- a/pan/gui/my-valgrind.sh
+++ b/pan/gui/my-valgrind.sh
@@ -2,4 +2,4 @@
 export G_SLICE=always-malloc
 export G_DEBUG=gc-friendly
 export GLIBCXX_FORCE_NEW=1
-valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=64 --log-file=pan-valgrind --show-reachable=yes ./pan
+valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=42 --log-file=pan-valgrind --show-reachable=yes ./pan
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index 514e7cb..137698a 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -58,6 +58,7 @@ extern "C" {
 
 using namespace pan;
 
+#define QUEUE_SAVE_KEY "upload-queue-save-enabled"
 #define USER_AGENT_PREFS_KEY "add-user-agent-header-when-posting"
 #define MESSAGE_ID_PREFS_KEY "add-message-id-header-when-posting"
 #define USER_AGENT_EXTRA_PREFS_KEY "user-agent-extra-info"
@@ -1967,6 +1968,10 @@ namespace
   {
     static_cast<Prefs*>(prefs_gpointer)->set_flag (USER_AGENT_PREFS_KEY, gtk_toggle_button_get_active(tb));
   }
+  void queue_save_toggled_cb (GtkToggleButton * tb, gpointer prefs_gpointer)
+  {
+    static_cast<Prefs*>(prefs_gpointer)->set_flag (QUEUE_SAVE_KEY, gtk_toggle_button_get_active(tb));
+  }
 }
 
 namespace
@@ -2020,6 +2025,11 @@ PostUI :: create_filequeue_tab ()
   w = add_button (buttons, GTK_STOCK_DELETE, G_CALLBACK(delete_clicked_cb), this);
   gtk_widget_set_tooltip_text( w, _("Delete from Queue"));
   gtk_box_pack_start (GTK_BOX(buttons), gtk_vseparator_new(), 0, 0, 0);
+  w = _save_check = gtk_check_button_new_with_mnemonic (_("Save queue to file"));
+  bool b = _prefs.get_flag (QUEUE_SAVE_KEY, true);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), b);
+  g_signal_connect (w, "toggled", G_CALLBACK(queue_save_toggled_cb), &_prefs);
+  gtk_box_pack_start (GTK_BOX(buttons), w, 0, 0, 0);
   pan_box_pack_start_defaults (GTK_BOX(buttons), gtk_event_box_new());
 
   gtk_box_pack_start (GTK_BOX(vbox), buttons, false, false, 0);
@@ -2613,7 +2623,7 @@ PostUI :: prompt_user_for_queueable_files (tasks_v& queue, GtkWindow * parent, c
 		if (_file_queue_empty) _file_queue_empty=!_file_queue_empty;
 
 		GSList * cur = g_slist_nth (tmp_list,0);
-
+    gtk_widget_destroy (w);
     GMimeMessage* msg = new_message_from_ui(POSTING);
 
     char * tmp;
@@ -2632,6 +2642,10 @@ PostUI :: prompt_user_for_queueable_files (tasks_v& queue, GtkWindow * parent, c
         groups.insert(groupname);
     }
 
+    bool b = _prefs.get_flag (QUEUE_SAVE_KEY, true);
+    if (b)
+      _save_file = prompt_user_for_upload_nzb_dir (GTK_WINDOW (gtk_widget_get_toplevel(_root)), _prefs);
+
     int cnt(1);
     for (; cur; cur = cur->next, ++cnt)
 		{
@@ -2646,6 +2660,9 @@ PostUI :: prompt_user_for_queueable_files (tasks_v& queue, GtkWindow * parent, c
       TaskUpload::Needed n;
       foreach_const (quarks_t, groups, git)
          n.xref.insert (profile.posting_server, *git,0);
+      foreach_const (quarks_t, groups, git)
+         a.xref.insert (profile.posting_server, *git,0);
+
       for (int i = 1; i <= total; ++i)
       {
         g_snprintf(buf,sizeof(buf),"%s.%d", basename, i);
@@ -2661,17 +2678,60 @@ PostUI :: prompt_user_for_queueable_files (tasks_v& queue, GtkWindow * parent, c
       const std::string message_id = !profile.fqdn.empty()
       ? GNKSA::generate_message_id (profile.fqdn)
       : GNKSA::generate_message_id_from_email_address (profile.address);
+
 		  TaskUpload* tmp = new TaskUpload(std::string((const char*)cur->data),
                         profile.posting_server, _cache,
-                        a, message_id, &import, 0, TaskUpload::YENC);
+                        a, message_id, _save_file, &import, 0, TaskUpload::YENC);
 		  _file_queue_tasks.push_back(tmp);
 		}
-  	g_slist_free (tmp_list);
+    g_slist_free (tmp_list);
+
   }
-	gtk_widget_destroy (w);
   g_object_unref (G_OBJECT(message));
 	update_filequeue_tab();
 }
 
+std::string
+PostUI :: prompt_user_for_upload_nzb_dir (GtkWindow * parent, const Prefs& prefs)
+{
+  char buf[4096];
+  struct stat sb;
+  std::string path;
+
+  std::string prev_path = prefs.get_string ("default-save-attachments-path", g_get_home_dir ());
+  if (!file :: file_exists (prev_path.c_str()))
+    prev_path = g_get_home_dir ();
+  std::string prev_file(_("Untitled.nzb"));
+
+  GtkWidget * w = gtk_file_chooser_dialog_new (_("Save Upload Queue as NZB File"),
+                                                GTK_WINDOW(parent),
+                                                GTK_FILE_CHOOSER_ACTION_SAVE,
+                                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                                GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                                NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG(w), GTK_RESPONSE_ACCEPT);
+  gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (w), TRUE);
+  gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), prev_path.c_str());
+  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (w), prev_file.c_str());
+
+  GtkFileFilter * filter = gtk_file_filter_new ();
+  gtk_file_filter_add_pattern (filter, "*.[Nn][Zz][Bb]");
+  gtk_file_filter_set_name (filter, _("NZB Files"));
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(w), filter);
+  gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(w), false);
+  if (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(w)))
+  {
+    char * tmp = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
+    path = tmp;
+    g_free (tmp);
+  }
+
+  gtk_widget_destroy (w);
+  return path;
+
+}
+
+
+
 
 
diff --git a/pan/gui/post-ui.h b/pan/gui/post-ui.h
index bfc4e0f..b5362bc 100644
--- a/pan/gui/post-ui.h
+++ b/pan/gui/post-ui.h
@@ -49,6 +49,7 @@ namespace pan
                                     GMimeMessage*, Prefs&, GroupPrefs&, EncodeCache&);
 
       void prompt_user_for_queueable_files (tasks_v& queue, GtkWindow * parent, const Prefs& prefs);
+      std::string prompt_user_for_upload_nzb_dir (GtkWindow * parent, const Prefs& prefs);
 
     protected:
       PostUI (GtkWindow*, Data&, Queue&, GroupServer&, Profiles&,
@@ -127,6 +128,7 @@ namespace pan
       GtkWidget * _replyto_entry;
       GtkWidget * _body_view;
       GtkWidget * _user_agent_check;
+      GtkWidget * _save_check;
       GtkWidget * _message_id_check;
       GtkTextBuffer * _body_buf;
       GtkTextBuffer * _headers_buf;
@@ -151,6 +153,7 @@ namespace pan
       tasks_v _file_queue_tasks;
       TaskUpload* _upload_ptr;
       int _total_parts;
+      std::string _save_file;
 
     private:
       void add_actions (GtkWidget* box);
diff --git a/pan/gui/prefs-ui.cc b/pan/gui/prefs-ui.cc
index 029087f..574853d 100644
--- a/pan/gui/prefs-ui.cc
+++ b/pan/gui/prefs-ui.cc
@@ -475,7 +475,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
     HIG :: workarea_add_wide_control (t, &row, w);
     w = new_spin_button ("newsrc-autosave-timeout-min", 0, 60, prefs);
     l = gtk_label_new(_("Minutes to autosave newsrc files."));
-    HIG::workarea_add_row (t, &row, l, w); 
+    HIG::workarea_add_row (t, &row, l, w);
   HIG :: workarea_finish (t, &row);
   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("_Behavior")));
 
@@ -610,6 +610,15 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
   HIG :: workarea_finish (t, &row);
   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("A_pplications")));
 
+  row = 0;
+  t = HIG :: workarea_create ();
+  HIG :: workarea_add_section_title (t, &row, _("Upload Queue Options"));
+  HIG :: workarea_add_section_spacer (t, row, 4);
+  w = new_check_button (_("Always save article information from Uploads to a file"), "upload-queue-save-enabled", false, prefs);
+  HIG :: workarea_add_wide_control (t, &row, w);
+  HIG :: workarea_finish (t, &row);
+  gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("O_ptions for Uploads")));
+
   gtk_widget_show_all (notebook);
   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area( GTK_DIALOG(dialog))), notebook, true, true, 0);
   _root = dialog;
diff --git a/pan/tasks/encoder.cc b/pan/tasks/encoder.cc
index fcbe1fd..2c77f56 100644
--- a/pan/tasks/encoder.cc
+++ b/pan/tasks/encoder.cc
@@ -37,48 +37,38 @@ extern "C" {
 #include <pan/general/file-util.h>
 #include <pan/general/macros.h>
 #include <pan/general/utf8-utils.h>
+#include <pan/usenet-utils/MersenneTwister.h>
 #include "encoder.h"
 
 using namespace pan;
 
-namespace
+
+/** generates a unique message-id for a usenet post, consisting of
+ *  the Îsec since the Epoch and 2 random numbers from a Mersenne-Twister RNG + the internal part counter
+ *  source for RNG: http://www.jwz.org/doc/mid.html
+ */
+void
+Encoder :: generate_unique_id (StringView& mid, int cnt, std::string& s)
 {
-  void generate_unique_id (StringView& mid, std::string& filename, int cnt, std::string& s)
-  {
-    std::stringstream out;
-    struct stat sb;
-    struct timeval tv;
-
-    const char * pch = mid.strchr ('@');
-    StringView domain = mid.substr (pch+1, NULL);
-    pch = domain.strchr ('>');
-    domain = domain.substr (NULL, pch);
-    domain.trim ();
-
-    // add unique local part to message-id
-    out << "pan.";
-    const time_t now (time(NULL));
-    struct tm local_now = *gmtime (&now);
-    gettimeofday (&tv, NULL);
-    char buf[64];
-    std::strftime (buf, sizeof(buf), "%Y.%m.%d.%H.%M.%S", &local_now);
-    out << buf;
-    out << "." << tv.tv_sec << "." << tv.tv_usec << "." << tv.tv_sec*tv.tv_usec;
-
-    // delimit
-    out<< '@';
-
-    // add domain
-    out << domain;
-    s = out.str();
-  }
+  std::stringstream out;
+  struct stat sb;
+  struct timeval tv;
+  out << "pan$";
+  gettimeofday (&tv, NULL);
+  out << std::hex << tv.tv_usec << "$" << std::hex <<
+      mtrand.randInt() << "$" << std::hex << mtrand.randInt() <<std::hex << cnt;
+  // delimit
+  out<< '@';
+  // add domain
+  out << mid;
+  s = out.str();
 }
 
 Encoder :: Encoder (WorkerPool& pool):
   _worker_pool (pool),
   _gsourceid (-1)
-{
-}
+{}
+
 
 Encoder :: ~Encoder()
 {
@@ -155,8 +145,12 @@ Encoder :: do_work()
       g_snprintf(buf, sizeof(buf), "\"%s\" - %s (/%03d)", basename.c_str(), subject.c_str(), needed->size());
       tmp->subject = buf;
 
+      char cachename[4096];
       for (TaskUpload::needed_t::iterator it = needed->begin(); it != needed->end(); ++it, ++cnt)
       {
+
+        cache->get_filename(cachename, Quark(it->second.message_id));
+
         FILE * fp = cache->get_fp_from_mid(it->second.message_id);
         if (!fp)
         {
@@ -166,7 +160,7 @@ Encoder :: do_work()
         }
         // 4000 lines SHOULD be OK for ANY nntp server ...
         StringView mid(global_mid);
-        generate_unique_id(mid, filename, cnt, s);
+        generate_unique_id(mid, cnt, s);
         res = UUE_PrepPartial (fp, NULL, (char*)filename.c_str(),YENC_ENCODED,
                                (char*)basename.c_str(),0644, cnt, 4000,
                                0, (char*)groups.c_str(),
@@ -174,19 +168,16 @@ Encoder :: do_work()
                                (char*)subject.c_str(), (char*)s.c_str(), 0);
 
         if (res != UURET_CONT) break;
-
         cache->finalize(it->second.message_id);
-        stat (it->second.message_id.c_str(), &sb);
+        stat (cachename, &sb);
         it->second.bytes  = sb.st_size;
         task->_all_bytes += sb.st_size;
-
-        std::cerr<<"add to batch: "<<it->second.message_id<<" "<<sb.st_size<<"\n";
-
         batch.add_part(cnt, StringView(s), sb.st_size);
       }
 
       if (res != UURET_OK)
       {
+        unlink(cachename); //brute-force
         g_snprintf(buf, bufsz,
                    _("Error encoding %s: %s"),
                    basename.c_str(),
diff --git a/pan/tasks/encoder.h b/pan/tasks/encoder.h
index 405d43e..e027498 100644
--- a/pan/tasks/encoder.h
+++ b/pan/tasks/encoder.h
@@ -31,6 +31,8 @@
 #include <pan/general/locking.h>
 #include <pan/general/worker-pool.h>
 #include <pan/tasks/task-upload.h>
+#include <pan/usenet-utils/MersenneTwister.h>
+
 extern "C" {
 #  define PROTOTYPES
 #  include <uulib/uudeview.h>
@@ -92,6 +94,9 @@ namespace pan
       TaskUpload::needed_t* needed;
       std::string global_mid;
       Article article;
+      MTRand mtrand;
+
+      void generate_unique_id (StringView& mid, int cnt, std::string& s);
 
       // These are set in the worker thread and polled in the main thread.
       Mutex mut;
diff --git a/pan/tasks/nzb.cc b/pan/tasks/nzb.cc
index 7cafa04..97ec500 100644
--- a/pan/tasks/nzb.cc
+++ b/pan/tasks/nzb.cc
@@ -47,8 +47,9 @@ namespace
     quarks_t groups;
     std::string text;
     std::string path;
-    std::vector<std::string>  groups_str;    // TaskUpload
-    TaskUpload::needed_t needed_parts;       // TaskUpload
+    std::vector<std::string>  groups_str;  // TaskUpload
+    TaskUpload::needed_t needed_parts;     // TaskUpload
+    std::string domain;                    // TaskUpload
     Article a;
     PartBatch parts;
     tasks_t tasks;
@@ -74,7 +75,8 @@ namespace
       a.clear ();
       bytes = 0;
       number = 0;
-      needed_parts.clear();     // TaskUpload
+      needed_parts.clear();   // TaskUpload
+      domain.clear();         // TaskUpload
     }
   };
 
@@ -103,6 +105,7 @@ namespace
              if (!strcmp (*k,"author"))  mc.a.author = *v;
         else if (!strcmp (*k,"subject")) mc.a.subject = *v;
         else if (!strcmp (*k,"server"))  mc.server = *v;
+        else if (!strcmp (*k,"domain"))  mc.domain = *v;
       }
     }
 
@@ -149,10 +152,6 @@ namespace
     }
 
     else if (!strcmp(element_name, "part") && mc.number && !mc.text.empty()) {
-//      if (mc.a.message_id.empty()) {
-//        mc.a.message_id = mc.text;
-//        mc.parts.init (mc.text);
-//      }
       mc.a.message_id = mc.text;
       TaskUpload::Needed n;
       n.partno = mc.number;
@@ -183,13 +182,11 @@ namespace
     else if (!strcmp (element_name, "upload"))
     {
       debug("adding taskupload from nzb.\n");
-//      mc.parts.sort ();
-//      mc.a.set_parts (mc.parts);
-//      foreach_const (quarks_t, mc.groups, git)
-//        mc.a.xref.insert (mc.server, *git,0);
-
-      TaskUpload* tmp = new TaskUpload (mc.path, mc.server, mc.encode_cache,
-                          mc.a, mc.a.message_id.to_string() , &mc.needed_parts, 0, TaskUpload::YENC);
+      foreach_const (quarks_t, mc.groups, git)
+        mc.a.xref.insert (mc.server, *git, 0);
+      TaskUpload* tmp = new TaskUpload (mc.path, mc.server, mc.encode_cache,mc.a,
+                                        mc.domain, std::string(""),
+                                        &mc.needed_parts, 0, TaskUpload::YENC);
       mc.tasks.push_back (tmp);
     }
   }
@@ -356,7 +353,9 @@ NZB :: nzb_to_xml (std::ostream             & out,
       out  << "\" subject=\"";
       escaped (out, task->_subject);
       out  << "\" server=\"";
-      escaped (out, task->_server.to_string()) << "\">\n";
+      escaped (out, task->_server.to_string());
+      out  << "\" domain=\"nospam@";
+      escaped (out, task->_domain) << "\">\n";
       ++depth;
       out << indent(depth)
           << "<path>" << task->_filename << "</path>\n";
diff --git a/pan/tasks/task-upload.cc b/pan/tasks/task-upload.cc
index 31b6487..83e2c3e 100644
--- a/pan/tasks/task-upload.cc
+++ b/pan/tasks/task-upload.cc
@@ -43,8 +43,6 @@ extern "C" {
 
 using namespace pan;
 
-///TODO refresh actual filesize inside article parts! (by encoder)
-
 namespace
 {
   std::string get_description (const char* name)
@@ -66,6 +64,22 @@ namespace
   }
 }
 
+namespace
+{
+  std::string get_domain(const StringView& mid)
+  {
+    const char * pch = mid.strchr ('@');
+    StringView domain;
+    if (pch) domain = mid.substr (pch+1, NULL);
+    if (pch) pch = domain.strchr ('>');
+    if (pch) domain = domain.substr (NULL, pch);
+    domain.trim ();
+
+    std::cerr<<"generate domain : "<<domain<<std::endl;
+
+    return domain.to_string();
+  }
+}
 
 /***
 ****
@@ -75,7 +89,8 @@ TaskUpload :: TaskUpload (const std::string         & filename,
                           const Quark               & server,
                           EncodeCache               & cache,
                           Article                     article,
-                          std::string                 mid,
+                          std::string                 domain,
+                          std::string                 save_file,
                           needed_t                  * imported,
                           Progress::Listener        * listener,
                           const TaskUpload::EncodeMode  enc):
@@ -85,12 +100,13 @@ TaskUpload :: TaskUpload (const std::string         & filename,
   _server(server),
   _cache(cache),
   _article(article),
+  _domain(get_domain(StringView(domain))),
+  _save_file(save_file),
   _subject (article.subject.to_string()),
   _author(article.author.to_string()),
   _encoder(0),
   _encoder_has_run (false),
   _encode_mode(enc),
-  _mid(mid),
   _lines_per_file(4000),
   _all_bytes(0)
 {
@@ -121,10 +137,6 @@ TaskUpload :: build_needed_tasks(bool imported)
   foreach_const (Xref, _article.xref, it)
     _groups.insert (it->group);
 
-//  TaskUpload::Needed n;
-//  foreach_const (quarks_t, groups, git)
-//      n.xref.insert (_server, *git, StringView(buf)==_article.message_id.to_string()
-//                     ? _article.xref.find_number(_server,*git) : 0);
   Article::mid_sequence_t mids;
   foreach (needed_t, _needed, it)
   {
@@ -207,14 +219,14 @@ TaskUpload :: use_nntp (NNTP * nntp)
 void
 TaskUpload :: on_nntp_line (NNTP * nntp,
                               const StringView & line_in)
-{}
+{
+}
 
 void
 TaskUpload :: on_nntp_done (NNTP * nntp,
                              Health health,
                              const StringView & response)
 {
-
   char buf[4096];
   Log::Entry tmp;
   tmp.date = time(NULL);
@@ -274,18 +286,18 @@ TaskUpload :: on_nntp_done (NNTP * nntp,
         _logfile.push_back(tmp);
         Log::add_entry_list (tmp, _logfile);
         _logfile.clear();
-      } else
-      {
-        Log::add_entry_list (tmp, _logfile);
-        _logfile.clear();
-        Log :: add_err_va (_("Posting of file %s not successful: Check the popup log!"),
-                   _basename.c_str(), response.str);
       }
-      break;
+
     case TOO_MANY_CONNECTIONS:
       // lockout for 120 secs, but try
       _state.set_need_nntp(nntp->_server);
       break;
+    default:
+      Log::add_entry_list (tmp, _logfile);
+      _logfile.clear();
+      Log :: add_err_va (_("Posting of file %s not successful: Check the popup log!"),
+                 _basename.c_str(), response.str);
+      break;
   }
 
   _end:
@@ -327,7 +339,7 @@ TaskUpload :: use_encoder (Encoder* encoder)
     groups += (*it).to_string();
   }
   _encoder->enqueue (this, &_cache, _article, _filename, _basename,
-                     groups, _subject, _author, _mid, YENC);
+                     groups, _subject, _author, _domain, YENC);
   debug ("encoder thread was free, enqueued work");
 }
 
@@ -373,16 +385,6 @@ TaskUpload :: on_worker_done (bool cancelled)
   check_in (d);
 }
 
-namespace
-{
-  void add_to_upload_list(std::vector<Article*>& vec)
-  {
-    std::ofstream out("/home/imhotep/download_list", std::fstream::out | std::fstream::app);
-    NZB :: upload_list_to_xml_file (out, vec);
-    out.close();
-  }
-}
-
 TaskUpload :: ~TaskUpload ()
 {
   // ensure our on_worker_done() doesn't get called after we're dead
@@ -392,5 +394,10 @@ TaskUpload :: ~TaskUpload ()
   _cache.release(_article.get_part_mids());
   _cache.resize();
 
-  add_to_upload_list(_upload_list);
+  if (!_save_file.empty())
+  {
+     std::ofstream out(_save_file.c_str(), std::fstream::out | std::fstream::app);
+     NZB :: upload_list_to_xml_file (out, _upload_list);
+     out.close();
+  }
 }
diff --git a/pan/tasks/task-upload.h b/pan/tasks/task-upload.h
index 0106d2d..3b3eff8 100644
--- a/pan/tasks/task-upload.h
+++ b/pan/tasks/task-upload.h
@@ -80,7 +80,8 @@ namespace pan
                    const Quark               & server,
                    EncodeCache               & cache,
                    Article                     article,
-                   std::string                 mid,
+                   std::string                 domain,
+                   std::string                 save_file,
                    needed_t                  * imported=0,
                    Progress::Listener        * listener= 0,
                    TaskUpload::EncodeMode enc= YENC);
@@ -135,9 +136,10 @@ namespace pan
       EncodeCache& _cache;
       std::deque<Log::Entry> _logfile;   // for intermediate updates
       Article _article;
-      std::string _mid;
+      std::string _domain;
       unsigned long _all_bytes;
       std::vector<Article*> _upload_list;
+      std::string _save_file;
 
     private:
       needed_t       _needed;
diff --git a/pan/usenet-utils/Makefile.am b/pan/usenet-utils/Makefile.am
index e845479..32749af 100644
--- a/pan/usenet-utils/Makefile.am
+++ b/pan/usenet-utils/Makefile.am
@@ -10,7 +10,8 @@ libusenetutils_a_SOURCES = \
  numbers.cc \
  scorefile.cc \
  text-massager.cc \
- url-find.cc
+ url-find.cc \
+ MersenneTwister.h
 
 noinst_HEADERS = \
  defgroup.h \
diff --git a/pan/usenet-utils/MersenneTwister.h b/pan/usenet-utils/MersenneTwister.h
new file mode 100644
index 0000000..df1b9ec
--- /dev/null
+++ b/pan/usenet-utils/MersenneTwister.h
@@ -0,0 +1,461 @@
+// MersenneTwister.h
+// Mersenne Twister random number generator -- a C++ class MTRand
+// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
+// Richard J. Wagner  v1.1  28 September 2009  wagnerr umich edu
+
+// The Mersenne Twister is an algorithm for generating random numbers.  It
+// was designed with consideration of the flaws in various other generators.
+// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
+// are far greater.  The generator is also fast; it avoids multiplication and
+// division, and it benefits from caches and pipelines.  For more information
+// see the inventors' web page at
+// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+
+// Reference
+// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
+// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
+// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
+
+// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+// Copyright (C) 2000 - 2009, Richard J. Wagner
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 
+//   1. Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//
+//   3. The names of its contributors may not be used to endorse or promote 
+//      products derived from this software without specific prior written 
+//      permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+// The original code included the following notice:
+// 
+//     When you use this, send an email to: m-mat math sci hiroshima-u ac jp
+//     with an appropriate reference to your work.
+// 
+// It would be nice to CC: wagnerr umich edu and Cokus math washington edu
+// when you write.
+
+#ifndef MERSENNETWISTER_H
+#define MERSENNETWISTER_H
+
+// Not thread safe (unless auto-initialization is avoided and each thread has
+// its own MTRand object)
+
+#include <iostream>
+#include <climits>
+#include <cstdio>
+#include <ctime>
+#include <cmath>
+
+class MTRand {
+// Data
+public:
+	typedef unsigned long uint32;  // unsigned integer type, at least 32 bits
+	
+	enum { N = 624 };       // length of state vector
+	enum { SAVE = N + 1 };  // length of array for save()
+
+protected:
+	enum { M = 397 };  // period parameter
+	
+	uint32 state[N];   // internal state
+	uint32 *pNext;     // next value to get from state
+	int left;          // number of values left before reload needed
+
+// Methods
+public:
+	MTRand( const uint32 oneSeed );  // initialize with a simple uint32
+	MTRand( uint32 *const bigSeed, uint32 const seedLength = N );  // or array
+	MTRand();  // auto-initialize with /dev/urandom or time() and clock()
+	MTRand( const MTRand& o );  // copy
+	
+	// Do NOT use for CRYPTOGRAPHY without securely hashing several returned
+	// values together, otherwise the generator state can be learned after
+	// reading 624 consecutive values.
+	
+	// Access to 32-bit random numbers
+	uint32 randInt();                     // integer in [0,2^32-1]
+	uint32 randInt( const uint32 n );     // integer in [0,n] for n < 2^32
+	double rand();                        // real number in [0,1]
+	double rand( const double n );        // real number in [0,n]
+	double randExc();                     // real number in [0,1)
+	double randExc( const double n );     // real number in [0,n)
+	double randDblExc();                  // real number in (0,1)
+	double randDblExc( const double n );  // real number in (0,n)
+	double operator()();                  // same as rand()
+	
+	// Access to 53-bit random numbers (capacity of IEEE double precision)
+	double rand53();  // real number in [0,1)
+	
+	// Access to nonuniform random number distributions
+	double randNorm( const double mean = 0.0, const double stddev = 1.0 );
+	
+	// Re-seeding functions with same behavior as initializers
+	void seed( const uint32 oneSeed );
+	void seed( uint32 *const bigSeed, const uint32 seedLength = N );
+	void seed();
+	
+	// Saving and loading generator state
+	void save( uint32* saveArray ) const;  // to array of size SAVE
+	void load( uint32 *const loadArray );  // from such array
+	friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
+	friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
+	MTRand& operator=( const MTRand& o );
+
+protected:
+	void initialize( const uint32 oneSeed );
+	void reload();
+	uint32 hiBit( const uint32 u ) const { return u & 0x80000000UL; }
+	uint32 loBit( const uint32 u ) const { return u & 0x00000001UL; }
+	uint32 loBits( const uint32 u ) const { return u & 0x7fffffffUL; }
+	uint32 mixBits( const uint32 u, const uint32 v ) const
+		{ return hiBit(u) | loBits(v); }
+	uint32 magic( const uint32 u ) const
+		{ return loBit(u) ? 0x9908b0dfUL : 0x0UL; }
+	uint32 twist( const uint32 m, const uint32 s0, const uint32 s1 ) const
+		{ return m ^ (mixBits(s0,s1)>>1) ^ magic(s1); }
+	static uint32 hash( time_t t, clock_t c );
+};
+
+// Functions are defined in order of usage to assist inlining
+
+inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
+{
+	// Get a uint32 from t and c
+	// Better than uint32(x) in case x is floating point in [0,1]
+	// Based on code by Lawrence Kirby (fred genesis demon co uk)
+	
+	static uint32 differ = 0;  // guarantee time-based seeds will change
+	
+	uint32 h1 = 0;
+	unsigned char *p = (unsigned char *) &t;
+	for( size_t i = 0; i < sizeof(t); ++i )
+	{
+		h1 *= UCHAR_MAX + 2U;
+		h1 += p[i];
+	}
+	uint32 h2 = 0;
+	p = (unsigned char *) &c;
+	for( size_t j = 0; j < sizeof(c); ++j )
+	{
+		h2 *= UCHAR_MAX + 2U;
+		h2 += p[j];
+	}
+	return ( h1 + differ++ ) ^ h2;
+}
+
+inline void MTRand::initialize( const uint32 seed )
+{
+	// Initialize generator state with seed
+	// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
+	// In previous versions, most significant bits (MSBs) of the seed affect
+	// only MSBs of the state array.  Modified 9 Jan 2002 by Makoto Matsumoto.
+	register uint32 *s = state;
+	register uint32 *r = state;
+	register int i = 1;
+	*s++ = seed & 0xffffffffUL;
+	for( ; i < N; ++i )
+	{
+		*s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
+		r++;
+	}
+}
+
+inline void MTRand::reload()
+{
+	// Generate N new values in state
+	// Made clearer and faster by Matthew Bellew (matthew bellew home com)
+	static const int MmN = int(M) - int(N);  // in case enums are unsigned
+	register uint32 *p = state;
+	register int i;
+	for( i = N - M; i--; ++p )
+		*p = twist( p[M], p[0], p[1] );
+	for( i = M; --i; ++p )
+		*p = twist( p[MmN], p[0], p[1] );
+	*p = twist( p[MmN], p[0], state[0] );
+	
+	left = N, pNext = state;
+}
+
+inline void MTRand::seed( const uint32 oneSeed )
+{
+	// Seed the generator with a simple uint32
+	initialize(oneSeed);
+	reload();
+}
+
+inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
+{
+	// Seed the generator with an array of uint32's
+	// There are 2^19937-1 possible initial states.  This function allows
+	// all of those to be accessed by providing at least 19937 bits (with a
+	// default seed length of N = 624 uint32's).  Any bits above the lower 32
+	// in each element are discarded.
+	// Just call seed() if you want to get array from /dev/urandom
+	initialize(19650218UL);
+	register int i = 1;
+	register uint32 j = 0;
+	register int k = ( N > seedLength ? N : seedLength );
+	for( ; k; --k )
+	{
+		state[i] =
+		state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
+		state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
+		state[i] &= 0xffffffffUL;
+		++i;  ++j;
+		if( i >= N ) { state[0] = state[N-1];  i = 1; }
+		if( j >= seedLength ) j = 0;
+	}
+	for( k = N - 1; k; --k )
+	{
+		state[i] =
+		state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
+		state[i] -= i;
+		state[i] &= 0xffffffffUL;
+		++i;
+		if( i >= N ) { state[0] = state[N-1];  i = 1; }
+	}
+	state[0] = 0x80000000UL;  // MSB is 1, assuring non-zero initial array
+	reload();
+}
+
+inline void MTRand::seed()
+{
+	// Seed the generator with an array from /dev/urandom if available
+	// Otherwise use a hash of time() and clock() values
+	
+	// First try getting an array from /dev/urandom
+	FILE* urandom = fopen( "/dev/urandom", "rb" );
+	if( urandom )
+	{
+		uint32 bigSeed[N];
+		register uint32 *s = bigSeed;
+		register int i = N;
+		register bool success = true;
+		while( success && i-- )
+			success = fread( s++, sizeof(uint32), 1, urandom );
+		fclose(urandom);
+		if( success ) { seed( bigSeed, N );  return; }
+	}
+	
+	// Was not successful, so use time() and clock() instead
+	seed( hash( time(NULL), clock() ) );
+}
+
+inline MTRand::MTRand( const uint32 oneSeed )
+	{ seed(oneSeed); }
+
+inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
+	{ seed(bigSeed,seedLength); }
+
+inline MTRand::MTRand()
+	{ seed(); }
+
+inline MTRand::MTRand( const MTRand& o )
+{
+	register const uint32 *t = o.state;
+	register uint32 *s = state;
+	register int i = N;
+	for( ; i--; *s++ = *t++ ) {}
+	left = o.left;
+	pNext = &state[N-left];
+}
+
+inline MTRand::uint32 MTRand::randInt()
+{
+	// Pull a 32-bit integer from the generator state
+	// Every other access function simply transforms the numbers extracted here
+	
+	if( left == 0 ) reload();
+	--left;
+	
+	register uint32 s1;
+	s1 = *pNext++;
+	s1 ^= (s1 >> 11);
+	s1 ^= (s1 <<  7) & 0x9d2c5680UL;
+	s1 ^= (s1 << 15) & 0xefc60000UL;
+	return ( s1 ^ (s1 >> 18) );
+}
+
+inline MTRand::uint32 MTRand::randInt( const uint32 n )
+{
+	// Find which bits are used in n
+	// Optimized by Magnus Jonsson (magnus smartelectronix com)
+	uint32 used = n;
+	used |= used >> 1;
+	used |= used >> 2;
+	used |= used >> 4;
+	used |= used >> 8;
+	used |= used >> 16;
+	
+	// Draw numbers until one is found in [0,n]
+	uint32 i;
+	do
+		i = randInt() & used;  // toss unused bits to shorten search
+	while( i > n );
+	return i;
+}
+
+inline double MTRand::rand()
+	{ return double(randInt()) * (1.0/4294967295.0); }
+
+inline double MTRand::rand( const double n )
+	{ return rand() * n; }
+
+inline double MTRand::randExc()
+	{ return double(randInt()) * (1.0/4294967296.0); }
+
+inline double MTRand::randExc( const double n )
+	{ return randExc() * n; }
+
+inline double MTRand::randDblExc()
+	{ return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
+
+inline double MTRand::randDblExc( const double n )
+	{ return randDblExc() * n; }
+
+inline double MTRand::rand53()
+{
+	uint32 a = randInt() >> 5, b = randInt() >> 6;
+	return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0);  // by Isaku Wada
+}
+
+inline double MTRand::randNorm( const double mean, const double stddev )
+{
+	// Return a real number from a normal (Gaussian) distribution with given
+	// mean and standard deviation by polar form of Box-Muller transformation
+	double x, y, r;
+	do
+	{
+		x = 2.0 * rand() - 1.0;
+		y = 2.0 * rand() - 1.0;
+		r = x * x + y * y;
+	}
+	while ( r >= 1.0 || r == 0.0 );
+	double s = sqrt( -2.0 * log(r) / r );
+	return mean + x * s * stddev;
+}
+
+inline double MTRand::operator()()
+{
+	return rand();
+}
+
+inline void MTRand::save( uint32* saveArray ) const
+{
+	register const uint32 *s = state;
+	register uint32 *sa = saveArray;
+	register int i = N;
+	for( ; i--; *sa++ = *s++ ) {}
+	*sa = left;
+}
+
+inline void MTRand::load( uint32 *const loadArray )
+{
+	register uint32 *s = state;
+	register uint32 *la = loadArray;
+	register int i = N;
+	for( ; i--; *s++ = *la++ ) {}
+	left = *la;
+	pNext = &state[N-left];
+}
+
+inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
+{
+	register const MTRand::uint32 *s = mtrand.state;
+	register int i = mtrand.N;
+	for( ; i--; os << *s++ << "\t" ) {}
+	return os << mtrand.left;
+}
+
+inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
+{
+	register MTRand::uint32 *s = mtrand.state;
+	register int i = mtrand.N;
+	for( ; i--; is >> *s++ ) {}
+	is >> mtrand.left;
+	mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
+	return is;
+}
+
+inline MTRand& MTRand::operator=( const MTRand& o )
+{
+	if( this == &o ) return (*this);
+	register const uint32 *t = o.state;
+	register uint32 *s = state;
+	register int i = N;
+	for( ; i--; *s++ = *t++ ) {}
+	left = o.left;
+	pNext = &state[N-left];
+	return (*this);
+}
+
+#endif  // MERSENNETWISTER_H
+
+// Change log:
+//
+// v0.1 - First release on 15 May 2000
+//      - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
+//      - Translated from C to C++
+//      - Made completely ANSI compliant
+//      - Designed convenient interface for initialization, seeding, and
+//        obtaining numbers in default or user-defined ranges
+//      - Added automatic seeding from /dev/urandom or time() and clock()
+//      - Provided functions for saving and loading generator state
+//
+// v0.2 - Fixed bug which reloaded generator one step too late
+//
+// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
+//
+// v0.4 - Removed trailing newline in saved generator format to be consistent
+//        with output format of built-in types
+//
+// v0.5 - Improved portability by replacing static const int's with enum's and
+//        clarifying return values in seed(); suggested by Eric Heimburg
+//      - Removed MAXINT constant; use 0xffffffffUL instead
+//
+// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
+//      - Changed integer [0,n] generator to give better uniformity
+//
+// v0.7 - Fixed operator precedence ambiguity in reload()
+//      - Added access for real numbers in (0,1) and (0,n)
+//
+// v0.8 - Included time.h header to properly support time_t and clock_t
+//
+// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
+//      - Allowed for seeding with arrays of any length
+//      - Added access for real numbers in [0,1) with 53-bit resolution
+//      - Added access for real numbers from normal (Gaussian) distributions
+//      - Increased overall speed by optimizing twist()
+//      - Doubled speed of integer [0,n] generation
+//      - Fixed out-of-range number generation on 64-bit machines
+//      - Improved portability by substituting literal constants for long enum's
+//      - Changed license from GNU LGPL to BSD
+//
+// v1.1 - Corrected parameter label in randNorm from "variance" to "stddev"
+//      - Changed randNorm algorithm from basic to polar form for efficiency
+//      - Updated includes from deprecated <xxxx.h> to standard <cxxxx> forms
+//      - Cleaned declarations and definitions to please Intel compiler
+//      - Revised twist() operator to work on ones'-complement machines
+//      - Fixed reload() function to work when N and M are unsigned
+//      - Added copy constructor and copy operator from Salvador Espana
diff --git a/uulib/uudeview.h b/uulib/uudeview.h
index 8df7e9d..258ef37 100644
--- a/uulib/uudeview.h
+++ b/uulib/uudeview.h
@@ -237,7 +237,7 @@ int	UUEXPORT UUEncodeToFile		_ANSI_ARGS_((FILE *, char *, int,
 int	UUEXPORT UUE_PrepSingle		_ANSI_ARGS_((FILE *, FILE *,
 						     char *, int,
 						     char *, int,
-						     char *, char *,
+						     char *, char *, char*,
 						     char *, int));
 int	UUEXPORT UUE_PrepPartial	_ANSI_ARGS_((FILE *, FILE *,
 						     char *, int,
@@ -249,7 +249,7 @@ int	UUEXPORT UUE_PrepSingleExt	_ANSI_ARGS_((FILE *, FILE *,
 						     char *, int,
 						     char *, int,
 						     char *, char *,
-						     char *, char *,
+						     char *, char *, char*,
 						     int));
 int	UUEXPORT UUE_PrepPartialExt	_ANSI_ARGS_((FILE *, FILE *,
 						     char *, int,
diff --git a/uulib/uuencode.c b/uulib/uuencode.c
index c02eba3..e71f582 100644
--- a/uulib/uuencode.c
+++ b/uulib/uuencode.c
@@ -1491,13 +1491,13 @@ UUE_PrepSingle (FILE *outfile, FILE *infile,
 		char *infname, int encoding,
 		char *outfname, int filemode,
 		char *destination, char *from,
-		char *subject, int isemail)
+		char *subject, char* mid, int isemail)
 {
   return UUE_PrepSingleExt (outfile, infile,
 			    infname, encoding,
 			    outfname, filemode,
 			    destination, from,
-			    subject, NULL,
+			    subject, mid, NULL,
 			    isemail);
 }
 
@@ -1506,7 +1506,7 @@ UUE_PrepSingleExt (FILE *outfile, FILE *infile,
 		   char *infname, int encoding,
 		   char *outfname, int filemode,
 		   char *destination, char *from,
-		   char *subject, char *replyto,
+		   char *subject, char* mid, char *replyto,
 		   int isemail)
 {
   mimemap *miter=mimetable;
@@ -1547,9 +1547,9 @@ UUE_PrepSingleExt (FILE *outfile, FILE *infile,
 
   if (encoding == YENC_ENCODED) {
     if (subject)
-      sprintf (subline, "- %s - %s (001/001)", oname, subject);
+      sprintf (subline, "\"%s\" - %s (001/001)", oname, subject);
     else
-      sprintf (subline, "- %s - (001/001)", oname);
+      sprintf (subline, "\"%s\" - (001/001)", oname);
   }
   else {
     if (subject)
@@ -1569,6 +1569,12 @@ UUE_PrepSingleExt (FILE *outfile, FILE *infile,
 
   fprintf (outfile, "Subject: %s%s", subline, eolstring);
 
+  if (mid)
+  {
+    fprintf(outfile, "Message-ID: <%s>%s", mid, eolstring);
+  }
+
+
   if (replyto) {
     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
   }
@@ -1709,7 +1715,7 @@ UUE_PrepPartialExt (FILE *outfile, FILE *infile,
       if (infile==NULL) fclose (theifile);
       return UUE_PrepSingleExt (outfile, infile, infname, encoding,
 				outfname, filemode, destination,
-				from, subject, replyto, isemail);
+				from, subject, mid, replyto, isemail);
     }
 
     /*
@@ -1761,10 +1767,10 @@ UUE_PrepPartialExt (FILE *outfile, FILE *infile,
 
   fprintf (outfile, "Subject: %s%s", subline, eolstring);
 
-//  if (mid)
-//  {
-//    fprintf(outfile, "Message-ID: <%s>%s", mid, eolstring);
-//  }
+  if (mid)
+  {
+    fprintf(outfile, "Message-ID: <%s>%s", mid, eolstring);
+  }
 
   if (replyto) {
     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);



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