Implement zip_register_progress_callback().

This function can be used to provide user interface updates
during zip_close().
diff --git a/NEWS.md b/NEWS.md
index 0555595..7b50aaa 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -6,6 +6,7 @@
 * Fix seeking in zip_source_file if start > 0.
 * Add zip_fseek() for seeking in uncompressed data.
 * Add zip_ftell() for telling position in uncompressed data.
+* Add zip_register_progress_callback() for UI updates during zip_close()
 
 1.1.3 [2016-05-28]
 ==================
diff --git a/TODO.md b/TODO.md
index 902ac6b..551437f 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,11 +1,5 @@
 # API Plans
 
-## Encryption
-
-````c
-int zip_file_set_encryption(struct zip *archive, zip_uint64_t idx, zip_uint16_t method, const char *password);
-````
-
 ## Prefixes
 
 For example for adding extractors for self-extracting zip archives.
@@ -14,15 +8,6 @@
 const zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp);
 ````
 
-## Progress Callback
-
-Register callback; will be called from `zip_close()` after each file has been processed.
-
-````c
-typedef void (*zip_progress_callback_t)(double);
-void zip_register_progress_callback(zip_t *, zip_progress_callback_t);
-````
-
 # API Issues
 
 * `zip_get_archive_comment` has `int *lenp` argument.  Cleaner would be `zip_uint32_t *`.
@@ -31,6 +16,7 @@
 * compression/crypt implementations: how to set error code on failure
 * compression/crypt error messages a la `ZIP_ER_ZLIB` (no detailed info passing)
 * check arguments for every entry point into libzip
+* remove unused `zip_archive_set_tempdir()`
 
 # Features
 
diff --git a/lib/zip.h b/lib/zip.h
index 97f01e5..0e71a55 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -307,6 +307,7 @@
 typedef zip_uint32_t zip_flags_t;
 
 typedef zip_int64_t (*zip_source_callback)(void *, void *, zip_uint64_t, zip_source_cmd_t);
+typedef void (*zip_progress_callback_t)(double);
 
 
 #ifndef ZIP_DISABLE_DEPRECATED
@@ -376,6 +377,7 @@
 ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *, const char *, zip_flags_t);
 ZIP_EXTERN zip_t *zip_open(const char *, int, int *);
 ZIP_EXTERN zip_t *zip_open_from_source(zip_source_t *, int, zip_error_t *);
+ZIP_EXTERN void zip_register_progress_callback(zip_t *, zip_progress_callback_t);
 ZIP_EXTERN int zip_set_archive_comment(zip_t *, const char *, zip_uint16_t);
 ZIP_EXTERN int zip_set_archive_flag(zip_t *, zip_flags_t, int);
 ZIP_EXTERN int zip_set_default_password(zip_t *, const char *);
diff --git a/lib/zip_close.c b/lib/zip_close.c
index fd5a107..15e2a2f 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -131,6 +131,10 @@
 	zip_entry_t *entry;
 	zip_dirent_t *de;
 
+	if (za->progress_callback) {
+	    za->progress_callback((double)j/survivors);
+	}
+
 	i = filelist[j].idx;
 	entry = za->entry+i;
 
@@ -222,6 +226,10 @@
 	return -1;
     }
 
+    if (za->progress_callback) {
+	za->progress_callback(1);
+    }
+
     zip_discard(za);
     
     return 0;
diff --git a/lib/zip_new.c b/lib/zip_new.c
index 562dd76..08a384e 100644
--- a/lib/zip_new.c
+++ b/lib/zip_new.c
@@ -69,6 +69,7 @@
     za->nopen_source = za->nopen_source_alloc = 0;
     za->open_source = NULL;
     za->tempdir = NULL;
+    za->progress_callback = NULL;
     
     return za;
 }
diff --git a/lib/zip_open.c b/lib/zip_open.c
index ff84a83..38aee49 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -177,6 +177,14 @@
     return 0;
 }
 
+
+ZIP_EXTERN void
+zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback)
+{
+    za->progress_callback = progress_callback;
+}
+
+
 zip_t *
 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
 {
diff --git a/lib/zipint.h b/lib/zipint.h
index 6d16caf..1242fe2 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -200,6 +200,7 @@
     zip_hash_t *names;			/* hash table for name lookup */
 
     char *tempdir;                      /* custom temp dir (needed e.g. for OS X sandboxing) */
+    zip_progress_callback_t progress_callback; /* progress callback for zip_close() */
 };
 
 /* file in zip archive, part of API */
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
index 9f893f5..4934f8b 100644
--- a/man/CMakeLists.txt
+++ b/man/CMakeLists.txt
@@ -48,6 +48,7 @@
   zip_get_num_files.mdoc
   zip_name_locate.mdoc
   zip_open.mdoc
+  zip_register_progress_callback.mdoc
   zip_rename.mdoc
   zip_set_archive_comment.mdoc
   zip_set_archive_flag.mdoc
