Import Debian changes 0.7.1-5 debian/0.7.1-5
authorRichard Atterer <atterer@debian.org>
Sat, 31 Jul 2004 15:09:30 +0000 (17:09 +0200)
committerSteve McIntyre <steve@einval.com>
Thu, 24 Oct 2019 10:34:58 +0000 (11:34 +0100)
jigdo (0.7.1-5) unstable; urgency=low

  * Added build-depends on GCC 3.4, use it for compilation
    Closes: #221375: jigdo should be compiled with g++-3.3 to undergo
    c102 transition.

jigdo (0.7.1-4) unstable; urgency=low

  * jigdo-file: Bugfix for the code which deduces missing --image/
    --jigdo/--template arguments. Broken in 0.7.1, would deduce
    /x.iso.template from /x.iso, instead of /x.template (Adrian Bunk)
    Closes: #257646: output file name changes broke scripts

jigdo (0.7.1-3) unstable; urgency=low

  * jigdo-lite: Fixed regular expressions so they work with sed 4.1
    Closes: #256331: Problem with recent unstable dvd images

jigdo (0.7.1-2) unstable; urgency=low

  * Fix for a build error on 64 bit architectures
  * Accidentally built 0.7.1-1 as a native package

jigdo (0.7.1-1) unstable; urgency=low

  * New upstream release
  * Fixes segfaults due to big local vars on stack, closes: #192275
  * jigdo-lite: Fix interpretation of jigdo-file return code,
    closes: #205740
  * Upstream release includes workaround which enables DVD (>4GB file)
    creation even if compiled with GCC 3.0 to 3.4, closes: #248489
  * Bugfix for "jigdo-file make-image": Failed assertion
    `nextAlignedOff>off' and huge .template with >4GB image,
    closes: #223786

jigdo (0.7.0-2) unstable; urgency=low

  * Fix for a build error on 64 bit architectures
  * Including upstream changelog in jigdo binary package

jigdo (0.7.0-1) unstable; urgency=low

  * New upstream release
  * First release of a BETA version of the jigdo GTK+ GUI in Debian
  * jigdo-lite: Fix for problem with the "read" builtin with some
    shells, e.g. dash; closes: #183691

jigdo (0.6.9-2) unstable; urgency=low

  * Fixed build errors with new versions of GCC 3.2, closes: #178195

jigdo (0.6.9-1) unstable; urgency=low

  * New upstream release
  * jigdo-lite: When temporary dir is already present, scan its
    contents *before* downloading the first batch of files,
    closes: #153643
  * jigdo-file: Prevent infinite loop if I/O error occurs during
    scanning of files, closes: #153947
  * jigdo-lite: Use a separate temporary dir for each new download.
    This allows you to run several jigdo-lite instances in the same
    dir at the same time, closes: #154338
  * Improved handling of invalid cache files (created if disc gets
    full during cache update): Instead of crashing, jigdo-file prints
    an error. However, libdb still corrupts the cache file,
    closes: #163721
  * jigdo-lite supports a --scan command line option to avoid the
    "Files to scan" question, closes: #176947
  * Conflicts: jigdo (<< 0.6.9) because of jigdo.mo in both packages,
    just to allow for smooth upgrade for people using my unofficial
    jigdo package.
  * Added the Debian jigdo mini-HOWTO to the doc directory

jigdo (0.6.8-1) unstable; urgency=low

  * New upstream release
  * jigdo-lite/mirror use "jigdo-file --no-cache" when reading
    downloaded files from tmp dir, closes: #150973

jigdo (0.6.7-1) unstable; urgency=low

  * New upstream release
  * Fixed in 0.6.6: [Image] sections in jigdo files now include
    checksum of template data, closes: #141418
  * Relative URLs allowed; fixes #149885, but leaving bug open and
    tagged "woody".

14 files changed:
1  2 
config.log
debian/changelog
debian/control
debian/copyright
debian/jigdo-file.doc-base
debian/jigdo-file.docs
debian/jigdo.docs
debian/rules
scripts/jigdo-lite
src/jigdo-file.cc
src/job/datasource.hh
src/job/jigdo-io.cc
src/job/jigdo-io.hh
src/job/jigdodownload.hh

diff --cc config.log
index 0000000,0000000..4558a55
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,200 @@@
++This file contains any messages produced by compilers while
++running configure, to aid debugging if configure makes a mistake.
++
++It was created by configure, which was
++generated by GNU Autoconf 2.59.  Invocation command line was
++
++  $ ./configure --prefix=/usr --with-gui --enable-nls --mandir=${prefix}/share/man --infodir=${prefix}/share/info
++
++## --------- ##
++## Platform. ##
++## --------- ##
++
++hostname = nenya
++uname -m = i686
++uname -r = 2.4.26
++uname -s = Linux
++uname -v = #1 Mon May 24 14:40:27 CEST 2004
++
++/usr/bin/uname -p = unknown
++/bin/uname -X     = unknown
++
++/bin/arch              = i686
++/usr/bin/arch -k       = unknown
++/usr/convex/getsysinfo = unknown
++hostinfo               = unknown
++/bin/machine           = unknown
++/usr/bin/oslevel       = unknown
++/bin/universe          = unknown
++
++PATH: /home/richard/bin
++PATH: /root/bin
++PATH: /usr/local/bin
++PATH: /usr/bin
++PATH: /bin
++PATH: /usr/bin/X11
++PATH: /usr/games
++PATH: /sbin
++PATH: /usr/sbin
++
++
++## ----------- ##
++## Core tests. ##
++## ----------- ##
++
++configure:1356: checking for gawk
++configure:1372: found /usr/bin/gawk
++configure:1382: result: gawk
++configure:1444: checking for gcc
++configure:1470: result: gcc-3.4
++configure:1714: checking for C compiler version
++configure:1717: gcc-3.4 --version </dev/null >&5
++/usr/local/bin/gcc: No such file or directory
++configure:1720: $? = 1
++configure:1722: gcc-3.4 -v </dev/null >&5
++/usr/local/bin/gcc: No such file or directory
++configure:1725: $? = 1
++configure:1727: gcc-3.4 -V </dev/null >&5
++/usr/local/bin/gcc: No such file or directory
++configure:1730: $? = 1
++configure:1753: checking for C compiler default output file name
++configure:1756: gcc-3.4    conftest.c  >&5
++/usr/local/bin/gcc: No such file or directory
++configure:1759: $? = 1
++configure: failed program was:
++| /* confdefs.h.  */
++| 
++| #define PACKAGE_NAME ""
++| #define PACKAGE_TARNAME ""
++| #define PACKAGE_VERSION ""
++| #define PACKAGE_STRING ""
++| #define PACKAGE_BUGREPORT ""
++| #define JIGDO_VERSION "0.7.1"
++| /* end confdefs.h.  */
++| 
++| int
++| main ()
++| {
++| 
++|   ;
++|   return 0;
++| }
++configure:1798: error: C compiler cannot create executables
++See `config.log' for more details.
++
++## ---------------- ##
++## Cache variables. ##
++## ---------------- ##
++
++ac_cv_env_CC_set=set
++ac_cv_env_CC_value=gcc-3.4
++ac_cv_env_CFLAGS_set=
++ac_cv_env_CFLAGS_value=
++ac_cv_env_CPPFLAGS_set=
++ac_cv_env_CPPFLAGS_value=
++ac_cv_env_CXXCPP_set=
++ac_cv_env_CXXCPP_value=
++ac_cv_env_CXXFLAGS_set=
++ac_cv_env_CXXFLAGS_value=
++ac_cv_env_CXX_set=set
++ac_cv_env_CXX_value=g++-3.4
++ac_cv_env_LDFLAGS_set=
++ac_cv_env_LDFLAGS_value=
++ac_cv_env_build_alias_set=
++ac_cv_env_build_alias_value=
++ac_cv_env_host_alias_set=
++ac_cv_env_host_alias_value=
++ac_cv_env_target_alias_set=
++ac_cv_env_target_alias_value=
++ac_cv_prog_AWK=gawk
++ac_cv_prog_ac_ct_CC=gcc-3.4
++
++## ----------------- ##
++## Output variables. ##
++## ----------------- ##
++
++AWK='gawk'
++CATALOGS=''
++CC='gcc-3.4'
++CFLAGS=''
++CPPFLAGS=''
++CXX='g++-3.4'
++CXXCPP=''
++CXXFLAGS=''
++DEFS=''
++ECHO_C=''
++ECHO_N='-n'
++ECHO_T=''
++EGREP=''
++EXEEXT=''
++GTKCFLAGS=''
++GTKLIBS=''
++IF_DEBUG=''
++IF_GUI=''
++IF_GXX2=''
++IF_LIBWWW_HACKS=''
++IF_NODEBUG=''
++IF_NOGXX2=''
++IF_UNIX=''
++IF_WINDOWS=''
++INSTALL_DATA=''
++INSTALL_PROGRAM=''
++INSTALL_SCRIPT=''
++JIGDO_VERSION='0.7.1'
++LDFLAGS=''
++LIBOBJS=''
++LIBS=''
++LIBWWWCFLAGS=''
++LIBWWWLIBS=''
++LTLIBOBJS=''
++OBJEXT=''
++PACKAGE_BUGREPORT=''
++PACKAGE_NAME=''
++PACKAGE_STRING=''
++PACKAGE_TARNAME=''
++PACKAGE_VERSION=''
++PATH_SEPARATOR=':'
++PKGCONFIG=''
++SHELL='/bin/sh'
++USE_NLS=''
++ac_ct_CC='gcc-3.4'
++ac_ct_CXX=''
++bindir='${exec_prefix}/bin'
++build_alias=''
++datadir='${prefix}/share'
++exe=''
++exec_prefix='NONE'
++have_wget=''
++host_alias=''
++includedir='${prefix}/include'
++infodir='${prefix}/share/info'
++libdir='${exec_prefix}/lib'
++libexecdir='${exec_prefix}/libexec'
++localstatedir='${prefix}/var'
++mandir='${prefix}/share/man'
++oldincludedir='/usr/include'
++prefix='/usr'
++program_transform_name='s,x,x,'
++sbindir='${exec_prefix}/sbin'
++sharedstatedir='${prefix}/com'
++sysconfdir='${prefix}/etc'
++target_alias=''
++
++## ------------- ##
++## Output files. ##
++## ------------- ##
++
++SRC_MAKEDEPS=''
++
++## ----------- ##
++## confdefs.h. ##
++## ----------- ##
++
++#define JIGDO_VERSION "0.7.1"
++#define PACKAGE_BUGREPORT ""
++#define PACKAGE_NAME ""
++#define PACKAGE_STRING ""
++#define PACKAGE_TARNAME ""
++#define PACKAGE_VERSION ""
++
++configure: exit 77
index 5d8c9ce,0000000..4fad1e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,141 @@@
- jigdo (0.6.5-2) stable; urgency=low
++jigdo (0.7.1-5) unstable; urgency=low
 +
