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( nullptr ),
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(), nullptr );
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"
EditorWatcher(const KURL &url, const TQString &mimeType, bool openWith, TQObject *parent, TQWidget *parentWidget)
Constructs an EditorWatcher.
folderdiaquotatab.h
Definition aboutdata.cpp:40