source: src-qt4/PCDM/src/pcdm-backend.cpp @ 1f0939e

9.1-release9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since 1f0939e was 1f0939e, checked in by Kris Moore <kris@…>, 20 months ago
  • Initial merge of code from PC-BSD SVN repo for my private (pre-release) hacking
  • Property mode set to 100644
File size: 12.0 KB
Line 
1/* PCDM Login Manager:
2*  Written by Ken Moore (ken@pcbsd.org) 2012/2013
3*  Copyright(c) 2013 by the PC-BSD Project
4*  Available under the 3-clause BSD license
5*/
6
7#include <QProcess>
8#include <QProcessEnvironment>
9
10#include "pcdm-backend.h"
11#include "pcdm-config.h"
12#include "pcbsd-utils.h"
13
14QStringList displaynameList,usernameList,homedirList,instXNameList,instXBinList,instXCommentList,instXIconList;
15QString logFile;
16QString saveX,saveUsername;
17
18QStringList Backend::getAvailableDesktops(){ 
19  if(instXNameList.isEmpty()){ loadXSessionsData(); }
20  QStringList out = instXNameList;
21  return out;
22}
23
24QString Backend::getDesktopComment(QString xName){
25  if(instXNameList.isEmpty()){ loadXSessionsData(); }
26  int index = instXNameList.indexOf(xName);
27  if(index == -1){ Backend::log("PCDM: Invalid Desktop Name: " + xName); return ""; }
28  return instXCommentList[index];
29}
30
31QString Backend::getDesktopIcon(QString xName){
32  if(instXNameList.isEmpty()){ loadXSessionsData(); }
33  int index = instXNameList.indexOf(xName);
34  if(index == -1){ Backend::log("PCDM: Invalid Desktop Name: " +xName); return ""; }
35  return instXIconList[index];
36}
37
38QString Backend::getDesktopBinary(QString xName){
39  if(instXNameList.isEmpty()){ loadXSessionsData(); }
40  int index = instXNameList.indexOf(xName);
41  if(index == -1){ Backend::log("PCDM: Invalid Desktop Name: " + xName); return ""; }
42  return instXBinList[index];
43}
44
45QStringList Backend::getSystemUsers(){
46  if(usernameList.isEmpty()){
47    readSystemUsers();
48  }
49  return displaynameList;
50}
51
52QString Backend::getALUsername(){
53  //Make sure the requested user is valid
54  readSystemUsers(); //first read the available users on this system
55  QString ruser = Config::autoLoginUsername();
56  int index = usernameList.indexOf(ruser);
57  if(index == -1){ //invalid username
58    //Check if a display name was given instead
59    index = displaynameList.indexOf(ruser);
60    if(index == -1){ //invalid display name
61      log("Invalid Auto-Login user requested - skipping....");
62      ruser.clear();
63    }else{
64      //use the valid username for the given display name
65      ruser = usernameList[index]; 
66    }
67  }
68  return ruser;
69}
70
71QString Backend::getALDesktopCmd(){
72   // Make sure the desired desktop is valid
73  QString rdesktop = Config::autoLoginDesktop();
74  if(!QFile::exists(rdesktop)){ //requested file does not exist
75    log("Invalid Auto-Login desktop requested - skipping....");
76    return "";
77  }
78  QStringList result = readXSessionsFile(rdesktop,"");
79  if(result.isEmpty()){  //requested file is not a valid xsessions file
80    log("Invalid Auto-Login desktop requested - skipping....");
81    return "";           
82  }
83  if(!result[0].startsWith("/")){ result[0] = "/usr/local/bin/"+result[0]; }
84  rdesktop = result[0]; //(absolute path) executable
85  if(!QFile::exists(rdesktop)){  //requested desktop is not currently installed
86    log("Invalid Auto-Login desktop requested - skipping....");
87    return "";           
88  }
89  return rdesktop;
90}
91
92QString Backend::getALPassword(){
93  QString rpassword = Config::autoLoginPassword();
94  return rpassword;
95}
96
97QString Backend::getUsernameFromDisplayname(QString dspname){
98  int i = displaynameList.indexOf(dspname);
99  return usernameList[i];
100}
101QString Backend::getUserHomeDir(QString username){
102  int i = usernameList.indexOf(username);
103  if( i == -1 ){ i = displaynameList.indexOf(username); }
104  return homedirList[i];
105}
106
107QStringList Backend::keyModels()
108{
109    QStringList _models;
110    QString code, desc, line;
111
112    Process p(QStringList() << "xkeyboard-models");
113
114    if (p.waitForFinished()) {
115        while (p.canReadLine()) {
116            line = p.readLine();
117            code = line;
118            code.truncate(line.indexOf(" "));
119            desc = line.remove(0, line.indexOf(" "));
120            _models.append(desc.simplified() + " - (" + code.simplified() + ")");
121        }
122    }
123    return _models;
124}
125
126QStringList Backend::keyLayouts()
127{
128    QStringList _layouts;
129    QString code, desc, line;
130
131    Process p(QStringList() << "xkeyboard-layouts");
132
133    if (p.waitForFinished()) {
134        while (p.canReadLine()) {
135            line = p.readLine();
136            code = line;
137            code.truncate(line.indexOf(" "));
138            desc = line.remove(0, line.indexOf(" "));
139            _layouts.append(desc.simplified() + " - (" + code.simplified() + ")");
140        }
141    }
142    return _layouts;
143}
144
145// Function which gets the key Variants for the target layout
146QStringList Backend::keyVariants(const QString &layout, QStringList &savedKeyVariants)
147{
148    QStringList _variants;
149    QString code, desc, line;
150
151    if ( savedKeyVariants.empty() )
152    {
153      Process p(QStringList() << "xkeyboard-variants");
154      if (p.waitForFinished()) {
155        while (p.canReadLine()) {
156            line = p.readLine();
157            savedKeyVariants << line;
158        }
159      }
160    }
161
162    for (int i = 0; i < savedKeyVariants.size(); ++i) {
163       // Look for variants for this particular layout
164       line = savedKeyVariants.at(i);
165       if ( line.indexOf(" " + layout + ":") != -1 )
166       {
167         code = line.simplified();
168         code.truncate(code.indexOf(" "));
169         desc = line.remove(0, line.indexOf(": ") + 1);
170         _variants.append(desc.simplified() + " - (" + code.simplified() + ")");
171       }
172    }
173
174    return _variants;
175}
176
177// Function which lets us run setxkbmap
178void Backend::changeKbMap(QString model, QString layout, QString variant)
179{
180   QProcess kbp;
181   QStringList args;
182   QString prog;
183   prog = "setxkbmap"; 
184   args << "-model" << model << "-layout" << layout << "-variant" << variant;
185   Backend::log("setxkbmap: " + args.join(" "));
186   kbp.start(prog, args);
187   kbp.waitForFinished();
188}
189
190QStringList Backend::languages()
191{
192    QStringList _languages;
193    QString code, desc, line;
194
195    QFile mFile;
196    mFile.setFileName("/usr/share/pc-sysinstall/conf/avail-langs");
197    if ( ! mFile.open(QIODevice::ReadOnly | QIODevice::Text))
198       return QStringList();
199
200    // Read in the meta-file for categories
201    QTextStream in(&mFile);
202    in.setCodec("UTF-8");
203    while ( !in.atEnd() ) {
204       line = in.readLine();
205       code = line;
206       code.truncate(line.indexOf(" "));
207       desc = line.remove(0, line.indexOf(" "));
208        _languages.append(desc.simplified() + " - (" + code.simplified() + ")");
209    }
210    mFile.close();
211    return _languages;
212}
213
214void Backend::openLogFile(QString logFilePath){
215  //If a log file exists, remove it
216  if(QFile::exists(logFilePath)){ QFile::remove(logFilePath); }
217  //save the path to the logfile
218  logFile = logFilePath;
219}
220
221void Backend::log(QString line){
222  QFile lFile(logFile);
223  lFile.open(QIODevice::Append);
224  QTextStream out(&lFile);
225  out << line << "\n";
226  lFile.close();
227}
228
229void Backend::checkLocalDirs(){
230  //Check for directories first
231  QString base = "/usr/local/share/PCDM";
232  QDir mainDir(base);
233  if(!mainDir.exists()){ mainDir.mkdir(base); }
234  if(!mainDir.exists("themes")){ mainDir.mkdir("themes"); }
235  //Check for sample files
236  if(!mainDir.exists("pcdm.conf.sample")){ QFile::copy(":samples/pcdm.conf",base+"/pcdm.conf.sample"); }
237  //if(!mainDir.exists("pcdm.theme.sample")){ QFile::copy(":samples/themes/default/default.theme",base+"/pcdm.theme.sample"); }
238 
239}
240
241//****** PRIVATE FUNCTIONS ******
242
243void Backend::loadXSessionsData(){
244  //Clear the current variables
245  instXNameList.clear(); instXBinList.clear(); 
246  instXCommentList.clear(); instXIconList.clear();
247  //Load the default paths/locale
248  QString xDir = Config::xSessionsDir();
249  if(!xDir.endsWith("/")){ xDir.append("/"); }
250  QString xIconDir = Config::xSessionsImageDir();
251  if(!xIconDir.endsWith("/")){ xIconDir.append("/"); }
252  QString localeCode = QLocale().name(); //gets the current locale code
253  //Find all *.desktop files
254  QDir dir(xDir);
255  QStringList deFiles = dir.entryList(QDir::Files);
256  deFiles = deFiles.filter(".desktop"); //only get *.desktop files
257  //Read each file to see if that desktop is installed
258  for(int i=0; i<deFiles.length(); i++){
259    QStringList tmp = readXSessionsFile(xDir+deFiles[i],localeCode);
260    //tmp[exec, name, comment, icon, tryexec]
261    if(!tmp.isEmpty()){
262      //Complete file paths if necessary
263      //if(!tmp[0].startsWith("/")){ tmp[0] = "/usr/local/bin/"+tmp[0]; }
264      if(!tmp[3].startsWith("/")&&!tmp[3].startsWith(":")&&!tmp[3].isEmpty()){ tmp[3] = xIconDir+tmp[3]; }
265      if(!tmp[4].startsWith("/")){ tmp[4] = "/usr/local/bin/"+tmp[4]; }
266      //Check for valid DE using the "tryexec" line
267        //this allows for special startup commands on the "exec" line
268      if(QFile::exists(tmp[4])){
269        //Add the DE to list of installed xsessions
270        instXBinList << tmp[0];
271        instXNameList << tmp[1];
272        instXCommentList << tmp[2];
273        //Check to make sure we have a valid icon
274        if(!tmp[3].isEmpty() && !QFile::exists(tmp[3]) ){ tmp[3] = ""; }
275        instXIconList << tmp[3];
276        Backend::log( "PCDM: Found xsession: " + tmp.join(" ") );
277      }
278    }
279  }
280  if(instXNameList.isEmpty()){
281    //Create an entry so that we know this function has been run already
282    instXNameList << "None";
283    instXBinList << "none";
284    instXCommentList << "No xSession Environments available in" << xDir;
285    instXIconList << ":images/nodesktop.png";
286  }
287}
288
289QStringList Backend::readXSessionsFile(QString filePath, QString locale){
290//output: [Exec, Localized Name, Localized Comment, Icon, TryExec]
291  QString name, lname, comm, lcomm, icon, exec, tryexec;
292  QStringList output;
293  QString lna = "Name["+locale+"]"; //variable to look at for localized name
294  QString lco = "Comment["+locale+"]"; //variable to look at for localized comment
295  QFile file(filePath);
296  if(file.open(QIODevice::ReadOnly | QIODevice::Text)){
297    QTextStream in(&file);
298    while (!in.atEnd()){
299      QString line = in.readLine().simplified();
300      QString var = line.section("=",0,0,QString::SectionSkipEmpty).simplified();
301      QString val = line.section("=",1,50,QString::SectionSkipEmpty).simplified();
302      if(var.toLower()=="exec"){ exec = val; }
303      else if(var.toLower()=="tryexec"){ tryexec = val; }
304      else if(var.toLower()=="icon"){ icon = val; }
305      else if(var.toLower()=="name"){ name = val; }
306      else if(var.toLower()=="comment"){ comm = val; }
307      else if(var==lna){ lname = val; }
308      else if(var==lco){ lcomm = val; }
309      else{} //do nothing with other lines
310
311    }
312  }
313  //Use the unlocalized name/comment if localized values not detected
314  if(lname.isEmpty()){ lname = name; }
315  if(lcomm.isEmpty()){ lcomm = comm; }
316  //Make sure that we have a name/exec for the session, otherwise invalid file
317  if(lname.isEmpty() || exec.isEmpty() || tryexec.isEmpty()){ return output; }
318  //Check that there is an icon given
319  if(icon.isEmpty()){
320    //Try to use a built in icon if a known DE
321    if(name.toLower().contains("gnome")){icon = ":images/gnome.png"; }
322    if(name.toLower().contains("kde")){icon = ":images/kde.png"; }
323    if(name.toLower().contains("xfce")){icon = ":images/xfce.png"; }
324    if(name.toLower().contains("lxde")){icon = ":images/lxde.png"; }
325    if(name.toLower().contains("fluxbox")){icon = ":images/fluxbox.png"; }
326    if(name.toLower().contains("openbox")){icon = ":images/openbox.png"; }
327  }
328  //Format the results into the output list
329  output.clear();
330  output << exec << lname << lcomm << icon << tryexec;
331  return output;
332
333}
334
335void Backend::readSystemUsers(){
336  //make sure the lists are empty
337  usernameList.clear(); displaynameList.clear(); homedirList.clear();
338  //Get all the users from the file "/etc/passwd"
339  QStringList uList = Utils::runShellCommand("cat /etc/passwd");
340
341  //Remove all users that have:
342  for(int i=0; i<uList.length(); i++){
343    bool bad = FALSE;
344    // "nologin" as their shell
345    if(uList[i].section(":",6,6).contains("nologin")){bad=TRUE;}
346    // "nonexistent" as their user directory
347    else if(uList[i].section(":",5,5).contains("nonexistent")){bad=TRUE;}
348    // uid > 1000
349    else if(uList[i].section(":",2,2).toInt() < 1000){bad=TRUE;}
350
351    //See if it failed any checks
352    if(bad){ uList.removeAt(i); i--; }
353    else{
354      //Add this user to the lists if it is good
355      usernameList << uList[i].section(":",0,0).simplified();
356      displaynameList << uList[i].section(":",4,4).simplified();
357      homedirList << uList[i].section(":",5,5).simplified();
358    }
359  }
360 
361}
Note: See TracBrowser for help on using the repository browser.