source: src-qt4/pc-softwaremanager/pbiDBAccess.cpp @ 4be3e27

releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since 4be3e27 was 4be3e27, checked in by Ken Moore <ken@…>, 9 months ago

Add the mime detection to the AppCafe? backend

  • Property mode set to 100644
File size: 15.5 KB
Line 
1/***************************************************************************
2 *   Copyright (C) 2011 - iXsystems                                       *
3 *   kris@pcbsd.org  *
4 *   tim@pcbsd.org   *
5 *   ken@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 #include "pbiDBAccess.h"
27
28// ================================
29// =======  SETUP FUNCTIONS =======
30// ================================
31bool PBIDBAccess::setDBPath(QString fullPath){
32  bool ok = FALSE;
33  //Make sure the directory exists first
34  if(QFile::exists(fullPath)){
35    DBPath = fullPath;
36    if(!DBPath.endsWith("/")){DBPath.append("/");}
37    DBDir->setPath(fullPath);
38    //Now read the list of available repos
39    reloadRepoList();
40    ok = TRUE;
41  }
42  return ok;
43}
44
45void PBIDBAccess::setRootCMDPrefix(QString prefix){
46  //All commands need root permissions to run, so this is used
47  //    to add the proper cmd prefix to prompt to run with root permissions
48  // Example: "pc-su" or "warden chroot <ip>"
49  cmdPrefix = prefix;
50  if(!cmdPrefix.endsWith(" ")){ cmdPrefix.append(" "); }
51  //qDebug() << "DB command prefix:" << cmdPrefix;
52}
53
54void PBIDBAccess::reloadRepoList(){
55  repoList.clear();
56  if(DBDir->cd(DBPath+"repos")){ //directory exists
57    repoList = DBDir->entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Readable);
58  }     
59}
60
61bool PBIDBAccess::setRepo(QString repoNum){
62  //Make sure the repo is available
63  bool ok = DBDir->cd(DBPath+"repos");
64  if(ok){ //directory exists
65    QStringList rL = DBDir->entryList(QStringList()<<repoNum+"*",QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Readable);
66    if(rL.length() == 1){ //this repo exists
67      currentRepoNumber=rL[0].section(".",0,0,QString::SectionSkipEmpty);
68      currentRepoID=rL[0].section(".",1,1,QString::SectionSkipEmpty);
69      return TRUE;
70    }
71  }
72  return FALSE;
73}
74
75bool PBIDBAccess::currentRepoInvalid(){
76  //Check to make sure that the current Repo is still valid
77  reloadRepoList();
78  if(repoList.contains(currentRepoNumber+"."+currentRepoID)){ return FALSE; }
79  else{ return TRUE; }
80}
81
82QStringList PBIDBAccess::availableRepos(){
83  QStringList output;
84  for(int i=0; i<repoList.length(); i++){
85    output << repoList[i].section(".",0,0,QString::SectionSkipEmpty);
86  }
87  return output;
88}
89
90QStringList PBIDBAccess::repoInfo(QString repoNum){
91  //Returns: output=[Name, Master URL] 
92  QStringList output;
93  QString ID = getIDFromNum(repoNum);
94    QStringList lines = Extras::readFile(DBPath+"repos/"+repoNum+"."+ID);
95    if(!lines.isEmpty()){
96      output <<"" << ""; //make sure there are two entries available
97      for(int j=0; j<lines.length(); j++){
98         if(lines[j].startsWith("URL: ")){ output[1] = lines[j].section("URL: ",1,50).simplified(); }
99         else if(lines[j].startsWith("Desc: ")){ output[0] = lines[j].section("Desc: ",1,50).simplified(); }
100      }
101    }
102  return output;
103}
104
105QStringList PBIDBAccess::repoMirrors(QString repoNum){
106  QStringList output;
107  QString ID = getIDFromNum(repoNum);
108  if(!ID.isEmpty()){
109    output = Extras::readFile(DBPath+"mirrors/"+ID);     
110  }
111  return output;
112}
113
114// ========================================
115// =======  PUBLIC ACCESS FUNCTIONS =======
116// ========================================
117QStringList PBIDBAccess::installed(){
118  QStringList output;
119  bool ok = DBDir->cd(DBPath+"installed");
120  if(ok){
121    output = DBDir->entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Readable);
122  }
123  return output;
124}
125
126QStringList PBIDBAccess::installedPbiInfo(QString pbiID){
127  //Output format: output[ name, version, arch, date created, author, website, installpath, iconpath, maintainer, description, fbsdversion]
128  QStringList output;
129  QString path = DBPath+"installed/"+pbiID;
130  bool ok = DBDir->cd(path);
131  if(ok){
132    output << readOneLineFile(path+"/pbi_name");
133    output << readOneLineFile(path+"/pbi_version");
134    output << readOneLineFile(path+"/pbi_arch");
135    //Get the latest date (remove the time) for this PBI (mdate and patchmdate seem to vary in use)
136    QString mdate = readOneLineFile(path+"/pbi_mdate").section(" ",0,0).simplified();
137    QString pdate = readOneLineFile(path+"/pbi_patchmdate").section(" ",0,0).simplified();
138    if( !pdate.isEmpty() && (pdate > mdate) ){
139      output << pdate; //use the date it was patched
140    }else{
141      output <<  mdate; //use the date it was initially created
142    }
143    output << readOneLineFile(path+"/pbi_author");
144    output << readOneLineFile(path+"/pbi_web");
145    output << readOneLineFile(path+"/pbi_installedpath");
146    output << path+"/pbi_icon.png";
147    output << readOneLineFile(path+"/pbi_maintainer");
148    output << cleanupDescription( readOneLineFile(path+"/pbi_desc").split("\n") );
149    output << readOneLineFile(path+"/pbi_fbsdver");
150  }
151  return output;
152}
153
154bool PBIDBAccess::installedPbiAutoUpdate(QString pbiID){
155   bool ok = FALSE;
156   if( QFile::exists(DBPath+"installed/"+pbiID+"/autoupdate-enable") ){ ok = TRUE; }
157   //qDebug() << "AutoUpdate:" << pbiID << ok;
158   return ok;
159}
160
161bool PBIDBAccess::installedPbiNeedsRoot(QString pbiID){
162  bool ok=FALSE;
163  if( QFile::exists(DBPath+"installed/"+pbiID+"/pbi_requiresroot") ){ ok=TRUE; }
164  else{
165    //Also check who installed the PBI if not flagged directly
166    QFileInfo fInfo(DBPath+"installed/"+pbiID);
167    if( fInfo.owner() == "root" ){ ok=TRUE; }
168  }
169  //qDebug() << pbiID << "requires root:" << ok;
170  return ok;
171}
172
173bool PBIDBAccess::installedPbiHasXdgDesktop(QString installPath){
174  if(!installPath.endsWith("/")){ installPath.append("/"); }
175  bool ok = DBDir->cd(installPath+".xdg-desktop");
176  if(ok){
177    if( DBDir->entryList(QStringList()<<"*.desktop",QDir::Files).length() > 0 ){ return TRUE; }   
178  }
179  return FALSE;
180}
181
182bool PBIDBAccess::installedPbiHasXdgMenu(QString installPath){
183  if(!installPath.endsWith("/")){ installPath.append("/"); }
184  bool ok = DBDir->cd(installPath+".xdg-menu");
185  if(ok){
186    if( DBDir->entryList(QStringList()<<"*.desktop",QDir::Files).length() > 0 ){ return TRUE; }   
187  }
188  return FALSE;
189}
190
191bool PBIDBAccess::installedPbiHasXdgMime(QString installPath){
192  if(!installPath.endsWith("/")){ installPath.append("/"); }
193  bool ok = DBDir->cd(installPath+".xdg-mime");
194  if(ok){
195    if( DBDir->entryList(QStringList()<<"*.xml",QDir::Files).length() > 0 ){ return TRUE; }       
196  }
197  return FALSE;
198}
199
200QString PBIDBAccess::indexFilePath(){
201  return DBPath+"index/"+currentRepoID+"-index";
202}
203
204QString PBIDBAccess::metaFilePath(){
205  return DBPath+"index/"+currentRepoID+"-meta"; 
206}
207
208QStringList PBIDBAccess::parseIndexLine(QString line){
209  //output[name, arch, version, date, sizeK, isLatest(bool), filename]
210  //line format 12/3/2013: [name,arch,version,checksum,datetimeBuilt,mirrorPathToPBI,datetimeApproved,?,current/active,sizeInK,?]
211      // NOTE: last two entries missing quite often
212  QStringList lineInfo = line.split(":");
213  QStringList output;
214  if(lineInfo.length() < 9 ){ return output; } //skip incomplete entries
215  output << lineInfo[0]; //name
216  output << lineInfo[1]; //architecture
217  output << lineInfo[2]; //version
218  QDateTime DT;
219  DT.setTime_t(lineInfo[6].toInt());
220  output << DT.toString("yyyyMMdd"); //date added to AppCafe
221  if(lineInfo.length() >= 10){ output << lineInfo[9]; }//Size in KB
222  else{ output << ""; }
223  if(lineInfo[8].simplified() == "current"){ output << "true"; } //is most recent version
224  else{ output << "false"; }  //is an older version
225  output << lineInfo[5].section("/",-1); //filename (Example: myapp-0.1-amd64.pbi)
226  return output;
227}
228
229QStringList PBIDBAccess::parseAppMetaLine(QString line){
230  // line format 11/14/2013 (10.x PBI format):
231  // [name,category,remoteIcon,author,website,license,apptype,tags,description,requiresroot,dateadded,maintainerEmail,shortDescription]
232  QStringList list = line.split(";");
233  //Format the output list
234  QStringList output;
235  //bool DEBUG = (list[0].toLower()=="xastir");
236  if(list.length() < 13){ return output;} //invalid line
237  output << list[0]; //NAME
238  output << list[1]; //CATEGORY
239  output << list[2]; //remoteIcon
240  output << list[3]; //AUTHOR
241  output << list[4]; //WEBSITE
242  output << list[5]; //LICENSE
243  output << list[6]; //APP-TYPE
244  output << list[7]; //TAGS
245  //Cleanup the description (try to format the text properly)
246  output << cleanupDescription( list[8].split("<br>") ); //DESCRIPTION
247  if(list[9]=="YES"){ list[9]="true"; } //change to the same true/false syntax as elsewhere
248  output << list[9]; //REQUIRESROOT
249  output << list[10]; //DATE ADDED (just a number - not human-readable)
250  output << list[11]; //MAINTAINER EMAIL
251  //Cleanup the short description (remove any line breaks)
252  QStringList tmp = list[12].split("<br>", QString::SkipEmptyParts);
253  list[12] = tmp.join(" ").simplified();
254  output << list[12]; //SHORT DESCRIPTION
255  return output;
256}
257
258QStringList PBIDBAccess::parseCatMetaLine(QString line){
259  // line format 11/14/2013: [name,remoteicon,description]
260  QStringList output = line.split(";");
261  if(output.length() < 3){output.clear(); } //incomplete line
262  return output;
263}
264       
265QString PBIDBAccess::remoteToLocalIcon(QString name, QString remoteIconPath){
266  QString output = DBPath+"repo-icons/"+currentRepoID+"-"+name+"."+remoteIconPath.section(".",-1);
267  //qDebug() << "Remote to Local Icon Path conversion:" << remoteIconPath << output;
268  return output;
269}
270
271// ===== Database Modification Functions =====
272bool PBIDBAccess::addRepoFile(QString rpofilepath){
273  if(!QFile::exists(rpofilepath)){ return FALSE; }
274  //Generate the command
275  QString cmd;
276  if(cmdPrefix.isEmpty()){ return FALSE; }
277  else{ cmd = cmdPrefix; }
278  cmd.append("\"pbi_addrepo "+rpofilepath+"\"");
279  qDebug() <<"DB cmd generated:" << cmd;
280  //Now run the command
281  QStringList result = runCMD(cmd).split("\n");
282  if(!result.isEmpty()){
283    if(result[result.length()-1].startsWith("Added new repo:")){ 
284      //Make sure to prompt the PBI Daemon to refresh the meta/index files now
285      runCMD( cmdPrefix+"\"pbid --refresh\"" ); //don't care about output
286      return TRUE;
287    }
288  } 
289  qDebug() << "PBI Database Error:";
290  qDebug() << " - CMD:"<<cmd;
291  qDebug() << " - Error:"<<result;
292  return FALSE;
293}
294
295bool PBIDBAccess::removeRepo(QString repoNum){
296  //Generate the command
297  QString cmd;
298  if(cmdPrefix.isEmpty()){ return FALSE; }
299  else{ cmd = cmdPrefix; }
300  cmd.append("\"pbi_deleterepo "+repoNum+"\"");
301  qDebug() <<"DB cmd generated:" << cmd;
302  //Now run the command
303  QStringList result = runCMD(cmd).split("\n");
304  if(!result.isEmpty()){
305    //qDebug() << "Repo Removed:" << result;
306    if(result[result.length()-1].startsWith("Deleted Repository")){ return TRUE; }
307  } 
308  qDebug() << "PBI Database Error:";
309  qDebug() << " - CMD:"<<cmd;
310  qDebug() << " - Error:"<<result;
311  return FALSE; 
312}
313
314bool PBIDBAccess::moveRepoUp(QString repoNum){
315  //Generate the command
316  QString cmd;
317  if(cmdPrefix.isEmpty()){ return FALSE; }
318  else{ cmd = cmdPrefix; }
319  cmd.append("\"pbi_listrepo --up "+repoNum+"\"");
320  qDebug() <<"DB cmd generated:" << cmd;
321  //Now run the command
322  QStringList result = runCMD(cmd).split("\n");
323  if(!result.isEmpty()){
324    return TRUE; //no special check for this - will need to re-load repos anyway
325  } 
326  return FALSE;
327}
328
329bool PBIDBAccess::moveRepoDown(QString repoNum){
330  //Generate the command
331  QString cmd;
332  if(cmdPrefix.isEmpty()){ return FALSE; }
333  else{ cmd = cmdPrefix; }
334  cmd.append("\"pbi_listrepo --down "+repoNum+"\"");
335  qDebug() <<"DB cmd generated:" << cmd;
336  //Now run the command
337  QStringList result = runCMD(cmd).split("\n");
338  if(!result.isEmpty()){
339    return TRUE; //no special check for this - will need to re-load repos anyway
340  } 
341  return FALSE;
342}
343
344bool PBIDBAccess::setRepoMirrors(QString repoNum, QStringList mirrors){
345  QString cmd;
346  if(cmdPrefix.isEmpty()){ return FALSE; }
347  else{ cmd = cmdPrefix; }
348  cmd.append("\"pbi_listrepo --mirror "+mirrors.join(",")+" "+repoNum+"\"");
349  qDebug() <<"DB cmd generated:" << cmd;
350  //Now run the command
351  QStringList result = runCMD(cmd).split("\n");
352  if(!result.isEmpty()){
353    if(mirrors.isEmpty()){
354      if(result[result.length()-1].startsWith("Mirror(s):")){ return TRUE; }
355    }else{
356      if(result[result.length()-1] == mirrors[mirrors.length()-1] ){ return TRUE; }
357    }
358  } 
359  qDebug() << "PBI Database Error:";
360  qDebug() << " - CMD:"<<cmd;
361  qDebug() << " - Error:"<<result;
362  return FALSE;         
363}
364
365// ========================================
366// =======  PRIVATE ACCESS FUNCTIONS ======
367// ========================================
368QString PBIDBAccess::readOneLineFile(QString path){
369  QFile file(path);
370  if(!file.exists()){ return ""; } //Return nothing for missing file
371  //Now read the file
372  QString output;
373  if(file.open(QIODevice::ReadOnly | QIODevice::Text)){
374    QTextStream in(&file);
375    while(!in.atEnd()){
376      if(!output.isEmpty()){ output.append("\n"); }
377      output.append( in.readLine() ); 
378    }
379    file.close();
380  }
381  return output;
382}
383
384QString PBIDBAccess::getIDFromNum(QString repoNum){
385  QString output;
386  for(int i=0; i<repoList.length(); i++){
387    if(repoList[i].startsWith(repoNum+".")){
388      output = repoList[i].section(".",1,1);
389      break;       
390    }
391  }     
392  return output;
393}
394
395QString PBIDBAccess::runCMD(QString cmd){
396  //Small function to run quick database modification commands
397  QString output;
398  proc->start(cmd);
399  if(proc->waitForFinished(30000)){
400    output = proc->readAll();     
401  }else{
402    proc->terminate();
403    output = "Process timed out (30 sec)";
404  }
405  if(output.endsWith("\n")){ output.chop(1); }
406  output = output.simplified();
407  return output;
408}
409
410QString PBIDBAccess::cleanupDescription(QStringList tmp){
411  for(int i=1; i<tmp.length(); i++){
412    //tmp[i-1] = tmp[i-1].simplified();
413    tmp[i] = tmp[i].simplified();
414    if( tmp[i].startsWith("WWW: ") ){
415      //Remove the website URL from the end, it is already accounted for elsewhere
416      tmp.removeAt(i);
417      i--;
418    }else if(tmp[i-1].isEmpty() || tmp[i].isEmpty() ){}
419    else if(tmp[i-1].endsWith(".") || tmp[i-1].endsWith(":") || tmp[i-1].endsWith(";") || tmp[i-1].endsWith("?") || tmp[i-1].endsWith("!") ){}
420    else if( tmp[i].startsWith("*") || tmp[i].startsWith("0") || tmp[i].startsWith("-") || tmp[i].startsWith("o ") ){}
421    else{
422      //if(DEBUG){ qDebug() << " - Bad Line Break:\n" << tmp[i-1] << "<br>" << tmp[i]; }
423      //Bad line break, combine it with the previous line
424      tmp[i-1].append(" "+tmp[i]);
425      tmp.removeAt(i);
426      i--;
427    }
428  }
429  return tmp.join("\n");
430}
Note: See TracBrowser for help on using the repository browser.