-   * Backported some changes from 0.6.8 to stable:
-   * Relative template URLs allowed, closes: #149885
++  * Added build-depends on GCC 3.4, use it for compilation
++    Closes: #221375: jigdo should be compiled with g++-3.3 to undergo
++    c102 transition.
++
++ -- Richard Atterer <atterer@debian.org>  Sat, 31 Jul 2004 17:09:30 +0200
++
++jigdo (0.7.1-4) unstable; urgency=low
++
++  * jigdo-file: Bugfix for the code which deduces missing --image/
++    --jigdo/--template arguments. Broken in 0.7.1, would deduce
++    /x.iso.template from /x.iso, instead of /x.template (Adrian Bunk)
++    Closes: #257646: output file name changes broke scripts
++
++ -- Richard Atterer <atterer@debian.org>  Mon,  5 Jul 2004 15:45:21 +0200
++
++jigdo (0.7.1-3) unstable; urgency=low
++
++  * jigdo-lite: Fixed regular expressions so they work with sed 4.1
++    Closes: #256331: Problem with recent unstable dvd images
++
++ --  <atterer@debian.org>  Sat, 26 Jun 2004 13:17:38 +0200
++
++jigdo (0.7.1-2) unstable; urgency=low
++
++  * Fix for a build error on 64 bit architectures
++  * Accidentally built 0.7.1-1 as a native package
++
++ --  <atterer@debian.org>  Thu, 24 Jun 2004 12:23:32 +0200
++
++jigdo (0.7.1-1) unstable; urgency=low
++
++  * New upstream release 
++  * Fixes segfaults due to big local vars on stack, closes: #192275
++  * jigdo-lite: Fix interpretation of jigdo-file return code,
++    closes: #205740
++  * Upstream release includes workaround which enables DVD (>4GB file)
++    creation even if compiled with GCC 3.0 to 3.4, closes: #248489
++  * Bugfix for "jigdo-file make-image": Failed assertion
++    `nextAlignedOff>off' and huge .template with >4GB image,
++    closes: #223786
++
++ -- Richard Atterer <atterer@debian.org>  Wed, 23 Jun 2004 15:26:36 +0200
++
++jigdo (0.7.0-2) unstable; urgency=low
++
++  * Fix for a build error on 64 bit architectures
++  * Including upstream changelog in jigdo binary package
++
++ -- Richard Atterer <atterer@debian.org>  Tue,  6 May 2003 21:12:41 +0200
++
++jigdo (0.7.0-1) unstable; urgency=low
++
++  * New upstream release
++  * First release of a BETA version of the jigdo GTK+ GUI in Debian
++  * jigdo-lite: Fix for problem with the "read" builtin with some
++    shells, e.g. dash; closes: #183691
++
++ -- Richard Atterer <atterer@debian.org>  Fri,  2 May 2003 17:28:28 +0200
++
++jigdo (0.6.9-2) unstable; urgency=low
++
++  * Fixed build errors with new versions of GCC 3.2, closes: #178195
++
++ -- Richard Atterer <atterer@debian.org>  Sat, 25 Jan 2003 00:10:32 +0100
++
++jigdo (0.6.9-1) unstable; urgency=low
++
++  * New upstream release
++  * jigdo-lite: When temporary dir is already present, scan its
++    contents *before* downloading the first batch of files,
++    closes: #153643
++  * jigdo-file: Prevent infinite loop if I/O error occurs during
++    scanning of files, closes: #153947
++  * jigdo-lite: Use a separate temporary dir for each new download. 
++    This allows you to run several jigdo-lite instances in the same
++    dir at the same time, closes: #154338
++  * Improved handling of invalid cache files (created if disc gets
++    full during cache update): Instead of crashing, jigdo-file prints
++    an error. However, libdb still corrupts the cache file,
++    closes: #163721
++  * jigdo-lite supports a --scan command line option to avoid the
++    "Files to scan" question, closes: #176947
++  * Conflicts: jigdo (<< 0.6.9) because of jigdo.mo in both packages,
++    just to allow for smooth upgrade for people using my unofficial
++    jigdo package.
++  * Added the Debian jigdo mini-HOWTO to the doc directory
++
++ -- Richard Atterer <atterer@debian.org>  Thu, 26 Dec 2002 18:02:28 +0100
++
++jigdo (0.6.8-1) unstable; urgency=low
++
++  * New upstream release
 +  * jigdo-lite/mirror use "jigdo-file --no-cache" when reading
 +    downloaded files from tmp dir, closes: #150973
 +
-  -- Richard Atterer <atterer@debian.org>  Thu, 19 Dec 2002 15:44:31 +0100
++ -- Richard Atterer <atterer@debian.org>  Fri, 28 Jun 2002 23:04:47 +0200
++
++jigdo (0.6.7-1) unstable; urgency=low
++
++  * New upstream release
++  * Fixed in 0.6.6: [Image] sections in jigdo files now include
++    checksum of template data, closes: #141418
++  * Relative URLs allowed; fixes #149885, but leaving bug open and
++    tagged "woody".
++
++ -- Richard Atterer <atterer@debian.org>  Thu, 13 Jun 2002 22:07:15 +0200
 +
 +jigdo (0.6.5-1) unstable; urgency=medium
 +
 +  * New upstream release
 +
 + -- Richard Atterer <atterer@debian.org>  Wed, 17 Apr 2002 15:12:01 +0200
 +
 +jigdo (0.6.4-1) unstable; urgency=medium
 +
 +  * New upstream release
 +
 + -- Richard Atterer <atterer@debian.org>  Fri,  1 Mar 2002 23:52:44 +0100
 +
 +jigdo (0.6.3-1) unstable; urgency=medium
 +
 +  * New upstream release
 +  * Fixes build problems on 64-bit machines, closes: #133533
 +
 + -- Richard Atterer <atterer@debian.org>  Sat, 23 Feb 2002 22:08:17 +0100
 +
 +jigdo (0.6.2-2) unstable; urgency=medium
 +
 +  * Unversioned dependency on wget, to allow wget-ssl to be used
 +    instead of wget. Closes: #132903, #133008
 +
 + -- Richard Atterer <atterer@debian.org>  Sat,  9 Feb 2002 18:25:22 +0100
 +
 +jigdo (0.6.2-1) unstable; urgency=low
 +
 +  * Initial Release.
 +
 + -- Richard Atterer <atterer@debian.org>  Mon,  4 Feb 2002 17:54:16 +0100
 +
diff --cc debian/control
index dc481f2,0000000..0bccb80
mode 100644,000000..100644
--- /dev/null
@@@ -1,29 -1,0 +1,47 @@@
- Build-Depends: debhelper (>= 2.0.86), zlib1g-dev, libdb3-dev
 +Source: jigdo
 +Section: utils
 +Priority: extra
 +Maintainer: Richard Atterer <atterer@debian.org>
++Build-Depends: gcc-3.4, g++-3.4, debhelper (>= 2.0.86), zlib1g-dev, libdb4.2-dev, libgtk2.0-dev (>= 2.0.6), libwww-dev (>= 5.4.0)
 +Standards-Version: 3.5.6
 +
++Package: jigdo
++Architecture: any
++Depends: ${shlibs:Depends}
++Suggests: jigdo-file
++Description: GTK+ download manager
++ This is a BETA version of the jigdo GTK+ download manager. In
++ particular, it is NOT yet capable of processing .jigdo files - use
++ jigdo-lite from the jigdo-file package for that!
++ .
++ This download manager features FTP and HTTP 1.1 pipelining support,
++ pausing, continuing and resuming of downloads, and automatic guessing
++ of your proxy configuration.
++ .
++ jigdo homepage: <http://atterer.net/jigdo/>
++
 +Package: jigdo-file
 +Architecture: any
 +Depends: wget, ${shlibs:Depends}
++Conflicts: jigdo (<< 0.6.9)
 +Description: Download Debian CD images from any Debian mirror
 + Using the jigdo-lite script contained in this package, you can use
 + your nearest "regular" Debian mirror to download Debian CD images,
 + instead of having to use one of the few, slow, overloaded mirrors
 + that offer the images as direct HTTP or FTP downloads. See
 + <http://www.debian.org/CD/jigdo-cd/> for details.
 + .
 + Jigsaw Download, or short jigdo, is a scheme developed primarily to
 + make it easy to distribute huge filesystem images (e.g. CD (ISO9660)
 + or DVD (UDF) images) over the internet, but it could also be used for
 + other data which is awkward to handle due to its size, like
 + audio/video files or large software packages.
 + .
 + jigdo tries to ensure that the large file is downloaded in small
 + parts which can be stored on different servers. People who want to
 + download the image do so by telling the jigdo download tool to
 + process one ".jigdo" file; using it, jigdo downloads the parts and
 + reassembles the image. jigdo-file is used to prepare the files for
 + download.
++ .
++ jigdo homepage: <http://atterer.net/jigdo/>
index f7c6b59,0000000..d6d2fb3
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,35 @@@
- Copyright (C) 2001-2002 Richard Atterer <richard@atterer.net>
++
++This package was debianized by Richard Atterer.
++It was downloaded from <http://atterer.net/jigdo/>
++
++
++Copyright (C) 2001-2004 Richard Atterer <richard at atterer.net>
 +
 +  This program is free software; you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License, version 2, as
 +  published by the Free Software Foundation.
 +
 +  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.
 +
++  In addition, as a special exception, Richard Atterer gives
++  permission to link the jigdo code with the OpenSSL project's
++  "OpenSSL" library (or with modified versions of it that use the same
++  license as the "OpenSSL" library), and to distribute the linked
++  executables. You must obey the GNU General Public License in all
++  respects for all of the code used other than "OpenSSL". If you
++  modify any jigdo source file, you may extend this exception to your
++  version of the file, but you are not obliged to do so. If you do not
++  wish to do so, delete this exception statement from your version.
++
 +Please note: The copyright notice in the file COPYING only applies to
 +the text of the GNU General Public License; the copyright of the
 +individual source files is as specified at the top of each file and
 +above. Also note that the code is licensed under GPL _version_2_ and
 +no other version. Special licensing for my (RA's) code is available on
 +request.
 +
 +On Debian GNU/Linux systems, the complete text of the GNU General
 +Public License can be found in `/usr/share/common-licenses/GPL'.
