/*
   Bacula(R) - The Network Backup Solution

   Copyright (C) 2000-2025 Kern Sibbald

   The original author of Bacula is Kern Sibbald, with contributions
   from many others, a complete list can be found in the file AUTHORS.

   You may use this file and others of this release according to the
   license defined in the LICENSE file, which includes the Affero General
   Public License, v3.0 ("AGPLv3") and some additional permissions and
   terms pursuant to its AGPLv3 Section 7.

   This notice must be preserved when any source code is
   conveyed and/or propagated.

   Bacula(R) is a registered trademark of Kern Sibbald.
 */
/**
 * @file test_metaplugin_backend.cpp
 * @author Radosław Korzeniewski (radoslaw@korzeniewski.net)
 * @brief This is a dumb and extremely simple backend simulator used for test Metaplugin.
 * @version 2.1.1
 * @date 2021-03-10
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>


#ifndef LOGDIR
#define LOGDIR "/tmp"
#endif

#define EXIT_BACKEND_NOMEMORY                255
#define EXIT_BACKEND_LOGFILE_ERROR           1
#define EXIT_BACKEND_HEADER_TOOSHORT         2
#define EXIT_BACKEND_MESSAGE_TOOLONG         3
#define EXIT_BACKEND_DATA_COMMAND_REQ        4
#define EXIT_BACKEND_SIGNAL_HANDLER_ERROR    5
#define EXIT_BACKEND_CANCEL                  6

extern const char *PLUGINPREFIX;
extern const char *PLUGINNAME;

int logfd;
pid_t mypid;
char *buf;
char *buflog;
char symlink_fname[32];
char namedpipe_fname[32];

bool regress_error_plugin_params = false;
bool regress_error_start_job = false;
bool regress_error_backup_no_files = false;
bool regress_error_backup_stderr = false;
bool regress_backup_plugin_objects = false;
bool regress_error_backup_abort = false;
bool regress_error_estimate_stderr = false;
bool regress_error_listing_stderr = false;
bool regress_error_restore_stderr = false;
bool regress_backup_other_file = false;
bool regress_metadata_support = false;
bool regress_standard_error_backup = false;
bool regress_cancel_backup = false;
bool regress_cancel_restore = false;
bool regress_backup_external_stat = false;

bool Job_Level_Incremental = false;

char working_directory[4096];    // it should be no more

#define BUFLEN             4096
#define BIGBUFLEN          131072

/**
 * @brief saves the log text to logfile
 *
 * @param txt log text to save
 */
void LOG(const char *txt)
{
   char _buf[BUFLEN];

   int p = 0;
   for (int a = 0; txt[a]; a++)
   {
      char c = txt[a];
      if (c == '\n')
      {
         _buf[p++] = '\\';
         _buf[p++] = 'n';
      } else {
         _buf[p++] = c;
      }
   }
   _buf[p++] = '\n';
   _buf[p] = '\0';
   write(logfd, _buf, p);
}

/**
 * @brief Reads the raw packet from plugin.
 *
 * @param buf the memory buffer to save packet payload
 * @return int the size of the packer read
 */
int read_plugin(char * buf)
{
   size_t len;
   size_t nread;
   size_t size;
   char header[8];

   len = read(STDIN_FILENO, &header, 8);
   if (len < 8){
      LOG("#> Err: header too short");
      close(logfd);
      exit(EXIT_BACKEND_HEADER_TOOSHORT);
   }
   if (header[0] == 'F'){
      LOG(">> EOD >>");
      return 0;
   }
   if (header[0] == 'T'){
      LOG(">> TERM >>");
      close(logfd);
      exit(EXIT_SUCCESS);
   }
   size = atoi(header + 1);

   if (header[0] == 'C'){
      if (size > BIGBUFLEN){
         LOG("#> Err: message too long");
         close(logfd);
         exit(EXIT_BACKEND_MESSAGE_TOOLONG);
      }
      len = read(STDIN_FILENO, buf, size);
      buf[len] = 0;
      snprintf(buflog, BUFLEN, "> %s", buf);
      LOG(buflog);
   } else {
      snprintf(buflog, BUFLEN, "> Data:%lu", size);
      LOG(buflog);
      len = 0;
      while (len < size) {
         int32_t nbytes = 0;
         int rc = ioctl(STDIN_FILENO, FIONREAD, &nbytes);
         snprintf(buflog, BUFLEN, ">> FIONREAD:%d:%ld", rc, (long int)nbytes);
         LOG(buflog);
         if (size > (size_t)nbytes){
            rc = ioctl(STDIN_FILENO, FIONREAD, &nbytes);
            snprintf(buflog, BUFLEN, ">> Second FIONREAD:%d:%ld", rc, (long int)nbytes);
            LOG(buflog);
         }
         size_t bufread = size - len > BIGBUFLEN ? BIGBUFLEN : size - len;
         nread = read(STDIN_FILENO, buf, bufread);
         len += nread;
         snprintf(buflog, BUFLEN, ">> Dataread:%lu", nread);
         LOG(buflog);
      }
   }

   return len;
}

void read_plugin_data_stream()
{
   int len = read_plugin(buf);
   if (len == 0){
      /* empty file to restore */
      LOG("#> Empty data.");
      return;
   }
   bool loopgo = true;
   int fsize = len;
   while (loopgo){
      len = read_plugin(buf);
      fsize += len;
      if (len > 0){
         LOG("#> data stream saved.");
         continue;
      } else {
         loopgo = false;
         snprintf(buflog, 4096, "#> data END = %i", fsize);
      }
   }
}

// #define USE_PRINTF

/**
 * @brief Sends/writes the data to plugin with assembling the raw packet.
 *
 * @param cmd the packet type to sent
 * @param str the text to write
 */
void write_plugin(const char cmd, const char *str)
{
   int len;
   const char * out;
   char header[9];

   if (str){
      len = strlen(str);
      out = str;
   } else {
      len = 0;
      out = "";
   }
#ifdef USE_PRINTF
   printf("%c%06d\n", cmd, len);
   printf("%s", out);
   fflush(stdout);
#else
   snprintf(header, 9, "%c%06d\n", cmd, len);
   write(STDOUT_FILENO, header, 8);
   write(STDOUT_FILENO, out, len);
#endif
   snprintf(buflog, BUFLEN, "<< %c%06d:%s", cmd, len, out);
   LOG(buflog);
}

/**
 * @brief Sends/writes the binary data to plugin with assembling the raw packet.
 *
 * @param cmd the packet type to sent
 * @param str the text to write
 */
void write_plugin_bin(const unsigned char *str, int len = 0)
{
   const unsigned char * out;

   if (str) {
      out = str;
   } else {
      out = (const unsigned char*)"";
   }

   printf("D%06d\n", len);
   int status = fwrite(out, len, 1, stdout);
   fflush(stdout);
   snprintf(buflog, BUFLEN, "<< D%06d:%d:<bindata>", len ,status);
   LOG(buflog);
}

/**
 * @brief Sends the EOD packet to plugin.
 */
void signal_eod(){
   printf("F000000\n");
   fflush(stdout);
   LOG("<< EOD <<");
}

/**
 * @brief Sends the termination packet to plugin.
 */
void signal_term(){
   printf("T000000\n");
   fflush(stdout);
   LOG("<< TERM <<");
}

static bool jobcancelled = false;