diff --git a/man/Makefile.am b/man/Makefile.am
index 4e0cc8e..f8fac8e 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -59,6 +59,7 @@
 	zip_name_locate.mdoc \
 	zip_open.mdoc \
 	zip_rename.mdoc \
+	zip_register_progress_callback.mdoc
 	zip_set_archive_comment.mdoc \
 	zip_set_archive_flag.mdoc \
 	zip_set_default_password.mdoc \
diff --git a/man/libzip.mdoc b/man/libzip.mdoc
index 8640b55..db9d206 100644
--- a/man/libzip.mdoc
+++ b/man/libzip.mdoc
@@ -128,6 +128,7 @@
 .Ss close archive
 .Xr zip_close 3
 .Ss miscellaneous
+.Xr zip_register_progress_callback 3
 .Xr zip_set_archive_comment 3
 .Xr zip_set_archive_flag 3
 .Xr zip_source 3
diff --git a/man/zip_register_progress_callback.mdoc b/man/zip_register_progress_callback.mdoc
new file mode 100644
index 0000000..25da988
--- /dev/null
+++ b/man/zip_register_progress_callback.mdoc
@@ -0,0 +1,66 @@
+.\" zip_register_progress_callback.mdoc -- provide updates during zip_close
+.\" Copyright (C) 2016 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP archives.
+.\" The authors can be contacted at <libzip@nih.at>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. The names of the authors may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd December 18, 2016
+.Dt ZIP_REGISTER_PROGRESS_CALLBACK 3
+.Os
+.Sh NAME
+.Nm zip_register_progress_callback
+.Nd provide updates during zip_close
+.Sh LIBRARY
+libzip (-lzip)
+.Sh SYNOPSIS
+.In zip.h
+.Vt typedef void (*zip_progress_callback_t)(double);
+.Ft void
+.Fn zip_register_progress_callback "zip_t *archive" "zip_progress_callback_t progress_callback"
+.Sh DESCRIPTION
+The
+.Fn zip_register_progress_callback
+function registers a callback function
+.Ar progress_callback
+for the zip archive
+.Ar archive .
+This function is called during
+.Xr zip_close 3
+after every zip archive entry that's completely written to disk.
+The value is a
+.Vt double
+in the range from 0.0 to 1.0.
+This can be used to provide progress indicators for user interfaces.
+.Sh SEE ALSO
+.Xr libzip 3 ,
+.Xr zip_close 3
+.Sh AUTHORS
+.An -nosplit
+.An Dieter Baron Aq Mt dillo@nih.at
+and
+.An Thomas Klausner Aq Mt tk@giga.or.at
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt
index 155bb4f..840cb77 100644
--- a/regress/CMakeLists.txt
+++ b/regress/CMakeLists.txt
@@ -85,6 +85,7 @@
 	open_truncate.test
 	open_zip64_3mf.test
 	open_zip64_ok.test
+	progress.test
 	rename_ascii.test
 	rename_cp437.test
 	rename_deleted.test
diff --git a/regress/Makefile.am b/regress/Makefile.am
index edd9da3..2352c13 100644
--- a/regress/Makefile.am
+++ b/regress/Makefile.am
@@ -206,6 +206,7 @@
 	open_truncate.test \
 	open_zip64_3mf.test \
 	open_zip64_ok.test \
+	progress.test \
 	rename_ascii.test \
 	rename_cp437.test \
 	rename_deleted.test \
diff --git a/regress/progress.test b/regress/progress.test
new file mode 100644
index 0000000..8604db2
--- /dev/null
+++ b/regress/progress.test
@@ -0,0 +1,10 @@
+# test default compression stores if smaller; print progress
+return 0
+args -n test.zip  print_progress  add compressable aaaaaaaaaaaaaa  add uncompressable uncompressable  add_nul large-compressable 8200  add_file large-uncompressable large-uncompressable 0 -1
+file-new test.zip cm-default.zip
+file large-uncompressable large-uncompressable large-uncompressable
+stdout 0.0% done
+stdout 25.0% done
+stdout 50.0% done
+stdout 75.0% done
+stdout 100.0% done
diff --git a/src/ziptool.c b/src/ziptool.c
index f7c2704..91310b5 100644
--- a/src/ziptool.c
+++ b/src/ziptool.c
@@ -401,6 +401,17 @@
     return 0;
 }
 
+static void
+progress_callback(double percentage) {
+    printf("%.1lf%% done\n", percentage*100);
+}
+
+static int
+print_progress(int argc, char *argv[]) {
+    zip_register_progress_callback(za, progress_callback);
+    return 0;
+}
+
 static int
 zrename(int argc, char *argv[]) {
     zip_uint64_t idx;
@@ -931,6 +942,7 @@
     { "get_file_comment", 1, "index", "get file comment", get_file_comment },
     { "get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries },
     { "name_locate", 2, "name flags", "find entry in archive", name_locate },
+    { "print_progress", 0, "", "print progress during zip_close()", print_progress },
     { "rename", 2, "index name", "rename entry", zrename },
     { "replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents },
     { "set_archive_comment", 1, "comment", "set archive comment", set_archive_comment },