/* Copyright (C) 2013 - 2014 Hong Jen Yee (PCMan) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "mountoperation.h" #include // for _() #include #include #include #include "mountoperationpassworddialog_p.h" #include "mountoperationquestiondialog_p.h" #include "ui_mount-operation-password.h" namespace Fm { MountOperation::MountOperation(bool interactive, QWidget* parent): QObject(parent), interactive_(interactive), running(false), op(g_mount_operation_new()), cancellable_(g_cancellable_new()), eventLoop(NULL), autoDestroy_(true) { g_signal_connect(op, "ask-password", G_CALLBACK(onAskPassword), this); g_signal_connect(op, "ask-question", G_CALLBACK(onAskQuestion), this); // g_signal_connect(op, "reply", G_CALLBACK(onReply), this); #if GLIB_CHECK_VERSION(2, 20, 0) g_signal_connect(op, "aborted", G_CALLBACK(onAbort), this); #endif #if GLIB_CHECK_VERSION(2, 22, 0) g_signal_connect(op, "show-processes", G_CALLBACK(onShowProcesses), this); #endif #if GLIB_CHECK_VERSION(2, 34, 0) g_signal_connect(op, "show-unmount-progress", G_CALLBACK(onShowUnmountProgress), this); #endif } MountOperation::~MountOperation() { qDebug("delete MountOperation"); if(cancellable_) { cancel(); g_object_unref(cancellable_); } if(eventLoop) { // if wait() is called to block the main loop, but the event loop is still running // NOTE: is this possible? eventLoop->exit(1); } if(op) { g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onAskPassword), this); g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onAskQuestion), this); #if GLIB_CHECK_VERSION(2, 20, 0) g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onAbort), this); #endif #if GLIB_CHECK_VERSION(2, 22, 0) g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onShowProcesses), this); #endif #if GLIB_CHECK_VERSION(2, 34, 0) g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onShowUnmountProgress), this); #endif g_object_unref(op); } // qDebug("MountOperation deleted"); } void MountOperation::onAbort(GMountOperation* _op, MountOperation* pThis) { } void MountOperation::onAskPassword(GMountOperation* _op, gchar* message, gchar* default_user, gchar* default_domain, GAskPasswordFlags flags, MountOperation* pThis) { qDebug("ask password"); MountOperationPasswordDialog dlg(pThis, flags); dlg.setMessage(QString::fromUtf8(message)); dlg.setDefaultUser(QString::fromUtf8(default_user)); dlg.setDefaultDomain(QString::fromUtf8(default_domain)); dlg.exec(); } void MountOperation::onAskQuestion(GMountOperation* _op, gchar* message, GStrv choices, MountOperation* pThis) { qDebug("ask question"); MountOperationQuestionDialog dialog(pThis, message, choices); dialog.exec(); } /* void MountOperation::onReply(GMountOperation* _op, GMountOperationResult result, MountOperation* pThis) { qDebug("reply"); } */ void MountOperation::onShowProcesses(GMountOperation* _op, gchar* message, GArray* processes, GStrv choices, MountOperation* pThis) { qDebug("show processes"); } void MountOperation::onShowUnmountProgress(GMountOperation* _op, gchar* message, gint64 time_left, gint64 bytes_left, MountOperation* pThis) { qDebug("show unmount progress"); } void MountOperation::onEjectMountFinished(GMount* mount, GAsyncResult* res, QPointer< MountOperation >* pThis) { if(*pThis) { GError* error = NULL; g_mount_eject_with_operation_finish(mount, res, &error); (*pThis)->handleFinish(error); } delete pThis; } void MountOperation::onEjectVolumeFinished(GVolume* volume, GAsyncResult* res, QPointer< MountOperation >* pThis) { if(*pThis) { GError* error = NULL; g_volume_eject_with_operation_finish(volume, res, &error); (*pThis)->handleFinish(error); } delete pThis; } void MountOperation::onMountFileFinished(GFile* file, GAsyncResult* res, QPointer< MountOperation >* pThis) { if(*pThis) { GError* error = NULL; g_file_mount_enclosing_volume_finish(file, res, &error); (*pThis)->handleFinish(error); } delete pThis; } void MountOperation::onMountVolumeFinished(GVolume* volume, GAsyncResult* res, QPointer< MountOperation >* pThis) { if(*pThis) { GError* error = NULL; g_volume_mount_finish(volume, res, &error); (*pThis)->handleFinish(error); } delete pThis; } void MountOperation::onUnmountMountFinished(GMount* mount, GAsyncResult* res, QPointer< MountOperation >* pThis) { if(*pThis) { GError* error = NULL; g_mount_unmount_with_operation_finish(mount, res, &error); (*pThis)->handleFinish(error); } delete pThis; } void MountOperation::handleFinish(GError* error) { qDebug("operation finished: %p", error); if(error) { bool showError = interactive_; if(error->domain == G_IO_ERROR) { if(error->code == G_IO_ERROR_FAILED) { // Generate a more human-readable error message instead of using a gvfs one. // The original error message is something like: // Error unmounting: umount exited with exit code 1: // helper failed with: umount: only root can unmount // UUID=18cbf00c-e65f-445a-bccc-11964bdea05d from /media/sda4 */ // Why they pass this back to us? This is not human-readable for the users at all. if(strstr(error->message, "only root can ")) { g_free(error->message); error->message = g_strdup(_("Only system administrators have the permission to do this.")); } } else if(error->code == G_IO_ERROR_FAILED_HANDLED) showError = false; } if(showError) QMessageBox::critical(NULL, QObject::tr("Error"), QString::fromUtf8(error->message)); } Q_EMIT finished(error); if(eventLoop) { // if wait() is called to block the main loop eventLoop->exit(error != NULL ? 1 : 0); eventLoop = NULL; } if(error) g_error_free(error); // free ourself here!! if(autoDestroy_) deleteLater(); } void MountOperation::prepareUnmount(GMount* mount) { /* ensure that CWD is not on the mounted filesystem. */ char* cwd_str = g_get_current_dir(); GFile* cwd = g_file_new_for_path(cwd_str); GFile* root = g_mount_get_root(mount); g_free(cwd_str); /* FIXME: This cannot cover 100% cases since symlinks are not checked. * There may be other cases that cwd is actually under mount root * but checking prefix is not enough. We already did our best, though. */ if(g_file_has_prefix(cwd, root)) g_chdir("/"); g_object_unref(cwd); g_object_unref(root); } // block the operation used an internal QEventLoop and returns // only after the whole operation is finished. bool MountOperation::wait() { QEventLoop loop; eventLoop = &loop; int exitCode = loop.exec(); return exitCode == 0 ? true : false; } } // namespace Fm