3 * Interaction thread between director and the GUI
5 * Nicolas Boichat, April 2004
10 Copyright (C) 2004-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
24 // http://66.102.9.104/search?q=cache:Djc1mPF3hRoJ:cvs.sourceforge.net/viewcvs.py/audacity/audacity-src/src/AudioIO.cpp%3Frev%3D1.102+macos+x+wxthread&hl=fr
26 /* _("...") macro returns a wxChar*, so if we need a char*, we need to convert it with:
27 * wxString(_("...")).mb_str(*wxConvCurrent) */
32 #include "console_conf.h"
34 #include "console_thread.h" // class's header file
36 #include <wx/wxprec.h>
38 #include <wx/thread.h>
44 char OK_msg[] = "2000 OK\n";
45 char TERM_msg[] = "2999 Terminate\n";
48 /* Imported functions */
49 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
51 bool console_thread::inited = false;
52 bool console_thread::configloaded = false;
53 wxString console_thread::working_dir = wxT(".");
58 * Call-back for reading a passphrase for an encrypted PEM file
59 * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
61 static int tls_pem_callback(char *buf, int size, const void *userdata)
63 #if defined(HAVE_TLS) && !defined(HAVE_WIN32)
64 const char *prompt = (const char *) userdata;
67 passwd = getpass(prompt);
68 bstrncpy(buf, passwd, size);
78 * Make a quick check to see that we have all the
81 static int check_resources()
89 foreach_res(director, R_DIRECTOR) {
91 /* tls_require implies tls_enable */
92 if (director->tls_require) {
94 director->tls_enable = true;
96 Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
102 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
103 Jmsg(NULL, M_FATAL, 0, wxString(_("Neither \"TLS CA Certificate\" or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in config file.\nAt least one CA certificate store is required.\n")).mb_str(*wxConvCurrent),
110 Jmsg(NULL, M_FATAL, 0, wxString(_("No Director resource defined in config file.\nWithout that I don't how to speak to the Director :-(\n")).mb_str(*wxConvCurrent));
115 /* Loop over Consoles */
116 foreach_res(cons, R_CONSOLE) {
117 /* tls_require implies tls_enable */
118 if (cons->tls_require) {
120 cons->tls_enable = true;
122 Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
128 if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
129 Jmsg(NULL, M_FATAL, 0, wxString(_("Neither \"TLS CA Certificate\" or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in config file.\n")).mb_str(*wxConvCurrent),
139 void console_thread::SetWorkingDirectory(wxString w_dir) {
140 if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
141 console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
144 console_thread::working_dir = w_dir;
148 void console_thread::InitLib()
150 if (WSA_Init() != 0) {
151 csprint(_("Error while initializing windows sockets...\n"));
157 my_name_is(0, NULL, "wx-console");
158 working_directory = (const char*) console_thread::working_dir.GetData();
163 void console_thread::FreeLib()
166 if (WSACleanup() != 0) {
167 csprint(_("Error while cleaning up windows sockets...\n"));
175 * Format a scanner error message
177 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
181 char more[MAXSTRING];
184 va_start(arg_ptr, msg);
185 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
188 if (lc->line_no > lc->begin_line_no) {
189 bsnprintf(more, sizeof(more),
190 wxString(_("Problem probably begins at line %d.\n")).mb_str(*wxConvCurrent), lc->begin_line_no);
195 err.Format(_("Config error: %s\n : line %d, col %d of file %s\n%s\n%s"),
196 buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
201 wxString console_thread::LoadConfig(wxString configfile)
206 return _("Error while initializing library.");
209 free_config_resources();
211 MSGS* msgs = (MSGS *)bmalloc(sizeof(MSGS));
212 memset(msgs, 0, sizeof(MSGS));
213 for (int i=1; i<=M_MAX; i++) {
215 add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
217 // add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
218 add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
221 init_msg(NULL, msgs);
222 //init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
225 if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
226 configloaded = false;
231 if (init_crypto() != 0) {
232 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Cryptographic library initialization failed.\n")).mb_str(*wxConvCurrent));
235 if (!check_resources()) {
236 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Please correct configuration file.\n")).mb_str(*wxConvCurrent));
240 wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
241 init_msg(NULL, NULL);
249 console_thread::console_thread() {
251 choosingdirector = false;
255 console_thread::~console_thread() {
257 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
266 void* console_thread::Entry() {
268 /* It seems we must redefine the locale on each thread on wxGTK.
269 * On Win32 it makes wx-console crash. */
272 m_locale.AddCatalog(wxT("bacula"));
273 wxLocale::AddCatalogLookupPathPrefix(wxT(LOCALEDIR));
278 csprint(_("Error : Library not initialized\n"));
279 csprint(NULL, CS_END);
280 csprint(NULL, CS_DISCONNECTED);
281 csprint(NULL, CS_TERMINATED);
289 csprint(_("Error : No configuration file loaded\n"));
290 csprint(NULL, CS_END);
291 csprint(NULL, CS_DISCONNECTED);
292 csprint(NULL, CS_TERMINATED);
299 csprint(_("Connecting...\n"));
302 DIRRES* res[16]; /* Maximum 16 directors */
305 foreach_res(dir, R_DIRECTOR) {
315 csprint(_("Error : No director defined in config file.\n"));
316 csprint(NULL, CS_END);
317 csprint(NULL, CS_DISCONNECTED);
318 csprint(NULL, CS_TERMINATED);
323 } else if (count == 1) {
327 csprint(_("Multiple directors found in your config file.\n"));
328 for (int i = 0; i < count; i++) {
330 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
333 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
336 csprint(wxString::Format(_("Please choose a director (1-%d): "), count), CS_DATA);
337 csprint(NULL, CS_PROMPT);
338 choosingdirector = true;
339 directorchoosen = -1;
340 while(directorchoosen == -1) {
341 bmicrosleep(0, 2000);
344 choosingdirector = false;
345 if (directorchoosen != 0) {
350 dir = res[directorchoosen-1];
352 memset(&jcr, 0, sizeof(jcr));
354 jcr.dequeuing = 1; /* TODO: catch messages */
357 /* If cons==NULL, default console will be used */
358 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
362 /* Initialize Console TLS context */
363 if (cons && (cons->tls_enable || cons->tls_require)) {
364 /* Generate passphrase prompt */
365 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Console \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), cons->hdr.name);
367 /* Initialize TLS context:
368 * Args: CA certfile, CA certdir, Certfile, Keyfile,
369 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
370 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
371 cons->tls_ca_certdir, cons->tls_certfile,
372 cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
374 if (!cons->tls_ctx) {
375 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Console \"%s\".\n")).mb_str(*wxConvCurrent),
383 /* Initialize Director TLS context */
384 if (dir->tls_enable || dir->tls_require) {
385 /* Generate passphrase prompt */
386 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Director \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), dir->hdr.name);
388 /* Initialize TLS context:
389 * Args: CA certfile, CA certdir, Certfile, Keyfile,
390 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
391 dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
392 dir->tls_ca_certdir, dir->tls_certfile,
393 dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
396 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Director \"%s\".\n")).mb_str(*wxConvCurrent),
404 UA_sock = bnet_connect(&jcr, 3, 3, wxString(_("Director daemon")).mb_str(*wxConvCurrent),
405 dir->address, NULL, dir->DIRport, 0);
407 if (UA_sock == NULL) {
408 csprint(_("Failed to connect to the director\n"));
409 csprint(NULL, CS_END);
410 csprint(NULL, CS_DISCONNECTED);
411 csprint(NULL, CS_TERMINATED);
418 csprint(_("Connected\n"));
420 jcr.dir_bsock = UA_sock;
421 if (!authenticate_director(&jcr, dir, cons)) {
423 csprint(UA_sock->msg);
424 csprint(NULL, CS_END);
425 csprint(NULL, CS_DISCONNECTED);
426 csprint(NULL, CS_TERMINATED);
433 csprint(NULL, CS_CONNECTED);
435 Write("autodisplay on\n");
436 Write(".messages\n");
440 int last_is_eod = 0; /* Last packet received is BNET_EOD */
441 int do_not_forward_eod = 0; /* Last packet received/sent is .messages, so don't forward EOD. (so wx-console don't show the prompt again) */
444 while(!TestDestroy()) { /* Tests if thread has been ended */
445 stat = bnet_wait_data(UA_sock, 10);
448 Write(".messages\n");
449 do_not_forward_eod = 1;
455 if ((stat = bnet_recv(UA_sock)) >= 0) {
456 if (do_not_forward_eod) { /* .messages got data: remove the prompt */
457 csprint(NULL, CS_REMOVEPROMPT);
459 csprint(UA_sock->msg);
461 else if (stat == BNET_SIGNAL) {
462 if (UA_sock->msglen == BNET_PROMPT) {
463 csprint(NULL, CS_PROMPT);
464 } else if (UA_sock->msglen == BNET_EOD) {
466 if (!do_not_forward_eod)
467 csprint(NULL, CS_END);
468 } else if (UA_sock->msglen == BNET_HEARTBEAT) {
469 bnet_sig(UA_sock, BNET_HB_RESPONSE);
470 csprint(_("<< Heartbeat signal received, answered. >>\n"), CS_DEBUG);
471 } else if (UA_sock->msglen == BNET_START_SELECT ||
472 UA_sock->msglen == BNET_END_SELECT) {
473 /* Ignore start/end selections for now */
475 csprint(_("<< Unexpected signal received : "), CS_DEBUG);
476 csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
477 csprint(">>\n", CS_DEBUG);
480 else { /* BNET_HARDEOF || BNET_ERROR */
481 csprint(NULL, CS_END);
485 if (is_bnet_stop(UA_sock)) {
486 csprint(NULL, CS_END);
487 break; /* error or term */
490 do_not_forward_eod = 0;
493 csprint(NULL, CS_DISCONNECTED);
495 csprint(_("Connection terminated\n"));
499 csprint(NULL, CS_TERMINATED);
508 void console_thread::Write(const char* str)
511 UA_sock->msglen = (int32_t)strlen(str);
512 pm_strcpy(&UA_sock->msg, str);
514 } else if (choosingdirector) {
515 // wxString number = str;
516 // number.RemoveLast(); /* Removes \n */
519 // if (number.ToLong(&val)) {
522 directorchoosen = (int)val;
529 void console_thread::Delete() {
532 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
535 /*csprint(NULL, CS_END);
536 csprint(NULL, CS_DISCONNECTED);
537 csprint(NULL, CS_TERMINATED);*/