- Release Notes for Bacula 1.34.0
+ Release Notes for Bacula 1.34.1
Bacula code: Total files = 306 Total lines = 91,131 (*.h *.c *.in)
+Changes for 1.34.1:
+- Autochanger users, please note you must add %d to the end of the
+ changer command line in your Device resource in your bacula-sd.conf
+ file.
+- Fixed a crash in the query command.
+- Removed the schedule from the default restore job.
+
+Release 1.34.0
Major Features:
- Data spooling which reduces tape shoe-shine during Inc backups,
and permits multiple simultaneous backups without interleaved blocks.
*
*/
/*
- Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+ Copyright (C) 2001-2004 Kern Sibbald and John Walker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
*/
#include "bacula.h"
Client=@hostname@-fd
FileSet="Full Set"
Storage = File
+ Pool = Default
Messages = Standard
Where = /tmp/bacula-restores
}
extern DIRRES *director;
-static char *substitute_prompts(UAContext *ua,
- char *query, char **prompt, int nprompt);
+static POOLMEM *substitute_prompts(UAContext *ua,
+ POOLMEM *query, char **prompt, int nprompt);
/*
* Read a file containing SQL queries and prompt
*/
int querycmd(UAContext *ua, char *cmd)
{
- FILE *fd;
+ FILE *fd = NULL;
POOLMEM *query = get_pool_memory(PM_MESSAGE);
char line[1000];
int i, item, len;
char *prompt[9];
- int nprompt;
+ int nprompt = 0;;
char *query_file = director->query_file;
if (!open_db(ua)) {
- free_pool_memory(query);
- return 1;
+ goto bail_out;
}
if ((fd=fopen(query_file, "r")) == NULL) {
bsendmsg(ua, "Could not open %s: ERR=%s\n", query_file,
strerror(errno));
- free_pool_memory(query);
- return 1;
+ goto bail_out;
}
start_prompt(ua, _("Available queries:\n"));
}
}
if ((item=do_prompt(ua, "", _("Choose a query"), NULL, 0)) < 0) {
- fclose(fd);
- free_pool_memory(query);
- return 1;
+ goto bail_out;
}
rewind(fd);
i = -1;
}
if (i != item) {
bsendmsg(ua, _("Could not find query.\n"));
- fclose(fd);
- free_pool_memory(query);
- return 1;
+ goto bail_out;
}
query[0] = 0;
for (i=0; i<9; i++) {
prompt[i] = NULL;
}
- nprompt = 0;
while (fgets(line, sizeof(line), fd) != NULL) {
if (line[0] == '#') {
continue;
continue;
}
}
- query = check_pool_memory_size(query, len + 1);
if (*query != 0) {
- strcat(query, " ");
+ pm_strcat(&query, " ");
}
- strcat(query, line);
+ pm_strcat(&query, line);
if (line[len-1] != ';') {
continue;
}
bsendmsg(ua, "%s\n", query);
}
}
+
+bail_out:
+ if (fd) {
+ fclose(fd);
+ }
free_pool_memory(query);
for (i=0; i<nprompt; i++) {
free(prompt[i]);
}
static POOLMEM *substitute_prompts(UAContext *ua,
- char *query, char **prompt, int nprompt)
+ POOLMEM *query, char **prompt, int nprompt)
{
char *p, *q, *o;
POOLMEM *new_query;
* so that the memory is allocated through smartalloc.
*/
+#ifdef xxx
void * operator new(size_t size)
{
// Dmsg1(000, "new called %d\n", size);
// Dmsg1(000, "free called 0x%x\n", buf);
sm_free(__FILE__, __LINE__, buf);
}
+#endif
#endif
if (spool_stats.data_size < 0) {
spool_stats.data_size = 0;
}
+ jcr->dcr->spool_size = 0;
V(mutex);
make_unique_data_spool_filename(jcr, &name);
dcr->spooling = false;
lock_device(dcr->dev);
dcr->dev_locked = true;
- /* Set up a dev structure to read */
+
+ /* Setup a dev structure to read */
rdev = (DEVICE *)malloc(sizeof(DEVICE));
memset(rdev, 0, sizeof(DEVICE));
rdev->dev_name = get_memory(strlen("spool")+1);
strcpy(rdev->dev_name, "spool");
rdev->errmsg = get_pool_memory(PM_EMSG);
*rdev->errmsg = 0;
+ rdev->max_block_size = dcr->dev->max_block_size;
+ rdev->min_block_size = dcr->dev->min_block_size;
rdev->device = dcr->dev->device;
rdcr = new_dcr(NULL, rdev);
rdcr->spool_fd = dcr->spool_fd;
rdcr->jcr = jcr; /* set a valid jcr */
block = rdcr->block;
+ Dmsg1(800, "read/write block size = %d\n", block->buf_len);
lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */
for ( ; ok; ) {
--- /dev/null
+General compiling notes:
+ - Fetch latest bacula sources from CVS or bacula-1.34.0 source
+ tarball, configure and build it.
+ - Extract bacula-wx-gui.tar.gz in bacula/src directory.
+
+Windows/cygwin compiling notes:
+ - Build and install wxWindows from sources
+ (http://www.wxwindows.org/). I'm not sure it's necessary but
+ this is how I get the thing to work.
+ - In bacula/src/wx-console/Makefile.win, modify every
+ occurrence of "J:/cygwin" with the path where cygwin is install
+ on your system
+ ~ Build bacula-wx-gui with "make -f Makefile.win" in bacula/src/wx-console
+
+GTK/Linux compiling notes:
+ - Comment out "new" and "delete" operator definitions in
+ bacula/src/lib/smartall.c (lines 501-511), because these
+ overloads seem to produce segmentation faults with wxWindows, and
+ do "make" again in bacula/src/lib
+ - Build bacula-wx-gui with "make all" in bacula/src/wx-console
--- /dev/null
+12-04-2004 :
+ - The source code is now better documented
+ - wxbRestorePanel : Check if a client was selected before
+ entering choose mode
+ - The source code is now right idented (3 spaces by level)
+ - Copyrights changed to Kern Sibbald and John Walker
+ - wxbPanel : super-class access rights problem corrected
+ - wxbRestorePanel : Added "nice" images to indicate restore status
--- /dev/null
+
+wxbRestorePanel : Allow the user to choose where he wants to restore his files
+
+wxbPanel/wxbMainFrame : Add a locking function (for example, deny the user to type something in the console when a restore is in progress)
+
+wxbRestorePanel : Check more carefully which job we just have run.
+
+console_thread : Allow the user to choose his config file.
+
+(old build params : )
+-lgcc -lodbc32 -lwsock32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lctl3d32 -ladvapi32 -lopengl32 -lglu32 -lole32 -loleaut32 -luuid
+-lkernel32 -lcomdlg32 -lgdi32 -lrpcrt4 -luser32 -lz
+
+-fno-pcc-struct-return -Os -fno-rtti -fno-exceptions
--- /dev/null
+/*
+ *
+ * Bacula UA authentication. Provides authentication with
+ * the Director.
+ *
+ * Kern Sibbald, June MMI
+ *
+ * This routine runs as a thread and must be thread reentrant.
+ *
+ * Basic tasks done here:
+ *
+ */
+/*
+ Copyright (C) 2001-2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+ */
+
+#include "bacula.h"
+#include "console_conf.h"
+#include "jcr.h"
+
+#include "csprint.h"
+
+void senditf(char *fmt, ...);
+void sendit(char *buf);
+
+/* Commands sent to Director */
+static char hello[] = "Hello %s calling\n";
+
+/* Response from Director */
+static char OKhello[] = "1000 OK:";
+
+/* Forward referenced functions */
+
+/*
+ * Authenticate Director
+ */
+int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons)
+{
+ BSOCK *dir = jcr->dir_bsock;
+ int ssl_need = BNET_SSL_NONE;
+ char bashed_name[MAX_NAME_LENGTH];
+ char *password;
+
+ /*
+ * Send my name to the Director then do authentication
+ */
+ if (cons) {
+ bstrncpy(bashed_name, cons->hdr.name, sizeof(bashed_name));
+ bash_spaces(bashed_name);
+ password = cons->password;
+ } else {
+ bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name));
+ password = director->password;
+ }
+ /* Timeout Hello after 5 mins */
+ btimer_t *tid = start_bsock_timer(dir, 60 * 5);
+ bnet_fsend(dir, hello, bashed_name);
+
+ if (!cram_md5_get_auth(dir, password, ssl_need) ||
+ !cram_md5_auth(dir, password, ssl_need)) {
+ stop_bsock_timer(tid);
+ csprint("Director authorization problem.\nMost likely the passwords do not agree.\n", CS_DATA);
+ return 0;
+ }
+
+ Dmsg1(6, ">dird: %s", dir->msg);
+ if (bnet_recv(dir) <= 0) {
+ stop_bsock_timer(tid);
+ csprint("Bad response to Hello command: ERR=", CS_DATA);
+ csprint(bnet_strerror(dir), CS_DATA);
+ csprint("\n", CS_DATA);
+ return 0;
+ }
+ Dmsg1(10, "<dird: %s", dir->msg);
+ stop_bsock_timer(tid);
+ if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) {
+ csprint("Director rejected Hello command\n", CS_DATA);
+ return 0;
+ } else {
+ csprint(dir->msg, CS_DATA);
+ }
+ return 1;
+}
+
--- /dev/null
+/*
+ * Main configuration file parser for Bacula User Agent
+ * some parts may be split into separate files such as
+ * the schedule configuration (sch_config.c).
+ *
+ * Note, the configuration file parser consists of three parts
+ *
+ * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
+ *
+ * 2. The generic config scanner in lib/parse_config.c and
+ * lib/parse_config.h.
+ * These files contain the parser code, some utility
+ * routines, and the common store routines (name, int,
+ * string).
+ *
+ * 3. The daemon specific file, which contains the Resource
+ * definitions as well as any specific store routines
+ * for the resource records.
+ *
+ * Kern Sibbald, January MM, September MM
+ */
+
+/*
+ Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "bacula.h"
+#include "console_conf.h"
+
+/* Define the first and last resource ID record
+ * types. Note, these should be unique for each
+ * daemon though not a requirement.
+ */
+int r_first = R_FIRST;
+int r_last = R_LAST;
+
+/* Forward referenced subroutines */
+
+
+/* We build the current resource here as we are
+ * scanning the resource configuration definition,
+ * then move it to allocated memory when the resource
+ * scan is complete.
+ */
+URES res_all;
+int res_all_size = sizeof(res_all);
+
+/* Definition of records permitted within each
+ * resource with the routine to process the record
+ * information.
+ */
+
+/* Console "globals" */
+static RES_ITEM cons_items[] = {
+ {"name", store_name, ITEM(res_cons.hdr.name), 0, ITEM_REQUIRED, 0},
+ {"description", store_str, ITEM(res_cons.hdr.desc), 0, 0, 0},
+ {"rcfile", store_dir, ITEM(res_cons.rc_file), 0, 0, 0},
+ {"historyfile", store_dir, ITEM(res_cons.hist_file), 0, 0, 0},
+ {"requiressl", store_yesno, ITEM(res_cons.require_ssl), 1, ITEM_DEFAULT, 0},
+ {"password", store_password, ITEM(res_cons.password), 0, ITEM_REQUIRED, 0},
+ {NULL, NULL, NULL, 0, 0, 0}
+};
+
+
+/* Director's that we can contact */
+static RES_ITEM dir_items[] = {
+ {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
+ {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
+ {"dirport", store_int, ITEM(res_dir.DIRport), 0, ITEM_DEFAULT, 9101},
+ {"address", store_str, ITEM(res_dir.address), 0, 0, 0},
+ {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
+ {"enablessl", store_yesno, ITEM(res_dir.enable_ssl), 1, ITEM_DEFAULT, 0},
+ {NULL, NULL, NULL, 0, 0, 0}
+};
+
+/*
+ * This is the master resource definition.
+ * It must have one item for each of the resources.
+ */
+RES_TABLE resources[] = {
+ {"console", cons_items, R_CONSOLE, NULL},
+ {"director", dir_items, R_DIRECTOR, NULL},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/* Dump contents of resource */
+void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock)
+{
+ URES *res = (URES *)reshdr;
+ int recurse = 1;
+
+ if (res == NULL) {
+ printf("No record for %d %s\n", type, res_to_str(type));
+ return;
+ }
+ if (type < 0) { /* no recursion */
+ type = - type;
+ recurse = 0;
+ }
+ switch (type) {
+ case R_CONSOLE:
+ printf("Console: name=%s rcfile=%s histfile=%s\n", reshdr->name,
+ res->res_cons.rc_file, res->res_cons.hist_file);
+ break;
+ case R_DIRECTOR:
+ printf("Director: name=%s address=%s DIRport=%d\n", reshdr->name,
+ res->res_dir.address, res->res_dir.DIRport);
+ break;
+ default:
+ printf("Unknown resource type %d\n", type);
+ }
+ if (recurse && res->res_dir.hdr.next) {
+ dump_resource(type, res->res_dir.hdr.next, sendit, sock);
+ }
+}
+
+/*
+ * Free memory of resource.
+ * NB, we don't need to worry about freeing any references
+ * to other resources as they will be freed when that
+ * resource chain is traversed. Mainly we worry about freeing
+ * allocated strings (names).
+ */
+void free_resource(RES *sres, int type)
+{
+ RES *nres;
+ URES *res = (URES *)sres;
+
+ if (res == NULL)
+ return;
+
+ /* common stuff -- free the resource name */
+ nres = (RES *)res->res_dir.hdr.next;
+ if (res->res_dir.hdr.name) {
+ free(res->res_dir.hdr.name);
+ }
+ if (res->res_dir.hdr.desc) {
+ free(res->res_dir.hdr.desc);
+ }
+
+ switch (type) {
+ case R_CONSOLE:
+ if (res->res_cons.rc_file) {
+ free(res->res_cons.rc_file);
+ }
+ if (res->res_cons.hist_file) {
+ free(res->res_cons.hist_file);
+ }
+ case R_DIRECTOR:
+ if (res->res_dir.address)
+ free(res->res_dir.address);
+ break;
+ default:
+ printf("Unknown resource type %d\n", type);
+ }
+ /* Common stuff again -- free the resource, recurse to next one */
+ free(res);
+ if (nres) {
+ free_resource(nres, type);
+ }
+}
+
+/* Save the new resource by chaining it into the head list for
+ * the resource. If this is pass 2, we update any resource
+ * pointers (currently only in the Job resource).
+ */
+void save_resource(int type, RES_ITEM *items, int pass)
+{
+ URES *res;
+ int rindex = type - r_first;
+ int i, size;
+ int error = 0;
+
+ /*
+ * Ensure that all required items are present
+ */
+ for (i=0; items[i].name; i++) {
+ if (items[i].flags & ITEM_REQUIRED) {
+ if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
+ Emsg2(M_ABORT, 0, "%s item is required in %s resource, but not found.\n",
+ items[i].name, resources[rindex]);
+ }
+ }
+ }
+
+ /* During pass 2, we looked up pointers to all the resources
+ * referrenced in the current resource, , now we
+ * must copy their address from the static record to the allocated
+ * record.
+ */
+ if (pass == 2) {
+ switch (type) {
+ /* Resources not containing a resource */
+ case R_CONSOLE:
+ case R_DIRECTOR:
+ break;
+
+ default:
+ Emsg1(M_ERROR, 0, "Unknown resource type %d\n", type);
+ error = 1;
+ break;
+ }
+ /* Note, the resoure name was already saved during pass 1,
+ * so here, we can just release it.
+ */
+ if (res_all.res_dir.hdr.name) {
+ free(res_all.res_dir.hdr.name);
+ res_all.res_dir.hdr.name = NULL;
+ }
+ if (res_all.res_dir.hdr.desc) {
+ free(res_all.res_dir.hdr.desc);
+ res_all.res_dir.hdr.desc = NULL;
+ }
+ return;
+ }
+
+ /* The following code is only executed during pass 1 */
+ switch (type) {
+ case R_CONSOLE:
+ size = sizeof(CONRES);
+ break;
+ case R_DIRECTOR:
+ size = sizeof(DIRRES);
+ break;
+ default:
+ printf("Unknown resource type %d\n", type);
+ error = 1;
+ size = 1;
+ break;
+ }
+ /* Common */
+ if (!error) {
+ res = (URES *)malloc(size);
+ memcpy(res, &res_all, size);
+ if (!resources[rindex].res_head) {
+ resources[rindex].res_head = (RES *)res; /* store first entry */
+ } else {
+ RES *next;
+ for (next=resources[rindex].res_head; next->next; next=next->next) {
+ if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
+ Emsg2(M_ERROR_TERM, 0,
+ _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
+ resources[rindex].name, res->res_dir.hdr.name);
+ }
+ }
+ next->next = (RES *)res;
+ Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
+ res->res_dir.hdr.name);
+ }
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2000-2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CONSOLECONF_H
+#define CONSOLECONF_H
+
+#include "bacula.h"
+#include "jcr.h"
+
+/*
+ * Resource codes -- they must be sequential for indexing
+ */
+#define R_FIRST 1001
+
+#define R_CONSOLE 1001
+#define R_DIRECTOR 1002
+
+#define R_LAST R_DIRECTOR
+
+/*
+ * Some resource attributes
+ */
+#define R_NAME 1020
+#define R_ADDRESS 1021
+#define R_PASSWORD 1022
+#define R_TYPE 1023
+#define R_BACKUP 1024
+
+
+/* Definition of the contents of each Resource */
+
+/* Console "globals" */
+struct s_res_con {
+ RES hdr;
+ char *rc_file; /* startup file */
+ char *hist_file; /* command history file */
+ int require_ssl; /* Require SSL on all connections */
+ char *password; /* UA server password */
+};
+typedef struct s_res_con CONRES;
+
+/* Director */
+struct s_res_dir {
+ RES hdr;
+ int DIRport; /* UA server port */
+ char *address; /* UA server address */
+ char *password; /* UA server password */
+ int enable_ssl; /* Use SSL */
+};
+typedef struct s_res_dir DIRRES;
+
+
+/* Define the Union of all the above
+ * resource structure definitions.
+ */
+union u_res {
+ struct s_res_dir res_dir;
+ struct s_res_con res_cons;
+ RES hdr;
+};
+
+typedef union u_res URES;
+
+#endif // CONSOLECONF_H
--- /dev/null
+/*
+ *
+ * Interaction thread between director and the GUI
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "console_thread.h" // class's header file
+
+#include <wx/wxprec.h>
+
+#include <wx/thread.h>
+#include <bacula.h>
+#include <jcr.h>
+
+#include "console_conf.h"
+
+#include "csprint.h"
+
+/* Imported functions */
+int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
+
+// class constructor
+console_thread::console_thread() {
+ UA_sock = NULL;
+}
+
+// class destructor
+console_thread::~console_thread() {
+ if (UA_sock) {
+ bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
+ bnet_close(UA_sock);
+ UA_sock = NULL;
+ }
+}
+
+/*
+ * Thread entry point
+ */
+void* console_thread::Entry() {
+ csprint("Connecting...\n");
+
+ init_stack_dump();
+ my_name_is(0, NULL, "console");
+ textdomain("bacula-console");
+ init_msg(NULL, NULL);
+
+ /* TODO (#4#): Allow the user to choose his config file. */
+ parse_config("./console.conf");
+
+ LockRes();
+ DIRRES *dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
+ UnlockRes();
+
+ memset(&jcr, 0, sizeof(jcr));
+
+ UA_sock = bnet_connect(&jcr, 5, 15, "Director daemon", dir->address, NULL, dir->DIRport, 0);
+ if (UA_sock == NULL) {
+ csprint("NULL\n");
+ return NULL;
+ }
+
+ csprint("Connected\n");
+
+ jcr.dir_bsock = UA_sock;
+ if (!authenticate_director(&jcr, dir, NULL)) {
+ csprint("ERR=");
+ csprint(UA_sock->msg);
+ return NULL;
+ }
+
+ Write("messages\n");
+
+ int stat;
+
+ /* main loop */
+ while(!TestDestroy()) { /* Tests if thread has been ended */
+ if ((stat = bnet_recv(UA_sock)) >= 0) {
+ csprint(UA_sock->msg);
+ }
+ else {
+ csprint(NULL, CS_END);
+ }
+
+ if (is_bnet_stop(UA_sock)) {
+ csprint(NULL, CS_END);
+ break; /* error or term */
+ }
+ }
+
+ csprint("Connection terminated\n");
+
+ return 0;
+}
+
+void console_thread::Write(const char* str) {
+ if (UA_sock) {
+ UA_sock->msglen = strlen(str);
+ pm_strcpy(&UA_sock->msg, str);
+ bnet_send(UA_sock);
+ }
+}
+
+void console_thread::Delete() {
+ Write("quit\n");
+ if (UA_sock) {
+ bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
+ bnet_close(UA_sock);
+ UA_sock = NULL;
+ }
+}
+
--- /dev/null
+/*
+ *
+ * Interaction thread between director and the GUI
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CONSOLE_THREAD_H
+#define CONSOLE_THREAD_H
+
+#include <wx/wxprec.h>
+
+#include <wx/thread.h> // inheriting class's header file
+#include "bacula.h"
+#include "jcr.h"
+
+/**
+ * Console thread, does interaction between bacula routines and the GUI
+ */
+class console_thread : public wxThread
+{
+ public:
+ // class constructor
+ console_thread();
+ // class destructor
+ ~console_thread();
+
+ void* Entry();
+ void Write(const char* str);
+ virtual void Delete();
+ private:
+ BSOCK* UA_sock;
+ JCR jcr;
+};
+
+int pm_cst_strcpy(POOLMEM **pm, const char *str);
+
+#endif // CONSOLE_THREAD_H
+
--- /dev/null
+/*
+ *
+ * csprint header file, used by console_thread to send events back to the GUI.
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CSPRINT_H
+#define CSPRINT_H
+
+#define CS_DATA 1 /* data has been received */
+#define CS_END 2 /* no data to receive anymore */
+#define CS_DEBUG 3 /* used to print debug messages */
+
+/* function called by console_thread to send events back to the GUI */
+void csprint(char* str, int status=CS_DATA);
+
+#endif
--- /dev/null
+/*
+ *
+ * Bacula wx GUI application
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWindows headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include "wxbmainframe.h"
+
+#include "csprint.h"
+
+// ----------------------------------------------------------------------------
+// resources
+// ----------------------------------------------------------------------------
+
+
+class MyApp : public wxApp
+{
+public:
+ virtual bool OnInit();
+};
+
+IMPLEMENT_APP(MyApp)
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// the application class
+// ----------------------------------------------------------------------------
+
+// 'Main program' equivalent: the program execution "starts" here
+bool MyApp::OnInit()
+{
+ wxbMainFrame *frame = wxbMainFrame::CreateInstance(_T("Minimal wxWindows App"),
+ wxPoint(50, 50), wxSize(780, 500));
+
+ frame->Show(TRUE);
+
+ frame->StartConsoleThread();
+
+ csprint("Console started !\n");
+
+ return TRUE;
+}
--- /dev/null
+/* XPM */
+static char *marked_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 16 1",
+" c Gray0",
+". c #bf0000",
+"X c #00bf00",
+"o c #bfbf00",
+"O c #0000bf",
+"+ c #bf00bf",
+"@ c #00bfbf",
+"# c None",
+"$ c #808080",
+"% c Red",
+"& c Green",
+"* c Yellow",
+"= c Blue",
+"- c Magenta",
+"; c Cyan",
+": c Gray100",
+/* pixels */
+"################",
+"################",
+"################",
+"################",
+"############&&&#",
+"###########&&&##",
+"#########&&&&###",
+"########&&&&####",
+"##&&&##&&&&#####",
+"###&&&&&&&######",
+"####&&&&&#######",
+"#####&&&########",
+"######&#########",
+"################",
+"################",
+"################"
+};
+
--- /dev/null
+/* XPM */
+static char *partmarked_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 16 1",
+" c Gray0",
+". c #bf0000",
+"X c #00bf00",
+"o c #bfbf00",
+"O c #0000bf",
+"+ c #bf00bf",
+"@ c #00bfbf",
+"# c None",
+"$ c #808080",
+"% c Red",
+"& c Green",
+"* c Yellow",
+"= c Blue",
+"- c Magenta",
+"; c Cyan",
+": c Gray100",
+/* pixels */
+"################",
+"################",
+"################",
+"##%%%######%%%##",
+"###%%%####%%%###",
+"####%%%##%%%####",
+"#####%%%%%%#####",
+"######%%%%######",
+"######%%%%######",
+"#####%%%%%%#####",
+"####%%%##%%%####",
+"###%%%####%%%#&&",
+"##%%%######%%&&#",
+"########&&##&&##",
+"#########&&&&###",
+"##########&&####"
+};
+
--- /dev/null
+/* XPM */
+static char *unmarked_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 16 1",
+" c Gray0",
+". c #bf0000",
+"X c #00bf00",
+"o c #bfbf00",
+"O c #0000bf",
+"+ c #bf00bf",
+"@ c #00bfbf",
+"# c None",
+"$ c #808080",
+"% c Red",
+"& c Green",
+"* c Yellow",
+"= c Blue",
+"- c Magenta",
+"; c Cyan",
+": c Gray100",
+/* pixels */
+"################",
+"################",
+"################",
+"##%%%######%%%##",
+"###%%%####%%%###",
+"####%%%##%%%####",
+"#####%%%%%%#####",
+"######%%%%######",
+"######%%%%######",
+"#####%%%%%%#####",
+"####%%%##%%%####",
+"###%%%####%%%###",
+"##%%%######%%%##",
+"################",
+"################",
+"################"
+};
+
--- /dev/null
+/*
+ *
+ * Main frame
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wxbmainframe.h" // class's header file
+
+#include "wxbrestorepanel.h"
+
+#include "csprint.h"
+
+#include "wxwin16x16.xpm"
+
+// ----------------------------------------------------------------------------
+// event tables and other macros for wxWindows
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// IDs for the controls and the menu commands
+enum
+{
+ // menu items
+ Minimal_Quit = 1,
+
+ // it is important for the id corresponding to the "About" command to have
+ // this standard value as otherwise it won't be handled properly under Mac
+ // (where it is special and put into the "Apple" menu)
+ Minimal_About = wxID_ABOUT,
+ TypeText = 2,
+ Thread = 3
+};
+
+/*
+ * wxbTHREAD_EVENT declaration, used by csprint
+ */
+BEGIN_DECLARE_EVENT_TYPES()
+ DECLARE_EVENT_TYPE(wxbTHREAD_EVENT, 1)
+END_DECLARE_EVENT_TYPES()
+
+DEFINE_EVENT_TYPE(wxbTHREAD_EVENT)
+
+// the event tables connect the wxWindows events with the functions (event
+// handlers) which process them. It can be also done at run-time, but for the
+// simple menu events like this the static method is much simpler.
+BEGIN_EVENT_TABLE(wxbMainFrame, wxFrame)
+ EVT_MENU(Minimal_Quit, wxbMainFrame::OnQuit)
+ EVT_MENU(Minimal_About, wxbMainFrame::OnAbout)
+ EVT_TEXT_ENTER(TypeText, wxbMainFrame::OnEnter)
+ EVT_CUSTOM(wxbTHREAD_EVENT, Thread, wxbMainFrame::OnPrint)
+END_EVENT_TABLE()
+
+// ----------------------------------------------------------------------------
+// wxbThreadEvent
+// ----------------------------------------------------------------------------
+
+/*
+ * wxbThreadEvent constructor
+ */
+wxbThreadEvent::wxbThreadEvent(int id): wxEvent(id, wxbTHREAD_EVENT) {
+ m_eventObject = NULL;
+}
+
+/*
+ * wxbThreadEvent destructor
+ */
+wxbThreadEvent::~wxbThreadEvent()
+{
+ if (m_eventObject != NULL) {
+ delete m_eventObject;
+ }
+}
+
+/*
+ * wxbThreadEvent copy constructor
+ */
+wxbThreadEvent::wxbThreadEvent(const wxbThreadEvent& te)
+{
+ this->m_eventType = te.m_eventType;
+ this->m_id = te.m_id;
+ if (te.m_eventObject != NULL) {
+ this->m_eventObject = new wxbPrintObject(*((wxbPrintObject*)te.m_eventObject));
+ }
+ else {
+ this->m_eventObject = NULL;
+ }
+ this->m_skipped = te.m_skipped;
+ this->m_timeStamp = te.m_timeStamp;
+}
+
+/*
+ * Must be implemented (abstract in wxEvent)
+ */
+wxEvent* wxbThreadEvent::Clone() const
+{
+ return new wxbThreadEvent(*this);
+}
+
+/*
+ * Gets the wxbPrintObject attached to this event, containing data sent by director
+ */
+wxbPrintObject* wxbThreadEvent::GetEventPrintObject()
+{
+ return (wxbPrintObject*)m_eventObject;
+}
+
+/*
+ * Sets the wxbPrintObject attached to this event
+ */
+void wxbThreadEvent::SetEventPrintObject(wxbPrintObject* object)
+{
+ m_eventObject = (wxObject*)object;
+}
+
+// ----------------------------------------------------------------------------
+// main frame
+// ----------------------------------------------------------------------------
+
+wxbMainFrame *wxbMainFrame::frame = NULL;
+
+/*
+ * Singleton constructor
+ */
+wxbMainFrame* wxbMainFrame::CreateInstance(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
+{
+ frame = new wxbMainFrame(title, pos, size, style);
+ return frame;
+}
+
+/*
+ * Returns singleton instance
+ */
+wxbMainFrame* wxbMainFrame::GetInstance()
+{
+ return frame;
+}
+
+/*
+ * Private destructor
+ */
+wxbMainFrame::~wxbMainFrame()
+{
+ ct->Delete();
+}
+
+/*
+ * Private constructor
+ */
+wxbMainFrame::wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
+ : wxFrame(NULL, -1, title, pos, size, style)
+{
+ ct = NULL;
+
+ // set the frame icon
+ SetIcon(wxIcon(wxwin16x16_xpm));
+
+#if wxUSE_MENUS
+ // create a menu bar
+ wxMenu *menuFile = new wxMenu;
+
+ // the "About" item should be in the help menu
+ wxMenu *helpMenu = new wxMenu;
+ helpMenu->Append(Minimal_About, _T("&About...\tF1"), _T("Show about dialog"));
+
+ menuFile->Append(Minimal_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
+
+ // now append the freshly created menu to the menu bar...
+ wxMenuBar *menuBar = new wxMenuBar();
+ menuBar->Append(menuFile, _T("&File"));
+ menuBar->Append(helpMenu, _T("&Help"));
+
+ // ... and attach this menu bar to the frame
+ SetMenuBar(menuBar);
+#endif // wxUSE_MENUS
+
+#if wxUSE_STATUSBAR
+ // create a status bar just for fun (by default with 1 pane only)
+ CreateStatusBar(2);
+ SetStatusText(_T("Welcome to Bacula wx-GUI!"));
+#endif // wxUSE_STATUSBAR
+
+ wxPanel* global = new wxPanel(this, -1);
+
+ notebook = new wxNotebook(global, -1);
+
+ /* Console */
+
+ wxPanel* consolePanel = new wxPanel(notebook, -1);
+ notebook->AddPage(consolePanel, "Console");
+
+ consoleCtrl = new wxTextCtrl(consolePanel,-1,"",wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH);
+ consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)));
+
+ typeCtrl = new wxTextCtrl(consolePanel,TypeText,"",wxDefaultPosition,wxSize(200,20), wxTE_PROCESS_ENTER);
+
+ wxFlexGridSizer *consoleSizer = new wxFlexGridSizer(2, 1, 0, 0);
+ consoleSizer->AddGrowableCol(0);
+ consoleSizer->AddGrowableRow(0);
+
+ consoleSizer->Add(consoleCtrl, 1, wxEXPAND | wxALL, 0);
+ consoleSizer->Add(typeCtrl, 0, wxEXPAND | wxALL, 0);
+
+ consolePanel->SetAutoLayout( TRUE );
+ consolePanel->SetSizer( consoleSizer );
+ consoleSizer->SetSizeHints( consolePanel );
+
+ // Creates the list of panels which are included in notebook, and that need to receive director information
+
+ panels = new (wxbPanel*)[2];
+ panels[0] = new wxbRestorePanel(notebook);
+ panels[1] = NULL;
+
+ for (int i = 0; panels[i] != NULL; i++) {
+ notebook->AddPage(panels[i], panels[i]->GetTitle());
+ }
+
+ wxBoxSizer* globalSizer = new wxBoxSizer(wxHORIZONTAL);
+
+ globalSizer->Add(new wxNotebookSizer(notebook), 1, wxEXPAND, 0);
+
+ global->SetSizer( globalSizer );
+ globalSizer->SetSizeHints( global );
+
+ wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
+
+ sizer->Add(global, 1, wxEXPAND | wxALL, 0);
+ SetAutoLayout(true);
+ SetSizer( sizer );
+ //sizer->SetSizeHints( this );
+}
+
+/*
+ * Starts the thread interacting with the director
+ */
+void wxbMainFrame::StartConsoleThread()
+{
+ if (ct != NULL) {
+ ct->Delete();
+ }
+ ct = new console_thread();
+ ct->Create();
+ ct->Run();
+}
+
+// event handlers
+
+void wxbMainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
+{
+ // TRUE is to force the frame to close
+ Close(TRUE);
+}
+
+void wxbMainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
+{
+ wxString msg;
+ msg.Printf( _T("Welcome to Bacula wx-GUI.\n (c) 2004 Nicolas Boichat <nicolas@boichat.ch>\n")
+ _T("Version : %s"), wxVERSION_STRING);
+
+ wxMessageBox(msg, _T("About Bacula-wx-GUI"), wxOK | wxICON_INFORMATION, this);
+}
+
+void wxbMainFrame::OnEnter(wxCommandEvent& WXUNUSED(event))
+{
+ wxString str = typeCtrl->GetValue() + "\n";
+ Send(str);
+}
+
+/*
+ * Called when data is arriving from director
+ */
+void wxbMainFrame::OnPrint(wxbThreadEvent& event) {
+ wxbPrintObject* po = event.GetEventPrintObject();
+
+ Print(po->str, po->status);
+}
+
+/*
+ * Prints data received from director to the console, and forwards it to the panels
+ */
+void wxbMainFrame::Print(wxString str, int status)
+{
+ // CS_DEBUG is often sent by panels, so resend it to them would cause an infinite loop
+ if (status != CS_DEBUG) {
+ for (int i = 0; panels[i] != NULL; i++) {
+ panels[i]->Print(str, status);
+ }
+ }
+
+ if (status == CS_END) {
+ str = "#";
+ }
+
+ consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK));
+ (*consoleCtrl) << str;
+ consoleCtrl->SetInsertionPointEnd();
+}
+
+/*
+ * Sends data to the director
+ */
+void wxbMainFrame::Send(wxString str)
+{
+ ct->Write((const char*)str);
+ typeCtrl->SetValue("");
+ consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED));
+ (*consoleCtrl) << str;
+}
+
+/*
+ * Used by csprint, which is called by console thread.
+ *
+ * In GTK and perhaps X11, only the main thread is allowed to interact with
+ * graphical components, so by firing an event, the main loop will call OnPrint.
+ *
+ * Calling OnPrint directly from console thread produces "unexpected async replies".
+ */
+void firePrintEvent(wxString str, int status)
+{
+ wxbPrintObject* po = new wxbPrintObject(str, status);
+
+ wxbThreadEvent evt(Thread);
+ evt.SetEventPrintObject(po);
+
+ wxbMainFrame::GetInstance()->AddPendingEvent(evt);
+}
+
+wxString csBuffer; /* Temporary buffer for receiving data from console thread */
+
+/*
+ * Called by console thread, this function forwards data line by line and end
+ * signals to the GUI.
+ */
+void csprint(char* str, int status)
+{
+ if (str != 0) {
+ int len = strlen(str);
+ bool allnewline = true;
+ for (int i = 0; i < len; i++) {
+ if (!(allnewline = (str[i] == '\n')))
+ break;
+ }
+
+ if (allnewline) {
+ firePrintEvent(csBuffer << "\n", CS_DATA);
+ csBuffer = "";
+ for (int i = 1; i < len; i++) {
+ firePrintEvent("\n", status);
+ }
+ }
+ else {
+ wxStringTokenizer tkz(str, "\n", wxTOKEN_RET_DELIMS | wxTOKEN_RET_EMPTY | wxTOKEN_RET_EMPTY_ALL);
+
+ while ( tkz.HasMoreTokens() ) {
+ csBuffer << tkz.GetNextToken();
+ if (csBuffer.Length() != 0) {
+ if ((csBuffer.GetChar(csBuffer.Length()-1) == '\n') ||
+ (csBuffer.GetChar(csBuffer.Length()-1) == '\r')) {
+ firePrintEvent(csBuffer, status);
+ csBuffer = "";
+ }
+ }
+ }
+ }
+
+ if (csBuffer == "$ ") { // Restore console
+ firePrintEvent(csBuffer, status);
+ csBuffer = "";
+ }
+ }
+
+ if (status == CS_END) {
+ if (csBuffer.Length() != 0) {
+ firePrintEvent(csBuffer, CS_DATA);
+ }
+ csBuffer = "";
+ firePrintEvent("", CS_END);
+ }
+}
+
--- /dev/null
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef WXBMAINFRAME_H
+#define WXBMAINFRAME_H
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWindows headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include <wx/textctrl.h>
+#include <wx/tokenzr.h>
+#include <wx/notebook.h>
+
+//#include "bacula.h"
+//#include "console_conf.h"
+
+#include "console_thread.h"
+
+#include "wxbpanel.h"
+
+// ----------------------------------------------------------------------------
+// wxbPrintObject - Used by wxbThreadEvent to contain data sent by director
+// ----------------------------------------------------------------------------
+
+class wxbPrintObject: public wxObject {
+ public:
+ wxString str;
+ int status;
+ wxbPrintObject(wxString str, int status): wxObject() {
+ this->str = str;
+ this->status = status;
+ }
+
+ wxbPrintObject(const wxbPrintObject& pe) {
+ this->str = pe.str;
+ this->status = pe.status;
+ }
+};
+
+// ----------------------------------------------------------------------------
+// wxbThreadEvent - Event used by wxbTHREAD_EVENT
+// ----------------------------------------------------------------------------
+
+class wxbThreadEvent: public wxEvent {
+ public:
+ wxbThreadEvent(int id);
+ ~wxbThreadEvent();
+ wxbThreadEvent(const wxbThreadEvent& te);
+ virtual wxEvent *Clone() const;
+ wxbPrintObject* GetEventPrintObject();
+ void SetEventPrintObject(wxbPrintObject* object);
+};
+
+// Define a new frame type: this is going to be our main frame
+class wxbMainFrame : public wxFrame
+{
+public:
+ /* this class is a singleton */
+ static wxbMainFrame* CreateInstance(const wxString& title, const wxPoint& pos, const wxSize& size, long style = wxDEFAULT_FRAME_STYLE);
+ static wxbMainFrame* GetInstance();
+
+ // event handlers (these functions should _not_ be virtual)
+ void OnQuit(wxCommandEvent& event);
+ void OnAbout(wxCommandEvent& event);
+ void OnEnter(wxCommandEvent& event);
+ void OnPrint(wxbThreadEvent& event);
+
+ /*
+ * Prints data received from director to the console,
+ * and forwards it to the panels
+ */
+ void Print(wxString str, int status);
+
+ /* Sends data to the director */
+ void Send(wxString str);
+
+ /*
+ * Starts the thread interacting with the director
+ */
+ void StartConsoleThread();
+
+private:
+ /* private constructor, singleton */
+ wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style);
+ ~wxbMainFrame();
+
+ wxNotebook *notebook; /* main notebook */
+ wxTextCtrl *typeCtrl; /* wxTextCtrl for console user input */
+ wxTextCtrl *consoleCtrl; /* wxTextCtrl containing graphical console */
+
+ wxbPanel **panels; /* panels array, contained in the notebook, and which need to receive console communication */
+
+ console_thread* ct; /* thread interacting with the director */
+
+ static wxbMainFrame *frame; /* this */
+
+ // any class wishing to process wxWindows events must use this macro
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // WXBMAINFRAME_H
+
--- /dev/null
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wxbrestorepanel.h"
+
+#include "wxbmainframe.h"
+
+#include "csprint.h"
+
+#include <wx/choice.h>
+#include <wx/datetime.h>
+
+#include "unmarked.xpm"
+#include "marked.xpm"
+#include "partmarked.xpm"
+
+/*
+ * Class which is stored in the tree and in the list to keep informations
+ * about the element.
+ */
+class wxbTreeItemData : public wxTreeItemData {
+ public:
+ wxbTreeItemData(wxString path, wxString name, int marked);
+ wxbTreeItemData(wxString path, wxString name, wxString marked);
+ ~wxbTreeItemData();
+ wxString GetPath();
+ wxString GetName();
+ //wxbTreeItemData* GetChild(wxString dirname);
+ int GetMarked();
+ void SetMarked(int marked);
+ void SetMarked(wxString marked);
+
+ static int GetMarkedStatus(wxString file);
+ private:
+ wxString* path; /* Full path */
+ wxString* name; /* File name */
+ int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
+};
+
+wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked): wxTreeItemData() {
+ this->path = new wxString(path);
+ this->name = new wxString(name);
+ this->marked = marked;
+}
+
+wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, wxString marked): wxTreeItemData() {
+ this->path = new wxString(path);
+ this->name = new wxString(name);
+ SetMarked(marked);
+}
+
+wxbTreeItemData::~wxbTreeItemData() {
+ delete path;
+ delete name;
+}
+
+int wxbTreeItemData::GetMarked() {
+ return marked;
+}
+
+void wxbTreeItemData::SetMarked(wxString marked) {
+ if (marked == "*") {
+ this->marked = 1;
+ }
+ else if (marked == "+") {
+ this->marked = 2;
+ }
+ else {
+ this->marked = 0;
+ }
+}
+
+void wxbTreeItemData::SetMarked(int marked) {
+ this->marked = marked;
+}
+
+wxString wxbTreeItemData::GetPath() {
+ return *path;
+}
+
+wxString wxbTreeItemData::GetName() {
+ return *name;
+}
+
+/*wxbTreeItemData* wxbTreeItemData::GetChild(wxString dirname) {
+ int marked = GetMarkedStatus(dirname);
+ return new wxbTreeItemData(path + (marked ? dirname.Mid(1) : dirname), marked);
+}*/
+
+int wxbTreeItemData::GetMarkedStatus(wxString file) {
+ if (file.Length() == 0)
+ return 0;
+
+ switch (file.GetChar(0)) {
+ case '*':
+ return 1;
+ case '+':
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// event tables and other macros for wxWindows
+// ----------------------------------------------------------------------------
+
+enum
+{
+ RestoreStart = 1,
+ TreeCtrl = 2,
+ ListCtrl = 3,
+ ClientChoice = 4
+};
+
+BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
+ EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
+ EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
+ EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
+ EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
+ EVT_TREE_ITEM_RIGHT_CLICK(TreeCtrl, wxbRestorePanel::OnTreeRightClicked)
+ EVT_LIST_ITEM_RIGHT_CLICK(ListCtrl, wxbRestorePanel::OnListRightClicked)
+ EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
+ EVT_CHOICE(ClientChoice, wxbRestorePanel::OnClientChoiceChanged)
+END_EVENT_TABLE()
+
+/*
+ * wxbRestorePanel constructor
+ */
+wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) {
+ imagelist = new wxImageList(16, 16, TRUE, 3);
+ imagelist->Add(wxIcon(unmarked_xpm));
+ imagelist->Add(wxIcon(marked_xpm));
+ imagelist->Add(wxIcon(partmarked_xpm));
+
+ wxFlexGridSizer *sizer = new wxFlexGridSizer(3, 1, 10, 10);
+ sizer->AddGrowableCol(0);
+ sizer->AddGrowableRow(1);
+
+ wxBoxSizer *firstSizer = new wxBoxSizer(wxHORIZONTAL);
+
+ start = new wxButton(this, RestoreStart, "Enter restore mode", wxDefaultPosition, wxSize(150, 30));
+ firstSizer->Add(start, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
+
+ wxString* elist = new wxString[1];
+
+ clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
+ firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
+
+ jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
+ firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
+
+ sizer->Add(firstSizer, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
+
+ wxFlexGridSizer *secondSizer = new wxFlexGridSizer(1, 2, 10, 10);
+
+ tree = new wxTreeCtrl(this, TreeCtrl, wxDefaultPosition, wxSize(250, 10));
+ secondSizer->Add(tree, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
+
+ tree->SetImageList(imagelist);
+
+ list = new wxListCtrl(this, ListCtrl, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
+ secondSizer->Add(list, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
+
+ list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
+
+ wxListItem info;
+ info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
+ info.SetText("M");
+ info.SetAlign(wxLIST_FORMAT_CENTER);
+ list->InsertColumn(0, info);
+
+ info.SetText("Filename");
+ info.SetAlign(wxLIST_FORMAT_LEFT);
+ list->InsertColumn(1, info);
+
+ info.SetText("Size");
+ info.SetAlign(wxLIST_FORMAT_RIGHT);
+ list->InsertColumn(2, info);
+
+ info.SetText("Date");
+ info.SetAlign(wxLIST_FORMAT_LEFT);
+ list->InsertColumn(3, info);
+
+ info.SetText("Perm.");
+ info.SetAlign(wxLIST_FORMAT_LEFT);
+ list->InsertColumn(4, info);
+
+ info.SetText("User");
+ info.SetAlign(wxLIST_FORMAT_RIGHT);
+ list->InsertColumn(5, info);
+
+ info.SetText("Group");
+ info.SetAlign(wxLIST_FORMAT_RIGHT);
+ list->InsertColumn(6, info);
+
+ secondSizer->AddGrowableCol(1);
+ secondSizer->AddGrowableRow(0);
+
+ sizer->Add(secondSizer, 1, wxEXPAND, 10);
+
+ gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
+
+ sizer->Add(gauge, 1, wxEXPAND, 5);
+ gauge->SetValue(0);
+ gauge->Enable(false);
+
+ SetSizer(sizer);
+ sizer->SetSizeHints(this);
+
+ setStatus(disabled);
+
+ tableParser = NULL;
+
+ jobChoice->Enable(false);
+
+ working = false;
+}
+
+/*
+ * wxbRestorePanel destructor
+ */
+wxbRestorePanel::~wxbRestorePanel() {
+ delete imagelist;
+}
+
+/*----------------------------------------------------------------------------
+ wxbPanel overloadings
+ ----------------------------------------------------------------------------*/
+
+wxString wxbRestorePanel::GetTitle() {
+ return "Restore";
+}
+
+void wxbRestorePanel::Print(wxString str, int stat) {
+ if (str == "$ ") {
+ ended = true;
+ }
+ else if (status == listing) {
+ if (str.Find("cwd is:") == 0) { // Sometimes cd command result "infiltrate" into listings.
+ return;
+ }
+
+ str.RemoveLast();
+
+ wxString* file = ParseList(str);
+
+ if (file == NULL)
+ return;
+
+ if (file[8].GetChar(file[8].Length()-1) == '/') {
+ wxString itemStr;
+
+ long cookie;
+ wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
+
+ bool updated = false;
+
+ while (currentChild.IsOk()) {
+ itemStr = tree->GetItemText(currentChild);
+ if (file[8] == itemStr) {
+ int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
+ if (static_cast<wxbTreeItemData*>(tree->GetItemData(currentChild))->GetMarked() != stat) {
+ tree->SetItemImage(currentChild, stat, wxTreeItemIcon_Normal);
+ tree->SetItemImage(currentChild, stat, wxTreeItemIcon_Selected);
+ static_cast<wxbTreeItemData*>(tree->GetItemData(currentChild))->SetMarked(file[6]);
+ }
+ updated = true;
+ break;
+ }
+ currentChild = tree->GetNextChild(currentTreeItem, cookie);
+ }
+
+ if (!updated) {
+ int img = wxbTreeItemData::GetMarkedStatus(file[6]);
+ tree->AppendItem(currentTreeItem, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
+ }
+ }
+
+ if (updatelist) {
+ long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
+ long data = (long)(new wxbTreeItemData(file[7], file[8], file[6]));
+ list->SetItemData(ind, data);
+ list->SetItem(ind, 1, file[8]); // filename
+ list->SetItem(ind, 2, file[4]); //Size
+ list->SetItem(ind, 3, file[5]); //date
+ list->SetItem(ind, 4, file[0]); //perm
+ list->SetItem(ind, 5, file[2]); //user
+ list->SetItem(ind, 6, file[3]); //grp
+ }
+
+ delete[] file;
+ }
+ else {
+ if (status == restoring) {
+ int i;
+ //15847 total files; 1 marked to be restored; 1,034 bytes.
+ if ((i = str.Find(" marked to be restored;")) > -1) {
+ int j = str.Find("; ");
+ str.Mid(j+2, i).ToLong(&totfilemessages);
+ //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
+ return;
+ }
+
+ if ((i = str.Find(" files selected to be restored.")) > -1) {
+ str.Mid(0, i).ToLong(&totfilemessages);
+ //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
+ return;
+ }
+
+ if ((i = str.Find(" file selected to be restored.")) > -1) {
+ str.Mid(0, i).ToLong(&totfilemessages);
+ //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
+ return;
+ }
+
+ wxStringTokenizer tkz(str, " ", wxTOKEN_STRTOK);
+
+ wxDateTime datetime;
+
+ // Date Time name: perm ? user grp size date time
+ //04-Apr-2004 17:19 Tom-fd: -rwx------ 1 nicolas None 514967 2004-03-20 20:03:42 filename
+
+ if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
+ if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
+ if (tkz.GetNextToken().Last() == ':') { // name:
+ tkz.GetNextToken(); // perm
+ tkz.GetNextToken(); // ?
+ tkz.GetNextToken(); // user
+ tkz.GetNextToken(); // grp
+ tkz.GetNextToken(); // size
+ if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
+ if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
+ filemessages++;
+ //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
+ gauge->SetValue(filemessages);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (tableParser != NULL) {
+ tableParser->Print(str, stat);
+ }
+ if (stat == CS_END) {
+ ended = true;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ Commands called by events handler
+ ----------------------------------------------------------------------------*/
+
+/* The main button has been clicked */
+void wxbRestorePanel::CmdStart() {
+ if (status == disabled) {
+ CreateAndWaitForParser("list clients\n");
+
+ clientChoice->Clear();
+ for (unsigned int i = 0; i < tableParser->size(); i++) {
+ /*for (unsigned int k = 0; k < (*tableParser)[i].size(); k++) {
+ wxbMainFrame::GetInstance()->Print(wxString() << (*tableParser)[i][k] << ":", CS_DEBUG);
+ }
+ wxbMainFrame::GetInstance()->Print(wxString(";\n"), CS_DEBUG);*/
+ long* j = new long;
+ (*tableParser)[i][0].ToLong(j);
+ clientChoice->Append((*tableParser)[i][1], (void*)j);
+ }
+
+ setStatus(entered);
+ }
+ else if (status == entered) {
+ if (jobChoice->GetStringSelection().Length() < 1) {
+ wxbMainFrame::GetInstance()->SetStatusText("Please select a client.\n");
+ return;
+ }
+ WaitForEnd("restore\n");
+ WaitForEnd("6\n");
+ WaitForEnd(wxString() << jobChoice->GetStringSelection() << "\n");
+ WaitForEnd(wxString() << *((long*)clientChoice->GetClientData(clientChoice->GetSelection())) << "\n");
+ WaitForEnd("unmark *\n");
+ setStatus(choosing);
+ wxTreeItemId root = tree->AddRoot(clientChoice->GetStringSelection(), -1, -1, new wxbTreeItemData("/", clientChoice->GetStringSelection(), 0));
+ tree->Refresh();
+ WaitForList(root, true);
+ wxbMainFrame::GetInstance()->SetStatusText("Right click on a file or on a directory to add it to the restore list.\n");
+ tree->Expand(root);
+ }
+ else if (status == choosing) {
+ setStatus(restoring);
+
+ wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...\n");
+
+ totfilemessages = 0;
+ WaitForEnd("estimate\n");
+ WaitForEnd("done\n");
+
+ if (totfilemessages == 0) {
+ wxbMainFrame::GetInstance()->Print("Restore failed : no file selected.\n", CS_DEBUG);
+ wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.\n");
+ setStatus(finished);
+ return;
+ }
+
+ WaitForEnd("yes\n");
+
+ gauge->SetValue(0);
+ gauge->SetRange(totfilemessages);
+
+ wxString cmd = "list jobid=";
+
+ CreateAndWaitForParser("list jobs\n");
+ /* TODO (#1#): Check more carefully which job we just have run. */
+ cmd << (*tableParser)[tableParser->size()-1][0] << "\n";
+
+ filemessages = 0;
+
+ while (true) {
+ CreateAndWaitForParser(cmd);
+ if ((*tableParser)[0][7] != "C") {
+ break;
+ }
+
+ WaitForEnd("messages\n");
+
+ wxbMainFrame::GetInstance()->SetStatusText(wxString("Restoring, please wait (") << filemessages << " of " << totfilemessages << " files done)...\n");
+
+ time_t start = wxDateTime::Now().GetTicks();
+ while (((wxDateTime::Now().GetTicks())-start) < 3) {
+ wxTheApp->Yield();
+ }
+ }
+
+ WaitForEnd("messages\n");
+
+ gauge->SetValue(totfilemessages);
+
+ if ((*tableParser)[0][7] == "T") {
+ wxbMainFrame::GetInstance()->Print("Restore done successfully.\n", CS_DEBUG);
+ wxbMainFrame::GetInstance()->SetStatusText("Restore done successfully.\n");
+ }
+ else {
+ wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
+ wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.\n");
+ }
+ setStatus(finished);
+ }
+}
+
+/* List jobs for a specified client */
+void wxbRestorePanel::CmdListJobs() {
+ if (status == entered) {
+ jobChoice->Clear();
+ WaitForEnd("query\n");
+ WaitForEnd("6\n");
+ CreateAndWaitForParser(clientChoice->GetString(clientChoice->GetSelection()) + "\n");
+
+ for (int i = tableParser->size()-1; i > -1; i--) {
+ wxString str = (*tableParser)[i][3];
+ wxDateTime datetime;
+ const char* chr;
+ if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
+ datetime = datetime.GetTicks() + 1;
+ //wxbMainFrame::GetInstance()->Print(wxString("-") << datetime.Format("%Y-%m-%d %H:%M:%S"), CS_DEBUG);
+ jobChoice->Append(datetime.Format("%Y-%m-%d %H:%M:%S"));
+ }
+ /*else {
+ jobChoice->Append("Invalid");
+ }*/
+ }
+
+ jobChoice->SetSelection(0);
+ }
+}
+
+/* List files and directories for a specified tree item */
+void wxbRestorePanel::CmdList(wxTreeItemId item) {
+ if (status == choosing) {
+ list->DeleteAllItems();
+
+ if (!item.IsOk()) {
+ return;
+ }
+ WaitForList(item, (tree->GetSelection() == item));
+
+ if (list->GetItemCount() > 1) {
+ int firstwidth = list->GetSize().GetWidth();
+ for (int i = 2; i < 7; i++) {
+ list->SetColumnWidth(i, wxLIST_AUTOSIZE);
+ firstwidth -= list->GetColumnWidth(i);
+ }
+
+ list->SetColumnWidth(0, 18);
+ firstwidth -= 18;
+ list->SetColumnWidth(1, wxLIST_AUTOSIZE);
+ if (list->GetColumnWidth(1) < firstwidth) {
+ list->SetColumnWidth(1, firstwidth-20);
+ }
+ }
+ }
+}
+
+/* Mark a treeitem (directory) or a listitem (file or directory) */
+void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long listitem) {
+ if (status == choosing) {
+ wxbTreeItemData* itemdata = NULL;
+ if (listitem != -1) {
+ itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
+ }
+ else if (treeitem.IsOk()) {
+ itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
+ }
+ else {
+ return;
+ }
+
+ if (itemdata == NULL) //Should never happen
+ return;
+
+ wxString dir = itemdata->GetPath();
+ wxString file;
+
+ if (dir != "/") {
+ if (dir.GetChar(dir.Length()-1) == '/') {
+ dir.RemoveLast();
+ }
+
+ int i = dir.Find('/', TRUE);
+ if (i == -1) {
+ file = dir;
+ dir = "/";
+ }
+ else { /* first dir below root */
+ file = dir.Mid(i+1);
+ dir = dir.Mid(0, i+1);
+ }
+ }
+ else {
+ dir = "/";
+ file = "*";
+ }
+
+ WaitForEnd(wxString("cd ") << dir << "\n");
+ WaitForEnd(wxString((itemdata->GetMarked() == 1) ? "unmark " : "mark ") << file << "\n");
+
+ if ((dir == "/") && (file == "*")) {
+ itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
+ }
+
+ if (listitem != -1) {
+ treeitem = tree->GetSelection();
+ UpdateTree(treeitem, true);
+ treeitem = tree->GetItemParent(treeitem);
+ }
+ else {
+ UpdateTree(treeitem, (tree->GetSelection() == treeitem));
+ treeitem = tree->GetItemParent(treeitem);
+ }
+
+ while (treeitem.IsOk()) {
+ WaitForList(treeitem, false);
+ treeitem = tree->GetItemParent(treeitem);
+ }
+
+ /* Update root marked status */
+ treeitem = tree->GetRootItem();
+ long cookie;
+ wxTreeItemId currentChild = tree->GetFirstChild(treeitem, cookie);
+
+ bool onechildmarked = false;
+ bool onechildunmarked = false;
+
+ while (currentChild.IsOk()) {
+ itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
+ switch (itemdata->GetMarked()) {
+ case 0:
+ onechildunmarked = true;
+ break;
+ case 1:
+ onechildmarked = true;
+ break;
+ case 2:
+ onechildmarked = true;
+ onechildunmarked = true;
+ break;
+ }
+
+ if (onechildmarked && onechildunmarked) {
+ break;
+ }
+
+ currentChild = tree->GetNextChild(treeitem, cookie);
+ }
+
+ itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
+ if (onechildmarked && onechildunmarked) {
+ itemdata->SetMarked(2);
+ tree->SetItemImage(treeitem, 2, wxTreeItemIcon_Normal);
+ tree->SetItemImage(treeitem, 2, wxTreeItemIcon_Selected);
+ }
+ else if (onechildmarked) {
+ itemdata->SetMarked(1);
+ tree->SetItemImage(treeitem, 1, wxTreeItemIcon_Normal);
+ tree->SetItemImage(treeitem, 1, wxTreeItemIcon_Selected);
+ }
+ else {
+ itemdata->SetMarked(0);
+ tree->SetItemImage(treeitem, 0, wxTreeItemIcon_Normal);
+ tree->SetItemImage(treeitem, 0, wxTreeItemIcon_Selected);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ General functions
+ ----------------------------------------------------------------------------*/
+
+/* Parse a table in tableParser */
+void wxbRestorePanel::CreateAndWaitForParser(wxString cmd) {
+ if (tableParser != NULL) {
+ delete tableParser;
+ }
+ tableParser = new wxbTableParser();
+
+ wxbMainFrame::GetInstance()->Send(cmd);
+
+ //time_t base = wxDateTime::Now().GetTicks();
+ while (!tableParser->hasFinished()) {
+ //innerThread->Yield();
+ wxTheApp->Yield();
+ //if (base+15 < wxDateTime::Now().GetTicks()) break;
+ }
+}
+
+/* Run a command, and waits until result is fully received. */
+void wxbRestorePanel::WaitForEnd(wxString cmd) {
+ wxbMainFrame::GetInstance()->Send(cmd);
+
+ ended = false;
+
+ //time_t base = wxDateTime::Now().GetTicks();
+ while (!ended) {
+ //innerThread->Yield();
+ wxTheApp->Yield();
+ //if (base+15 < wxDateTime::Now().GetTicks()) break;
+ }
+}
+
+/* Run a dir command, and waits until result is fully received. */
+void wxbRestorePanel::WaitForList(wxTreeItemId item, bool updatelist) {
+ this->updatelist = updatelist;
+ currentTreeItem = item;
+
+ WaitForEnd(wxString("cd \"") << static_cast<wxbTreeItemData*>(tree->GetItemData(currentTreeItem))->GetPath() << "\"\n");
+
+ status = listing;
+
+ if (updatelist)
+ list->DeleteAllItems();
+ WaitForEnd("dir\n");
+
+ tree->Refresh();
+ status = choosing;
+}
+
+/* Parse dir command results. */
+wxString* wxbRestorePanel::ParseList(wxString line) {
+ //drwx------ 11 1003 42949672 0 2001-07-30 16:45:14 *filename
+ //+ 10 ++ 4++ 10 ++ 8 ++ 8 + + 19 + *+ ->
+ //0 10 14 24 32 42 62
+
+ if (line.Length() < 63)
+ return NULL;
+
+ wxString* ret = new wxString[9];
+
+ ret[0] = line.Mid(0, 10).Trim();
+ ret[1] = line.Mid(10, 4).Trim();
+ ret[2] = line.Mid(14, 10).Trim();
+ ret[3] = line.Mid(24, 8).Trim();
+ ret[4] = line.Mid(32, 8).Trim();
+ ret[5] = line.Mid(42, 19).Trim();
+ ret[6] = line.Mid(62, 1);
+ ret[7] = line.Mid(63).Trim();
+
+ if (ret[6] == " ") ret[6] = "";
+
+ if (ret[7].GetChar(ret[7].Length()-1) == '/') {
+ ret[8] = ret[7];
+ ret[8].RemoveLast();
+ ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
+ }
+ else {
+ ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
+ }
+
+ return ret;
+}
+
+/* Update a tree item, and all its childs. */
+void wxbRestorePanel::UpdateTree(wxTreeItemId item, bool updatelist) {
+ WaitForList(item, updatelist);
+
+ /* Updated all child which are not collapsed */
+ long cookie;
+ wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
+
+ while (currentChild.IsOk()) {
+ if (tree->IsExpanded(currentChild))
+ UpdateTree(currentChild, false);
+
+ currentChild = tree->GetNextChild(item, cookie);
+ }
+}
+
+/*----------------------------------------------------------------------------
+ Status function
+ ----------------------------------------------------------------------------*/
+
+/* Set current status by enabling/disabling components */
+void wxbRestorePanel::setStatus(status_enum newstatus) {
+ switch (newstatus) {
+ case finished:
+ tree->DeleteAllItems();
+ list->DeleteAllItems();
+ clientChoice->Clear();
+ jobChoice->Clear();
+ newstatus = disabled;
+ case disabled:
+ start->SetLabel("Enter restore mode");
+ start->Enable(true);
+ clientChoice->Enable(false);
+ jobChoice->Enable(false);
+ tree->Enable(false);
+ list->Enable(false);
+ gauge->Enable(false);
+ break;
+ case entered:
+ gauge->SetValue(0);
+ start->SetLabel("Choose files to restore");
+ clientChoice->Enable(true);
+ jobChoice->Enable(true);
+ tree->Enable(false);
+ list->Enable(false);
+ break;
+ case listing:
+
+ break;
+ case choosing:
+ start->SetLabel("Restore");
+ clientChoice->Enable(false);
+ jobChoice->Enable(false);
+ tree->Enable(true);
+ list->Enable(true);
+ working = false;
+ break;
+ case restoring:
+ start->SetLabel("Restoring...");
+ gauge->Enable(true);
+ gauge->SetValue(0);
+ start->Enable(false);
+ clientChoice->Enable(false);
+ jobChoice->Enable(false);
+ tree->Enable(false);
+ list->Enable(false);
+ working = true;
+ break;
+ }
+ status = newstatus;
+}
+
+/*----------------------------------------------------------------------------
+ Event handling
+ ----------------------------------------------------------------------------*/
+
+void wxbRestorePanel::OnClientChoiceChanged(wxCommandEvent& event) {
+ if (working) {
+ return;
+ }
+ working = true;
+ clientChoice->Enable(false);
+ CmdListJobs();
+ clientChoice->Enable(true);
+ jobChoice->Refresh();
+ working = false;
+}
+
+void wxbRestorePanel::OnStart(wxEvent& WXUNUSED(event)) {
+ if (working) {
+ return;
+ }
+ working = true;
+ CmdStart();
+ working = false;
+}
+
+void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
+ if (working) {
+ event.Veto();
+ }
+}
+
+void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
+ if (working) {
+ event.Veto();
+ return;
+ }
+ //working = true;
+ //CmdList(event.GetItem());
+ tree->SelectItem(event.GetItem());
+ //working = false;
+}
+
+void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
+ if (working) {
+ return;
+ }
+ working = true;
+ CmdList(event.GetItem());
+ working = false;
+}
+
+void wxbRestorePanel::OnTreeRightClicked(wxTreeEvent& event) {
+ if (working) {
+ event.Skip();
+ return;
+ }
+ working = true;
+ CmdMark(event.GetItem(), -1);
+ event.Skip();
+ tree->Refresh();
+ working = false;
+}
+
+void wxbRestorePanel::OnListRightClicked(wxListEvent& event) {
+ if (working) {
+ event.Skip();
+ return;
+ }
+ working = true;
+ long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
+ CmdMark(wxTreeItemId(), item);
+ event.Skip();
+ tree->Refresh();
+ working = false;
+}
+
+void wxbRestorePanel::OnListActivated(wxListEvent& event) {
+ if (working) {
+ event.Skip();
+ return;
+ }
+ working = true;
+ long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
+ if (item > -1) {
+ wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
+ wxString name = itemdata->GetName();
+ event.Skip();
+
+ wxString itemStr;
+
+ long cookie;
+
+ if (name.GetChar(name.Length()-1) == '/') {
+ wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
+
+ while (currentChild.IsOk()) {
+ wxString name2 = tree->GetItemText(currentChild);
+ if (name2 == name) {
+ working = false;
+ tree->UnselectAll();
+ tree->Expand(currentTreeItem);
+ tree->SelectItem(currentChild);
+ //tree->Refresh();
+ return;
+ }
+ currentChild = tree->GetNextChild(currentTreeItem, cookie);
+ }
+ }
+ }
+ working = false;
+}
--- /dev/null
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef WXBRESTOREPANEL_H
+#define WXBRESTOREPANEL_H
+
+#include "wx/wxprec.h"
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include "wxbtableparser.h"
+
+#include <wx/thread.h>
+#include <wx/listctrl.h>
+#include <wx/treectrl.h>
+#include <wx/gauge.h>
+
+#include "wxbpanel.h"
+
+/*
+ * wxbPanel for restoring files
+ */
+class wxbRestorePanel : public wxbPanel
+{
+ public:
+ wxbRestorePanel(wxWindow* parent);
+ ~wxbRestorePanel();
+
+ /* wxbPanel overloadings */
+ virtual wxString GetTitle();
+ virtual void Print(wxString str, int status);
+
+ private:
+/* Commands called by events handler */
+
+ /* The main button has been clicked */
+ void CmdStart();
+
+ /* List jobs for a specified client */
+ void CmdListJobs();
+
+ /* List files and directories for a specified tree item */
+ void CmdList(wxTreeItemId item);
+
+ /* Mark a treeitem (directory) or a listitem (file or directory) */
+ void CmdMark(wxTreeItemId treeitem, long listitem);
+
+/* General functions and variables */
+ bool ended; /* The last command send has finished */
+
+ long filemessages; /* When restoring, number of files restored */
+ long totfilemessages; /* When restoring, number of files to be restored */
+
+ /* When listing a directory, sets if file list must be updated
+ * (otherwise only the tree structure is updated)
+ */
+ bool updatelist;
+
+ wxbTableParser* tableParser; /* Used to parse tables */
+
+ /* Parse a table in tableParser */
+ void CreateAndWaitForParser(wxString cmd);
+
+ /* Run a command, and waits until result is fully received. */
+ void WaitForEnd(wxString cmd);
+
+ /* Run a dir command, and waits until result is fully received. */
+ void WaitForList(wxTreeItemId item, bool updatelist);
+
+ /* Parse dir command results. */
+ wxString* ParseList(wxString line);
+
+ /* Update a tree item, and all its childs. */
+ void UpdateTree(wxTreeItemId item, bool updatelist);
+
+/* Status related */
+ enum status_enum
+ {
+ disabled, // The panel is not activated
+ entered, // The panel is activated
+ choosing, // The user is choosing files to restore
+ listing, // Dir listing is in progress
+ restoring, // Bacula is restoring files
+ finished // Retore done
+ };
+
+ status_enum status;
+
+ /* Set current status by enabling/disabling components */
+ void setStatus(status_enum newstatus);
+
+/* UI related */
+ bool working; // A command is running, discard GUI events
+ wxTreeItemId currentTreeItem; // Currently selected tree item
+
+/* Event handling */
+ void OnStart(wxEvent& WXUNUSED(event));
+ void OnTreeChanging(wxTreeEvent& event);
+ void OnTreeExpanding(wxTreeEvent& event);
+ void OnTreeChanged(wxTreeEvent& event);
+ void OnTreeRightClicked(wxTreeEvent& event);
+ void OnListRightClicked(wxListEvent& event);
+ void OnListActivated(wxListEvent& event);
+ void OnClientChoiceChanged(wxCommandEvent& event);
+
+/* Components */
+ wxImageList* imagelist; //image list for tree and list
+
+ wxButton* start;
+ wxChoice* clientChoice;
+ wxChoice* jobChoice;
+ wxTreeCtrl* tree;
+ wxListCtrl* list;
+ wxGauge* gauge;
+
+ DECLARE_EVENT_TABLE();
+};
+
+#endif // WXBRESTOREPANEL_H
+
--- /dev/null
+/*
+ *
+ * Class used to parse tables received from director in this format :
+ *
+ * +---------+---------+-------------------+
+ * | Header1 | Header2 | ... |
+ * +---------+---------+-------------------+
+ * | Data11 | Data12 | ... |
+ * | .... | ... | ... |
+ * +---------+---------+-------------------+
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wxbtableparser.h" // class's header file
+
+#include "csprint.h"
+
+#include <wx/tokenzr.h>
+
+#include "wxbmainframe.h"
+
+/*
+ * wxbTableParser constructor
+ */
+wxbTableParser::wxbTableParser() : wxbTable(5) {
+ separatorNum = 0;
+ tableHeader = wxbTableRow(5);
+}
+
+/*
+ * wxbTableParser destructor
+ */
+wxbTableParser::~wxbTableParser() {
+
+}
+
+/*
+ * Returns table header as an array of wxStrings.
+ */
+wxbTableRow* wxbTableParser::GetHeader() {
+ return &tableHeader;
+}
+
+/*
+ * Receives director information, forwarded by the wxbPanel which
+ * uses this parser.
+ */
+void wxbTableParser::Print(wxString str, int status) {
+ if ((status == CS_END) && (separatorNum > 0)) {
+ separatorNum = 3;
+ }
+
+ if (separatorNum == 3) return;
+
+ if (str.Length() > 4) {
+ if ((str.GetChar(0) == '+') && (str.GetChar(str.Length()-2) == '+') && (str.GetChar(str.Length()-1) == '\n')) {
+ separatorNum++;
+ return;
+ }
+
+ if ((str.GetChar(0) == '|') && (str.GetChar(str.Length()-2) == '|') && (str.GetChar(str.Length()-1) == '\n')) {
+ str.RemoveLast();
+ wxStringTokenizer tkz(str, "|", wxTOKEN_STRTOK);
+
+ if (separatorNum == 1) {
+ int i = 0;
+ while ( tkz.HasMoreTokens() ) {
+ tableHeader[i++] = tkz.GetNextToken().Trim(true).Trim(false);
+ }
+ }
+ else if (separatorNum == 2) {
+ wxbTableRow tablerow(tableHeader.size());
+ int i = 0;
+ while ( tkz.HasMoreTokens() ) {
+ tablerow[i++] = tkz.GetNextToken().Trim(true).Trim(false);
+ }
+ (*this)[size()] = tablerow;
+ }
+ }
+ }
+}
+
+/*
+ * Return true table parsing has finished.
+ */
+bool wxbTableParser::hasFinished() {
+ return (separatorNum == 3);
+}
--- /dev/null
+/*
+ *
+ * Class used to parse tables received from director in this format :
+ *
+ * +---------+---------+-------------------+
+ * | Header1 | Header2 | ... |
+ * +---------+---------+-------------------+
+ * | Data11 | Data12 | ... |
+ * | .... | ... | ... |
+ * +---------+---------+-------------------+
+ *
+ * Nicolas Boichat, April 2004
+ *
+ */
+/*
+ Copyright (C) 2004 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef WXBTABLEPARSER_H
+#define WXBTABLEPARSER_H
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWindows headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include <wx/hashmap.h>
+
+/* int-indexed array of wxString, used for one line */
+WX_DECLARE_HASH_MAP( int, wxString, wxIntegerHash, wxIntegerEqual, wxbTableRow );
+/* int-indexed array of wxbTableRow, contains the whole table */
+WX_DECLARE_HASH_MAP( int, wxbTableRow, wxIntegerHash, wxIntegerEqual, wxbTable );
+
+/*
+ * Class used to parse tables received from director. Data can be accessed with
+ * the operator [].
+ *
+ * Example : wxString elem = parser[3][2]; fetches column 2 of element 3.
+ */
+class wxbTableParser: public wxbTable
+{
+ public:
+ wxbTableParser();
+ ~wxbTableParser();
+
+ /*
+ * Receives director information, forwarded by the wxbPanel which
+ * uses this parser.
+ */
+ void Print(wxString str, int status);
+
+ /*
+ * Return true table parsing has finished.
+ */
+ bool hasFinished();
+
+ /*
+ * Returns table header as an array of wxStrings.
+ */
+ wxbTableRow* GetHeader();
+ private:
+ wxbTableRow tableHeader;
+
+ /*
+ * 0 - Table has not begun
+ * 1 - first +--+ line obtained, header will follow
+ * 2 - second +--+ line obtained, data will follow
+ * 3 - last +--+ line obtained, table parsing has finished
+ */
+ int separatorNum;
+};
+
+#endif // WXBTABLEPARSER_H
+
--- /dev/null
+/* XPM */
+static char *wxwin16x16_xpm[] = {
+"16 16 6 1",
+" c None",
+". c #000000",
+"X c #000084",
+"o c #FFFFFF",
+"O c #FFFF00",
+"+ c #FF0000",
+" ",
+" ",
+" ",
+" ....... ",
+" .XXXXX. ",
+" .oXXXX. ",
+" .oXXX.......",
+".....oXXX.OOOOO.",
+".+++.XXXX.oOOOO.",
+".o++......oOOOO.",
+".o++++. .oOOOO.",
+".o++++. .OOOOO.",
+".+++++. .......",
+"....... ",
+" ",
+" "};