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 <tqsocketnotifier.h>
00031
00032 #include <cassert>
00033
00034
00035 #ifdef HAVE_SYS_INOTIFY
00036 #include <sys/ioctl.h>
00037 #include <sys/inotify.h>
00038 #include <fcntl.h>
00039 #elif HAVE_INOTIFY
00040 #include <sys/ioctl.h>
00041 #include <unistd.h>
00042 #include <sys/inotify.h>
00043 #include <sys/syscall.h>
00044 #include <linux/types.h>
00045
00046 #define _S390_BITOPS_H
00047 #endif
00048
00049 using namespace KMail;
00050
00051 EditorWatcher::EditorWatcher(const KURL & url, const TQString &mimeType, bool openWith,
00052 TQObject * parent, TQWidget *parentWidget) :
00053 TQObject( parent ),
00054 mUrl( url ),
00055 mMimeType( mimeType ),
00056 mOpenWith( openWith ),
00057 mEditor( 0 ),
00058 mParentWidget( parentWidget ),
00059 mHaveInotify( false ),
00060 mFileOpen( false ),
00061 mEditorRunning( false ),
00062 mFileModified( true ),
00063 mDone( false )
00064 {
00065 assert( mUrl.isLocalFile() );
00066 connect( &mTimer, TQT_SIGNAL(timeout()), TQT_SLOT(checkEditDone()) );
00067 }
00068
00069 bool EditorWatcher::start()
00070 {
00071
00072 KURL::List list;
00073 list.append( mUrl );
00074 KService::Ptr offer = KServiceTypeProfile::preferredService( mMimeType, "Application" );
00075 if ( mOpenWith || !offer ) {
00076 KOpenWithDlg dlg( list, i18n("Edit with:"), TQString(), 0 );
00077 if ( !dlg.exec() )
00078 return false;
00079 offer = dlg.service();
00080 if ( !offer )
00081 return false;
00082 }
00083
00084 #ifdef HAVE_INOTIFY
00085
00086 mInotifyFd = inotify_init();
00087 if ( mInotifyFd > 0 ) {
00088 mInotifyWatch = inotify_add_watch( mInotifyFd, mUrl.path().latin1(), IN_CLOSE | IN_OPEN | IN_MODIFY );
00089 if ( mInotifyWatch >= 0 ) {
00090 TQSocketNotifier *sn = new TQSocketNotifier( mInotifyFd, TQSocketNotifier::Read, this );
00091 connect( sn, TQT_SIGNAL(activated(int)), TQT_SLOT(inotifyEvent()) );
00092 mHaveInotify = true;
00093 mFileModified = false;
00094 }
00095 } else {
00096 kdWarning(5006) << k_funcinfo << "Failed to activate INOTIFY!" << endl;
00097 }
00098 #endif
00099
00100
00101 TQStringList params = KRun::processDesktopExec( *offer, list, false );
00102 mEditor = new KProcess( this );
00103 *mEditor << params;
00104 connect( mEditor, TQT_SIGNAL(processExited(KProcess*)), TQT_SLOT(editorExited()) );
00105 if ( !mEditor->start() )
00106 return false;
00107 mEditorRunning = true;
00108
00109 mEditTime.start();
00110 return true;
00111 }
00112
00113 void EditorWatcher::inotifyEvent()
00114 {
00115 assert( mHaveInotify );
00116 #ifdef HAVE_INOTIFY
00117 int pending = -1;
00118 char buffer[4096];
00119 ioctl( mInotifyFd, FIONREAD, &pending );
00120 while ( pending > 0 ) {
00121 int size = read( mInotifyFd, buffer, TQMIN( pending, (int)sizeof(buffer) ) );
00122 pending -= size;
00123 if ( size < 0 )
00124 break;
00125 int offset = 0;
00126 while ( size > 0 ) {
00127 struct inotify_event *event = (struct inotify_event *) &buffer[offset];
00128 size -= sizeof( struct inotify_event ) + event->len;
00129 offset += sizeof( struct inotify_event ) + event->len;
00130 if ( event->mask & IN_OPEN )
00131 mFileOpen = true;
00132 if ( event->mask & IN_CLOSE )
00133 mFileOpen = false;
00134 if ( event->mask & IN_MODIFY )
00135 mFileModified = true;
00136 }
00137 }
00138 #endif
00139 mTimer.start( 500, true );
00140
00141 }
00142
00143 void EditorWatcher::editorExited()
00144 {
00145 mEditorRunning = false;
00146 mTimer.start( 500, true );
00147 }
00148
00149 void EditorWatcher::checkEditDone()
00150 {
00151 if ( mEditorRunning || (mFileOpen && mHaveInotify) || mDone )
00152 return;
00153
00154
00155 mDone = true;
00156
00157
00158 if ( mEditTime.elapsed() <= 3000 ) {
00159 KMessageBox::information(
00160 mParentWidget,
00161 i18n( "KMail is unable to detect when the chosen editor is closed. "
00162 "To avoid data loss, editing the attachment will be aborted." ),
00163 i18n( "Unable to edit attachment" ),
00164 "UnableToEditAttachment" );
00165
00166 }
00167
00168 emit editDone( this );
00169 deleteLater();
00170 }
00171
00172 #include "editorwatcher.moc"