X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fqt-console%2Fconsole%2Fconsole.cpp;h=81fce7c02c75e89a684cce319c0567c9e966ff33;hb=e189e1ee42e3398596f4fa463bb1adc66d2cee6a;hp=8a14015091864bf8c397f7923340095886f9e72a;hpb=3cfe3c8b357d584ef876387026ff283f4f80ea06;p=bacula%2Fbacula diff --git a/bacula/src/qt-console/console/console.cpp b/bacula/src/qt-console/console/console.cpp index 8a14015091..81fce7c02c 100644 --- a/bacula/src/qt-console/console/console.cpp +++ b/bacula/src/qt-console/console/console.cpp @@ -1,12 +1,12 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2008 Free Software Foundation Europe e.V. + Copyright (C) 2007-2010 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public + modify it under the terms of version three of the GNU Affero General Public License as published by the Free Software Foundation and included in the file LICENSE. @@ -15,7 +15,7 @@ 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 + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -26,8 +26,6 @@ Switzerland, email:ftf@fsfeurope.org. */ /* - * Version $Id$ - * * Console Class * * Kern Sibbald, January MMVII @@ -40,14 +38,20 @@ #include "select.h" #include "run/run.h" -Console::Console(QStackedWidget *parent) +Console::Console(QTabWidget *parent) { QFont font; + m_name = tr("Console"); m_messages_pending = false; m_parent = parent; m_closeable = false; m_console = this; + m_warningPrevent = false; m_dircommCounter = 0; + + /* + * Create a connection to the Director and put it in a hash table + */ m_dircommHash.insert(m_dircommCounter, new DirComm(this, m_dircommCounter)); setupUi(this); @@ -91,10 +95,23 @@ void Console::stopTimer() * requires preferences of check messages and operates at interval */ void Console::poll_messages() { - int conn = availableDirComm(); - DirComm *dircomm = m_dircommHash.value(conn); + int conn; + + /* Do not poll if notifier off */ + if (!mainWin->m_notify) { + return; + } + + /* + * Note if we call getDirComm here, we continuously consume + * file descriptors. + */ + if (!findDirComm(conn)) { /* find a free DirComm */ + return; /* try later */ + } - if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus()){ + DirComm *dircomm = m_dircommHash.value(conn); + if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus() && !mainWin->getWaitState()){ messagesPending(true); dircomm->write(".messages"); displayToPrompt(conn); @@ -103,7 +120,8 @@ void Console::poll_messages() } /* - * Connect to Director. + * Connect to Director. This does not connect to the director, dircomm does. + * This creates the first and possibly 2nd dircomm instance */ void Console::connect_dir() { @@ -117,98 +135,177 @@ void Console::connect_dir() m_textEdit = textEdit; /* our console screen */ if (dircomm->connect_dir()) { - if (mainWin->m_connDebug) - Pmsg0(000, "DirComm 0 Seems to have Connected\n"); - beginNewCommand(0); - job_list.clear(); - client_list.clear(); - fileset_list.clear(); - fileset_list.clear(); - messages_list.clear(); - pool_list.clear(); - storage_list.clear(); - type_list.clear(); - level_list.clear(); - int jl = 0; - bool done = false; - /* this was added because I was getting job lists with 0 count, but not consistently*/ - while (!done) { - dir_cmd(".jobs", job_list); - jl++; - if ((jl > 10) || job_list.count() > 0) done = true; - } - dir_cmd(".clients", client_list); - dir_cmd(".filesets", fileset_list); - dir_cmd(".msgs", messages_list); - dir_cmd(".pools", pool_list); - dir_cmd(".storage", storage_list); - dir_cmd(".types", type_list); - dir_cmd(".levels", level_list); - if (mainWin->m_connDebug) { - QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8\n") - .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count()) - .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count()); - Pmsg1(000, "%s\n", dbgmsg.toUtf8().data()); + Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name()); } + beginNewCommand(0); + } + mainWin->set_status(_("Connected")); - mainWin->set_status(_("Connected")); - startTimer(); /* start message timer */ + startTimer(); /* start message timer */ +} + +/* + * A function created to separate out the population of the lists + * from the Console::connect_dir function + */ +void Console::populateLists(bool /*forcenew*/) +{ + int conn; + if (!getDirComm(conn)) { + if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n"); + if (!newDirComm(conn)) { + Emsg1(M_ABORT, 0, "Failed to connect to %s for populateLists.\n", m_dir->name()); + return; + } + } + populateLists(conn); +} + +void Console::populateLists(int conn) +{ + job_list.clear(); + restore_list.clear(); + client_list.clear(); + fileset_list.clear(); + messages_list.clear(); + pool_list.clear(); + storage_list.clear(); + type_list.clear(); + level_list.clear(); + volstatus_list.clear(); + mediatype_list.clear(); + dir_cmd(conn, ".jobs", job_list); + dir_cmd(conn, ".jobs type=R", restore_list); + dir_cmd(conn, ".clients", client_list); + dir_cmd(conn, ".filesets", fileset_list); + dir_cmd(conn, ".msgs", messages_list); + dir_cmd(conn, ".pools", pool_list); + dir_cmd(conn, ".storage", storage_list); + dir_cmd(conn, ".types", type_list); + dir_cmd(conn, ".levels", level_list); + dir_cmd(conn, ".volstatus", volstatus_list); + dir_cmd(conn, ".mediatypes", mediatype_list); + dir_cmd(conn, ".locations", location_list); + + if (mainWin->m_connDebug) { + QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n") + .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count()) + .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count()) + .arg(conn).arg(m_dir->name()); + Pmsg1(000, "%s", dbgmsg.toUtf8().data()); } + job_list.sort(); + client_list.sort(); + fileset_list.sort(); + messages_list.sort(); + pool_list.sort(); + storage_list.sort(); + type_list.sort(); + level_list.sort(); } +/* + * Overload function for dir_cmd with a QString + * Ease of use + */ bool Console::dir_cmd(QString &cmd, QStringList &results) { return dir_cmd(cmd.toUtf8().data(), results); } +/* + * Overload function for dir_cmd, this is if connection is not worried about + */ +bool Console::dir_cmd(const char *cmd, QStringList &results) +{ + int conn; + if (getDirComm(conn)) { + dir_cmd(conn, cmd, results); + return true; + } else { + Pmsg1(000, "dir_cmd failed to connect to %s\n", m_dir->name()); + return false; + } +} + /* * Send a command to the Director, and return the * results in a QStringList. */ -bool Console::dir_cmd(const char *cmd, QStringList &results) +bool Console::dir_cmd(int conn, const char *cmd, QStringList &results) { - int conn = availableDirComm(); - int stat; + mainWin->waitEnter(); DirComm *dircomm = m_dircommHash.value(conn); + int stat; + bool prev_notify = mainWin->m_notify; - if (mainWin->m_connDebug) - Pmsg2(000, "dir_cmd conn %i %s\n", conn, cmd); + if (mainWin->m_connDebug) { + QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd); + Pmsg1(000, "%s", dbgmsg.toUtf8().data()); + } notify(conn, false); dircomm->write(cmd); - while ((stat = dircomm->read()) > 0) { + while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) { if (mainWin->m_displayAll) display_text(dircomm->msg()); strip_trailing_junk(dircomm->msg()); results << dircomm->msg(); } - notify(conn, true); + if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg()); + if (prev_notify) { + notify(conn, true); /* turn it back on */ + } discardToPrompt(conn); - return true; /* ***FIXME*** return any command error */ + mainWin->waitExit(); + return true; /* ***FIXME*** return any command error */ +} + +/* + * OverLoads for sql_cmd + */ +bool Console::sql_cmd(int &conn, QString &query, QStringList &results) +{ + return sql_cmd(conn, query.toUtf8().data(), results, false); } bool Console::sql_cmd(QString &query, QStringList &results) { - return sql_cmd(query.toUtf8().data(), results); + int conn; + if (!getDirComm(conn)) { + return false; + } + return sql_cmd(conn, query.toUtf8().data(), results, true); +} + +bool Console::sql_cmd(const char *query, QStringList &results) +{ + int conn; + if (!getDirComm(conn)) { + return false; + } + return sql_cmd(conn, query, results, true); } /* * Send an sql query to the Director, and return the * results in a QStringList. */ -bool Console::sql_cmd(const char *query, QStringList &results) +bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify) { - int conn = availableDirComm(); DirComm *dircomm = m_dircommHash.value(conn); int stat; POOL_MEM cmd(PM_MESSAGE); + bool prev_notify = mainWin->m_notify; if (!is_connectedGui()) { return false; } - if (mainWin->m_connDebug) - Pmsg2(000, "sql_cmd conn %i %s\n", conn, query); - notify(conn, false); + if (mainWin->m_connDebug) Pmsg2(000, "sql_cmd conn %i %s\n", conn, query); + if (donotify) { + dircomm->notify(false); + } + mainWin->waitEnter(); pm_strcpy(cmd, ".sql query=\""); pm_strcat(cmd, query); @@ -226,32 +323,60 @@ bool Console::sql_cmd(const char *query, QStringList &results) QString dum = dircomm->msg(); if ((dum.left(6) == "*None*")) doappend = false; } - if (doappend) + if (doappend) { results << dircomm->msg(); + } first = false; } - notify(conn, true); + if (donotify && prev_notify) { + dircomm->notify(true); + } discardToPrompt(conn); - return true; /* ***FIXME*** return any command error */ + mainWin->waitExit(); + return !mainWin->isClosing(); /* return false if closing */ } -/* Send a command to the Director */ +/* + * Overloads for + * Sending a command to the Director + */ int Console::write_dir(const char *msg) { - int conn = availableDirComm(); - write_dir(conn, msg); + int conn; + if (getDirComm(conn)) { + write_dir(conn, msg); + } + return conn; +} + +int Console::write_dir(const char *msg, bool dowait) +{ + int conn; + if (getDirComm(conn)) { + write_dir(conn, msg, dowait); + } return conn; } -/* Send a command to the Director */ void Console::write_dir(int conn, const char *msg) +{ + write_dir(conn, msg, true); +} + +/* + * Send a command to the Director + */ +void Console::write_dir(int conn, const char *msg, bool dowait) { DirComm *dircomm = m_dircommHash.value(conn); if (dircomm->m_sock) { mainWin->set_status(_("Processing command ...")); - QApplication::setOverrideCursor(Qt::WaitCursor); + if (dowait) + mainWin->waitEnter(); dircomm->write(msg); + if (dowait) + mainWin->waitExit(); } else { mainWin->set_status( tr(" Director not connected. Click on connect button.")); mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png")); @@ -263,21 +388,42 @@ void Console::write_dir(int conn, const char *msg) } } +/* + * get_job_defaults overload + */ +bool Console::get_job_defaults(struct job_defaults &job_defs) +{ + int conn; + return get_job_defaults(conn, job_defs, true); +} + +bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs) +{ + return get_job_defaults(conn, job_defs, false); +} + /* * Send a job name to the director, and read all the resulting * defaults. */ -bool Console::get_job_defaults(struct job_defaults &job_defs) +bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify) { QString scmd; int stat; char *def; + bool prev_notify = mainWin->m_notify; + bool rtn = false; - int conn = notifyOff(); + if (donotify) { + conn = notifyOff(); + } beginNewCommand(conn); DirComm *dircomm = m_dircommHash.value(conn); + bool prevWaitState = mainWin->getWaitState(); + if (!prevWaitState) + mainWin->waitEnter(); if (mainWin->m_connDebug) - Pmsg1(000, "job_defaults conn %i\n", conn); + Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name()); scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name); dircomm->write(scmd); while ((stat = dircomm->read()) > 0) { @@ -337,13 +483,16 @@ bool Console::get_job_defaults(struct job_defaults &job_defs) continue; } } - - notify(conn, true); - return true; - + rtn = true; + /* Fall through wanted */ bail_out: - notify(conn, true); - return false; + if (donotify && prev_notify) { + notify(conn, true); + } + if (!prevWaitState) { + mainWin->waitExit(); + } + return rtn; } @@ -454,7 +603,6 @@ void Console::display_html(const QString buf) /* Position cursor to end of screen */ void Console::update_cursor() { - QApplication::restoreOverrideCursor(); m_textEdit->moveCursor(QTextCursor::End); m_textEdit->ensureCursorVisible(); } @@ -466,6 +614,7 @@ void Console::beginNewCommand(int conn) for (int i=0; i < 3; i++) { dircomm->write("."); while (dircomm->read() > 0) { + Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name()); if (mainWin->m_displayAll) display_text(dircomm->msg()); } if (dircomm->m_at_main_prompt) { @@ -481,7 +630,7 @@ void Console::displayToPrompt(int conn) int stat = 0; QString buf; - if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n"); + if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name()); while (!dircomm->m_at_prompt) { if ((stat=dircomm->read()) > 0) { buf += dircomm->msg(); @@ -493,7 +642,7 @@ void Console::displayToPrompt(int conn) } } display_text(buf); - if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat); + if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name()); } void Console::discardToPrompt(int conn) @@ -501,33 +650,59 @@ void Console::discardToPrompt(int conn) DirComm *dircomm = m_dircommHash.value(conn); int stat = 0; - if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n"); + if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name()); if (mainWin->m_displayAll) { displayToPrompt(conn); } else { while (!dircomm->m_at_prompt) { - stat=dircomm->read(); + stat = dircomm->read(); + if (stat < 0) { + break; + } } } - if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat); + if (mainWin->m_commDebug) { + Pmsg2(000, "endDiscardToPrompt conn=%i %s\n", conn, m_dir->name()); + } +} + +QString Console::returnFromPrompt(int conn) +{ + DirComm *dircomm = m_dircommHash.value(conn); + QString text(""); + + int stat = 0; + text = ""; + dircomm->read(); + text += dircomm->msg(); + if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name()); + while (!dircomm->m_at_prompt) { + if ((stat=dircomm->read()) > 0) { + text += dircomm->msg(); + } + } + if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name()); + return text; } /* * When the notifier is enabled, read_dir() will automatically be * called by the Qt event loop when ever there is any output - * from the Directory, and read_dir() will then display it on + * from the Director, and read_dir() will then display it on * the console. * * When we are in a bat dialog, we want to control *all* output - * from the Directory, so we set notify to off. + * from the Director, so we set notify to off. * m_console->notifiy(false); */ -/* dual purpose function to turn notify off and return an available connection */ +/* dual purpose function to turn notify off and return a connection */ int Console::notifyOff() { - int conn = availableDirComm(); - notify(conn, false); + int conn = 0; + if (getDirComm(conn)) { + notify(conn, false); + } return conn; } @@ -577,49 +752,11 @@ void Console::consoleReload() consoleCommand(cmd); } -/* Function to get a list of volumes */ -void Console::getVolumeList(QStringList &volumeList) -{ - QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media"); - if (mainWin->m_sqlDebug) { - Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data()); - } - QStringList results; - if (sql_cmd(query, results)) { - QString field; - QStringList fieldlist; - /* Iterate through the lines of results. */ - foreach (QString resultline, results) { - fieldlist = resultline.split("\t"); - volumeList.append(fieldlist[0]); - } /* foreach resultline */ - } /* if results from query */ -} - -/* Function to get a list of volumes */ -void Console::getStatusList(QStringList &statusLongList) -{ - QString statusQuery("SELECT JobStatusLong FROM Status"); - if (mainWin->m_sqlDebug) { - Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data()); - } - QStringList statusResults; - if (sql_cmd(statusQuery, statusResults)) { - QString field; - QStringList fieldlist; - /* Iterate through the lines of results. */ - foreach (QString resultline, statusResults) { - fieldlist = resultline.split("\t"); - statusLongList.append(fieldlist[0]); - } /* foreach resultline */ - } /* if results from statusquery */ -} - /* For suppressing .messages * This may be rendered not needed if the multiple connections feature gets working */ bool Console::hasFocus() { - if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this)) + if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this)) return true; else return false; @@ -671,13 +808,19 @@ char *Console::msg(int conn) int Console::write(int conn, const QString msg) { DirComm *dircomm = m_dircommHash.value(conn); - return dircomm->write(msg); + mainWin->waitEnter(); + int ret = dircomm->write(msg); + mainWin->waitExit(); + return ret; } int Console::write(int conn, const char *msg) { DirComm *dircomm = m_dircommHash.value(conn); - return dircomm->write(msg); + mainWin->waitEnter(); + int ret = dircomm->write(msg); + mainWin->waitExit(); + return ret; } /* This checks to see if any is connected */ @@ -699,35 +842,74 @@ bool Console::is_connected(int conn) } /* - * Need an available connection. Check existing connections or create one + * Need a connection. Check existing connections or create one */ -int Console::availableDirComm() +bool Console::getDirComm(int &conn) { + if (findDirComm(conn)) { + return true; + } + if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n"); + return newDirComm(conn); +} + + +/* + * Try to find a free (unused but established) connection + * KES: Note, I think there is a problem here because for + * some reason, the notifier is often turned off on file + * descriptors that seem to me to be available. That means + * that we do not use a free descriptor and thus we will create + * a new connection that is maybe not necessary. Someone needs + * to look into whether or not notify() is correctly turned on + * when we are back at the command prompt and idle. + * + */ +bool Console::findDirComm(int &conn) +{ + int i = 1; QHash::const_iterator iter = m_dircommHash.constBegin(); while (iter != m_dircommHash.constEnd()) { DirComm *dircomm = iter.value(); - if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) - return dircomm->m_conn; + if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) { + conn = dircomm->m_conn; + return true; + } + if (mainWin->m_connDebug) { + Pmsg4(000, "currentDirComm=%d at_prompt=%d at_main=%d && notify=%d\n", + i, dircomm->m_at_prompt, dircomm->m_at_main_prompt, dircomm->is_notify_enabled()); + i++; + } ++iter; } - return newDirComm(); + return false; } /* * Create a new connection */ -int Console::newDirComm() +bool Console::newDirComm(int &conn) { - m_dircommCounter += 1; - if (mainWin->m_connDebug) - Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter); + m_dircommCounter++; + if (mainWin->m_connDebug) { + Pmsg2(000, "newDirComm=%i to: %s\n", m_dircommCounter, m_dir->name()); + } DirComm *dircomm = new DirComm(this, m_dircommCounter); m_dircommHash.insert(m_dircommCounter, dircomm); bool success = dircomm->connect_dir(); - if (mainWin->m_connDebug) - if (success) - Pmsg1(000, "DirComm %i Connected\n", m_dircommCounter); - else - Pmsg1(000, "DirComm %i NOT Connected\n", m_dircommCounter); - return m_dircommCounter; + if (mainWin->m_connDebug) { + if (success) { + Pmsg2(000, "newDirComm=%i Connected %s\n", m_dircommCounter, m_dir->name()); + } else { + Emsg2(M_ERROR, 0, "DirComm=%i. Unable to connect to %s\n", + m_dircommCounter, m_dir->name()); + } + } + if (!success) { + m_dircommHash.remove(m_dircommCounter); + delete dircomm; + m_dircommCounter--; + } + conn = m_dircommCounter; + return success; }