Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <sfx2/securitypage.hxx>
22 :
23 : #include <sfx2/sfxresid.hxx>
24 :
25 : #include <sfx2/sfx.hrc>
26 : #include <sfx2/sfxsids.hrc>
27 : #include <sfx2/objsh.hxx>
28 : #include <sfx2/viewsh.hxx>
29 : #include <sfx2/dispatch.hxx>
30 : #include <sfx2/passwd.hxx>
31 :
32 : #include <vcl/button.hxx>
33 : #include <vcl/edit.hxx>
34 : #include <vcl/fixed.hxx>
35 : #include <vcl/msgbox.hxx>
36 : #include <svl/eitem.hxx>
37 : #include <svl/poolitem.hxx>
38 : #include <svl/intitem.hxx>
39 : #include <svl/PasswordHelper.hxx>
40 : #include <svtools/xwindowitem.hxx>
41 :
42 : #include "../appl/app.hrc"
43 :
44 :
45 : using namespace ::com::sun::star;
46 :
47 :
48 :
49 : namespace
50 : {
51 : enum RedliningMode { RL_NONE, RL_WRITER, RL_CALC };
52 : enum RedlineFunc { RF_ON, RF_PROTECT };
53 :
54 0 : bool QueryState( sal_uInt16 _nSlot, bool& _rValue )
55 : {
56 0 : bool bRet = false;
57 0 : SfxViewShell* pViewSh = SfxViewShell::Current();
58 0 : if (pViewSh)
59 : {
60 : const SfxPoolItem* pItem;
61 0 : SfxDispatcher* pDisp = pViewSh->GetDispatcher();
62 0 : SfxItemState nState = pDisp->QueryState( _nSlot, pItem );
63 0 : bRet = SFX_ITEM_AVAILABLE <= nState;
64 0 : if (bRet)
65 0 : _rValue = ( static_cast< const SfxBoolItem* >( pItem ) )->GetValue();
66 : }
67 0 : return bRet;
68 : }
69 :
70 :
71 0 : bool QueryRecordChangesProtectionState( RedliningMode _eMode, bool& _rValue )
72 : {
73 0 : bool bRet = false;
74 0 : if (_eMode != RL_NONE)
75 : {
76 0 : sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_PROTECT : SID_CHG_PROTECT;
77 0 : bRet = QueryState( nSlot, _rValue );
78 : }
79 0 : return bRet;
80 : }
81 :
82 :
83 0 : bool QueryRecordChangesState( RedliningMode _eMode, bool& _rValue )
84 : {
85 0 : bool bRet = false;
86 0 : if (_eMode != RL_NONE)
87 : {
88 0 : sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_ON : FID_CHG_RECORD;
89 0 : bRet = QueryState( nSlot, _rValue );
90 : }
91 0 : return bRet;
92 : }
93 : }
94 :
95 :
96 0 : static bool lcl_GetPassword(
97 : Window *pParent,
98 : bool bProtect,
99 : /*out*/OUString &rPassword )
100 : {
101 0 : bool bRes = false;
102 0 : SfxPasswordDialog aPasswdDlg( pParent );
103 0 : aPasswdDlg.SetMinLen( 1 );
104 0 : if (bProtect)
105 0 : aPasswdDlg.ShowExtras( SHOWEXTRAS_CONFIRM );
106 0 : if (RET_OK == aPasswdDlg.Execute() && !aPasswdDlg.GetPassword().isEmpty())
107 : {
108 0 : rPassword = aPasswdDlg.GetPassword();
109 0 : bRes = true;
110 : }
111 0 : return bRes;
112 : }
113 :
114 :
115 0 : static bool lcl_IsPasswordCorrect( const OUString &rPassword )
116 : {
117 0 : bool bRes = false;
118 :
119 0 : SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
120 0 : uno::Sequence< sal_Int8 > aPasswordHash;
121 0 : pCurDocShell->GetProtectionHash( aPasswordHash );
122 :
123 : // check if supplied password was correct
124 0 : uno::Sequence< sal_Int8 > aNewPasswd( aPasswordHash );
125 0 : SvPasswordHelper::GetHashPassword( aNewPasswd, rPassword );
126 0 : if (SvPasswordHelper::CompareHashPassword( aPasswordHash, rPassword ))
127 0 : bRes = true; // password was correct
128 : else
129 0 : InfoBox( NULL, SFX2_RESSTR(RID_SVXSTR_INCORRECT_PASSWORD) ).Execute();
130 :
131 0 : return bRes;
132 : }
133 :
134 :
135 : struct SfxSecurityPage_Impl
136 : {
137 : SfxSecurityPage & m_rMyTabPage;
138 :
139 : CheckBox* m_pOpenReadonlyCB;
140 : CheckBox* m_pRecordChangesCB; // for record changes
141 : PushButton* m_pProtectPB; // for record changes
142 : PushButton* m_pUnProtectPB; // for record changes
143 : RedliningMode m_eRedlingMode; // for record changes
144 :
145 : bool m_bOrigPasswordIsConfirmed;
146 : bool m_bNewPasswordIsValid;
147 : OUString m_aNewPassword;
148 :
149 : OUString m_aEndRedliningWarning;
150 : bool m_bEndRedliningWarningDone;
151 :
152 : DECL_LINK( RecordChangesCBToggleHdl, void* );
153 : DECL_LINK( ChangeProtectionPBHdl, void* );
154 :
155 : SfxSecurityPage_Impl( SfxSecurityPage &rDlg, const SfxItemSet &rItemSet );
156 : ~SfxSecurityPage_Impl();
157 :
158 : bool FillItemSet_Impl( SfxItemSet & );
159 : void Reset_Impl( const SfxItemSet & );
160 : };
161 :
162 :
163 0 : SfxSecurityPage_Impl::SfxSecurityPage_Impl( SfxSecurityPage &rTabPage, const SfxItemSet & ) :
164 : m_rMyTabPage (rTabPage),
165 : m_eRedlingMode ( RL_NONE ),
166 : m_bOrigPasswordIsConfirmed ( false ),
167 : m_bNewPasswordIsValid ( false ),
168 : m_aEndRedliningWarning ( SFX2_RESSTR(RID_SVXSTR_END_REDLINING_WARNING) ),
169 0 : m_bEndRedliningWarningDone ( false )
170 : {
171 0 : rTabPage.get(m_pOpenReadonlyCB, "readonly");
172 0 : rTabPage.get(m_pRecordChangesCB, "recordchanges");
173 0 : rTabPage.get(m_pProtectPB, "protect");
174 0 : rTabPage.get(m_pUnProtectPB, "unprotect");
175 0 : m_pProtectPB->Show();
176 0 : m_pUnProtectPB->Hide();
177 :
178 : // force toggle hdl called before visual change of checkbox
179 0 : m_pRecordChangesCB->SetStyle( m_pRecordChangesCB->GetStyle() | WB_EARLYTOGGLE );
180 0 : m_pRecordChangesCB->SetToggleHdl( LINK( this, SfxSecurityPage_Impl, RecordChangesCBToggleHdl ) );
181 0 : m_pProtectPB->SetClickHdl( LINK( this, SfxSecurityPage_Impl, ChangeProtectionPBHdl ) );
182 0 : m_pUnProtectPB->SetClickHdl( LINK( this, SfxSecurityPage_Impl, ChangeProtectionPBHdl ) );
183 0 : }
184 :
185 :
186 0 : SfxSecurityPage_Impl::~SfxSecurityPage_Impl()
187 : {
188 0 : }
189 :
190 :
191 0 : bool SfxSecurityPage_Impl::FillItemSet_Impl( SfxItemSet & )
192 : {
193 0 : bool bModified = false;
194 :
195 0 : SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
196 0 : if (pCurDocShell&& !pCurDocShell->IsReadOnly())
197 : {
198 0 : if (m_eRedlingMode != RL_NONE )
199 : {
200 0 : const bool bDoRecordChanges = m_pRecordChangesCB->IsChecked();
201 0 : const bool bDoChangeProtection = m_pUnProtectPB->IsVisible();
202 :
203 : // sanity checks
204 : DBG_ASSERT( bDoRecordChanges || !bDoChangeProtection, "no change recording should imply no change protection" );
205 : DBG_ASSERT( bDoChangeProtection || !bDoRecordChanges, "no change protection should imply no change recording" );
206 : DBG_ASSERT( !bDoChangeProtection || !m_aNewPassword.isEmpty(), "change protection should imply password length is > 0" );
207 : DBG_ASSERT( bDoChangeProtection || m_aNewPassword.isEmpty(), "no change protection should imply password length is 0" );
208 :
209 : // change recording
210 0 : if (bDoRecordChanges != pCurDocShell->IsChangeRecording())
211 : {
212 0 : pCurDocShell->SetChangeRecording( bDoRecordChanges );
213 0 : bModified = true;
214 : }
215 :
216 : // change record protection
217 0 : if (m_bNewPasswordIsValid &&
218 0 : bDoChangeProtection != pCurDocShell->HasChangeRecordProtection())
219 : {
220 : DBG_ASSERT( !bDoChangeProtection || bDoRecordChanges,
221 : "change protection requires record changes to be active!" );
222 0 : pCurDocShell->SetProtectionPassword( m_aNewPassword );
223 0 : bModified = true;
224 : }
225 : }
226 :
227 : // open read-only?
228 0 : const bool bDoOpenReadonly = m_pOpenReadonlyCB->IsChecked();
229 0 : if (pCurDocShell->HasSecurityOptOpenReadOnly() &&
230 0 : bDoOpenReadonly != pCurDocShell->IsSecurityOptOpenReadOnly())
231 : {
232 0 : pCurDocShell->SetSecurityOptOpenReadOnly( bDoOpenReadonly );
233 0 : bModified = true;
234 : }
235 : }
236 :
237 0 : return bModified;
238 : }
239 :
240 :
241 0 : void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet & )
242 : {
243 0 : SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
244 :
245 0 : if (!pCurDocShell)
246 : {
247 : // no doc -> hide document settings
248 0 : m_pOpenReadonlyCB->Disable();
249 0 : m_pRecordChangesCB->Disable();
250 0 : m_pProtectPB->Show();
251 0 : m_pProtectPB->Disable();
252 0 : m_pUnProtectPB->Hide();
253 0 : m_pUnProtectPB->Disable();
254 : }
255 : else
256 : {
257 0 : bool bIsHTMLDoc = false;
258 0 : bool bProtect = true, bUnProtect = false;
259 0 : SfxViewShell* pViewSh = SfxViewShell::Current();
260 0 : if (pViewSh)
261 : {
262 : const SfxPoolItem* pItem;
263 0 : SfxDispatcher* pDisp = pViewSh->GetDispatcher();
264 0 : if (SFX_ITEM_AVAILABLE <= pDisp->QueryState( SID_HTML_MODE, pItem ))
265 : {
266 0 : sal_uInt16 nMode = static_cast< const SfxUInt16Item* >( pItem )->GetValue();
267 0 : bIsHTMLDoc = ( ( nMode & HTMLMODE_ON ) != 0 );
268 : }
269 : }
270 :
271 0 : bool bIsReadonly = pCurDocShell->IsReadOnly();
272 0 : if (pCurDocShell->HasSecurityOptOpenReadOnly() && !bIsHTMLDoc)
273 : {
274 0 : m_pOpenReadonlyCB->Check( pCurDocShell->IsSecurityOptOpenReadOnly() );
275 0 : m_pOpenReadonlyCB->Enable( !bIsReadonly );
276 : }
277 : else
278 0 : m_pOpenReadonlyCB->Disable();
279 :
280 : bool bRecordChanges;
281 0 : if (QueryRecordChangesState( RL_WRITER, bRecordChanges ) && !bIsHTMLDoc)
282 0 : m_eRedlingMode = RL_WRITER;
283 0 : else if (QueryRecordChangesState( RL_CALC, bRecordChanges ))
284 0 : m_eRedlingMode = RL_CALC;
285 : else
286 0 : m_eRedlingMode = RL_NONE;
287 :
288 0 : if (m_eRedlingMode != RL_NONE)
289 : {
290 : bool bProtection;
291 0 : QueryRecordChangesProtectionState( m_eRedlingMode, bProtection );
292 :
293 0 : m_pProtectPB->Enable( !bIsReadonly );
294 0 : m_pUnProtectPB->Enable( !bIsReadonly );
295 : // set the right text
296 0 : if (bProtection)
297 : {
298 0 : bProtect = false;
299 0 : bUnProtect = true;
300 : }
301 :
302 0 : m_pRecordChangesCB->Check( bRecordChanges );
303 0 : m_pRecordChangesCB->Enable( /*!bProtection && */!bIsReadonly );
304 :
305 0 : m_bOrigPasswordIsConfirmed = true; // default case if no password is set
306 0 : uno::Sequence< sal_Int8 > aPasswordHash;
307 : // check if password is available
308 0 : if (pCurDocShell->GetProtectionHash( aPasswordHash ) &&
309 0 : aPasswordHash.getLength() > 0)
310 0 : m_bOrigPasswordIsConfirmed = false; // password found, needs to be confirmed later on
311 : }
312 : else
313 : {
314 : // A Calc document that is shared will have 'm_eRedlingMode == RL_NONE'
315 : // In shared documents change recording and protection must be disabled,
316 : // similar to documents that do not support change recording at all.
317 0 : m_pRecordChangesCB->Check( false );
318 0 : m_pRecordChangesCB->Disable();
319 0 : m_pProtectPB->Check( false );
320 0 : m_pUnProtectPB->Check( false );
321 0 : m_pProtectPB->Disable();
322 0 : m_pUnProtectPB->Disable();
323 : }
324 :
325 0 : m_pProtectPB->Show(bProtect);
326 0 : m_pUnProtectPB->Show(bUnProtect);
327 : }
328 0 : }
329 :
330 :
331 0 : IMPL_LINK_NOARG(SfxSecurityPage_Impl, RecordChangesCBToggleHdl)
332 : {
333 : // when change recording gets disabled protection must be disabled as well
334 0 : if (!m_pRecordChangesCB->IsChecked()) // the new check state is already present, thus the '!'
335 : {
336 0 : bool bAlreadyDone = false;
337 0 : if (!m_bEndRedliningWarningDone)
338 : {
339 : WarningBox aBox( m_rMyTabPage.GetParent(), WinBits(WB_YES_NO | WB_DEF_NO),
340 0 : m_aEndRedliningWarning );
341 0 : if (aBox.Execute() != RET_YES)
342 0 : bAlreadyDone = true;
343 : else
344 0 : m_bEndRedliningWarningDone = true;
345 : }
346 :
347 0 : const bool bNeedPasssword = !m_bOrigPasswordIsConfirmed
348 0 : && m_pProtectPB->IsVisible();
349 0 : if (!bAlreadyDone && bNeedPasssword)
350 : {
351 0 : OUString aPasswordText;
352 :
353 : // dialog canceled or no password provided
354 0 : if (!lcl_GetPassword( m_rMyTabPage.GetParent(), false, aPasswordText ))
355 0 : bAlreadyDone = true;
356 :
357 : // ask for password and if dialog is canceled or no password provided return
358 0 : if (lcl_IsPasswordCorrect( aPasswordText ))
359 0 : m_bOrigPasswordIsConfirmed = true;
360 : else
361 0 : bAlreadyDone = true;
362 : }
363 :
364 0 : if (bAlreadyDone)
365 0 : m_pRecordChangesCB->Check( true ); // restore original state
366 : else
367 : {
368 : // remember required values to change protection and change recording in
369 : // FillItemSet_Impl later on if password was correct.
370 0 : m_bNewPasswordIsValid = true;
371 0 : m_aNewPassword = "";
372 0 : m_pProtectPB->Show();
373 0 : m_pUnProtectPB->Hide();
374 : }
375 : }
376 :
377 0 : return 0;
378 : }
379 :
380 :
381 0 : IMPL_LINK_NOARG(SfxSecurityPage_Impl, ChangeProtectionPBHdl)
382 : {
383 0 : if (m_eRedlingMode == RL_NONE)
384 0 : return 0;
385 :
386 : // the push button text is always the opposite of the current state. Thus:
387 0 : const bool bCurrentProtection = m_pUnProtectPB->IsVisible();
388 :
389 : // ask user for password (if still necessary)
390 0 : OUString aPasswordText;
391 0 : bool bNewProtection = !bCurrentProtection;
392 0 : const bool bNeedPassword = bNewProtection || !m_bOrigPasswordIsConfirmed;
393 0 : if (bNeedPassword)
394 : {
395 : // ask for password and if dialog is canceled or no password provided return
396 0 : if (!lcl_GetPassword( m_rMyTabPage.GetParent(), bNewProtection, aPasswordText ))
397 0 : return 0;
398 :
399 : // provided password still needs to be checked?
400 0 : if (!bNewProtection && !m_bOrigPasswordIsConfirmed)
401 : {
402 0 : if (lcl_IsPasswordCorrect( aPasswordText ))
403 0 : m_bOrigPasswordIsConfirmed = true;
404 : else
405 0 : return 0;
406 : }
407 : }
408 : DBG_ASSERT( m_bOrigPasswordIsConfirmed, "ooops... this should not have happened!" );
409 :
410 : // remember required values to change protection and change recording in
411 : // FillItemSet_Impl later on if password was correct.
412 0 : m_bNewPasswordIsValid = true;
413 0 : m_aNewPassword = bNewProtection? aPasswordText : OUString();
414 :
415 0 : m_pRecordChangesCB->Check( bNewProtection );
416 :
417 0 : m_pUnProtectPB->Show(bNewProtection);
418 0 : m_pProtectPB->Show(!bNewProtection);
419 :
420 0 : return 0;
421 : }
422 :
423 :
424 0 : SfxTabPage* SfxSecurityPage::Create( Window * pParent, const SfxItemSet & rItemSet )
425 : {
426 0 : return new SfxSecurityPage( pParent, rItemSet );
427 : }
428 :
429 :
430 0 : SfxSecurityPage::SfxSecurityPage( Window* pParent, const SfxItemSet& rItemSet )
431 0 : : SfxTabPage(pParent, "SecurityInfoPage", "sfx/ui/securityinfopage.ui", rItemSet)
432 : {
433 0 : m_pImpl.reset(new SfxSecurityPage_Impl( *this, rItemSet ));
434 0 : }
435 :
436 :
437 0 : SfxSecurityPage::~SfxSecurityPage()
438 : {
439 0 : }
440 :
441 :
442 0 : bool SfxSecurityPage::FillItemSet( SfxItemSet & rItemSet )
443 : {
444 0 : bool bModified = false;
445 : DBG_ASSERT( m_pImpl.get(), "implementation pointer is 0. Still in c-tor?" );
446 0 : if (m_pImpl.get() != 0)
447 0 : bModified = m_pImpl->FillItemSet_Impl( rItemSet );
448 0 : return bModified;
449 : }
450 :
451 :
452 0 : void SfxSecurityPage::Reset( const SfxItemSet & rItemSet )
453 : {
454 : DBG_ASSERT( m_pImpl.get(), "implementation pointer is 0. Still in c-tor?" );
455 0 : if (m_pImpl.get() != 0)
456 0 : m_pImpl->Reset_Impl( rItemSet );
457 3 : }
458 :
459 :
460 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|