index 0000000,0000000..56a96aa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,12 @@@
++Document: jigdo-mini-howto
++Title: Debian Jigdo mini-HOWTO
++Abstract: jigdo-lite (in the jigdo-file package) is a tool for
++ downloading Debian CD images from any "regular" Debian package mirror
++ instead of one of the few and slow CD mirrors. This HOWTO explains
++ how to use the program for downloading images or updating existing
++ images to the latest version.
++Section: Apps/Net
++
++Format: HTML
++Index: /usr/share/doc/jigdo-file/debian-jigdo-mini-howto.html
++Files: /usr/share/doc/jigdo-file/debian-jigdo-mini-howto.html
index 6d10dce,0000000..f7577fd
mode 100644,000000..100644
--- /dev/null
@@@ -1,1 -1,0 +1,4 @@@
++THANKS
 +changelog
++doc/TechDetails.txt
++doc/debian-jigdo-mini-howto.html
index 0000000,0000000..49b2949
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++THANKS
++changelog
diff --cc debian/rules
index 0816f6d,0000000..9749ddd
mode 100755,000000..100755
--- /dev/null
@@@ -1,60 -1,0 +1,64 @@@
-       ./configure --prefix=/usr --disable-nls --without-gui \
 +#!/usr/bin/make -f
 +
 +# Uncomment this to turn on verbose mode.
 +#export DH_VERBOSE=1
 +
 +# This is the debhelper compatability version to use.
 +export DH_COMPAT=2
 +
 +configure: configure-stamp
 +configure-stamp:
 +      dh_testdir
++      CC=gcc-3.4 CXX=g++-3.4 \
++          ./configure --prefix=/usr --with-gui --enable-nls \
 +          --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
 +      touch configure-stamp
 +
 +build: configure-stamp build-stamp
 +build-stamp:
 +      dh_testdir
 +      $(MAKE)
++      $(MAKE) -C src test || true
 +      touch build-stamp
 +
-       $(MAKE) DESTDIR=debian/jigdo-file install
 +clean:
 +      dh_testdir
 +      dh_testroot
 +      rm -f build-stamp configure-stamp
 +      -$(MAKE) distclean
 +      dh_clean
 +
 +install: build
 +      dh_testdir
 +      dh_testroot
 +      dh_clean -k
-       dh_undocumented
++      $(MAKE) DESTDIR=debian/jigdo install-jigdo
++      $(MAKE) DESTDIR=debian/jigdo-file install-po \
++          install-jigdo-file install-jigdo-lite install-jigdo-mirror
++      ln -sf "../common-licenses/GPL-2" \
++          "debian/jigdo/usr/share/jigdo/COPYING"
 +
 +# Build architecture-independent files here.
 +binary-indep: build install
 +# We have nothing to do by default.
 +
 +# Build architecture-dependent files here.
 +binary-arch: build install
 +      dh_testdir
 +      dh_testroot
 +      dh_installdocs
 +      dh_installexamples
 +      dh_installmenu
 +      dh_installchangelogs 
 +      dh_link
 +      dh_strip
 +      dh_compress
 +      dh_fixperms
 +      dh_installdeb
 +      dh_shlibdeps
 +      dh_gencontrol
 +      dh_md5sums
 +      dh_builddeb
 +
 +binary: binary-indep binary-arch
 +.PHONY: build clean binary-indep binary-arch binary install configure
index 3c4f6c4,bda90ba..e30b582
mode 100644,100755..100755
@@@ -82,36 -107,58 +107,58 @@@ input() 
  # has been read and a non-[Image] section follows. This is not
  # correct, but speeds things up a lot because in many cases the large
  # [Parts] section does not have to be scanned.
- selectImage() {
-     imageSel="$1"
-     imageCount=0
-     section=""
-     while read REPLY; do
-         set -- `echo "$REPLY" | sed -e 's/^ *\[ *\([^ ]*\) *\] *$/[\1]/; s/ *= */ /; s/['\''"$]//g'`
-         case "$1" in
-             "["*"]")
-                 printImageInfo "$imageSel" || return
-                 unset section image templateURI shortInfo info
-                 test "$1" != "[Image]" -a "$imageCount" -gt 0 && return
-                 section="$1";;
-             Filename) image="$2";;
-             Template) templateURI="$2";;
-             ShortInfo) shift; shortInfo="$*";;
-             Info) shift; info="$*";;
-         esac
-     done <"$jigdoF"
-     printImageInfo "$imageSel"
- }
- printImageInfo() {
-     if test "$section" = "[Image]" -a "$image" -a "$templateURI"; then
-         imageCount=`expr $imageCount + 1`
-         if test -z "$1"; then
-             printf "%3d: %s - %s\n" "$imageCount" "$image" "$shortInfo"
-         elif test "$1" = "$imageCount"; then
-             return 1
+ imageMenu() {
+   imageSel="$1"
+   curImageCount=0
+   section=""
+   exec 3<"$jigdoF"
+   l=""
+   while true; do
+     case "$l" in
+       "[Image]"*)
+         # Read image section contents
+         unset image templateURI templateMD5 shortInfo info
+         while $readLine l <&3; do
+           case "$l" in
+             "["*"]"*) break;;
 -            Filename=*) image="`echo $l | sed -e 's/^Filename= *//; s%['\\''\"$\\\`|&/[]%%g'`";;
 -            Template=*) templateURI="`echo $l | sed -e 's/^Template= *//; s%['\\''\"$\\\`|&[]%%g'`";;
 -            Template-MD5Sum=*) templateMD5="`echo $l | sed -e 's/^Template-MD5Sum= *//; s%['\\''\"$\\\`|&/[]%%g'`";;
