From: Kern Sibbald Date: Tue, 13 Apr 2004 12:50:27 +0000 (+0000) Subject: Add wx-console directory X-Git-Tag: Release-1.34.1~59 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=db83bc1a5a407a0d77f22f598b767112af81632d;p=bacula%2Fbacula Add wx-console directory git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1194 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index 291a24af30..f6ce8e0905 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -1,8 +1,16 @@ - 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. diff --git a/bacula/src/console/authenticate.c b/bacula/src/console/authenticate.c index 5f5be7bfca..0970447649 100644 --- a/bacula/src/console/authenticate.c +++ b/bacula/src/console/authenticate.c @@ -11,7 +11,7 @@ * */ /* - 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 @@ -23,9 +23,10 @@ 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" diff --git a/bacula/src/dird/bacula-dir.conf.in b/bacula/src/dird/bacula-dir.conf.in index f150794933..25e719882b 100644 --- a/bacula/src/dird/bacula-dir.conf.in +++ b/bacula/src/dird/bacula-dir.conf.in @@ -68,6 +68,7 @@ Job { Client=@hostname@-fd FileSet="Full Set" Storage = File + Pool = Default Messages = Standard Where = /tmp/bacula-restores } diff --git a/bacula/src/dird/ua_query.c b/bacula/src/dird/ua_query.c index 970ef5ab52..32f2114266 100644 --- a/bacula/src/dird/ua_query.c +++ b/bacula/src/dird/ua_query.c @@ -32,8 +32,8 @@ 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 @@ -50,23 +50,21 @@ static char *substitute_prompts(UAContext *ua, */ 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")); @@ -77,9 +75,7 @@ int querycmd(UAContext *ua, char *cmd) } } 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; @@ -93,15 +89,12 @@ int querycmd(UAContext *ua, char *cmd) } 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; @@ -121,11 +114,10 @@ int querycmd(UAContext *ua, char *cmd) 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; } @@ -151,6 +143,11 @@ int querycmd(UAContext *ua, char *cmd) bsendmsg(ua, "%s\n", query); } } + +bail_out: + if (fd) { + fclose(fd); + } free_pool_memory(query); for (i=0; idcr->spool_size = 0; V(mutex); make_unique_data_spool_filename(jcr, &name); @@ -185,18 +186,22 @@ static bool despool_data(DCR *dcr) 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; ) { diff --git a/bacula/src/wx-console/BUILD b/bacula/src/wx-console/BUILD new file mode 100644 index 0000000000..a9cf4e0cc9 --- /dev/null +++ b/bacula/src/wx-console/BUILD @@ -0,0 +1,20 @@ +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 diff --git a/bacula/src/wx-console/CHANGELOG b/bacula/src/wx-console/CHANGELOG new file mode 100644 index 0000000000..041464d4aa --- /dev/null +++ b/bacula/src/wx-console/CHANGELOG @@ -0,0 +1,8 @@ +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 diff --git a/bacula/src/wx-console/TODO b/bacula/src/wx-console/TODO new file mode 100644 index 0000000000..2d3eebce8b --- /dev/null +++ b/bacula/src/wx-console/TODO @@ -0,0 +1,14 @@ + +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 diff --git a/bacula/src/wx-console/authenticate.c b/bacula/src/wx-console/authenticate.c new file mode 100644 index 0000000000..94babca87f --- /dev/null +++ b/bacula/src/wx-console/authenticate.c @@ -0,0 +1,99 @@ +/* + * + * 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, "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; +} + diff --git a/bacula/src/wx-console/console_conf.c b/bacula/src/wx-console/console_conf.c new file mode 100644 index 0000000000..b9d4c72026 --- /dev/null +++ b/bacula/src/wx-console/console_conf.c @@ -0,0 +1,266 @@ +/* + * 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); + } + } +} diff --git a/bacula/src/wx-console/console_conf.h b/bacula/src/wx-console/console_conf.h new file mode 100644 index 0000000000..f5bf3693bc --- /dev/null +++ b/bacula/src/wx-console/console_conf.h @@ -0,0 +1,79 @@ +/* + 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 diff --git a/bacula/src/wx-console/console_thread.cpp b/bacula/src/wx-console/console_thread.cpp new file mode 100644 index 0000000000..a4ba832923 --- /dev/null +++ b/bacula/src/wx-console/console_thread.cpp @@ -0,0 +1,130 @@ +/* + * + * 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 + +#include +#include +#include + +#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; + } +} + diff --git a/bacula/src/wx-console/console_thread.h b/bacula/src/wx-console/console_thread.h new file mode 100644 index 0000000000..f3a9cbc44a --- /dev/null +++ b/bacula/src/wx-console/console_thread.h @@ -0,0 +1,57 @@ +/* + * + * 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 + +#include // 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 + diff --git a/bacula/src/wx-console/csprint.h b/bacula/src/wx-console/csprint.h new file mode 100644 index 0000000000..b84d99a72d --- /dev/null +++ b/bacula/src/wx-console/csprint.h @@ -0,0 +1,36 @@ +/* + * + * 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 diff --git a/bacula/src/wx-console/main.cpp b/bacula/src/wx-console/main.cpp new file mode 100644 index 0000000000..b0e1349cbb --- /dev/null +++ b/bacula/src/wx-console/main.cpp @@ -0,0 +1,84 @@ +/* + * + * 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; +} diff --git a/bacula/src/wx-console/marked.xpm b/bacula/src/wx-console/marked.xpm new file mode 100644 index 0000000000..7aac244570 --- /dev/null +++ b/bacula/src/wx-console/marked.xpm @@ -0,0 +1,39 @@ +/* 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 */ +"################", +"################", +"################", +"################", +"############&&&#", +"###########&&&##", +"#########&&&&###", +"########&&&&####", +"##&&&##&&&&#####", +"###&&&&&&&######", +"####&&&&&#######", +"#####&&&########", +"######&#########", +"################", +"################", +"################" +}; + diff --git a/bacula/src/wx-console/partmarked.xpm b/bacula/src/wx-console/partmarked.xpm new file mode 100644 index 0000000000..23e181820e --- /dev/null +++ b/bacula/src/wx-console/partmarked.xpm @@ -0,0 +1,39 @@ +/* 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 */ +"################", +"################", +"################", +"##%%%######%%%##", +"###%%%####%%%###", +"####%%%##%%%####", +"#####%%%%%%#####", +"######%%%%######", +"######%%%%######", +"#####%%%%%%#####", +"####%%%##%%%####", +"###%%%####%%%#&&", +"##%%%######%%&&#", +"########&&##&&##", +"#########&&&&###", +"##########&&####" +}; + diff --git a/bacula/src/wx-console/unmarked.xpm b/bacula/src/wx-console/unmarked.xpm new file mode 100644 index 0000000000..fc624bc70c --- /dev/null +++ b/bacula/src/wx-console/unmarked.xpm @@ -0,0 +1,39 @@ +/* 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 */ +"################", +"################", +"################", +"##%%%######%%%##", +"###%%%####%%%###", +"####%%%##%%%####", +"#####%%%%%%#####", +"######%%%%######", +"######%%%%######", +"#####%%%%%%#####", +"####%%%##%%%####", +"###%%%####%%%###", +"##%%%######%%%##", +"################", +"################", +"################" +}; + diff --git a/bacula/src/wx-console/wxbmainframe.cpp b/bacula/src/wx-console/wxbmainframe.cpp new file mode 100644 index 0000000000..e763fec41b --- /dev/null +++ b/bacula/src/wx-console/wxbmainframe.cpp @@ -0,0 +1,401 @@ +/* + * + * 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 \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); + } +} + diff --git a/bacula/src/wx-console/wxbmainframe.h b/bacula/src/wx-console/wxbmainframe.h new file mode 100644 index 0000000000..9f9022e9c4 --- /dev/null +++ b/bacula/src/wx-console/wxbmainframe.h @@ -0,0 +1,126 @@ +/* + 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 +#include +#include + +//#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 + diff --git a/bacula/src/wx-console/wxbrestorepanel.cpp b/bacula/src/wx-console/wxbrestorepanel.cpp new file mode 100644 index 0000000000..1ab4efb395 --- /dev/null +++ b/bacula/src/wx-console/wxbrestorepanel.cpp @@ -0,0 +1,900 @@ +/* + 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 +#include + +#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(tree->GetItemData(currentChild))->GetMarked() != stat) { + tree->SetItemImage(currentChild, stat, wxTreeItemIcon_Normal); + tree->SetItemImage(currentChild, stat, wxTreeItemIcon_Selected); + static_cast(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(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; +} diff --git a/bacula/src/wx-console/wxbrestorepanel.h b/bacula/src/wx-console/wxbrestorepanel.h new file mode 100644 index 0000000000..da335f59d2 --- /dev/null +++ b/bacula/src/wx-console/wxbrestorepanel.h @@ -0,0 +1,137 @@ +/* + 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 +#include +#include +#include + +#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 + diff --git a/bacula/src/wx-console/wxbtableparser.cpp b/bacula/src/wx-console/wxbtableparser.cpp new file mode 100644 index 0000000000..f5cbf84d3c --- /dev/null +++ b/bacula/src/wx-console/wxbtableparser.cpp @@ -0,0 +1,107 @@ +/* + * + * 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 + +#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); +} diff --git a/bacula/src/wx-console/wxbtableparser.h b/bacula/src/wx-console/wxbtableparser.h new file mode 100644 index 0000000000..fb249592d3 --- /dev/null +++ b/bacula/src/wx-console/wxbtableparser.h @@ -0,0 +1,95 @@ +/* + * + * 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 + +/* 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 + diff --git a/bacula/src/wx-console/wxwin16x16.xpm b/bacula/src/wx-console/wxwin16x16.xpm new file mode 100644 index 0000000000..9964e69313 --- /dev/null +++ b/bacula/src/wx-console/wxwin16x16.xpm @@ -0,0 +1,25 @@ +/* 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.", +".+++++. .......", +"....... ", +" ", +" "};