kmail

editorwatcher.cpp
1/*
2 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include "editorwatcher.h"
20
21#include <config.h>
22
23#include <kdebug.h>
24#include <tdelocale.h>
25#include <tdemessagebox.h>
26#include <kopenwith.h>
27#include <tdeprocess.h>
28#include <kuserprofile.h>
29
30#include <tqsocketnotifier.h>
31
32#include <cassert>
33
34// inotify stuff taken from tdelibs/tdeio/tdeio/kdirwatch.cpp
35#ifdef HAVE_SYS_INOTIFY
36#include <sys/ioctl.h>
37#include <sys/inotify.h>
38#include <fcntl.h>
39#elif HAVE_INOTIFY
40#include <sys/ioctl.h>
41#include <unistd.h>
42#include <sys/inotify.h>
43#include <sys/syscall.h>
44#include <linux/types.h>
45// Linux kernel headers are documented to not compile
46#define _S390_BITOPS_H
47#endif
48
49using namespace KMail;
50
51EditorWatcher::EditorWatcher(const KURL & url, const TQString &mimeType, bool openWith,
52 TQObject * parent, TQWidget *parentWidget) :
53 TQObject( parent ),
54 mUrl( url ),
55 mMimeType( mimeType ),
56 mOpenWith( openWith ),
57 mEditor( 0 ),
58 mParentWidget( parentWidget ),
59 mHaveInotify( false ),
60 mFileOpen( false ),
61 mEditorRunning( false ),
62 mFileModified( true ), // assume the worst unless we know better
63 mDone( false )
64{
65 assert( mUrl.isLocalFile() );
66 connect( &mTimer, TQ_SIGNAL(timeout()), TQ_SLOT(checkEditDone()) );
67}
68
69bool EditorWatcher::start()
70{
71 // find an editor
72 KURL::List list;
73 list.append( mUrl );
74 KService::Ptr offer = KServiceTypeProfile::preferredService( mMimeType, "Application" );
75 if ( mOpenWith || !offer ) {
76 KOpenWithDlg dlg( list, i18n("Edit with:"), TQString(), 0 );
77 if ( !dlg.exec() )
78 return false;
79 offer = dlg.service();
80 if ( !offer )
81 return false;
82 }
83
84#ifdef HAVE_INOTIFY
85 // monitor file
86 mInotifyFd = inotify_init();
87 if ( mInotifyFd > 0 ) {
88 mInotifyWatch = inotify_add_watch( mInotifyFd, mUrl.path().latin1(), IN_CLOSE | IN_OPEN | IN_MODIFY );
89 if ( mInotifyWatch >= 0 ) {
90 TQSocketNotifier *sn = new TQSocketNotifier( mInotifyFd, TQSocketNotifier::Read, this );
91 connect( sn, TQ_SIGNAL(activated(int)), TQ_SLOT(inotifyEvent()) );
92 mHaveInotify = true;
93 mFileModified = false;
94 }
95 } else {
96 kdWarning(5006) << k_funcinfo << "Failed to activate INOTIFY!" << endl;
97 }
98#endif
99
100 // start the editor
101 TQStringList params = KRun::processDesktopExec( *offer, list, false );
102 mEditor = new TDEProcess( this );
103 *mEditor << params;
104 connect( mEditor, TQ_SIGNAL(processExited(TDEProcess*)), TQ_SLOT(editorExited()) );
105 if ( !mEditor->start() )
106 return false;
107 mEditorRunning = true;
108
109 mEditTime.start();
110 return true;
111}
112
113void EditorWatcher::inotifyEvent()
114{
115 assert( mHaveInotify );
116#ifdef HAVE_INOTIFY
117 int pending = -1;
118 char buffer[4096];
119 ioctl( mInotifyFd, FIONREAD, &pending );
120 while ( pending > 0 ) {
121 int size = read( mInotifyFd, buffer, TQMIN( pending, (int)sizeof(buffer) ) );
122 pending -= size;
123 if ( size < 0 )
124 break; // error
125 int offset = 0;
126 while ( size > 0 ) {
127 struct inotify_event *event = (struct inotify_event *) &buffer[offset];
128 size -= sizeof( struct inotify_event ) + event->len;
129 offset += sizeof( struct inotify_event ) + event->len;
130 if ( event->mask & IN_OPEN )
131 mFileOpen = true;
132 if ( event->mask & IN_CLOSE )
133 mFileOpen = false;
134 if ( event->mask & IN_MODIFY )
135 mFileModified = true;
136 }
137 }
138#endif
139 mTimer.start( 500, true );
140
141}
142
143void EditorWatcher::editorExited()
144{
145 mEditorRunning = false;
146 mTimer.start( 500, true );
147}
148
149void EditorWatcher::checkEditDone()
150{
151 if ( mEditorRunning || (mFileOpen && mHaveInotify) || mDone )
152 return;
153 // protect us against double-deletion by calling this method again while
154 // the subeventloop of the message box is running
155 mDone = true;
156 // nobody can edit that fast, we seem to be unable to detect
157 // when the editor will be closed
158 if ( mEditTime.elapsed() <= 3000 ) {
159 KMessageBox::information(
160 mParentWidget,
161 i18n( "KMail is unable to detect when the chosen editor is closed. "
162 "To avoid data loss, editing the attachment will be aborted." ),
163 i18n( "Unable to edit attachment" ),
164 "UnableToEditAttachment" );
165
166 }
167
168 emit editDone( this );
169 deleteLater();
170}
171
172#include "editorwatcher.moc"
folderdiaquotatab.h
Definition: aboutdata.cpp:40