static void catch_function(int signo)
{
   if (regress_cancel_backup) {
      LOG("#CANCELLED BACKUP#");
   } else
   if (regress_cancel_restore) {
      LOG("#CANCELLED RESTORE#");
   } else {
      LOG("#CANCELLED UNKNOWN#");
   }
   jobcancelled = true;
}

unsigned char restore_object_data[] = {
  0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20,
  0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a, 0x20, 0x4e, 0x61, 0x6d,
  0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64,
  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
  0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69,
  0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a,
  0x20, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x0a, 0x6d, 0x65, 0x74, 0x61,
  0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
  0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x6e,
  0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c,
  0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c,
  0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61,
  0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
  0x73, 0x74, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x23,
  0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x62,
  0x61, 0x63, 0x75, 0x6c, 0x61, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x70, 0x61,
  0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x73,
  0x65, 0x63, 0x72, 0x65, 0x74, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x35, 0x62,
  0x41, 0x6f, 0x56, 0x32, 0x43, 0x70, 0x7a, 0x42, 0x76, 0x68, 0x42, 0x51,
  0x5a, 0x61, 0x59, 0x55, 0x58, 0x31, 0x71, 0x59, 0x61, 0x77, 0x43, 0x30,
  0x30, 0x71, 0x68, 0x72, 0x78, 0x38, 0x63, 0x45, 0x57, 0x30, 0x66, 0x4b,
  0x31, 0x7a, 0x59, 0x6b, 0x54, 0x78, 0x56, 0x64, 0x62, 0x78, 0x66, 0x76,
  0x57, 0x4d, 0x79, 0x69, 0x30, 0x68, 0x35, 0x51, 0x62, 0x77, 0x65, 0x4a,
  0x6b, 0x71, 0x0a, 0x20, 0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
  0x65, 0x3a, 0x20, 0x59, 0x6d, 0x46, 0x6a, 0x64, 0x57, 0x78, 0x68, 0x43,
  0x67, 0x3d, 0x3d, 0x0a, 0x20, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
  0x72, 0x64, 0x3a, 0x20, 0x63, 0x47, 0x78, 0x31, 0x5a, 0x32, 0x6c, 0x75,
  0x64, 0x47, 0x56, 0x7a, 0x64, 0x41, 0x6f, 0x3d, 0x0a, 0x20, 0x20, 0x73,
  0x65, 0x63, 0x72, 0x65, 0x74, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x4e, 0x57,
  0x4a, 0x42, 0x62, 0x31, 0x59, 0x79, 0x51, 0x33, 0x42, 0x36, 0x51, 0x6e,
  0x5a, 0x6f, 0x51, 0x6c, 0x46, 0x61, 0x59, 0x56, 0x6c, 0x56, 0x57, 0x44,
  0x46, 0x78, 0x57, 0x57, 0x46, 0x33, 0x51, 0x7a, 0x41, 0x77, 0x63, 0x57,
  0x68, 0x79, 0x65, 0x44, 0x68, 0x6a, 0x52, 0x56, 0x63, 0x77, 0x5a, 0x6b,
  0x73, 0x78, 0x65, 0x6c, 0x6c, 0x72, 0x56, 0x48, 0x68, 0x57, 0x5a, 0x47,
  0x4a, 0x34, 0x5a, 0x6e, 0x5a, 0x58, 0x54, 0x58, 0x6c, 0x70, 0x4d, 0x47,
  0x67, 0x31, 0x55, 0x57, 0x4a, 0x33, 0x5a, 0x55, 0x70, 0x72, 0x63, 0x51,
  0x6f, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69,
  0x6e, 0x64, 0x3a, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61,
  0x70, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a,
  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69,
  0x67, 0x6d, 0x61, 0x70, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
  0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
  0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c,
  0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20,
  0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x64,
  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62,
  0x61, 0x73, 0x65, 0x3a, 0x20, 0x62, 0x61, 0x63, 0x75, 0x6c, 0x61, 0x0a,
  0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x68,
  0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30,
  0x2e, 0x31, 0x0a, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
  0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x27, 0x35, 0x34, 0x33,
  0x32, 0x27, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69,
  0x6e, 0x64, 0x3a, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a,
  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20,
  0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
  0x74, 0x65, 0x73, 0x74, 0x2d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61,
  0x69, 0x6e, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
  0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
  0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c,
  0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x73, 0x70, 0x65,
  0x63, 0x3a, 0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
  0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
  0x20, 0x20, 0x23, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49,
  0x50, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x20, 0x20, 0x70, 0x6f,
  0x72, 0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d,
  0x65, 0x3a, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x23, 0x20, 0x41, 0x63, 0x74,
  0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2c, 0x20, 0x6e, 0x6f, 0x20, 0x70, 0x6f,
  0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x65, 0x64,
  0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20,
  0x31, 0x32, 0x33, 0x34, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x61, 0x72,
  0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x33,
  0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
  0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
  0x64, 0x3a, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x6d,
  0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e,
  0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
  0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x73, 0x65,
  0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
  0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
  0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65,
  0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
  0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20,
  0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x0a, 0x73, 0x70, 0x65, 0x63,
  0x3a, 0x0a, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x0a, 0x20,
  0x20, 0x2d, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x0a,
  0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x77, 0x65,
  0x62, 0x0a, 0x20, 0x20, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49,
  0x50, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x20, 0x20, 0x73, 0x65,
  0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
  0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77, 0x65,
  0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
  0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
  0x64, 0x3a, 0x20, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e,
  0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d,
  0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20,
  0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
  0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73,
  0x74, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x2d,
  0x63, 0x6c, 0x61, 0x69, 0x6d, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
  0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
  0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65,
  0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
  0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x61, 0x63, 0x63, 0x65,
  0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x2d, 0x20, 0x52, 0x65, 0x61, 0x64, 0x57, 0x72, 0x69, 0x74, 0x65,
  0x4f, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x73, 0x6f, 0x75,
  0x72, 0x63, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
  0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x31,
  0x47, 0x69, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
  0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69,
  0x6e, 0x64, 0x3a, 0x20, 0x50, 0x6f, 0x64, 0x0a, 0x6d, 0x65, 0x74, 0x61,
  0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
  0x31, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
  0x74, 0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a,
  0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75,
  0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x3a,
  0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
  0x20, 0x20, 0x20, 0x20, 0x23, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20,
  0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x73, 0x70, 0x65,
  0x63, 0x3a, 0x0a, 0x20, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d,
  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
  0x74, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d,
  0x61, 0x69, 0x6e, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
  0x65, 0x73, 0x74, 0x2d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69,
  0x6e, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
  0x72, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x69, 0x6d, 0x61, 0x67,
  0x65, 0x3a, 0x20, 0x62, 0x75, 0x73, 0x79, 0x62, 0x6f, 0x78, 0x3a, 0x31,
  0x2e, 0x32, 0x38, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
  0x61, 0x6e, 0x64, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d,
  0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x2d, 0x20, 0x22, 0x33, 0x36, 0x30, 0x30, 0x22, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76,
  0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d,
  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
  0x74, 0x2d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74,
  0x2d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61,
  0x74, 0x68, 0x3a, 0x20, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x20,
  0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75,
  0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x70, 0x65, 0x72, 0x73,
  0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x6f, 0x72, 0x61,
  0x67, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72,
  0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d,
  0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x4e, 0x61, 0x6d,
  0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
  0x74, 0x2d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74,
  0x2d, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x2d, 0x63, 0x6c, 0x61, 0x69,
  0x6d, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72,
  0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
  0x64, 0x3a, 0x20, 0x50, 0x6f, 0x64, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64,
  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x32,
  0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
  0x0a, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x3a,
  0x0a, 0x20, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
  0x32, 0x0a, 0x20, 0x20, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69,
  0x6e, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73,
  0x74, 0x2d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0a,
  0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
  0x3a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a,
  0x20, 0x62, 0x75, 0x73, 0x79, 0x62, 0x6f, 0x78, 0x3a, 0x31, 0x2e, 0x32,
  0x38, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
  0x64, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x73,
  0x6c, 0x65, 0x65, 0x70, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d,
  0x20, 0x22, 0x33, 0x36, 0x30, 0x30, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
  0x74, 0x65, 0x73, 0x74, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70, 0x69,
  0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x70, 0x70,
  0x73, 0x2f, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a, 0x20, 0x52,
  0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x53, 0x65, 0x74, 0x0a, 0x6d, 0x65,
  0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x6e, 0x61,
  0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
  0x73, 0x74, 0x2d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a,
  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
  0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
  0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63,
  0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20,
  0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x73, 0x70, 0x65,
  0x63, 0x3a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61,
  0x73, 0x3a, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63,
  0x74, 0x6f, 0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74,
  0x63, 0x68, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20, 0x66, 0x72,
  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x74, 0x65, 0x6d,
  0x70, 0x6c, 0x61, 0x74, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d,
  0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x65, 0x72, 0x3a,
  0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
  0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61,
  0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
  0x73, 0x74, 0x2d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2d,
  0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x67, 0x63, 0x72, 0x2e,
  0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x73, 0x61,
  0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x67, 0x62, 0x2d, 0x66, 0x72, 0x6f,
  0x6e, 0x74, 0x65, 0x6e, 0x64, 0x3a, 0x76, 0x33, 0x0a, 0x2d, 0x2d, 0x2d,
  0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a,
  0x20, 0x61, 0x70, 0x70, 0x73, 0x2f, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e,
  0x64, 0x3a, 0x20, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e,
  0x74, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a,
  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78,
  0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x0a,
  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x0a,
  0x20, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69,
  0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79,
  0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20,
  0x20, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x3a, 0x20, 0x32,
  0x0a, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x61,
  0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74,
  0x65, 0x73, 0x74, 0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65,
  0x6e, 0x74, 0x0a, 0x20, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74,
  0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64,
  0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
  0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x64, 0x65, 0x70, 0x6c, 0x6f,
  0x79, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70,
  0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f,
  0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x3a, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20,
  0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e,
  0x67, 0x69, 0x6e, 0x78, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x6e, 0x67, 0x69, 0x6e,
  0x78, 0x3a, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x3a, 0x0a,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x63, 0x6f,
  0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x3a,
  0x20, 0x38, 0x30, 0x38, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, 0x0a, 0x61, 0x70,
  0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x70,
  0x70, 0x73, 0x2f, 0x76, 0x31, 0x0a, 0x6b, 0x69, 0x6e, 0x64, 0x3a, 0x20,
  0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, 0x53, 0x65, 0x74, 0x0a,
  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20,
  0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
  0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77,
  0x65, 0x62, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
  0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65,
  0x73, 0x74, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x73,
  0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x3a, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
  0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20,
  0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x22, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x22, 0x0a, 0x20, 0x20, 0x72,
  0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x3a, 0x20, 0x33, 0x0a, 0x20,
  0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x3a, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
  0x70, 0x61, 0x63, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
  0x74, 0x65, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
  0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x6e, 0x67, 0x69, 0x6e, 0x78,
  0x2d, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x74, 0x69, 0x65, 0x72, 0x3a, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x65,
  0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x69,
  0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x61, 0x63, 0x65, 0x50,
  0x65, 0x72, 0x69, 0x6f, 0x64, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73,
  0x3a, 0x20, 0x31, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63,
  0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x3a, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a,
  0x20, 0x6b, 0x38, 0x73, 0x2e, 0x67, 0x63, 0x72, 0x2e, 0x69, 0x6f, 0x2f,
  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x73, 0x6c, 0x69, 0x6d, 0x3a, 0x30,
  0x2e, 0x38, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70,
  0x6f, 0x72, 0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
  0x72, 0x50, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65,
  0x3a, 0x20, 0x77, 0x65, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4d, 0x6f, 0x75, 0x6e,
  0x74, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x2d, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67,
  0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d, 0x77, 0x77, 0x77, 0x2d, 0x64,
  0x61, 0x74, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x3a,
  0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f,
  0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x20,
  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d,
  0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x3a, 0x0a, 0x20,
  0x20, 0x2d, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3a,
  0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74, 0x2d,
  0x77, 0x77, 0x77, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
  0x3a, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, 0x65, 0x73, 0x74,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d,
  0x6f, 0x64, 0x65, 0x73, 0x3a, 0x20, 0x5b, 0x20, 0x22, 0x52, 0x65, 0x61,
  0x64, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x6e, 0x63, 0x65, 0x22, 0x20,
  0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x6f,
  0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x3a,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
  0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x31, 0x47, 0x69, 0x0a,
};
unsigned int restore_object_data_len = 3984;

