Imported Upstream version 2.6.1p1
[debian/amanda] / recover-src / extract_list.c
index 67c02d1bd10325a8c5ee358ef6fbeb61952ee95e..43b27a27dfb57f50973e1c4986b47dabeb7b5191 100644 (file)
 #include "findpass.h"
 #endif
 #include "util.h"
-#include "clientconf.h"
+#include "conffile.h"
 #include "protocol.h"
 #include "event.h"
+#include "client_util.h"
 #include "security.h"
 
 typedef struct EXTRACT_LIST_ITEM {
@@ -83,7 +84,6 @@ char *amidxtaped_client_get_security_conf(char *, void *);
 static char *dump_device_name = NULL;
 static char *errstr;
 static char *amidxtaped_line = NULL;
-
 extern char *localhost;
 
 /* global pid storage for interrupt handler */
@@ -92,9 +92,7 @@ pid_t extract_restore_child_pid = -1;
 static EXTRACT_LIST *extract_list = NULL;
 static const security_driver_t *amidxtaped_secdrv;
 
-#ifdef SAMBA_CLIENT
 unsigned short samba_extract_method = SAMBA_TAR;
-#endif /* SAMBA_CLIENT */
 
 #define READ_TIMEOUT   240*60
 
@@ -166,7 +164,7 @@ read_buffer(
     long       timeout_s)
 {
     ssize_t size = 0;
-    fd_set readset;
+    SELECT_ARG_TYPE readset;
     struct timeval timeout;
     char *dataptr;
     ssize_t spaceleft;
@@ -188,7 +186,7 @@ read_buffer(
         nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
         if(nfound < 0 ) {
             /* Select returned an error. */
-           fprintf(stderr,"select error: %s\n", strerror(errno));
+           g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
             size = -1;
            break;
         }
@@ -197,8 +195,8 @@ read_buffer(
             /* Select timed out. */
             if (timeout_s != 0)  {
                 /* Not polling: a real read timeout */
-                fprintf(stderr,"timeout waiting for restore\n");
-                fprintf(stderr,"increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n");
+                g_fprintf(stderr,_("timeout waiting for restore\n"));
+                g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
             }
             errno = ETIMEDOUT;
             size = -1;
@@ -215,7 +213,7 @@ read_buffer(
                continue;
            }
            if (errno != EPIPE) {
-               fprintf(stderr, "read_buffer: read error - %s",
+               g_fprintf(stderr, _("read_buffer: read error - %s"),
                    strerror(errno));
                break;
            }
@@ -364,8 +362,8 @@ clean_tape_list(
            }
 
            if (remove_fn2) {
-               dbprintf(("removing path %s, it is included in %s\n",
-                         fn2->path, fn1->path));
+               dbprintf(_("removing path %s, it is included in %s\n"),
+                         fn2->path, fn1->path);
                ofn2 = fn2;
                fn2 = fn2->next;
                amfree(ofn2->path);
@@ -379,8 +377,8 @@ clean_tape_list(
 
        if(remove_fn1 != 0) {
            /* fn2->path is always valid */
-           /*@i@*/ dbprintf(("removing path %s, it is included in %s\n",
-           /*@i@*/           fn1->path, fn2->path));
+           /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"),
+           /*@i@*/           fn1->path, fn2->path);
            ofn1 = fn1;
            fn1 = fn1->next;
            amfree(ofn1->path);
@@ -450,7 +448,7 @@ do_unlink_list(void)
 
     for (ul = unlink_list; ul != NULL; ul = ul->next) {
        if (unlink(ul->path) < 0) {
-           fprintf(stderr,"Can't unlink %s: %s\n", ul->path, strerror(errno));
+           g_fprintf(stderr,_("Can't unlink %s: %s\n"), ul->path, strerror(errno));
            ret = 0;
        }
     }
@@ -500,14 +498,14 @@ check_file_overwrite(
                if (lstat(path, &stat_buf) == 0) {
                    if(!S_ISDIR(stat_buf.st_mode)) {
                        if (add_to_unlink_list(path)) {
-                           printf("WARNING: %s is not a directory, "
-                                  "it will be deleted.\n",
+                           g_printf(_("WARNING: %s is not a directory, "
+                                  "it will be deleted.\n"),
                                   path);
                        }
                    }
                }
                else if (errno != ENOENT) {
-                   printf("Can't stat %s: %s\n", path, strerror(errno));
+                   g_printf(_("Can't stat %s: %s\n"), path, strerror(errno));
                }
                *s = '/';
                s++;
@@ -524,20 +522,20 @@ check_file_overwrite(
            if (lstat(filename, &stat_buf) == 0) {
                if(S_ISDIR(stat_buf.st_mode)) {
                    if(!is_empty_dir(filename)) {
-                       printf("WARNING: All existing files in %s "
-                              "will be deleted.\n", filename);
+                       g_printf(_("WARNING: All existing files in %s "
+                              "will be deleted.\n"), filename);
                    }
                } else if(S_ISREG(stat_buf.st_mode)) {
-                   printf("WARNING: Existing file %s will be overwritten\n",
+                   g_printf(_("WARNING: Existing file %s will be overwritten\n"),
                           filename);
                } else {
                    if (add_to_unlink_list(filename)) {
-                       printf("WARNING: Existing entry %s will be deleted\n",
+                       g_printf(_("WARNING: Existing entry %s will be deleted\n"),
                               filename);
                    }
                }
            } else if (errno != ENOENT) {
-               printf("Can't stat %s: %s\n", filename, strerror(errno));
+               g_printf(_("Can't stat %s: %s\n"), filename, strerror(errno));
            }
            amfree(filename);
        }
@@ -691,9 +689,9 @@ add_glob(
     char *uqglob = unquote_string(glob);
  
     regex = glob_to_regex(uqglob);
-    dbprintf(("add_glob (%s) -> %s\n", uqglob, regex));
+    dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex);
     if ((s = validate_regexp(regex)) != NULL) {
-       printf("%s is not a valid shell wildcard pattern: ", glob);
+       g_printf(_("%s is not a valid shell wildcard pattern: "), glob);
        puts(s);
     } else {
         /*
@@ -721,7 +719,7 @@ add_regex(
     char *uqregex = unquote_string(regex);
  
     if ((s = validate_regexp(uqregex)) != NULL) {
-       printf("\"%s\" is not a valid regular expression: ", regex);
+       g_printf(_("\"%s\" is not a valid regular expression: "), regex);
        puts(s);
     } else {
         add_file(uqregex, regex);
@@ -736,13 +734,13 @@ add_file(
 {
     DIR_ITEM *ditem, lditem;
     char *path_on_disk = NULL;
-    char *path_on_disk_slash = NULL;
     char *cmd = NULL;
     char *err = NULL;
     int i;
     ssize_t j;
     char *dir, *dir_undo, dir_undo_ch = '\0';
     char *ditem_path = NULL;
+    char *qditem_path = NULL;
     char *l = NULL;
     int  added;
     char *s, *fp, *quoted;
@@ -751,18 +749,17 @@ add_file(
     int dir_entries;
 
     if (disk_path == NULL) {
-       printf("Must select directory before adding files\n");
+       g_printf(_("Must select directory before adding files\n"));
        return;
     }
     memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
 
-    dbprintf(("add_file: Looking for \"%s\"\n", regex));
+    dbprintf(_("add_file: Looking for \"%s\"\n"), regex);
 
     if(strcmp(regex, "/[/]*$") == 0) { /* "/" behave like "." */
        regex = "\\.[/]*$";
     }
     else if(strcmp(regex, "[^/]*[/]*$") == 0) {                /* "*" */
-       //regex = 
        regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
     } else {
        /* remove "/" at end of path */
@@ -786,10 +783,8 @@ add_file(
        amfree(clean_disk_path);
     }
 
-    path_on_disk_slash = stralloc2(path_on_disk, "/");
-
-    dbprintf(("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n",
-             regex, path_on_disk));
+    dbprintf(_("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
+             regex, path_on_disk);
 
     found_one = 0;
     dir_entries = 0;
@@ -797,10 +792,9 @@ add_file(
     {
        dir_entries++;
        quoted = quote_string(ditem->path);
-       dbprintf(("add_file: Pondering ditem->path=%s\n", quoted));
+       dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted);
        amfree(quoted);
-       if (match(path_on_disk, ditem->path)
-           || match(path_on_disk_slash, ditem->path))
+       if (match(path_on_disk, ditem->path))
        {
            found_one = 1;
            j = (ssize_t)strlen(ditem->path);
@@ -810,12 +804,13 @@ add_file(
                ditem_path = newstralloc(ditem_path, ditem->path);
                clean_pathname(ditem_path);
 
-               cmd = stralloc2("ORLD ", ditem_path);
+               qditem_path = quote_string(ditem_path);
+               cmd = newstralloc2(cmd, "ORLD ", qditem_path);
+               amfree(qditem_path);
                if(send_command(cmd) == -1) {
                    amfree(cmd);
                    amfree(ditem_path);
                    amfree(path_on_disk);
-                   amfree(path_on_disk_slash);
                    exit(1);
                }
                amfree(cmd);
@@ -824,15 +819,13 @@ add_file(
                if ((i = get_reply_line()) == -1) {
                    amfree(ditem_path);
                    amfree(path_on_disk);
-                   amfree(path_on_disk_slash);
                    exit(1);
                }
                if(i==0) {              /* assume something wrong */
                    amfree(ditem_path);
                    amfree(path_on_disk);
-                   amfree(path_on_disk_slash);
                    l = reply_line();
-                   printf("%s\n", l);
+                   g_printf("%s\n", l);
                    return;
                }
                dir_undo = NULL;
@@ -844,7 +837,6 @@ add_file(
                    if (i == -1) {
                        amfree(ditem_path);
                        amfree(path_on_disk);
-                       amfree(path_on_disk_slash);
                        exit(1);
                    }
                    if(err) {
@@ -860,18 +852,17 @@ add_file(
                        puts(l);
                        continue;
                    }
-#define sc "201-"
-                   if(strncmp(l, sc, sizeof(sc)-1) != 0) {
-                       err = "bad reply: not 201-";
+
+                   s = l;
+                   if(strncmp_const_skip(l, "201-", s, ch) != 0) {
+                       err = _("bad reply: not 201-");
                        continue;
                    }
-
-                   s = l + sizeof(sc)-1;
                    ch = *s++;
-#undef sc
+
                    skip_whitespace(s, ch);
                    if(ch == '\0') {
-                       err = "bad reply: missing date field";
+                       err = _("bad reply: missing date field");
                        continue;
                    }
                     fp = s-1;
@@ -882,14 +873,14 @@ add_file(
 
                    skip_whitespace(s, ch);
                    if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
-                       err = "bad reply: cannot parse level field";
+                       err = _("bad reply: cannot parse level field");
                        continue;
                    }
                    skip_integer(s, ch);
 
                    skip_whitespace(s, ch);
                    if(ch == '\0') {
-                       err = "bad reply: missing tape field";
+                       err = _("bad reply: missing tape field");
                        continue;
                    }
                     fp = s-1;
@@ -899,18 +890,20 @@ add_file(
                     s[-1] = (char)ch;
 
                    if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
+                       long long fileno_ = (long long)0;
                        skip_whitespace(s, ch);
-                       if(ch == '\0' || sscanf(s - 1, OFF_T_FMT,
-                               (OFF_T_FMT_TYPE *)&lditem.fileno) != 1) {
-                           err = "bad reply: cannot parse fileno field";
+                       if(ch == '\0' ||
+                          sscanf(s - 1, "%lld", &fileno_) != 1) {
+                           err = _("bad reply: cannot parse fileno field");
                            continue;
                        }
+                       lditem.fileno = (off_t)fileno_;
                        skip_integer(s, ch);
                    }
 
                    skip_whitespace(s, ch);
                    if(ch == '\0') {
-                       err = "bad reply: missing directory field";
+                       err = _("bad reply: missing directory field");
                        continue;
                    }
                    dir = s - 1;
@@ -921,16 +914,16 @@ add_file(
 
                    switch(add_extract_item(&lditem)) {
                    case -1:
-                       printf("System error\n");
-                       dbprintf(("add_file: (Failed) System error\n"));
+                       g_printf(_("System error\n"));
+                       dbprintf(_("add_file: (Failed) System error\n"));
                        break;
 
                    case  0:
                        quoted = quote_string(lditem.path);
-                       printf("Added dir %s at date %s\n",
+                       g_printf(_("Added dir %s at date %s\n"),
                               quoted, lditem.date);
-                       dbprintf(("add_file: (Successful) Added dir %s at date %s\n",
-                                 quoted, lditem.date));
+                       dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"),
+                                 quoted, lditem.date);
                        amfree(quoted);
                        added=1;
                        break;
@@ -948,8 +941,8 @@ add_file(
                        puts(cmd);
                } else if(added == 0) {
                    quoted = quote_string(ditem_path);
-                   printf("dir %s already added\n", quoted);
-                   dbprintf(("add_file: dir %s already added\n", quoted));
+                   g_printf(_("dir %s already added\n"), quoted);
+                   dbprintf(_("add_file: dir %s already added\n"), quoted);
                    amfree(quoted);
                }
            }
@@ -957,21 +950,21 @@ add_file(
            {
                switch(add_extract_item(ditem)) {
                case -1:
-                   printf("System error\n");
-                   dbprintf(("add_file: (Failed) System error\n"));
+                   g_printf(_("System error\n"));
+                   dbprintf(_("add_file: (Failed) System error\n"));
                    break;
 
                case  0:
                    quoted = quote_string(ditem->path);
-                   printf("Added file %s\n", quoted);
-                   dbprintf(("add_file: (Successful) Added %s\n", quoted));
+                   g_printf(_("Added file %s\n"), quoted);
+                   dbprintf(_("add_file: (Successful) Added %s\n"), quoted);
                    amfree(quoted);
                    break;
 
                case  1:
                    quoted = quote_string(ditem->path);
-                   printf("File %s already added\n", quoted);
-                   dbprintf(("add_file: file %s already added\n", quoted));
+                   g_printf(_("File %s already added\n"), quoted);
+                   dbprintf(_("add_file: file %s already added\n"), quoted);
                    amfree(quoted);
                }
            }
@@ -981,7 +974,6 @@ add_file(
     amfree(cmd);
     amfree(ditem_path);
     amfree(path_on_disk);
-    amfree(path_on_disk_slash);
 
     amfree(lditem.path);
     amfree(lditem.date);
@@ -989,9 +981,9 @@ add_file(
 
     if(! found_one) {
        quoted = quote_string(path);
-       printf("File %s doesn't exist in directory\n", quoted);
-       dbprintf(("add_file: (Failed) File %s doesn't exist in directory\n",
-                 quoted));
+       g_printf(_("File %s doesn't exist in directory\n"), quoted);
+       dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"),
+                 quoted);
        amfree(quoted);
     }
 }
@@ -1007,9 +999,9 @@ delete_glob(
     char *uqglob = unquote_string(glob);
  
     regex = glob_to_regex(uqglob);
-    dbprintf(("delete_glob (%s) -> %s\n", uqglob, regex));
+    dbprintf(_("delete_glob (%s) -> %s\n"), uqglob, regex);
     if ((s = validate_regexp(regex)) != NULL) {
-       printf("\"%s\" is not a valid shell wildcard pattern: ", glob);
+       g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
        puts(s);
     } else {
         /*
@@ -1037,7 +1029,7 @@ delete_regex(
     char *uqregex = unquote_string(regex);
 
     if ((s = validate_regexp(regex)) != NULL) {
-       printf("\"%s\" is not a valid regular expression: ", regex);
+       g_printf(_("\"%s\" is not a valid regular expression: "), regex);
        puts(s);
     } else {
        delete_file(uqregex, uqregex);
@@ -1052,7 +1044,6 @@ delete_file(
 {
     DIR_ITEM *ditem, lditem;
     char *path_on_disk = NULL;
-    char *path_on_disk_slash = NULL;
     char *cmd = NULL;
     char *err = NULL;
     int i;
@@ -1063,6 +1054,7 @@ delete_file(
     int  level = 0;
     off_t fileno;
     char *ditem_path = NULL;
+    char *qditem_path;
     char *l = NULL;
     int  deleted;
     char *s;
@@ -1071,12 +1063,12 @@ delete_file(
     char *quoted;
 
     if (disk_path == NULL) {
-       printf("Must select directory before deleting files\n");
+       g_printf(_("Must select directory before deleting files\n"));
        return;
     }
     memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
 
-    dbprintf(("delete_file: Looking for \"%s\"\n", path));
+    dbprintf(_("delete_file: Looking for \"%s\"\n"), path);
 
     if (strcmp(regex, "[^/]*[/]*$") == 0) {
        /* Looking for * find everything but single . */
@@ -1107,18 +1099,15 @@ delete_file(
        amfree(clean_disk_path);
     }
 
-    path_on_disk_slash = stralloc2(path_on_disk, "/");
-
-    dbprintf(("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n",
-             regex, path_on_disk));
+    dbprintf(_("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
+             regex, path_on_disk);
     found_one = 0;
     for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
     {
        quoted = quote_string(ditem->path);
-       dbprintf(("delete_file: Pondering ditem->path=%s\n", quoted));
+       dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted);
        amfree(quoted);
-       if (match(path_on_disk, ditem->path)
-           || match(path_on_disk_slash, ditem->path))
+       if (match(path_on_disk, ditem->path))
        {
            found_one = 1;
            j = (ssize_t)strlen(ditem->path);
@@ -1128,12 +1117,13 @@ delete_file(
                ditem_path = newstralloc(ditem_path, ditem->path);
                clean_pathname(ditem_path);
 
-               cmd = stralloc2("ORLD ", ditem_path);
+               qditem_path = quote_string(ditem_path);
+               cmd = newstralloc2(cmd, "ORLD ", qditem_path);
+               amfree(qditem_path);
                if(send_command(cmd) == -1) {
                    amfree(cmd);
                    amfree(ditem_path);
                    amfree(path_on_disk);
-                   amfree(path_on_disk_slash);
                    exit(1);
                }
                amfree(cmd);
@@ -1141,16 +1131,14 @@ delete_file(
                if ((i = get_reply_line()) == -1) {
                    amfree(ditem_path);
                    amfree(path_on_disk);
-                   amfree(path_on_disk_slash);
                    exit(1);
                }
                if(i==0)                /* assume something wrong */
                {
                    amfree(ditem_path);
                    amfree(path_on_disk);
-                   amfree(path_on_disk_slash);
                    l = reply_line();
-                   printf("%s\n", l);
+                   g_printf("%s\n", l);
                    return;
                }
                deleted=0;
@@ -1163,7 +1151,6 @@ delete_file(
                    if (i == -1) {
                        amfree(ditem_path);
                        amfree(path_on_disk);
-                       amfree(path_on_disk_slash);
                        exit(1);
                    }
                    if(err) {
@@ -1180,17 +1167,17 @@ delete_file(
                        puts(l);
                        continue;
                    }
-#define sc "201-"
-                   if(strncmp(l, sc, sizeof(sc)-1) != 0) {
-                       err = "bad reply: not 201-";
+
+                   s = l;
+                   if(strncmp_const_skip(l, "201-", s, ch) != 0) {
+                       err = _("bad reply: not 201-");
                        continue;
                    }
-                   s = l + sizeof(sc)-1;
                    ch = *s++;
-#undef sc
+
                    skip_whitespace(s, ch);
                    if(ch == '\0') {
-                       err = "bad reply: missing date field";
+                       err = _("bad reply: missing date field");
                        continue;
                    }
                    date = s - 1;
@@ -1199,14 +1186,14 @@ delete_file(
 
                    skip_whitespace(s, ch);
                    if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
-                       err = "bad reply: cannot parse level field";
+                       err = _("bad reply: cannot parse level field");
                        continue;
                    }
                    skip_integer(s, ch);
 
                    skip_whitespace(s, ch);
                    if(ch == '\0') {
-                       err = "bad reply: missing tape field";
+                       err = _("bad reply: missing tape field");
                        continue;
                    }
                    tape = s - 1;
@@ -1216,18 +1203,20 @@ delete_file(
                    *tape_undo = '\0';
 
                    if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
+                       long long fileno_ = (long long)0;
                        skip_whitespace(s, ch);
-                       if(ch == '\0' || sscanf(s - 1, OFF_T_FMT,
-                               (OFF_T_FMT_TYPE *)&fileno) != 1) {
-                           err = "bad reply: cannot parse fileno field";
+                       if(ch == '\0' ||
+                          sscanf(s - 1, "%lld", &fileno_) != 1) {
+                           err = _("bad reply: cannot parse fileno field");
                            continue;
                        }
+                       fileno = (off_t)fileno_;
                        skip_integer(s, ch);
                    }
 
                    skip_whitespace(s, ch);
                    if(ch == '\0') {
-                       err = "bad reply: missing directory field";
+                       err = _("bad reply: missing directory field");
                        continue;
                    }
                    skip_non_whitespace(s, ch);
@@ -1240,13 +1229,13 @@ delete_file(
                     lditem.tape = newstralloc(lditem.tape, tape);
                    switch(delete_extract_item(&lditem)) {
                    case -1:
-                       printf("System error\n");
-                       dbprintf(("delete_file: (Failed) System error\n"));
+                       g_printf(_("System error\n"));
+                       dbprintf(_("delete_file: (Failed) System error\n"));
                        break;
                    case  0:
-                       printf("Deleted dir %s at date %s\n", ditem_path, date);
-                       dbprintf(("delete_file: (Successful) Deleted dir %s at date %s\n",
-                                 ditem_path, date));
+                       g_printf(_("Deleted dir %s at date %s\n"), ditem_path, date);
+                       dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"),
+                                 ditem_path, date);
                        deleted=1;
                        break;
                    case  1:
@@ -1261,29 +1250,29 @@ delete_file(
                    if (cmd)
                        puts(cmd);
                } else if(deleted == 0) {
-                   printf("Warning - dir '%s' not on tape list\n",
+                   g_printf(_("Warning - dir '%s' not on tape list\n"),
                           ditem_path);
-                   dbprintf(("delete_file: dir '%s' not on tape list\n",
-                             ditem_path));
+                   dbprintf(_("delete_file: dir '%s' not on tape list\n"),
+                             ditem_path);
                }
            }
            else
            {
                switch(delete_extract_item(ditem)) {
                case -1:
-                   printf("System error\n");
-                   dbprintf(("delete_file: (Failed) System error\n"));
+                   g_printf(_("System error\n"));
+                   dbprintf(_("delete_file: (Failed) System error\n"));
                    break;
                case  0:
-                   printf("Deleted %s\n", ditem->path);
-                   dbprintf(("delete_file: (Successful) Deleted %s\n",
-                             ditem->path));
+                   g_printf(_("Deleted %s\n"), ditem->path);
+                   dbprintf(_("delete_file: (Successful) Deleted %s\n"),
+                             ditem->path);
                    break;
                case  1:
-                   printf("Warning - file '%s' not on tape list\n",
+                   g_printf(_("Warning - file '%s' not on tape list\n"),
                           ditem->path);
-                   dbprintf(("delete_file: file '%s' not on tape list\n",
-                             ditem->path));
+                   dbprintf(_("delete_file: file '%s' not on tape list\n"),
+                             ditem->path);
                    break;
                }
            }
@@ -1292,12 +1281,11 @@ delete_file(
     amfree(cmd);
     amfree(ditem_path);
     amfree(path_on_disk);
-    amfree(path_on_disk_slash);
 
     if(! found_one) {
-       printf("File %s doesn't exist in directory\n", path);
-       dbprintf(("delete_file: (Failed) File %s doesn't exist in directory\n",
-                 path));
+       g_printf(_("File %s doesn't exist in directory\n"), path);
+       dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"),
+                 path);
     }
 }
 
@@ -1327,7 +1315,7 @@ display_extract_list(
        pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
        if ((fp = popen(pager_command, "w")) == NULL)
        {
-           printf("Warning - can't pipe through %s\n", pager);
+           g_printf(_("Warning - can't pipe through %s\n"), pager);
            fp = stdout;
        }
        amfree(pager_command);
@@ -1337,7 +1325,7 @@ display_extract_list(
        uqfile = unquote_string(file);
        if ((fp = fopen(uqfile, "w")) == NULL)
        {
-           printf("Can't open file %s to print extract list into\n", file);
+           g_printf(_("Can't open file %s to print extract list into\n"), file);
            amfree(uqfile);
            return;
        }
@@ -1346,16 +1334,16 @@ display_extract_list(
 
     for (this = extract_list; this != NULL; this = this->next)
     {
-       fprintf(fp, "TAPE %s LEVEL %d DATE %s\n",
+       g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"),
                this->tape, this->level, this->date);
        for (that = this->files; that != NULL; that = that->next)
-           fprintf(fp, "\t%s\n", that->path);
+           g_fprintf(fp, "\t%s\n", that->path);
     }
 
     if (file == NULL) {
        apclose(fp);
     } else {
-       printf("Extract list written to file %s\n", file);
+       g_printf(_("Extract list written to file %s\n"), file);
        afclose(fp);
     }
 }
@@ -1403,20 +1391,20 @@ okay_to_continue(
     char *line = NULL;
     char *s;
     char *prompt;
-    int get_tape;
+    int get_device;
 
-    get_tape = 0;
+    get_device = 0;
     while (ret < 0) {
-       if (get_tape) {
-           prompt = "New tape device [?]: ";
+       if (get_device) {
+           prompt = _("New device name [?]: ");
        } else if (allow_tape && allow_skip) {
-           prompt = "Continue [?/Y/n/s/t]? ";
+           prompt = _("Continue [?/Y/n/s/d]? ");
        } else if (allow_tape && !allow_skip) {
-           prompt = "Continue [?/Y/n/t]? ";
+           prompt = _("Continue [?/Y/n/d]? ");
        } else if (allow_retry) {
-           prompt = "Continue [?/Y/n/r]? ";
+           prompt = _("Continue [?/Y/n/r]? ");
        } else {
-           prompt = "Continue [?/Y/n]? ";
+           prompt = _("Continue [?/Y/n]? ");
        }
        fputs(prompt, stdout);
        fflush(stdout); fflush(stderr);
@@ -1424,40 +1412,53 @@ okay_to_continue(
        if ((line = agets(stdin)) == NULL) {
            putchar('\n');
            clearerr(stdin);
-           if (get_tape) {
-               get_tape = 0;
+           if (get_device) {
+               get_device = 0;
                continue;
            }
            ret = 0;
            break;
        }
+       dbprintf("User prompt: '%s'; response: '%s'\n", prompt, line);
+
        s = line;
-       while ((ch = *s++) != '\0' && isspace(ch)) {
+       while ((ch = *s++) != '\0' && g_ascii_isspace(ch)) {
            (void)ch;   /* Quiet empty loop compiler warning */
        }
        if (ch == '?') {
-           if (get_tape) {
-               printf("Enter a new device ([host:]device) or \"default\"\n");
+           if (get_device) {
+               g_printf(_("Enter a new device name or \"default\"\n"));
            } else {
-               printf("Enter \"y\"es to continue, \"n\"o to stop");
+               g_printf(_("Enter \"y\"es to continue, \"n\"o to stop"));
                if(allow_skip) {
-                   printf(", \"s\"kip this tape");
+                   g_printf(_(", \"s\"kip this tape"));
                }
                if(allow_retry) {
-                   printf(" or \"r\"etry this tape");
+                   g_printf(_(" or \"r\"etry this tape"));
                }
                if (allow_tape) {
-                   printf(" or \"t\"ape to change tape drives");
+                   g_printf(_(" or \"d\" to change to a new device"));
                }
                putchar('\n');
            }
-       } else if (get_tape) {
-           set_tape(s - 1);
-           get_tape = 0;
+       } else if (get_device) {
+           char *tmp = stralloc(tape_server_name);
+
+           if (strncmp_const(s - 1, "default") == 0) {
+               set_device(tmp, NULL); /* default device, existing host */
+           } else if (s[-1] != '\0') {
+               set_device(tmp, s - 1); /* specified device, existing host */
+           } else {
+               g_printf(_("No change.\n"));
+           }
+
+           amfree(tmp);
+
+           get_device = 0;
        } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
            ret = 1;
-       } else if (allow_tape && (ch == 'T' || ch == 't')) {
-           get_tape = 1;
+       } else if (allow_tape && (ch == 'D' || ch == 'd' || ch == 'T' || ch == 't')) {
+           get_device = 1; /* ('T' and 't' are for backward-compatibility) */
        } else if (ch == 'N' || ch == 'n') {
            ret = 0;
        } else if (allow_retry && (ch == 'R' || ch == 'r')) {
@@ -1481,7 +1482,7 @@ send_to_tape_server(
 
     if (security_stream_write(stream, msg, strlen(msg)) < 0)
     {
-       error("Error writing to tape server");
+       error(_("Error writing to tape server"));
        exit(101);
        /*NOTREACHED*/
     }
@@ -1506,7 +1507,7 @@ extract_files_setup(
 
     amidxtaped_secdrv = security_getdriver(authopt);
     if (amidxtaped_secdrv == NULL) {
-       error("no '%s' security driver available for host '%s'",
+       error(_("no '%s' security driver available for host '%s'"),
              authopt, tape_server_name);
     }
 
@@ -1518,7 +1519,7 @@ extract_files_setup(
                                "auth=", authopt, ";",
                    "\n", NULL);
     protocol_sendreq(tape_server_name, amidxtaped_secdrv,
-                    amidxtaped_client_get_security_conf, req, STARTUP_TIMEOUT,
+                    generic_client_get_security_conf, req, STARTUP_TIMEOUT,
                     amidxtaped_response, &response_error);
     amfree(req);
     protocol_run();
@@ -1589,10 +1590,10 @@ extract_files_setup(
        tt = newstralloc2(tt, "FEATURES=", our_features_string);
        send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
        get_amidxtaped_line();
-       if(strncmp(amidxtaped_line,"FEATURES=",9) == 0) {
+       if(strncmp_const(amidxtaped_line,"FEATURES=") == 0) {
            tapesrv_features = am_string_to_feature(amidxtaped_line+9);
        } else {
-           fprintf(stderr, "amrecover - expecting FEATURES line from amidxtaped\n");
+           g_fprintf(stderr, _("amrecover - expecting FEATURES line from amidxtaped\n"));
            stop_amidxtaped();
            amfree(disk_regex);
            amfree(host_regex);
@@ -1610,7 +1611,7 @@ extract_files_setup(
        am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
 
        if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
-           tt = newstralloc2(tt, "CONFIG=", config);
+           tt = newstralloc2(tt, "CONFIG=", get_config_name());
            send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
        }
        if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
@@ -1620,7 +1621,7 @@ extract_files_setup(
        }
        if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
            char v_fsf[100];
-           snprintf(v_fsf, 99, OFF_T_FMT, (OFF_T_FMT_TYPE)fsf);
+           g_snprintf(v_fsf, 99, "%lld", (long long)fsf);
            tt = newstralloc2(tt, "FSF=",v_fsf);
            send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
        }
@@ -1654,8 +1655,8 @@ extract_files_setup(
        send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex);
        send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp);
 
-       dbprintf(("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n",
-                 dump_device_name, host_regex, disk_regex, clean_datestamp));
+       dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"),
+                 dump_device_name, host_regex, disk_regex, clean_datestamp);
     }
 
     amfree(disk_regex);
@@ -1680,16 +1681,17 @@ read_file_header(
     ssize_t bytes_read;
     bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
     if(bytes_read < 0) {
-       error("error reading header (%s), check amidxtaped.*.debug on server",
+       error(_("error reading header (%s), check amidxtaped.*.debug on server"),
              strerror(errno));
        /*NOTREACHED*/
     }
 
     if((size_t)bytes_read < buflen) {
-       fprintf(stderr, "%s: short block %d byte%s\n",
-               get_pname(), (int)bytes_read, (bytes_read == 1) ? "" : "s");
+       g_fprintf(stderr, plural(_("%s: short block %d byte\n"),
+                              _("%s: short block %d bytes\n"), bytes_read),
+               get_pname(), (int)bytes_read);
        print_header(stdout, file);
-       error("Can't read file header");
+       error(_("Can't read file header"));
        /*NOTREACHED*/
     }
 
@@ -1703,7 +1705,8 @@ enum dumptypes {
        IS_GNUTAR,
        IS_TAR,
        IS_SAMBA,
-       IS_SAMBA_TAR
+       IS_SAMBA_TAR,
+       IS_APPLICATION_API
 };
 
 static void
@@ -1726,6 +1729,8 @@ extract_files_child(
 #ifdef SAMBA_CLIENT
     char *domain = NULL, *smbpass = NULL;
 #endif
+    backup_support_option_t *bsu;
+    GPtrArray              *errarray;
 
     /* code executed by child to do extraction */
     /* never returns */
@@ -1733,7 +1738,7 @@ extract_files_child(
     /* make in_fd be our stdin */
     if (dup2(in_fd, STDIN_FILENO) == -1)
     {
-       error("dup2 failed in extract_files_child: %s", strerror(errno));
+       error(_("dup2 failed in extract_files_child: %s"), strerror(errno));
        /*NOTREACHED*/
     }
 
@@ -1743,11 +1748,13 @@ extract_files_child(
 
     if(file.type != F_DUMPFILE) {
        print_header(stdout, &file);
-       error("bad header");
+       error(_("bad header"));
        /*NOTREACHED*/
     }
 
     if (file.program != NULL) {
+       if (strcmp(file.program, "APPLICATION") == 0)
+           dumptype = IS_APPLICATION_API;
 #ifdef GNUTAR
        if (strcmp(file.program, GNUTAR) == 0)
            dumptype = IS_GNUTAR;
@@ -1800,8 +1807,22 @@ extract_files_child(
        }
 #endif
        break;
+    case IS_APPLICATION_API:
+       extra_params = 12;
+       if (dump_dle) {
+           GSList   *scriptlist;
+           script_t *script;
+           extra_params += application_property_argv_size(dump_dle);
+           for (scriptlist = dump_dle->scriptlist; scriptlist != NULL;
+                scriptlist = scriptlist->next) {
+               script = (script_t *)scriptlist->data;
+               if (script->result && script->result->proplist) {
+                   extra_params += property_argv_size(script->result->proplist);
+               }
+           }
+       }
+       break;
     }
-
     restore_args = (char **)alloc((size_t)((extra_params + files_off_tape + 1)
                                  * sizeof(char *)));
     switch(dumptype) {
@@ -1862,11 +1883,58 @@ extract_files_child(
         restore_args[j++] = stralloc("-");     /* data on stdin */
        }
 #endif
+       break;
+    case IS_APPLICATION_API:
+       {
+           g_option_t g_options;
+           g_options.config = get_config_name();
+           g_options.hostname = dump_hostname;
+           if (dump_dle) {
+               bsu = backup_support_option(file.application, &g_options,
+                                           file.disk, dump_dle->device,
+                                           &errarray);
+           } else {
+               bsu = backup_support_option(file.application, &g_options,
+                                           file.disk, NULL,
+                                           &errarray);
+           }
+       }
+       restore_args[j++] = stralloc(file.application);
+       restore_args[j++] = stralloc("restore");
+       restore_args[j++] = stralloc("--config");
+       restore_args[j++] = stralloc(get_config_name());
+       restore_args[j++] = stralloc("--disk");
+       restore_args[j++] = stralloc(file.disk);
+       if (dump_dle && dump_dle->device) {
+           restore_args[j++] = stralloc("--device");
+           restore_args[j++] = stralloc(dump_dle->device);
+       }
+       if (bsu->smb_recover_mode && samba_extract_method == SAMBA_SMBCLIENT){
+           restore_args[j++] = "--recover-mode";
+           restore_args[j++] = "smb";
+       }
+       if (dump_dle) {
+           GSList   *scriptlist;
+           script_t *script;
+
+           j += application_property_add_to_argv(&restore_args[j], dump_dle, NULL);
+           for (scriptlist = dump_dle->scriptlist; scriptlist != NULL;
+                scriptlist = scriptlist->next) {
+               script = (script_t *)scriptlist->data;
+               if (script->result && script->result->proplist) {
+                   j += property_add_to_argv(&restore_args[j],
+                                             script->result->proplist);
+               }
+           }
+
+       }
+       break;
     }
   
     for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next)
     {
        switch (dumptype) {
+       case IS_APPLICATION_API:
        case IS_TAR:
        case IS_GNUTAR:
        case IS_SAMBA_TAR:
@@ -1891,6 +1959,7 @@ extract_files_child(
            {
            restore_args[j++] = stralloc(fn->path);
            }
+           break;
        }
     }
 #if defined(XFSDUMP)
@@ -1913,7 +1982,7 @@ extract_files_child(
     case IS_GNUTAR:
     case IS_SAMBA_TAR:
 #ifndef GNUTAR
-       fprintf(stderr, "warning: GNUTAR program not available.\n");
+       g_fprintf(stderr, _("warning: GNUTAR program not available.\n"));
        cmd = stralloc("tar");
 #else
        cmd = stralloc(GNUTAR);
@@ -1943,19 +2012,24 @@ extract_files_child(
        }
 #endif
        if (cmd == NULL) {
-           fprintf(stderr, "warning: restore program for %s not available.\n",
+           g_fprintf(stderr, _("warning: restore program for %s not available.\n"),
                    file.program);
            cmd = stralloc("restore");
        }
+       break;
+    case IS_APPLICATION_API:
+       cmd = vstralloc(APPLICATION_DIR, "/", file.application, NULL);
+       break;
     }
     if (cmd) {
-        dbprintf(("Exec'ing %s with arguments:\n", cmd));
+        dbprintf(_("Exec'ing %s with arguments:\n"), cmd);
        for (i = 0; i < j; i++) {
            if( i == passwd_field)
-               dbprintf(("\tXXXXX\n"));
+               dbprintf("\tXXXXX\n");
            else
-               dbprintf(("\t%s\n", restore_args[i]));
+               dbprintf(_("\t%s\n"), restore_args[i]);
        }
+       safe_fd(-1, 0);
         (void)execv(cmd, restore_args);
        /* only get here if exec failed */
        save_errno = errno;
@@ -1964,14 +2038,21 @@ extract_files_child(
        }
        amfree(restore_args);
        errno = save_errno;
-        perror("amrecover couldn't exec");
-        fprintf(stderr, " problem executing %s\n", cmd);
+        perror(_("amrecover couldn't exec"));
+        g_fprintf(stderr, _(" problem executing %s\n"), cmd);
        amfree(cmd);
     }
     exit(1);
     /*NOT REACHED */
 }
 
+typedef struct ctl_data_s {
+  int           header_done;
+  int           child_pipe[2];
+  int           pid;
+  EXTRACT_LIST *elist;
+} ctl_data_t;
+
 /*
  * Interpose something between the process writing out the dump (writing it to
  * some extraction program, really) and the socket from which we're reading, so
@@ -1981,35 +2062,17 @@ int
 writer_intermediary(
     EXTRACT_LIST *     elist)
 {
-    int child_pipe[2];
-    pid_t pid;
-    amwait_t extractor_status;
+    ctl_data_t ctl_data;
+    amwait_t   extractor_status;
 
-    if(pipe(child_pipe) == -1) {
-       error("extract_list - error setting up pipe to extractor: %s\n",
-             strerror(errno));
-       /*NOTREACHED*/
-    }
-
-    /* okay, ready to extract. fork a child to do the actual work */
-    if ((pid = fork()) == 0) {
-       /* this is the child process */
-       /* never gets out of this clause */
-       aclose(child_pipe[1]);
-        extract_files_child(child_pipe[0], elist);
-       /*NOTREACHED*/
-    }
-
-    /* This is the parent */
-    if (pid == -1) {
-       printf("writer_intermediary - error forking child");
-       return -1;
-    }
-
-    aclose(child_pipe[0]);
+    ctl_data.header_done   = 0;
+    ctl_data.child_pipe[0] = -1;
+    ctl_data.child_pipe[1] = -1;
+    ctl_data.pid           = -1;
+    ctl_data.elist         = elist;
 
     security_stream_read(amidxtaped_streams[DATAFD].fd,
-                        read_amidxtaped_data, &(child_pipe[1]));
+                        read_amidxtaped_data, &ctl_data);
 
     while(get_amidxtaped_line() >= 0) {
        char desired_tape[MAX_TAPE_LABEL_BUF];
@@ -2017,7 +2080,8 @@ writer_intermediary(
        /* if prompted for a tape, relay said prompt to the user */
        if(sscanf(amidxtaped_line, "FEEDME %132s\n", desired_tape) == 1) {
            int done;
-           printf("Load tape %s now\n", desired_tape);
+           g_printf(_("Load tape %s now\n"), desired_tape);
+           dbprintf(_("Requesting tape %s from user\n"), desired_tape);
            done = okay_to_continue(am_has_feature(indexsrv_features,
                                                   fe_amrecover_feedme_tape),
                                    0, 0);
@@ -2034,10 +2098,10 @@ writer_intermediary(
                send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ERROR");
                break;
            }
-       } else if(strncmp(amidxtaped_line, "MESSAGE ", 8) == 0) {
-           printf("%s\n",&amidxtaped_line[8]);
+       } else if(strncmp_const(amidxtaped_line, "MESSAGE ") == 0) {
+           g_printf("%s\n",&amidxtaped_line[8]);
        } else {
-           fprintf(stderr, "Strange message from tape server: %s",
+           g_fprintf(stderr, _("Strange message from tape server: %s"),
                    amidxtaped_line);
            break;
        }
@@ -2045,14 +2109,21 @@ writer_intermediary(
 
     /* CTL might be close before DATA */
     event_loop(0);
-    aclose(child_pipe[1]);
+    if (ctl_data.child_pipe[1] != -1)
+       aclose(ctl_data.child_pipe[1]);
 
-    waitpid(pid, &extractor_status, 0);
-    if(WEXITSTATUS(extractor_status) != 0){
-       int ret = WEXITSTATUS(extractor_status);
-        if(ret == 255) ret = -1;
-       printf("Extractor child exited with status %d\n", ret);
-       return -1;
+    if (ctl_data.header_done == 0) {
+       g_printf(_("Got no header and data from server, check in amidxtaped.*.debug and amandad.*.debug files on server\n"));
+    }
+
+    if (ctl_data.pid != -1) {
+       waitpid(ctl_data.pid, &extractor_status, 0);
+       if(WEXITSTATUS(extractor_status) != 0){
+           int ret = WEXITSTATUS(extractor_status);
+            if(ret == 255) ret = -1;
+           g_printf(_("Extractor child exited with status %d\n"), ret);
+           return -1;
+       }
     }
     return(0);
 }
@@ -2080,15 +2151,18 @@ void
 extract_files(void)
 {
     EXTRACT_LIST *elist;
-    char cwd[STR_SIZE];
+    char * cwd;
     char *l;
     int first;
     int otc;
     tapelist_t *tlist = NULL, *a_tlist;
+    g_option_t g_options;
+    GSList *all_level = NULL;
+    int last_level;
 
     if (!is_extract_list_nonempty())
     {
-       printf("Extract list empty - No files to extract!\n");
+       g_printf(_("Extract list empty - No files to extract!\n"));
        return;
     }
 
@@ -2106,7 +2180,7 @@ extract_files(void)
        l = reply_line();
        if (!server_happy())
        {
-           printf("%s\n", l);
+           g_printf("%s\n", l);
            exit(1);
        }
        /* skip reply number */
@@ -2115,7 +2189,7 @@ extract_files(void)
 
     if (strcmp(tape_device_name, "/dev/null") == 0)
     {
-       printf("amrecover: warning: using %s as the tape device will not work\n",
+       g_printf(_("amrecover: warning: using %s as the tape device will not work\n"),
               tape_device_name);
     }
 
@@ -2123,17 +2197,17 @@ extract_files(void)
     for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
        if(elist->tape[0]!='/') {
            if(first) {
-               printf("\nExtracting files using tape drive %s on host %s.\n",
+               g_printf(_("\nExtracting files using tape drive %s on host %s.\n"),
                        tape_device_name, tape_server_name);
-               printf("The following tapes are needed:");
+               g_printf(_("The following tapes are needed:"));
                first=0;
            }
            else
-               printf("                               ");
+               g_printf("                               ");
            tlist = unmarshal_tapelist_str(elist->tape); 
            for(a_tlist = tlist ; a_tlist != NULL; a_tlist = a_tlist->next)
-               printf(" %s", a_tlist->label);
-           printf("\n");
+               g_printf(" %s", a_tlist->label);
+           g_printf("\n");
            free_tapelist(tlist);
        }
     }
@@ -2141,61 +2215,79 @@ extract_files(void)
     for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
        if(elist->tape[0]=='/') {
            if(first) {
-               printf("\nExtracting files from holding disk on host %s.\n",
+               g_printf(_("\nExtracting files from holding disk on host %s.\n"),
                        tape_server_name);
-               printf("The following files are needed:");
+               g_printf(_("The following files are needed:"));
                first=0;
            }
            else
-               printf("                               ");
+               g_printf("                               ");
            tlist = unmarshal_tapelist_str(elist->tape); 
            for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
-               printf(" %s", a_tlist->label);
-           printf("\n");
+               g_printf(" %s", a_tlist->label);
+           g_printf("\n");
            free_tapelist(tlist);
        }
     }
-    printf("\n");
+    g_printf("\n");
 
-    if (getcwd(cwd, sizeof(cwd)) == NULL) {
-       perror("extract_list: Current working directory unavailable");
+    cwd = g_get_current_dir();
+    if (cwd == NULL) {
+       perror(_("extract_list: Current working directory unavailable"));
        exit(1);
     }
 
-    printf("Restoring files into directory %s\n", cwd);
+    g_printf(_("Restoring files into directory %s\n"), cwd);
     check_file_overwrite(cwd);
 
-#ifdef SAMBA_CLIENT
     if (samba_extract_method == SAMBA_SMBCLIENT)
-      printf("(unless it is a Samba backup, that will go through to the SMB server)\n");
-#endif
-    if (!okay_to_continue(0,0,0))
+      g_printf(_("(unless it is a Samba backup, that will go through to the SMB server)\n"));
+    dbprintf(_("Checking with user before restoring into directory %s\n"), cwd);
+    if (!okay_to_continue(0,0,0)) {
+        amfree(cwd);
        return;
-    printf("\n");
+    }
+    g_printf("\n");
 
     if (!do_unlink_list()) {
-       fprintf(stderr, "Can't recover because I can't cleanup the cwd (%s)\n",
+       g_fprintf(stderr, _("Can't recover because I can't cleanup the cwd (%s)\n"),
                cwd);
+        amfree(cwd);
        return;
     }
     free_unlink_list();
 
+    g_options.config = get_config_name();
+    g_options.hostname = dump_hostname;
+    for (elist = first_tape_list(); elist != NULL;
+        elist = next_tape_list(elist)) {
+       all_level = g_slist_append(all_level, GINT_TO_POINTER(elist->level));
+    }
+    if (dump_dle) {
+       g_slist_free(dump_dle->level);
+       dump_dle->level = all_level;
+       run_client_scripts(EXECUTE_ON_PRE_RECOVER, &g_options, dump_dle,
+                          stderr);
+       dump_dle->level = NULL;
+    }
+    last_level = -1;
     while ((elist = first_tape_list()) != NULL)
     {
        if(elist->tape[0]=='/') {
            dump_device_name = newstralloc(dump_device_name, elist->tape);
-           printf("Extracting from file ");
+           g_printf(_("Extracting from file "));
            tlist = unmarshal_tapelist_str(dump_device_name); 
            for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
-               printf(" %s", a_tlist->label);
-           printf("\n");
+               g_printf(" %s", a_tlist->label);
+           g_printf("\n");
            free_tapelist(tlist);
        }
        else {
-           printf("Extracting files using tape drive %s on host %s.\n",
+           g_printf(_("Extracting files using tape drive %s on host %s.\n"),
                   tape_device_name, tape_server_name);
            tlist = unmarshal_tapelist_str(elist->tape); 
-           printf("Load tape %s now\n", tlist->label);
+           g_printf(_("Load tape %s now\n"), tlist->label);
+           dbprintf(_("Requesting tape %s from user\n"), tlist->label);
            free_tapelist(tlist);
            otc = okay_to_continue(1,1,0);
            if (otc == 0)
@@ -2208,12 +2300,31 @@ extract_files(void)
        }
        dump_datestamp = newstralloc(dump_datestamp, elist->date);
 
+       if (last_level != -1 && dump_dle) {
+           dump_dle->level = g_slist_append(dump_dle->level,
+                                            GINT_TO_POINTER(last_level));
+           dump_dle->level = g_slist_append(dump_dle->level,
+                                            GINT_TO_POINTER(elist->level));
+           run_client_scripts(EXECUTE_ON_INTER_LEVEL_RECOVER, &g_options,
+                              dump_dle, stderr);
+           g_slist_free(dump_dle->level);
+           dump_dle->level = NULL;
+       }
+
        /* connect to the tape handler daemon on the tape drive server */
        if ((extract_files_setup(elist->tape, elist->fileno)) == -1)
        {
-           fprintf(stderr, "amrecover - can't talk to tape server\n");
+           g_fprintf(stderr, _("amrecover - can't talk to tape server: %s\n"),
+                   errstr);
            return;
        }
+       if (dump_dle) {
+           dump_dle->level = g_slist_append(dump_dle->level,
+                                            GINT_TO_POINTER(elist->level));
+           run_client_scripts(EXECUTE_ON_PRE_LEVEL_RECOVER, &g_options,
+                              dump_dle, stderr);
+       }
+       last_level = elist->level;
 
        /* if the server have fe_amrecover_feedme_tape, it has asked for
         * the tape itself, even if the restore didn't succeed, we should
@@ -2224,6 +2335,21 @@ extract_files(void)
            delete_tape_list(elist);    /* tape done so delete from list */
 
        stop_amidxtaped();
+
+       if (dump_dle) {
+           run_client_scripts(EXECUTE_ON_POST_LEVEL_RECOVER, &g_options,
+                              dump_dle, stderr);
+           g_slist_free(dump_dle->level);
+           dump_dle->level = NULL;
+       }
+    }
+    if (dump_dle) {
+       dump_dle->level = all_level;
+       run_client_scripts(EXECUTE_ON_POST_RECOVER, &g_options, dump_dle,
+                          stderr);
+       g_slist_free(dump_dle->level);
+       all_level = NULL;
+       dump_dle->level = NULL;
     }
 }
 
@@ -2242,17 +2368,16 @@ amidxtaped_response(
     assert(sech != NULL);
     memset(ports, -1, SIZEOF(ports));
 
-    security_close_connection(sech, dump_hostname);
     if (pkt == NULL) {
-       errstr = newvstralloc(errstr, "[request failed: ",
-                            security_geterror(sech), "]", NULL);
+       errstr = newvstrallocf(errstr, _("[request failed: %s]"), security_geterror(sech));
        *response_error = 1;
        return;
     }
+    security_close_connection(sech, dump_hostname);
 
     if (pkt->type == P_NAK) {
 #if defined(PACKET_DEBUG)
-       fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body);
+       g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
 #endif
 
        tok = strtok(pkt->body, " ");
@@ -2272,14 +2397,14 @@ bad_nak:
     }
 
     if (pkt->type != P_REP) {
-       errstr = newvstralloc(errstr, "received strange packet type ",
-                             pkt_type2str(pkt->type), ": ", pkt->body, NULL);
+       errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
+                             pkt_type2str(pkt->type), pkt->body);
        *response_error = 1;
        return;
     }
 
 #if defined(PACKET_DEBUG)
-    fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body);
+    g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body);
 #endif
 
     for(i = 0; i < NSTREAMS; i++) {
@@ -2298,7 +2423,7 @@ bad_nak:
        if (strcmp(tok, "ERROR") == 0) {
            tok = strtok(NULL, "\n");
            if (tok == NULL)
-               tok = "[bogus error packet]";
+               tok = _("[bogus error packet]");
            errstr = newstralloc(errstr, tok);
            *response_error = 2;
            return;
@@ -2316,22 +2441,16 @@ bad_nak:
            for (i = 0; i < NSTREAMS; i++) {
                tok = strtok(NULL, " ");
                if (tok == NULL || strcmp(tok, amidxtaped_streams[i].name) != 0) {
-                   extra = vstralloc("CONNECT token is \"",
+                   extra = vstrallocf(_("CONNECT token is \"%s\": expected \"%s\""),
                                      tok ? tok : "(null)",
-                                     "\": expected \"",
-                                     amidxtaped_streams[i].name,
-                                     "\"",
-                                     NULL);
+                                     amidxtaped_streams[i].name);
                    goto parse_error;
                }
                tok = strtok(NULL, " \n");
                if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
-                   extra = vstralloc("CONNECT ",
+                   extra = vstrallocf(_("CONNECT %s token is \"%s\": expected a port number"),
                                      amidxtaped_streams[i].name,
-                                     " token is \"",
-                                     tok ? tok : "(null)",
-                                     "\": expected a port number",
-                                     NULL);
+                                     tok ? tok : "(null)");
                    goto parse_error;
                }
            }
@@ -2344,20 +2463,18 @@ bad_nak:
        if (strcmp(tok, "OPTIONS") == 0) {
            tok = strtok(NULL, "\n");
            if (tok == NULL) {
-               extra = stralloc("OPTIONS token is missing");
+               extra = stralloc(_("OPTIONS token is missing"));
                goto parse_error;
            }
 /*
            while((p = strchr(tok, ';')) != NULL) {
                *p++ = '\0';
-#define sc "features="
-               if(strncmp(tok, sc, sizeof(sc)-1) == 0) {
-                   tok += sizeof(sc) - 1;
-#undef sc
+               if(strncmp_const(tok, "features=") == 0) {
+                   tok += sizeof("features=") - 1;
                    am_release_feature_set(their_features);
                    if((their_features = am_string_to_feature(tok)) == NULL) {
                        errstr = newvstralloc(errstr,
-                                             "OPTIONS: bad features value: ",
+                                             _("OPTIONS: bad features value: "),
                                              tok,
                                              NULL);
                        goto parse_error;
@@ -2369,10 +2486,8 @@ bad_nak:
            continue;
        }
 /*
-       extra = vstralloc("next token is \"",
-                         tok ? tok : "(null)",
-                         "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"",
-                         NULL);
+       extra = vstrallocf("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""),
+                         tok ? tok : _("(null)"));
        goto parse_error;
 */
     }
@@ -2384,11 +2499,12 @@ bad_nak:
        if (ports[i] == -1)
            continue;
        amidxtaped_streams[i].fd = security_stream_client(sech, ports[i]);
-       dbprintf(("amidxtaped_streams[%d].fd = %p\n",i, amidxtaped_streams[i].fd));
+       dbprintf(_("amidxtaped_streams[%d].fd = %p\n"),i, amidxtaped_streams[i].fd);
        if (amidxtaped_streams[i].fd == NULL) {
-           errstr = newvstralloc(errstr,
-                       "[could not connect ", amidxtaped_streams[i].name, " stream: ",
-                       security_geterror(sech), "]", NULL);
+           errstr = newvstrallocf(errstr,\
+                       _("[could not connect %s stream: %s]"),
+                       amidxtaped_streams[i].name,
+                       security_geterror(sech));
            goto connect_error;
        }
     }
@@ -2399,9 +2515,10 @@ bad_nak:
        if (amidxtaped_streams[i].fd == NULL)
            continue;
        if (security_stream_auth(amidxtaped_streams[i].fd) < 0) {
-           errstr = newvstralloc(errstr,
-               "[could not authenticate ", amidxtaped_streams[i].name, " stream: ",
-               security_stream_geterror(amidxtaped_streams[i].fd), "]", NULL);
+           errstr = newvstrallocf(errstr,
+               _("[could not authenticate %s stream: %s]"),
+               amidxtaped_streams[i].name,
+               security_stream_geterror(amidxtaped_streams[i].fd));
            goto connect_error;
        }
     }
@@ -2411,11 +2528,11 @@ bad_nak:
      * them, complain.
      */
     if (amidxtaped_streams[CTLFD].fd == NULL) {
-        errstr = newstralloc(errstr, "[couldn't open CTL streams]");
+        errstr = newvstrallocf(errstr, _("[couldn't open CTL streams]"));
         goto connect_error;
     }
     if (amidxtaped_streams[DATAFD].fd == NULL) {
-        errstr = newstralloc(errstr, "[couldn't open DATA streams]");
+        errstr = newvstrallocf(errstr, _("[couldn't open DATA streams]"));
         goto connect_error;
     }
 
@@ -2424,11 +2541,13 @@ bad_nak:
     return;
 
 parse_error:
-    errstr = newvstralloc(errstr,
-                         "[parse of reply message failed: ",
-                         extra ? extra : "(no additional information)",
-                         "]",
-                         NULL);
+    if (extra) {
+       errstr = newvstrallocf(errstr,
+                         _("[parse of reply message failed: %s]"), extra);
+    } else {
+       errstr = newvstrallocf(errstr,
+                         _("[parse of reply message failed: (no additional information)"));
+    }
     amfree(extra);
     *response_error = 2;
     return;
@@ -2503,13 +2622,11 @@ read_amidxtaped_data(
     void *     buf,
     ssize_t    size)
 {
-    int fd;
-
+    ctl_data_t *ctl_data = (ctl_data_t *)cookie;
     assert(cookie != NULL);
 
-    fd = *(int *)cookie;
     if (size < 0) {
-       errstr = newstralloc2(errstr, "amidxtaped read: ",
+       errstr = newstralloc2(errstr, _("amidxtaped read: "),
                 security_stream_geterror(amidxtaped_streams[DATAFD].fd));
        return;
     }
@@ -2528,10 +2645,34 @@ read_amidxtaped_data(
 
     assert(buf != NULL);
 
+    if (ctl_data->header_done == 0) {
+       ctl_data->header_done = 1;
+       if(pipe(ctl_data->child_pipe) == -1) {
+           error(_("extract_list - error setting up pipe to extractor: %s\n"),
+                 strerror(errno));
+           /*NOTREACHED*/
+       }
+
+       /* okay, ready to extract. fork a child to do the actual work */
+       if ((ctl_data->pid = fork()) == 0) {
+           /* this is the child process */
+           /* never gets out of this clause */
+           aclose(ctl_data->child_pipe[1]);
+           extract_files_child(ctl_data->child_pipe[0], ctl_data->elist);
+           /*NOTREACHED*/
+       }
+       
+       if (ctl_data->pid == -1) {
+           errstr = newstralloc(errstr, _("writer_intermediary - error forking child"));
+           g_printf(_("writer_intermediary - error forking child"));
+           return;
+       }
+       aclose(ctl_data->child_pipe[0]);
+    }
     /*
      * We ignore errors while writing to the index file.
      */
-    (void)fullwrite(fd, buf, (size_t)size);
+    (void)full_write(ctl_data->child_pipe[1], buf, (size_t)size);
     security_stream_read(amidxtaped_streams[DATAFD].fd, read_amidxtaped_data, cookie);
 }
 
@@ -2546,10 +2687,10 @@ amidxtaped_client_get_security_conf(
        return(NULL);
 
     if(strcmp(string, "auth")==0) {
-       return(client_getconf_str(CLN_AUTH));
+       return(getconf_str(CNF_AUTH));
     }
     if(strcmp(string, "ssh_keys")==0) {
-       return(client_getconf_str(CLN_SSH_KEYS));
+       return(getconf_str(CNF_SSH_KEYS));
     }
     return(NULL);
 }