/* This file is part of the KDE project Copyright (c) 2004 Kévin Ottens Parts of this file are Copyright 2003 Waldo Bastian This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __TDE_HAVE_TDEHWLIB #include #endif #include "dialog.h" #include "tdeio_media_mounthelper.h" const Medium MountHelper::findMedium(const KURL &url) { DCOPRef mediamanager("kded", "mediamanager"); // Try filename first DCOPReply reply = mediamanager.call( "properties", url.fileName() ); if ( !reply.isValid() ) { m_errorStr = i18n("The TDE mediamanager is not running.")+"\n"; return Medium(TQString::null, TQString::null, TQString::null); } const Medium& medium = Medium::create(reply); if ( medium.id().isEmpty() ) { // Try full URL now reply = mediamanager.call( "properties", url.prettyURL() ); if ( !reply.isValid() ) { m_errorStr = i18n("Internal Error"); return Medium(TQString::null, TQString::null, TQString::null); } return Medium::create(reply); } else { return medium; } } MountHelper::MountHelper() : TDEApplication() { TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); m_errorStr = TQString::null; KURL url(args->url(0)); const Medium medium = findMedium(url); if (medium.id().isEmpty()) { if (m_errorStr.isEmpty()) { m_errorStr+= i18n("%1 cannot be found.").arg(url.prettyURL()); } TQTimer::singleShot(0, this, TQT_SLOT(error()) ); return; } if (!medium.isMountable() && !args->isSet("e") && !args->isSet("s")) { m_errorStr = i18n("%1 is not a mountable media.").arg(url.prettyURL()); TQTimer::singleShot(0, this, TQT_SLOT(error()) ); return; } TQString device = medium.deviceNode(); TQString mount_point = medium.mountPoint(); m_isCdrom = medium.mimeType().find("dvd") != -1 || medium.mimeType().find("cd") != -1; if (args->isSet("d")) { if (!medium.isEncrypted()) { m_errorStr = i18n("%1 is not an encrypted media.").arg(url.prettyURL()); TQTimer::singleShot(0, this, TQT_SLOT(error()) ); return; } if (!medium.needDecryption()) { m_errorStr = i18n("%1 is already unlocked.").arg(url.prettyURL()); TQTimer::singleShot(0, this, TQT_SLOT(error())); return; } TQString iconName = medium.iconName(); if (iconName.isEmpty()) { TQString mime = medium.mimeType(); iconName = KMimeType::mimeType(mime)->icon(mime, false); } m_mediumId = medium.id(); dialog = new Dialog(url.prettyURL(), iconName); dialog->show(); connect(dialog, TQT_SIGNAL (user1Clicked()), this, TQT_SLOT (slotSendPassword())); connect(dialog, TQT_SIGNAL (cancelClicked()), this, TQT_SLOT (slotCancel())); connect(this, TQT_SIGNAL (signalPasswordError(TQString)), dialog, TQT_SLOT (slotDialogError(TQString))); } else if (args->isSet("u")) { DCOPRef mediamanager("kded", "mediamanager"); DCOPReply reply = mediamanager.call("unmount", medium.id()); TQStringVariantMap unmountResult; if (reply.isValid()) { reply.get(unmountResult); } if (unmountResult.contains("result") && unmountResult["result"].toBool()) { ::exit(0); } else { m_errorStr = unmountResult.contains("errStr") ? unmountResult["errStr"].toString() : i18n("Unknown unmount error."); kdDebug() << "medium unmount " << m_errorStr << endl; error(); } } else if (args->isSet("s") || args->isSet("e")) { DCOPRef mediamanager("kded", "mediamanager"); /* * We want to call mediamanager unmount before invoking eject. That's * because unmount would provide an informative error message in case of * failure. However, there are cases when unmount would fail * (supermount, slackware, see bug#116209) but eject would succeed. * Thus if unmount fails, save unmount error message and invokeEject() * anyway. Only if both unmount and eject fail, notify the user by * displaying the saved error message (see ejectFinished()). */ if (medium.isMounted()) { DCOPReply reply = mediamanager.call( "unmount", medium.id()); if (reply.isValid()) { TQStringVariantMap unmountResult; reply.get(unmountResult); if (unmountResult["result"].toBool()) { reply.get(m_errorStr); } } } // If this is an unlocked encrypted volume and there is no error yet, we try to lock it if (unmountResult.contains("result") && unmountResult["result"].toBool() && medium.isEncrypted() && !medium.clearDeviceUdi().isNull()) { DCOPReply reply = mediamanager.call( "undecrypt", medium.id()); if (reply.isValid()) { TQStringVariantMap undecryptResult; reply.get(undecryptResult); if (undecryptResult["result"].toBool()) { reply.get(m_errorStr); } } } if (m_errorStr.isNull()) { invokeEject(device, true); } else { error(); } } else { DCOPRef mediamanager("kded", "mediamanager"); DCOPReply reply = mediamanager.call("mount", medium.id()); TQStringVariantMap mountResult; if (reply.isValid()) { reply.get(mountResult); } if (mountResult.contains("result") && mountResult["result"].toBool()) { ::exit(0); } else { m_errorStr = mountResult.contains("errStr") ? mountResult["errStr"].toString() : i18n("Unknown mount error."); error(); } } } void MountHelper::invokeEject(const TQString &device, bool quiet) { #ifdef __TDE_HAVE_TDEHWLIB // Try TDE HW library eject first... TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices(); TDEGenericDevice *hwdevice = hwdevices->findByDeviceNode(device); if (hwdevice->type() == TDEGenericDeviceType::Disk) { TDEStorageDevice* sdevice = static_cast(hwdevice); if (sdevice->ejectDrive()) { // Success! ::exit(0); } } #endif // Then fall back to tdeeject if needed TDEProcess *proc = new TDEProcess(TQT_TQOBJECT(this)); *proc << "tdeeject"; if (quiet) { *proc << "-q"; } *proc << device; connect( proc, TQT_SIGNAL(processExited(TDEProcess *)), this, TQT_SLOT( ejectFinished(TDEProcess *) ) ); proc->start(); } void MountHelper::ejectFinished(TDEProcess* proc) { /* * If eject failed, report the error stored in m_errorStr */ if (proc->normalExit() && proc->exitStatus() == 0) { ::exit(0); } else { if (m_errorStr.isEmpty()) { if (m_isCdrom) m_errorStr = i18n("The device was successfully unmounted, but the tray could not be opened"); else m_errorStr = i18n("The device was successfully unmounted, but could not be ejected"); } //X Comment this because the error is useless as long as the unmount is successful. //X TQTimer::singleShot(0, this, TQT_SLOT(error())); ::exit(0); } } void MountHelper::error() { TQString prettyErrorString = m_errorStr; if (m_errorStr.contains("<") && m_errorStr.contains(">")) { if (!m_errorStr.contains("")) { prettyErrorString = TQString("%1").arg(m_errorStr); } } KMessageBox::error(0, prettyErrorString); ::exit(1); } void MountHelper::slotSendPassword() { DCOPRef mediamanager("kded", "mediamanager"); DCOPReply reply = mediamanager.call( "decrypt", m_mediumId, dialog->getPassword() ); TQStringVariantMap decryptResult; if (reply.isValid()) { reply.get(decryptResult); } if (decryptResult.contains("result") && decryptResult["result"].toBool()) { ::exit(0); } else { m_errorStr = decryptResult.contains("errStr") ? decryptResult["errStr"].toString() : i18n("Unknown decrypt error."); kdDebug() << "medium decrypt " << m_errorStr << endl; emit signalPasswordError(m_errorStr); error(); } } void MountHelper::slotCancel() { exit(0); } static TDECmdLineOptions options[] = { { "d", I18N_NOOP("Decrypt given URL"), 0 }, { "u", I18N_NOOP("Unmount given URL"), 0 }, { "m", I18N_NOOP("Mount given URL (default)"), 0 }, { "e", I18N_NOOP("Eject given URL via tdeeject"), 0}, { "s", I18N_NOOP("Unmount and Eject given URL (necessary for some USB devices)"), 0}, {"!+URL", I18N_NOOP("media:/ URL to mount/unmount/eject/remove"), 0 }, TDECmdLineLastOption }; int main(int argc, char **argv) { TDECmdLineArgs::init(argc, argv, "tdeio_media_mounthelper", "tdeio_media_mounthelper", "tdeio_media_mounthelper", "0.1"); TDECmdLineArgs::addCmdLineOptions( options ); TDEGlobal::locale()->setMainCatalogue("tdeio_media"); TDEApplication::addCmdLineOptions(); if (TDECmdLineArgs::parsedArgs()->count()==0) TDECmdLineArgs::usage(); TDEApplication *app = new MountHelper(); TDEStartupInfo::appStarted(); app->dcopClient()->attach(); return app->exec(); } #include "tdeio_media_mounthelper.moc"