1 /**************************************************************************
2 *   Copyright (C) 2012 by Yuri Momotyuk                                   *
3 *   yurkis@gmail.com                                                      *
4 *   Copyright (C) 2013 by Kris Moore                                      *
5 *   kris@pcbsd.org                                                        *
6 *                                                                         *
7 *   Permission is hereby granted, free of charge, to any person obtaining *
8 *   a copy of this software and associated documentation files (the       *
9 *   "Software"), to deal in the Software without restriction, including   *
10 *   without limitation the rights to use, copy, modify, merge, publish,   *
11 *   distribute, sublicense, and/or sell copies of the Software, and to    *
12 *   permit persons to whom the Software is furnished to do so, subject to *
13 *   the following conditions:                                             *
14 *                                                                         *
15 *   The above copyright notice and this permission notice shall be        *
16 *   included in all copies or substantial portions of the Software.       *
17 *                                                                         *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
20 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
21 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
22 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
23 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
24 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
25 ***************************************************************************/
26 
27 #include "mainwindow.h"
28 #include "ui_mainwindow.h"
29 
30 #include <QInputDialog>
31 #include <QMessageBox>
32 #include <QTextStream>
33 #include <QProcess>
34 #include <QProcessEnvironment>
35 #include <QFile>
36 #include <QTextStream>
37 #include <QDir>
38 
39 #define DM_CONFIG_FILE QString("/usr/local/etc/pcdm.conf")
40 
41 ///////////////////////////////////////////////////////////////////////////////
toBoolean(QString Str,bool Default=false)42 inline bool toBoolean(QString Str, bool Default=false)
43 {
44     if (Str.trimmed().toLower() == "true")
45         return true;
46     if (Str.trimmed().toLower() == "false")
47         return false;
48     return Default;
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////
fromBoolean(bool flag)52 inline QString fromBoolean(bool flag)
53 {
54     return (flag)?QString("true"):QString("false");
55 }
56 
57 ///////////////////////////////////////////////////////////////////////////////
MainWindow(QWidget * parent)58 MainWindow::MainWindow(QWidget *parent) :
59     QMainWindow(parent),
60     ui(new Ui::MainWindow)
61 {
62     ui->setupUi(this);
63     exUserMenu = new QMenu(this);
64       ui->tool_exuser_add->setMenu(exUserMenu);
65       connect(exUserMenu, SIGNAL(triggered(QAction*)), this, SLOT(add_exuser(QAction*)) );
66     initUI();
67 }
68 
69 ///////////////////////////////////////////////////////////////////////////////
~MainWindow()70 MainWindow::~MainWindow()
71 {
72     delete ui;
73 }
74 
75 ///////////////////////////////////////////////////////////////////////////////
initUI()76 void MainWindow::initUI()
77 {
78 
79     //Make sure the conf file exists
80     if(!QFile::exists(DM_CONFIG_FILE)){
81       qDebug() << "Copying over the default configuration file:" << DM_CONFIG_FILE;
82       if( !QFile::copy(DM_CONFIG_FILE+".dist", DM_CONFIG_FILE) ){
83 	QMessageBox::warning(this,tr("Missing Config File"), QString(tr("The PCDM configuration file could not be found: %1")).arg(DM_CONFIG_FILE)+"\n\n"+tr("This application will now close"));
84 	exit(1);
85       }
86     }
87     getUsers();
88     ui->UsersList->clear();
89     QString autoLogDelay = getValFromSHFile(DM_CONFIG_FILE, "AUTO_LOGIN_DELAY");
90     if(!autoLogDelay.isEmpty()){
91       ui->spin_autoLogDelay->setValue(autoLogDelay.toInt());
92     }
93 
94     QString autoLogUser = getValFromSHFile(DM_CONFIG_FILE, "AUTO_LOGIN_USER");
95     for (int  i=0; i<mvUsers.size(); i++)
96     {
97         ui->UsersList->addItem(mvUsers[i]);
98 	if ( autoLogUser == mvUsers[i] )
99           ui->UsersList->setCurrentIndex(i);
100     }
101 
102     QString autoLog = getValFromSHFile(DM_CONFIG_FILE, "ENABLE_AUTO_LOGIN");
103     if ( autoLog == "TRUE" ) {
104       ui->AutoLoginEnabledCB->setChecked(true);
105       ui->UsersList->setEnabled(true);
106     } else {
107       ui->AutoLoginEnabledCB->setChecked(false);
108       ui->UsersList->setEnabled(false);
109     }
110 
111     ui->EnableVNC->setChecked(false);
112     QString vnc = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_REMOTE_LOGIN");
113     if ( vnc == "TRUE" )
114       ui->EnableVNC->setChecked(true);
115 
116     ui->checkShowPW->setChecked(false);
117     QString showpw = getValFromSHFile(DM_CONFIG_FILE, "ENABLE_VIEW_PASSWORD_BUTTON");
118     if ( showpw == "TRUE" )
119       ui->checkShowPW->setChecked(true);
120 
121     ui->checkShowUsers->setChecked(true); //PCDM defaults to true
122     QString showusers = getValFromSHFile(DM_CONFIG_FILE, "SHOW_SYSTEM_USERS");
123     if( showusers != "TRUE" && !showusers.isEmpty() ){
124       ui->checkShowUsers->setChecked(false);
125     }
126 
127     ui->checkAllowRoot->setChecked(false); //PCDM defaults to false
128     QString allowroot = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_ROOT");
129     if(allowroot.toLower() == "true"){
130       ui->checkAllowRoot->setChecked(true);
131     }
132 
133     ui->checkAllowStealth->setChecked(false); //PCDM defaults to false
134     QString allowstealth = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_STEALTH_LOGIN");
135     if(allowstealth.toLower() == "true"){
136       ui->checkAllowStealth->setChecked(true);
137     }
138 
139     ui->groupAllowUnder1K->setChecked(false); //PCDM defaults to false
140     QString allowU1K = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_UID_UNDER_1K");
141     if(allowU1K.toLower() == "true"){
142       ui->groupAllowUnder1K->setChecked(true);
143     }
144     //Theme setting
145     loadAvailableThemes(); //update the combobox first
146     QString theme = getValFromSHFile(DM_CONFIG_FILE, "THEME_FILE");
147     int index = ui->combo_themes->findData(theme);
148     if(index>=0){ ui->combo_themes->setCurrentIndex(index);  ui->radio_theme_bundle->setChecked(true); }
149     else{ ui->line_theme_custom->setText(theme); ui->radio_theme_custom->setChecked(true); }
150 
151     //Update the UI appropriately
152     itemChanged();
153     ui->SaveButton->setEnabled(false); //re-disable the save button because nothing has changed yet
154 
155 
156 
157     //Now setup all the signals/slots for updating the UI appropriately
158     connect( ui->AutoLoginEnabledCB, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
159     connect( ui->UsersList, SIGNAL(currentIndexChanged(int)), this, SLOT(itemChanged()) );
160     connect( ui->spin_autoLogDelay, SIGNAL(valueChanged(int)), this, SLOT(itemChanged()) );
161     connect( ui->EnableVNC, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
162     connect( ui->checkShowPW, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
163     connect( ui->checkShowUsers, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
164     connect(ui->checkAllowRoot, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
165     connect( ui->checkAllowStealth, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
166     connect( ui->groupAllowUnder1K, SIGNAL(toggled(bool)), this, SLOT(itemChanged()) );
167     connect( ui->radio_theme_bundle, SIGNAL(toggled(bool)), this, SLOT(itemChanged()) );
168     connect( ui->radio_theme_custom, SIGNAL(toggled(bool)), this, SLOT(itemChanged()) );
169     connect( ui->combo_themes, SIGNAL(currentIndexChanged(int)), this, SLOT(itemChanged()) );
170     connect( ui->line_exuser, SIGNAL(returnPressed()), this, SLOT(on_tool_exuser_add_clicked()) );
171 }
172 
173 ///////////////////////////////////////////////////////////////////////////////
getUsers()174 void MainWindow::getUsers()
175 {
176     QStringList users = runShellCommand("getent passwd");
177     mvUsers.clear();
178     exUserMenu->clear();
179     for(int i=0; i<users.length(); i++){
180       QString line = users[i];
181       if ((line.trimmed().indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
182 	QString username = line.section(":",0,0);
183 	QString homedir = line.section(":",5,5);
184 	QString shell = line.section(":",6,6);
185 	//Ignore invalid users
186 	if(shell.contains("nologin") || homedir.contains("nonexistent") || homedir.endsWith("/empty") ){ continue; }
187 
188 	// Ignore PEFS encrypted users
189 	if ( QFile::exists(homedir + "/.pefs.db") )
190 	  continue;
191 
192 	int uid = line.section(":",2,2).toInt();
193 	if(uid==0){ continue; }
194 	if ((uid>1000)&&(uid<65534)){
195 	  mvUsers.push_back(username);
196         }else if(QFile::exists(homedir) && QFile::exists(shell)){
197 	  exUserMenu->addAction(username);
198 	}
199       }
200     }
201 
202     /*QFile userFile("/etc/passwd");
203     if ( userFile.open(QIODevice::ReadOnly) ) {
204         QTextStream stream(&userFile);
205         stream.setCodec("UTF-8");
206         QString line;
207 
208         while ( !stream.atEnd() ) {
209             line = stream.readLine();
210 
211             if ((line.trimmed().indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
212                 QString username = line.section(":",0,0);
213                 QString homedir = line.section(":",5,5);
214 
215 		// Ignore PEFS encrypted users
216 		if ( QFile::exists(homedir + "/.pefs.db") )
217 		  continue;
218 
219                 int uid = line.section(":",2,2).toInt();
220                 if ((uid>1000)&&(uid<65534))
221                     mvUsers.push_back(username);
222             }//if gout user
223         }//for all lines
224     }//if can open file*/
225 }
226 
227 ///////////////////////////////////////////////////////////////////////////////
getConfFileValue(QString oFile,QString Key)228 QString MainWindow::getConfFileValue( QString oFile, QString Key )
229 {
230    return getConfFileValue(oFile, Key, 1);
231 }
232 
getConfFileValue(QString oFile,QString Key,int occur)233 QString MainWindow::getConfFileValue( QString oFile, QString Key, int occur )
234 {
235 	int found = 1;
236 
237     	QFile file( oFile );
238     	if ( ! file.open( QIODevice::ReadOnly ) ) {
239 		return QString();
240 	}
241 
242        	QTextStream stream( &file );
243        	QString line;
244        	while ( !stream.atEnd() ) {
245             	line = stream.readLine(); // line of text excluding '\n'
246 		line = line.section("#",0,0).trimmed(); //remove any comments
247 		if(line.isEmpty()){ continue; }
248 		int index = line.indexOf(Key, 0);
249                 //qDebug() << "Line:" << line << index;
250                 // If the KEY is not found at the start of the line, continue processing
251 		if(index!=0)
252 			continue;
253 
254 	    	if ( found == occur) {
255  			line.remove(line.indexOf(Key, 0), Key.length());
256 
257     			// Remove any quotes
258    			if ( line.indexOf('"') == 0 )
259 				line = line.remove(0, 1);
260 
261     			if ( line.indexOf('"') != -1  )
262 				line.truncate(line.indexOf('"'));
263 
264 			file.close();
265 
266     			return line;
267     		} else {
268        			found++;
269     		}
270         }
271 
272 	file.close();
273 	return QString();
274 }
275 
276 ///////////////////////////////////////////////////////////////////////////////
setConfFileValue(QString oFile,QString oldKey,QString newKey)277 bool MainWindow::setConfFileValue( QString oFile, QString oldKey, QString newKey )
278 {
279 	return setConfFileValue(oFile, oldKey, newKey, -1);
280 }
281 
setConfFileValue(QString oFile,QString oldKey,QString newKey,int occur)282 bool MainWindow::setConfFileValue( QString oFile, QString oldKey, QString newKey, int occur )
283 {
284     	// Lets the dev save a value into a specified config file.
285 	// The occur value tells which occurance of "oldKey" to replace
286     	// If occur is set to -1, it will remove any duplicates of "oldKey"
287 
288 	//copy the original file to create a temporary file for editing
289 	QString oFileTmp = oFile + ".tmp";
290 	QString cmd = "cp "+oFile+" "+oFileTmp;
291 	runShellCommand(cmd);
292 
293 	//Continue evaluating the temporary file
294     	QStringList SavedFile;
295     	int found = 1;
296 
297     	// Load the old file, find the oldKey, remove it and replace with newKey
298     	QFile file( oFileTmp );
299 	if ( ! file.open( QIODevice::ReadOnly ) )
300 		return false;
301 
302         QTextStream stream( &file );
303         QString line;
304         while ( !stream.atEnd() ) {
305         	line = stream.readLine(); // line of text excluding '\n'
306 
307 		// Key is not found at all
308 		if ( line.indexOf(oldKey, 0) == -1 ) {
309 	        	SavedFile << line ;
310 			continue;
311 		}
312 
313 		// Found the key, but it is commented out, so don't worry about this line
314 		if ( line.trimmed().indexOf("#", 0) == 0 ) {
315 	         	SavedFile << line ;
316 			continue;
317 		}
318 
319 		// If the KEY is found, and we are just on wrong occurance, save it and continue to search
320 		if ( occur != -1 && found != occur ) {
321 	         	SavedFile << line ;
322 			found++;
323 			continue;
324 		}
325 
326             	// If the KEY is found in the line and this matches the occurance that must be processed
327             	if ( ! newKey.isEmpty() && found == occur )
328            	{
329 	         	SavedFile << newKey ;
330 			newKey.clear();
331 	    		found++;
332 			continue;
333             	}
334 
335              	// If the KEY is found and we just want one occurance of the key
336             	if ( occur == -1 && ! newKey.isEmpty() ) {
337 	         	SavedFile << newKey ;
338 			newKey.clear();
339 			found++;
340 			continue;
341 		}
342 
343         }
344 
345    	file.close();
346 
347 	// Didn't find the key? Write it!
348 	if ( ! newKey.isEmpty() )
349 	    SavedFile << newKey;
350 
351 
352     	// Save the new file
353     	QFile fileout( oFileTmp );
354     	if ( ! fileout.open( QIODevice::WriteOnly ) )
355 		return false;
356 
357   	QTextStream streamout( &fileout );
358 	for (int i = 0; i < SavedFile.size(); ++i)
359           	streamout << SavedFile.at(i) << "\n";
360 
361        	fileout.close();
362 
363 	//Have the temporary file with new changes overwrite the original file
364 	cmd = "mv "+oFileTmp+" "+oFile;
365 	runShellCommand(cmd);
366 
367 	return true;
368 
369 }
370 
371 ///////////////////////////////////////////////////////////////////////////////
getValFromSHFile(QString envFile,QString envVal)372 QString MainWindow::getValFromSHFile(QString envFile, QString envVal)
373 {
374   QFile confFile(envFile);
375   if ( ! confFile.open( QIODevice::ReadOnly ) )
376         return "";
377 
378   QTextStream stream( &confFile );
379   QString line;
380   while ( !stream.atEnd() ) {
381      line = stream.readLine();
382      if ( line.indexOf(envVal + "=") == 0 ) {
383 	line.replace(envVal + "=", "");
384 
385 	// Remove the ' or " from variable
386 	if ( line.indexOf("'") == 0 ) {
387 	   line = line.section("'", 1, 1);
388 	   line = line.section("'", 0, 0);
389 	}
390 	if ( line.indexOf('"') == 0 ) {
391 	   line = line.section('"', 1, 1);
392 	   line = line.section('"', 0, 0);
393 	}
394 
395         confFile.close();
396 	return line.simplified();
397      }
398   }
399   confFile.close();
400 
401   return QString();
402 }
403 
404 ///////////////////////////////////////////////////////////////////////////////
runShellCommand(QString cmd)405 QStringList MainWindow::runShellCommand(QString cmd){
406    QProcess p;
407    //Make sure we use the system environment to properly read system variables, etc.
408    p.setProcessEnvironment(QProcessEnvironment::systemEnvironment());
409    //Merge the output channels to retrieve all output possible
410    p.setProcessChannelMode(QProcess::MergedChannels);
411    p.start(cmd);
412    while(p.state()==QProcess::Starting || p.state() == QProcess::Running){
413      p.waitForFinished(200);
414      QCoreApplication::processEvents();
415    }
416    QString tmp = p.readAllStandardOutput();
417     if(tmp.endsWith("\n")){ tmp.chop(1); }
418     return tmp.split("\n");
419 }
420 
421 ///////////////////////////////////////////////////////////////////////////////
loadAvailableThemes()422 void MainWindow::loadAvailableThemes(){
423   ui->combo_themes->clear();
424   QDir themedir("/usr/local/share/PCDM/themes");
425   QStringList dirs = themedir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
426   QStringList themefiles;
427   for(int i=0; i<dirs.length(); i++){
428     themedir.cd(dirs[i]);
429       QStringList files = themedir.entryList(QStringList() << "*.theme", QDir::Files, QDir::Name);
430       for(int j=0; j<files.length(); j++){ themefiles << themedir.absoluteFilePath(files[j]); }
431     themedir.cdUp();
432   }
433   //Now add the theme files to the combo box
434   for(int i=0; i<themefiles.length(); i++){
435     ui->combo_themes->addItem( themefiles[i].section("/",-1).section(".theme",0,-2), themefiles[i]);
436   }
437 }
438 ///////////////////////////////////////////////////////////////////////////////
on_SaveButton_clicked()439 void MainWindow::on_SaveButton_clicked()
440 {
441     bool ok;
442     system("touch " + DM_CONFIG_FILE.toLatin1());
443     if ( ui->AutoLoginEnabledCB->isChecked() && !ui->UsersList->currentText().isEmpty() ) {
444        // First ask for password
445        QString pw = QInputDialog::getText(this, tr("Password Request"),
446                         tr("Please enter the login password for this user"),
447                         QLineEdit::Password, "", &ok);
448        if ( ! ok )
449           return;
450 
451        setConfFileValue(DM_CONFIG_FILE, "ENABLE_AUTO_LOGIN", "ENABLE_AUTO_LOGIN=TRUE", -1);
452        setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_USER", "AUTO_LOGIN_USER=" + ui->UsersList->currentText(), -1);
453        setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_PASSWORD", "AUTO_LOGIN_PASSWORD=" + pw, -1);
454        setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_DELAY","AUTO_LOGIN_DELAY="+QString::number(ui->spin_autoLogDelay->value()), -1);
455     } else {
456        ui->AutoLoginEnabledCB->setChecked(false); //make sure this is not checked to reflect file contents
457        setConfFileValue(DM_CONFIG_FILE, "ENABLE_AUTO_LOGIN", "ENABLE_AUTO_LOGIN=FALSE", -1);
458        setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_USER", "", -1);
459        setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_PASSWORD", "", -1);
460        setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_DELAY","", -1);
461     }
462 
463     if ( ui->EnableVNC->isChecked() ) {
464        // First ask for password
465        QString pw = QInputDialog::getText(this, tr("Password Request"),
466                         tr("Please enter the remote login password"),
467                         QLineEdit::Password, "", &ok);
468        if ( ! ok )
469           return;
470 
471        QFile file("/usr/local/etc/vncpass");
472        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
473           return;
474 
475        QTextStream out(&file);
476        out << pw;
477        file.close();
478        system("chmod 600 /usr/local/etc/vncpass");
479 
480        setConfFileValue(DM_CONFIG_FILE, "ALLOW_REMOTE_LOGIN", "ALLOW_REMOTE_LOGIN=TRUE", -1);
481     } else {
482        setConfFileValue(DM_CONFIG_FILE, "ALLOW_REMOTE_LOGIN", "ALLOW_REMOTE_LOGIN=FALSE", -1);
483        system("rm /usr/local/etc/vncpass 2>/dev/null");
484     }
485 
486     if ( ui->checkShowPW->isChecked() )
487        setConfFileValue(DM_CONFIG_FILE, "ENABLE_VIEW_PASSWORD_BUTTON", "ENABLE_VIEW_PASSWORD_BUTTON=TRUE", -1);
488     else
489        setConfFileValue(DM_CONFIG_FILE, "ENABLE_VIEW_PASSWORD_BUTTON", "ENABLE_VIEW_PASSWORD_BUTTON=FALSE", -1);
490 
491     if(ui->checkShowUsers->isChecked()){
492 	setConfFileValue(DM_CONFIG_FILE, "SHOW_SYSTEM_USERS", "SHOW_SYSTEM_USERS=TRUE", -1);
493     }else{
494 	setConfFileValue(DM_CONFIG_FILE, "SHOW_SYSTEM_USERS", "SHOW_SYSTEM_USERS=FALSE", -1);
495     }
496     if(ui->checkAllowRoot->isChecked()){
497 	setConfFileValue(DM_CONFIG_FILE, "ALLOW_ROOT", "ALLOW_ROOT=TRUE", -1);
498     }else{
499 	setConfFileValue(DM_CONFIG_FILE, "ALLOW_ROOT", "ALLOW_ROOT=FALSE", -1);
500     }
501     if(ui->checkAllowStealth->isChecked()){
502 	setConfFileValue(DM_CONFIG_FILE, "ALLOW_STEALTH_LOGIN", "ALLOW_STEALTH_LOGIN=TRUE", -1);
503     }else{
504 	setConfFileValue(DM_CONFIG_FILE, "ALLOW_STEALTH_LOGIN", "ALLOW_STEALTH_LOGIN=FALSE", -1);
505     }
506     if(ui->groupAllowUnder1K->isChecked()){
507 	setConfFileValue(DM_CONFIG_FILE, "ALLOW_UID_UNDER_1K", "ALLOW_UID_UNDER_1K=TRUE", -1);
508     }else{
509 	setConfFileValue(DM_CONFIG_FILE, "ALLOW_UID_UNDER_1K", "ALLOW_UID_UNDER_1K=FALSE", -1);
510     }
511     QStringList exusers;
512     for(int i=0; i<ui->list_exuser->count(); i++){
513       exusers << ui->list_exuser->item(i)->text();
514     }
515     exusers.removeDuplicates();
516     setConfFileValue(DM_CONFIG_FILE,"EXCLUDED_USERS", "EXCLUDED_USERS="+exusers.join(","), -1);
517 
518     QString theme;
519     if(ui->radio_theme_bundle->isChecked()){
520       theme = ui->combo_themes->currentData().toString();
521     }else{
522       theme = ui->line_theme_custom->text();
523     }
524     if(!theme.isEmpty()){ setConfFileValue(DM_CONFIG_FILE,"THEME_FILE", "THEME_FILE="+theme, -1); }
525 
526     // Lastly make sure we set perms
527     system("chmod 600 " + DM_CONFIG_FILE.toLatin1());
528     ui->SaveButton->setEnabled(false);
529 }
530 
531 
532 ///////////////////////////////////////////////////////////////////////////////
slotSingleInstance()533 void MainWindow::slotSingleInstance()
534 {
535    this->hide();
536    this->showNormal();
537    this->activateWindow();
538    this->raise();
539 }
540 
541 /////////////////////////////////////////////////
itemChanged()542 void MainWindow::itemChanged(){
543   ui->SaveButton->setEnabled(true);
544   //Double check the dependant options for whether they are possible to be changed
545   ui->UsersList->setEnabled( ui->AutoLoginEnabledCB->isChecked() );
546   ui->spin_autoLogDelay->setEnabled( ui->AutoLoginEnabledCB->isChecked() );
547 }
548 
on_tool_exuser_rem_clicked()549 void MainWindow::on_tool_exuser_rem_clicked(){
550   QList<QListWidgetItem*> sel = ui->list_exuser->selectedItems();
551   for(int i=0; i<sel.length(); i++){
552     delete sel[i];
553   }
554   itemChanged();
555 }
556 
on_tool_exuser_add_clicked()557 void MainWindow::on_tool_exuser_add_clicked(){
558   QString name = ui->line_exuser->text();
559   ui->line_exuser->setText("");
560   name = name.remove(" ");
561   if(name.isEmpty() || !ui->list_exuser->findItems(name,Qt::MatchExactly).isEmpty() ){ return; }
562   ui->list_exuser->addItem(name);
563   itemChanged();
564 }
565 
add_exuser(QAction * act)566 void MainWindow::add_exuser(QAction* act){ //for a username selected from the menu
567   if( !ui->list_exuser->findItems(act->text(), Qt::MatchExactly).isEmpty() ){ return; }
568   ui->list_exuser->addItem(act->text());
569   itemChanged();
570 }
571