00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "editorwatcher.h"
00020
00021 #include <config.h>
00022
00023 #include <kdebug.h>
00024 #include <klocale.h>
00025 #include <kmessagebox.h>
00026 #include <kopenwith.h>
00027 #include <kprocess.h>
00028 #include <kuserprofile.h>
00029
00030 #include <qsocketnotifier.h>
00031
00032 #include <cassert>
00033
00034
00035 #ifdef HAVE_INOTIFY
00036 #include <sys/ioctl.h>
00037 #include <unistd.h>
00038 #include <fcntl.h>
00039 #include <sys/syscall.h>
00040 #include <sys/inotify.h>
00041 #endif
00042
00043 using namespace KMail;
00044
00045 EditorWatcher::EditorWatcher(const KURL & url, const QString &mimeType, bool openWith, QObject * parent) :
00046 QObject( parent ),
00047 mUrl( url ),
00048 mMimeType( mimeType ),
00049 mOpenWith( openWith ),
00050 mEditor( 0 ),
00051 mHaveInotify( false ),
00052 mFileOpen( false ),
00053 mEditorRunning( false ),
00054 mFileModified( true ),
00055 mDone( false )
00056 {
00057 assert( mUrl.isLocalFile() );
00058 connect( &mTimer, SIGNAL(timeout()), SLOT(checkEditDone()) );
00059 }
00060
00061 bool EditorWatcher::start()
00062 {
00063
00064 KURL::List list;
00065 list.append( mUrl );
00066 KService::Ptr offer = KServiceTypeProfile::preferredService( mMimeType, "Application" );
00067 if ( mOpenWith || !offer ) {
00068 KOpenWithDlg dlg( list, i18n("Edit with:"), QString::null, 0 );
00069 if ( !dlg.exec() )
00070 return false;
00071 offer = dlg.service();
00072 if ( !offer )
00073 return false;
00074 }
00075
00076 #ifdef HAVE_INOTIFY
00077
00078 mInotifyFd = inotify_init();
00079 if ( mInotifyFd > 0 ) {
00080 mInotifyWatch = inotify_add_watch( mInotifyFd, mUrl.path().latin1(), IN_CLOSE | IN_OPEN | IN_MODIFY );
00081 if ( mInotifyWatch >= 0 ) {
00082 QSocketNotifier *sn = new QSocketNotifier( mInotifyFd, QSocketNotifier::Read, this );
00083 connect( sn, SIGNAL(activated(int)), SLOT(inotifyEvent()) );
00084 mHaveInotify = true;
00085 mFileModified = false;
00086 }
00087 } else {
00088 kdWarning(5006) << k_funcinfo << "Failed to activate INOTIFY!" << endl;
00089 }
00090 #endif
00091
00092
00093 QStringList params = KRun::processDesktopExec( *offer, list, false );
00094 mEditor = new KProcess( this );
00095 *mEditor << params;
00096 connect( mEditor, SIGNAL(processExited(KProcess*)), SLOT(editorExited()) );
00097 if ( !mEditor->start() )
00098 return false;
00099 mEditorRunning = true;
00100
00101 mEditTime.start();
00102 return true;
00103 }
00104
00105 void EditorWatcher::inotifyEvent()
00106 {
00107 assert( mHaveInotify );
00108 #ifdef HAVE_INOTIFY
00109 int pending = -1;
00110 char buffer[4096];
00111 ioctl( mInotifyFd, FIONREAD, &pending );
00112 while ( pending > 0 ) {
00113 int size = read( mInotifyFd, buffer, QMIN( pending, (int)sizeof(buffer) ) );
00114 pending -= size;
00115 if ( size < 0 )
00116 break;
00117 int offset = 0;
00118 while ( size > 0 ) {
00119 struct inotify_event *event = (struct inotify_event *) &buffer[offset];
00120 size -= sizeof( struct inotify_event ) + event->len;
00121 offset += sizeof( struct inotify_event ) + event->len;
00122 if ( event->mask & IN_OPEN )
00123 mFileOpen = true;
00124 if ( event->mask & IN_CLOSE )
00125 mFileOpen = false;
00126 if ( event->mask & IN_MODIFY )
00127 mFileModified = true;
00128 }
00129 }
00130 #endif
00131 mTimer.start( 500, true );
00132
00133 }
00134
00135 void EditorWatcher::editorExited()
00136 {
00137 mEditorRunning = false;
00138 mTimer.start( 500, true );
00139 }
00140
00141 void EditorWatcher::checkEditDone()
00142 {
00143 if ( mEditorRunning || (mFileOpen && mHaveInotify) || mDone )
00144 return;
00145
00146
00147 mDone = true;
00148
00149
00150 if ( mEditTime.elapsed() <= 3000 ) {
00151 KMessageBox::error( 0, i18n("KMail is unable to detect when the choosen editor is closed. "
00152 "To avoid data loss, editing the attachment will be aborted."), i18n("Unable to edit attachment") );
00153 }
00154
00155 emit editDone( this );
00156 deleteLater();
00157 }
00158
00159 #include "editorwatcher.moc"