/*
Bacula® - The Network Backup Solution
- Copyright (C) 2007-2009 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.
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.
Switzerland, email:ftf@fsfeurope.org.
*/
/*
- * Version $Id$
- *
* Console Class
*
* Kern Sibbald, January MMVII
#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);
* requires preferences of check messages and operates at interval */
void Console::poll_messages()
{
- int conn = availableDirComm();
- DirComm *dircomm = m_dircommHash.value(conn);
+ int conn;
+
+ /*
+ * 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);
}
/*
- * 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()
{
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;
+ if (mainWin->m_connDebug) {
+ Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
}
- 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);
+ beginNewCommand(0);
+ }
+ mainWin->set_status(_("Connected"));
+
+ 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) {
- 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());
+ Pmsg0(000, "call newDirComm\n");
}
-
- mainWin->set_status(_("Connected"));
- startTimer(); /* start message timer */
+ 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();
+ 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, ".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;
- 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 && dircomm->is_in_command()) {
if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
notify(conn, true);
discardToPrompt(conn);
+ 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);
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);
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) {
+ 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"));
}
}
+/*
+ * 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;
- 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) {
}
}
- notify(conn, true);
+ if (donotify)
+ notify(conn, true);
+ if (!prevWaitState)
+ mainWin->waitExit();
return true;
bail_out:
- notify(conn, true);
+ if (donotify)
+ notify(conn, true);
+ if (!prevWaitState)
+ mainWin->waitExit();
return false;
}
/* Position cursor to end of screen */
void Console::update_cursor()
{
- QApplication::restoreOverrideCursor();
m_textEdit->moveCursor(QTextCursor::End);
m_textEdit->ensureCursorVisible();
}
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) {
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();
}
}
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)
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) {
+ 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 = "";
+ 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) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
+ 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;
}
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;
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 */
}
/*
- * Need an available connection. Check existing connections or create one
+ * Need a connection. Check existing connections or create one
+ */
+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.
+ *
*/
-int Console::availableDirComm()
+bool Console::findDirComm(int &conn)
{
+ int i = 1;
QHash<int, DirComm*>::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;
}