++            Filename=*) image="`echo $l | sed -e 's/^Filename= *//; s%[['\\''\"$\\\`|&/]%%g'`";;
++            Template=*) templateURI="`echo $l | sed -e 's/^Template= *//; s%[['\\''\"$\\\`|&]%%g'`";;
++            Template-MD5Sum=*) templateMD5="`echo $l | sed -e 's/^Template-MD5Sum= *//; s%[['\\''\"$\\\`|&/]%%g'`";;
+             Template-MD5Sum=*) templateMD5="`echo $l | sed -e 's/^Template-MD5Sum= *//; s%[^a-zA-Z0-9_-]%%g'`";;
 -            ShortInfo=*) shortInfo="`echo $l | sed -e 's/^ShortInfo= *//; s%[$\\\`|[]%%g'`";;
 -            Info=*) info="`echo $l | sed -e 's/^Info= *//; s%['\\''\"$\\\`|[]%%g'`";;
++            ShortInfo=*) shortInfo="`echo $l | sed -e 's/^ShortInfo= *//; s%[[$\\\`|]%%g'`";;
++            Info=*) info="`echo $l | sed -e 's/^Info= *//; s%[['\\''\"$\\\`|]%%g'`";;
+           esac
+         done
+         # Image section read, check for validity
+         if strNotEmpty "$image" && strNotEmpty "$templateURI"; then
+           curImageCount="`expr $curImageCount + 1`"
+           if strNotEmpty "$imageSel"; then
+             # Return info for image selected via $imageSel
+             if test "$imageSel" -eq "$curImageCount"; then exec 3<&-; return 0; fi
+           else
+             # Print image menu
+             if strEmpty "$shortInfo"; then
+               printf "%3d: %s\n" "$curImageCount" "$image"
+             else
+               printf "%3d: %s (%s)\n" "$curImageCount" "$shortInfo" "$image"
+             fi
+           fi
          fi
-     fi
+         case "$l" in "[Image]"*) continue;; esac
+         # Abort early, avoid reading [Parts]
+         imageCount="$curImageCount"; exec 3<&-; return 0;;
+       *)
+         # Skip other parts of the file
+         while $readLine l <&3; do
+             case "$l" in "["*"]"*) break;; esac
+         done
+         case "$l" in "["*"]"*) continue;; esac
+         imageCount="$curImageCount"; exec 3<&-; return 0;;
+     esac
+   done
+   imageCount="$curImageCount"
+   exec 3<&-
+   return 0
  }
  #______________________________________________________________________
  
