[pan2/testing] + invert selection + gnome-keyring implementation + preparations for yenc glib changes
- From: Heinrich MÃller <henmull src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pan2/testing] + invert selection + gnome-keyring implementation + preparations for yenc glib changes
- Date: Fri, 9 Dec 2011 14:26:50 +0000 (UTC)
commit 70dac2530883b844f8cbf031ff677e17d9fbc53f
Author: Heinrich MÃller <henmull src gnome org>
Date: Tue Dec 6 03:30:50 2011 +0100
+ invert selection
+ gnome-keyring implementation
+ preparations for yenc glib changes
configure.in | 16 +-
gtkspell/examples/advanced.c | 82 ++
gtkspell/examples/simple.c | 58 +
gtkspell/gtkspell/deprecated.c | 35 +
gtkspell/gtkspell/gtkspell.c | 888 ++++++++++++
pan/data-impl/Makefile.am | 8 +-
pan/data-impl/data-impl.cc | 115 ++
pan/data-impl/data-impl.h | 19 +
pan/data-impl/server.cc | 35 +-
pan/data/data.h | 16 +-
pan/gui/Makefile.am | 5 +-
pan/gui/actions.cc | 20 +-
pan/gui/dl-headers-ui.cc | 2 +-
pan/gui/gui.cc | 15 +
pan/gui/gui.h | 2 +
pan/gui/header-pane.cc | 37 +-
pan/gui/header-pane.h | 4 +-
pan/gui/pan-ui.h | 2 +
pan/gui/pan.cc | 6 +
pan/gui/pan.ui.h | 8 +
pan/gui/server-ui.cc | 10 +-
pan/icons/icon_get_flagged.png | Bin 935 -> 1128 bytes
pan/tasks/Makefile.am | 2 +
pan/tasks/nntp-pool.cc | 5 +-
pan/tasks/nntp.cc | 88 ++-
pan/tasks/nntp.h | 22 +-
pan/tasks/task-xoverinfo.cc | 208 +++
pan/tasks/task-xoverinfo.h | 90 ++
pan/usenet-utils/Makefile.am | 7 +-
pan/usenet-utils/blowfish.cc | 229 +++
pan/usenet-utils/blowfish.h | 79 +
pan/usenet-utils/blowfish_cyphers.h | 268 ++++
yenclib/crc32.c | 614 ++++++++
yenclib/crc32.h | 38 +
yenclib/uuencode.c | 2692 +++++++++++++++++++++++++++++++++++
yenclib/uunconc.c | 1718 ++++++++++++++++++++++
36 files changed, 7413 insertions(+), 30 deletions(-)
---
diff --git a/configure.in b/configure.in
index 6ab3e39..b95f646 100644
--- a/configure.in
+++ b/configure.in
@@ -53,6 +53,7 @@ GTKSPELL_REQUIRED=2.0.7
OPENSSL_REQUIRED=1.0.0
LIBNOTIFY_REQUIRED=0.4.1
LIBGSASL_REQUIRED=1.6.1
+LIBGKR_REQUIRED=6.2.2
AC_SUBST(GLIB_REQUIRED)
AC_SUBST(GMIME_REQUIRED)
AC_SUBST(GTK_REQUIRED)
@@ -60,6 +61,7 @@ AC_SUBST(GTKSPELL_REQUIRED)
AC_SUBST(OPENSSL_REQUIRED)
AC_SUBST(LIBNOTIFY_REQUIRED)
AC_SUBST(LIBGSASL_REQUIRED)
+AC_SUBST(LIBGKR_REQUIRED)
AC_PROG_CXX
AC_HEADER_STDC
@@ -137,6 +139,14 @@ if test "x$HAVE_SASL" = "xyes"; then
AC_DEFINE([HAVE_SASL],[1],[libgsasl for secure NNTP authentication])
fi
+dnl Check for gnome-keyring for password storage
+PKG_CHECK_MODULES([LIBGNOME_KEYRING_1],[gnome-keyring-1 >= $LIBGKR_REQUIRED],[HAVE_GKR="yes"],[HAVE_GKR="no"])
+AC_SUBST([LIBGNOME_KEYRING_1_CFLAGS])
+AC_SUBST([LIBGNOME_KEYRING_1_LIBS])
+if test "x$HAVE_GKR" = "xyes"; then
+ AC_DEFINE([HAVE_GKR],[1],[gnome-keyring-1 for password storage])
+fi
+
dnl Check to see if strftime supports the use of %l and %k
AC_MSG_CHECKING(for %l and %k support in strftime)
@@ -188,9 +198,9 @@ case $host_os in
esac
AM_CONDITIONAL([HAVE_WIN32],[test "$win32" = "yes"])
-CXXFLAGS="$CXXFLAGS -g"
-CPPFLAGS="$CPPFLAGS -g"
-CFLAGS="$CFLAGS -g"
+CXXFLAGS="$CXXFLAGS -g -I/usr/lib/"
+CPPFLAGS="$CPPFLAGS -g -I/usr/lib/"
+CFLAGS="$CFLAGS -g -I/usr/lib/"
dnl build the output files
AC_SUBST(panlocaledir)
diff --git a/gtkspell/examples/advanced.c b/gtkspell/examples/advanced.c
new file mode 100644
index 0000000..1ce2273
--- /dev/null
+++ b/gtkspell/examples/advanced.c
@@ -0,0 +1,82 @@
+/* vim: set ts=4 sw=4 wm=5 : */
+
+/* This example demonstrates detaching and reattaching GtkSpell. */
+
+#include <gtk/gtk.h>
+#include <gtkspell/gtkspell.h>
+
+GtkWidget *window, *attached, *view;
+
+static void
+report_gtkspell_error(const char *err) {
+ GtkWidget *dlg;
+ dlg = gtk_message_dialog_new(
+ GTK_WINDOW(window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "GtkSpell error: %s", err);
+ gtk_dialog_run(GTK_DIALOG(dlg));
+ gtk_widget_destroy(dlg);
+}
+
+static void
+attach_cb() {
+ GtkSpell *spell;
+ GError *error = NULL;
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(attached))) {
+ spell = gtkspell_new_attach(GTK_TEXT_VIEW(view), NULL, &error);
+
+ if (spell == NULL) {
+ report_gtkspell_error(error->message);
+ g_error_free(error);
+ }
+ } else {
+ gtkspell_detach(gtkspell_get_from_text_view(GTK_TEXT_VIEW(view)));
+ }
+}
+
+int
+main(int argc, char* argv[]) {
+ GtkWidget *box, *hbox, *scroll;
+
+ gtk_init(&argc, &argv);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ view = gtk_text_view_new();
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
+ GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(scroll), view);
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ attached = gtk_toggle_button_new_with_label("Attached");
+ g_signal_connect(G_OBJECT(attached), "toggled",
+ G_CALLBACK(attach_cb), NULL);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(attached), TRUE);
+ gtk_box_pack_start(GTK_BOX(hbox), attached, FALSE, FALSE, 0);
+
+ box = gtk_vbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
+ gtk_widget_show_all(box);
+
+ gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
+ gtk_window_set_title(GTK_WINDOW(window), "\"Advanced\" GtkSpell Demonstration");
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+ g_signal_connect(G_OBJECT(window), "delete-event",
+ G_CALLBACK(gtk_main_quit), NULL);
+ gtk_container_add(GTK_CONTAINER(window), box);
+
+ gtk_widget_show(window);
+ gtk_main();
+
+ return 0;
+}
diff --git a/gtkspell/examples/simple.c b/gtkspell/examples/simple.c
new file mode 100644
index 0000000..cc454f1
--- /dev/null
+++ b/gtkspell/examples/simple.c
@@ -0,0 +1,58 @@
+/* vim: set ts=4 sw=4 wm=5 : */
+
+#include <gtk/gtk.h>
+#include <gtkspell/gtkspell.h>
+
+int
+main(int argc, char* argv[]) {
+ GtkWidget *win, *box, *scroll, *view;
+ GError *error = NULL;
+ char *errortext = NULL;
+
+ gtk_init(&argc, &argv);
+
+ view = gtk_text_view_new();
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
+
+ if (gtkspell_new_attach(GTK_TEXT_VIEW(view), NULL, &error) == NULL) {
+ g_print("gtkspell error: %s\n", error->message);
+ errortext = g_strdup_printf("GtkSpell was unable to initialize.\n"
+ "%s", error->message);
+ g_error_free(error);
+ }
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
+ GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(scroll), view);
+
+ box = gtk_vbox_new(FALSE, 5);
+ if (errortext) {
+ gtk_box_pack_start(GTK_BOX(box), gtk_label_new(errortext),
+ FALSE, FALSE, 0);
+ g_free(errortext);
+ } else {
+ gtk_box_pack_start(GTK_BOX(box),
+ gtk_label_new("Type some text into the text box.\n"
+ "Try misspelling some words. Then right-click on them."),
+ FALSE, FALSE, 0);
+ }
+ gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
+ gtk_widget_show_all(box);
+
+ win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size(GTK_WINDOW(win), 400, 300);
+ gtk_window_set_title(GTK_WINDOW(win), "Simple GtkSpell Demonstration");
+ gtk_container_set_border_width(GTK_CONTAINER(win), 10);
+ g_signal_connect(G_OBJECT(win), "delete-event",
+ G_CALLBACK(gtk_main_quit), NULL);
+ gtk_container_add(GTK_CONTAINER(win), box);
+
+ gtk_widget_show(win);
+ gtk_main();
+
+ return 0;
+}
diff --git a/gtkspell/gtkspell/deprecated.c b/gtkspell/gtkspell/deprecated.c
new file mode 100644
index 0000000..7fe93e2
--- /dev/null
+++ b/gtkspell/gtkspell/deprecated.c
@@ -0,0 +1,35 @@
+/* gtkspell - a spell-checking addon for GTK's TextView widget
+ * Copyright (c) 2002 Evan Martin.
+ */
+
+/* vim: set ts=4 sw=4 wm=5 : */
+
+#include <gtk/gtk.h>
+#include "gtkspell.h"
+
+/**
+ * gtkspell_init:
+ *
+ * This function is deprecated and included only for backward
+ * compatibility.
+ *
+ * Returns: nothing.
+ */
+int
+gtkspell_init() {
+ /* we do nothing. */
+ return 0;
+}
+
+/**
+ * gtkspell_attach:
+ * @view: a #GtkTextView.
+ *
+ * This function is deprecated and included only for backward
+ * compatibility. It calls gtkspell_new_attach() with the default language
+ * and without error handling.
+ */
+void
+gtkspell_attach(GtkTextView *view) {
+ gtkspell_new_attach(view, NULL, NULL);
+}
diff --git a/gtkspell/gtkspell/gtkspell.c b/gtkspell/gtkspell/gtkspell.c
new file mode 100644
index 0000000..ecca064
--- /dev/null
+++ b/gtkspell/gtkspell/gtkspell.c
@@ -0,0 +1,888 @@
+/* gtkspell - a spell-checking addon for GTK's TextView widget
+ * Copyright (c) 2002 Evan Martin.
+ */
+
+/* vim: set ts=4 sw=4 wm=5 : */
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <libintl.h>
+#include <locale.h>
+#include "../config.h"
+#include "gtkspell.h"
+
+#define _(String) dgettext (PACKAGE, String)
+
+#define GTKSPELL_MISSPELLED_TAG "gtkspell-misspelled"
+
+#include <enchant.h>
+
+static const int debug = 0;
+static const int quiet = 0;
+
+static EnchantBroker *broker = NULL;
+static int broker_ref_cnt;
+
+struct _GtkSpell {
+ GtkTextView *view;
+ GtkTextBuffer *buffer;
+ GtkTextTag *tag_highlight;
+ GtkTextMark *mark_insert_start;
+ GtkTextMark *mark_insert_end;
+ gboolean deferred_check;
+ EnchantDict *speller;
+ GtkTextMark *mark_click;
+ gchar *lang;
+};
+
+static void gtkspell_free(GtkSpell *spell);
+
+#define GTKSPELL_OBJECT_KEY "gtkspell"
+
+GQuark
+gtkspell_error_quark(void) {
+ static GQuark q = 0;
+ if (q == 0)
+ q = g_quark_from_static_string("gtkspell-error-quark");
+ return q;
+}
+
+static gboolean
+gtkspell_text_iter_forward_word_end(GtkTextIter *i) {
+ GtkTextIter iter;
+
+/* heuristic:
+ * if we're on an singlequote/apostrophe and
+ * if the next letter is alphanumeric,
+ * this is an apostrophe. */
+
+ if (!gtk_text_iter_forward_word_end(i))
+ return FALSE;
+
+ if (gtk_text_iter_get_char(i) != '\'')
+ return TRUE;
+
+ iter = *i;
+ if (gtk_text_iter_forward_char(&iter)) {
+ if (g_unichar_isalpha(gtk_text_iter_get_char(&iter))) {
+ return (gtk_text_iter_forward_word_end(i));
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gtkspell_text_iter_backward_word_start(GtkTextIter *i) {
+ GtkTextIter iter;
+
+ if (!gtk_text_iter_backward_word_start(i))
+ return FALSE;
+
+ iter = *i;
+ if (gtk_text_iter_backward_char(&iter)) {
+ if (gtk_text_iter_get_char(&iter) == '\'') {
+ if (gtk_text_iter_backward_char(&iter)) {
+ if (g_unichar_isalpha(gtk_text_iter_get_char(&iter))) {
+ return (gtk_text_iter_backward_word_start(i));
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+#define gtk_text_iter_backward_word_start gtkspell_text_iter_backward_word_start
+#define gtk_text_iter_forward_word_end gtkspell_text_iter_forward_word_end
+
+static void
+check_word(GtkSpell *spell, GtkTextBuffer *buffer,
+ GtkTextIter *start, GtkTextIter *end) {
+ char *text;
+ if (!spell->speller)
+ return;
+ text = gtk_text_buffer_get_text(buffer, start, end, FALSE);
+ if (debug) g_print("checking: %s\n", text);
+ if (g_unichar_isdigit(*text) == FALSE) /* don't check numbers */
+ if (enchant_dict_check(spell->speller, text, strlen(text)) != 0)
+ gtk_text_buffer_apply_tag(buffer, spell->tag_highlight, start, end);
+ g_free(text);
+}
+
+static void
+print_iter(char *name, GtkTextIter *iter) {
+ g_print("%1s[%d%c%c%c] ", name, gtk_text_iter_get_offset(iter),
+ gtk_text_iter_starts_word(iter) ? 's' : ' ',
+ gtk_text_iter_inside_word(iter) ? 'i' : ' ',
+ gtk_text_iter_ends_word(iter) ? 'e' : ' ');
+}
+
+static void
+check_range(GtkSpell *spell, GtkTextBuffer *buffer,
+ GtkTextIter start, GtkTextIter end, gboolean force_all) {
+ /* we need to "split" on word boundaries.
+ * luckily, pango knows what "words" are
+ * so we don't have to figure it out. */
+
+ GtkTextIter wstart, wend, cursor, precursor;
+ gboolean inword, highlight;
+ if (debug) {
+ g_print("check_range: "); print_iter("s", &start); print_iter("e", &end); g_print(" -> ");
+ }
+
+ if (gtk_text_iter_inside_word(&end))
+ gtk_text_iter_forward_word_end(&end);
+ if (!gtk_text_iter_starts_word(&start)) {
+ if (gtk_text_iter_inside_word(&start) ||
+ gtk_text_iter_ends_word(&start)) {
+ gtk_text_iter_backward_word_start(&start);
+ } else {
+ /* if we're neither at the beginning nor inside a word,
+ * me must be in some spaces.
+ * skip forward to the beginning of the next word. */
+ //gtk_text_buffer_remove_tag(buffer, tag_highlight, &start, &end);
+ if (gtk_text_iter_forward_word_end(&start))
+ gtk_text_iter_backward_word_start(&start);
+ }
+ }
+ gtk_text_buffer_get_iter_at_mark(buffer, &cursor,
+ gtk_text_buffer_get_insert(buffer));
+
+ precursor = cursor;
+ gtk_text_iter_backward_char(&precursor);
+ highlight = gtk_text_iter_has_tag(&cursor, spell->tag_highlight) ||
+ gtk_text_iter_has_tag(&precursor, spell->tag_highlight);
+
+ gtk_text_buffer_remove_tag(buffer, spell->tag_highlight, &start, &end);
+
+ /* Fix a corner case when replacement occurs at beginning of buffer:
+ * An iter at offset 0 seems to always be inside a word,
+ * even if it's not. Possibly a pango bug.
+ */
+ if (gtk_text_iter_get_offset(&start) == 0) {
+ gtk_text_iter_forward_word_end(&start);
+ gtk_text_iter_backward_word_start(&start);
+ }
+
+ if (debug) {print_iter("s", &start); print_iter("e", &end); g_print("\n");}
+
+ wstart = start;
+ while (gtk_text_iter_compare(&wstart, &end) < 0) {
+ /* move wend to the end of the current word. */
+ wend = wstart;
+ gtk_text_iter_forward_word_end(&wend);
+
+ inword = (gtk_text_iter_compare(&wstart, &cursor) < 0) &&
+ (gtk_text_iter_compare(&cursor, &wend) <= 0);
+
+ if (inword && !force_all) {
+ /* this word is being actively edited,
+ * only check if it's already highligted,
+ * otherwise defer this check until later. */
+ if (highlight)
+ check_word(spell, buffer, &wstart, &wend);
+ else
+ spell->deferred_check = TRUE;
+ } else {
+ check_word(spell, buffer, &wstart, &wend);
+ spell->deferred_check = FALSE;
+ }
+
+ /* now move wend to the beginning of the next word, */
+ gtk_text_iter_forward_word_end(&wend);
+ gtk_text_iter_backward_word_start(&wend);
+ /* make sure we've actually advanced
+ * (we don't advance in some corner cases), */
+ if (gtk_text_iter_equal(&wstart, &wend))
+ break; /* we're done in these cases.. */
+ /* and then pick this as the new next word beginning. */
+ wstart = wend;
+ }
+}
+
+static void
+check_deferred_range(GtkSpell *spell, GtkTextBuffer *buffer, gboolean force_all) {
+ GtkTextIter start, end;
+ gtk_text_buffer_get_iter_at_mark(buffer, &start, spell->mark_insert_start);
+ gtk_text_buffer_get_iter_at_mark(buffer, &end, spell->mark_insert_end);
+ check_range(spell, buffer, start, end, force_all);
+}
+
+/* insertion works like this:
+ * - before the text is inserted, we mark the position in the buffer.
+ * - after the text is inserted, we see where our mark is and use that and
+ * the current position to check the entire range of inserted text.
+ *
+ * this may be overkill for the common case (inserting one character). */
+
+static void
+insert_text_before(GtkTextBuffer *buffer, GtkTextIter *iter,
+ gchar *text, gint len, GtkSpell *spell) {
+ gtk_text_buffer_move_mark(buffer, spell->mark_insert_start, iter);
+}
+
+static void
+insert_text_after(GtkTextBuffer *buffer, GtkTextIter *iter,
+ gchar *text, gint len, GtkSpell *spell) {
+ GtkTextIter start;
+
+ if (debug) g_print("insert\n");
+
+ /* we need to check a range of text. */
+ gtk_text_buffer_get_iter_at_mark(buffer, &start, spell->mark_insert_start);
+ check_range(spell, buffer, start, *iter, FALSE);
+
+ gtk_text_buffer_move_mark(buffer, spell->mark_insert_end, iter);
+}
+
+/* deleting is more simple: we're given the range of deleted text.
+ * after deletion, the start and end iters should be at the same position
+ * (because all of the text between them was deleted!).
+ * this means we only really check the words immediately bounding the
+ * deletion.
+ */
+
+static void
+delete_range_after(GtkTextBuffer *buffer,
+ GtkTextIter *start, GtkTextIter *end, GtkSpell *spell) {
+ if (debug) g_print("delete\n");
+ check_range(spell, buffer, *start, *end, FALSE);
+}
+
+static void
+mark_set(GtkTextBuffer *buffer, GtkTextIter *iter,
+ GtkTextMark *mark, GtkSpell *spell) {
+ /* if the cursor has moved and there is a deferred check so handle it now */
+ if ((mark == gtk_text_buffer_get_insert(buffer)) && spell->deferred_check)
+ check_deferred_range(spell, buffer, FALSE);
+}
+
+static void
+get_word_extents_from_mark(GtkTextBuffer *buffer,
+ GtkTextIter *start, GtkTextIter *end, GtkTextMark *mark) {
+ gtk_text_buffer_get_iter_at_mark(buffer, start, mark);
+ if (!gtk_text_iter_starts_word(start))
+ gtk_text_iter_backward_word_start(start);
+ *end = *start;
+ if (gtk_text_iter_inside_word(end))
+ gtk_text_iter_forward_word_end(end);
+}
+
+static void
+add_to_dictionary(GtkWidget *menuitem, GtkSpell *spell) {
+ char *word;
+ GtkTextIter start, end;
+
+ get_word_extents_from_mark(spell->buffer, &start, &end, spell->mark_click);
+ word = gtk_text_buffer_get_text(spell->buffer, &start, &end, FALSE);
+
+ enchant_dict_add_to_pwl( spell->speller, word, strlen(word));
+
+ gtkspell_recheck_all(spell);
+
+ g_free(word);
+}
+
+static void
+ignore_all(GtkWidget *menuitem, GtkSpell *spell) {
+ char *word;
+ GtkTextIter start, end;
+
+ get_word_extents_from_mark(spell->buffer, &start, &end, spell->mark_click);
+ word = gtk_text_buffer_get_text(spell->buffer, &start, &end, FALSE);
+
+ enchant_dict_add_to_session(spell->speller, word, strlen(word));
+
+ gtkspell_recheck_all(spell);
+
+ g_free(word);
+}
+
+static void
+replace_word(GtkWidget *menuitem, GtkSpell *spell) {
+ char *oldword;
+ const char *newword;
+ GtkTextIter start, end;
+
+ if (!spell->speller)
+ return;
+
+ get_word_extents_from_mark(spell->buffer, &start, &end, spell->mark_click);
+ oldword = gtk_text_buffer_get_text(spell->buffer, &start, &end, FALSE);
+ newword = gtk_label_get_text(GTK_LABEL
+ (gtk_bin_get_child(GTK_BIN(menuitem))));
+
+ if (debug) {
+ g_print("old word: '%s'\n", oldword);
+ print_iter("s", &start); print_iter("e", &end);
+ g_print("\nnew word: '%s'\n", newword);
+ }
+
+ gtk_text_buffer_begin_user_action(spell->buffer);
+ gtk_text_buffer_delete(spell->buffer, &start, &end);
+ gtk_text_buffer_insert(spell->buffer, &start, newword, -1);
+ gtk_text_buffer_end_user_action(spell->buffer);
+
+ enchant_dict_store_replacement(spell->speller,
+ oldword, strlen(oldword),
+ newword, strlen(newword));
+
+ g_free(oldword);
+}
+
+/* This function populates suggestions at the top of the passed menu */
+static void
+add_suggestion_menus(GtkSpell *spell, GtkTextBuffer *buffer,
+ const char *word, GtkWidget *topmenu) {
+ GtkWidget *menu;
+ GtkWidget *mi;
+ char **suggestions;
+ size_t n_suggs, i;
+ char *label;
+
+ menu = topmenu;
+
+ if (!spell->speller)
+ return;
+
+ gint menu_position = 0;
+
+ suggestions = enchant_dict_suggest(spell->speller, word, strlen(word), &n_suggs);
+
+ if (suggestions == NULL || !n_suggs) {
+ /* no suggestions. put something in the menu anyway... */
+ GtkWidget *label;
+ label = gtk_label_new("");
+ gtk_label_set_markup(GTK_LABEL(label), _("<i>(no suggestions)</i>"));
+
+ mi = gtk_menu_item_new();
+ gtk_container_add(GTK_CONTAINER(mi), label);
+ gtk_widget_show_all(mi);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(menu), mi, menu_position++);
+ } else {
+ /* build a set of menus with suggestions. */
+ gboolean inside_more_submenu = FALSE;
+ for (i = 0; i < n_suggs; i++ ) {
+ if (i > 0 && i % 10 == 0) {
+ inside_more_submenu = TRUE;
+ mi = gtk_menu_item_new_with_label(_("More..."));
+ gtk_widget_show(mi);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(menu), mi, menu_position++);
+
+ menu = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi), menu);
+ }
+ mi = gtk_menu_item_new_with_label(suggestions[i]);
+ g_signal_connect(G_OBJECT(mi), "activate",
+ G_CALLBACK(replace_word), spell);
+ gtk_widget_show(mi);
+ if (inside_more_submenu) gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
+ else gtk_menu_shell_insert(GTK_MENU_SHELL(menu), mi, menu_position++);
+ }
+ }
+
+ if (suggestions)
+ enchant_dict_free_string_list(spell->speller, suggestions);
+
+ /* + Add to Dictionary */
+ label = g_strdup_printf(_("Add \"%s\" to Dictionary"), word);
+ mi = gtk_image_menu_item_new_with_label(label);
+ g_free(label);
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi),
+ gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
+ g_signal_connect(G_OBJECT(mi), "activate",
+ G_CALLBACK(add_to_dictionary), spell);
+ gtk_widget_show_all(mi);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(topmenu), mi, menu_position++);
+
+ /* - Ignore All */
+ mi = gtk_image_menu_item_new_with_label(_("Ignore All"));
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi),
+ gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
+ g_signal_connect(G_OBJECT(mi), "activate",
+ G_CALLBACK(ignore_all), spell);
+ gtk_widget_show_all(mi);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(topmenu), mi, menu_position++);
+}
+
+static GtkWidget*
+build_suggestion_menu(GtkSpell *spell, GtkTextBuffer *buffer,
+ const char *word) {
+ GtkWidget *topmenu;
+ topmenu = gtk_menu_new();
+ add_suggestion_menus(spell, buffer, word, topmenu);
+
+ return topmenu;
+}
+
+static void
+language_change_callback(GtkCheckMenuItem *mi, GtkSpell* spell) {
+ if (gtk_check_menu_item_get_active(mi)) {
+ GError* error = NULL;
+ gchar *name;
+ g_object_get(G_OBJECT(mi), "name", &name, NULL);
+ gtkspell_set_language(spell, name, &error);
+ g_free(name);
+ }
+}
+
+struct _languages_cb_struct {GList *langs;};
+
+static void
+dict_describe_cb(const char * const lang_tag,
+ const char * const provider_name,
+ const char * const provider_desc,
+ const char * const provider_file,
+ void * user_data) {
+
+ struct _languages_cb_struct *languages_cb_struct = (struct _languages_cb_struct *)user_data;
+
+ languages_cb_struct->langs = g_list_insert_sorted(
+ languages_cb_struct->langs, g_strdup(lang_tag),
+ (GCompareFunc) strcmp);
+}
+
+static GtkWidget*
+build_languages_menu(GtkSpell *spell) {
+ GtkWidget *active_item = NULL, *menu = gtk_menu_new();
+ GList *langs;
+ GSList *menu_group = NULL;
+
+ struct _languages_cb_struct languages_cb_struct;
+ languages_cb_struct.langs = NULL;
+
+ enchant_broker_list_dicts(broker, dict_describe_cb, &languages_cb_struct);
+
+ langs = languages_cb_struct.langs;
+
+ for (; langs; langs = langs->next) {
+ gchar *lang_tag = langs->data;
+ GtkWidget* mi = gtk_radio_menu_item_new_with_label(menu_group, lang_tag);
+ menu_group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mi));
+
+ g_object_set(G_OBJECT(mi), "name", lang_tag, NULL);
+ if (strcmp(spell->lang, lang_tag) == 0)
+ active_item = mi;
+ else
+ g_signal_connect(G_OBJECT(mi), "activate",
+ G_CALLBACK(language_change_callback), spell);
+ gtk_widget_show(mi);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
+
+ g_free(lang_tag);
+ }
+ if (active_item)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(active_item), TRUE);
+
+ g_list_free(languages_cb_struct.langs);
+
+ return menu;
+}
+
+static void
+populate_popup(GtkTextView *textview, GtkMenu *menu, GtkSpell *spell) {
+ GtkWidget *mi;
+ GtkTextIter start, end;
+ char *word;
+
+ /* menu separator comes first. */
+ mi = gtk_separator_menu_item_new();
+ gtk_widget_show(mi);
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+ /* on top: language selection */
+ mi = gtk_menu_item_new_with_label(_("Languages"));
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi), build_languages_menu(spell));
+ gtk_widget_show_all(mi);
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
+
+ /* we need to figure out if they picked a misspelled word. */
+ get_word_extents_from_mark(spell->buffer, &start, &end, spell->mark_click);
+
+ /* if our highlight algorithm ever messes up,
+ * this isn't correct, either. */
+ if (!gtk_text_iter_has_tag(&start, spell->tag_highlight))
+ return; /* word wasn't misspelled. */
+
+ /* then, on top of it, the suggestions */
+ word = gtk_text_buffer_get_text(spell->buffer, &start, &end, FALSE);
+ add_suggestion_menus(spell, spell->buffer, word, GTK_WIDGET (menu) );
+ g_free(word);
+}
+
+/* when the user right-clicks on a word, they want to check that word.
+ * here, we do NOT move the cursor to the location of the clicked-upon word
+ * since that prevents the use of edit functions on the context menu. */
+static gboolean
+button_press_event(GtkTextView *view, GdkEventButton *event, GtkSpell *spell) {
+ if (event->button == 3) {
+ gint x, y;
+ GtkTextIter iter;
+
+ /* handle deferred check if it exists */
+ if (spell->deferred_check)
+ check_deferred_range(spell, spell->buffer, TRUE);
+
+ gtk_text_view_window_to_buffer_coords(view,
+ GTK_TEXT_WINDOW_TEXT,
+ event->x, event->y,
+ &x, &y);
+ gtk_text_view_get_iter_at_location(view, &iter, x, y);
+ gtk_text_buffer_move_mark(spell->buffer, spell->mark_click, &iter);
+ }
+ return FALSE; /* false: let gtk process this event, too.
+ we don't want to eat any events. */
+}
+
+/* This event occurs when the popup menu is requested through a key-binding
+ * (Menu Key or <shift>+F10 by default). In this case we want to set
+ * spell->mark_click to the cursor position. */
+static gboolean
+popup_menu_event(GtkTextView *view, GtkSpell *spell) {
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_mark(spell->buffer, &iter,
+ gtk_text_buffer_get_insert(spell->buffer));
+ gtk_text_buffer_move_mark(spell->buffer, spell->mark_click, &iter);
+ return FALSE; /* false: let gtk process this event, too. */
+}
+
+static void
+_set_lang_from_dict(const char * const lang_tag,
+ const char * const provider_name,
+ const char * const provider_desc,
+ const char * const provider_dll_file,
+ void * user_data)
+{
+ GtkSpell *spell = user_data;
+
+ g_free(spell->lang);
+ spell->lang = g_strdup(lang_tag);
+}
+
+static gboolean
+gtkspell_set_language_internal(GtkSpell *spell, const gchar *lang, GError **error) {
+ EnchantDict *dict;
+
+ if (lang == NULL) {
+ lang = g_getenv("LANG");
+ if (lang) {
+ if ((strcmp(lang, "C") == 0) || (strcmp(lang, "c") == 0))
+ lang = NULL;
+ else if (lang[0] == 0)
+ lang = NULL;
+ }
+ }
+
+ if (!lang)
+ lang = "en";
+
+ dict = enchant_broker_request_dict(broker, lang);
+
+ if (!dict) {
+ g_set_error(error, GTKSPELL_ERROR, GTKSPELL_ERROR_BACKEND,
+ _("enchant error for language: %s"), lang);
+ return FALSE;
+ }
+
+ if (spell->speller)
+ enchant_broker_free_dict(broker, spell->speller);
+ spell->speller = dict;
+
+ enchant_dict_describe(dict, _set_lang_from_dict, spell);
+
+ return TRUE;
+}
+
+/**
+ * gtkspell_set_language:
+ * @spell: The #GtkSpell object.
+ * @lang: The language to use, in a form enchant understands (it appears to
+ * be a locale specifier?).
+ * @error: Return location for error.
+ *
+ * Set the language on @spell to @lang, possibily returning an error in
+ * @error.
+ *
+ * Returns: FALSE if there was an error.
+ */
+gboolean
+gtkspell_set_language(GtkSpell *spell, const gchar *lang, GError **error) {
+ gboolean ret;
+
+ if (error)
+ g_return_val_if_fail(*error == NULL, FALSE);
+
+ ret = gtkspell_set_language_internal(spell, lang, error);
+ if (ret)
+ gtkspell_recheck_all(spell);
+
+ return ret;
+}
+
+/**
+ * gtkspell_recheck_all:
+ * @spell: The #GtkSpell object.
+ *
+ * Recheck the spelling in the entire buffer.
+ */
+void
+gtkspell_recheck_all(GtkSpell *spell) {
+ GtkTextIter start, end;
+
+ gtk_text_buffer_get_bounds(spell->buffer, &start, &end);
+
+ check_range(spell, spell->buffer, start, end, TRUE);
+}
+
+/* changes the buffer
+ * a NULL buffer is acceptable and will only release the current one */
+static void
+gtkspell_set_buffer(GtkSpell *spell, GtkTextBuffer *buffer)
+{
+ GtkTextTagTable *tagtable;
+ GtkTextIter start, end;
+
+ if (spell->buffer) {
+ g_signal_handlers_disconnect_matched(spell->buffer,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL,
+ spell);
+
+ tagtable = gtk_text_buffer_get_tag_table(spell->buffer);
+
+ gtk_text_buffer_get_bounds(spell->buffer, &start, &end);
+ gtk_text_buffer_remove_tag(spell->buffer, spell->tag_highlight, &start, &end);
+ spell->tag_highlight = NULL;
+
+ gtk_text_buffer_delete_mark(spell->buffer, spell->mark_insert_start);
+ spell->mark_insert_start = NULL;
+ gtk_text_buffer_delete_mark(spell->buffer, spell->mark_insert_end);
+ spell->mark_insert_end = NULL;
+ gtk_text_buffer_delete_mark(spell->buffer, spell->mark_click);
+ spell->mark_click = NULL;
+
+ g_object_unref (spell->buffer);
+ }
+
+ spell->buffer = buffer;
+
+ if (spell->buffer) {
+ g_object_ref (spell->buffer);
+
+ g_signal_connect(G_OBJECT(spell->buffer),
+ "insert-text",
+ G_CALLBACK(insert_text_before), spell);
+ g_signal_connect_after(G_OBJECT(spell->buffer),
+ "insert-text",
+ G_CALLBACK(insert_text_after), spell);
+ g_signal_connect_after(G_OBJECT(spell->buffer),
+ "delete-range",
+ G_CALLBACK(delete_range_after), spell);
+ g_signal_connect(G_OBJECT(spell->buffer),
+ "mark-set",
+ G_CALLBACK(mark_set), spell);
+
+ tagtable = gtk_text_buffer_get_tag_table(spell->buffer);
+ spell->tag_highlight = gtk_text_tag_table_lookup(tagtable, GTKSPELL_MISSPELLED_TAG);
+
+ if (spell->tag_highlight == NULL) {
+ spell->tag_highlight = gtk_text_buffer_create_tag(spell->buffer,
+ GTKSPELL_MISSPELLED_TAG,
+#ifdef HAVE_PANGO_UNDERLINE_ERROR
+ "underline", PANGO_UNDERLINE_ERROR,
+#else
+ "foreground", "red",
+ "underline", PANGO_UNDERLINE_SINGLE,
+#endif
+ NULL);
+ }
+
+ /* we create the mark here, but we don't use it until text is
+ * inserted, so we don't really care where iter points. */
+ gtk_text_buffer_get_bounds(spell->buffer, &start, &end);
+ spell->mark_insert_start = gtk_text_buffer_create_mark(spell->buffer,
+ "gtkspell-insert-start",
+ &start, TRUE);
+ spell->mark_insert_end = gtk_text_buffer_create_mark(spell->buffer,
+ "gtkspell-insert-end",
+ &start, TRUE);
+ spell->mark_click = gtk_text_buffer_create_mark(spell->buffer,
+ "gtkspell-click",
+ &start, TRUE);
+
+ spell->deferred_check = FALSE;
+
+ /* now check the entire text buffer. */
+ gtkspell_recheck_all(spell);
+ }
+}
+
+static void
+buffer_changed (GtkTextView *view, GParamSpec *pspec, GtkSpell *spell)
+{
+ gtkspell_set_buffer(spell, gtk_text_view_get_buffer(view));
+}
+
+/**
+ * gtkspell_new_attach:
+ * @view: The #GtkTextView to attach to.
+ * @lang: The language to use, in a form pspell understands (it appears to
+ * be a locale specifier?).
+ * @error: Return location for error.
+ *
+ * Create a new #GtkSpell object attached to @view with language @lang.
+ *
+ * Returns: a new #GtkSpell object, or %NULL on error.
+ */
+GtkSpell*
+gtkspell_new_attach(GtkTextView *view, const gchar *lang, GError **error) {
+ GtkSpell *spell;
+
+#ifdef ENABLE_NLS
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset(PACKAGE, "UTF-8");
+#endif
+
+ if (error)
+ g_return_val_if_fail(*error == NULL, NULL);
+
+ spell = g_object_get_data(G_OBJECT(view), GTKSPELL_OBJECT_KEY);
+ g_assert(spell == NULL);
+
+ /* We don't need to worry about thread safety.
+ * Stuff shouldn't be attaching to a GtkTextView from anything other
+ * than the mainloop thread */
+ if (!broker) {
+ broker = enchant_broker_init();
+ broker_ref_cnt = 0;
+ }
+ broker_ref_cnt++;
+
+
+ /* attach to the widget */
+ spell = g_new0(GtkSpell, 1);
+ spell->view = view;
+ if (!gtkspell_set_language_internal(spell, lang, error)) {
+ broker_ref_cnt--;
+ if (broker_ref_cnt == 0) {
+ enchant_broker_free(broker);
+ broker = NULL;
+ }
+ g_free(spell);
+ return NULL;
+ }
+ g_object_set_data(G_OBJECT(view), GTKSPELL_OBJECT_KEY, spell);
+
+ g_signal_connect_swapped(G_OBJECT(view), "destroy",
+ G_CALLBACK(gtkspell_free), spell);
+ g_signal_connect(G_OBJECT(view), "button-press-event",
+ G_CALLBACK(button_press_event), spell);
+ g_signal_connect(G_OBJECT(view), "populate-popup",
+ G_CALLBACK(populate_popup), spell);
+ g_signal_connect(G_OBJECT(view), "popup-menu",
+ G_CALLBACK(popup_menu_event), spell);
+ g_signal_connect(G_OBJECT(view), "notify::buffer",
+ G_CALLBACK(buffer_changed), spell);
+
+ spell->buffer = NULL;
+ gtkspell_set_buffer(spell, gtk_text_view_get_buffer(view));
+
+ return spell;
+}
+
+static void
+gtkspell_free(GtkSpell *spell) {
+
+ gtkspell_set_buffer(spell, NULL);
+
+ if (broker) {
+ if (spell->speller) {
+ enchant_broker_free_dict(broker, spell->speller);
+ }
+ broker_ref_cnt--;
+ if (broker_ref_cnt == 0) {
+ enchant_broker_free(broker);
+ broker = NULL;
+ }
+ }
+ g_signal_handlers_disconnect_matched(spell->view,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL,
+ spell);
+ g_free(spell->lang);
+ g_free(spell);
+}
+
+/**
+ * gtkspell_get_from_text_view:
+ * @view: A #GtkTextView.
+ *
+ * Retrieves the #GtkSpell object attached to a text view.
+ *
+ * Returns: the #GtkSpell object, or %NULL if there is no #GtkSpell
+ * attached to @view.
+ */
+GtkSpell*
+gtkspell_get_from_text_view(GtkTextView *view) {
+ return g_object_get_data(G_OBJECT(view), GTKSPELL_OBJECT_KEY);
+}
+
+/**
+ * gtkspell_detach:
+ * @spell: A #GtkSpell.
+ *
+ * Detaches this #GtkSpell from its text view. Use
+ * gtkspell_get_from_text_view() to retrieve a GtkSpell from a
+ * #GtkTextView.
+ */
+void
+gtkspell_detach(GtkSpell *spell) {
+ g_return_if_fail(spell != NULL);
+
+ g_object_set_data(G_OBJECT(spell->view), GTKSPELL_OBJECT_KEY, NULL);
+ gtkspell_free(spell);
+}
+
+/**
+ * gtkspell_get_suggestions_menu:
+ * @iter: Textiter of position in buffer to be corrected if necessary.
+ *
+ * Retrieves a submenu of replacement spellings, or NULL if the word at @iter is
+ * not misspelt.
+ *
+ * Returns: the #GtkMenu widget, or %NULL if there is no need for a menu
+ */
+GtkWidget*
+gtkspell_get_suggestions_menu(GtkSpell *spell, GtkTextIter *iter) {
+ GtkWidget *submenu = NULL;
+ GtkTextIter start, end;
+
+ g_return_val_if_fail(spell != NULL, NULL);
+
+ /* avoid an empty submenu when enchant is not working properly */
+ if (!spell->speller)
+ return NULL;
+
+ start = *iter;
+ /* use the same lazy test, with same risk, as does the default menu arrangement */
+ if (gtk_text_iter_has_tag(&start, spell->tag_highlight)) {
+ /* word was mis-spelt */
+ gchar *badword;
+ /* in case a fix is requested, move the attention-point */
+ gtk_text_buffer_move_mark(spell->buffer, spell->mark_click, iter);
+ if (!gtk_text_iter_starts_word(&start))
+ gtk_text_iter_backward_word_start(&start);
+ end = start;
+ if (gtk_text_iter_inside_word(&end))
+ gtk_text_iter_forward_word_end(&end);
+ badword = gtk_text_buffer_get_text (spell->buffer, &start, &end, FALSE);
+
+ submenu = build_suggestion_menu (spell, spell->buffer, badword);
+ gtk_widget_show (submenu);
+
+ g_free (badword);
+ }
+ return submenu;
+}
diff --git a/pan/data-impl/Makefile.am b/pan/data-impl/Makefile.am
index 7955688..e080653 100644
--- a/pan/data-impl/Makefile.am
+++ b/pan/data-impl/Makefile.am
@@ -1,4 +1,6 @@
-AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @OPENSSL_CFLAGS@
+AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @OPENSSL_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@
+
+AM_LDFLAGS = @LIBGNOME_KEYRING_1_LIBS@
noinst_LIBRARIES = libpandata.a
@@ -13,7 +15,7 @@ libpandata_a_SOURCES = \
server.cc \
my-tree.cc \
task-archive.cc \
- xover.cc
+ xover.cc
noinst_HEADERS = \
article-filter.h \
@@ -22,7 +24,7 @@ noinst_HEADERS = \
data-io.h \
defgroup.h \
profiles.h \
- memchunk.h
+ memchunk.h
#noinst_PROGRAMS = \
# add-server \
diff --git a/pan/data-impl/data-impl.cc b/pan/data-impl/data-impl.cc
index d285e9e..65e7e73 100644
--- a/pan/data-impl/data-impl.cc
+++ b/pan/data-impl/data-impl.cc
@@ -33,6 +33,9 @@ extern "C" {
#include <pan/general/time-elapsed.h>
#include "data-impl.h"
+#include <gnome-keyring-1/gnome-keyring.h>
+#include <gnome-keyring-1/gnome-keyring-memory.h>
+
using namespace pan;
/**
@@ -71,6 +74,8 @@ DataImpl :: DataImpl (bool unit_test, int cache_megs, DataIO * io):
_descriptions_loaded (false),
newsrc_autosave_id (0),
newsrc_autosave_timeout (0)
+// ,
+// _blowfish_inited(false)
{
rebuild_backend ();
}
@@ -120,3 +125,113 @@ DataImpl :: save_state ()
}
}
+
+namespace
+{
+
+ static void
+ stored_password (GnomeKeyringResult res, gpointer user_data)
+ {
+ if (res == GNOME_KEYRING_RESULT_OK)
+ g_print ("password saved successfully!\n");
+ else
+ g_print ("couldn't save password: %s", gnome_keyring_result_to_message (res));
+ }
+
+ static void
+ found_password (GnomeKeyringResult res, const gchar* password, gpointer user_data)
+ {
+ if (res == GNOME_KEYRING_RESULT_OK)
+ g_print ("password found was: %s\n", password);
+ else
+ g_print ("couldn't find password: %s", gnome_keyring_result_to_message (res));
+
+ /* Once this function returns |password| will be freed */
+ }
+
+}
+
+#ifdef HAVE_GKR
+GnomeKeyringResult
+DataImpl :: password_encrypt (const PasswordData& pw)
+{
+ g_return_val_if_fail (gnome_keyring_is_available(), GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON);
+
+ return (
+ gnome_keyring_store_password_sync (
+ GNOME_KEYRING_NETWORK_PASSWORD,
+ GNOME_KEYRING_DEFAULT,
+ _("Pan server password"),
+ pw.pw.str,
+ "user", pw.user.str,
+ "server", pw.server.c_str(),
+ NULL)
+ );
+
+}
+
+GnomeKeyringResult
+DataImpl :: password_decrypt (PasswordData& pw) const
+{
+
+ gchar* pwd(0);
+ g_return_val_if_fail (gnome_keyring_is_available(), GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON);
+
+ GnomeKeyringResult ret =
+ gnome_keyring_find_password_sync (
+ GNOME_KEYRING_NETWORK_PASSWORD,
+ &pwd,
+ "user", pw.user.str,
+ "server", pw.server.c_str(),
+ NULL);
+
+ std::string tmp(pwd);
+ gnome_keyring_free_password(pwd);
+ pw.pw = tmp;
+
+ return ret;
+}
+#endif
+
+//void
+//DataImpl :: blowfish_init ()
+//{
+//
+// /TODO : Custom key with gtkwidget*
+// if (!_blowfish_inited)
+// {
+// _blowfish_inited = true;
+// char* key = (char*)"fjghdfjghdfkjg";
+// _blowfish.Initialize(key, 14);
+// }
+//}
+
+//void
+//DataImpl :: blowfish_encrypt (char* t, const StringView& s)
+//{
+//
+// std::cerr<<"bf encrypt "<<s<<"\n";
+//
+// size_t len (s.len);
+// std::string str(s);
+// int i(0);
+// for (;i<len%8;++i) str += " ";
+// _blowfish.Encode ((char*)str.c_str(),t,len+i);
+//
+//}
+
+//void
+//DataImpl :: blowfish_decrypt (char* t, size_t len)
+//{
+//
+// std::cerr<<"bf decrypt "<<t<<" "<<len<<"\n";
+//
+// std::string str((char*)t);
+// int i(0);
+// for (;i<len%8;++i) str += " ";
+// char* buf = (char*)str.c_str();
+// _blowfish.Decode (buf,buf,len+i);
+// t = buf;
+//
+//}
+
diff --git a/pan/data-impl/data-impl.h b/pan/data-impl/data-impl.h
index 1cd97b1..8590fd9 100644
--- a/pan/data-impl/data-impl.h
+++ b/pan/data-impl/data-impl.h
@@ -33,6 +33,7 @@
#include <pan/general/sorted-vector.h>
#include <pan/usenet-utils/numbers.h>
#include <pan/usenet-utils/scorefile.h>
+#include <pan/usenet-utils/blowfish.h>
#include <pan/data/article.h>
#include <pan/data/article-cache.h>
#include <pan/data/encode-cache.h>
@@ -72,6 +73,8 @@ namespace pan
public ProfilesImpl
{
+ typedef Data::PasswordData PasswordData;
+
/**
*** SERVERS
**/
@@ -97,6 +100,21 @@ namespace pan
CertStore _certstore;
private:
+// CBlowFish _blowfish;
+// bool _blowfish_inited;
+
+ public:
+// void blowfish_init ();
+// void blowfish_encrypt (char*, const StringView&);
+// void blowfish_decrypt (char* t, size_t len);
+
+
+ public:
+#ifdef HAVE_GKR
+ GnomeKeyringResult password_encrypt (const PasswordData&);
+ GnomeKeyringResult password_decrypt (PasswordData&) const;
+#endif
+ private:
void rebuild_backend ();
const bool _unit_test;
@@ -670,6 +688,7 @@ namespace pan
save_newsrc_files(*_data_io);
newsrc_autosave_id = 0;
}
+
};
}
diff --git a/pan/data-impl/server.cc b/pan/data-impl/server.cc
index 729c1fa..ff6cb3f 100644
--- a/pan/data-impl/server.cc
+++ b/pan/data-impl/server.cc
@@ -127,7 +127,14 @@ DataImpl :: set_server_auth (const Quark & server,
assert (s);
s->username = username;
+#ifndef HAVE_GKR
s->password = password;
+#else
+ PasswordData pw ;
+ pw.server = s->host;
+ pw.user = username;
+ pw.pw = password;
+#endif
}
@@ -194,13 +201,14 @@ DataImpl :: save_server_info (const Quark& server)
}
+
bool
DataImpl :: get_server_auth (const Quark & server,
std::string & setme_username,
std::string & setme_password) const
{
const Server * s (find_server (server));
- const bool found (s);
+ bool found (s);
if (found) {
setme_username = s->username;
setme_password = s->password;
@@ -383,7 +391,32 @@ DataImpl :: load_server_properties (const DataIO& source)
keyvals_t kv (it->second);
s.host = kv["host"];
s.username = kv["username"];
+#ifndef HAVE_GKR
s.password = kv["password"];
+#else
+ PasswordData pw ;
+ pw.server = s.host;
+ pw.user = s.username;
+ GnomeKeyringResult res (password_decrypt(pw));
+ switch (res)
+ {
+ case GNOME_KEYRING_RESULT_NO_MATCH:
+ Log::add_info_va(_("There seems to be no password set for server %s."), s.host.c_str());
+ break;
+
+ case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON:
+ Log::add_urgent_va (_("The gnome keyring denied access to the passwords."), s.host.c_str());
+ break;
+
+ case GNOME_KEYRING_RESULT_OK:
+ s.password.assign(pw.pw.str, pw.pw.len);
+ break;
+
+ default:
+ Log::add_info_va ("%s %s",gnome_keyring_result_to_message (res),res);
+ break;
+ }
+#endif
s.port = to_int (kv["port"], STD_NNTP_PORT);
s.max_connections = to_int (kv["connection-limit"], 2);
s.article_expiration_age = to_int(kv["expire-articles-n-days-old"], 31);
diff --git a/pan/data/data.h b/pan/data/data.h
index 89bf317..79dd046 100644
--- a/pan/data/data.h
+++ b/pan/data/data.h
@@ -35,6 +35,9 @@
#include <pan/data/cert-store.h>
#include <pan/data/server-info.h>
+#include <gnome-keyring-1/gnome-keyring.h>
+#include <gnome-keyring-1/gnome-keyring-memory.h>
+
namespace pan
{
class FilterInfo;
@@ -165,6 +168,14 @@ namespace pan
{
public:
+ struct PasswordData
+ {
+ Quark server;
+ StringView user;
+ StringView pw;
+ };
+
+ public:
struct Server
{
std::string username;
@@ -204,7 +215,10 @@ namespace pan
virtual const CertStore& get_certstore () const = 0;
public:
-
+#ifdef HAVE_GKR
+ virtual GnomeKeyringResult password_encrypt (const PasswordData&) = 0;
+ virtual GnomeKeyringResult password_decrypt (PasswordData&) const = 0;
+#endif
/** Gets a quark to the provided hostname */
virtual bool find_server_by_hn (const Quark& server, Quark& setme) const = 0;
diff --git a/pan/gui/Makefile.am b/pan/gui/Makefile.am
index 3db1bed..c5517f8 100644
--- a/pan/gui/Makefile.am
+++ b/pan/gui/Makefile.am
@@ -1,4 +1,5 @@
-AM_CPPFLAGS = -I top_srcdir@ @GTKSPELL_CFLAGS@ @GTK_CFLAGS@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @OPENSSL_CFLAGS@ @LIBNOTIFY_CFLAGS@ -DPANLOCALEDIR=\""$(panlocaledir)"\"
+AM_CPPFLAGS = -I top_srcdir@ @GTKSPELL_CFLAGS@ @GTK_CFLAGS@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ \
+ @OPENSSL_CFLAGS@ @LIBNOTIFY_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@ -DPANLOCALEDIR=\""$(panlocaledir)"\"
noinst_LIBRARIES = libpangui.a
@@ -94,7 +95,7 @@ endif
pan_SOURCES = gui.cc pan.cc $(WINRC)
pan_LDADD = ./libpangui.a $(WINRCOBJ) ../data-impl/libpandata.a ../tasks/libtasks.a ../data/libdata.a ../usenet-utils/libusenetutils.a ../general/libgeneralutils.a \
- ../../uulib/libuu.a @GTKSPELL_LIBS@ @GTK_LIBS@ @GMIME_LIBS@ @GLIB_LIBS@ @OPENSSL_LIBS@ @LIBNOTIFY_LIBS@
+ ../../uulib/libuu.a @GTKSPELL_LIBS@ @GTK_LIBS@ @GMIME_LIBS@ @GLIB_LIBS@ @OPENSSL_LIBS@ @LIBNOTIFY_LIBS@ @LIBGNOME_KEYRING_1_LIBS@
if HAVE_WIN32
pan_LDFLAGS = -mwindows
diff --git a/pan/gui/actions.cc b/pan/gui/actions.cc
index cf886c9..e553163 100644
--- a/pan/gui/actions.cc
+++ b/pan/gui/actions.cc
@@ -64,7 +64,8 @@ namespace
{ icon_read_unread_thread, "ICON_READ_UNREAD_THREAD" },
{ icon_score, "ICON_SCORE" },
{ icon_search_pulldown, "ICON_SEARCH_PULLDOWN" },
- { icon_red_flag, "ICON_FLAGGED"}
+ { icon_red_flag, "ICON_FLAGGED"},
+ { icon_get_flagged, "ICON_GET_FLAGGED" }
};
void
@@ -149,6 +150,8 @@ namespace
void do_flag_off (GtkAction*) { pan_ui->do_flag_off(); }
void do_next_flag (GtkAction*) { pan_ui->do_next_flag(); }
void do_last_flag (GtkAction*) { pan_ui->do_last_flag(); }
+ void do_download_flagged (GtkAction*) { pan_ui->do_download_flagged(); }
+ void do_invert_selection (GtkAction*) { pan_ui->do_invert_selection(); }
void do_mark_all_flagged (GtkAction*) { pan_ui->do_mark_all_flagged(); }
void do_show_score_dialog (GtkAction*) { pan_ui->do_show_score_dialog(); }
void do_show_new_score_dialog (GtkAction*) { pan_ui->do_show_new_score_dialog(); }
@@ -306,6 +309,11 @@ namespace
N_("Get New Headers in Subscribed Groups"),
G_CALLBACK(do_xover_subscribed_groups) },
+ { "update-stats-in-selected-groups", "ICON_GET_SUBSCRIBED",
+ N_("Get New _Headers in Subscribed Groups"), "<shift>A",
+ N_("Get New Headers in Subscribed Groups"),
+ G_CALLBACK(do_xover_subscribed_groups) },
+
{ "download-headers", "ICON_GET_DIALOG",
N_("Get _Headers..."), "",
N_("Get Headers..."),
@@ -569,6 +577,16 @@ namespace
N_("_Goto last flagged Thread"),
G_CALLBACK(do_last_flag) },
+ { "get-all-flagged", NULL,
+ N_("_Get all flagged Thread"), NULL, ///TODO invent shortcut
+ N_("_Get all flagged Thread"),
+ G_CALLBACK(do_download_flagged) },
+
+ { "invert-selection", NULL,
+ N_("_Invert Selection"), "<control>I",
+ N_("_Invert Selection"),
+ G_CALLBACK(do_invert_selection) },
+
{ "view-article-score", "ICON_SCORE",
N_("Edit Article's Watch/Ignore/Score..."), "<control><shift>C",
NULL,
diff --git a/pan/gui/dl-headers-ui.cc b/pan/gui/dl-headers-ui.cc
index 2eaaa3f..1c585a2 100644
--- a/pan/gui/dl-headers-ui.cc
+++ b/pan/gui/dl-headers-ui.cc
@@ -132,7 +132,7 @@ pan :: headers_dialog (Data& data, Prefs& prefs, Queue& queue,
GtkWidget *w, *x;
GtkAdjustment * adj;
int row = 0;
- state->n_days_rb = w = gtk_radio_button_new_with_mnemonic (NULL, _("Get the last N _days' headers: "));
+ state->n_days_rb = w = gtk_radio_button_new_with_mnemonic (NULL, _("Get the last N _days' headers: "));
gtk_button_set_alignment (GTK_BUTTON(w), 0.5, 0.0);
gtk_table_attach_defaults (GTK_TABLE(t), w, 0, 1, row, row+1);
adj = GTK_ADJUSTMENT(gtk_adjustment_new (n_days, 1, INT_MAX, 1, 1, 0));
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index feb329f..bb1d060 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -1190,6 +1190,21 @@ GUI :: do_last_flag ()
step_bookmarks(-1);
}
+void
+GUI :: do_download_flagged ()
+{
+ do_mark_all_flagged();
+ do_download_selected_article();
+ do_unselect_all_articles();
+}
+
+void
+GUI :: do_invert_selection ()
+{
+// std::cerr<<__LINE__<< " "<<__FILE__<<" : implement me.\n";
+ _header_pane->invert_selection();
+}
+
void GUI :: do_plonk ()
{
score_add (ScoreAddDialog::PLONK);
diff --git a/pan/gui/gui.h b/pan/gui/gui.h
index b38a447..1f38559 100644
--- a/pan/gui/gui.h
+++ b/pan/gui/gui.h
@@ -140,6 +140,8 @@ namespace pan
virtual void do_next_flag ();
virtual void do_last_flag ();
virtual void do_mark_all_flagged ();
+ virtual void do_download_flagged ();
+ virtual void do_invert_selection ();
virtual void do_show_score_dialog ();
virtual void do_show_new_score_dialog ();
virtual void do_cancel_article ();
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index db5e472..4ce33a9 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -90,6 +90,7 @@ namespace
ICON_ERROR,
ICON_EMPTY,
ICON_FLAGGED,
+ ICON_GET_FLAGGED,
ICON_QTY
};
@@ -110,7 +111,8 @@ namespace
{ icon_bluecheck, 0 },
{ icon_x, 0 },
{ icon_empty, 0 },
- { icon_red_flag, 0 }
+ { icon_red_flag, 0 },
+ { icon_get_flagged, 0 }
};
int
@@ -843,6 +845,39 @@ HeaderPane :: mark_all_flagged ()
}
void
+HeaderPane :: invert_selection ()
+{
+
+ GtkTreeIter iter;
+ GtkTreeModel * model(gtk_tree_view_get_model(GTK_TREE_VIEW(_tree_view)));
+ GtkTreeSelection * sel (gtk_tree_view_get_selection (GTK_TREE_VIEW(_tree_view)));
+ gtk_tree_model_get_iter_first (model, &iter);
+ walk_and_invert_selection (model, &iter, sel);
+
+}
+
+
+void
+HeaderPane :: walk_and_invert_selection (GtkTreeModel * model,
+ GtkTreeIter * cur,
+ GtkTreeSelection * ref) const
+{
+ for (;;) {
+ const bool selected(gtk_tree_selection_iter_is_selected (ref, cur));
+ if (selected)
+ gtk_tree_selection_unselect_iter(ref,cur);
+ else
+ gtk_tree_selection_select_iter(ref,cur);
+ GtkTreeIter child;
+ if (gtk_tree_model_iter_children (model, &child, cur))
+ walk_and_invert_selection (model, &child, ref);
+ if (!gtk_tree_model_iter_next (model, cur))
+ break;
+ }
+
+}
+
+void
HeaderPane :: walk_and_collect_flagged (GtkTreeModel * model,
GtkTreeIter * cur,
GtkTreeSelection * setme) const
diff --git a/pan/gui/header-pane.h b/pan/gui/header-pane.h
index 8552c53..a29e021 100644
--- a/pan/gui/header-pane.h
+++ b/pan/gui/header-pane.h
@@ -123,6 +123,7 @@ namespace pan
std::set<const Article*> get_full_selection () const;
std::vector<const Article*> get_full_selection_v () const;
void mark_all_flagged ();
+ void invert_selection ();
const guint get_full_selection_rows_num () const;
std::set<const Article*> get_nested_selection (bool do_mark_all) const;
bool set_group (const Quark& group);
@@ -347,7 +348,8 @@ namespace pan
class RowInserter;
class SimilarWalk;
void walk_and_collect (GtkTreeModel*, GtkTreeIter*, articles_set&) const;
- void walk_and_collect_flagged (GtkTreeModel*, GtkTreeIter*, GtkTreeSelection*) const;
+ void walk_and_collect_flagged (GtkTreeModel*, GtkTreeIter*, GtkTreeSelection*) const;
+ void walk_and_invert_selection (GtkTreeModel*, GtkTreeIter*, GtkTreeSelection*) const;
private:
typedef void RenderFunc (GtkTreeViewColumn*, GtkCellRenderer*, GtkTreeModel*, GtkTreeIter*, gpointer);
diff --git a/pan/gui/pan-ui.h b/pan/gui/pan-ui.h
index 96932f7..a32be83 100644
--- a/pan/gui/pan-ui.h
+++ b/pan/gui/pan-ui.h
@@ -71,6 +71,8 @@ namespace pan
virtual void do_next_flag () = 0;
virtual void do_last_flag () = 0;
virtual void do_mark_all_flagged () = 0;
+ virtual void do_download_flagged () = 0;
+ virtual void do_invert_selection () = 0;
virtual void do_cancel_article () = 0;
virtual void do_supersede_article () = 0;
virtual void do_delete_article () = 0;
diff --git a/pan/gui/pan.cc b/pan/gui/pan.cc
index f14e488..53a64ee 100644
--- a/pan/gui/pan.cc
+++ b/pan/gui/pan.cc
@@ -67,6 +67,10 @@ extern "C" {
#include "server-ui.h"
#include "pad.h"
+#include <gnome-keyring-1/gnome-keyring.h>
+#include <gnome-keyring-1/gnome-keyring-memory.h>
+
+
//#define DEBUG_LOCALE 1
using namespace pan;
@@ -78,6 +82,8 @@ namespace
namespace
{
+// bool keyring_active(gnome_keyring_is_available());
+
GMainLoop * nongui_gmainloop (0);
void mainloop ()
diff --git a/pan/gui/pan.ui.h b/pan/gui/pan.ui.h
index bbfa8f9..3be86ae 100644
--- a/pan/gui/pan.ui.h
+++ b/pan/gui/pan.ui.h
@@ -120,6 +120,8 @@ const char * fallback_ui_file =
" <menuitem action='download-selected-article' />\n"
" <menuitem action='show-selected-article-info' />\n"
" <separator />\n"
+" <menuitem action='invert-selection' />\n"
+" <separator />\n"
" <menuitem action='mark-article-read' />\n"
" <menuitem action='mark-article-unread' />\n"
" <separator />\n"
@@ -136,6 +138,8 @@ const char * fallback_ui_file =
" <menuitem action='last-flagged' />\n"
" <menuitem action='mark-all-flagged' />\n"
" <separator />\n"
+" <menuitem action='get-all-flagged' />\n"
+" <separator />\n"
" <menuitem action='plonk' />\n"
" <menuitem action='view-article-score' />\n"
" <separator />\n"
@@ -194,6 +198,8 @@ const char * fallback_ui_file =
" <menuitem action='download-selected-article' />\n"
" <menuitem action='show-selected-article-info' />\n"
" <separator />\n"
+" <menuitem action='invert-selection' />\n"
+" <separator />\n"
" <menuitem action='mark-article-read' />\n"
" <menuitem action='mark-article-unread' />\n"
" <separator />\n"
@@ -210,6 +216,8 @@ const char * fallback_ui_file =
" <menuitem action='last-flagged' />\n"
" <menuitem action='mark-all-flagged' />\n"
" <separator />\n"
+" <menuitem action='get-all-flagged' />\n"
+" <separator />\n"
" <menuitem action='plonk' />\n"
" <menuitem action='view-article-score' />\n"
" <separator />\n"
diff --git a/pan/gui/server-ui.cc b/pan/gui/server-ui.cc
index 6b06112..35ea2c8 100644
--- a/pan/gui/server-ui.cc
+++ b/pan/gui/server-ui.cc
@@ -183,6 +183,7 @@ namespace
server_edit_response_cb (GtkDialog * w, int response, gpointer user_data)
{
bool destroy (true);
+ bool bf_set (false);
ServerEditDialog * d (static_cast<ServerEditDialog*>(user_data));
g_assert (d!=NULL);
@@ -195,7 +196,8 @@ namespace
const int port (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->port_spin)));
const int max_conn (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->connection_limit_spin)));
StringView user (pan_entry_get_text (d->auth_username_entry));
- StringView pass (pan_entry_get_text (d->auth_password_entry));
+ StringView pass = pan_entry_get_text (d->auth_password_entry);
+
int age (31);
GtkTreeIter iter;
GtkComboBox * combo (GTK_COMBO_BOX (d->expiration_age_combo));
@@ -415,8 +417,10 @@ pan :: server_edit_dialog_new (Data& data, Queue& queue, GtkWindow * window, con
e = gtk_event_box_new ();
gtk_container_add (GTK_CONTAINER(e), l);
gtk_misc_set_alignment (GTK_MISC(l), 0.0f, 0.5f);
- gtk_widget_set_tooltip_text( e, _("You can set the option for using/disabling secure SSL/TLS connections here. If you enable SSL/TLS, your data is encrypted and secure. "
- "It is encouraged to use this option for privacy reasons."));
+ gtk_widget_set_tooltip_text( e,
+ _("You can set the option for using/disabling secure SSL/TLS connections here. "
+ "If you enable SSL/TLS, your data is encrypted and secure. "
+ "It is encouraged to use this option for privacy reasons."));
HIG::workarea_add_row (t, &row, e, w);
#endif
diff --git a/pan/icons/icon_get_flagged.png b/pan/icons/icon_get_flagged.png
index d215856..1eb3e77 100644
Binary files a/pan/icons/icon_get_flagged.png and b/pan/icons/icon_get_flagged.png differ
diff --git a/pan/tasks/Makefile.am b/pan/tasks/Makefile.am
index 968692d..54e5145 100644
--- a/pan/tasks/Makefile.am
+++ b/pan/tasks/Makefile.am
@@ -12,6 +12,7 @@ libtasks_a_SOURCES = \
task-groups.cc \
task-post.cc \
task-xover.cc \
+ task-xoverinfo.cc \
task-upload.cc \
nntp.cc \
nzb.cc \
@@ -38,6 +39,7 @@ noinst_HEADERS = \
task-upload.h \
task-weak-ordering.h \
task-xover.h \
+ task-xoverinfo.h \
nntp.h \
nzb.h \
queue.h \
diff --git a/pan/tasks/nntp-pool.cc b/pan/tasks/nntp-pool.cc
index bf7ece7..a82b694 100644
--- a/pan/tasks/nntp-pool.cc
+++ b/pan/tasks/nntp-pool.cc
@@ -170,8 +170,9 @@ NNTP_Pool :: on_socket_created (const StringView & host,
bool ok,
Socket * socket)
{
-
- debug("on socket created "<<host<<" "<<ok<<" "<<socket);
+ std::string user, pass;
+ _server_info.get_server_auth (_server, user, pass);
+ debug("on socket created "<<host<<" "<<ok<<" "<<socket<<" "<<pass);
if (!ok)
{
delete socket;
diff --git a/pan/tasks/nntp.cc b/pan/tasks/nntp.cc
index b284996..15030c9 100644
--- a/pan/tasks/nntp.cc
+++ b/pan/tasks/nntp.cc
@@ -302,6 +302,15 @@ NNTP :: help (Listener * l)
}
void
+NNTP :: get_group (Listener * l)
+{
+ _listener = l;
+ _commands.push_back ("GROUP \r\n");
+ write_next_command();
+}
+
+
+void
NNTP :: xover (const Quark & group,
uint64_t low,
uint64_t high,
@@ -309,8 +318,7 @@ NNTP :: xover (const Quark & group,
{
_listener = l;
- if (group != _group)
- _commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
+ get_group(l);
_commands.push_back (build_command ("XOVER %"G_GUINT64_FORMAT"-%"G_GUINT64_FORMAT"\r\n", low, high));
@@ -318,6 +326,19 @@ NNTP :: xover (const Quark & group,
}
void
+NNTP :: xover_count_only (const Quark & group,
+ Listener * l)
+{
+ _listener = l;
+
+ get_group(l);
+
+ _commands.push_back (build_command ("XOVER"));
+
+ write_next_command ();
+}
+
+void
NNTP :: list_newsgroups (Listener * l)
{
_listener = l;
@@ -340,8 +361,7 @@ NNTP :: article (const Quark & group,
{
_listener = l;
- if (group != _group)
- _commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
+ get_group(l);
_commands.push_back (build_command ("ARTICLE %"G_GUINT64_FORMAT"\r\n", article_number));
@@ -355,8 +375,7 @@ NNTP :: article (const Quark & group,
{
_listener = l;
- if (group != _group)
- _commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
+ get_group(l);
_commands.push_back (build_command ("ARTICLE %s\r\n", message_id));
@@ -364,6 +383,63 @@ NNTP :: article (const Quark & group,
}
void
+NNTP :: get_headers (const Quark & group,
+ const char * message_id,
+ Listener * l)
+{
+ _listener = l;
+
+ get_group(l);
+
+ _commands.push_back (build_command ("HEAD %s\r\n", message_id));
+
+ write_next_command ();
+}
+
+void
+NNTP :: get_headers (const Quark & group,
+ uint64_t article_number,
+ Listener * l)
+{
+ _listener = l;
+
+ get_group(l);
+
+ _commands.push_back (build_command ("HEAD %"G_GUINT64_FORMAT"\r\n", article_number));
+
+ write_next_command ();
+}
+
+void
+NNTP :: get_body (const Quark & group,
+ const char * message_id,
+ Listener * l)
+{
+ _listener = l;
+
+ get_group(l);
+
+ _commands.push_back (build_command ("BODY %s\r\n", message_id));
+
+ write_next_command ();
+}
+
+void
+NNTP :: get_body (const Quark & group,
+ uint64_t article_number,
+ Listener * l)
+{
+ _listener = l;
+
+ if (group != _group) get_group(l);
+
+ _commands.push_back (build_command ("BODY %"G_GUINT64_FORMAT"\r\n", article_number));
+
+ write_next_command ();
+}
+
+
+void
NNTP :: group (const Quark & group,
Listener * l)
{
diff --git a/pan/tasks/nntp.h b/pan/tasks/nntp.h
index 3c11970..a6bdcdc 100644
--- a/pan/tasks/nntp.h
+++ b/pan/tasks/nntp.h
@@ -157,11 +157,16 @@ namespace pan
{}
virtual ~NNTP ()
- {
- }
+ {}
public:
+ /* Internal only */
+ void get_group (Listener * l);
+ void get_headers (const Quark & group, const char * message_id, Listener * l);
+ void get_headers (const Quark & group, uint64_t article_number, Listener * l);
+ void get_body (const Quark & group, const char * message_id, Listener * l);
+ void get_body (const Quark & group, uint64_t article_number, Listener * l);
/**
* Lists all available commands.
*/
@@ -188,7 +193,18 @@ namespace pan
uint64_t low,
uint64_t high,
Listener * l);
-
+ /**
+ * Executes an XOVER command: "XOVER" to count
+ * the xover numbers internally
+ *
+ * If successful, this will invoke Listener::on_nntp_line()
+ * for each article header line we get back.
+ *
+ * Listener::on_nntp_done() will be called whether the
+ * command is successful or not.
+ */
+ void xover_count_only (const Quark & group,
+ Listener * l);
/**
* Executes a LIST command: "LIST"
diff --git a/pan/tasks/task-xoverinfo.cc b/pan/tasks/task-xoverinfo.cc
new file mode 100644
index 0000000..5d19e25
--- /dev/null
+++ b/pan/tasks/task-xoverinfo.cc
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 Charles Kerr <charles rebelbase com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <cassert>
+#include <cerrno>
+extern "C" {
+ #define PROTOTYPES
+ #include <stdio.h>
+ #include <uulib/uudeview.h>
+ #include <glib/gi18n.h>
+ #include <gmime/gmime-utils.h>
+ #include <zlib.h>
+}
+#include <fstream>
+#include <iostream>
+#include <pan/general/debug.h>
+#include <pan/general/file-util.h>
+#include <pan/general/macros.h>
+#include <pan/general/messages.h>
+#include <pan/general/utf8-utils.h>
+#include <pan/data/data.h>
+#include "nntp.h"
+#include "task-xoverinfo.h"
+
+
+using namespace pan;
+
+namespace
+{
+ std::string
+ get_short_name (const StringView& in)
+ {
+ static const StringView moderated ("moderated");
+ static const StringView d ("d");
+
+ StringView myline, long_token;
+
+ // find the long token -- use the last, unless that's "moderated" or "d"
+ myline = in;
+ myline.pop_last_token (long_token, '.');
+ if (!myline.empty() && (long_token==moderated || long_token==d))
+ myline.pop_last_token (long_token, '.');
+
+ // build a new string where each token is shortened except for long_token
+ std::string out;
+ myline = in;
+ StringView tok;
+ while (myline.pop_token (tok, '.')) {
+ out.insert (out.end(), tok.begin(), (tok==long_token ? tok.end() : tok.begin()+1));
+ out += '.';
+ }
+ if (!out.empty())
+ out.erase (out.size()-1);
+
+ return out;
+ }
+
+ std::string get_description (const Quark& group)
+ {
+ char buf[1024];
+ snprintf (buf, sizeof(buf), _("Getting header counts for \"%s\""), group.c_str());
+ return std::string (buf);
+ }
+}
+
+TaskXOverInfo :: TaskXOverInfo (Data & data,
+ const Quark & group,
+ std::map<Quark,xover_t>& xovers) :
+ Task("XOVER", get_description(group)),
+ _data (data),
+ _group (group),
+ _short_group_name (get_short_name (StringView (group.c_str()))),
+ _xovers(xovers)
+{
+
+ debug ("ctor for " << group);
+
+ // add a ``GROUP'' MiniTask for each server that has this group
+ // initialize the _high lookup table to boundaries
+ const MiniTask group_minitask (MiniTask::GROUP);
+ quarks_t servers;
+ _data.group_get_servers (group, servers);
+
+ foreach_const (quarks_t, servers, it)
+ {
+ if (_data.get_server_limits(*it))
+ {
+ _server_to_minitasks[*it].push_front (group_minitask);
+ std::pair<uint64_t,uint64_t>& p (xovers[*it]);
+ p.first = data.get_xover_high (group, *it);
+ }
+ }
+ init_steps (0);
+
+ update_work ();
+}
+
+TaskXOverInfo :: ~TaskXOverInfo ()
+{}
+
+void
+TaskXOverInfo :: use_nntp (NNTP* nntp)
+{
+ const Quark& server (nntp->_server);
+ debug ("got an nntp from " << nntp->_server);
+
+ nntp->xover_count_only (_group, this);
+}
+
+/***
+****
+***/
+
+namespace
+{
+ unsigned long view_to_ul (const StringView& view)
+ {
+ unsigned long ul = 0ul;
+
+ if (!view.empty()) {
+ errno = 0;
+ ul = strtoul (view.str, 0, 10);
+ if (errno)
+ ul = 0ul;
+ }
+
+ return ul;
+ }
+ uint64_t view_to_ull (const StringView& view)
+ {
+ uint64_t ul = 0ul;
+
+ if (!view.empty()) {
+ errno = 0;
+ ul = g_ascii_strtoull (view.str, 0, 10);
+ if (errno)
+ ul = 0ul;
+ }
+
+ return ul;
+ }
+
+ bool header_is_nonencoded_utf8 (const StringView& in)
+ {
+ const bool is_nonencoded (!in.strstr("=?"));
+ const bool is_utf8 (g_utf8_validate (in.str, in.len, 0));
+ return is_nonencoded && is_utf8;
+ }
+}
+
+void
+TaskXOverInfo :: on_nntp_line (NNTP * nntp,
+ const StringView & line)
+{
+ uint64_t new_high(atoi(line.str));
+// nntp
+}
+
+void
+TaskXOverInfo :: on_nntp_done (NNTP * nntp,
+ Health health,
+ const StringView & response UNUSED)
+{
+ update_work (true);
+ check_in (nntp, health);
+}
+
+void
+TaskXOverInfo :: update_work (bool subtract_one_from_nntp_count)
+{
+ int nntp_count (get_nntp_count ());
+ if (subtract_one_from_nntp_count)
+ --nntp_count;
+
+ // find any servers we still need
+ quarks_t servers;
+ foreach_const (server_to_minitasks_t, _server_to_minitasks, it)
+ if (!it->second.empty())
+ servers.insert (it->first);
+
+ //std::cerr << LINE_ID << " servers: " << servers.size() << " nntp: " << nntp_count << std::endl;
+
+ if (!servers.empty())
+ _state.set_need_nntp (servers);
+ else if (nntp_count)
+ _state.set_working ();
+ else {
+ _state.set_completed();
+ set_finished(OK);
+ }
+}
diff --git a/pan/tasks/task-xoverinfo.h b/pan/tasks/task-xoverinfo.h
new file mode 100644
index 0000000..afb134c
--- /dev/null
+++ b/pan/tasks/task-xoverinfo.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 Charles Kerr <charles rebelbase com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __TASK_XOVERINFO__H__
+#define __TASK_XOVERINFO__H__
+
+#include <map>
+#include <vector>
+#include <sstream>
+
+#include <pan/data/data.h>
+#include <pan/tasks/task.h>
+#include <pan/tasks/nntp.h>
+#include <fstream>
+#include <iostream>
+
+namespace pan
+{
+ /**
+ * Task for downloading a some or all of a newsgroups' headers
+ * @ingroup tasks
+ */
+ class TaskXOverInfo: public Task, private NNTP::Listener
+ {
+ public: // life cycle
+
+ typedef std::pair<uint64_t,uint64_t> xover_t;
+
+ TaskXOverInfo (Data& data, const Quark& group, std::map<Quark,xover_t>& xovers);
+ virtual ~TaskXOverInfo ();
+
+ public: // task subclass
+ virtual unsigned long get_bytes_remaining () const { return 0ul; }
+
+ protected: // task subclass
+ virtual void use_nntp (NNTP * nntp);
+
+ private: // NNTP::Listener
+ virtual void on_nntp_line (NNTP*, const StringView&);
+ virtual void on_nntp_done (NNTP*, Health, const StringView&);
+ virtual void on_nntp_group (NNTP*, const Quark&, unsigned long, uint64_t, uint64_t);
+
+ private: // implementation - minitasks
+ struct MiniTask {
+ enum Type { GROUP, XOVER };
+ Type _type;
+ uint64_t _low, _high;
+ MiniTask (Type type, uint64_t low=0ul, uint64_t high=0ul):
+ _type(type), _low(low), _high(high) {}
+ };
+ typedef std::deque<MiniTask> MiniTasks_t;
+ typedef std::map<Quark,MiniTasks_t> server_to_minitasks_t;
+ server_to_minitasks_t _server_to_minitasks;
+
+ private: // implementation
+ Data& _data;
+ const Quark _group;
+ std::string _short_group_name;
+ typedef std::map<Quark,uint64_t> server_to_high_t;
+ server_to_high_t _high;
+ void update_work (bool subtract_one_from_nntp_count=false);
+ std::set<Quark> _servers_that_got_xover_minitasks;
+ std::map<NNTP*,uint64_t> _last_xover_number;
+ unsigned long _bytes_so_far;
+ unsigned long _parts_so_far;
+ unsigned long _articles_so_far;
+ unsigned long _total_minitasks;
+ std::map<Quark,xover_t>& _xovers;
+
+
+ };
+}
+
+#endif
diff --git a/pan/usenet-utils/Makefile.am b/pan/usenet-utils/Makefile.am
index df16332..7ee5aed 100644
--- a/pan/usenet-utils/Makefile.am
+++ b/pan/usenet-utils/Makefile.am
@@ -11,7 +11,8 @@ libusenetutils_a_SOURCES = \
numbers.cc \
scorefile.cc \
text-massager.cc \
- url-find.cc
+ url-find.cc \
+ blowfish.cc
noinst_HEADERS = \
defgroup.h \
@@ -24,7 +25,9 @@ noinst_HEADERS = \
scorefile.h \
text-massager.h \
url-find.h \
- ssl-utils.h
+ ssl-utils.h \
+ blowfish.h \
+ blowfish_cyphers.h
#noinst_PROGRAMS = \
# gnksa-test \
diff --git a/pan/usenet-utils/blowfish.cc b/pan/usenet-utils/blowfish.cc
new file mode 100644
index 0000000..b1ee060
--- /dev/null
+++ b/pan/usenet-utils/blowfish.cc
@@ -0,0 +1,229 @@
+// blowfish.cpp C++ class implementation of the BLOWFISH encryption algorithm
+// _THE BLOWFISH ENCRYPTION ALGORITHM_
+// by Bruce Schneier
+// Revised code--3/20/94
+// Converted to C++ class 5/96, Jim Conger
+
+#include "blowfish.h"
+#include "blowfish_cyphers.h" //! holds the random digit tables
+
+#define S(x,i) (SBoxes[i][x.w.byte##i])
+#define bf_F(x) (((S(x,0) + S(x,1)) ^ S(x,2)) + S(x,3))
+#define ROUND(a,b,n) (a.dword ^= bf_F(b) ^ PArray[n])
+
+
+CBlowFish::CBlowFish ()
+{
+ PArray = new DWORD [18] ;
+ SBoxes = new DWORD [4][256] ;
+}
+
+CBlowFish::~CBlowFish ()
+{
+ delete PArray ;
+ delete [] SBoxes ;
+}
+
+/** the low level (private) encryption function */
+void CBlowFish::Blowfish_encipher (DWORD *xl, DWORD *xr)
+{
+ union aword Xl, Xr ;
+
+ Xl.dword = *xl ;
+ Xr.dword = *xr ;
+
+ Xl.dword ^= PArray [0];
+ ROUND (Xr, Xl, 1) ; ROUND (Xl, Xr, 2) ;
+ ROUND (Xr, Xl, 3) ; ROUND (Xl, Xr, 4) ;
+ ROUND (Xr, Xl, 5) ; ROUND (Xl, Xr, 6) ;
+ ROUND (Xr, Xl, 7) ; ROUND (Xl, Xr, 8) ;
+ ROUND (Xr, Xl, 9) ; ROUND (Xl, Xr, 10) ;
+ ROUND (Xr, Xl, 11) ; ROUND (Xl, Xr, 12) ;
+ ROUND (Xr, Xl, 13) ; ROUND (Xl, Xr, 14) ;
+ ROUND (Xr, Xl, 15) ; ROUND (Xl, Xr, 16) ;
+ Xr.dword ^= PArray [17] ;
+
+ *xr = Xl.dword ;
+ *xl = Xr.dword ;
+}
+
+/** the low level (private) decryption function */
+void CBlowFish::Blowfish_decipher (DWORD *xl, DWORD *xr)
+{
+ union aword Xl ;
+ union aword Xr ;
+
+ Xl.dword = *xl ;
+ Xr.dword = *xr ;
+
+ Xl.dword ^= PArray [17] ;
+ ROUND (Xr, Xl, 16) ; ROUND (Xl, Xr, 15) ;
+ ROUND (Xr, Xl, 14) ; ROUND (Xl, Xr, 13) ;
+ ROUND (Xr, Xl, 12) ; ROUND (Xl, Xr, 11) ;
+ ROUND (Xr, Xl, 10) ; ROUND (Xl, Xr, 9) ;
+ ROUND (Xr, Xl, 8) ; ROUND (Xl, Xr, 7) ;
+ ROUND (Xr, Xl, 6) ; ROUND (Xl, Xr, 5) ;
+ ROUND (Xr, Xl, 4) ; ROUND (Xl, Xr, 3) ;
+ ROUND (Xr, Xl, 2) ; ROUND (Xl, Xr, 1) ;
+ Xr.dword ^= PArray[0];
+
+ *xl = Xr.dword;
+ *xr = Xl.dword;
+}
+
+
+/** constructs the enctryption sieve */
+void CBlowFish::Initialize (BYTE key[], int keybytes)
+{
+ int i, j ;
+ DWORD data, datal, datar ;
+ union aword temp ;
+
+ // first fill arrays from data tables
+ for (i = 0 ; i < 18 ; i++)
+ PArray [i] = bf_P [i] ;
+
+ for (i = 0 ; i < 4 ; i++)
+ {
+ for (j = 0 ; j < 256 ; j++)
+ SBoxes [i][j] = bf_S [i][j] ;
+ }
+
+
+ j = 0 ;
+ for (i = 0 ; i < NPASS + 2 ; ++i)
+ {
+ temp.dword = 0 ;
+ temp.w.byte0 = key[j];
+ temp.w.byte1 = key[(j+1) % keybytes] ;
+ temp.w.byte2 = key[(j+2) % keybytes] ;
+ temp.w.byte3 = key[(j+3) % keybytes] ;
+ data = temp.dword ;
+ PArray [i] ^= data ;
+ j = (j + 4) % keybytes ;
+ }
+
+ datal = 0 ;
+ datar = 0 ;
+
+ for (i = 0 ; i < NPASS + 2 ; i += 2)
+ {
+ Blowfish_encipher (&datal, &datar) ;
+ PArray [i] = datal ;
+ PArray [i + 1] = datar ;
+ }
+
+ for (i = 0 ; i < 4 ; ++i)
+ {
+ for (j = 0 ; j < 256 ; j += 2)
+ {
+ Blowfish_encipher (&datal, &datar) ;
+ SBoxes [i][j] = datal ;
+ SBoxes [i][j + 1] = datar ;
+ }
+ }
+}
+
+/** get output length, which must be even MOD 8 */
+DWORD CBlowFish::GetOutputLength (DWORD lInputLong)
+{
+ DWORD lVal ;
+
+ lVal = lInputLong % 8 ; // find out if uneven number of bytes at the end
+ if (lVal != 0)
+ return lInputLong + 8 - lVal ;
+ else
+ return lInputLong ;
+}
+
+/** Encode pIntput into pOutput. Input length in lSize. Returned value
+ * is length of output which will be even MOD 8 bytes. Inputbuffer and
+ * output buffer can be the same, but be sure buffer length is even MOD 8. */
+DWORD CBlowFish::Encode (BYTE * pInput, BYTE * pOutput, DWORD lSize)
+{
+ DWORD lCount, lOutSize, lGoodBytes ;
+ BYTE *pi, *po ;
+ int i, j ;
+ int SameDest = (pInput == pOutput ? 1 : 0) ;
+
+ lOutSize = GetOutputLength (lSize) ;
+ for (lCount = 0 ; lCount < lOutSize ; lCount += 8)
+ {
+ if (SameDest) // if encoded data is being written into input buffer
+ {
+ if (lCount < lSize - 7) // if not dealing with uneven bytes at end
+ {
+ Blowfish_encipher ((DWORD *) pInput,
+ (DWORD *) (pInput + 4)) ;
+ }
+ else // pad end of data with null bytes to complete encryption
+ {
+ po = pInput + lSize ; // point at byte past the end of actual data
+ j = (int) (lOutSize - lSize) ; // number of bytes to set to null
+ for (i = 0 ; i < j ; i++)
+ *po++ = 0 ;
+ Blowfish_encipher ((DWORD *) pInput,
+ (DWORD *) (pInput + 4)) ;
+ }
+ pInput += 8 ;
+ }
+ else // output buffer not equal to input buffer, so must copy
+ { // input to output buffer prior to encrypting
+ if (lCount < lSize - 7) // if not dealing with uneven bytes at end
+ {
+ pi = pInput ;
+ po = pOutput ;
+ for (i = 0 ; i < 8 ; i++)
+ // copy bytes to output
+ *po++ = *pi++ ;
+ Blowfish_encipher ((DWORD *) pOutput, // now encrypt them
+ (DWORD *) (pOutput + 4)) ;
+ }
+ else // pad end of data with null bytes to complete encryption
+ {
+ lGoodBytes = lSize - lCount ; // number of remaining data bytes
+ po = pOutput ;
+ for (i = 0 ; i < (int) lGoodBytes ; i++)
+ *po++ = *pInput++ ;
+ for (j = i ; j < 8 ; j++)
+ *po++ = 0 ;
+ Blowfish_encipher ((DWORD *) pOutput,
+ (DWORD *) (pOutput + 4)) ;
+ }
+ pInput += 8 ;
+ pOutput += 8 ;
+ }
+ }
+ return lOutSize ;
+ }
+
+/** Decode pInput into pOutput. Input length in lSize. Input buffer and
+ * output buffer can be the same, but be sure buffer length is even MOD 8. */
+void CBlowFish::Decode (BYTE * pInput, BYTE * pOutput, DWORD lSize)
+{
+ DWORD lCount ;
+ BYTE *pi, *po ;
+ int i ;
+ int SameDest = (pInput == pOutput ? 1 : 0) ;
+
+ for (lCount = 0 ; lCount < lSize ; lCount += 8)
+ {
+ if (SameDest) // if encoded data is being written into input buffer
+ {
+ Blowfish_decipher ((DWORD *) pInput,
+ (DWORD *) (pInput + 4)) ;
+ pInput += 8 ;
+ }
+ else // output buffer not equal to input buffer
+ { // so copy input to output before decoding
+ pi = pInput ;
+ po = pOutput ;
+ for (i = 0 ; i < 8 ; i++)
+ *po++ = *pi++ ;
+ Blowfish_decipher ((DWORD *) pOutput,
+ (DWORD *) (pOutput + 4)) ;
+ pInput += 8 ;
+ pOutput += 8 ;
+ }
+ }
+}
diff --git a/pan/usenet-utils/blowfish.h b/pan/usenet-utils/blowfish.h
new file mode 100644
index 0000000..6e06b39
--- /dev/null
+++ b/pan/usenet-utils/blowfish.h
@@ -0,0 +1,79 @@
+// blowfish.h interface file for blowfish.cpp
+// _THE BLOWFISH ENCRYPTION ALGORITHM_
+// by Bruce Schneier
+// Revised code--3/20/94
+// Converted to C++ class 5/96, Jim Conger
+
+#define MAXKEYBYTES 56 // 448 bits max
+#define NPASS 16 // SBox passes
+
+#ifndef DWORD
+ #define DWORD unsigned long
+#endif
+#ifndef WORD
+ #define WORD unsigned short
+#endif
+#ifndef BYTE
+ #define BYTE char
+#endif
+
+class CBlowFish
+{
+private:
+ DWORD * PArray ;
+ DWORD (* SBoxes)[256];
+ void Blowfish_encipher (DWORD *xl, DWORD *xr) ;
+ void Blowfish_decipher (DWORD *xl, DWORD *xr) ;
+
+public:
+ CBlowFish () ;
+ ~CBlowFish () ;
+ void Initialize (BYTE key[], int keybytes) ;
+ DWORD GetOutputLength (DWORD lInputLong) ;
+ DWORD Encode (BYTE * pInput, BYTE * pOutput, DWORD lSize) ;
+ void Decode (BYTE * pInput, BYTE * pOutput, DWORD lSize) ;
+
+} ;
+
+// choose a byte order for your hardware
+#define ORDER_DCBA // chosing Intel in this case
+
+#ifdef ORDER_DCBA // DCBA - little endian - intel
+ union aword {
+ DWORD dword;
+ BYTE byte [4];
+ struct {
+ unsigned int byte3:8;
+ unsigned int byte2:8;
+ unsigned int byte1:8;
+ unsigned int byte0:8;
+ } w;
+ };
+#endif
+
+#ifdef ORDER_ABCD // ABCD - big endian - motorola
+ union aword {
+ DWORD dword;
+ BYTE byte [4];
+ struct {
+ unsigned int byte0:8;
+ unsigned int byte1:8;
+ unsigned int byte2:8;
+ unsigned int byte3:8;
+ } w;
+ };
+#endif
+
+#ifdef ORDER_BADC // BADC - vax
+ union aword {
+ DWORD dword;
+ BYTE byte [4];
+ struct {
+ unsigned int byte1:8;
+ unsigned int byte0:8;
+ unsigned int byte3:8;
+ unsigned int byte2:8;
+ } w;
+};
+#endif
+
diff --git a/pan/usenet-utils/blowfish_cyphers.h b/pan/usenet-utils/blowfish_cyphers.h
new file mode 100644
index 0000000..828c445
--- /dev/null
+++ b/pan/usenet-utils/blowfish_cyphers.h
@@ -0,0 +1,268 @@
+// blowfish_cyphers.h
+// header file containing random number tables
+
+static DWORD bf_P[NPASS + 2] = {
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+ 0x9216d5d9, 0x8979fb1b,
+};
+static DWORD bf_S[4][256] = {
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+};
diff --git a/yenclib/crc32.c b/yenclib/crc32.c
new file mode 100644
index 0000000..de276f7
--- /dev/null
+++ b/yenclib/crc32.c
@@ -0,0 +1,614 @@
+// adapted from zlib 1.2.3 by putting it on a piece of wood
+// and banging a few nails throught it
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64 csc com au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+#define FAR
+
+/* @(#) $Id$ */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little (unsigned long,
+ const unsigned char FAR *, unsigned);
+ local unsigned long crc32_big (unsigned long,
+ const unsigned char FAR *, unsigned);
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+static const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
+
+#include <stddef.h> /* for NULL */
+#include "crc32.h"
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long crc32(unsigned long crc, const unsigned char * buf, unsigned int len)
+{
+ if (buf == NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
diff --git a/yenclib/crc32.h b/yenclib/crc32.h
new file mode 100644
index 0000000..b520cd7
--- /dev/null
+++ b/yenclib/crc32.h
@@ -0,0 +1,38 @@
+#ifndef __CRC32_H__
+#define __CRC32_H__
+
+#ifndef _ANSI_ARGS_
+#ifdef PROTOTYPES
+#define _ANSI_ARGS_(c) c
+#else
+#define _ANSI_ARGS_(c) ()
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned long crc32_t;
+#define Z_NULL 0
+
+crc32_t crc32 _ANSI_ARGS_((crc32_t crc, const unsigned char *buf, unsigned int len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/yenclib/uuencode.c b/yenclib/uuencode.c
new file mode 100644
index 0000000..6256ab6
--- /dev/null
+++ b/yenclib/uuencode.c
@@ -0,0 +1,2692 @@
+/*
+ * This file is part of uudeview, the simple and friendly multi-part multi-
+ * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
+ * be contacted at fp fpx de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef SYSTEM_WINDLL
+#include <windows.h>
+#endif
+#ifdef SYSTEM_OS2
+#include <os2.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include <math.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <uudeview.h>
+#include <uuint.h>
+#include <fptools.h>
+#include <uustring.h>
+#include <crc32.h>
+
+/* for braindead systems */
+#ifndef SEEK_SET
+#ifdef L_BEGIN
+#define SEEK_SET L_BEGIN
+#else
+#define SEEK_SET 0
+#endif
+#endif
+
+char * uuencode_id = "$Id: uuencode.c,v 1.22 2002/04/02 10:04:52 fp Exp $";
+
+#if 0
+/*
+ * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
+ * implementations of uudecode will complain about a missing end line, since
+ * they look for "end^J" but find "end^J^M". We don't care - especially be-
+ * cause they still decode the file properly despite this complaint.
+ */
+
+#ifndef EOLSTRING
+#define EOLSTRING "\015\012"
+#endif
+
+#else
+
+/*
+ * Argh. Some delivery software (inews) has problems with the CRLF
+ * line termination. Let's try native EOL and see if we run into
+ * any problems.
+ * This involves opening output files in text mode instead of binary
+ */
+
+#ifndef EOLSTRING
+#define EOLSTRING "\n"
+#endif
+
+#endif
+
+
+/*
+ * =========================================================================
+ * User-configurable settings end here. Don't spy below unless you know what
+ * you're doing.
+ * =========================================================================
+ */
+
+/*
+ * Define End-Of-Line sequence
+ */
+
+#ifdef EOLSTRING
+static unsigned char *eolstring = (unsigned char *) EOLSTRING;
+#else
+static unsigned char *eolstring = (unsigned char *) "\012";
+#endif
+
+/*
+ * Content-Transfer-Encoding types for non-MIME encodings
+ */
+
+#define CTE_UUENC "x-uuencode"
+#define CTE_XXENC "x-xxencode"
+#define CTE_BINHEX "x-binhex"
+#define CTE_YENC "x-yenc"
+
+#define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \
+ ((y)==UU_ENCODED) ? CTE_UUENC : \
+ ((y)==XX_ENCODED) ? CTE_XXENC : \
+ ((y)==PT_ENCODED) ? "8bit" : \
+ ((y)==QP_ENCODED) ? "quoted-printable" : \
+ ((y)==BH_ENCODED) ? CTE_BINHEX : \
+ ((y)==YENC_ENCODED) ? CTE_YENC : "x-oops")
+
+/*
+ * encoding tables
+ */
+
+unsigned char UUEncodeTable[64] =
+{
+ '`', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\',']', '^', '_'
+};
+
+
+unsigned char B64EncodeTable[64] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+unsigned char XXEncodeTable[64] =
+{
+ '+', '-', '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
+ 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
+};
+
+unsigned char BHEncodeTable[64] =
+{
+ '!', '"', '#', '$', '%', '&', '\'', '(',
+ ')', '*', '+', ',', '-', '0', '1', '2',
+ '3', '4', '5', '6', '8', '9', '@', 'A',
+ 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
+ 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
+ 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h',
+ 'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r'
+};
+
+unsigned char HexEncodeTable[16] =
+{
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+typedef struct
+{
+ char *extension;
+ char *mimetype;
+} mimemap;
+
+/*
+ * This table maps a file's extension into a Content-Type. The current
+ * official list can be downloaded as
+ * ftp://ftp.isi.edu/in-notes/iana/assignments/media-type
+ * I haven't listed any text types since it doesn't make sense to encode
+ * them. Everything not on the list gets mapped to application/octet-stream
+ */
+
+static mimemap mimetable[] =
+{
+ { "gif", "image/gif" }, /* Grafics Interchange Format */
+ { "jpg", "image/jpeg" }, /* JFIF encoded files */
+ { "jpeg", "image/jpeg" },
+ { "tif", "image/tiff" }, /* Tag Image File Format */
+ { "tiff", "image/tiff" },
+ { "cgm", "image/cgm" }, /* Computer Graphics Metafile */
+ { "au", "audio/basic" }, /* 8kHz ulaw audio data */
+ { "mov", "video/quicktime" }, /* Apple Quicktime */
+ { "qt", "video/quicktime" }, /* Also infrequently used */
+ { "mpeg", "video/mpeg" }, /* Motion Picture Expert Group */
+ { "mpg", "video/mpeg" },
+ { "mp2", "video/mpeg" }, /* dito, MPEG-2 encoded files */
+ { "mp3", "audio/mpeg" }, /* dito, MPEG-3 encoded files */
+ { "ps", "application/postscript" }, /* Postscript Language */
+ { "zip", "application/zip" }, /* ZIP archive */
+ { "doc", "application/msword"},/* assume Microsoft Word */
+ { NULL, NULL }
+};
+
+/*
+ * the order of the following two tables must match the
+ * Encoding Types definition in uudeview.h
+ */
+
+/*
+ * encoded bytes per line
+ */
+
+static int bpl[8] = { 0, 45, 57, 45, 45, 0, 0, 128 };
+
+/*
+ * tables
+ */
+
+static unsigned char *etables[5] =
+{
+ NULL,
+ UUEncodeTable,
+ B64EncodeTable,
+ XXEncodeTable,
+ BHEncodeTable
+};
+
+/*
+ * variables to malloc upon initialization
+ */
+
+char *uuestr_itemp;
+char *uuestr_otemp;
+
+/*
+ * Encode one part of the data stream
+ */
+
+static int
+UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc32_t *crc, crc32_t *pcrc)
+{
+ unsigned char *itemp = (char *) uuestr_itemp;
+ unsigned char *otemp = (char *) uuestr_otemp;
+ unsigned char *optr, *table, *tptr;
+ int index, count;
+ long line=0;
+ size_t llen;
+
+ if (outfile==NULL || infile==NULL ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUEncodeStream()");
+ return UURET_ILLVAL;
+ }
+
+ /*
+ * Special handling for plain text and quoted printable. Text is
+ * read line oriented.
+ */
+
+ if (encoding == PT_ENCODED || encoding == QP_ENCODED)
+ {
+ while (!feof (infile) && (linperfile <= 0 || line < linperfile))
+ {
+ if (_FP_fgets (itemp, 255, infile) == NULL)
+ {
+ break;
+ }
+
+ itemp[255] = '\0';
+ count = strlen (itemp);
+
+ llen = 0;
+ optr = otemp;
+
+ /*
+ * Busy Callback
+ */
+
+ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
+ uustring (S_ENCODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ if (encoding == PT_ENCODED)
+ {
+ /*
+ * If there is a line feed, replace by eolstring
+ */
+ if (count > 0 && itemp[count-1] == '\n')
+ {
+ itemp[--count] = '\0';
+ if (fwrite (itemp, 1, count, outfile) != count ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ }
+ else
+ {
+ if (fwrite (itemp, 1, count, outfile) != llen)
+ {
+ return UURET_IOERR;
+ }
+ }
+ }
+ else if (encoding == QP_ENCODED)
+ {
+ for (index=0; index<count; index++)
+ {
+ if (llen == 0 && itemp[index] == '.')
+ {
+ /*
+ * Special rule: encode '.' at the beginning of a line, so
+ * that some mailers aren't confused.
+ */
+ *optr++ = '=';
+ *optr++ = HexEncodeTable[itemp[index] >> 4];
+ *optr++ = HexEncodeTable[itemp[index] & 0x0f];
+ llen += 3;
+ }
+ else if ((itemp[index] >= 33 && itemp[index] <= 60) ||
+ (itemp[index] >= 62 && itemp[index] <= 126) ||
+ itemp[index] == 9 || itemp[index] == 32)
+ {
+ *optr++ = itemp[index];
+ llen++;
+ }
+ else if (itemp[index] == '\n')
+ {
+ /*
+ * If the last character before EOL was a space or tab,
+ * we must encode it. If llen > 74, there's no space to do
+ * that, so generate a soft line break instead.
+ */
+
+ if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32))
+ {
+ *(optr-1) = '=';
+ if (llen <= 74)
+ {
+ *optr++ = HexEncodeTable[itemp[index-1] >> 4];
+ *optr++ = HexEncodeTable[itemp[index-1] & 0x0f];
+ llen += 2;
+ }
+ }
+
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+
+ /*
+ * Fix the soft line break condition from above
+ */
+
+ if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32) &&
+ *(optr-1) == '=')
+ {
+ otemp[0] = '=';
+ otemp[1] = HexEncodeTable[itemp[index-1] >> 4];
+ otemp[2] = HexEncodeTable[itemp[index-1] & 0x0f];
+
+ if (fwrite (otemp, 1, 3, outfile) != 3 ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ }
+
+ optr = otemp;
+ llen = 0;
+ }
+ else
+ {
+ *optr++ = '=';
+ *optr++ = HexEncodeTable[itemp[index] >> 4];
+ *optr++ = HexEncodeTable[itemp[index] & 0x0f];
+ llen += 3;
+ }
+
+ /*
+ * Lines must be shorter than 76 characters (not counting CRLF).
+ * If the line grows longer than that, we must include a soft
+ * line break.
+ */
+
+ if (itemp[index+1] != 0 && itemp[index+1] != '\n' &&
+ (llen >= 75 ||
+ (!((itemp[index+1] >= 33 && itemp[index+1] <= 60) ||
+ (itemp[index+1] >= 62 && itemp[index+1] <= 126)) &&
+ llen >= 73)))
+ {
+
+ *optr++ = '=';
+ llen++;
+
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+
+ optr = otemp;
+ llen = 0;
+ }
+ }
+ }
+
+ line++;
+ }
+
+ return UURET_OK;
+ }
+
+ /*
+ * Special handling for yEnc
+ */
+
+ if (encoding == YENC_ENCODED)
+ {
+ llen = 0;
+ optr = otemp;
+
+ while (!feof (infile) && (linperfile <= 0 || line < linperfile))
+ {
+ if ((count = fread (itemp, 1, 128, infile)) != 128)
+ {
+ if (count == 0)
+ {
+ break;
+ }
+ else if (ferror (infile))
+ {
+ return UURET_IOERR;
+ }
+ }
+
+ if (pcrc)
+ *pcrc = crc32(*pcrc, itemp, count);
+ if (crc)
+ *crc = crc32(*crc, itemp, count);
+
+ line++;
+
+ /*
+ * Busy Callback
+ */
+
+ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
+ uustring (S_ENCODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ for (index=0; index<count; index++)
+ {
+ if (llen > 127)
+ {
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ llen = 0;
+ optr = otemp;
+ }
+
+ switch ((char) ((int) itemp[index] + 42))
+ {
+ case '\0':
+// case '\t': yEnc 1.3 draft
+ case '\n':
+ case '\r':
+ case '=':
+ case '\033':
+ *optr++ = '=';
+ *optr++ = (char) ((int) itemp[index] + 42 + 64);
+ llen += 2;
+ break;
+
+ case '.':
+ if (llen == 0)
+ {
+ *optr++ = '=';
+ *optr++ = (char) ((int) itemp[index] + 42 + 64);
+ llen += 2;
+ }
+ else
+ {
+ *optr++ = (char) ((int) itemp[index] + 42);
+ llen++;
+ }
+ break;
+
+ default:
+ *optr++ = (char) ((int) itemp[index] + 42);
+ llen++;
+ break;
+ }
+ }
+ }
+
+ /*
+ * write last line
+ */
+
+ if (llen)
+ {
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ }
+
+ return UURET_OK;
+ }
+
+ /*
+ * Handling for binary encodings
+ */
+
+ /*
+ * select charset
+ */
+
+ table = etables[encoding];
+
+ if (table==NULL || bpl[encoding]==0)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUEncodeStream()");
+ return UURET_ILLVAL;
+ }
+
+ while (!feof (infile) && (linperfile <= 0 || line < linperfile))
+ {
+ if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding])
+ {
+ if (count == 0)
+ break;
+ else if (ferror (infile))
+ return UURET_IOERR;
+ }
+
+ optr = otemp;
+ llen = 0;
+
+ /*
+ * Busy Callback
+ */
+
+ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
+ uustring (S_ENCODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ /*
+ * for UU and XX, encode the number of bytes as first character
+ */
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ *optr++ = table[count];
+ llen++;
+ }
+
+ /*
+ * Main encoding
+ */
+
+ for (index=0; index<=count-3; index+=3, llen+=4)
+ {
+ *optr++ = table[itemp[index] >> 2];
+ *optr++ = table[((itemp[index ] & 0x03) << 4)|(itemp[index+1] >> 4)];
+ *optr++ = table[((itemp[index+1] & 0x0f) << 2)|(itemp[index+2] >> 6)];
+ *optr++ = table[ itemp[index+2] & 0x3f];
+ }
+
+ /*
+ * Special handling for incomplete lines
+ */
+
+ if (index != count)
+ {
+ if (encoding == B64ENCODED)
+ {
+ if (count - index == 2)
+ {
+ *optr++ = table[itemp[index] >> 2];
+ *optr++ = table[((itemp[index ] & 0x03) << 4) |
+ ((itemp[index+1] & 0xf0) >> 4)];
+ *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
+ *optr++ = '=';
+ }
+ else if (count - index == 1)
+ {
+ *optr++ = table[ itemp[index] >> 2];
+ *optr++ = table[(itemp[index] & 0x03) << 4];
+ *optr++ = '=';
+ *optr++ = '=';
+ }
+ llen += 4;
+ }
+ else if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ if (count - index == 2)
+ {
+ *optr++ = table[itemp[index] >> 2];
+ *optr++ = table[((itemp[index ] & 0x03) << 4) |
+ ( itemp[index+1] >> 4)];
+ *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
+ *optr++ = table[0];
+ }
+ else if (count - index == 1)
+ {
+ *optr++ = table[ itemp[index] >> 2];
+ *optr++ = table[(itemp[index] & 0x03) << 4];
+ *optr++ = table[0];
+ *optr++ = table[0];
+ }
+ llen += 4;
+ }
+ }
+
+ /*
+ * end of line
+ */
+
+ tptr = eolstring;
+
+ while (*tptr)
+ *optr++ = *tptr++;
+
+ *optr++ = '\0';
+ llen += strlen ((char *) eolstring);
+
+ if (fwrite (otemp, 1, llen, outfile) != llen)
+ return UURET_IOERR;
+
+ line++;
+ }
+ return UURET_OK;
+}
+
+static int
+UUEncodeStream_byFSize (FILE *outfile, FILE *infile, int encoding, long bpf, crc32_t *crc, crc32_t *pcrc)
+{
+ unsigned char *itemp = (char *) uuestr_itemp;
+ unsigned char *otemp = (char *) uuestr_otemp;
+ unsigned char *optr, *table, *tptr;
+ int index, count;
+ long offset=0;
+ long line = 0;
+ size_t llen;
+
+ if (outfile==NULL || infile==NULL ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ return UURET_ILLVAL;
+ }
+
+ /*
+ * Special handling for plain text and quoted printable. Text is
+ * read line oriented.
+ */
+
+ long rest = bpf;
+ long current = 0;
+
+ ///FIXME
+
+ if (encoding == PT_ENCODED || encoding == QP_ENCODED)
+ {
+ while (!feof (infile) && rest > 0 )
+ {
+ current = rest > 255 ? 255 : rest;
+
+ if ((count = fread (itemp, sizeof(unsigned char), current, infile)) != 255)
+ {
+ if (count == 0)
+ break;
+ else if (ferror (infile))
+ return UURET_IOERR;
+ }
+
+ rest -= count;
+ itemp[count] = '\0';
+
+ llen = 0;
+ optr = otemp;
+
+ /*
+ * Busy Callback
+ */
+
+ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize))
+ return UURET_CANCEL;
+
+ if (encoding == PT_ENCODED)
+ {
+ size_t res;
+ if ((res=fwrite (itemp, sizeof(unsigned char), count, outfile)) != count)
+ return UURET_IOERR;
+ }
+ else if (encoding == QP_ENCODED)
+ {
+ for (index=0; index<count; index++)
+ {
+ if (llen == 0 && itemp[index] == '.')
+ {
+ /*
+ * Special rule: encode '.' at the beginning of a line, so
+ * that some mailers aren't confused.
+ */
+ *optr++ = '=';
+ *optr++ = HexEncodeTable[itemp[index] >> 4];
+ *optr++ = HexEncodeTable[itemp[index] & 0x0f];
+ llen += 3;
+ }
+ else if ((itemp[index] >= 33 && itemp[index] <= 60) ||
+ (itemp[index] >= 62 && itemp[index] <= 126) ||
+ itemp[index] == 9 || itemp[index] == 32)
+ {
+ *optr++ = itemp[index];
+ llen++;
+ }
+ else if (itemp[index] == '\n')
+ {
+ /*
+ * If the last character before EOL was a space or tab,
+ * we must encode it. If llen > 74, there's no space to do
+ * that, so generate a soft line break instead.
+ */
+
+ if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32))
+ {
+ *(optr-1) = '=';
+ if (llen <= 74)
+ {
+ *optr++ = HexEncodeTable[itemp[index-1] >> 4];
+ *optr++ = HexEncodeTable[itemp[index-1] & 0x0f];
+ llen += 2;
+ }
+ }
+
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+
+ /*
+ * Fix the soft line break condition from above
+ */
+
+ if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32) &&
+ *(optr-1) == '=')
+ {
+ otemp[0] = '=';
+ otemp[1] = HexEncodeTable[itemp[index-1] >> 4];
+ otemp[2] = HexEncodeTable[itemp[index-1] & 0x0f];
+
+ if (fwrite (otemp, 1, 3, outfile) != 3 ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ }
+
+ optr = otemp;
+ llen = 0;
+ }
+ else
+ {
+ *optr++ = '=';
+ *optr++ = HexEncodeTable[itemp[index] >> 4];
+ *optr++ = HexEncodeTable[itemp[index] & 0x0f];
+ llen += 3;
+ }
+
+ /*
+ * Lines must be shorter than 76 characters (not counting CRLF).
+ * If the line grows longer than that, we must include a soft
+ * line break.
+ */
+
+ if (itemp[index+1] != 0 && itemp[index+1] != '\n' &&
+ (llen >= 75 ||
+ (!((itemp[index+1] >= 33 && itemp[index+1] <= 60) ||
+ (itemp[index+1] >= 62 && itemp[index+1] <= 126)) &&
+ llen >= 73)))
+ {
+
+ *optr++ = '=';
+ llen++;
+
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+
+ optr = otemp;
+ llen = 0;
+ }
+ }
+ }
+ line++;
+ }
+
+ return UURET_OK;
+ }
+
+ /*
+ * Special handling for yEnc
+ */
+
+ if (encoding == YENC_ENCODED)
+ {
+ llen = 0;
+ optr = otemp;
+ long rest = bpf;
+ long current = 0;
+
+ while (rest > 0)
+ {
+ current = rest > 128 ? 128 : rest;
+
+ if ((count = fread (itemp, sizeof(unsigned char), current, infile)) != 128)
+ {
+ if (count == 0)
+ {
+ break;
+ }
+ else if (ferror (infile))
+ {
+ return UURET_IOERR;
+ }
+
+ }
+
+ if (pcrc)
+ *pcrc = crc32(*pcrc, itemp, count);
+ if (crc)
+ *crc = crc32(*crc, itemp, count);
+
+ line++;
+
+ /*
+ * Busy Callback
+ */
+
+ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
+ uustring (S_ENCODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ for (index=0; index<count; index++)
+ {
+ if (llen > 127 )
+ {
+ if (fwrite (otemp, sizeof(unsigned char), llen, outfile) != llen ||
+ fwrite ((char *) eolstring, sizeof(unsigned char),
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ llen = 0;
+ optr = otemp;
+ }
+
+ char tmp = (char) ((int) itemp[index] + 42);
+
+ switch (tmp)
+ {
+ case '\0':
+// case '\t': yEnc 1.3 draft
+ case '\n':
+ case '\r':
+ case '=':
+ case '\033':
+ *optr++ = '=';
+ *optr++ = tmp + 64;
+ llen += 2;
+ break;
+
+ case '.':
+ if (llen == 0)
+ {
+ *optr++ = '=';
+ *optr++ = tmp + 64;
+ llen += 2;
+ break;
+ }
+
+ default:
+ *optr++ = tmp;
+ llen++;
+ break;
+ }
+ }
+
+ rest -= count;
+ }
+
+
+ /*
+ * write last line
+ */
+
+ if (llen)
+ {
+ if (fwrite (otemp, 1, llen, outfile) != llen ||
+ fwrite ((char *) eolstring, 1,
+ strlen(eolstring), outfile) != strlen (eolstring))
+ {
+ return UURET_IOERR;
+ }
+ }
+
+ return UURET_OK;
+ }
+
+ /*
+ * Handling for binary encodings
+ */
+
+ /*
+ * select charset
+ */
+
+ table = etables[encoding];
+
+ if (table==NULL || bpl[encoding]==0)
+ {
+ return UURET_ILLVAL;
+ }
+
+ while (!feof (infile) && rest > 0)
+ {
+ current = rest > bpl[encoding] ? bpl[encoding] : rest;
+ if ((count = fread (itemp, 1, current, infile)) != bpl[encoding])
+ {
+ if (count == 0)
+ break;
+ else if (ferror (infile))
+ return UURET_IOERR;
+ }
+
+ rest -= count;
+
+ optr = otemp;
+ llen = 0;
+
+ /*
+ * Busy Callback
+ */
+
+ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
+ uustring (S_ENCODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ /*
+ * for UU and XX, encode the number of bytes as first character
+ */
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ *optr++ = table[count];
+ llen++;
+ }
+
+ /*
+ * Main encoding
+ */
+
+ for (index=0; index<=count-3; index+=3, llen+=4)
+ {
+ *optr++ = table[itemp[index] >> 2];
+ *optr++ = table[((itemp[index ] & 0x03) << 4)|(itemp[index+1] >> 4)];
+ *optr++ = table[((itemp[index+1] & 0x0f) << 2)|(itemp[index+2] >> 6)];
+ *optr++ = table[ itemp[index+2] & 0x3f];
+ }
+
+ /*
+ * Special handling for incomplete lines
+ */
+
+ if (index != count)
+ {
+ if (encoding == B64ENCODED)
+ {
+ if (count - index == 2)
+ {
+ *optr++ = table[itemp[index] >> 2];
+ *optr++ = table[((itemp[index ] & 0x03) << 4) |
+ ((itemp[index+1] & 0xf0) >> 4)];
+ *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
+ *optr++ = '=';
+ }
+ else if (count - index == 1)
+ {
+ *optr++ = table[ itemp[index] >> 2];
+ *optr++ = table[(itemp[index] & 0x03) << 4];
+ *optr++ = '=';
+ *optr++ = '=';
+ }
+ llen += 4;
+ }
+ else if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ if (count - index == 2)
+ {
+ *optr++ = table[itemp[index] >> 2];
+ *optr++ = table[((itemp[index ] & 0x03) << 4) |
+ ( itemp[index+1] >> 4)];
+ *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
+ *optr++ = table[0];
+ }
+ else if (count - index == 1)
+ {
+ *optr++ = table[ itemp[index] >> 2];
+ *optr++ = table[(itemp[index] & 0x03) << 4];
+ *optr++ = table[0];
+ *optr++ = table[0];
+ }
+ llen += 4;
+ }
+ }
+
+ /*
+ * end of line
+ */
+
+ tptr = eolstring;
+
+ while (*tptr)
+ *optr++ = *tptr++;
+
+ *optr++ = '\0';
+ llen += strlen ((char *) eolstring);
+
+ if (fwrite (otemp, 1, llen, outfile) != llen)
+ return UURET_IOERR;
+
+ line++;
+ }
+ return UURET_OK;
+}
+
+/*
+ * Encode as MIME multipart/mixed sub-message.
+ */
+
+int UUEXPORT
+UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding,
+ char *outfname, char *mimetype, int filemode)
+{
+ mimemap *miter=mimetable;
+ struct stat finfo;
+ int res, themode;
+ FILE *theifile;
+ char *ptr;
+ crc32_t crc;
+ crc32_t *crcptr=NULL;
+
+ if (outfile==NULL ||
+ (infile == NULL && infname==NULL) ||
+ (outfname==NULL && infname==NULL) ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUEncodeMulti()");
+ return UURET_ILLVAL;
+ }
+
+ progress.action = 0;
+
+ if (infile==NULL)
+ {
+ if (stat (infname, &finfo) == -1)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_STAT_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if ((theifile = fopen (infname, "rb")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
+ progress.fsize = (long) finfo.st_size;
+ }
+ else
+ {
+ if (fstat (fileno (infile), &finfo) != 0)
+ {
+ themode = (filemode)?filemode:0644;
+ progress.fsize = -1;
+ }
+ else
+ {
+ themode = (int) finfo.st_mode & 0777;
+ progress.fsize = (long) finfo.st_size;
+ }
+ theifile = infile;
+ }
+
+ if (progress.fsize < 0)
+ progress.fsize = -1;
+
+ _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 2048);
+
+ progress.partno = 1;
+ progress.numparts = 1;
+ progress.percent = 0;
+ progress.foffset = 0;
+ progress.action = UUACT_ENCODING;
+
+ /*
+ * If not given from outside, select an appropriate Content-Type by
+ * looking at the file's extension. If it is unknown, default to
+ * Application/Octet-Stream
+ */
+
+ if (mimetype == NULL)
+ {
+ if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.')))
+ {
+ while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
+ miter++;
+ mimetype = miter->mimetype;
+ }
+ }
+
+ if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED))
+ {
+ mimetype = "text/plain";
+ }
+
+ /*
+ * print sub-header
+ */
+
+ if (encoding != YENC_ENCODED)
+ {
+ fprintf (outfile, "Content-Type: %s%s",
+ (mimetype)?mimetype:"Application/Octet-Stream",
+ eolstring);
+ fprintf (outfile, "Content-Transfer-Encoding: %s%s",
+ CTE_TYPE(encoding), eolstring);
+ fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
+ UUFNameFilter ((outfname)?outfname:infname), eolstring);
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ fprintf (outfile, "begin %o %s%s",
+ (themode) ? themode : 0644,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ crc = crc32(0L, Z_NULL, 0);
+ crcptr = &crc;
+ if (progress.fsize == -1)
+ {
+ fprintf (outfile, "=ybegin line=128 name=%s%s",
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
+ progress.fsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ }
+
+ if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK)
+ {
+ if (res != UURET_CANCEL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_ERR_ENCODING),
+ UUFNameFilter ((infname)?infname:outfname),
+ (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
+ }
+ progress.action = 0;
+ return res;
+ }
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ fprintf (outfile, "%c%s",
+ (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
+ eolstring);
+ fprintf (outfile, "end%s", eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ if (progress.fsize == -1)
+ {
+ fprintf (outfile, "=yend crc32=%08lx%s",
+ crc,
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
+ progress.fsize,
+ crc,
+ eolstring);
+ }
+ }
+
+ /*
+ * empty line at end does no harm
+ */
+
+ fprintf (outfile, "%s", eolstring);
+
+ if (infile==NULL)
+ fclose (theifile);
+
+ progress.action = 0;
+ return UURET_OK;
+}
+
+/*
+ * Encode as MIME message/partial
+ */
+
+int UUEXPORT
+UUEncodePartial (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, char *mimetype,
+ int filemode, int partno, long linperfile, unsigned long* crcptr)
+{
+ mimemap *miter=mimetable;
+ static FILE *theifile;
+ int themode, numparts;
+ struct stat finfo;
+ long thesize;
+ char *ptr;
+ int res;
+ crc32_t pcrc;
+ crc32_t *pcrcptr=NULL;
+
+ if ((outfname==NULL&&infname==NULL) || partno<=0 ||
+ (infile == NULL&&infname==NULL) || outfile==NULL ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+// UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+// uustring (S_PARM_CHECK), "UUEncodePartial()");
+ return UURET_ILLVAL;
+ }
+
+ /*
+ * The first part needs a set of headers
+ */
+
+ progress.action = 0;
+
+ if (partno == 1)
+ {
+ *crcptr = crc32(0L, Z_NULL, 0);
+
+ if (infile==NULL)
+ {
+ if (stat (infname, &finfo) == -1)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_STAT_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if ((theifile = fopen (infname, "rb")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
+ (linperfile*bpl[encoding]));
+
+ themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
+ thesize = (long) finfo.st_size;
+ }
+ else
+ {
+ if (fstat (fileno (infile), &finfo) != 0)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
+ uustring (S_STAT_ONE_PART));
+ numparts = 1;
+ themode = (filemode)?filemode:0644;
+ thesize = -1;
+ }
+ else
+ {
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
+ (linperfile*bpl[encoding]));
+
+ themode = (int) finfo.st_mode & 0777;
+ thesize = (long) finfo.st_size;
+ }
+ theifile = infile;
+ }
+
+ _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 2048);
+
+ progress.totsize = (thesize>=0) ? thesize : -1;
+ progress.partno = 1;
+ progress.numparts = numparts;
+ progress.percent = 0;
+ progress.foffset = 0;
+
+ /*
+ * If not given from outside, select an appropriate Content-Type by
+ * looking at the file's extension. If it is unknown, default to
+ * Application/Octet-Stream
+ */
+
+ if (mimetype == NULL)
+ {
+ if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.')))
+ {
+ while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
+ miter++;
+ mimetype = miter->mimetype;
+ }
+ }
+
+ if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED))
+ {
+ mimetype = "text/plain";
+ }
+
+ /*
+ * print sub-header
+ */
+
+ if (encoding != YENC_ENCODED)
+ {
+ fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
+ fprintf (outfile, "Content-Type: %s%s",
+ (mimetype)?mimetype:"Application/Octet-Stream",
+ eolstring);
+ fprintf (outfile, "Content-Transfer-Encoding: %s%s",
+ CTE_TYPE(encoding), eolstring);
+ fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
+ UUFNameFilter ((outfname)?outfname:infname), eolstring);
+ }
+
+ fprintf (outfile, "%s", eolstring);
+
+ /*
+ * for the first part of UU or XX messages, print a begin line
+ */
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ fprintf (outfile, "begin %o %s%s",
+ (themode) ? themode : ((filemode)?filemode:0644),
+ UUFNameFilter ((outfname)?outfname:infname), eolstring);
+ }
+ }
+ if (encoding == YENC_ENCODED)
+ {
+ pcrc = crc32(0L, Z_NULL, 0);
+ pcrcptr = &pcrc;
+ if (numparts != 1)
+ {
+ if (progress.totsize == -1)
+ {
+ fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
+ partno,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
+ partno,
+ progress.totsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+
+ fprintf (outfile, "=ypart begin=%ld end=%ld%s",
+ (partno-1)*linperfile*128+1,
+ (partno*linperfile*128) < progress.totsize ?
+ (partno*linperfile*128) : progress.totsize,
+ eolstring);
+ }
+ else
+ {
+ if (progress.totsize == -1)
+ {
+ fprintf (outfile, "=ybegin line=128 name=%s%s",
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
+ progress.totsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ }
+ }
+
+ /*
+ * update progress information
+ */
+
+ progress.partno = partno;
+ progress.percent = 0;
+ progress.foffset = ftell (theifile);
+
+ if (progress.totsize <= 0)
+ progress.fsize = -1;
+ else if (linperfile <= 0)
+ progress.fsize = progress.totsize;
+ else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
+ progress.fsize = progress.totsize - progress.foffset;
+ else
+ progress.fsize = linperfile*bpl[encoding];
+
+ progress.action = UUACT_ENCODING;
+
+ if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile,
+ crcptr, pcrcptr)) != UURET_OK)
+ {
+ if (infile==NULL) fclose (theifile);
+ if (res != UURET_CANCEL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_ERR_ENCODING),
+ UUFNameFilter ((outfname)?outfname:infname),
+ (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
+ }
+ progress.action = 0;
+ return res;
+ }
+
+ /*
+ * print end line
+ */
+
+ if (feof (theifile) &&
+ (encoding == UU_ENCODED || encoding == XX_ENCODED))
+ {
+ fprintf (outfile, "%c%s",
+ (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
+ eolstring);
+ fprintf (outfile, "end%s", eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ if (numparts != 1)
+ {
+ fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
+ (partno*linperfile*128) < progress.totsize ?
+ linperfile*128 : (progress.totsize-(partno-1)*linperfile*128),
+ partno,
+ pcrc);
+ }
+ else
+ {
+ fprintf (outfile, "=yend size=%ld",
+ progress.totsize);
+ }
+ if (feof (theifile))
+ fprintf (outfile, " crc32=%08lx", *crcptr);
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ /*
+ * empty line at end does no harm
+ */
+
+ if (encoding != PT_ENCODED && encoding != QP_ENCODED)
+ {
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ if (infile==NULL)
+ {
+ if (res != UURET_OK)
+ {
+ progress.action = 0;
+ fclose (theifile);
+ return res;
+ }
+ if (feof (theifile))
+ {
+ progress.action = 0;
+ fclose (theifile);
+ return UURET_OK;
+ }
+ return UURET_CONT;
+ }
+
+ /*
+ * leave progress.action as-is
+ */
+
+ return UURET_OK;
+}
+
+int UUEXPORT
+UUEncodePartial_byFSize (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, char *mimetype,
+ int filemode, int partno, long bpf, unsigned long* crcptr)
+{
+ mimemap *miter=mimetable;
+ static FILE *theifile;
+ int themode, numparts;
+ struct stat finfo;
+ long thesize;
+ char *ptr;
+ int res;
+ crc32_t pcrc;
+ crc32_t *pcrcptr=NULL;
+
+ if ((outfname==NULL&&infname==NULL) || partno<=0 ||
+ (infile == NULL&&infname==NULL) || outfile==NULL ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ return UURET_ILLVAL;
+ }
+
+ /*
+ * The first part needs a set of headers
+ */
+
+ progress.action = 0;
+
+ if (partno == 1)
+ {
+ *crcptr = crc32(0L, Z_NULL, 0);
+
+ if (infile==NULL)
+ {
+ if (stat (infname, &finfo) == -1)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_STAT_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if ((theifile = fopen (infname, "rb")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+
+ if (finfo.st_size <= bpf)
+ numparts = 1;
+ else
+ numparts = (int) (ceil((double)finfo.st_size / (double)bpf));
+
+ themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
+ thesize = (long) finfo.st_size;
+ }
+ else
+ {
+ if (fstat (fileno (infile), &finfo) != 0)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
+ uustring (S_STAT_ONE_PART));
+ numparts = 1;
+ themode = (filemode)?filemode:0644;
+ thesize = -1;
+ }
+ else
+ {
+ themode = (int) finfo.st_mode & 0777;
+ thesize = (long) finfo.st_size;
+
+ if (finfo.st_size <= bpf)
+ numparts = 1;
+ else
+ numparts = (int) (ceill(thesize / bpf));
+
+
+ }
+ theifile = infile;
+ }
+
+ _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 2048);
+
+ progress.totsize = (thesize>=0) ? thesize : -1;
+ progress.partno = 1;
+ progress.numparts = numparts;
+ progress.percent = 0;
+ progress.foffset = 0;
+
+ /*
+ * If not given from outside, select an appropriate Content-Type by
+ * looking at the file's extension. If it is unknown, default to
+ * Application/Octet-Stream
+ */
+
+ if (mimetype == NULL)
+ {
+ if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.')))
+ {
+ while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
+ miter++;
+ mimetype = miter->mimetype;
+ }
+ }
+
+ if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED))
+ {
+ mimetype = "text/plain";
+ }
+
+
+ /*
+ * print sub-header
+ */
+
+// if (encoding != YENC_ENCODED)
+// {
+// fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
+// fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s",
+// partno, numparts, eolstring);
+// fprintf (outfile, "Content-Transfer-Encoding: %s%s",
+// CTE_TYPE(encoding), eolstring);
+// fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
+// UUFNameFilter ((outfname)?outfname:infname), eolstring);
+// }
+// fprintf (outfile, "%s", eolstring);
+
+ /*
+ * for the first part of UU or XX messages, print a begin line
+ */
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ fprintf (outfile, "begin %o %s%s",
+ (themode) ? themode : ((filemode)?filemode:0644),
+ UUFNameFilter ((outfname)?outfname:infname), eolstring);
+ }
+ }
+
+ if (encoding == YENC_ENCODED)
+ {
+ pcrc = crc32(0L, Z_NULL, 0);
+ pcrcptr = &pcrc;
+ if (numparts != 1)
+ {
+ if (progress.totsize == -1)
+ {
+ fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
+ partno,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
+ partno,
+ progress.totsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+
+ fprintf (outfile, "=ypart begin=%ld end=%ld%s",
+ (partno-1)*bpf,
+ (partno*bpf) < progress.totsize ?
+ (partno*bpf) : progress.totsize,
+ eolstring);
+ }
+ else
+ {
+
+ if (progress.totsize == -1)
+ {
+ fprintf (outfile, "=ybegin line=128 name=%s%s",
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
+ progress.totsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ }
+ }
+
+ /*
+ * update progress information
+ */
+
+ progress.partno = partno;
+ progress.percent = 0;
+ progress.foffset = ftell (theifile);
+
+ if (progress.totsize <= 0)
+ progress.fsize = -1;
+ else if (bpf <= 0)
+ progress.fsize = progress.totsize;
+ else if (progress.foffset+ bpf > progress.totsize)
+ progress.fsize = progress.totsize - progress.foffset;
+ else
+ progress.fsize = bpf;
+
+ progress.action = UUACT_ENCODING;
+
+ if ((res = UUEncodeStream_byFSize (outfile, theifile, encoding, bpf,
+ crcptr, pcrcptr)) != UURET_OK)
+ {
+ if (infile==NULL) fclose (theifile);
+ if (res != UURET_CANCEL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_ERR_ENCODING),
+ UUFNameFilter ((outfname)?outfname:infname),
+ (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
+ }
+ progress.action = 0;
+ return res;
+ }
+
+ /*
+ * print end line
+ */
+
+ if (feof (theifile) &&
+ (encoding == UU_ENCODED || encoding == XX_ENCODED))
+ {
+ fprintf (outfile, "%c%s",
+ (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
+ eolstring);
+ fprintf (outfile, "end%s", eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ if (numparts != 1)
+ {
+ fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
+ (partno*bpf) < progress.totsize ?
+ bpf : (progress.totsize-(partno-1)*bpf),
+ partno,
+ pcrc);
+ }
+ else
+ {
+ fprintf (outfile, "=yend size=%ld",
+ progress.totsize);
+ }
+ if (feof (theifile))
+ fprintf (outfile, " crc32=%08lx", *crcptr);
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ /*
+ * empty line at end does no harm
+ */
+
+ if (encoding != PT_ENCODED && encoding != QP_ENCODED)
+ {
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ if (infile==NULL)
+ {
+ if (res != UURET_OK)
+ {
+ progress.action = 0;
+ fclose (theifile);
+ return res;
+ }
+ if (feof (theifile))
+ {
+ progress.action = 0;
+ fclose (theifile);
+ return UURET_OK;
+ }
+ return UURET_CONT;
+ }
+
+ /*
+ * leave progress.action as-is
+ */
+
+ return UURET_OK;
+}
+
+/*
+ * send output to a stream, don't do any headers at all
+ */
+
+int UUEXPORT
+UUEncodeToStream (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, int filemode)
+{
+ struct stat finfo;
+ FILE *theifile;
+ int themode;
+ int res;
+ crc32_t crc;
+ crc32_t *crcptr=NULL;
+
+ if (outfile==NULL ||
+ (infile == NULL&&infname==NULL) ||
+ (outfname==NULL&&infname==NULL) ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUEncodeToStream()");
+ return UURET_ILLVAL;
+ }
+
+ progress.action = 0;
+
+ if (infile==NULL)
+ {
+ if (stat (infname, &finfo) == -1)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_STAT_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if ((theifile = fopen (infname, "rb")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
+ progress.fsize = (long) finfo.st_size;
+ }
+ else
+ {
+ if (fstat (fileno (infile), &finfo) == -1)
+ {
+ /* gotta live with it */
+ themode = 0644;
+ progress.fsize = -1;
+ }
+ else
+ {
+ themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
+ progress.fsize = (long) finfo.st_size;
+ }
+ theifile = infile;
+ }
+
+ if (progress.fsize < 0)
+ progress.fsize = -1;
+
+ _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 2048);
+
+ progress.partno = 1;
+ progress.numparts = 1;
+ progress.percent = 0;
+ progress.foffset = 0;
+ progress.action = UUACT_ENCODING;
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ fprintf (outfile, "begin %o %s%s",
+ (themode) ? themode : 0644,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ crc = crc32(0L, Z_NULL, 0);
+ crcptr = &crc;
+ if (progress.fsize == -1)
+ {
+ fprintf (outfile, "=ybegin line=128 name=%s%s",
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
+ progress.fsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ }
+
+ if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK)
+ {
+ if (res != UURET_CANCEL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_ERR_ENCODING),
+ UUFNameFilter ((infname)?infname:outfname),
+ (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
+ }
+ progress.action = 0;
+ return res;
+ }
+
+ if (encoding == UU_ENCODED || encoding == XX_ENCODED)
+ {
+ fprintf (outfile, "%c%s",
+ (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
+ eolstring);
+ fprintf (outfile, "end%s", eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ if (progress.fsize == -1)
+ {
+ fprintf (outfile, "=yend crc32=%08lx%s",
+ crc,
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
+ progress.fsize,
+ crc,
+ eolstring);
+ }
+ }
+
+ /*
+ * empty line at end does no harm
+ */
+
+ fprintf (outfile, "%s", eolstring);
+
+ if (infile==NULL) fclose (theifile);
+ progress.action = 0;
+
+ return UURET_OK;
+}
+
+/*
+ * Encode to files on disk, don't generate any headers
+ */
+
+int UUEXPORT
+UUEncodeToFile (FILE *infile, char *infname, int encoding,
+ char *outfname, char *diskname, long linperfile)
+{
+ int part, numparts, len, filemode, res;
+ char *oname=NULL, *optr, *ptr;
+ FILE *theifile, *outfile;
+ struct stat finfo;
+ crc32_t pcrc, crc;
+ crc32_t *pcrcptr=NULL, *crcptr=NULL;
+
+ if ((diskname==NULL&&infname==NULL) ||
+ (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUEncodeToFile()");
+ return UURET_ILLVAL;
+ }
+
+ if (diskname)
+ {
+ if ((ptr = strchr (diskname, '/')) == NULL)
+ ptr = strchr (diskname, '\\');
+ if (ptr)
+ {
+ len = strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):3) + 5;
+
+ if ((oname = malloc (len)) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_OUT_OF_MEMORY), len);
+ return UURET_NOMEM;
+ }
+ sprintf (oname, "%s", diskname);
+ }
+ else
+ {
+ len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname)
+ + ((uuencodeext)?strlen(uuencodeext):0) + 5;
+
+ if ((oname = malloc (len)) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_OUT_OF_MEMORY), len);
+ return UURET_NOMEM;
+ }
+ sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", diskname);
+ }
+ }
+ else
+ {
+ len = ((uusavepath) ? strlen (uusavepath) : 0) +
+ strlen(UUFNameFilter(infname)) +
+ ((uuencodeext)?strlen(uuencodeext):0) + 5;
+
+ if ((oname = malloc (len)) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_OUT_OF_MEMORY), len);
+ return UURET_NOMEM;
+ }
+ optr = UUFNameFilter (infname);
+ sprintf (oname, "%s%s",
+ (uusavepath)?uusavepath:"",
+ (*optr=='.')?optr+1:optr);
+ }
+
+ /*
+ * optr points after the last dot, so that we can print the part number
+ * there.
+ */
+
+ optr = _FP_strrchr (oname, '.');
+ if (optr==NULL || strchr (optr, '/')!=NULL || strchr (optr, '\\')!=NULL)
+ {
+ optr = oname + strlen (oname);
+ *optr++ = '.';
+ }
+ else if (optr==oname || *(optr-1)=='/' || *(optr-1)=='\\')
+ {
+ optr = oname + strlen (oname);
+ *optr++ = '.';
+ }
+ else
+ optr++;
+
+ progress.action = 0;
+
+ if (infile==NULL)
+ {
+ if (stat (infname, &finfo) == -1)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_STAT_FILE),
+ infname, strerror (uu_errno=errno));
+ _FP_free (oname);
+ return UURET_IOERR;
+ }
+ if ((theifile = fopen (infname, "rb")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ infname, strerror (uu_errno=errno));
+ _FP_free (oname);
+ return UURET_IOERR;
+ }
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) (((long)finfo.st_size + (linperfile*bpl[encoding]-1)) /
+ (linperfile*bpl[encoding]));
+
+ filemode = (int) finfo.st_mode & 0777;
+ progress.totsize = (long) finfo.st_size;
+ }
+ else
+ {
+ if (fstat (fileno (infile), &finfo) == -1)
+ {
+ /* gotta live with it */
+ filemode = 0644;
+ numparts = -1;
+ progress.totsize = -1;
+ }
+ else
+ {
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
+ (linperfile*bpl[encoding]));
+
+ filemode = (int) finfo.st_mode & 0777;
+ progress.totsize = -1;
+ }
+ theifile = infile;
+ }
+
+ _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 2048);
+
+ progress.totsize = (progress.totsize<0) ? -1 : progress.totsize;
+ progress.numparts = numparts;
+
+ for (part=1; !feof (theifile); part++)
+ {
+ /*
+ * Attach extension
+ */
+ if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL)
+ strcpy (optr, uuencodeext);
+ else
+ sprintf (optr, "%03d", part);
+
+ /*
+ * check if target file exists
+ */
+
+ if (!uu_overwrite)
+ {
+ if (stat (oname, &finfo) == 0)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_TARGET_EXISTS), oname);
+ if (infile==NULL) fclose (theifile);
+ progress.action = 0;
+ free (oname);
+ return UURET_EXISTS;
+ }
+ }
+
+ /*
+ * update progress information
+ */
+
+ progress.action = 0;
+ progress.partno = part;
+ progress.percent = 0;
+ progress.foffset = ftell (theifile);
+
+ if (progress.totsize == -1)
+ progress.fsize = -1;
+ else if (linperfile <= 0)
+ progress.fsize = progress.totsize;
+ else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
+ progress.fsize = progress.totsize - progress.foffset;
+ else
+ progress.fsize = linperfile*bpl[encoding];
+
+ progress.action = UUACT_ENCODING;
+
+ if ((outfile = fopen (oname, "w")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_TARGET),
+ oname, strerror (uu_errno = errno));
+ if (infile==NULL) fclose (theifile);
+ progress.action = 0;
+ free (oname);
+ return UURET_IOERR;
+ }
+
+ if (encoding != YENC_ENCODED)
+ {
+ fprintf (outfile, "%s", eolstring);
+ fprintf (outfile, "_=_ %s", eolstring);
+ if (numparts == -1)
+ fprintf (outfile, "_=_ Part %03d of file %s%s",
+ part, UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ else
+ fprintf (outfile, "_=_ Part %03d of %03d of file %s%s",
+ part, numparts,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ fprintf (outfile, "_=_ %s", eolstring);
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ if (part==1 && (encoding == UU_ENCODED || encoding == XX_ENCODED))
+ {
+ fprintf (outfile, "begin %o %s%s",
+ (filemode)?filemode : 0644,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ if (!crcptr)
+ {
+ crc = crc32(0L, Z_NULL, 0);
+ crcptr = &crc;
+ }
+ pcrc = crc32(0L, Z_NULL, 0);
+ pcrcptr = &pcrc;
+ if (numparts != 1)
+ {
+ if (progress.totsize == -1)
+ {
+ fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
+ part,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
+ part,
+ progress.totsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+
+ fprintf (outfile, "=ypart begin=%ld end=%ld%s",
+ (part-1)*linperfile*128+1,
+ (part*linperfile*128) < progress.totsize ?
+ (part*linperfile*128) : progress.totsize,
+ eolstring);
+ }
+ else
+ {
+ if (progress.totsize == -1)
+ {
+ fprintf (outfile, "=ybegin line=128 name=%s%s",
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ else
+ {
+ fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
+ progress.totsize,
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ }
+ }
+ }
+
+ if ((res = UUEncodeStream (outfile, theifile,
+ encoding, linperfile, crcptr, pcrcptr)) != UURET_OK)
+ {
+ if (res != UURET_CANCEL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_ERR_ENCODING),
+ UUFNameFilter ((infname)?infname:outfname),
+ (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
+ }
+ if (infile==NULL) fclose (theifile);
+ progress.action = 0;
+ fclose (outfile);
+ unlink (oname);
+ _FP_free (oname);
+ return res;
+ }
+
+ if (feof (theifile) &&
+ (encoding == UU_ENCODED || encoding == XX_ENCODED))
+ {
+ fprintf (outfile, "%c%s",
+ (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
+ eolstring);
+ fprintf (outfile, "end%s", eolstring);
+ }
+ else if (encoding == YENC_ENCODED)
+ {
+ if (numparts != 1)
+ {
+ fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
+ (part*linperfile*128) < progress.totsize ?
+ linperfile*128 : (progress.totsize-(part-1)*linperfile*128),
+ part,
+ pcrc);
+ }
+ else
+ {
+ fprintf (outfile, "=yend size=%ld",
+ progress.totsize);
+ }
+ if (feof (theifile))
+ fprintf (outfile, " crc32=%08lx", crc);
+ fprintf (outfile, "%s", eolstring);
+ }
+
+ /*
+ * empty line at end does no harm
+ */
+
+ fprintf (outfile, "%s", eolstring);
+ fclose (outfile);
+ }
+
+ if (infile==NULL) fclose (theifile);
+ progress.action = 0;
+ _FP_free (oname);
+ return UURET_OK;
+}
+
+/*
+ * Encode a MIME Mail message or Newsgroup posting and send to a
+ * stream. Still needs a somewhat smart MDA, since we only gene-
+ * rate a minimum set of headers.
+ */
+
+int UUEXPORT
+UUE_PrepSingle (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, int filemode,
+ char *destination, char *from,
+ char *subject, int isemail)
+{
+ return UUE_PrepSingleExt (outfile, infile,
+ infname, encoding,
+ outfname, filemode,
+ destination, from,
+ subject, NULL,
+ isemail);
+}
+
+int UUEXPORT
+UUE_PrepSingleExt (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, int filemode,
+ char *destination, char *from,
+ char *subject, char *replyto,
+ int isemail)
+{
+ mimemap *miter=mimetable;
+ char *subline, *oname;
+ char *mimetype, *ptr;
+ int res, len;
+
+ if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUE_PrepSingle()");
+ return UURET_ILLVAL;
+ }
+
+ oname = UUFNameFilter ((outfname)?outfname:infname);
+ len = ((subject)?strlen(subject):0) + strlen(oname) + 40;
+
+ if ((ptr = _FP_strrchr (oname, '.')))
+ {
+ while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
+ miter++;
+ mimetype = miter->mimetype;
+ }
+ else
+ mimetype = NULL;
+
+ if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED))
+ {
+ mimetype = "text/plain";
+ }
+
+ if ((subline = (char *) malloc (len)) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_OUT_OF_MEMORY), len);
+ return UURET_NOMEM;
+ }
+
+ if (encoding == YENC_ENCODED)
+ {
+ if (subject)
+ sprintf (subline, "- %s - %s (001/001)", oname, subject);
+ else
+ sprintf (subline, "- %s - (001/001)", oname);
+ }
+ else
+ {
+ if (subject)
+ sprintf (subline, "%s (001/001) - [ %s ]", subject, oname);
+ else
+ sprintf (subline, "[ %s ] (001/001)", oname);
+ }
+
+ if (from)
+ {
+ fprintf (outfile, "From: %s%s", from, eolstring);
+ }
+ if (destination)
+ {
+ fprintf (outfile, "%s: %s%s",
+ (isemail)?"To":"Newsgroups",
+ destination, eolstring);
+ }
+
+ fprintf (outfile, "Subject: %s%s", subline, eolstring);
+
+ if (replyto)
+ {
+ fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
+ }
+
+ if (encoding != YENC_ENCODED)
+ {
+ fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
+ fprintf (outfile, "Content-Type: %s; name=\"%s\"%s",
+ (mimetype)?mimetype:"Application/Octet-Stream",
+ UUFNameFilter ((outfname)?outfname:infname),
+ eolstring);
+ fprintf (outfile, "Content-Transfer-Encoding: %s%s",
+ CTE_TYPE(encoding), eolstring);
+ }
+
+ fprintf (outfile, "%s", eolstring);
+
+ res = UUEncodeToStream (outfile, infile, infname, encoding,
+ outfname, filemode);
+
+ _FP_free (subline);
+ return res;
+}
+
+int UUEXPORT
+UUE_PrepPartial (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, int filemode,
+ int partno, long linperfile, long filesize,
+ char *destination, char *from, char *subject,
+ int isemail)
+{
+ return UUE_PrepPartialExt (outfile, infile,
+ infname, encoding,
+ outfname, filemode,
+ partno, linperfile, filesize,
+ destination,
+ from, subject, NULL,
+ isemail);
+}
+
+int UUEXPORT
+UUE_PrepPartialExt (FILE *outfile, FILE *infile,
+ char *infname, int encoding,
+ char *outfname, int filemode,
+ int partno, long linperfile, long filesize,
+ char *destination,
+ char *from, char *subject, char *replyto,
+ int isemail)
+{
+ static int numparts, themode;
+ static char mimeid[64];
+ static FILE *theifile;
+ struct stat finfo;
+ char *subline, *oname;
+ long thesize;
+ int res, len;
+ static crc32_t crc;
+ crc32_t *crcptr=NULL;
+
+ if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
+ (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
+ encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED))
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_PARM_CHECK), "UUE_PrepPartial()");
+ return UURET_ILLVAL;
+ }
+
+ oname = UUFNameFilter ((outfname)?outfname:infname);
+ len = ((subject)?strlen(subject):0) + strlen (oname) + 40;
+
+ /*
+ * if first part, get information about the file
+ */
+
+ if (partno == 1)
+ {
+ if (infile==NULL)
+ {
+ if (stat (infname, &finfo) == -1)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_STAT_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if ((theifile = fopen (infname, "rb")) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ infname, strerror (uu_errno=errno));
+ return UURET_IOERR;
+ }
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
+ (linperfile*bpl[encoding]));
+
+ themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
+ thesize = (long) finfo.st_size;
+ }
+ else
+ {
+ if (fstat (fileno (infile), &finfo) != 0)
+ {
+ if (filesize <= 0)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
+ uustring (S_STAT_ONE_PART));
+ numparts = 1;
+ themode = (filemode)?filemode:0644;
+ thesize = -1;
+ }
+ else
+ {
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) ((filesize+(linperfile*bpl[encoding]-1))/
+ (linperfile*bpl[encoding]));
+
+ themode = (filemode)?filemode:0644;
+ thesize = filesize;
+ }
+ }
+ else
+ {
+ if (linperfile <= 0)
+ numparts = 1;
+ else
+ numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
+ (linperfile*bpl[encoding]));
+
+ filemode = (int) finfo.st_mode & 0777;
+ thesize = (long) finfo.st_size;
+ }
+ theifile = infile;
+ }
+
+ /*
+ * if there's one part only, don't use Message/Partial
+ */
+
+ if (numparts == 1)
+ {
+ if (infile==NULL) fclose (theifile);
+ return UUE_PrepSingleExt (outfile, infile, infname, encoding,
+ outfname, filemode, destination,
+ from, subject, replyto, isemail);
+ }
+
+ /*
+ * we also need a unique ID
+ */
+
+ sprintf (mimeid, "UUDV-%ld.%ld.%s",
+ (long) time(NULL), thesize,
+ (strlen(oname)>16)?"oops":oname);
+ }
+
+ if ((subline = (char *) malloc (len)) == NULL)
+ {
+ UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
+ uustring (S_OUT_OF_MEMORY), len);
+ if (infile==NULL) fclose (theifile);
+ return UURET_NOMEM;
+ }
+
+
+ if (encoding == YENC_ENCODED)
+ {
+ if (partno == 1)
+ crc = crc32(0L, Z_NULL, 0);
+ crcptr = &crc;
+ if (subject)
+ sprintf (subline, "- %s - %s (%03d/%03d)", oname, subject,
+ partno, numparts);
+ else
+ sprintf (subline, "- %s - (%03d/%03d)", oname,
+ partno, numparts);
+ }
+ else
+ {
+ if (subject)
+ sprintf (subline, "%s (%03d/%03d) - [ %s ]",
+ subject, partno, numparts, oname);
+ else
+ sprintf (subline, "[ %s ] (%03d/%03d)",
+ oname, partno, numparts);
+ }
+
+ if (from)
+ {
+ fprintf (outfile, "From: %s%s", from, eolstring);
+ }
+
+ if (destination)
+ {
+ fprintf (outfile, "%s: %s%s",
+ (isemail)?"To":"Newsgroups",
+ destination, eolstring);
+ }
+
+ fprintf (outfile, "Subject: %s%s", subline, eolstring);
+
+ if (replyto)
+ {
+ fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
+ }
+
+ if (encoding != YENC_ENCODED)
+ {
+ fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
+ fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s",
+ partno, numparts, eolstring);
+ fprintf (outfile, "\tid=\"%s\"%s",
+ mimeid, eolstring);
+ }
+
+ fprintf (outfile, "%s", eolstring);
+
+ res = UUEncodePartial (outfile, theifile,
+ infname, encoding,
+ (outfname)?outfname:infname, NULL,
+ themode, partno, linperfile, crcptr);
+
+ _FP_free (subline);
+
+ if (infile==NULL)
+ {
+ if (res != UURET_OK)
+ {
+ fclose (theifile);
+ return res;
+ }
+ if (feof (theifile))
+ {
+ fclose (theifile);
+ return UURET_OK;
+ }
+ return UURET_CONT;
+ }
+
+ return res;
+}
diff --git a/yenclib/uunconc.c b/yenclib/uunconc.c
new file mode 100644
index 0000000..42f9753
--- /dev/null
+++ b/yenclib/uunconc.c
@@ -0,0 +1,1718 @@
+/*
+ * This file is part of uudeview, the simple and friendly multi-part multi-
+ * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
+ * be contacted at fp fpx de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * These are the functions that are responsible for decoding. The
+ * original idea is from a freeware utility called "uunconc", and
+ * few lines of this code may still bear a remote resemblance to
+ * its code. If you are the author or know him, contact me.
+ * This program could only decode one multi-part, uuencoded file
+ * where the parts were in order. Base64, XX and BinHex decoding,
+ * support for multi-files and part-ordering covered by myself.
+ **/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#ifdef SYSTEM_WINDLL
+#include <windows.h>
+#endif
+#ifdef SYSTEM_OS2
+#include <os2.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <crc32.h>
+#include <uudeview.h>
+#include <uuint.h>
+#include <fptools.h>
+#include <uustring.h>
+
+char * uunconc_id = "$Id$";
+
+/* for braindead systems */
+#ifndef SEEK_SET
+#ifdef L_BEGIN
+#define SEEK_SET L_BEGIN
+#else
+#define SEEK_SET 0
+#endif
+#endif
+
+/*
+ * decoder states
+ */
+
+#define BEGIN (1)
+#define DATA (2)
+#define END (3)
+#define DONE (4)
+
+/*
+ * mallocable areas
+ */
+
+char *uunconc_UUxlat;
+char *uunconc_UUxlen;
+char *uunconc_B64xlat;
+char *uunconc_XXxlat;
+char *uunconc_BHxlat;
+char *uunconc_save;
+
+/*
+ * decoding translation tables and line length table
+ */
+
+static int * UUxlen; /* initialized in UUInitConc() */
+static int * UUxlat; /* from the malloc'ed areas above */
+static int * B64xlat;
+static int * XXxlat;
+static int * BHxlat;
+
+/*
+ * buffer for decoding
+ */
+
+static char *save[3];
+
+/*
+ * mallocable areas
+ */
+
+char *uuncdl_fulline;
+char *uuncdp_oline;
+
+/*
+ * Return information for QuickDecode
+ */
+
+static int uulboundary;
+
+/*
+ * To prevent warnings when using a char as index into an array
+ */
+
+#define ACAST(s) ((int)(unsigned char)(s))
+
+/*
+ * Initialize decoding tables
+ */
+
+void
+UUInitConc (void)
+{
+ int i, j;
+
+ /*
+ * Update pointers
+ */
+ UUxlen = (int *) uunconc_UUxlen;
+ UUxlat = (int *) uunconc_UUxlat;
+ B64xlat = (int *) uunconc_B64xlat;
+ XXxlat = (int *) uunconc_XXxlat;
+ BHxlat = (int *) uunconc_BHxlat;
+
+ save[0] = uunconc_save;
+ save[1] = uunconc_save + 256;
+ save[2] = uunconc_save + 512;
+
+ /* prepare decoding translation table */
+ for(i = 0; i < 256; i++)
+ UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1;
+
+ /*
+ * At some time I received a file which used lowercase characters for
+ * uuencoding. This shouldn't be, but let's accept it. Must take special
+ * care that this doesn't break xxdecoding. This is giving me quite a
+ * headache. If this one file hadn't been a Pocahontas picture, I might
+ * have ignored it for good.
+ */
+
+ for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
+ UUxlat[i] /* = UUxlat[i+64] */ = j;
+ for (i = '`', j = 0; i < '`' + 32; i++, j++)
+ UUxlat[i] = j;
+
+ /* add special cases */
+ UUxlat['`'] = UUxlat[' '];
+ UUxlat['~'] = UUxlat['^'];
+
+ /* prepare line length table */
+ UUxlen[0] = 1;
+ for(i = 1, j = 5; i <= 61; i += 3, j += 4)
+ UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j;
+
+ /* prepare other tables */
+ for (i=0; i<64; i++) {
+ B64xlat[ACAST(B64EncodeTable[i])] = i;
+ XXxlat [ACAST(XXEncodeTable [i])] = i;
+ BHxlat [ACAST(BHEncodeTable [i])] = i;
+ }
+}
+
+/*
+ * Workaround for Netscape
+ */
+
+/*
+ * Determines whether Netscape may have broken up a data line (by
+ * inserting a newline). This only seems to happen after <a in a
+ * href statement
+ */
+
+static int
+UUBrokenByNetscape (char *string)
+{
+ char *ptr;
+ int len;
+
+ if (string==NULL || (len=strlen(string))<3)
+ return 0;
+
+ if ((ptr = _FP_stristr (string, "<a href=")) != NULL) {
+ if (_FP_stristr (string, "</a>") > ptr)
+ return 2;
+ }
+
+ ptr = string + len;
+
+ while (len && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) {
+ ptr--; len--;
+ }
+ if (len<3) return 0;
+ if (*--ptr == ' ') ptr--;
+ ptr--;
+
+ if (_FP_strnicmp (ptr, "<a", 2) == 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Try to repair a Netscape-corrupted line of data.
+ * This must only be called on corrupted lines, since non-Netscape
+ * data may even _get_ corrupted by this procedure.
+ *
+ * Some checks are included multiply to speed up the procedure. For
+ * example: (*p1!='<' || strnicmp(p1,"</a>",4)). If the first expression
+ * becomes true, the costly function isn't called :-)
+ *
+ * Since '<', '>', '&' might even be replaced by their html equivalents
+ * in href strings, I'm now using two passes, the first one for & + co,
+ * the second one for hrefs.
+ */
+
+static int
+UUNetscapeCollapse (char *string)
+{
+ char *p1=string, *p2=string;
+ int res = 0;
+
+ if (string==NULL)
+ return 0;
+
+ /*
+ * First pass
+ */
+ while (*p1) {
+ if (*p1 == '&') {
+ if (_FP_strnicmp (p1, "&", 5) == 0) { p1+=5; *p2++='&'; res=1; }
+ else if (_FP_strnicmp (p1, "<", 4) == 0) { p1+=4; *p2++='<'; res=1; }
+ else if (_FP_strnicmp (p1, ">", 4) == 0) { p1+=4; *p2++='>'; res=1; }
+ else *p2++ = *p1++;
+ }
+ else *p2++ = *p1++;
+ }
+ *p2 = '\0';
+ /*
+ * Second pass
+ */
+ p1 = p2 = string;
+
+ while (*p1) {
+ if (*p1 == '<') {
+ if ((_FP_strnicmp (p1, "<ahref=", 7) == 0 ||
+ _FP_strnicmp (p1, "<a href=",8) == 0) &&
+ (_FP_strstr (p1, "</a>") != 0 || _FP_strstr (p1, "</A>") != 0)) {
+ while (*p1 && *p1!='>') p1++;
+ if (*p1=='\0' || *(p1+1)!='<') return 0;
+ p1++;
+ while (*p1 && (*p1!='<' || _FP_strnicmp(p1,"</a>",4)!=0)) {
+ *p2++ = *p1++;
+ }
+ if (_FP_strnicmp(p1,"</a>",4) != 0)
+ return 0;
+ p1+=4;
+ res=1;
+ }
+ else
+ *p2++ = *p1++;
+ }
+ else
+ *p2++ = *p1++;
+ }
+ *p2 = '\0';
+
+ return res;
+}
+
+/*
+ * The second parameter is 0 if we are still searching for encoded data,
+ * otherwise it indicates the encoding we're using right now. If we're
+ * still in the searching stage, we must be a little more strict in
+ * deciding for or against encoding; there's too much plain text looking
+ * like encoded data :-(
+ */
+
+int
+UUValidData (char *ptr, int encoding, int *bhflag)
+{
+ int i=0, j, len=0, suspicious=0, flag=0;
+ char *s = ptr;
+
+ if ((s == NULL) || (*s == '\0')) {
+ return 0; /* bad string */
+ }
+
+ while (*s && *s!='\012' && *s!='\015') {
+ s++;
+ len++;
+ i++;
+ }
+
+ if (i == 0)
+ return 0;
+
+ switch (encoding) {
+ case UU_ENCODED:
+ goto _t_UU;
+ case XX_ENCODED:
+ goto _t_XX;
+ case B64ENCODED:
+ goto _t_B64;
+ case BH_ENCODED:
+ goto _t_Binhex;
+ case YENC_ENCODED:
+ return YENC_ENCODED;
+ }
+
+ _t_Binhex: /* Binhex Test */
+ len = i; s = ptr;
+
+ /*
+ * bhflag notes the state we're in. Within the data, it's 1. If we're
+ * still looking for the initial :, it's 0
+ */
+ if (*bhflag == 0 && *s != ':') {
+ if (encoding==BH_ENCODED) return 0;
+ goto _t_B64;
+ }
+ else if (*bhflag == 0 /* *s == ':' */) {
+ s++; len--;
+ }
+
+ while (len && BHxlat[ACAST(*s)] != -1) {
+ len--; s++;
+ }
+
+ /* allow space characters at the end of the line if we are sure */
+ /* that this is Binhex encoded data or the line was long enough */
+
+ flag = (*s == ':') ? 0 : 1;
+
+ if (*s == ':' && len>0) {
+ s++; len--;
+ }
+ if (((i>=60 && len<=10) || encoding) && *s==' ') {
+ while (len && *s==' ') {
+ s++; len--;
+ }
+ }
+
+ /*
+ * BinHex data shall have exactly 64 characters (except the last
+ * line). We ignore everything with less than 40 characters to
+ * be flexible
+ */
+
+ if (len != 0 || (flag && i < 40)) {
+ if (encoding==BH_ENCODED) return 0;
+ goto _t_B64;
+ }
+
+ *bhflag = flag;
+
+ return BH_ENCODED;
+
+ _t_B64: /* Base64 Test */
+ len = i; s = ptr;
+
+ /*
+ * Face it: there _are_ Base64 lines that are not a multiple of four
+ * in length :-(
+ *
+ * if (len%4)
+ * goto _t_UU;
+ */
+
+ while (len--) {
+ if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) {
+ /* allow space characters at the end of the line if we are sure */
+ /* that this is Base64 encoded data or the line was long enough */
+ if (((i>=60 && len<=10) || encoding) && *s++==' ') {
+ while (*s==' ' && len) s++;
+ if (len==0) return B64ENCODED;
+ }
+ if (encoding==B64ENCODED) return 0;
+ goto _t_UU;
+ }
+ else if (*s == '=') { /* special case at end */
+ /* if we know this is B64encoded, allow spaces at end of line */
+ s++;
+ if (*s=='=' && len>=1) {
+ len--; s++;
+ }
+ if (encoding && len && *s==' ') {
+ while (len && *s==' ') {
+ s++; len--;
+ }
+ }
+ if (len != 0) {
+ if (encoding==B64ENCODED) return 0;
+ goto _t_UU;
+ }
+ return B64ENCODED;
+ }
+ s++;
+ }
+ return B64ENCODED;
+
+ _t_UU:
+ len = i; s = ptr;
+
+ if (UUxlat[ACAST(*s)] == -1) { /* uutest */
+ if (encoding==UU_ENCODED) return 0;
+ goto _t_XX;
+ }
+
+ j = UUxlen[UUxlat[ACAST(*s)]];
+
+ if (len-1 == j) /* remove trailing character */
+ len--;
+ if (len != j) {
+ switch (UUxlat[ACAST(*s)]%3) {
+ case 1:
+ if (j-2 == len) j-=2;
+ break;
+ case 2:
+ if (j-1 == len) j-=1;
+ break;
+ }
+ }
+
+ /*
+ * some encoders are broken with respect to encoding the last line of
+ * a file and produce extraoneous characters beyond the expected EOL
+ * So were not too picky here about the last line, as long as it's longer
+ * than necessary and shorter than the maximum
+ * this tolerance broke the xxdecoding, because xxencoded data was
+ * detected as being uuencoded :( so don't accept 'h' as first character
+ * also, if the first character is lowercase, don't accept the line to
+ * have space characters. the only encoder I've heard of which uses
+ * lowercase characters at least accepts the special case of encoding
+ * 0 as `. The strchr() shouldn't be too expensive here as it's only
+ * evaluated if the first character is lowercase, which really shouldn't
+ * be in uuencoded text.
+ */
+ if (len != j &&
+ ((ptr[0] == '-' && ptr[1] == '-' && strstr(ptr,"part")!=NULL) ||
+ !(*ptr != 'M' && *ptr != 'h' &&
+ len > j && len <= UUxlen[UUxlat['M']]))) {
+ if (encoding==UU_ENCODED) return 0;
+ goto _t_XX; /* bad length */
+ }
+
+ if (len != j || islower (*ptr)) {
+ /*
+ * if we are not in a 'uuencoded' state, don't allow the line to have
+ * space characters at all. if we know we _are_ decoding uuencoded
+ * data, the rest of the line, beyond the length of encoded data, may
+ * have spaces.
+ */
+ if (encoding != UU_ENCODED)
+ if (strchr (ptr, ' ') != NULL)
+ goto _t_XX;
+
+/* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */
+ len = j;
+ }
+
+ while (len--) {
+ if (*s < 0 || UUxlat[ACAST(*s++)] < 0) {
+ if (encoding==UU_ENCODED) return 0;
+ goto _t_XX; /* bad code character */
+ }
+ if (*s == ' ' && suspicious) {
+ if (encoding==UU_ENCODED) return 0;
+ goto _t_XX; /* this line looks _too_ suspicious */
+ }
+ }
+ return UU_ENCODED; /* data is valid */
+
+ _t_XX: /* XX Test */
+ len = i; s = ptr;
+
+ if (XXxlat[ACAST(*s)] == -1)
+ return 0;
+
+ j = UUxlen[XXxlat[ACAST(*s)]]; /* Same line length table as UUencoding */
+
+ if (len-1 == j) /* remove trailing character */
+ len--;
+ if (len != j)
+ switch (UUxlat[ACAST(*s)]%3) {
+ case 1:
+ if (j-2 == len) j-=2;
+ break;
+ case 2:
+ if (j-1 == len) j-=1;
+ break;
+ }
+ /*
+ * some encoders are broken with respect to encoding the last line of
+ * a file and produce extraoneous characters beyond the expected EOL
+ * So were not too picky here about the last line, as long as it's longer
+ * than necessary and shorter than the maximum
+ */
+ if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']]))
+ return 0; /* bad length */
+
+ while(len--) {
+ if(*s < 0 || XXxlat[ACAST(*s++)] < 0) {
+ return 0; /* bad code character */
+ }
+ }
+ return XX_ENCODED; /* data is valid */
+}
+
+/*
+ * This function may be called upon a line that does not look like
+ * valid encoding on first sight, but might be erroneously encoded
+ * data from Netscape, Lynx or MS Exchange. We might need to read
+ * a new line from the stream, which is why we need the FILE.
+ * Returns the type of encoded data if successful or 0 otherwise.
+ */
+
+int
+UURepairData (FILE *datei, char *line, int encoding, int *bhflag)
+{
+ int nflag, vflag=0, safety=42;
+ char *ptr;
+
+ nflag = UUBrokenByNetscape (line);
+
+ while (vflag == 0 && nflag && safety--) {
+ if (nflag == 1) { /* need next line to repair */
+ if (strlen (line) > 250)
+ break;
+ ptr = line + strlen (line);
+ while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012'))
+ ptr--;
+ if (_FP_fgets (ptr, 255-(ptr-line), datei) == NULL)
+ break;
+ }
+ else { /* don't need next line to repair */
+ }
+ if (UUNetscapeCollapse (line)) {
+ if ((vflag = UUValidData (line, encoding, bhflag)) == 0)
+ nflag = UUBrokenByNetscape (line);
+ }
+ else
+ nflag = 0;
+ }
+ /*
+ * Sometimes, a line is garbled even without it being split into
+ * the next line. Then we try this in our despair
+ */
+ if (vflag == 0) {
+ if (UUNetscapeCollapse (line))
+ vflag = UUValidData (line, encoding, bhflag);
+ }
+
+ /*
+ * If this line looks uuencoded, but the line is one character short
+ * of a valid line, it was probably broken by MS Exchange. According
+ * to my test cases, there is at most one space character missing;
+ * there are never two spaces together.
+ * If adding a space character helps making this line uuencoded, do
+ * it!
+ */
+
+ if (vflag == 0) {
+ ptr = line + strlen(line);
+ while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) {
+ ptr--;
+ }
+ *ptr++ = ' ';
+ *ptr-- = '\0';
+ if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) {
+ *ptr = '\0';
+ vflag = 0;
+ }
+ }
+ return vflag;
+}
+
+/*
+ * Decode a single encoded line using method
+ */
+
+size_t
+UUDecodeLine (char *s, char *d, int method)
+{
+ int i, j, c, cc, count=0, z1, z2, z3, z4;
+ static int leftover=0;
+ int *table;
+
+ /*
+ * for re-initialization
+ */
+
+ if (s == NULL || d == NULL) {
+ leftover = 0;
+ return 0;
+ }
+
+ /*
+ * To shut up gcc -Wall
+ */
+ z1 = z2 = z3 = z4 = 0;
+
+ if (method == UU_ENCODED || method == XX_ENCODED) {
+ if (method == UU_ENCODED)
+ table = UUxlat;
+ else
+ table = XXxlat;
+
+ i = table [ACAST(*s++)];
+ j = UUxlen[i] - 1;
+
+ while(j > 0) {
+ c = table[ACAST(*s++)] << 2;
+ cc = table[ACAST(*s++)];
+ c |= (cc >> 4);
+
+ if(i-- > 0)
+ d[count++] = c;
+
+ cc <<= 4;
+ c = table[ACAST(*s++)];
+ cc |= (c >> 2);
+
+ if(i-- > 0)
+ d[count++] = cc;
+
+ c <<= 6;
+ c |= table[ACAST(*s++)];
+
+ if(i-- > 0)
+ d[count++] = c;
+
+ j -= 4;
+ }
+ }
+ else if (method == B64ENCODED) {
+ if (leftover) {
+ strcpy (uuncdl_fulline+leftover, s);
+ leftover = 0;
+ s = uuncdl_fulline;
+ }
+
+ while ((z1 = B64xlat[ACAST(*s)]) != -1) {
+ if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
+ if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
+ if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
+
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ d[count++] = (z2 << 4) | (z3 >> 2);
+ d[count++] = (z3 << 6) | (z4);
+
+ s += 4;
+ }
+ if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ s+=2;
+ }
+ else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ d[count++] = (z2 << 4) | (z3 >> 2);
+ s+=3;
+ }
+ while (B64xlat[ACAST(*s)] != -1)
+ uuncdl_fulline[leftover++] = *s++;
+ }
+ else if (method == BH_ENCODED) {
+ if (leftover) {
+ strcpy (uuncdl_fulline+leftover, s);
+ leftover = 0;
+ s = uuncdl_fulline;
+ }
+ else if (*s == ':')
+ s++;
+
+ while ((z1 = BHxlat[ACAST(*s)]) != -1) {
+ if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break;
+ if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break;
+ if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break;
+
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ d[count++] = (z2 << 4) | (z3 >> 2);
+ d[count++] = (z3 << 6) | (z4);
+
+ s += 4;
+ }
+ if (z1 != -1 && z2 != -1 && *(s+2) == ':') {
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ s+=2;
+ }
+ else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') {
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ d[count++] = (z2 << 4) | (z3 >> 2);
+ s+=3;
+ }
+ while (BHxlat[ACAST(*s)] != -1)
+ uuncdl_fulline[leftover++] = *s++;
+ }
+ else if (method == YENC_ENCODED) {
+ while (*s) {
+ if (*s == '=') {
+ if (*++s != '\0') {
+ d[count++] = (char) ((int) *s - 64 - 42);
+ s++;
+ }
+ }
+ else if (*s == '\n' || *s == '\r') {
+ s++; /* ignore */
+ }
+ else {
+ d[count++] = (char) ((int) *s++ - 42);
+ }
+ }
+ }
+
+ return count;
+}
+
+/*
+ * ``Decode'' Quoted-Printable text
+ */
+
+static int
+UUDecodeQP (FILE *datain, FILE *dataout, int *state,
+ long maxpos, int method, int flags,
+ char *boundary)
+{
+ char *line=uugen_inbuffer, *p1, *p2;
+ int val;
+
+ uulboundary = -1;
+
+ while (!feof (datain) &&
+ (ftell(datain)<maxpos || flags&FL_TOEND ||
+ (!(flags&FL_PROPER) && uu_fast_scanning))) {
+ if (_FP_fgets (line, 255, datain) == NULL)
+ break;
+ if (ferror (datain)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_SOURCE_READ_ERR),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+ line[255] = '\0';
+
+ if (boundary && line[0]=='-' && line[1]=='-' &&
+ strncmp (line+2, boundary, strlen (boundary)) == 0) {
+ if (line[strlen(boundary)+2]=='-')
+ uulboundary = 1;
+ else
+ uulboundary = 0;
+ return UURET_OK;
+ }
+
+ if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
+ uustring (S_DECODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ p1 = p2 = line;
+
+ while (*p2) {
+ while (*p2 && *p2 != '=')
+ p2++;
+ if (*p2 == '\0')
+ break;
+ *p2 = '\0';
+ fprintf (dataout, "%s", p1);
+ p1 = ++p2;
+
+ if (isxdigit (*p2) && isxdigit (*(p2+1))) {
+ val = ((isdigit(*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4;
+ val |= ((isdigit(*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10));
+
+ fputc (val, dataout);
+ p2 += 2;
+ p1 = p2;
+ }
+ else if (*p2 == '\012' || *(p2+1) == '\015') {
+ /* soft line break */
+ *p2 = '\0';
+ break;
+ }
+ else {
+ /* huh? */
+ fputc ('=', dataout);
+ }
+ }
+ /*
+ * p2 points to a nullbyte right after the CR/LF/CRLF
+ */
+ val = 0;
+ while (p2>p1 && isspace (*(p2-1))) {
+ if (*(p2-1) == '\012' || *(p2-1) == '\015')
+ val = 1;
+ p2--;
+ }
+ *p2 = '\0';
+
+ /*
+ * If the part ends directly after this line, the data does not end
+ * with a linebreak. Or, as the docs put it, "the CRLF preceding the
+ * encapsulation line is conceptually attached to the boundary.
+ * So if the part ends here, don't print a line break"
+ */
+ if (val && (!feof (datain) &&
+ (ftell(datain)<maxpos || flags&FL_TOEND ||
+ (!(flags&FL_PROPER) && uu_fast_scanning))))
+ fprintf (dataout, "%s\n", p1);
+ else
+ fprintf (dataout, "%s", p1);
+ }
+ return UURET_OK;
+}
+
+/*
+ * ``Decode'' plain text. Our job is to properly handle the EOL sequence
+ */
+
+static int
+UUDecodePT (FILE *datain, FILE *dataout, int *state,
+ long maxpos, int method, int flags,
+ char *boundary)
+{
+ char *line=uugen_inbuffer, *ptr;
+
+ uulboundary = -1;
+
+ while (!feof (datain) &&
+ (ftell(datain)<maxpos || flags&FL_TOEND ||
+ (!(flags&FL_PROPER) && uu_fast_scanning))) {
+ if (_FP_fgets (line, 255, datain) == NULL)
+ break;
+ if (ferror (datain)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_SOURCE_READ_ERR),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+ line[255] = '\0';
+
+ if (boundary && line[0]=='-' && line[1]=='-' &&
+ strncmp (line+2, boundary, strlen (boundary)) == 0) {
+ if (line[strlen(boundary)+2]=='-')
+ uulboundary = 1;
+ else
+ uulboundary = 0;
+ return UURET_OK;
+ }
+
+ if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
+ uustring (S_DECODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ ptr = line + strlen (line);
+
+ while (ptr>line && (*(ptr-1) == '\012' || *(ptr-1) == '\015'))
+ ptr--;
+
+
+ /*
+ * If the part ends directly after this line, the data does not end
+ * with a linebreak. Or, as the docs put it, "the CRLF preceding the
+ * encapsulation line is conceptually attached to the boundary.
+ * So if the part ends here, don't print a line break"
+ */
+ if ((*ptr == '\012' || *ptr == '\015') &&
+ (ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
+ !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
+ *ptr = '\0';
+ fprintf (dataout, "%s\n", line);
+ }
+ else {
+ *ptr = '\0';
+ fprintf (dataout, "%s", line);
+ }
+ }
+ return UURET_OK;
+}
+
+/*
+ * Decode a single field using method. For the moment, this supports
+ * Base64 and Quoted Printable only, to support RFC 1522 header decoding.
+ * Quit when seeing the RFC 1522 ?= end marker.
+ */
+
+int
+UUDecodeField (char *s, char *d, int method)
+{
+ int z1, z2, z3, z4;
+ int count=0;
+
+ if (method == B64ENCODED) {
+ while ((z1 = B64xlat[ACAST(*s)]) != -1) {
+ if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
+ if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
+ if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
+
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ d[count++] = (z2 << 4) | (z3 >> 2);
+ d[count++] = (z3 << 6) | (z4);
+
+ s+=4;
+ }
+ if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ s+=2;
+ }
+ else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
+ d[count++] = (z1 << 2) | (z2 >> 4);
+ d[count++] = (z2 << 4) | (z3 >> 2);
+ s+=3;
+ }
+ }
+ else if (method == QP_ENCODED) {
+ while (*s && (*s != '?' || *(s+1) != '=')) {
+ while (*s && *s != '=' && (*s != '?' || *(s+1) != '=')) {
+ d[count++] = *s++;
+ }
+ if (*s == '=') {
+ if (isxdigit (*(s+1)) && isxdigit (*(s+2))) {
+ d[count] = (isdigit (*(s+1)) ? (*(s+1)-'0') : (tolower (*(s+1))-'a'+10)) << 4;
+ d[count] |= (isdigit (*(s+2)) ? (*(s+2)-'0') : (tolower (*(s+2))-'a'+10));
+ count++;
+ s+=3;
+ }
+ else if (*(s+1) == '\012' || *(s+1) == '\015') {
+ s+=2;
+ }
+ else {
+ d[count++] = *s++;
+ }
+ }
+ }
+ }
+ else {
+ return -1;
+ }
+
+ d[count] = '\0';
+ return count;
+}
+
+int
+UUDecodePart (FILE *datain, FILE *dataout, int *state,
+ long maxpos, int method, int flags,
+ char *boundary)
+{
+ char *line = uugen_fnbuffer;
+ int line_len = UUGEN_FNBUFFER_LEN;
+ char *oline=uuncdp_oline;
+ int warning=0, vlc=0, lc[2], hadct=0;
+ int tc=0, tf=0, vflag, haddata=0, haddh=0;
+ long yefilesize=0, yepartends=0;
+ crc32_t yepartcrc=crc32(0L, Z_NULL, 0);
+ static crc32_t yefilecrc=0;
+ static int bhflag=0;
+ size_t count=0;
+ size_t yepartsize=0;
+ char *ptr;
+
+ if (datain == NULL || dataout == NULL) {
+ yefilecrc = crc32(0L, Z_NULL, 0);
+ bhflag = 0;
+ return UURET_OK;
+ }
+
+ /*
+ * Use specialized functions for QP_ENCODED and PT_ENCODED plaintext
+ */
+
+ if (method == QP_ENCODED)
+ return UUDecodeQP (datain, dataout, state, maxpos,
+ method, flags, boundary);
+ else if (method == PT_ENCODED)
+ return UUDecodePT (datain, dataout, state, maxpos,
+ method, flags, boundary);
+
+ lc[0] = lc[1] = 0;
+ vflag = 0;
+
+ uulboundary = -1;
+
+ if (method == YENC_ENCODED) {
+ *state = BEGIN;
+ }
+
+ while (!feof (datain) && *state != DONE &&
+ (ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
+ (!(flags&FL_PROPER) && uu_fast_scanning))) {
+ if (_FP_fgets (line, line_len, datain) == NULL)
+ break;
+
+ if (ferror (datain)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_SOURCE_READ_ERR),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+
+ if (line[0]=='\015' || line[0]=='\012') { /* Empty line? */
+ if (*state == DATA &&
+ (method == UU_ENCODED || method == XX_ENCODED))
+ *state = END;
+
+ /*
+ * if we had a whole block of valid lines before, we reset our
+ * 'valid data' flag, tf. Without this 'if', we'd break decoding
+ * files with interleaved blank lines. The value of 5 is chosen
+ * quite arbitrarly.
+ */
+
+ if (vlc > 5)
+ tf = tc = 0;
+ vlc = 0;
+ continue;
+ }
+
+ /*
+ * Busy Polls
+ */
+
+ if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
+ uustring (S_DECODE_CANCEL));
+ return UURET_CANCEL;
+ }
+
+ /*
+ * try to make sense of data
+ */
+
+ line[255] = '\0'; /* For Safety of string functions */
+ count = 0;
+
+ if (boundary && line[0]=='-' && line[1]=='-' &&
+ strncmp (line+2, boundary, strlen (boundary)) == 0) {
+ if (line[strlen(boundary)+2]=='-')
+ uulboundary = 1;
+ else
+ uulboundary = 0;
+ return UURET_OK;
+ }
+
+ /*
+ * Use this pseudo-handling only if !FL_PROPER
+ */
+
+ if ((flags&FL_PROPER) == 0) {
+ if (strncmp (line, "BEGIN", 5) == 0 &&
+ _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */
+ tc = tf = vlc = 0;
+ continue;
+ }
+ /* MIME body boundary */
+ if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) {
+ if ((haddata || tc) && (haddh || hadct)) {
+ *state = DONE;
+ vlc = 0;
+ lc[0] = lc[1] = 0;
+ continue;
+ }
+ hadct = 0;
+ haddh = 1;
+ continue;
+ }
+ if (_FP_strnicmp (line, "Content-Type", 12) == 0)
+ hadct = 1;
+ }
+
+ if (*state == BEGIN) {
+ if ((method == UU_ENCODED || method == XX_ENCODED) &&
+ (strncmp (line, "begin ", 6) == 0 ||
+ _FP_strnicmp (line, "<pre>begin ", 11) == 0)) { /* for LYNX */
+ *state = DATA;
+ continue;
+ }
+ else if (method == BH_ENCODED && line[0] == ':') {
+ if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
+ bhflag = 0;
+ *state = DATA;
+ }
+ else
+ continue;
+ }
+ else if (method == YENC_ENCODED &&
+ strncmp (line, "=ybegin ", 8) == 0 &&
+ _FP_strstr (line, " name=") != NULL) {
+ *state = DATA;
+
+ if ((ptr = _FP_strstr (line, " size=")) != NULL) {
+ ptr += 6;
+ yefilesize = atoi (ptr);
+ }
+ else {
+ yefilesize = -1;
+ }
+
+ if (_FP_strstr (line, " part=") != NULL) {
+ if (_FP_fgets (line, line_len, datain) == NULL) {
+ break;
+ }
+
+ if ((ptr = _FP_strstr (line, " end=")) == NULL) {
+ break;
+ }
+
+ yepartends = atoi (ptr + 5);
+ }
+ tf = 1;
+ continue;
+ }
+ else {
+ continue;
+ }
+
+ tc = tf = vlc = 0;
+ lc[0] = lc[1] = 0;
+ }
+ else if ((*state == END) &&
+ (method == UU_ENCODED || method == XX_ENCODED)) {
+ if (strncmp (line, "end", 3) == 0) {
+ *state = DONE;
+ break;
+ }
+ }
+
+ if (*state == DATA && method == YENC_ENCODED &&
+ strncmp (line, "=yend ", 6) == 0) {
+ if ((ptr = _FP_strstr (line, " pcrc32=")) != NULL) {
+ crc32_t pcrc32 = strtoul (ptr + 8, NULL, 16);
+ if (pcrc32 != yepartcrc) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno);
+ }
+ }
+ if ((ptr = _FP_strstr (line, " crc32=")) != NULL)
+ {
+ crc32_t fcrc32 = strtoul (ptr + 7, NULL, 16);
+ if (fcrc32 != yefilecrc) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_CRC_MISMATCH), progress.curfile);
+ }
+ }
+ if ((ptr = _FP_strstr (line, " size=")) != NULL)
+ {
+ size_t size = atol(ptr + 6);
+ if (size != yepartsize && yefilesize != -1) {
+ if (size != yefilesize)
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_PSIZE_MISMATCH), progress.curfile,
+ progress.partno, yepartsize, size);
+ else
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_SIZE_MISMATCH), progress.curfile,
+ yepartsize, size);
+ }
+ }
+ if (yepartends == 0 || yepartends >= yefilesize) {
+ *state = DONE;
+ }
+ break;
+ }
+
+ if (*state == DATA || *state == END) {
+ if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
+ break;
+ }
+
+ if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
+ vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);
+
+ /*
+ * correct XX/UUencoded lines that were declared Base64
+ */
+
+ if ((method == XX_ENCODED || method == UU_ENCODED) &&
+ vflag == B64ENCODED) {
+ if (UUValidData (line, method, &bhflag) == method)
+ vflag = method;
+ }
+
+ if (vflag == method) {
+ if (tf) {
+ count = UUDecodeLine (line, oline, method);
+ if (method == YENC_ENCODED) {
+ if (yepartends)
+ yepartcrc = crc32(yepartcrc, (unsigned char*)oline, count);
+ yefilecrc = crc32(yefilecrc, (unsigned char*)oline, count);
+ yepartsize += count;
+ }
+ vlc++; lc[1]++;
+ }
+ else if (tc == 3) {
+ count = UUDecodeLine (save[0], oline, method);
+ count += UUDecodeLine (save[1], oline + count, method);
+ count += UUDecodeLine (save[2], oline + count, method);
+ count += UUDecodeLine (line, oline + count, method);
+ tf = 1;
+ tc = 0;
+
+ /*
+ * complain if we had one or two invalid lines amidst of
+ * correctly encoded data. This usually means that the
+ * file is in error
+ */
+
+ if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_DATA_SUSPICIOUS));
+ warning=1;
+ }
+ lc[0] = 0;
+ lc[1] = 3;
+ }
+ else {
+ _FP_strncpy (save[tc++], line, 256);
+ }
+
+ if (method == UU_ENCODED)
+ *state = (line[0] == 'M') ? DATA : END;
+ else if (method == XX_ENCODED)
+ *state = (line[0] == 'h') ? DATA : END;
+ else if (method == B64ENCODED)
+ *state = (strchr (line, '=') == NULL) ? DATA : DONE;
+ else if (method == BH_ENCODED)
+ *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
+ }
+ else {
+ vlc = tf = tc = 0;
+ haddh = 0;
+ lc[0]++;
+ }
+ }
+ else if (*state != DONE) {
+ return UURET_NOEND;
+ }
+
+ if (count) {
+ if (method == BH_ENCODED) {
+ if (UUbhwrite (oline, 1, count, dataout) != count) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TEMP),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+ }
+ else if (fwrite (oline, 1, count, dataout) != count) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TEMP),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+ haddata++;
+ count = 0;
+ }
+ }
+
+ if (*state == DONE ||
+ (*state == DATA && method == B64ENCODED &&
+ vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
+ for (tf=0; tf<tc; tf++)
+ count += UUDecodeLine (save[tf], oline + count, method);
+ if (count) {
+ if (method == BH_ENCODED) {
+ if (UUbhwrite (oline, 1, count, dataout) != count) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TEMP),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+ }
+ else if (fwrite (oline, 1, count, dataout) != count) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TEMP),
+ strerror (uu_errno = errno));
+ return UURET_IOERR;
+ }
+ }
+ }
+ return UURET_OK;
+}
+
+/*
+ * this function decodes the file into a temporary file
+ */
+
+int
+UUDecode (uulist *data)
+{
+ int state=BEGIN, part=-1, res=0, hb;
+ long rsize, dsize, numbytes;
+ FILE *datain, *dataout;
+ unsigned char r[8];
+ char *mode, *ntmp, *template;
+ uufile *iter;
+ size_t bytes;
+ int fd;
+
+ if (data == NULL || data->thisfile == NULL)
+ return UURET_ILLVAL;
+
+ if (data->state & UUFILE_TMPFILE)
+ return UURET_OK;
+
+ if (data->state & UUFILE_NODATA)
+ return UURET_NODATA;
+
+ if (data->state & UUFILE_NOBEGIN) {
+ if (!uu_desperate)
+ return UURET_NODATA;
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring(S_DATA_SUSPICIOUS));
+ }
+
+ if (data->uudet == PT_ENCODED)
+ mode = "wt"; /* open text files in text mode */
+ else
+ mode = "wb"; /* otherwise in binary */
+
+
+ template = g_build_filename (g_get_tmp_dir(), "uuXXXXXX", NULL);
+ data->binfile = strdup (template);
+ fd = g_mkstemp (data->binfile);
+ g_free (template);
+
+ if (fd == -1) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NO_TEMP_NAME));
+ _FP_free (data->binfile);
+ data->binfile = NULL;
+ uu_errno = errno;
+ return UURET_NOMEM;
+ }
+
+ if ((dataout = fdopen (fd, mode)) == NULL) {
+ /*
+ * we couldn't create a temporary file. Usually this means that TMP
+ * and TEMP aren't set
+ */
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TARGET),
+ data->binfile, strerror (uu_errno = errno));
+ _FP_free (data->binfile);
+ data->binfile = NULL;
+ uu_errno = errno;
+ return UURET_IOERR;
+ }
+ /*
+ * we don't have begin lines in Base64 or plain text files.
+ */
+ if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
+ data->uudet == PT_ENCODED)
+ state = DATA;
+
+ /*
+ * If we know that the file does not have a begin, we simulate
+ * it in desperate mode
+ */
+
+ if ((data->state & UUFILE_NOBEGIN) && uu_desperate) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, uustring(S_DATA_SUSPICIOUS));
+ state = DATA;
+ }
+
+ (void) UUDecodeLine (NULL, NULL, 0); /* init */
+ (void) UUbhwrite (NULL, 0, 0, NULL); /* dito */
+ (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep */
+
+ /*
+ * initialize progress information
+ */
+ progress.action = 0;
+ if (data->filename != NULL) {
+ _FP_strncpy (progress.curfile,
+ (strlen(data->filename)>2047)?
+ (data->filename+strlen(data->filename)-2047):data->filename,
+ 2048);
+ }
+ else {
+ _FP_strncpy (progress.curfile,
+ (strlen(data->binfile)>2047)?
+ (data->binfile+strlen(data->binfile)-2047):data->binfile,
+ 2048);
+ }
+ progress.partno = 0;
+ progress.numparts = 0;
+ progress.fsize = -1;
+ progress.percent = 0;
+ progress.action = UUACT_DECODING;
+
+ iter = data->thisfile;
+ while (iter) {
+ progress.numparts = (iter->partno)?iter->partno:1;
+ iter = iter->NEXT;
+ }
+
+ /*
+ * let's rock!
+ */
+
+ iter = data->thisfile;
+ while (iter) {
+
+ if (part==-1 && iter->partno!=1)
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, "Missing everything before part #%d", iter->partno);
+ if (part!=-1 && iter->partno!=part+1) {
+ if (!uu_desperate)
+ break;
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring(S_PART_MISSING), part);
+ }
+ part = iter->partno;
+
+ if (iter->data->sfname == NULL) {
+ iter = iter->NEXT;
+ continue;
+ }
+
+ /*
+ * call our FileCallback to retrieve the file
+ */
+
+ if (uu_FileCallback) {
+ if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
+ uugen_fnbuffer, 1)) != UURET_OK)
+ break;
+ if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
+ (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
+ uugen_fnbuffer, 0);
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ uugen_fnbuffer, strerror (uu_errno = errno));
+ res = UURET_IOERR;
+ break;
+ }
+ }
+ else {
+ if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ iter->data->sfname, strerror (uu_errno = errno));
+ res = UURET_IOERR;
+ break;
+ }
+ _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
+ }
+
+ progress.partno = part;
+ progress.fsize = (iter->data->length)?iter->data->length:-1;
+ progress.percent = 0;
+ progress.foffset = iter->data->startpos;
+
+ fseek (datain, iter->data->startpos, SEEK_SET);
+ res = UUDecodePart (datain, dataout, &state,
+ iter->data->startpos+iter->data->length,
+ data->uudet, iter->data->flags, NULL);
+ fclose (datain);
+
+ if (uu_FileCallback)
+ (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);
+
+ if (state == DONE || res != UURET_OK)
+ break;
+
+ iter = iter->NEXT;
+ }
+
+ if (state == DATA &&
+ (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
+ data->uudet == PT_ENCODED))
+ state = DONE; /* assume we're done */
+
+ if (fclose (dataout)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TEMP),
+ strerror (uu_errno = errno));
+ res = UURET_IOERR;
+ }
+
+ if (res != UURET_OK || (state != DONE && !uu_desperate)) {
+ unlink (data->binfile);
+ _FP_free (data->binfile);
+ data->binfile = NULL;
+ data->state &= ~UUFILE_TMPFILE;
+ data->state |= UUFILE_ERROR;
+
+ if (res == UURET_OK && state != DONE)
+ res = UURET_NOEND;
+ }
+ else if (res != UURET_OK) {
+ data->state &= ~UUFILE_DECODED;
+ data->state |= UUFILE_ERROR | UUFILE_TMPFILE;
+ }
+ else {
+ data->state &= ~UUFILE_ERROR;
+ data->state |= UUFILE_TMPFILE;
+ }
+
+ /*
+ * If this was a BinHex file, we must extract its data or resource fork
+ */
+
+ if (data->uudet == BH_ENCODED && data->binfile)
+ {
+ char * template = g_build_filename (g_get_tmp_dir(), "uuXXXXXX", NULL);
+ ntmp = strdup (template);
+ fd = g_mkstemp (ntmp);
+ g_free (template);
+
+ if (fd == -1) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NO_TEMP_NAME));
+ progress.action = 0;
+ free (ntmp);
+ return UURET_NOMEM;
+ }
+ if ((datain = fdopen (fd, "rb")) == NULL) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_FILE),
+ data->binfile, strerror (uu_errno = errno));
+ progress.action = 0;
+ free (ntmp);
+ return UURET_IOERR;
+ }
+ if ((dataout = fopen (ntmp, "wb")) == NULL) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_NOT_OPEN_TARGET),
+ ntmp, strerror (uu_errno = errno));
+ progress.action = 0;
+ fclose (datain);
+ free (ntmp);
+ return UURET_IOERR;
+ }
+ /*
+ * read fork lengths. remember they're in Motorola format
+ */
+ r[0] = fgetc (datain);
+ hb = (int) r[0] + 22;
+ fseek (datain, (int) r[0] + 12, SEEK_SET);
+ fread (r, 1, 8, datain);
+
+ dsize = (((long) 1 << 24) * (long) r[0]) +
+ (((long) 1 << 16) * (long) r[1]) +
+ (((long) 1 << 8) * (long) r[2]) +
+ ( (long) r[3]);
+ rsize = (((long) 1 << 24) * (long) r[4]) +
+ (((long) 1 << 16) * (long) r[5]) +
+ (((long) 1 << 8) * (long) r[6]) +
+ ( (long) r[7]);
+
+ UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
+ uustring (S_BINHEX_SIZES),
+ dsize, rsize);
+
+ if (dsize == 0) {
+ fseek (datain, dsize + hb + 2, SEEK_SET);
+ numbytes = rsize;
+ }
+ else if (rsize == 0) {
+ fseek (datain, hb, SEEK_SET);
+ numbytes = dsize;
+ }
+ else {
+ /* we should let the user have the choice here */
+ UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
+ uustring (S_BINHEX_BOTH));
+ fseek (datain, hb, SEEK_SET);
+ numbytes = dsize;
+ }
+
+ progress.action = 0;
+ progress.partno = 0;
+ progress.numparts = 1;
+ progress.fsize = (numbytes)?numbytes:-1;
+ progress.foffset = hb;
+ progress.percent = 0;
+ progress.action = UUACT_COPYING;
+
+ /*
+ * copy the chosen fork
+ */
+
+ while (!feof (datain) && numbytes) {
+ if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
+ uustring (S_DECODE_CANCEL));
+ fclose (datain);
+ fclose (dataout);
+ unlink (ntmp);
+ free (ntmp);
+ return UURET_CANCEL;
+ }
+
+ bytes = fread (uugen_inbuffer, 1,
+ (size_t) ((numbytes>1024)?1024:numbytes), datain);
+
+ if (ferror (datain) || (bytes == 0 && !feof (datain))) {
+ progress.action = 0;
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_SOURCE_READ_ERR),
+ data->binfile, strerror (uu_errno = errno));
+ fclose (datain);
+ fclose (dataout);
+ unlink (ntmp);
+ free (ntmp);
+ return UURET_IOERR;
+ }
+ if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
+ progress.action = 0;
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TARGET),
+ ntmp, strerror (uu_errno = errno));
+ fclose (datain);
+ fclose (dataout);
+ unlink (ntmp);
+ free (ntmp);
+ return UURET_IOERR;
+ }
+ numbytes -= bytes;
+ }
+
+ if (numbytes) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_SHORT_BINHEX),
+ (data->filename)?data->filename:
+ (data->subfname)?data->subfname:"???",
+ numbytes);
+ }
+
+ /*
+ * replace temp file
+ */
+
+ fclose (datain);
+ if (fclose (dataout)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
+ uustring (S_WR_ERR_TARGET),
+ ntmp, strerror (uu_errno = errno));
+ unlink (ntmp);
+ free (ntmp);
+ return UURET_IOERR;
+ }
+
+ if (unlink (data->binfile)) {
+ UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
+ uustring (S_TMP_NOT_REMOVED),
+ data->binfile, strerror (uu_errno = errno));
+ }
+
+ free (data->binfile);
+ data->binfile = ntmp;
+ }
+
+ progress.action = 0;
+ return res;
+}
+
+/*
+ * QuickDecode for proper MIME attachments. We expect the pointer to
+ * be on the first header line.
+ */
+
+int
+UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
+{
+ int state=BEGIN, encoding=-1;
+ headers myenv;
+
+ /*
+ * Read header and find out about encoding.
+ */
+
+ memset (&myenv, 0, sizeof (headers));
+ UUScanHeader (datain, &myenv);
+
+ if (_FP_stristr (myenv.ctenc, "uu") != NULL)
+ encoding = UU_ENCODED;
+ else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
+ encoding = XX_ENCODED;
+ else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
+ encoding = B64ENCODED;
+ else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
+ encoding = QP_ENCODED;
+ else
+ encoding = PT_ENCODED;
+
+ UUkillheaders (&myenv);
+
+ /*
+ * okay, so decode this one
+ */
+
+ (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init */
+ return UUDecodePart (datain, dataout, &state, maxpos,
+ encoding, FL_PROPER|FL_TOEND,
+ boundary);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]