3 * Interaction thread between director and the GUI
5 * Nicolas Boichat, April 2004
10 Copyright (C) 2004-2005 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) */
30 #include "console_conf.h"
32 #include "console_thread.h" // class's header file
34 #include <wx/wxprec.h>
36 #include <wx/thread.h>
42 char OK_msg[] = "2000 OK\n";
43 char TERM_msg[] = "2999 Terminate\n";
46 /* Imported functions */
47 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
49 bool console_thread::inited = false;
50 bool console_thread::configloaded = false;
51 wxString console_thread::working_dir = wxT(".");
56 * Call-back for reading a passphrase for an encrypted PEM file
57 * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
59 static int tls_pem_callback(char *buf, int size, const void *userdata)
61 #if defined(HAVE_TLS) && !defined(HAVE_WIN32)
62 const char *prompt = (const char *) userdata;
65 passwd = getpass(prompt);
66 bstrncpy(buf, passwd, size);
76 * Make a quick check to see that we have all the
79 static int check_resources()
87 foreach_res(director, R_DIRECTOR) {
89 /* tls_require implies tls_enable */
90 if (director->tls_require) {
92 director->tls_enable = true;
94 Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
100 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
101 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),
108 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));
113 /* Loop over Consoles */
114 foreach_res(cons, R_CONSOLE) {
115 /* tls_require implies tls_enable */
116 if (cons->tls_require) {
118 cons->tls_enable = true;
120 Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
126 if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
127 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),
137 void console_thread::SetWorkingDirectory(wxString w_dir) {
138 if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
139 console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
142 console_thread::working_dir = w_dir;
146 void console_thread::InitLib() {
147 if (WSA_Init() != 0) {
148 csprint(_("Error while initializing windows sockets...\n"));
154 my_name_is(0, NULL, "wx-console");
155 working_directory = (const char*) console_thread::working_dir.GetData();
160 void console_thread::FreeLib() {
162 if (WSACleanup() != 0) {
163 csprint(_("Error while cleaning up windows sockets...\n"));
171 * Format a scanner error message
173 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
177 char more[MAXSTRING];
180 va_start(arg_ptr, msg);
181 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
184 if (lc->line_no > lc->begin_line_no) {
185 bsnprintf(more, sizeof(more),
186 wxString(_("Problem probably begins at line %d.\n")).mb_str(*wxConvCurrent), lc->begin_line_no);
191 err.Format(_("Config error: %s\n : line %d, col %d of file %s\n%s\n%s"),
192 buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
197 wxString console_thread::LoadConfig(wxString configfile) {
201 return _("Error while initializing library.");
204 free_config_resources();
206 MSGS* msgs = (MSGS *)malloc(sizeof(MSGS));
207 memset(msgs, 0, sizeof(MSGS));
208 for (int i=1; i<=M_MAX; i++) {
210 add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
212 // add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
213 add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
216 init_msg(NULL, msgs);
217 //init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
220 if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
221 configloaded = false;
226 if (init_crypto() != 0) {
227 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Cryptographic library initialization failed.\n")).mb_str(*wxConvCurrent));
230 if (!check_resources()) {
231 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Please correct configuration file.\n")).mb_str(*wxConvCurrent));
235 wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
236 init_msg(NULL, NULL);
244 console_thread::console_thread() {
246 choosingdirector = false;
250 console_thread::~console_thread() {
252 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
261 void* console_thread::Entry() {
263 /* It seems we must redefine the locale on each thread on wxGTK.
264 * On Win32 it makes wx-console crash. */
267 m_locale.AddCatalog(wxT("bacula"));
268 wxLocale::AddCatalogLookupPathPrefix(wxT(LOCALEDIR));
273 csprint(_("Error : Library not initialized\n"));
274 csprint(NULL, CS_END);
275 csprint(NULL, CS_DISCONNECTED);
276 csprint(NULL, CS_TERMINATED);
284 csprint(_("Error : No configuration file loaded\n"));
285 csprint(NULL, CS_END);
286 csprint(NULL, CS_DISCONNECTED);
287 csprint(NULL, CS_TERMINATED);
294 csprint(_("Connecting...\n"));
297 DIRRES* res[16]; /* Maximum 16 directors */
300 foreach_res(dir, R_DIRECTOR) {
310 csprint(_("Error : No director defined in config file.\n"));
311 csprint(NULL, CS_END);
312 csprint(NULL, CS_DISCONNECTED);
313 csprint(NULL, CS_TERMINATED);
318 } else if (count == 1) {
322 csprint(_("Multiple directors found in your config file.\n"));
323 for (int i = 0; i < count; i++) {
325 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
328 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
331 csprint(wxString::Format(_("Please choose a director (1-%d): "), count), CS_DATA);
332 csprint(NULL, CS_PROMPT);
333 choosingdirector = true;
334 directorchoosen = -1;
335 while(directorchoosen == -1) {
336 bmicrosleep(0, 2000);
339 choosingdirector = false;
340 if (directorchoosen != 0) {
345 dir = res[directorchoosen-1];
347 memset(&jcr, 0, sizeof(jcr));
349 jcr.dequeuing = 1; /* TODO: catch messages */
352 /* If cons==NULL, default console will be used */
353 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
357 /* Initialize Console TLS context */
358 if (cons && (cons->tls_enable || cons->tls_require)) {
359 /* Generate passphrase prompt */
360 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Console \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), cons->hdr.name);
362 /* Initialize TLS context:
363 * Args: CA certfile, CA certdir, Certfile, Keyfile,
364 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
365 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
366 cons->tls_ca_certdir, cons->tls_certfile,
367 cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
369 if (!cons->tls_ctx) {
370 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Console \"%s\".\n")).mb_str(*wxConvCurrent),
378 /* Initialize Director TLS context */
379 if (dir->tls_enable || dir->tls_require) {
380 /* Generate passphrase prompt */
381 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Director \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), dir->hdr.name);
383 /* Initialize TLS context:
384 * Args: CA certfile, CA certdir, Certfile, Keyfile,
385 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
386 dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
387 dir->tls_ca_certdir, dir->tls_certfile,
388 dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
391 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Director \"%s\".\n")).mb_str(*wxConvCurrent),
399 UA_sock = bnet_connect(&jcr, 3, 3, wxString(_("Director daemon")).mb_str(*wxConvCurrent),
400 dir->address, NULL, dir->DIRport, 0);
402 if (UA_sock == NULL) {
403 csprint(_("Failed to connect to the director\n"));
404 csprint(NULL, CS_END);
405 csprint(NULL, CS_DISCONNECTED);
406 csprint(NULL, CS_TERMINATED);
413 csprint(_("Connected\n"));
415 jcr.dir_bsock = UA_sock;
416 if (!authenticate_director(&jcr, dir, cons)) {
418 csprint(UA_sock->msg);
419 csprint(NULL, CS_END);
420 csprint(NULL, CS_DISCONNECTED);
421 csprint(NULL, CS_TERMINATED);
428 csprint(NULL, CS_CONNECTED);
430 Write("autodisplay on\n");
431 Write(".messages\n");
435 int last_is_eod = 0; /* Last packet received is BNET_EOD */
436 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) */
439 while(!TestDestroy()) { /* Tests if thread has been ended */
440 stat = bnet_wait_data(UA_sock, 10);
443 Write(".messages\n");
444 do_not_forward_eod = 1;
450 if ((stat = bnet_recv(UA_sock)) >= 0) {
451 if (do_not_forward_eod) { /* .messages got data: remove the prompt */
452 csprint(NULL, CS_REMOVEPROMPT);
454 csprint(UA_sock->msg);
456 else if (stat == BNET_SIGNAL) {
457 if (UA_sock->msglen == BNET_PROMPT) {
458 csprint(NULL, CS_PROMPT);
459 } else if (UA_sock->msglen == BNET_EOD) {
461 if (!do_not_forward_eod)
462 csprint(NULL, CS_END);
463 } else if (UA_sock->msglen == BNET_HEARTBEAT) {
464 bnet_sig(UA_sock, BNET_HB_RESPONSE);
465 csprint(_("<< Heartbeat signal received, answered. >>\n"), CS_DEBUG);
466 } else if (UA_sock->msglen == BNET_START_SELECT ||
467 UA_sock->msglen == BNET_END_SELECT) {
468 /* Ignore start/end selections for now */
470 csprint(_("<< Unexpected signal received : "), CS_DEBUG);
471 csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
472 csprint(">>\n", CS_DEBUG);
475 else { /* BNET_HARDEOF || BNET_ERROR */
476 csprint(NULL, CS_END);
480 if (is_bnet_stop(UA_sock)) {
481 csprint(NULL, CS_END);
482 break; /* error or term */
485 do_not_forward_eod = 0;
488 csprint(NULL, CS_DISCONNECTED);
490 csprint(_("Connection terminated\n"));
494 csprint(NULL, CS_TERMINATED);
503 void console_thread::Write(const char* str)
506 UA_sock->msglen = (int32_t)strlen(str);
507 pm_strcpy(&UA_sock->msg, str);
509 } else if (choosingdirector) {
510 // wxString number = str;
511 // number.RemoveLast(); /* Removes \n */
514 // if (number.ToLong(&val)) {
517 directorchoosen = (int)val;
524 void console_thread::Delete() {
527 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
530 /*csprint(NULL, CS_END);
531 csprint(NULL, CS_DISCONNECTED);
532 csprint(NULL, CS_TERMINATED);*/