@@@ -437,9 -444,9 +444,9 @@@ size_t scanTimespan(const char* str) 
     Only deduceName() should call deduceName2(). */
  void deduceName2(string& dest, const char* ext, const string& src) {
    Paranoid(dest.empty());
-   string::size_type lastDot = src.find_last_of(EXTSEP);
+   string::size_type lastDot = src.rfind(EXTSEP);
    if (lastDot != string::npos) {
-     if (src.find_first_of(DIRSEP, lastDot + 1) != string::npos)
 -    if (src.rfind(DIRSEP, lastDot + 1) != string::npos)
++    if (src.find(DIRSEP, lastDot + 1) != string::npos)
        lastDot = string::npos;
    }
    dest.assign(src, 0U, lastDot);
index 0000000,1d51ca1..c4957fe
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,102 +1,102 @@@
 -    virtual void dataSource_data(const byte* data, size_t size,
+ /* $Id: datasource.hh,v 1.4 2003/08/28 23:21:00 atterer Exp $ -*- C++ -*-
+   __   _
+   |_) /|  Copyright (C) 2003  |  richard@
+   | \/¯|  Richard Atterer     |  atterer.net
+   ¯ '` ¯
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License, version 2. See
+   the file COPYING for details.
+   Interface for objects returning data from the network or from disk
+ */
+ #ifndef DATASOURCE_HH
+ #define DATASOURCE_HH
+ #include <config.h>
+ #include <job.hh>
+ #include <makeimagedl.fh>
+ #include <nocopy.hh>
+ #include <progress.fh>
+ //______________________________________________________________________
+ namespace Job {
+   class DataSource;
+ }
+ /** Interface for objects returning data from the network or from disk.
+     Implemented by SingleUrl and CachedUrl. MakeImageDl::dataSourceFor() is
+     the function which examines the local jigdo download's temporary
+     directory and creates a SingleUrl/CachedUrl as appropriate before putting
+     it inside a MakeImageDl::Child. */
+ class Job::DataSource : NoCopy {
+ public:
+   /** User interaction for DataSource.
+       Instances of derived classes are attached to any DataSources that the
+       MakeImageDl creates. */
+   class IO : public Job::IO {
+   public:
+     // Not overriding here:
+     // virtual IO* job_removeIo(IO* rmIo);
+     /** Called by the job when it is deleted or when a different IO object is
+         registered with it. If the IO object considers itself owned by its
+         job, it can delete itself. */
+     virtual void job_deleted() = 0;
+     /** Called when the job has successfully completed its task. */
+     virtual void job_succeeded() = 0;
+     /** Called when the job fails. The only remaining action after getting
+         this is to delete the job object. */
+     virtual void job_failed(string* message) = 0;
+     /** Informational message. */
+     virtual void job_message(string* message) = 0;
+     /** Called as soon as the size of the downloaded data is known. May not
+         be called at all if the size is unknown. Problem with libwww: Returns
+         size as long int - 2 GB size limit! */
+     virtual void dataSource_dataSize(uint64 n) = 0;
+     /** Called during download whenever data arrives, with the data that just
+         arrived. You can write the data to a file, copy it away etc.
+         currentSize is the offset into the downloaded data (including the
+         "size" new bytes) - useful for "x% done" messages. */
++    virtual void dataSource_data(const byte* data, unsigned size,
+                                  uint64 currentSize) = 0;
+   };
+   //____________________
+   IOPtr<IO> io;
+   inline DataSource(IO* ioPtr);
+   virtual ~DataSource();
+   /** Start delivering data. */
+   virtual void run() = 0;
+   /** Is the data stream currently paused? */
+   virtual bool paused() const = 0;
+   /** Pause the data stream. */
+   virtual void pause() = 0;
+   /** Continue after pause(). */
+   virtual void cont() = 0;
+   /** Return the internal progress object. */
+   virtual const Progress* progress() const = 0;
+   /** Return the URL used to download the data, or its filename on disc */
+   virtual const string& location() const = 0;
+ };
+ //______________________________________________________________________
+ Job::DataSource::DataSource(IO* ioPtr) : io(ioPtr) { }
+ #endif
index 0000000,30d6ab0..4832b25
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,695 +1,695 @@@
 -void JigdoIO::dataSource_data(const byte* data, size_t size,
+ /* $Id: jigdo-io.cc,v 1.15 2004/06/20 20:35:15 atterer Exp $ -*- C++ -*-
+   __   _
+   |_) /|  Copyright (C) 2003  |  richard@
+   | \/¯|  Richard Atterer     |  atterer.net
+   ¯ '` ¯
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License, version 2. See
+   the file COPYING for details.
+   IO object for downloads of .jigdo URLs; download, gunzip, interpret
+ */
+ #include <config.h>
+ #include <memory>
+ #include <configfile.hh>
+ #include <debug.hh>
+ #include <jigdo-io.hh>
+ #include <log.hh>
+ #include <makeimagedl.hh>
+ #include <md5sum.hh>
+ #include <mimestream.hh>
+ //#include <url-part.hh>
+ //______________________________________________________________________
+ DEBUG_UNIT("jigdo-io")
+ using namespace Job;
+ namespace {
+   inline bool isWhitespace(char x) { return ConfigFile::isWhitespace(x); }
+   inline bool advanceWhitespace(string::const_iterator& x,
+                                 const string::const_iterator& end) {
+     return ConfigFile::advanceWhitespace(x, end);
+   }
+   inline bool advanceWhitespace(string::iterator& x,
+                                 const string::const_iterator& end) {
+     return ConfigFile::advanceWhitespace(x, end);
+   }
+ }
+ // Root object
+ JigdoIO::JigdoIO(MakeImageDl::Child* c, const string& url,
+                  DataSource::IO* frontendIo)
+   : childDl(c), urlVal(url), frontend(frontendIo), parent(0), includeLine(0),
+     firstChild(0), next(0), rootAndImageSectionCandidate(this), line(0),
+     section(), imageSectionLine(0), imageName(), imageInfo(),
+     imageShortInfo(), templateUrl(), templateMd5(0), childFailedId(0),
+     gunzip(this) { }
+ // Non-root, i.e. [Include]d object
+ JigdoIO::JigdoIO(MakeImageDl::Child* c, const string& url,
+                  DataSource::IO* frontendIo, JigdoIO* parentJigdo,
+                  int inclLine)
+   : childDl(c), urlVal(url), frontend(frontendIo), parent(parentJigdo),
+     includeLine(inclLine), firstChild(0), next(0),
+     rootAndImageSectionCandidate(parent->root()), line(0), section(),
+     imageSectionLine(0), imageName(), imageInfo(), imageShortInfo(),
+     templateUrl(), templateMd5(0), childFailedId(0), gunzip(this) {
+   //debug("JigdoIO: Parent of %1 is %2", url, parent->urlVal);
+ }
+ //______________________________________________________________________
+ JigdoIO::~JigdoIO() {
+   debug("~JigdoIO");
+   if (childFailedId != 0) {
+     g_source_remove(childFailedId);
+     childFailedId = 0;
+     master()->childFailed(childDl, this, frontend);
+   }
+   /* Don't delete children; master will do this! If we deleted them here,
+      MakeImageDl::Child::childIoVal would be left dangling. */
+ //   // Delete all our children
+ //   JigdoIO* x = firstChild;
+ //   while (x != 0) {
+ //     JigdoIO* y = x->next;
+ //     delete x;
+ //     x = y;
+ //   }
+   delete templateMd5;
+   if (source() != 0) {
+     source()->io.remove(this);
+     Paranoid(source()->io.get() != this);
+   }
+ }
+ //______________________________________________________________________
+ Job::IO* JigdoIO::job_removeIo(Job::IO* rmIo) {
+   debug("job_removeIo %1", rmIo);
+   if (rmIo == this) {
+     // Do not "delete this" - this is called from ~JigdoIO above
+     DataSource::IO* c = frontend;
+     frontend = 0;
+     return c;
+   } else if (frontend != 0) {
+     Job::IO* c = frontend->job_removeIo(rmIo);
+     Paranoid(c == 0 || dynamic_cast<DataSource::IO*>(c) != 0);
+     debug("job_removeIo frontend=%1", c);
+     frontend = static_cast<DataSource::IO*>(c);
+   }
+   return this;
+ }
+ void JigdoIO::job_deleted() {
+   if (frontend != 0) frontend->job_deleted();
+   // Do not "delete this" - childDl owns us
+ }
+ void JigdoIO::job_succeeded() {
+   if (failed()) return;
+   if (gunzip.nextOut() > gunzipBuf) {
+     debug("job_succeeded: No newline at end");
+     ++line;
+     const char* lineChars = reinterpret_cast<const char*>(gunzipBuf);
+     if (g_utf8_validate(lineChars, gunzip.nextOut()-gunzipBuf, NULL) != TRUE)
+       return generateError(_("Input .jigdo data is not valid UTF-8"));
+     string line(lineChars, gunzip.nextOut() - gunzipBuf);
+     jigdoLine(&line);
+     if (failed()) return;
+   }
+   if (sectionEnd().failed()) return;
+   setFinished();
+   XStatus st = imgSect_eof();
+   if (st.xfailed()) return;
+   if (frontend != 0) frontend->job_succeeded();
+   master()->childSucceeded(childDl, this, frontend);
+   if (st.returned(1)) master()->jigdoFinished(); // Causes "delete this"
+ }
+ void JigdoIO::job_failed(string* message) {
+   Paranoid(!failed());
+   if (failed()) return;
+   if (frontend != 0) frontend->job_failed(message);
+   string err = _("Download of .jigdo file failed");
+   master()->generateError(&err);
+   /* We cannot call this right now:
+      master()->childFailed(childDl, this, frontend);
+      so schedule a callback to call it later. */
+   childFailedId = g_idle_add_full(G_PRIORITY_HIGH_IDLE,&childFailed_callback,
+                                   (gpointer)this, NULL);
+   Paranoid(childFailedId != 0);
+   imageName.assign("", 1); Paranoid(failed());
+ }
+ void JigdoIO::job_message(string* message) {
+   if (failed()) return;
+   if (frontend != 0) frontend->job_message(message);
+ }
+ void JigdoIO::dataSource_dataSize(uint64 n) {
+   if (failed()) return;
+   if (frontend != 0) frontend->dataSource_dataSize(n);
+ }
++void JigdoIO::dataSource_data(const byte* data, unsigned size,
+                               uint64 currentSize) {
+   Assert(!finished());
+   if (/*master()->finalState() ||*/ failed()) {
+     debug("Got %1 bytes, ignoring", size);
+     return;
+   }
+   //Assert(master()->state() == MakeImageDl::DOWNLOADING_JIGDO);
+   debug("Got %1 bytes, processing", size);
+   try {
+     gunzip.inject(data, size);
+   } catch (Error e) {
+     ++line;
+     generateError(e.message);
+     return;
+   }
+   if (frontend != 0) frontend->dataSource_data(data, size, currentSize);
+ }
+ //______________________________________________________________________
+ void JigdoIO::gunzip_deleted() { }
+ void JigdoIO::gunzip_needOut(Gunzip*) {
+   /* This is only called once, at the very start - afterwards, we always call
+      setOut() from gunzip_data, so Gunzip won't call this. */
+   gunzip.setOut(gunzipBuf, GUNZIP_BUF_SIZE);
+ }
+ /* Uncompressed data arrives. "decompressed" points somewhere inside
+    gunzipBuf. Split data apart at \n and interpret line(s), then copy any
+    remaining unfinished line to the start of gunzipBuf. The first byte of
+    gunzipBuf (if it contains valid data) is always the first char of a line
+    in the config file. */
+ void JigdoIO::gunzip_data(Gunzip*, byte* decompressed, unsigned size) {
+   if (failed()) return;
+   // Look for end of line.
+   byte* p = decompressed;
+   const byte* end = decompressed + size;
+   const byte* stringStart = gunzipBuf;
+   string line;
+   while (p < end) {
+     if (*p == '\n') {
+       // Process new line
+       Paranoid(static_cast<unsigned>(p - stringStart) <= GUNZIP_BUF_SIZE);
+       Paranoid(line.empty());
+       const char* lineChars = reinterpret_cast<const char*>(stringStart);
+       if (g_utf8_validate(lineChars, p - stringStart, NULL) != TRUE)
+         throw Error(_("Input .jigdo data is not valid UTF-8"));
+       line.append(lineChars, p - stringStart);
+       jigdoLine(&line);
+       if (failed()) return;
+       ++p;
+       stringStart = p;
+       continue;
+     }
+     if (*p == '\r')
+       *p = ' '; // Allow Windows-style line endings by turning CR into space
+     else if (*p == 127 || (*p < 32 && *p != '\t')) // Check for evil chars
+      throw Error(_("Input .jigdo data contains invalid control characters"));
+     ++p;
+   }
+   if (stringStart == gunzipBuf && p == stringStart + GUNZIP_BUF_SIZE) {
+     // A single line fills the whole buffer. Truncate it at that length.
+     debug("gunzip_data: long line");
+     Paranoid(line.empty());
+     const char* lineChars = reinterpret_cast<const char*>(stringStart);
+     if (g_utf8_validate(lineChars, p - stringStart, NULL) != TRUE)
+       throw Error(_("Input .jigdo data is not valid UTF-8"));
+     line.append(lineChars, p - stringStart);
+     jigdoLine(&line);
+     if (failed()) return;
+     // Trick: To ignore remainder of huge line, prepend a comment char '#'
+     gunzipBuf[0] = '#';
+     gunzip.setOut(gunzipBuf + 1, GUNZIP_BUF_SIZE - 1);
+     return;
+   }
+   unsigned len = p - stringStart;
+   if (len > 0 && stringStart > gunzipBuf) {
+     // Unprocessed data left somewhere inside the buffer - copy to buf start
+     Assert(len < GUNZIP_BUF_SIZE); // Room must be left in the buffer
+     memmove(gunzipBuf, stringStart, len);
+   }
+   gunzip.setOut(gunzipBuf + len, GUNZIP_BUF_SIZE - len);
+ }
+ void JigdoIO::gunzip_failed(string* message) {
+   throw Error(*message, true);
+ }
+ //______________________________________________________________________
+ void JigdoIO::generateError(const string& msg) {
+   string err;
+   const char* fmt = (finished() ?
+                      _("%1 (at end of %3)") : _("%1 (line %2 in %3)"));
+   err = subst(fmt, msg, line,
+               (source() != 0 ? source()->location().c_str() : "?") );
+   generateError_plain(&err);
+ }
+ void JigdoIO::generateError(const char* msg) {
+   string err;
+   const char* fmt = (finished() ?
+                      _("%1 (at end of %3)") : _("%1 (line %2 in %3)"));
+   err = subst(fmt, msg, line,
+               (source() != 0 ? source()->location().c_str() : "?") );
+   generateError_plain(&err);
+ }
+ void JigdoIO::generateError_plain(string* err) {
+   debug("generateError: %1", err);
+   Paranoid(!failed());
+   if (failed()) return;
+   if (frontend != 0) frontend->job_failed(err);
+   *err = _("Error processing .jigdo file contents");
+   master()->generateError(err);
+   /* We cannot call this right now:
+      master()->childFailed(childDl, this, frontend);
+      so schedule a callback to call it later. */
+   childFailedId = g_idle_add_full(G_PRIORITY_HIGH_IDLE,&childFailed_callback,
+                                   (gpointer)this, NULL);
+   Paranoid(childFailedId != 0);
+   imageName.assign("", 1); Paranoid(failed());
+ }
+ gboolean JigdoIO::childFailed_callback(gpointer data) {
+   JigdoIO* self = static_cast<JigdoIO*>(data);
+   debug("childFailed_callback for %1",
+         (self->source() != 0 ? self->source()->location().c_str() : "?") );
+   self->childFailedId = 0;
+   self->master()->childFailed(self->childDl, self, self->frontend);
+   self->master()->jigdoFinished(); // "delete self"
+   return FALSE; // "Don't call me again"
+ }
+ //______________________________________________________________________
+ // Finding the first [Image] section
+ /* While scanning the tree of [Include]d .jigdo files, only the first [Image]
+    section is relevant. IOW, we do a depth-first search of the tree. However,
+    the .jigdo files are downloaded in parallel, and we want to pass on the
+    image info as soon as possible. For this reason, we maintain an "image
+    section candidate pointer", one for the whole include tree.
+    If during the scanning of jigdo data we encounter an [Image] section AND
+    imgSectCandidate()==this, then that section is the first such section in
+    depth-first-order in the whole tree.
+    If instead we encounter an [Include], the included file /might/ contain an
+    image section, so we descend by setting imgSectCandidate() to the newly
+    created child download. However, it can turn out the child does not
+    actually contain an image section. In this case, we go back up to its
+    parent.
+    This is where it gets more complicated: Of course, the parent's data
+    continued to be downloaded while we were wasting our time waiting for the
+    last lines of the child, to be sure those last lines didn't contain an
+    image section. After the point where we descended into the child, any
+    number of [Include]s and /maybe/ an [Image] somewhere inbetween the
+    [Include]s could have been downloaded. To find out whether this was the
+    case, a quick depth-first scan of the tree is now necessary, up to the
+    next point where we "hang" again because some .jigdo file has not been
+    downloaded completely.
+    The whole code is also used to find out when all JigdoIOs have finished -
+    this could be done in simpler ways just by counting the active ones, but
+    it comes "for free" with this code. */
+ // New child created due to [Include] in current .jigdo data
+ void JigdoIO::imgSect_newChild(JigdoIO* child) {
+   if (master()->finalState() || imgSectCandidate() != this) return;
+   debug("imgSect_newChild%1: From %2:%3 to child %4",
+         (master()->haveImageSection() ? "(haveImageSection)" : ""),
+         urlVal, line, child->urlVal);
+   setImgSectCandidate(child);
+ }
+ // An [Image] section just ended - maybe it was the first one?
+ void JigdoIO::imgSect_parsed() {
+   //debug("imgSect_parsed: %1 %2 %3", imgSectCandidate(), this, master()->finalState());
+   if (master()->finalState() || imgSectCandidate() != this) return;
+   debug("imgSect_parsed%1: %2:%3", (master()->haveImageSection()
+         ? "(haveImageSection)" : ""), urlVal, line - 1);
+   if (master()->haveImageSection()) return;
+   master()->setImageSection(&imageName, &imageInfo, &imageShortInfo,
+                             &templateUrl, &templateMd5);
+ }
+ #if DEBUG
+ namespace {
+   inline const char* have(MakeImageDl* master) {
+     if (master->haveImageSection())
+       return "I";
+     else
+       return " ";
+   }
+ }
+ #endif
+ // The end of the file was hit
+ XStatus JigdoIO::imgSect_eof() {
+   MakeImageDl* m = master();
+   if (m->finalState() || imgSectCandidate() != this) return OK;
+   JigdoIO* x = parent; // Current position in tree
+   int l = includeLine; // Line number in x, 0 if at start
+   JigdoIO* child = this; // child included at line l of x, null if l==0
+   while (x != 0) {
+ #   if DEBUG
+     const char* indentStr = "                                        ";
+     const char* indent = indentStr + 40;
+     JigdoIO* ii = x;
+     while (ii != 0) { indent -= 2; ii = ii->parent; }
+     if (indent < indentStr) indent = indentStr;
+     debug("imgSect_eof:%1%2Now at %3:%4", have(m), indent, x->urlVal, l);
+ #   endif
+     JigdoIO* nextChild;
+     if (l == 0) nextChild = x->firstChild; else nextChild = child->next;
+     if (nextChild != 0) {
+       /* Before moving l to the line of the next [Include], check whether the
+          area of the file that l moves over contains an [Image] */
+       if (l < x->imageSectionLine
+           && x->imageSectionLine < nextChild->includeLine) {
+         debug("imgSect_eof:%1%2Found before [Include]", have(m), indent);
+         if (!m->haveImageSection())
+           m->setImageSection(&x->imageName, &x->imageInfo,
+               &x->imageShortInfo, &x->templateUrl, &x->templateMd5);
+       }
+       // No [Image] inbetween - move on, descend into [Include]
+       debug("imgSect_eof:%1%2Now at %3:%4, descending",
+             have(m), indent, x->urlVal, nextChild->includeLine);
+       x = nextChild;
+       l = 0;
+       child = 0;
+       continue;
+     }
+     // x has no more children - but maybe an [Image] at the end?
+     if (l < x->imageSectionLine) {
+       debug("imgSect_eof:%1%2Found after last [Include], if any",
+             have(m), indent);
+       if (!m->haveImageSection())
+         m->setImageSection(&x->imageName, &x->imageInfo,
+                        &x->imageShortInfo, &x->templateUrl, &x->templateMd5);
+     }
+     // Nothing found. If x not yet fully downloaded, stop here
+     if (!x->finished()) {
+       debug("imgSect_eof:%1%2Waiting for %3 to download",
+             have(m), indent, x->urlVal);
+       setImgSectCandidate(x);
+       return OK;
+     }
+     // Nothing found and finished - go back up in tree
+     debug("imgSect_eof:%1%2Now at end of %3, ascending",
+           have(m), indent, x->urlVal);
+     l = x->includeLine;
+     child = x;
+     x = x->parent;
+   }
+   if (m->haveImageSection()) {
+     debug("imgSect_eof: Finished");
+     return XStatus(1);
+   } else {
+     generateError(_("No `[Image]' section found in .jigdo data"));
+     return FAILED;
+   }
+ }
+ //______________________________________________________________________
+ // New line of jigdo data arrived. This is similar to ConfigFile::rescan()
+ void JigdoIO::jigdoLine(string* l) {
+   //debug("\"%1\"", l);
+   string s;
+   s.swap(*l);
+   if (failed()) return;
+   ++line;
+   string::const_iterator x = s.begin(), end = s.end();
+   // Empty line, or only contains '#' comment
+   if (advanceWhitespace(x, end)) return;
+   bool inComment = (section == "Comment" || section == "comment");
+   if (*x != '[') {
+     // This is a "Label=Value" line
+     if (inComment) return;
+     string labelName;
+     while (!isWhitespace(*x) && *x != '=') { labelName += *x; ++x; }
+     if (advanceWhitespace(x, end) || *x != '=')
+       return generateError(_("No `=' after first word"));
+     ++x; // Skip '='
+     advanceWhitespace(x, end);
+ //     vector<string> value;
+ //     ConfigFile::split(value, s, x - s.begin());
+ //     entry(&labelName, &value);
+     entry(&labelName, &s, x - s.begin());
+     return;
+   }
+   //____________________
+   // This is a "[Section]" line
+   if (sectionEnd().failed()) return;
+   ++x; // Advance beyond the '['
+   if (advanceWhitespace(x, end)) // Skip space after '['
+     return generateError(_("No closing `]' for section name"));
+   string::const_iterator s1 = x; // s1 points to start of section name
+   while (x != end && *x != ']' && !isWhitespace(*x) && *x != '['
+          && *x != '=' && *x != '#') ++x;
+   string::const_iterator s2 = x; // s2 points to end of section name
+   if (advanceWhitespace(x, end))
+     return generateError(_("No closing `]' for section name"));
+   section.assign(s1, s2);
+   //debug("Section `%1'", section);
+   // In special case of "Image", ignore 2nd and subsequent sections
+   if (section == "Image") {
+     if (imageSectionLine == 0)
+       imageSectionLine = line;
+     else
+       section += "(ignored)";
+   }
+   // In special case of "Include", format differs: URL after section name
+   if (section == "Include") {
+     string url;
+     while (x != end && *x != ']') { url += *x; ++x; }
+     int i = url.size();
+     while (i > 0 && isWhitespace(url[--i])) { }
+     url.erase(i + 1);
+     include(&url);
+   }
+   if (*x != ']')
+     return generateError(_("Section name invalid"));
+   ++x; // Advance beyond the ']'
+   if (!advanceWhitespace(x, end))
+     return generateError(_("Invalid characters after closing `]'"));
+ }
+ //______________________________________________________________________
+ Status JigdoIO::sectionEnd() {
+   if (section != "Image") return OK;
+   // Section that just ended was [Image]
+   const char* valueName = 0;
+   if (templateMd5 == 0) valueName = "Template-MD5Sum";
+   if (templateUrl.empty()) valueName = "Template";
+   if (imageName.empty()) valueName = "Filename";
+   if (valueName == 0) {
+     imgSect_parsed();
+     return OK;
+   }
+   // Error: Not all required fields found
+   --line;
+   string s = subst(_("`%1=...' line missing in [Image] section"), valueName);
+   generateError(s);
+   return FAILED;
+ }
+ //______________________________________________________________________
+ // "[Include url]" found - add
+ void JigdoIO::include(string* url) {
+   string includeUrl;
+   Download::uriJoin(&includeUrl, urlVal, *url);
+   debug("%1:[Include %2]", line, includeUrl);
+   JigdoIO* p = this;
+   do {
+     //debug("include: Parent of %1 is %2", p->urlVal,
+     //      (p->parent ? p->parent->urlVal : "none"));
+     if (p->urlVal == includeUrl)
+       return generateError(_("Loop of [Include] directives"));
+     p = p->parent;
+   } while (p != 0);
+   string leafname;
+   auto_ptr<MakeImageDl::Child> childDl(
+       master()->childFor(includeUrl, 0, &leafname));
+   if (childDl.get() != 0) {
+     MakeImageDl::IO* mio = master()->io.get();
+     string info = _("Retrieving .jigdo data");
+     string destDesc = subst(Job::MakeImageDl::destDescTemplate(),
+                             leafname, info);
+     auto_ptr<DataSource::IO> frontend(0);
+     if (mio != 0)
+       frontend.reset(mio->makeImageDl_new(childDl->source(), includeUrl,
+                                           destDesc) );
+     JigdoIO* jio = new JigdoIO(childDl.get(), includeUrl, frontend.get(),
+                                this, line);
+     childDl->setChildIo(jio);
+     frontend.release();
+     if (mio != 0) mio->job_message(&info);
+     // Add new child
+     JigdoIO** jiop = &firstChild;
+     while (*jiop != 0) jiop = &(*jiop)->next;
+     *jiop = jio;
+     imgSect_newChild(jio);
+     (childDl.release())->source()->run();
+   }
+ }
+ //______________________________________________________________________
+ namespace {
+   // For Base64In - put decoded bytes into 16-byte array
+   struct ArrayOut {
+     typedef ArrayOut& ResultType;
+     ArrayOut() { }
+     void set(byte* array) { cur = array; end = array + 16; }
+     void put(byte b) { if (cur == end) cur = end = 0; else *cur++ = b; }
+     ArrayOut& result() { return *this; }
+     byte* cur; byte* end;
+   };
+ }
+ //____________________
+ /* @param label Pointer to word before the '='
+    @param data Pointer to string containing whole input line
+    @param valueOff Offset of value (part after '=') in data */
+ void JigdoIO::entry(string* label, string* data, unsigned valueOff) {
+   vector<string> value;
+   ConfigFile::split(value, *data, valueOff);
+ # if DEBUG
+   string s;
+   for (vector<string>::iterator i = value.begin(), e = value.end();
+        i != e; ++i) { s += '>'; s += *i; s += "< "; }
+   // { s += ConfigFile::quote(*i); s += ' '; }
+   debug("%1:[%2] %3=%4", line, section, label, s);
+ # endif
+   //____________________
+   if (section == "Include") {
+     return generateError(_("A new section must be started after [Include]"));
+     //____________________
+   } else if (section == "Jigdo") {
+     if (*label == "Version") {
+       if (value.empty()) return generateError(_("Missing argument"));
+       int ver = 0;
+       string::const_iterator i = value.front().begin();
+       string::const_iterator e = value.front().end();
+       while (i != e && *i >= '0' && *i <= '9') {
+         ver = 10 * ver + *i - '0';
+         ++i;
+       }
+       if (ver > SUPPORTED_FORMAT)
+         return generateError(_("Upgrade required - this .jigdo file needs "
+                                "a newer version of the jigdo program"));
+     }
+     //____________________
+   } else if (section == "Image") {
+     /* Only called for first [Image] section in file - for further sections,
+        section=="Image(ignored)". Does some sanity checks on the supplied
+        data. */
+     if (*label == "Filename") {
+       if (!imageName.empty()) return generateError(_("Value redefined"));
+       if (value.empty()) return generateError(_("Missing argument"));
+       // Only use leaf name, ignore dirname delimiters, max 100 chars
+       string::size_type lastSlash = value.front().rfind('/');
+       string::size_type lastSep = value.front().rfind(DIRSEP);
+       if (lastSlash > lastSep) lastSep = lastSlash;
+       imageName.assign(value.front(), lastSep + 1, 100);
+       if (imageName.empty()) return generateError(_("Invalid image name"));
+     } else if (*label == "Template") {
+       if (!templateUrl.empty()) return generateError(_("Value redefined"));
+       if (value.empty()) return generateError(_("Missing argument"));
+       templateUrl = value.front();
+     } else if (*label == "Template-MD5Sum") {
+       if (templateMd5 != 0) return generateError(_("Value redefined"));
+       if (value.empty()) return generateError(_("Missing argument"));
+       templateMd5 = new MD5();
+       // Helper class places decoded bytes into MD5 object
+       Base64In<ArrayOut> decoder;
+       decoder.result().set(templateMd5->sum);
+       decoder << value.front();
+       if (decoder.result().cur == 0
+           || decoder.result().cur != decoder.result().end) {
+         delete templateMd5; templateMd5 = 0;
+         return generateError(_("Invalid Template-MD5Sum argument"));
+       }
+       // For security, double-check the value
+       Base64String b64;
+       b64.write(templateMd5->sum, 16).flush();
+       if (b64.result() != value.front()) {
+         debug("b64='%1' value='%2'", b64.result(), value.front());
+         return generateError(_("Invalid Template-MD5Sum argument"));
+       }
+     } else if (*label == "ShortInfo") {
+       // ShortInfo is 200 chars max
+       if(!imageShortInfo.empty()) return generateError(_("Value redefined"));
+       imageShortInfo.assign(*data, valueOff, 200);
+     } else if (*label == "Info") {
+       // ImageInfo is 5000 chars max
+       if (!imageInfo.empty()) return generateError(_("Value redefined"));
+       imageInfo.assign(*data, valueOff, 5000);
+     }
+   } else if (section == "Parts") {
+     // TODO
+     if (value.empty()) return generateError(_("Missing argument"));
+     MD5 md5;
+     Base64In<ArrayOut> decoder;
+     decoder.result().set(md5.sum);
+       decoder << *label;
+       if (decoder.result().cur == 0
+           || decoder.result().cur != decoder.result().end) {
+         return generateError(_("Invalid MD5Sum in Parts section"));
+       }
+       // For security, double-check the value
+       Base64String b64;
+       b64.write(md5.sum, 16).flush();
+       if (b64.result() != *label) {
+         debug("x b64='%1' value='%2'", b64.result(), *label);
+         return generateError(_("Invalid MD5Sum in Parts section"));
+       }
+       debug("PART %1 -> %2", md5.toString(), value.front());
+   } // endif (section == "Something")
+ }
index 0000000,d976eda..c4bc3a7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,198 +1,198 @@@
 -  virtual void dataSource_data(const byte* data, size_t size,
+ /* $Id: jigdo-io.hh,v 1.8 2004/02/04 15:34:40 atterer Exp $ -*- C++ -*-
+   __   _
+   |_) /|  Copyright (C) 2003  |  richard@
+   | \/¯|  Richard Atterer     |  atterer.net
+   ¯ '` ¯
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License, version 2. See
+   the file COPYING for details.
+   IO object for .jigdo downloads; download, gunzip, interpret
+   Data (=downloaded bytes, status info) flows as follows:
+   class:       Download ->    SingleUrl      -> JigdoIO -> GtkSingleUrl
+   data member:             childDl->source()      this        frontend
+   The JigdoIO owns the SingleUrl (and the Download *object* inside it), but
+   it doesn't own the GtkSingleUrl.
+ */
+ #ifndef JIGDO_IO_HH
+ #define JIGDO_IO_HH
+ #include <config.h>
+ #include <vector>
+ #include <string>
+ #include <datasource.hh>
+ #include <gunzip.hh>
+ #include <jigdo-io.fh>
+ #include <makeimagedl.hh>
+ #include <md5sum.fh>
+ #include <nocopy.hh>
+ #include <status.hh>
+ //______________________________________________________________________
+ namespace Job {
+   class JigdoIO;
+   struct JigdoIOTest;
+ }
+ class Job::JigdoIO : NoCopy, public Job::DataSource::IO, Gunzip::IO {
+ public:
+   /** The supported major version format number inside .jigdo files. E.g. "1"
+       means that this code will accept all .jigdo files whose [Jigdo]
+       sections contain "Version=" lines followed by 0.x or 1.x version
+       numbers. A hard (non-recoverable) error happens for 2.x or bigger
+       numbers. */
+   static const int SUPPORTED_FORMAT = 1;
+   /** Create a new JigdoIO which is owned by m, gets data from download (will
+       register itself with download's IOPtr) and passes it on to childIo.
+       @param c Object which owns us (it is the MakeImageDl's child, but our
+       master)
+       @param download Gives the data of the .jigdo file to us
+       @param childIo Provided by the frontend, e.g. a GtkSingleUrl object */
+   JigdoIO(MakeImageDl::Child* c, const string& url,
+           DataSource::IO* frontendIo);
+   ~JigdoIO();
+   virtual Job::IO* job_removeIo(Job::IO* rmIo);
+   inline MakeImageDl* master() const;
+   inline DataSource* source() const;
+ private:
+   friend struct Job::JigdoIOTest;
+   /* Create object for an [Include]d file */
+   JigdoIO(MakeImageDl::Child* c, const string& url,
+           DataSource::IO* frontendIo, JigdoIO* parentJigdo,
+           int inclLine);
+   /** @return Root object of the include tree */
+   inline JigdoIO* root();
+   inline const JigdoIO* root() const;
+   /** @return true iff this object is the root of the include tree. */
+   inline bool isRoot() const;
+   /** Return the ptr to the image section candidate object; the JigdoIO which
+       might or might not contain the first [Image] section. If new data is
+       received for that object and that new data contains an [Image], we know
+       it's the first [Image]. If all data is recvd without any [Image]
+       turning up, we continue walking the include tree depth-first. */
+   inline JigdoIO* imgSectCandidate() const;
+   /** Set the ptr to the image section candidate object */
+   inline void setImgSectCandidate(JigdoIO* c);
+   // The methods below are called in various places to find 1st image section
+   inline void imgSect_newChild(JigdoIO* child); // Child created after [Incl.
+   inline void imgSect_parsed(); // [Image] occurred in current .jigdo data
+   /* End of current file without any [Image]. Returns 1 if OK and all
+      JigdoIOs finished */
+   inline XStatus imgSect_eof();
+   // Create error message with URL and line number
+   void generateError(const string& msg);
+   void generateError(const char* msg);
+   // As above, but directly pass on error string, do not add URL/line
+   void generateError_plain(string* err);
+   // True after above was called
+   inline bool failed() const;
+   // Called by gunzip_data(): New .jigdo line ready. Arg is empty on exit.
+   void jigdoLine(string* l);
+   void include(string* url); // "[Include http://xxx]" found
+   void entry(string* label, string* data, unsigned valueOff);
+   /* Called at the end of a [Section] (=start of another section or EOF)
+      Returns FAILURE if there is an error. */
+   Status sectionEnd();
+   // Virtual methods from DataSource::IO
+   virtual void job_deleted();
+   virtual void job_succeeded();
+   virtual void job_failed(string* message);
+   virtual void job_message(string* message);
+   virtual void dataSource_dataSize(uint64 n);
++  virtual void dataSource_data(const byte* data, unsigned size,
+                                uint64 currentSize);
+   // Virtual methods from Gunzip::IO
+   virtual void gunzip_deleted();
+   virtual void gunzip_data(Gunzip*, byte* decompressed, unsigned size);
+   virtual void gunzip_needOut(Gunzip*);
+   virtual void gunzip_failed(string* message);
+   MakeImageDl::Child* childDl;
+   string urlVal;
+   DataSource::IO* frontend; // Object provided by frontend for this download
+   /* Representation of the tree of [Include] directives. Most of the time,
+      the order of data in the .jigdo files is not relevant, with one
+      exception: We must interpret the first [Image] section only, and ignore
+      all following ones. */
+   JigdoIO* parent; // .jigdo file which [Include]d us, or null if top-level
+   int includeLine; // If parent!=null, line num of [Include] in parent
+   JigdoIO* firstChild; // First file we [Include], or null if none
+   JigdoIO* next; // Right sibling, or null if none
+   /* For the root object, contains imgSectCandidate, else ptr to root object.
+      Don't access directly, use accessor methods. */
+   JigdoIO* rootAndImageSectionCandidate;
+   int line; // Line number, for errors. 0 if no data yet, -1 if finished
+   bool finished() { return line < 0; }
+   void setFinished() { line = -1; }
+   string section; // Current section name, empty if none yet
+   // Info about first image section of this .jigdo, if any
+   int imageSectionLine; // 0 if no [Image] found yet
+   string imageName;
+   string imageInfo, imageShortInfo;
+   string templateUrl;
+   MD5* templateMd5;
+   /* When an error happens inside gunzip_data(), cannot immediately tell the
+      master about it, because it would delete the DataSource => the Download
+      would be deleted from within download_data(). */
+   static gboolean childFailed_callback(gpointer data);
+   int childFailedId;
+   /* Transparent gunzipping of .jigdo file. GUNZIP_BUF_SIZE is also the max
+      size a single line in the .jigdo is allowed to have */
+   static const unsigned GUNZIP_BUF_SIZE = 16384;
+   Gunzip gunzip;
+   byte gunzipBuf[GUNZIP_BUF_SIZE];
+ };
+ //______________________________________________________________________
+ Job::JigdoIO* Job::JigdoIO::root() {
+   if (isRoot()) return this; else return rootAndImageSectionCandidate;
+ }
+ const Job::JigdoIO* Job::JigdoIO::root() const {
+   if (isRoot()) return this; else return rootAndImageSectionCandidate;
+ }
+ bool Job::JigdoIO::isRoot() const {
+   return parent == 0;
+ }
+ Job::JigdoIO* Job::JigdoIO::imgSectCandidate() const {
+   if (isRoot())
+     return rootAndImageSectionCandidate;
+   else
+     return rootAndImageSectionCandidate->rootAndImageSectionCandidate;
+ }
+ void Job::JigdoIO::setImgSectCandidate(JigdoIO* c) {
+   if (isRoot())
+     rootAndImageSectionCandidate = c;
+   else
+     rootAndImageSectionCandidate->rootAndImageSectionCandidate = c;
+ }
+ Job::MakeImageDl* Job::JigdoIO::master() const { return childDl->master(); }
+ Job::DataSource*  Job::JigdoIO::source() const { return childDl->source(); }
+ bool Job::JigdoIO::failed() const {
+   return (imageName.length() == 1 && imageName[0] == '\0');
+   //return (childFailedId != 0);
+ }
+ #endif
index 0000000,e526c4d..1fa8251
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,90 +1,90 @@@
 -  virtual void dataSource_data(const byte* data, size_t size,
+ /* $Id: jigdodownload.hh,v 1.7 2003/08/15 11:38:30 atterer Exp $ -*- C++ -*-
+   __   _
+   |_) /|  Copyright (C) 2003  |  richard@
+   | \/¯|  Richard Atterer     |  atterer.net
+   ¯ '` ¯
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License, version 2. See
+   the file COPYING for details.
+   Download .jigdo data, take care of handling [Include] directives.
+ */
+ #ifndef JIGDODOWNLOAD_HH
+ #define JIGDODOWNLOAD_HH
+ #include <config.h>
+ #include <makeimagedl.hh>
+ //______________________________________________________________________
+ // PRIVATE stuff, internal to MakeImageDl
+ /** Private class of MakeImageDl: Object extending a SingleUrl and used to
+     retrieve the data of the .jigdo file.
+     NB: The underlying Download's io pointer is set up to point to this
+     object. Once this receives the calls, this object passes them on to its
+     own io pointer, which will point to the corresponding front-end object,
+     e.g. a GtkSingleUrl. This sandwiching is in contrast to "normal"
+     single-file downloads, where the Download directly calls the
+     GtkSingleUrl. */
+ class Job::MakeImageDl::JigdoDownload
+     : SingleUrl, // This object is a special kind of SingleUrl
+       DataSource::IO,
+       Gunzip::IO {
+ public:
+   /** @param m Master which owns us
+       @param p Parent JigdoDownload which [Include]d us, or null
+       @param jigdoUrl Where to download .jigdo data
+       @param destPos Where in config file to insert downloaded data */
+   JigdoDownload(MakeImageDl* m, JigdoDownload* p, const string& jigdoUrl,
+                 ConfigFile::iterator destPos);
+   virtual ~JigdoDownload();
+   void run();
+   /** Access the correct io member, i.e. for the derived class. */
+   virtual IOPtr<DataSource::IO>& io();
+   virtual const IOPtr<DataSource::IO>& io() const;
+ private:
+   /** Methods from SingleUrl::IO */
+   virtual void job_deleted();
+   virtual void job_succeeded();
+   virtual void job_failed(string* message);
+   virtual void job_message(string* message);
+   virtual void dataSource_dataSize(uint64 n);
++  virtual void dataSource_data(const byte* data, unsigned size,
+                                uint64 currentSize);
+   // Virtual methods from Gunzip::IO
+   virtual void gunzip_deleted();
+   virtual void gunzip_data(Gunzip*, byte* decompressed, unsigned size);
+   virtual void gunzip_needOut(Gunzip*);
+   virtual void gunzip_failed(string* message);
+   // Convenience helper function
+   inline ConfigFile& configFile() const;
+   MakeImageDl* master; // Ptr to the MakeImageDl which owns us
+   JigdoDownload* parent; // Ptr to the download which [Include]d us, or null
+   // IO for this SingleUrl, given by master. Points to e.g. a GtkSingleUrl
+   IOPtr<Job::DataSource::IO> ioVal;
+   /* Transparent gunzipping of .jigdo file. GUNZIP_BUF_SIZE is also the max
+      size a single line in the .jigdo is allowed to have */
+   static const unsigned GUNZIP_BUF_SIZE = 16384;
+   byte gunzipBuf[GUNZIP_BUF_SIZE];
+   Gunzip gunzip;
+   // Where to put .jigdo data. Points somewhere inside configFile()
+   ConfigFile::iterator insertPos;
+ };
+ ConfigFile& Job::MakeImageDl::JigdoDownload::configFile() const {
+   return master->mi.configFile();
+ }
+ #endif