/**
 * @brief Perform test backup.
 */
void perform_backup()
{
   // This is a test for FileIndex Query
   snprintf(buf, BIGBUFLEN, "FileIndex\n");
   write_plugin('C', buf);
   char firesponse[32] = {0};    // well the file index is int32_t so max 11 chars
   read_plugin(firesponse);
   int fileindex = atoi(firesponse);
   snprintf(buf, BIGBUFLEN, "TEST05 - FileIndex query: %d", fileindex);
   write_plugin('I', buf);

   // here we store the linked.file origin fname
   char fileindex_link[256];
   snprintf(fileindex_link, 256, "%s/bucket/%d/vm1.iso", PLUGINPREFIX, mypid);

   // Backup Loop
   if (regress_error_backup_no_files) {
      write_plugin('E', "No files found for pattern container1/otherobject\n");
      signal_eod();
      return;
   }

   // first file
   snprintf(buf, BIGBUFLEN, "FNAME:%s\n", fileindex_link);           // we use it here
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 1048576 100 100 100640 2\n");           // this will be the first file hardlinked
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   write_plugin('I', "TEST5");
   signal_eod();
   // here comes a file data contents
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();
   write_plugin('I', "TEST5Data");
   // and now additional metadata
   write_plugin('C', "ACL\n");
   write_plugin('D', "user::rw-\nuser:root:-wx\ngroup::r--\nmask::rwx\nother::r--\n");
   write_plugin('I', "TEST5Acl");
   signal_eod();

   if (regress_cancel_backup)
   {
      LOG("#Cancel wait started...");
      snprintf(buf, BIGBUFLEN, "#Cancel PID: %d", getpid());
      write_plugin('I', buf);
      while (!jobcancelled)
         sleep(1);
      LOG("#Cancel event received, EXIT");
      exit(EXIT_BACKEND_CANCEL);
   }

   // next file
   // this files we will restore using Bacula Core functionality, so it is crucial
   write_plugin('I', "TEST6");
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/etc/issue\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 26 200 200 100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   write_plugin('C', "PIPE:/etc/issue\n");
   read_plugin(buf);
   signal_eod();
   write_plugin('C', "DATA\n");
   write_plugin('I', "TEST6Data");

   write_plugin('I', "TEST6A");
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/fileforcore\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 27 200 200 100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('C', "DATA\n");
   write_plugin('I', "TEST6AData");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();
   write_plugin('I', "TEST6Axattr");
   write_plugin('C', "XATTR\n");
   write_plugin('D', "bacula.custom.data=Inteos\nsystem.custom.data=Bacula\n");
   signal_eod();

   // next file
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vm2.iso\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");

   if (regress_error_backup_stderr)
   {
      // test some stderror handling, yes in the middle file parameters
      errno = EACCES;
      perror("I've got some unsuspected error which I'd like to display on stderr (COMM_STDERR)");
      sleep(1);
   }

   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST7");
   /* here comes a file data contents */
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");

   if (regress_error_backup_stderr && false)
   {
      // test some stderror handling, yes in the middle of data transfer
      errno = EACCES;
      perror("I've got some unsuspected error which I'd like to display on stderr (COMM_STDERR)");
      sleep(1);
   }

   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();
   write_plugin('I', "TEST7Data");
   write_plugin('C', "XATTR\n");
   write_plugin('D', "bacula.custom.data=Inteos\nsystem.custom.data=Bacula\n");
   signal_eod();

   if (regress_backup_other_file)
   {
      // restore object
      snprintf(buf, BIGBUFLEN, "RESTOREOBJ:TestRObject%d\n", mypid);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "RESTOREOBJ_LEN:%u\n", restore_object_data_len);
      write_plugin('C', buf);
      write_plugin_bin(restore_object_data, restore_object_data_len);
      signal_eod();

      snprintf(buf, BIGBUFLEN, "RESTOREOBJ:OtherObject%d\n", mypid);
      write_plugin('C', buf);
      const char *r_data = "/* here comes a file data contents */";
      snprintf(buf, BIGBUFLEN, "RESTOREOBJ_LEN:%lu\n", strlen(r_data) + 1);
      write_plugin('C', buf);
      write_plugin('D', r_data);
      signal_eod();

      // long restore object
      snprintf(buf, BIGBUFLEN, "RESTOREOBJ:LongObject%d\n", mypid);
      write_plugin('C', buf);
      const size_t longobject_num = 6;
      snprintf(buf, BIGBUFLEN, "RESTOREOBJ_LEN:%lu\n", BIGBUFLEN * longobject_num);
      write_plugin('C', buf);
      memset(buf, 'A', BIGBUFLEN);
      for (size_t a = 0; a < longobject_num; a++)
      {
         write_plugin_bin((unsigned char*)buf, BIGBUFLEN);
      }
      signal_eod();

      // next file
      snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vm222-other-file.iso\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();
      write_plugin('I', "TEST7-Other");
      /* here comes a file data contents */
      write_plugin('C', "DATA\n");
      write_plugin('D', "/* here comes a file data contents */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('I', "TEST7-Other-End");
      signal_eod();

      // check acceptfile() skip
      write_plugin('C', "ACCEPT:/exclude/file1\n");
      write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      read_plugin(buf);
      write_plugin('I', "TEST ACCEPT Response\n");
      write_plugin('I', buf);
      if (strncmp(buf, "SKIP", 4) == 0)
      {
         write_plugin('I', "TEST ACCEPT Response OK (ACCEPT_FILE_OK)\n");
      }

      // check acceptfile() ok
      write_plugin('C', "ACCEPT:/etc/passwd\n");
      write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      read_plugin(buf);
      write_plugin('I', "TEST ACCEPT Response\n");
      write_plugin('I', buf);
      if (strncmp(buf, "OK", 2) == 0)
      {
         write_plugin('I', "TEST ACCEPT Response OK (ACCEPT_FILE_OK)\n");
      }

      // check acceptfile() with STAT(2) on file
      write_plugin('C', "ACCEPT:/etc/passwd\n");
      write_plugin('C', "STAT:/etc/passwd\n");
      read_plugin(buf);
      write_plugin('I', "TEST ACCEPT Response\n");
      write_plugin('I', buf);
      if (strncmp(buf, "OK", 2) == 0)
      {
         write_plugin('I', "TEST ACCEPT Response OK (ACCEPT_FILE_OK)\n");
      }
   }

   bool seen = false;
   if (Job_Level_Incremental) {
      // we can accurateCheck query
      write_plugin('C', "CHECK:/etc/passwd\n");
      write_plugin('C', "STAT:F 37 0 0 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      read_plugin(buf);
      write_plugin('I', "TEST CHECK Response");
      write_plugin('I', buf);
      if (strncmp(buf, "SEEN", 4) == 0) {
         seen = true;
      }

      // accurate check nonexistent file
      snprintf(buf, BIGBUFLEN, "CHECK:%s/nonexistent/%d/file\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "STAT:F 0 0 0 100640 1\n");
      write_plugin('C', "TSTAMP:0 0 0\n");
      read_plugin(buf);
      if (strncmp(buf, "SEEN", 4) != 0) {
         write_plugin('I', "TEST CHECK nonexistentok");
      }

      // now accurateGet query
      write_plugin('C', "CHECKGET:/etc/passwd\n");
      read_plugin(buf);
      if (strncmp(buf, "STAT", 4) == 0) {
         // yes, the data is available
         read_plugin(buf);
         write_plugin('I', "TEST CHECKGET");
      }

      // accurate check nonexistent file
      snprintf(buf, BIGBUFLEN, "CHECKGET:%s/nonexistent/%d/file\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      read_plugin(buf);
      if (strncmp(buf, "UNAVAIL", 7) == 0) {
         write_plugin('I', "TEST CHECK nonexistentok");
      }

      // check addinclude()
      snprintf(buf, BIGBUFLEN, "%s/passwd", working_directory);
      creat(buf, 0600);
      snprintf(buf, BIGBUFLEN, "INCLUDE:%s/passwd", working_directory);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "%s/group", working_directory);
      creat(buf, 0600);
      snprintf(buf, BIGBUFLEN, "INCLUDE:%s/group", working_directory);
      write_plugin('C', buf);

      write_plugin('C', "STRIP:3\n");
      snprintf(buf, BIGBUFLEN, "%s/tmp", working_directory);
      mkdir(buf, 0700);
      snprintf(buf, BIGBUFLEN, "%s/tmp/bacula", working_directory);
      mkdir(buf, 0700);
      snprintf(buf, BIGBUFLEN, "%s/tmp/bacula/test", working_directory);
      mkdir(buf, 0700);
      snprintf(buf, BIGBUFLEN, "%s/tmp/bacula/test/split", working_directory);
      mkdir(buf, 0700);
      snprintf(buf, BIGBUFLEN, "%s/tmp/bacula/test/split/file", working_directory);
      creat(buf, 0600);
      snprintf(buf, BIGBUFLEN, "INCLUDE:%s/tmp/bacula/test/split", working_directory);
      write_plugin('C', buf);
   }

   // backup if full or not seen
   if (!Job_Level_Incremental || !seen) {
      write_plugin('C', "FNAME:/etc/passwd\n");
      write_plugin('C', "STAT:F 37 0 0 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();
      /* here comes a file data contents */
      write_plugin('C', "DATA\n");
      write_plugin('D', "/* here comes a file data contents */");
      signal_eod();
   }

   // next file
   write_plugin('I', "TEST8");
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/SHELL\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 1099016 0 0 100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   write_plugin('C', "PIPE:/bin/bash\n");
   read_plugin(buf);
   signal_eod();
   write_plugin('C', "DATA\n");
   write_plugin('I', "TEST8Data");

   if (regress_standard_error_backup)
   {
      // next file
      snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/standard-error-file\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();
      write_plugin('I', "TEST8-Error-Start");
      /* here comes a file data contents */
      write_plugin('E', "TEST8-Error: Standard IO Error goes Here");
      write_plugin('I', "TEST8-Error-End");
      // signal_eod();
   }

   if (regress_backup_plugin_objects)
   {
      // test Plugin Objects interface
      write_plugin('I', "TEST PluginObject");
      snprintf(buf, BIGBUFLEN, "PLUGINOBJ:%s/images/%d/vm1\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "PLUGINOBJ_CAT:Image\n");
      write_plugin('C', "PLUGINOBJ_TYPE:VM\n");
      snprintf(buf, BIGBUFLEN, "PLUGINOBJ_NAME:%s%d/vm1 - Name\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "PLUGINOBJ_SRC:%s\n", PLUGINPREFIX);
      write_plugin('C', buf);
      write_plugin('C', "PLUGINOBJ_UUID:c3260b8c560e5e093e8913065fa3cba9\n");
      write_plugin('C', "PLUGINOBJ_SIZE:1024kB\n");
      signal_eod();
      write_plugin('I', "TEST PluginObject - END");
   }

   // next file
   write_plugin('I', "TEST9");
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/lockfile\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:E 0 300 300 0100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST9E");
   signal_eod();

   // next file
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/file.xattr\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:E 0 300 300 0100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST10");
   signal_eod();
   write_plugin('C', "XATTR\n");
   write_plugin('D', "bacula.custom.data=Inteos\nsystem.custom.data=Bacula\n");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vmsnap.iso\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:S 1048576 0 0 100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   snprintf(buf, BIGBUFLEN, "LSTAT:bucket/%d/vm1.iso/1508502750.495885/69312986/10485760/\n", mypid);
   write_plugin('C', buf);
   signal_eod();
   write_plugin('I', "TEST11 - segmented object");
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();

   if (regress_standard_error_backup)
   {
      // next file
      snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/standard-error-file2\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();
      write_plugin('I', "TEST8-Error-Start");
      /* here comes a file data contents */
      write_plugin('C', "DATA\n");
      write_plugin('D', "/* here comes a file data contents */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('E', "TEST8-Error: Standard IO Error goes Here");
      write_plugin('I', "TEST8-Error-End");
      // signal_eod();
   }

   const int bigfileblock = 100000;
   const int bigfilesize = bigfileblock * 5;
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/bigfile.raw\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   snprintf(buf, BIGBUFLEN, "STAT:F %d 0 0 100640 1\n", bigfilesize);
   write_plugin('C', buf);
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST17 - big file block");
   write_plugin('C', "DATA\n");
   {
      unsigned char *bigfileblock_ptr = (unsigned char*)malloc(bigfileblock);
      memset(bigfileblock_ptr, 0xA1, bigfileblock);
      for (int s = bigfilesize; s > 0; s -= bigfileblock) {
         write_plugin_bin(bigfileblock_ptr, bigfileblock);
      }
      free(bigfileblock_ptr);
   }
   signal_eod();

   if (regress_error_backup_abort)
   {
      snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/file on error\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "STAT:F 234560 900 900 0100640 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();
      write_plugin('A', "Some error...\n");
      return;
   }

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/data.dir/\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST15 - backup data dir");
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/directory.with.xattrs/\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST16 - backup dir + xattrs");
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();
   write_plugin('C', "XATTR\n");
   write_plugin('D', "bacula.custom.data=Inteos\nsystem.custom.data=Bacula\n");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/acl.dir/\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST12 - backup dir");
   signal_eod();
   write_plugin('C', "ACL\n");
   write_plugin('D', "user::rwx\ngroup::r-x\nother::r-x\n");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST12 - backup dir");
   signal_eod();
   write_plugin('C', "XATTR\n");
   write_plugin('D', "bacula.custom.data=Inteos\nsystem.custom.data=Bacula\n");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/\n", PLUGINPREFIX);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST12 - backup another dir");
   write_plugin('W', "Make some warning messages.");
   signal_eod();

   const char longfilenamestr[] =
      "cb1e1926239b467c8e9affd7d22cea4993940d1e8f5377a1540d2b58e10be5669888c7e729fc9fe98f1400ca2e68c93075fd26e2806bebd727c71022de47f37b"
      "cb1e1926239b467c8e9affd7d22cea4993940d1e8f5377a1540d2b58e10be5669888c7e729fc9fe98f1400ca2e68c93075fd26e2806bebd727c71022de47f37b"
      "cb1e1926239b467c8e9affd7d22cea4993940d1e8f5377a1540d2b58e10be5669888c7e729fc9fe98f1400ca2e68c93075fd26e2806bebd727c71022de47f37b"
      "cb1e1926239b467c8e9affd7d22cea4993940d1e8f5377a1540d2b58e10be5669888c7e729fc9fe98f1400ca2e68c93075fd26e2806bebd727c71022de47f37b"
      "ENDOFNAME";
   const char *longfilename = longfilenamestr;

   // test for fname > 500c
#if __cplusplus > 201103L
   static_assert(sizeof(longfilenamestr) > 500);
#endif
   snprintf(buf, BIGBUFLEN, "FNAME:%s/%s\n", PLUGINPREFIX, longfilename);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 234560 901 901 0100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   write_plugin('I', "TEST13 - long FNAME test");
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();

   if (regress_metadata_support)
   {
      snprintf(buf, BIGBUFLEN, "FNAME:%s/office/%d/document.docx\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "STAT:F 10240 100 100 040755 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");

      write_plugin('C', "METADATA_STREAM\n");
         write_plugin('D', "{ \"bacula.custom.data\": \"Inteos\"\n  \"system.custom.data\":\"Bacula\" }\n");
      signal_eod();

      write_plugin('C', "METADATA_STREAM\n");
         write_plugin('D', "This is a binary data!");
      signal_eod();

      write_plugin('C', "METADATA_STREAM\n");
      const size_t _mdlargebuf_len = 300000;
      unsigned char *_mdlargebuf = (unsigned char *)malloc(_mdlargebuf_len);
      memset(_mdlargebuf, '0', _mdlargebuf_len);
      write_plugin_bin(_mdlargebuf, _mdlargebuf_len);
      free(_mdlargebuf);
      signal_eod();

      // disabled intentionally
      // write_plugin('C', "METADATA_CATALOG\n");
      //    write_plugin('D', "TABLE1: { field1: \"value1\", field2: \"value2\", field3: \"value3\"}");
      // signal_eod();

      // write_plugin('C', "METADATA_CATALOG\n");
      //    write_plugin('D', "TABLE2: { field2: \"value1\", field2: \"value2\", field3: \"value3\"}");
      // signal_eod();

      signal_eod();  // end of file attributes

      write_plugin('I', "TEST14 - backup metadata");
      write_plugin('C', "DATA\n");
      write_plugin('D', "/* here comes a file data contents */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      write_plugin('D', "/* here comes another file line    */");
      signal_eod();
   }

   snprintf(buf, BIGBUFLEN, "FNAME:%s/office/%d/linked.file\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   snprintf(buf, BIGBUFLEN, "STAT:L 10240 100 100 040755 2 %d\n", fileindex);
   write_plugin('C', buf);
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   snprintf(buf, BIGBUFLEN, "LSTAT:%s\n", fileindex_link);
   write_plugin('C', buf);
   signal_eod();
   signal_eod();

   // the file with external stat(2) packet
   snprintf(buf, BIGBUFLEN, "FNAME:%s/java/%d/stat.file\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:/etc/passwd\n");
   write_plugin('I', "TEST18");
   signal_eod();
   // here comes a file data contents
   write_plugin('C', "DATA\n");
   write_plugin('D', "/* here comes a file data contents */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   write_plugin('D', "/* here comes another file line    */");
   signal_eod();
   write_plugin('I', "TEST18Data");

   // now test `STAT:/path/to/file` using symbolic link
   snprintf(symlink_fname, 32, "/tmp/passwd.%d", mypid);
   symlink("/etc/passwd", symlink_fname);

   // the file with external stat(2) packet
   snprintf(buf, BIGBUFLEN, "FNAME:%s/java/%d/stat.symlink\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   snprintf(buf, BIGBUFLEN, "STAT:%s\n", symlink_fname);
   write_plugin('C', buf);
   write_plugin('I', "TEST18S");
   signal_eod();
   signal_eod();

   // now test `STAT:/path/to/file` using named pipe
   snprintf(namedpipe_fname, 32, "/tmp/namedpipe.%d", mypid);
   mkfifo(namedpipe_fname, 0600);

   // the file with external stat(2) packet
   snprintf(buf, BIGBUFLEN, "FNAME:%s/java/%d/stat.namedpipe\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   snprintf(buf, BIGBUFLEN, "STAT:%s\n", namedpipe_fname);
   write_plugin('C', buf);
   write_plugin('I', "TEST18NP");
   signal_eod();
   signal_eod();

   //
   if (regress_backup_external_stat)
   {
      // the file with external stat(2) packet
      snprintf(buf, BIGBUFLEN, "FNAME:%s/java/%d/stat.error\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "STAT:%s\n", "/nonexistent.file");
      write_plugin('C', buf);
      write_plugin('I', "TEST18NEX");
      signal_eod();
      signal_eod();
   }

   // this plugin object should be the latest item to backup
   if (regress_backup_plugin_objects)
   {
      // test Plugin Objects interface
      write_plugin('I', "TEST PluginObject Last");
      snprintf(buf, BIGBUFLEN, "PLUGINOBJ:%s/images/%d/last_po_item\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      write_plugin('C', "PLUGINOBJ_CAT:POITEM\n");
      write_plugin('C', "PLUGINOBJ_TYPE:POINTEM\n");
      snprintf(buf, BIGBUFLEN, "PLUGINOBJ_NAME:%s%d/last_po_item - Name\n", PLUGINPREFIX, mypid);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "PLUGINOBJ_SRC:%s\n", PLUGINPREFIX);
      write_plugin('C', buf);
      write_plugin('C', "PLUGINOBJ_UUID:09bf8b2a-915d-11eb-8ebb-db6e14058a82\n");
      write_plugin('C', "PLUGINOBJ_SIZE:1024kB\n");
      signal_eod();
      write_plugin('I', "TEST PluginObject Last - END");
   }

   write_plugin('I', "M_INFO test message\n");
   write_plugin('W', "M_WARNING test message\n");
   write_plugin('S', "M_SAVED test message\n");
   write_plugin('N', "M_NOTSAVED test message\n");
   write_plugin('R', "M_RESTORED test message\n");
   write_plugin('P', "M_SKIPPED test message\n");
   write_plugin('O', "M_OPER?MOUNT test message\n");
   write_plugin('V', "M_EVENTS test message\n");
   if (regress_standard_error_backup)
   {
      write_plugin('Q', "M_ERROR test message\n");
   }

   /* this is the end of all data */
   signal_eod();
}

/**
 * @brief Perform test estimate
 */
void perform_estimate(){
   /* Estimate Loop (5) */
   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vm1.iso\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 1048576 100 100 100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   // write_plugin('I', "TEST5");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vm2.iso\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();
   // write_plugin('I', "TEST5A");

   if (regress_error_estimate_stderr)
   {
      // test some stderror handling
      errno = EACCES;
      perror("I've got some unsuspected error which I'd like to display on stderr (COMM_STDERR)");
   }

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/lockfile\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:E 0 300 300 0100640 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vmsnap.iso\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:S 0 0 0 0120777 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   snprintf(buf, BIGBUFLEN, "LSTAT:/bucket/%d/vm1.iso\n", mypid);
   write_plugin('C', buf);
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/\n", PLUGINPREFIX, mypid);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();

   snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/\n", PLUGINPREFIX);
   write_plugin('C', buf);
   write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
   write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
   signal_eod();

   /* this is the end of all data */
   signal_eod();
}

/*
 * The listing procedure
 * when:
 * - / - it display           drwxr-x--- containers
 * - containers - it display  drwxr-x--- bucket1
 *                            drwxr-x--- bucket2
 */
void perform_listing(char *listing){
   /* Listing Loop (5) */
   if (strcmp(listing, "containers") == 0){
      /* this is a containers listing */
      write_plugin('C', "FNAME:bucket1/\n");
      write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();

   if (regress_error_listing_stderr)
   {
      // test some stderror handling
      errno = EACCES;
      perror("I've got some unsuspected error which I'd like to display on stderr (COMM_STDERR)");
   }

      write_plugin('C', "FNAME:bucket2/\n");
      write_plugin('C', "STAT:D 1024 100 100 040755 1\n");
      write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
      signal_eod();
   } else {
      if (strcmp(listing, "containers/bucket1") == 0){
         snprintf(buf, BIGBUFLEN, "FNAME:bucket1/%d/vm1.iso\n", mypid);
         write_plugin('C', buf);
         write_plugin('C', "STAT:F 1048576 100 100 100640 1\n");
         write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
         signal_eod();

         snprintf(buf, BIGBUFLEN, "FNAME:bucket1/%d/lockfile\n", mypid);
         write_plugin('C', buf);
         write_plugin('C', "STAT:E 0 300 300 0100640 1\n");
         write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
         signal_eod();
      } else
      if (strcmp(listing, "containers/bucket2") == 0){
         snprintf(buf, BIGBUFLEN, "FNAME:bucket2/%d/vm2.iso\n", mypid);
         write_plugin('C', buf);
         write_plugin('C', "STAT:F 1048576 200 200 100640 1\n");
         write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
         signal_eod();

         snprintf(buf, BIGBUFLEN, "FNAME:bucket2/%d/vmsnap.iso\n", mypid);
         write_plugin('C', buf);
         write_plugin('C', "STAT:S 0 0 0 0120777 1\n");
         write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
         snprintf(buf, BIGBUFLEN, "LSTAT:/bucket/%d/vm1.iso\n", mypid);
         write_plugin('C', buf);
         signal_eod();
      } else {
         /* this is a top-level listing, response with a single containers list */
         snprintf(buf, BIGBUFLEN, "FNAME:containers\n");
         write_plugin('C', buf);
         write_plugin('C', "STAT:D 0 0 0 040755 1\n");
         write_plugin('C', "TSTAMP:1504271937 1504271937 1504271937\n");
         // write_plugin('I', "TEST5");
         signal_eod();
      }
   }

   /* this is the end of all data */
   signal_eod();
}

const unsigned char m_json[] = {
  0x7b, 0x22, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x22, 0x3a, 0x20, 0x7b,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x62, 0x75, 0x67, 0x22,
  0x3a, 0x20, 0x22, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
  0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x22, 0x3a, 0x20, 0x7b, 0x0a,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74,
  0x6c, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
  0x20, 0x4b, 0x6f, 0x6e, 0x66, 0x61, 0x62, 0x75, 0x6c, 0x61, 0x74, 0x6f,
  0x72, 0x20, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x22, 0x2c, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65,
  0x22, 0x3a, 0x20, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x77, 0x69, 0x6e,
  0x64, 0x6f, 0x77, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x35,
  0x30, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x22, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3a, 0x20, 0x35, 0x30,
  0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20,
  0x20, 0x22, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x20,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x72,
  0x63, 0x22, 0x3a, 0x20, 0x22, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2f,
  0x53, 0x75, 0x6e, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22,
  0x3a, 0x20, 0x22, 0x73, 0x75, 0x6e, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x4f, 0x66, 0x66, 0x73,
  0x65, 0x74, 0x22, 0x3a, 0x20, 0x32, 0x35, 0x30, 0x2c, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x4f, 0x66, 0x66, 0x73,
  0x65, 0x74, 0x22, 0x3a, 0x20, 0x32, 0x35, 0x30, 0x2c, 0x0a, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x6c, 0x69, 0x67, 0x6e,
  0x6d, 0x65, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x63, 0x65, 0x6e, 0x74,
  0x65, 0x72, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20,
  0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x3a, 0x20, 0x7b,
  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x61,
  0x74, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x20,
  0x48, 0x65, 0x72, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x22, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x3a, 0x20, 0x33,
  0x36, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
  0x73, 0x74, 0x79, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x62, 0x6f, 0x6c,
  0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x78,
  0x74, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x22, 0x68, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x3a, 0x20,
  0x32, 0x35, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x22, 0x76, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x3a, 0x20,
  0x31, 0x30, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x22, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x22,
  0x3a, 0x20, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x0a,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6f, 0x6e, 0x4d,
  0x6f, 0x75, 0x73, 0x65, 0x55, 0x70, 0x22, 0x3a, 0x20, 0x22, 0x73, 0x75,
  0x6e, 0x31, 0x2e, 0x6f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x20, 0x3d,
  0x20, 0x28, 0x73, 0x75, 0x6e, 0x31, 0x2e, 0x6f, 0x70, 0x61, 0x63, 0x69,
  0x74, 0x79, 0x20, 0x2f, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x2a, 0x20,
  0x39, 0x30, 0x3b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x7d,
  0x7d, 0x0a, 0x00
};
unsigned int m_json_len = 603;

/*
 * The query param procedure
 *    return 3 simple parameters
 */
void perform_queryparam(const char *query)
{
   /* Query Loop (5) */
   if (strcmp(query, "m_id") == 0) {
      snprintf(buf, BIGBUFLEN, "%s=test1\n", query);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "%s=test2\n", query);
      write_plugin('C', buf);
      snprintf(buf, BIGBUFLEN, "%s=test3\n", query);
      write_plugin('C', buf);
   } else
   if (strcmp(query, "m_json") == 0) {
      write_plugin_bin(m_json, m_json_len);
      write_plugin('D', "UmFkb3PFgmF3IEtvcnplbmlld3NraQo=\n");
   }

   /* this is the end of all data */
   signal_eod();
}

/*
 * The main and universal restore procedure
 */
void perform_restore()
{
   bool loopgo = true;
   bool restore_skip_create = false;
   bool restore_with_core = false;
   bool restore_skip_metadata = false;

   if (regress_error_restore_stderr) {
      // test some stderror handling
      errno = EACCES;
      perror("I've got some unsuspected error which I'd like to display on stderr (COMM_STDERR)");
   }

   /* Restore Loop (5) */
   LOG("#> Restore Loop.");
   while (true) {
      read_plugin(buf);
      /* check if FINISH job */
      if (strcmp(buf, "FINISH\n") == 0) {
         LOG("#> finish files.");
         break;
      }
      /* check for ACL command */
      if (strcmp(buf, "ACL\n") == 0) {
         while (read_plugin(buf) > 0);
         LOG("#> ACL data saved.");
         write_plugin('I', "TEST5R - acl data saved.");
         write_plugin('C', "OK\n");
         continue;
      }

      /* check for XATTR command */
      if (strcmp(buf, "XATTR\n") == 0) {
         while (read_plugin(buf) > 0);
         LOG("#> XATTR data saved.");
         write_plugin('I', "TEST5R - xattr data saved.");
         write_plugin('C', "OK\n");
         continue;
      }
      /* check if FNAME then follow file parameters */
      if (strncmp(buf, "FNAME:", 6) == 0) {
         restore_with_core = strstr(buf, "/_restore_with_core/") != NULL && (strstr(buf, "/etc/issue") != NULL || strstr(buf, "/fileforcore") != NULL);
         restore_skip_create = strstr(buf, "/_restore_skip_create/") != NULL;
         restore_skip_metadata = strstr(buf, "/_restore_skip_metadata/") != NULL;

         /* we read here a file parameters */
         while (read_plugin(buf) > 0);

         if (restore_skip_create){
            // simple skipall
            write_plugin('I', "TEST5R - create file skipped.");
            write_plugin('C', "SKIP\n");
            continue;
         }

         if (restore_with_core){
            // signal Core
            write_plugin('I', "TEST5R - handle file with Core.");
            write_plugin('C', "CORE\n");
            continue;
         }

         // signal OK
         write_plugin('I', "TEST5R - create file ok.");
         write_plugin('C', "OK\n");
         continue;
      }

      /* check for METADATA stream */
      if (strncmp(buf, "METADATA_STREAM", 15) == 0) {
         // handle metadata
         read_plugin_data_stream();
         /* signal OK */
         LOG("#> METADATA_STREAM data saved.");

         if (restore_skip_metadata){
            write_plugin('I', "TEST5R - metadata select skip restore.");
            write_plugin('C', "SKIP\n");
            continue;
         }

         write_plugin('I', "TEST5R - metadata saved.");
         write_plugin('C', "OK\n");
         continue;
      }

      /* Restore Object stream */
      if (strncmp(buf, "RESTOREOBJ", 10) == 0) {
         read_plugin(buf);    // RESTOREOBJ_LEN

         // handle object data
         read_plugin_data_stream();
         /* signal OK */
         LOG("#> RESTOREOBJ data saved.");

         write_plugin('I', "TEST6R - RO saved.");
         write_plugin('C', "OK\n");
         continue;
      }

      /* check if DATA command, so read the data packets */
      if (strcmp(buf, "DATA\n") == 0){
         int len = read_plugin(buf);
         if (len == 0){
            /* empty file to restore */
            LOG("#> Empty file.");
            continue;
         } else {
            LOG("#> file data saved.");
         }
         loopgo = true;
         int fsize = len;
         while (loopgo){
            len = read_plugin(buf);
            fsize += len;
            if (len > 0){
               LOG("#> file data saved.");
               continue;
            } else {
               loopgo = false;
               snprintf(buflog, 4096, "#> file data END = %i", fsize);
            }
         }
         /* confirm restore ok */
         write_plugin('I', "TEST5R - end of data.");
         write_plugin('C', "OK\n");
      } else {
         write_plugin('E', "Error DATA command required.");
         exit(EXIT_BACKEND_DATA_COMMAND_REQ);
      }
   }

   /* this is the end of all data */
   signal_eod();
}

/*
 * Start here
 */
int main(int argc, char** argv) {

   int len;
   char *listing;
   char *query;

   buf = (char*)malloc(BIGBUFLEN);
   if (buf == NULL){
      exit(EXIT_BACKEND_NOMEMORY);
   }
   buflog = (char*)malloc(BUFLEN);
   if (buflog == NULL){
      exit(EXIT_BACKEND_NOMEMORY);
   }
   listing = (char*)malloc(BUFLEN);
   if (listing == NULL){
      exit(EXIT_BACKEND_NOMEMORY);
   }
   query = (char*)malloc(BUFLEN);
   if (query == NULL){
      exit(EXIT_BACKEND_NOMEMORY);
   }

   working_directory[0] = 0;
   mypid = getpid();
   snprintf(buf, 4096, "%s/%s_backend_%d.log", LOGDIR, PLUGINNAME, mypid);
   logfd = open(buf, O_CREAT|O_TRUNC|O_WRONLY, 0640);
   if (logfd < 0){
      exit(EXIT_BACKEND_LOGFILE_ERROR);
   }
   //sleep(30);

#ifdef F_GETPIPE_SZ
   int pipesize = fcntl(STDIN_FILENO, F_GETPIPE_SZ);
   snprintf(buflog, BUFLEN, "#> F_GETPIPE_SZ:%i", pipesize);
   LOG(buflog);
#endif

   /* handshake (1) */
   len = read_plugin(buf);
#if 1
   write_plugin('C',"Hello Bacula\n");
#else
   write_plugin('E',"Invalid Plugin name.");
   goto Term;
#endif

   /* Job Info (2) */
   while ((len = read_plugin(buf)) > 0)
   {
      if (strcmp(buf, "Level=I\n") == 0) {
         Job_Level_Incremental = true;
         continue;
      }
   }

   write_plugin('I', "TEST2");
   signal_eod();

   /* Plugin Params (3) */
   while ((len = read_plugin(buf)) > 0)
   {
      // "regress_error_plugin_params",
      // "regress_error_start_job",
      // "regress_error_backup_no_files",
      // "regress_error_backup_stderr",
      // "regress_error_estimate_stderr",
      // "regress_error_listing_stderr",
      // "regress_error_restore_stderr",
      // "regress_backup_plugin_objects",
      // "regress_error_backup_abort",
      // "regress_standard_error_backup",
      // "regress_cancel_backup",
      // "regress_cancel_restore",

      if (strcmp(buf, "regress_error_plugin_params=1\n") == 0)
      {
         regress_error_plugin_params = true;
         continue;
      }
      if (strcmp(buf, "regress_error_start_job=1\n") == 0)
      {
         regress_error_start_job = true;
         continue;
      }
      if (strcmp(buf, "regress_error_backup_no_files=1\n") == 0)
      {
         regress_error_backup_no_files = true;
         continue;
      }
      if (strcmp(buf, "regress_error_backup_stderr=1\n") == 0)
      {
         regress_error_backup_stderr = true;
         continue;
      }
      if (strcmp(buf, "regress_error_estimate_stderr=1\n") == 0)
      {
         regress_error_estimate_stderr = true;
         continue;
      }
      if (strcmp(buf, "regress_error_listing_stderr=1\n") == 0)
      {
         regress_error_listing_stderr = true;
         continue;
      }
      if (strcmp(buf, "regress_error_restore_stderr=1\n") == 0)
      {
         regress_error_restore_stderr = true;
         continue;
      }
      if (strcmp(buf, "regress_backup_plugin_objects=1\n") == 0)
      {
         regress_backup_plugin_objects = true;
         continue;
      }
      if (strcmp(buf, "regress_error_backup_abort=1\n") == 0)
      {
         regress_error_backup_abort = true;
         continue;
      }
      if (strcmp(buf, "regress_backup_other_file=1\n") == 0)
      {
         regress_backup_other_file = true;
         continue;
      }
      if (strcmp(buf, "regress_backup_external_stat=1\n") == 0)
      {
         regress_backup_external_stat = true;
         continue;
      }
      if (strcmp(buf, "regress_metadata_support=1\n") == 0)
      {
         regress_metadata_support = true;
         continue;
      }
      if (strcmp(buf, "regress_standard_error_backup=1\n") == 0)
      {
         regress_standard_error_backup = true;
         continue;
      }
      if (strcmp(buf, "regress_cancel_backup=1\n") == 0)
      {
         regress_cancel_backup = true;
         continue;
      }
      if (strcmp(buf, "regress_cancel_restore=1\n") == 0)
      {
         regress_cancel_restore = true;
         continue;
      }
      if (sscanf(buf, "listing=%s\n", buf) == 1)
      {
         strcpy(listing, buf);
         continue;
      }
      if (sscanf(buf, "query=%s\n", buf) == 1)
      {
         strcpy(query, buf);
         continue;
      }
      if (sscanf(buf, "regress_working_dir=%s\n", buf) == 1)
      {
         strcpy(working_directory, buf);
         continue;
      }
   }
   if (regress_cancel_restore || regress_cancel_backup)
   {
      if (signal(SIGUSR1, catch_function) == SIG_ERR)
      {
         LOG("Cannot setup signal handler!");
         exit(EXIT_BACKEND_SIGNAL_HANDLER_ERROR);
      }
   }
   write_plugin('I', "TEST3");
   if (!regress_error_plugin_params)
   {
      signal_eod();
   } else {
      write_plugin('E', "We do not accept your TEST3E! AsRequest.");
   }

   /* Start Backup/Estimate/Restore (4) */
   len = read_plugin(buf);
   write_plugin('I', "TEST4");

   if (regress_error_start_job)
   {
      write_plugin('A', "We do not accept your TEST4E! AsRequest.");
      goto Term;
   }

   if (Job_Level_Incremental)
   {
      write_plugin('C', "STRIP:1\n");
   }

   signal_eod();  // ACK of the `BackupStart` phase is always required!

   /* check what kind of Job we have */
   buf[len] = 0;
   if (strcmp(buf, "BackupStart\n") == 0)
   {
      perform_backup();
   } else
   if (strcmp(buf, "EstimateStart\n") == 0)
   {
      perform_estimate();
   } else
   if (strcmp(buf, "ListingStart\n") == 0)
   {
      perform_listing(listing);
   } else
   if (strcmp(buf, "QueryStart\n") == 0)
   {
      perform_queryparam(query);
   } else
   if (strcmp(buf, "RestoreStart\n") == 0)
   {
      perform_restore();
   }

   /* End Job */
   len = read_plugin(buf);
   write_plugin('I', "TESTEND");
   signal_eod();
   len = read_plugin(buf);

Term:
   signal_term();
   LOG("#> Unlink symlink_fname.");
   unlink(symlink_fname);
   LOG("#> Unlink namedpipe_fname.");
   unlink(namedpipe_fname);
   LOG("#> Terminating backend.");
   close(logfd);
   free(buf);
   free(buflog);
   free(listing);
   return (EXIT_SUCCESS);
}
