1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 //_______________________________________________
27 // my own includes
28 
29 #ifndef __FRAMEWORK_SERVICES_TYPEDETECTION_HXX_
30 #include <services/sessionlistener.hxx>
31 #endif
32 #include <threadhelp/readguard.hxx>
33 #include <threadhelp/resetableguard.hxx>
34 #include <protocols.h>
35 #include <services.h>
36 
37 #include <osl/thread.h>
38 
39 
40 #include <vcl/svapp.hxx>
41 #include <tools/urlobj.hxx>
42 #include <tools/tempfile.hxx>
43 #include <unotools/tempfile.hxx>
44 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
45 #include <com/sun/star/lang/XComponent.hpp>
46 #include <com/sun/star/container/XNameAccess.hpp>
47 #include <com/sun/star/container/XNameContainer.hpp>
48 #include <com/sun/star/beans/NamedValue.hpp>
49 #include <com/sun/star/beans/PropertyValue.hpp>
50 #include <com/sun/star/beans/PropertyState.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/frame/XFramesSupplier.hpp>
53 #include <com/sun/star/frame/XStorable.hpp>
54 #include <com/sun/star/frame/XComponentLoader.hpp>
55 #include <com/sun/star/frame/XDispatch.hpp>
56 #include <com/sun/star/frame/XDesktop.hpp>
57 #include <com/sun/star/util/XModifiable.hpp>
58 #include <com/sun/star/util/XChangesBatch.hpp>
59 #include <com/sun/star/util/XURLTransformer.hpp>
60 #include <com/sun/star/util/URL.hpp>
61 #include <osl/time.h>
62 #include <comphelper/processfactory.hxx>
63 #include <unotools/pathoptions.hxx>
64 #include <unotools/internaloptions.hxx>
65 #include <stdio.h>
66 //_______________________________________________
67 // interface includes
68 #include <com/sun/star/uno/Any.hxx>
69 
70 #include <com/sun/star/uno/Sequence.hxx>
71 //_______________________________________________
72 // includes of other projects
73 
74 //_______________________________________________
75 // namespace
76 
77 using namespace com::sun::star::uno;
78 using namespace com::sun::star::util;
79 using namespace com::sun::star::frame;
80 using namespace com::sun::star::lang;
81 using namespace com::sun::star::beans;
82 using namespace com::sun::star::container;
83 
84 using namespace rtl;
85 
86 namespace framework{
87 
88 //_______________________________________________
89 // non exported const
90 
91 //_______________________________________________
92 // non exported definitions
93 
94 //_______________________________________________
95 // declarations
96 
97 //***********************************************
98 // XInterface, XTypeProvider, XServiceInfo
99 
DEFINE_XINTERFACE_6(SessionListener,OWeakObject,DIRECT_INTERFACE (css::lang::XTypeProvider),DIRECT_INTERFACE (css::lang::XInitialization),DIRECT_INTERFACE (css::frame::XSessionManagerListener),DIRECT_INTERFACE (css::frame::XSessionManagerListener2),DIRECT_INTERFACE (css::frame::XStatusListener),DIRECT_INTERFACE (css::lang::XServiceInfo))100 DEFINE_XINTERFACE_6(
101         SessionListener,
102         OWeakObject,
103         DIRECT_INTERFACE(css::lang::XTypeProvider),
104         DIRECT_INTERFACE(css::lang::XInitialization),
105         DIRECT_INTERFACE(css::frame::XSessionManagerListener),
106         DIRECT_INTERFACE(css::frame::XSessionManagerListener2),
107         DIRECT_INTERFACE(css::frame::XStatusListener),
108         DIRECT_INTERFACE(css::lang::XServiceInfo))
109 
110 DEFINE_XTYPEPROVIDER_5(
111         SessionListener,
112         css::lang::XTypeProvider,
113         css::lang::XInitialization,
114         css::frame::XSessionManagerListener2,
115         css::frame::XStatusListener,
116         css::lang::XServiceInfo)
117 
118 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE(
119        SessionListener,
120        cppu::OWeakObject,
121        SERVICENAME_SESSIONLISTENER,
122        IMPLEMENTATIONNAME_SESSIONLISTENER)
123 
124 DEFINE_INIT_SERVICE(SessionListener,
125                     {
126                         /* Add special code for initialization here, if you have to use your own instance
127                            during your ctor is still in progress! */
128                     }
129                    )
130 
131 SessionListener::SessionListener(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
132         : ThreadHelpBase      (&Application::GetSolarMutex())
133         , OWeakObject         (                             )
134         , m_xSMGR             (xSMGR                        )
135         , m_bRestored( sal_False )
136         , m_bSessionStoreRequested( sal_False )
137         , m_bAllowUserInteractionOnQuit( sal_False )
138         , m_bTerminated( sal_False )
139 {
140 }
141 
~SessionListener()142 SessionListener::~SessionListener()
143 {
144     if (m_rSessionManager.is())
145     {
146         css::uno::Reference< XSessionManagerListener> me(this);
147         m_rSessionManager->removeSessionManagerListener(me);
148     }
149 }
150 
StoreSession(sal_Bool bAsync)151 void SessionListener::StoreSession( sal_Bool bAsync )
152 {
153     ResetableGuard aGuard(m_aLock);
154     try
155     {
156         // xd create SERVICENAME_AUTORECOVERY -> XDispatch
157         // xd->dispatch("vnd.sun.star.autorecovery:/doSessionSave, async=bAsync
158         // on stop event m_rSessionManager->saveDone(this); in case of asynchronous call
159         // in case of synchronous call the caller should do saveDone() call himself!
160 
161         css::uno::Reference< XDispatch > xDispatch(m_xSMGR->createInstance(SERVICENAME_AUTORECOVERY), UNO_QUERY_THROW);
162         css::uno::Reference< XURLTransformer > xURLTransformer(m_xSMGR->createInstance(SERVICENAME_URLTRANSFORMER), UNO_QUERY_THROW);
163         URL aURL;
164         aURL.Complete = OUString::createFromAscii("vnd.sun.star.autorecovery:/doSessionSave");
165         xURLTransformer->parseStrict(aURL);
166 
167         // in case of asynchronous call the notification will trigger saveDone()
168         if ( bAsync )
169             xDispatch->addStatusListener(this, aURL);
170 
171         Sequence< PropertyValue > args(1);
172         args[0] = PropertyValue(OUString::createFromAscii("DispatchAsynchron"),-1,makeAny(bAsync),PropertyState_DIRECT_VALUE);
173         xDispatch->dispatch(aURL, args);
174     } catch (com::sun::star::uno::Exception& e) {
175         OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8);
176         OSL_ENSURE(sal_False, aMsg.getStr());
177         // save failed, but tell manager to go on if we havent yet dispatched the request
178         // in case of synchronous saving the notification is done by the caller
179         if ( bAsync && m_rSessionManager.is() )
180             m_rSessionManager->saveDone(this);
181     }
182 }
183 
QuitSessionQuietly()184 void SessionListener::QuitSessionQuietly()
185 {
186     ResetableGuard aGuard(m_aLock);
187     try
188     {
189         // xd create SERVICENAME_AUTORECOVERY -> XDispatch
190         // xd->dispatch("vnd.sun.star.autorecovery:/doSessionQuietQuit, async=false
191         // it is done synchronously to avoid conflict with normal quit process
192 
193         css::uno::Reference< XDispatch > xDispatch(m_xSMGR->createInstance(SERVICENAME_AUTORECOVERY), UNO_QUERY_THROW);
194         css::uno::Reference< XURLTransformer > xURLTransformer(m_xSMGR->createInstance(SERVICENAME_URLTRANSFORMER), UNO_QUERY_THROW);
195         URL aURL;
196         aURL.Complete = OUString::createFromAscii("vnd.sun.star.autorecovery:/doSessionQuietQuit");
197         xURLTransformer->parseStrict(aURL);
198 
199         Sequence< PropertyValue > args(1);
200         args[0] = PropertyValue(OUString::createFromAscii("DispatchAsynchron"),-1,makeAny(sal_False),PropertyState_DIRECT_VALUE);
201         xDispatch->dispatch(aURL, args);
202     } catch (com::sun::star::uno::Exception& e) {
203         OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8);
204         OSL_ENSURE(sal_False, aMsg.getStr());
205     }
206 }
207 
disposing(const com::sun::star::lang::EventObject &)208 void SAL_CALL SessionListener::disposing(const com::sun::star::lang::EventObject&) throw (RuntimeException)
209 {
210 }
211 
initialize(const Sequence<Any> & args)212 void SAL_CALL SessionListener::initialize(const Sequence< Any  >& args)
213     throw (RuntimeException)
214 {
215 
216     OUString aSMgr = OUString::createFromAscii("com.sun.star.frame.SessionManagerClient");
217     if (args.getLength() > 0)
218     {
219         NamedValue v;
220         for (int i = 0; i < args.getLength(); i++)
221         {
222             if (args[i] >>= v)
223             {
224                 if (v.Name.equalsAscii("SessionManagerName"))
225                     v.Value >>= aSMgr;
226                 else if (v.Name.equalsAscii("SessionManager"))
227                     v.Value >>= m_rSessionManager;
228                 else if (v.Name.equalsAscii("AllowUserInteractionOnQuit"))
229                     v.Value >>= m_bAllowUserInteractionOnQuit;
230             }
231         }
232     }
233     if (!m_rSessionManager.is())
234         m_rSessionManager = css::uno::Reference< XSessionManagerClient >
235             (m_xSMGR->createInstance(aSMgr), UNO_QUERY);
236 
237     if (m_rSessionManager.is())
238     {
239         m_rSessionManager->addSessionManagerListener(this);
240     }
241 }
242 
statusChanged(const FeatureStateEvent & event)243 void SAL_CALL SessionListener::statusChanged(const FeatureStateEvent& event)
244     throw (css::uno::RuntimeException)
245 {
246    if (event.FeatureURL.Complete.equalsAscii("vnd.sun.star.autorecovery:/doSessionRestore"))
247     {
248         if (event.FeatureDescriptor.compareToAscii("update")==0)
249             m_bRestored = sal_True; // a document was restored
250         // if (event.FeatureDescriptor.compareToAscii("stop")==0)
251 
252     }
253     else if (event.FeatureURL.Complete.equalsAscii("vnd.sun.star.autorecovery:/doSessionSave"))
254     {
255         if (event.FeatureDescriptor.compareToAscii("stop")==0)
256         {
257             if (m_rSessionManager.is())
258                 m_rSessionManager->saveDone(this); // done with save
259         }
260     }
261 }
262 
263 
doRestore()264 sal_Bool SAL_CALL SessionListener::doRestore()
265     throw (RuntimeException)
266 {
267     ResetableGuard aGuard(m_aLock);
268     m_bRestored = sal_False;
269     try {
270         css::uno::Reference< XDispatch > xDispatch(m_xSMGR->createInstance(SERVICENAME_AUTORECOVERY), UNO_QUERY_THROW);
271 
272         URL aURL;
273         aURL.Complete = OUString::createFromAscii("vnd.sun.star.autorecovery:/doSessionRestore");
274         css::uno::Reference< XURLTransformer > xURLTransformer(m_xSMGR->createInstance(SERVICENAME_URLTRANSFORMER), UNO_QUERY_THROW);
275         xURLTransformer->parseStrict(aURL);
276         Sequence< PropertyValue > args;
277         xDispatch->addStatusListener(this, aURL);
278         xDispatch->dispatch(aURL, args);
279         m_bRestored = sal_True;
280 
281     } catch (com::sun::star::uno::Exception& e) {
282         OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8);
283         OSL_ENSURE(sal_False, aMsg.getStr());
284     }
285 
286     return m_bRestored;
287 }
288 
289 
doSave(sal_Bool bShutdown,sal_Bool)290 void SAL_CALL SessionListener::doSave( sal_Bool bShutdown, sal_Bool /*bCancelable*/ )
291     throw (RuntimeException)
292 {
293     if (bShutdown)
294     {
295         m_bSessionStoreRequested = sal_True; // there is no need to protect it with mutex
296         if ( m_bAllowUserInteractionOnQuit && m_rSessionManager.is() )
297             m_rSessionManager->queryInteraction( static_cast< css::frame::XSessionManagerListener* >( this ) );
298         else
299             StoreSession( sal_True );
300     }
301     // we don't have anything to do so tell the session manager we're done
302     else if( m_rSessionManager.is() )
303         m_rSessionManager->saveDone( this );
304 }
305 
approveInteraction(sal_Bool bInteractionGranted)306 void SAL_CALL SessionListener::approveInteraction( sal_Bool bInteractionGranted )
307     throw (RuntimeException)
308 {
309     // do AutoSave as the first step
310     ResetableGuard aGuard(m_aLock);
311 
312     if ( bInteractionGranted )
313     {
314         // close the office documents in normal way
315         try
316         {
317             // first of all let the session be stored to be sure that we lose no information
318             StoreSession( sal_False );
319 
320             css::uno::Reference< css::frame::XDesktop > xDesktop( m_xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
321             m_bTerminated = xDesktop->terminate();
322 
323             if ( m_rSessionManager.is() )
324             {
325                 // false means that the application closing has been cancelled
326                 if ( !m_bTerminated )
327                     m_rSessionManager->cancelShutdown();
328                 else
329                     m_rSessionManager->interactionDone( this );
330             }
331         }
332         catch( css::uno::Exception& )
333         {
334             StoreSession( sal_True );
335             m_rSessionManager->interactionDone( this );
336         }
337 
338         if ( m_rSessionManager.is() )
339             m_rSessionManager->saveDone(this);
340     }
341     else
342     {
343         StoreSession( sal_True );
344     }
345 }
346 
shutdownCanceled()347 void SessionListener::shutdownCanceled()
348     throw (RuntimeException)
349 {
350     // set the state back
351     m_bSessionStoreRequested = sal_False; // there is no need to protect it with mutex
352 }
353 
doQuit()354 void SessionListener::doQuit()
355     throw (RuntimeException)
356 {
357     if ( m_bSessionStoreRequested && !m_bTerminated )
358     {
359         // let the session be closed quietly in this case
360         QuitSessionQuietly();
361     }
362 }
363 
364 }
365