author | erik <erik> | 2007-01-26 20:30:32 (UTC) |
---|---|---|
committer | erik <erik> | 2007-01-26 20:30:32 (UTC) |
commit | f77da1ae08512b02a3c50a124f823ed77e53dd64 (patch) (side-by-side diff) | |
tree | ac7e414aff95348e0bf2fba3f45b2a06a4eb4623 | |
parent | 4688f98202f590ec6af6c2e66a49dd2f80536083 (diff) | |
download | opie-f77da1ae08512b02a3c50a124f823ed77e53dd64.zip opie-f77da1ae08512b02a3c50a124f823ed77e53dd64.tar.gz opie-f77da1ae08512b02a3c50a124f823ed77e53dd64.tar.bz2 |
Both packageslave.cpp and textedit.cpp have instances of possibly exploitable
race conditions associated to files. The big deal is that it is quite typical
to use strings of pathnames to track files. But because that does not leverage
the filesystem would be attackers may be able to exploit time lags in uses
of filesystem functions (like stat and chmod or open) to get files with
suspect data into the files that the applications are working with.
This commit closes that potential hole even though there are no known exploits.
Better safe then sorry. There is no change in the behavior of the apps.
-rw-r--r-- | core/apps/textedit/textedit.cpp | 45 | ||||
-rw-r--r-- | core/launcher/packageslave.cpp | 48 |
2 files changed, 49 insertions, 44 deletions
diff --git a/core/apps/textedit/textedit.cpp b/core/apps/textedit/textedit.cpp index 4bbc62b..1c81a55 100644 --- a/core/apps/textedit/textedit.cpp +++ b/core/apps/textedit/textedit.cpp @@ -1,1191 +1,1188 @@ /********************************************************************** // textedit.cpp ** Copyright (C) 2000 Trolltech AS. All rights reserved. ** ** This file is part of Opie Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** **********************************************************************/ // changes added by L. J. Potter Sun 02-17-2002 21:31:31 #include "textedit.h" #include "filePermissions.h" /* OPIE */ #include <opie2/odebug.h> #include <opie2/ofileselector.h> #include <opie2/ofiledialog.h> #include <opie2/ofontselector.h> #include <opie2/oresource.h> #include <qpe/config.h> #include <qpe/qpeapplication.h> /* QT */ #include <qmenubar.h> #include <qtoolbar.h> #include <qtextstream.h> #include <qclipboard.h> #include <qaction.h> #include <qlineedit.h> #include <qmessagebox.h> #include <qlayout.h> #include <qtimer.h> #include <qdir.h> /* STD */ #include <unistd.h> #include <sys/stat.h> #include <stdlib.h> //getenv using namespace Opie::Core; using namespace Opie::Ui; #if QT_VERSION < 0x030000 class QpeEditor : public QMultiLineEdit { public: QpeEditor( QWidget *parent, const char * name = 0 ) : QMultiLineEdit( parent, name ) { clearTableFlags(); setTableFlags( Tbl_vScrollBar | Tbl_autoHScrollBar ); } void find( const QString &txt, bool caseSensitive, bool backwards ); protected: bool markIt; int line1, line2, col1, col2; void mousePressEvent( QMouseEvent * ); void mouseReleaseEvent( QMouseEvent * ); //public slots: /* signals: void notFound(); void searchWrapped(); */ private: }; void QpeEditor::mousePressEvent( QMouseEvent *e ) { switch(e->button()) { case RightButton: { //rediculous workaround for qt popup menu //and the hold right click mechanism this->setSelection( line1, col1, line2, col2); QMultiLineEdit::mousePressEvent( e ); markIt = false; } break; default: { if(!markIt) { int line, col; this->getCursorPosition(&line, &col); line1=line2=line; col1=col2=col; } QMultiLineEdit::mousePressEvent( e ); } break; }; } void QpeEditor::mouseReleaseEvent( QMouseEvent * ) { if(this->hasMarkedText()) { markIt = true; this->getMarkedRegion( &line1, &col1, &line2, & col2 ); } else { markIt = false; } } void QpeEditor::find ( const QString &txt, bool caseSensitive, bool backwards ) { static bool wrap = false; int line, col; if ( wrap ) { if ( !backwards ) line = col = 0; wrap = false; // emit searchWrapped(); } else { getCursorPosition( &line, &col ); } //ignore backwards for now.... if ( !backwards ) { for ( ; ; ) { if ( line >= numLines() ) { wrap = true; //emit notFound(); break; } int findCol = getString( line )->find( txt, col, caseSensitive ); if ( findCol >= 0 ) { setCursorPosition( line, findCol, false ); col = findCol + txt.length(); setCursorPosition( line, col, true ); //found = true; break; } line++; col = 0; } } } #else #error "Must make a QpeEditor that inherits QTextEdit" #endif static const int nfontsizes = 6; static const int fontsize[nfontsizes] = {8,10,12,14,18,24}; TextEdit::TextEdit( QWidget *parent, const char *name, WFlags f ) : QMainWindow( parent, name, f ), bFromDocView( false ) { doc = 0; edited=false; fromSetDocument=false; setToolBarsMovable( false ); connect( qApp,SIGNAL( aboutToQuit()),SLOT( cleanUp()) ); channel = new QCopChannel( "QPE/Application/textedit", this ); connect( channel, SIGNAL(received(const QCString&,const QByteArray&)), this, SLOT(receive(const QCString&,const QByteArray&)) ); setIcon( Opie::Core::OResource::loadPixmap( "textedit/TextEditor", Opie::Core::OResource::SmallIcon ) ); QToolBar *bar = new QToolBar( this ); bar->setHorizontalStretchable( true ); menu = bar; QMenuBar *mb = new QMenuBar( bar ); QPopupMenu *file = new QPopupMenu( this ); QPopupMenu *edit = new QPopupMenu( this ); QPopupMenu *advancedMenu = new QPopupMenu(this); font = new QPopupMenu( this ); bar = new QToolBar( this ); editBar = bar; QAction *a = new QAction( tr( "New" ), Opie::Core::OResource::loadPixmap( "new", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( fileNew() ) ); // a->addTo( bar ); a->addTo( file ); a = new QAction( tr( "Open" ), Opie::Core::OResource::loadPixmap( "fileopen", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( fileOpen() ) ); a->addTo( bar ); a->addTo( file ); a = new QAction( tr( "Save" ), Opie::Core::OResource::loadPixmap( "save", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( save() ) ); file->insertSeparator(); a->addTo( bar ); a->addTo( file ); a = new QAction( tr( "Save As" ), Opie::Core::OResource::loadPixmap( "save", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( saveAs() ) ); a->addTo( file ); a = new QAction( tr( "Cut" ), Opie::Core::OResource::loadPixmap( "cut", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( editCut() ) ); a->addTo( editBar ); a->addTo( edit ); a = new QAction( tr( "Copy" ), Opie::Core::OResource::loadPixmap( "copy", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( editCopy() ) ); a->addTo( editBar ); a->addTo( edit ); a = new QAction( tr( "Paste" ), Opie::Core::OResource::loadPixmap( "paste", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( editPaste() ) ); a->addTo( editBar ); a->addTo( edit ); #ifndef QT_NO_CLIPBOARD a = new QAction( tr( "Insert Time and Date" ), Opie::Core::OResource::loadPixmap( "paste", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( editPasteTimeDate() ) ); a->addTo( edit ); #endif a = new QAction( tr( "Goto Line..." ), Opie::Core::OResource::loadPixmap( "find", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( gotoLine() ) ); edit->insertSeparator(); a->addTo( edit ); a = new QAction( tr( "Find..." ), Opie::Core::OResource::loadPixmap( "find", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( editFind() ) ); a->addTo( bar ); a->addTo( edit ); zin = new QAction( tr("Zoom in"), QString::null, 0, this, 0 ); connect( zin, SIGNAL( activated() ), this, SLOT( zoomIn() ) ); zin->addTo( font ); zout = new QAction( tr("Zoom out"), QString::null, 0, this, 0 ); connect( zout, SIGNAL( activated() ), this, SLOT( zoomOut() ) ); zout->addTo( font ); font->insertSeparator(); font->insertItem(tr("Font"), this, SLOT(changeFont()) ); font->insertSeparator(); font->insertItem(tr("Advanced Features"), advancedMenu); QAction *wa = new QAction( tr("Wrap lines"), QString::null, 0, this, 0 ); connect( wa, SIGNAL( toggled(bool) ), this, SLOT( setWordWrap(bool) ) ); wa->setToggleAction(true); wa->addTo( advancedMenu); nStart = new QAction( tr("Start with new file"), QString::null, 0, this, 0 ); connect( nStart, SIGNAL( toggled(bool) ), this, SLOT( changeStartConfig(bool) ) ); nStart->setToggleAction(true); nStart->addTo( advancedMenu ); nStart->setEnabled(false); nAdvanced = new QAction( tr("Prompt on Exit"), QString::null, 0, this, 0 ); connect( nAdvanced, SIGNAL( toggled(bool) ), this, SLOT( doPrompt(bool) ) ); nAdvanced->setToggleAction(true); nAdvanced->addTo( advancedMenu ); desktopAction = new QAction( tr("Always open linked file"), QString::null, 0, this, 0 ); connect( desktopAction, SIGNAL( toggled(bool) ), this, SLOT( doDesktop(bool) ) ); desktopAction->setToggleAction(true); desktopAction->addTo( advancedMenu); filePermAction = new QAction( tr("File Permissions"), QString::null, 0, this, 0 ); connect( filePermAction, SIGNAL( toggled(bool) ), this, SLOT( doFilePerms(bool) ) ); filePermAction->setToggleAction(true); filePermAction->addTo( advancedMenu); searchBarAction = new QAction( tr("Search Bar Open"), QString::null, 0, this, 0 ); connect( searchBarAction, SIGNAL( toggled(bool) ), this, SLOT( setSearchBar(bool) ) ); searchBarAction->setToggleAction(true); searchBarAction->addTo( advancedMenu); nAutoSave = new QAction( tr("Auto Save 5 min."), QString::null, 0, this, 0 ); connect( nAutoSave, SIGNAL( toggled(bool) ), this, SLOT( doTimer(bool) ) ); nAutoSave->setToggleAction(true); nAutoSave->addTo( advancedMenu); //font->insertSeparator(); //font->insertItem(tr("About"), this, SLOT( doAbout()) ); mb->insertItem( tr( "File" ), file ); mb->insertItem( tr( "Edit" ), edit ); mb->insertItem( tr( "View" ), font ); searchBar = new QToolBar(this); addToolBar( searchBar, "Search", QMainWindow::Top, true ); searchBar->setHorizontalStretchable( true ); searchEdit = new QLineEdit( searchBar, "searchEdit" ); searchBar->setStretchableWidget( searchEdit ); connect( searchEdit, SIGNAL( textChanged(const QString&) ), this, SLOT( search() ) ); a = new QAction( tr( "Find Next" ), Opie::Core::OResource::loadPixmap( "next", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( findNext() ) ); a->addTo( searchBar ); a->addTo( edit ); a = new QAction( tr( "Close Find" ), Opie::Core::OResource::loadPixmap( "close", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( findClose() ) ); a->addTo( searchBar ); edit->insertSeparator(); a = new QAction( tr( "Delete" ), Opie::Core::OResource::loadPixmap( "close", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL( activated() ), this, SLOT( editDelete() ) ); a->addTo( edit ); searchBar->hide(); editor = new QpeEditor( this ); setCentralWidget( editor ); editor->setFrameStyle( QFrame::Panel | QFrame::Sunken ); connect( editor, SIGNAL( textChanged() ), this, SLOT( editorChanged() ) ); QPEApplication::setStylusOperation( editor, QPEApplication::RightOnHold); Config cfg("TextEdit"); cfg. setGroup ( "Font" ); QFont defaultFont = editor-> font ( ); QString family = cfg. readEntry ( "Family", defaultFont. family ( )); int size = cfg. readNumEntry ( "Size", defaultFont. pointSize ( )); int weight = cfg. readNumEntry ( "Weight", defaultFont. weight ( )); bool italic = cfg. readBoolEntry ( "Italic", defaultFont. italic ( )); defaultFont = QFont ( family, size, weight, italic ); editor-> setFont ( defaultFont ); // updateCaption(); cfg.setGroup ( "View" ); promptExit = cfg.readBoolEntry ( "PromptExit", false ); openDesktop = cfg.readBoolEntry ( "OpenDesktop", true ); filePerms = cfg.readBoolEntry ( "FilePermissions", false ); useSearchBar = cfg.readBoolEntry ( "SearchBar", false ); startWithNew = cfg.readBoolEntry ( "startNew", true); featureAutoSave = cfg.readBoolEntry( "autosave", false); if(useSearchBar) searchBarAction->setOn(true); if(promptExit) nAdvanced->setOn( true ); if(openDesktop) desktopAction->setOn( true ); if(filePerms) filePermAction->setOn( true ); if(startWithNew) nStart->setOn( true ); if(featureAutoSave) nAutoSave->setOn(true); // { // doTimer(true); // } bool wrap = cfg. readBoolEntry ( "Wrap", true ); wa-> setOn ( wrap ); setWordWrap ( wrap ); ///////////////// if( qApp->argc() > 1) { currentFileName=qApp->argv()[1]; QFileInfo fi(currentFileName); if(fi.baseName().left(1) == "") { openDotFile(currentFileName); } else { openFile(currentFileName); } } else { edited1=false; openDotFile(""); } viewSelection = cfg.readNumEntry( "FileView", 0 ); } TextEdit::~TextEdit() { if( edited1 && !promptExit) { switch( savePrompt() ) { case 1: { saveAs(); } break; }; } delete editor; } void TextEdit::closeEvent(QCloseEvent *) { if( promptExit) { switch( savePrompt() ) { case 1: { saveAs(); qApp->quit(); } break; case 2: { qApp->quit(); } break; case -1: break; }; } else qApp->quit(); } void TextEdit::cleanUp() { Config cfg ( "TextEdit" ); cfg. setGroup ( "Font" ); QFont f = editor->font(); cfg.writeEntry ( "Family", f. family ( )); cfg.writeEntry ( "Size", f. pointSize ( )); cfg.writeEntry ( "Weight", f. weight ( )); cfg.writeEntry ( "Italic", f. italic ( )); cfg.setGroup ( "View" ); cfg.writeEntry ( "Wrap", editor->wordWrap() == QMultiLineEdit::WidgetWidth ); cfg.writeEntry ( "FileView", viewSelection ); cfg.writeEntry ( "PromptExit", promptExit ); cfg.writeEntry ( "OpenDesktop", openDesktop ); cfg.writeEntry ( "FilePermissions", filePerms ); cfg.writeEntry ( "SearchBar", useSearchBar ); cfg.writeEntry ( "startNew", startWithNew ); } void TextEdit::accept() { if( edited1) saveAs(); qApp->quit(); } void TextEdit::zoomIn() { setFontSize(editor->font().pointSize()+1,false); } void TextEdit::zoomOut() { setFontSize(editor->font().pointSize()-1,true); } void TextEdit::setFontSize(int sz, bool round_down_not_up) { int s=10; for (int i=0; i<nfontsizes; i++) { if ( fontsize[i] == sz ) { s = sz; break; } else if ( round_down_not_up ) { if ( fontsize[i] < sz ) s = fontsize[i]; } else { if ( fontsize[i] > sz ) { s = fontsize[i]; break; } } } QFont f = editor->font(); f.setPointSize(s); editor->setFont(f); zin->setEnabled(s != fontsize[nfontsizes-1]); zout->setEnabled(s != fontsize[0]); } void TextEdit::setBold(bool y) { QFont f = editor->font(); f.setBold(y); editor->setFont(f); } void TextEdit::setItalic(bool y) { QFont f = editor->font(); f.setItalic(y); editor->setFont(f); } void TextEdit::setWordWrap(bool y) { bool state = editor->edited(); QString captionStr = caption(); bool b1 = edited1; bool b2 = edited; editor->setWordWrap(y ? QMultiLineEdit::WidgetWidth : QMultiLineEdit::NoWrap ); editor->setEdited( state ); edited1=b1; edited=b2; setCaption(captionStr); } void TextEdit::setSearchBar(bool b) { useSearchBar=b; Config cfg("TextEdit"); cfg.setGroup("View"); cfg.writeEntry ( "SearchBar", b ); searchBarAction->setOn(b); if(b) searchBar->show(); else searchBar->hide(); editor->setFocus(); } void TextEdit::fileNew() { // if( !bFromDocView ) { // saveAs(); // } newFile(DocLnk()); } void TextEdit::fileOpen() { Config cfg("TextEdit"); cfg. setGroup ( "View" ); QMap<QString, QStringList> map; map.insert(tr("All"), QStringList() ); QStringList text; text << "text/*"; map.insert(tr("Text"), text ); text << "*"; map.insert(tr("All"), text ); QString str = OFileDialog::getOpenFileName( 2, QString::null , QString::null, map); if( !str.isEmpty() && QFile(str).exists() && !QFileInfo(str).isDir() ) { openFile( str ); } else updateCaption(); } void TextEdit::doSearchBar() { if(!useSearchBar) searchBar->hide(); else searchBar->show(); } #if 0 void TextEdit::slotFind() { FindDialog frmFind( tr("Text Editor"), this ); connect( &frmFind, SIGNAL(signalFindClicked(const QString&,bool,bool,int)), editor, SLOT(slotDoFind(const QString&,bool,bool))); //case sensitive, backwards, [category] connect( editor, SIGNAL(notFound()), &frmFind, SLOT(slotNotFound()) ); connect( editor, SIGNAL(searchWrapped()), &frmFind, SLOT(slotWrapAround()) ); frmFind.exec(); } #endif void TextEdit::fileRevert() { clear(); fileOpen(); } void TextEdit::editCut() { #ifndef QT_NO_CLIPBOARD editor->cut(); #endif } void TextEdit::editCopy() { #ifndef QT_NO_CLIPBOARD editor->copy(); #endif } void TextEdit::editPaste() { #ifndef QT_NO_CLIPBOARD editor->paste(); #endif } void TextEdit::editFind() { searchBar->show(); searchEdit->setFocus(); } void TextEdit::findNext() { editor->find( searchEdit->text(), false, false ); } void TextEdit::findClose() { searchBar->hide(); } void TextEdit::search() { editor->find( searchEdit->text(), false, false ); } void TextEdit::newFile( const DocLnk &f ) { DocLnk nf = f; nf.setType("text/plain"); clear(); setWState (WState_Reserved1 ); editor->setFocus(); doc = new DocLnk(nf); currentFileName = "Unnamed"; odebug << "newFile "+currentFileName << oendl; updateCaption( currentFileName); // editor->setEdited( false); } void TextEdit::openDotFile( const QString &f ) { if(!currentFileName.isEmpty()) { currentFileName=f; odebug << "openFile dotfile " + currentFileName << oendl; QString txt; QFile file(f); if (!file.open(IO_ReadWrite)) owarn << "Failed to open file " << file.name() << oendl; else { QTextStream t(&file); while ( !t.atEnd()) { txt+=t.readLine()+"\n"; } editor->setText(txt); editor->setEdited( false); edited1=false; edited=false; } } updateCaption( currentFileName); } void TextEdit::openFile( const QString &f ) { odebug << "filename is "+ f << oendl; QString filer; QFileInfo fi( f); // bFromDocView = true; if(f.find(".desktop",0,true) != -1 && !openDesktop ) { switch ( QMessageBox::warning(this,tr("Text Editor"),tr("Text Editor has detected<BR>you selected a <B>.desktop</B>file.<BR>Open<B>.desktop</B> file or <B>linked</B> file?"),tr(".desktop File"),tr("Linked Document"),0,1,1) ) { case 0: //desktop filer = f; break; case 1: //linked DocLnk sf(f); filer = sf.file(); break; }; } else if(fi.baseName().left(1) == "") { odebug << "opening dotfile" << oendl; currentFileName=f; openDotFile(currentFileName); return; } /* * The problem is a file where Config(f).isValid() and it does not * end with .desktop will be treated as desktop file */ else if (f.find(".desktop",0,true) != -1 ) { DocLnk sf(f); filer = sf.file(); if(filer.right(1) == "/") filer = f; } else filer = f; DocLnk nf; nf.setType("text/plain"); nf.setFile(filer); currentFileName=filer; nf.setName(fi.baseName()); openFile(nf); odebug << "openFile string "+currentFileName << oendl; showEditTools(); // Show filename in caption QString name = filer; int sep = name.findRev( '/' ); if ( sep > 0 ) name = name.mid( sep+1 ); updateCaption( name ); } void TextEdit::openFile( const DocLnk &f ) { // clear(); // bFromDocView = true; FileManager fm; QString txt; currentFileName=f.file(); odebug << "openFile doclnk " + currentFileName << oendl; if ( !fm.loadFile( f, txt ) ) { // ####### could be a new file odebug << "Cannot open file" << oendl; } // fileNew(); if ( doc ) delete doc; doc = new DocLnk(f); editor->setText(txt); editor->setEdited( false); edited1=false; edited=false; doc->setName(currentFileName); updateCaption(); setTimer(); } void TextEdit::showEditTools() { menu->show(); editBar->show(); if(!useSearchBar) searchBar->hide(); else searchBar->show(); setWState (WState_Reserved1 ); } /*! unprompted save */ bool TextEdit::save() { - QString name, file; + QString name, file; odebug << "saveAsFile " + currentFileName << oendl; if(currentFileName.isEmpty()) { saveAs(); return false; } - name = currentFileName; - if(doc) { - file = doc->file(); - odebug << "saver file "+file << oendl; - name = doc->name(); - odebug << "File named "+name << oendl; - } else { - file = currentFileName; + if(doc) { + file = doc->file(); + odebug << "saver file "+file << oendl; + name = doc->name(); + odebug << "File named "+name << oendl; + } else { + file = currentFileName; name = QFileInfo(currentFileName).baseName(); - } + } QString rt = editor->text(); if( !rt.isEmpty() ) { if(name.isEmpty()) { saveAs(); } else { currentFileName = name; odebug << "saveFile "+currentFileName << oendl; struct stat buf; mode_t mode; - stat(file.latin1(), &buf); + QFile f(file); + fstat(f.handle(), &buf); mode = buf.st_mode; if(!fileIs) { doc->setName( name); FileManager fm; if ( !fm.saveFile( *doc, rt ) ) { - QMessageBox::message(tr("Text Edit"),tr("Save Failed")); + QMessageBox::message(tr("Text Edit"),tr("Save Failed")); return false; } } else { odebug << "regular save file" << oendl; - QFile f(file); - if( f.open(IO_WriteOnly)) { - QCString crt = rt.utf8(); - f.writeBlock(crt,crt.length()); - } else { - QMessageBox::message(tr("Text Edit"),tr("Write Failed")); - return false; - } - + if( f.open(IO_WriteOnly)) { + QCString crt = rt.utf8(); + f.writeBlock(crt,crt.length()); + } else { + QMessageBox::message(tr("Text Edit"),tr("Write Failed")); + return false; + } } editor->setEdited( false); edited1=false; edited=false; if(caption().left(1)=="*") - setCaption(caption().right(caption().length()-1)); - + setCaption(caption().right(caption().length()-1)); - chmod( file.latin1(), mode); + fchmod( f.handle(), mode); } return true; } return false; } /*! prompted save */ bool TextEdit::saveAs() { if(caption() == tr("Text Editor")) return false; odebug << "saveAsFile " + currentFileName << oendl; QString rt = editor->text(); odebug << currentFileName << oendl; if( currentFileName.isEmpty() || currentFileName == tr("Unnamed") || currentFileName == tr("Text Editor")) { odebug << "do silly TT filename thing" << oendl; QString pt = rt.simplifyWhiteSpace(); int i = pt.find( ' ' ); QString docname = pt; if ( i > 0 ) docname = pt.left( i ); while( docname.startsWith( "." ) ) docname = docname.mid( 1 ); docname.replace( QRegExp("/"), "_" ); // Cut the length. Filenames longer than 40 are not helpful // and something goes wrong when they get too long. if ( docname.length() > 40 ) docname = docname.left(40); if ( docname.isEmpty() ) docname = tr("Unnamed"); if(doc) doc->setName(docname); currentFileName=docname; } QMap<QString, QStringList> map; map.insert(tr("All"), QStringList() ); QStringList text; text << "text/*"; map.insert(tr("Text"), text ); text << "*"; map.insert(tr("All"), text ); QFileInfo cuFi( currentFileName); QString filee = cuFi.fileName(); QString dire = cuFi.dirPath(); if(dire==".") dire = QPEApplication::documentDir(); QString str; if( !featureAutoSave) { str = OFileDialog::getSaveFileName( 2, dire, filee, map); } else str = currentFileName; if(!str.isEmpty()) { QString fileNm=str; odebug << "saving filename "+fileNm << oendl; QFileInfo fi(fileNm); currentFileName=fi.fileName(); if(doc) delete doc; DocLnk nf; nf.setType("text/plain"); nf.setFile( fileNm); doc = new DocLnk(nf); odebug << "Saving file as "+currentFileName << oendl; doc->setName( fi.baseName() ); updateCaption( currentFileName); FileManager fm; if ( !fm.saveFile( *doc, rt ) ) { QMessageBox::message(tr("Text Edit"),tr("Save Failed")); return false; } if( filePerms ) { filePermissions *filePerm; filePerm = new filePermissions(this, tr("Permissions"),true, 0, (const QString &)fileNm); QPEApplication::execDialog( filePerm ); delete filePerm; } editor->setEdited( false); edited1 = false; edited = false; if(caption().left(1)=="*") setCaption(caption().right(caption().length()-1)); return true; } odebug << "returning false" << oendl; currentFileName = ""; return false; } //end saveAs void TextEdit::clear() { delete doc; doc = 0; editor->clear(); } void TextEdit::updateCaption( const QString &name ) { if ( name.isEmpty() ) setCaption( tr("Text Editor") ); else { QString s = name; if ( s.isNull() ) s = doc->name(); if ( s.isEmpty() ) { s = tr( "Unnamed" ); currentFileName=s; } // if(s.left(1) == "/") // s = s.right(s.length()-1); setCaption( tr("%1 - Text Editor").arg( s ) ); } } void TextEdit::setDocument(const QString& fileref) { if(fileref != "Unnamed") { currentFileName=fileref; odebug << "setDocument" << oendl; QFileInfo fi(currentFileName); odebug << "basename:"+fi.baseName()+": current filenmame "+currentFileName << oendl; if( (fi.baseName().left(1)).isEmpty() ) { openDotFile(currentFileName); } else { odebug << "setDoc open" << oendl; bFromDocView = true; openFile(fileref); editor->setEdited(true); edited1=false; edited=true; // fromSetDocument=false; // doSearchBar(); } } updateCaption( currentFileName); } void TextEdit::changeFont() { QDialog *d = new QDialog ( this, "FontDialog", true ); d-> setCaption ( tr( "Choose font" )); QBoxLayout *lay = new QVBoxLayout ( d ); OFontSelector *ofs = new OFontSelector ( true, d ); lay-> addWidget ( ofs ); ofs-> setSelectedFont ( editor-> font ( )); if ( QPEApplication::execDialog( d ) == QDialog::Accepted ) editor-> setFont ( ofs-> selectedFont ( )); delete d; } void TextEdit::editDelete() { switch ( QMessageBox::warning(this,tr("Text Editor"), tr("Do you really want<BR>to <B>delete</B> " "the current file\nfrom the disk?<BR>This is " "<B>irreversable!</B>"), tr("Yes"),tr("No"),0,0,1) ) { case 0: if(doc) { doc->removeFiles(); clear(); setCaption( tr("Text Editor") ); } break; case 1: // exit break; }; } void TextEdit::changeStartConfig( bool b ) { startWithNew=b; Config cfg("TextEdit"); cfg.setGroup("View"); cfg.writeEntry("startNew",b); update(); } void TextEdit::editorChanged() { // odebug << "editor changed" << oendl; if( /*editor->edited() &&*/ /*edited && */!edited1) { setCaption( "*"+caption()); edited1=true; } edited=true; } void TextEdit::receive(const QCString&msg, const QByteArray &) { odebug << "QCop "+msg << oendl; if ( msg == "setDocument(QString)" ) { odebug << "bugger all" << oendl; } } void TextEdit::doAbout() { QMessageBox::about(0,tr("Text Edit"),tr("Text Edit is copyright<BR>" "2000 Trolltech AS, and<BR>" "2002 by <B>L. J. Potter <BR>llornkcor@handhelds.org</B><BR>" "and is licensed under the GPL")); } void TextEdit::doPrompt(bool b) { promptExit=b; Config cfg("TextEdit"); cfg.setGroup ( "View" ); cfg.writeEntry ( "PromptExit", b); } void TextEdit::doDesktop(bool b) { openDesktop=b; Config cfg("TextEdit"); cfg.setGroup ( "View" ); cfg.writeEntry ( "OpenDesktop", b); } void TextEdit::doFilePerms(bool b) { filePerms=b; Config cfg("TextEdit"); cfg.setGroup ( "View" ); cfg.writeEntry ( "FilePermissions", b); } void TextEdit::editPasteTimeDate() { #ifndef QT_NO_CLIPBOARD QClipboard *cb = QApplication::clipboard(); QDateTime dt = QDateTime::currentDateTime(); cb->setText( dt.toString()); editor->paste(); #endif } int TextEdit::savePrompt() { switch( QMessageBox::information( 0, (tr("Textedit")), (tr("Textedit detected\n" "you have unsaved changes\n" "Go ahead and save?\n")), (tr("Save")), (tr("Don't Save")), (tr("&Cancel")), 2, 2 ) ) { case 0: { return 1; } break; case 1: { return 2; } break; case 2: { return -1; } break; }; return 0; } void TextEdit::timerCrank() { if(featureAutoSave && edited1) { if(currentFileName.isEmpty()) { currentFileName = QDir::homeDirPath()+"/textedit.tmp"; saveAs(); } else { // odebug << "autosave" << oendl; save(); } setTimer(); } } void TextEdit::doTimer(bool b) { Config cfg("TextEdit"); cfg.setGroup ( "View" ); cfg.writeEntry ( "autosave", b); featureAutoSave = b; nAutoSave->setOn(b); if(b) { // odebug << "doTimer true" << oendl; setTimer(); } // else // odebug << "doTimer false" << oendl; } void TextEdit::setTimer() { if(featureAutoSave) { // odebug << "setting autosave" << oendl; QTimer *timer = new QTimer(this ); connect( timer, SIGNAL(timeout()), this, SLOT(timerCrank()) ); timer->start( 300000, true); //5 minutes } } void TextEdit::gotoLine() { if( editor->length() < 1) return; QWidget *d = QApplication::desktop(); gotoEdit = new QLineEdit( 0, "Goto line"); gotoEdit->move( (d->width()/2) - ( gotoEdit->width()/2) , (d->height()/2) - (gotoEdit->height()/2)); gotoEdit->setFrame(true); gotoEdit->show(); connect (gotoEdit,SIGNAL(returnPressed()), this, SLOT(doGoto())); } void TextEdit::doGoto() { QString number = gotoEdit->text(); gotoEdit->hide(); delete gotoEdit; gotoEdit = 0; bool ok; int lineNumber = number.toInt(&ok, 10); if( editor->numLines() < lineNumber) QMessageBox::message(tr("Text Edit"),tr("Not enough lines")); else { editor->setCursorPosition(lineNumber, 0, false); } } diff --git a/core/launcher/packageslave.cpp b/core/launcher/packageslave.cpp index abbc610..965020e 100644 --- a/core/launcher/packageslave.cpp +++ b/core/launcher/packageslave.cpp @@ -1,348 +1,356 @@ /********************************************************************** ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** ** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #include "packageslave.h" /* OPIE */ #include <opie2/odebug.h> #include <qtopia/qprocess.h> #ifdef Q_WS_QWS #include <qtopia/qcopenvelope_qws.h> #endif using namespace Opie::Core; /* QT */ #ifdef Q_WS_QWS #include <qcopchannel_qws.h> #endif #include <qtextstream.h> /* STD */ #include <stdlib.h> #include <sys/stat.h> // mkdir() #if defined(_OS_LINUX_) || defined(Q_OS_LINUX) #include <unistd.h> #include <sys/vfs.h> #include <mntent.h> #elif defined(Q_OS_MACX) #include <unistd.h> #endif PackageHandler::PackageHandler( QObject *parent, char* name ) : QObject( parent, name ), packageChannel( 0 ), currentProcess( 0 ), mNoSpaceLeft( FALSE ) { // setup qcop channel #ifndef QT_NO_COP packageChannel = new QCopChannel( "QPE/Package", this ); connect( packageChannel, SIGNAL( received(const QCString&,const QByteArray&) ), this, SLOT( qcopMessage(const QCString&,const QByteArray&) ) ); #endif } void PackageHandler::qcopMessage( const QCString &msg, const QByteArray &data ) { QDataStream stream( data, IO_ReadOnly ); if ( msg == "installPackage(QString)" ) { QString file; stream >> file; installPackage( file ); } else if ( msg == "installPackage(QString,QString)" ) { QString file, dest; stream >> file >> dest; installPackage( file, dest ); } else if ( msg == "removePackage(QString)" ) { QString file; stream >> file; removePackage( file ); } else if ( msg == "addPackageFiles(QString,QString)" ) { QString location, listfile; stream >> location >> listfile; addPackageFiles( location, listfile); } else if ( msg == "addPackages(QString)" ) { QString location; stream >> location; addPackages( location ); } else if ( msg == "cleanupPackageFiles(QString)" ) { QString listfile; stream >> listfile; cleanupPackageFiles( listfile ); } else if ( msg == "cleanupPackages(QString)" ) { QString location; stream >> location; cleanupPackages( location ); } else if ( msg == "prepareInstall(QString,QString)" ) { QString size, path; stream >> size; stream >> path; prepareInstall( size, path ); } } void PackageHandler::installPackage( const QString &package, const QString &dest ) { if ( mNoSpaceLeft ) { mNoSpaceLeft = FALSE; // Don't emit that for now, I still couldn't test it (Wener) //sendReply( "installFailed(QString)", package ); //return; } QStringList cmd; cmd << "ipkg"; if ( !dest.isEmpty() ) { cmd << "-d" << dest; } cmd << "install" << package; currentProcess = new QProcess( cmd ); // No tr connect( currentProcess, SIGNAL( processExited() ), SLOT( iProcessExited() ) ); connect( currentProcess, SIGNAL( readyReadStdout() ), SLOT( readyReadStdout() ) ); connect( currentProcess, SIGNAL( readyReadStderr() ), SLOT( readyReadStderr() ) ); currentPackage = package; currentProcessError=""; sendReply( "installStarted(QString)", package ); currentProcess->start(); } void PackageHandler::removePackage( const QString &package ) { currentProcess = new QProcess( QStringList() << "ipkg" << "remove" << package ); // No tr connect( currentProcess, SIGNAL( processExited() ), SLOT( rmProcessExited() ) ); connect( currentProcess, SIGNAL( readyReadStdout() ), SLOT( readyReadStdout() ) ); connect( currentProcess, SIGNAL( readyReadStderr() ), SLOT( readyReadStderr() ) ); currentPackage = package; currentProcessError=""; sendReply( "removeStarted(QString)", package ); currentProcess->start(); } void PackageHandler::sendReply( const QCString& msg, const QString& arg ) { #ifndef QT_NO_COP QCopEnvelope e( "QPE/Desktop", msg ); e << arg; #endif } void PackageHandler::addPackageFiles( const QString &location, const QString &listfile ) { QFile f(listfile); #ifndef Q_OS_WIN32 //make a copy so we can remove the symlinks later mkdir( ("/usr/lib/ipkg/info/"+location).ascii(), 0777 ); system(("cp " + f.name() + " /usr/lib/ipkg/info/"+location).ascii()); #else QDir d; //#### revise odebug << "Copy file at " << __FILE__ << ": " << __LINE__ << "" << oendl; d.mkdir(("/usr/lib/ipkg/info/" + location).ascii()); system(("copy " + f.name() + " /usr/lib/ipkg/info/"+location).ascii()); #endif if ( f.open(IO_ReadOnly) ) { QTextStream ts(&f); QString s; while ( !ts.eof() ) { // until end of file... s = ts.readLine(); // line of text excluding '\n' // for s, do link/mkdir. if ( s.right(1) == "/" ) { odebug << "do mkdir for " << s.ascii() << "" << oendl; #ifndef Q_OS_WIN32 mkdir( s.ascii(), 0777 ); //possible optimization: symlink directories //that don't exist already. -- Risky. #else d.mkdir( s.ascii()); #endif } else { #ifndef Q_OS_WIN32 odebug << "do symlink for " << s.ascii() << "" << oendl; symlink( (location + s).ascii(), s.ascii() ); #else odebug << "Copy file instead of a symlink for WIN32" << oendl; if (!CopyFile((TCHAR*)qt_winTchar((location + s), TRUE), (TCHAR*)qt_winTchar(s, TRUE), FALSE)) owarn << "Unable to create symlinkfor " << (location + s).ascii() << oendl; #endif } } f.close(); } } void PackageHandler::addPackages( const QString &location ) { // get list of *.list in location/usr/lib/ipkg/info/*.list QDir dir(location + "/usr/lib/ipkg/info", "*.list", // No tr QDir::Name, QDir::Files); if ( !dir.exists() ) return; QStringList packages = dir.entryList(); for ( QStringList::Iterator it = packages.begin(); it != packages.end(); ++it ) { addPackageFiles( location, *it ); } } void PackageHandler::cleanupPackageFiles( const QString &listfile ) { QFile f(listfile); if ( f.open(IO_ReadOnly) ) { - QTextStream ts(&f); - - QString s; - while ( !ts.eof() ) { // until end of file... - s = ts.readLine(); // line of text excluding '\n' - // for s, do link/mkdir. - if ( s.right(1) == "/" ) { - //should rmdir if empty, after all files have been removed - } else { + QTextStream ts(&f); + + QString s; + while ( !ts.eof() ) { // until end of file... + s = ts.readLine(); // line of text excluding '\n' + // for s, do link/mkdir. + // @todo Right now we just move on if the name of the file we + // find is actually a directory. What we ought to do is check + // to see if the directory is empty and if so remove it. + if ( s.right(1) != "/" ) { #ifndef Q_OS_WIN32 - odebug << "remove symlink for " << s.ascii() << "" << oendl; - //check if it is a symlink first (don't remove /etc/passwd...) - char buf[10]; //we don't care about the contents - if ( ::readlink( s.ascii(),buf, 10 >= 0 ) ) - ::unlink( s.ascii() ); + odebug << "remove symlink for " << s << oendl; + QFile symFile(s); + QFileInfo symFileInfo(symFile); + //check if it is a symlink first (don't remove /etc/passwd...) + if ( !symFileInfo.readLink().isNull()) + if (!symFile.remove()) + owarn << "Unable to remove symlink " << symFile.name() + << " " << __FILE__ << ":" << __LINE__ << oendl; #else - // ### revise - owarn << "Unable to remove symlink " << __FILE__ << ":" << __LINE__ << "" << oendl; + // @todo If we actually want to be portable to other operating + // systems we ought to at least have a portable way of removing + // their notion of symlinks. + owarn << "Unable to remove symlink " << s " " << __FILE__ + << ":" << __LINE__ << oendl; #endif + } } - } - f.close(); + f.close(); //remove the list file - ::unlink( listfile.ascii() ); - + if (!f.remove()) + owarn << "Unable to remove list file " << f.name() << " " + << __FILE__ << ":" << __LINE__ << oendl; } } void PackageHandler::cleanupPackages( const QString &location ) { // get list of *.list in location/usr/lib/ipkg/info/*.list QDir dir( "/usr/lib/ipkg/info/"+location, "*.list", // No tr QDir::Name, QDir::Files); if ( !dir.exists() ) return; QStringList packages = dir.entryList(); for ( QStringList::Iterator it = packages.begin(); it != packages.end(); ++it ) { cleanupPackageFiles( *it ); } //remove the backup directory //### } void PackageHandler::prepareInstall( const QString& size, const QString& path ) { // Check whether there will be enough space to install the next package. bool ok; unsigned int s = size.toUInt( &ok ); if ( !ok ) return; // Shamelessly stolen from the sysinfo application (Werner) #if defined(_OS_LINUX_) || defined(Q_OS_LINUX) struct statfs fs; if ( statfs( path.latin1(), &fs ) == 0 ) if ( s > fs.f_bsize * fs.f_bavail ) { //odebug << "############### Not enough space left ###############" << oendl; mNoSpaceLeft = TRUE; } #endif } void PackageHandler::iProcessExited() { if ( currentProcess->normalExit() && currentProcess->exitStatus() == 0 ) sendReply( "installDone(QString)", currentPackage ); else { #ifndef QT_NO_COP QCopEnvelope e( "QPE/Desktop", "installFailed(QString,int,QString)" ); e << currentPackage << currentProcess->exitStatus() << currentProcessError; #endif } delete currentProcess; currentProcess = 0; #ifndef QT_NO_COP QCopEnvelope e("QPE/System", "linkChanged(QString)"); QString lf = QString::null; e << lf; #endif unlink( currentPackage ); } void PackageHandler::rmProcessExited() { if ( currentProcess->normalExit() && currentProcess->exitStatus() == 0 ) sendReply( "removeDone(QString)", currentPackage ); else sendReply( "removeFailed(QString)", currentPackage ); #ifndef QT_NO_COP QCopEnvelope e("QPE/System", "linkChanged(QString)"); QString lf = QString::null; e << lf; #endif } void PackageHandler::readyReadStdout() { while ( currentProcess->canReadLineStdout() ) { QString line = currentProcess->readLineStdout(); currentProcessError.append("OUT:"+line); if ( line.contains( "Unpacking" ) ) // No tr sendReply( "installStep(QString)", "one" ); // No tr else if ( line.contains( "Configuring" ) ) // No tr sendReply( "installStep(QString)", "two" ); // No tr } } void PackageHandler::readyReadStderr() { while ( currentProcess->canReadLineStderr() ) { QString line = currentProcess->readLineStderr(); currentProcessError.append("ERR:"+line); } } void PackageHandler::redoPackages() { //get list of filesystems //call cleanupPackages for the ones that have disappeared //call addPackageFiles for the new ones } |