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 "securitypage.hrc"
24 : #include "sfxresid.hxx"
25 :
26 : #include <sfx2/sfx.hrc>
27 : #include <sfx2/sfxsids.hrc>
28 : #include <sfx2/objsh.hxx>
29 : #include <sfx2/viewsh.hxx>
30 : #include <sfx2/dispatch.hxx>
31 : #include <sfx2/passwd.hxx>
32 :
33 : #include <vcl/button.hxx>
34 : #include <vcl/edit.hxx>
35 : #include <vcl/fixed.hxx>
36 : #include <vcl/msgbox.hxx>
37 : #include <svl/eitem.hxx>
38 : #include <svl/poolitem.hxx>
39 : #include <svl/intitem.hxx>
40 : #include <svl/PasswordHelper.hxx>
41 : #include <svtools/xwindowitem.hxx>
42 :
43 :
44 : using namespace ::com::sun::star;
45 :
46 :
47 :
48 : namespace
49 : {
50 : enum RedliningMode { RL_NONE, RL_WRITER, RL_CALC };
51 : enum RedlineFunc { RF_ON, RF_PROTECT };
52 :
53 0 : bool QueryState( sal_uInt16 _nSlot, bool& _rValue )
54 : {
55 0 : bool bRet = false;
56 0 : SfxViewShell* pViewSh = SfxViewShell::Current();
57 0 : if (pViewSh)
58 : {
59 : const SfxPoolItem* pItem;
60 0 : SfxDispatcher* pDisp = pViewSh->GetDispatcher();
61 0 : SfxItemState nState = pDisp->QueryState( _nSlot, pItem );
62 0 : bRet = SFX_ITEM_AVAILABLE <= nState;
63 0 : if (bRet)
64 0 : _rValue = ( static_cast< const SfxBoolItem* >( pItem ) )->GetValue();
65 : }
66 0 : return bRet;
67 : }
68 :
69 :
70 0 : bool QueryRecordChangesProtectionState( RedliningMode _eMode, bool& _rValue )
71 : {
72 0 : bool bRet = false;
73 0 : if (_eMode != RL_NONE)
74 : {
75 0 : sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_PROTECT : SID_CHG_PROTECT;
76 0 : bRet = QueryState( nSlot, _rValue );
77 : }
78 0 : return bRet;
79 : }
80 :
81 :
82 0 : bool QueryRecordChangesState( RedliningMode _eMode, bool& _rValue )
83 : {
84 0 : bool bRet = false;
85 0 : if (_eMode != RL_NONE)
86 : {
87 0 : sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_ON : FID_CHG_RECORD;
88 0 : bRet = QueryState( nSlot, _rValue );
89 : }
90 0 : return bRet;
91 : }
92 : }
93 :
94 :
95 0 : static short lcl_GetPassword(
96 : Window *pParent,
97 : bool bProtect,
98 : /*out*/String &rPassword )
99 : {
100 0 : bool bRes = false;
101 0 : SfxPasswordDialog aPasswdDlg( pParent );
102 0 : aPasswdDlg.SetMinLen( 1 );
103 0 : if (bProtect)
104 0 : aPasswdDlg.ShowExtras( SHOWEXTRAS_CONFIRM );
105 0 : if (RET_OK == aPasswdDlg.Execute() && aPasswdDlg.GetPassword().Len() > 0)
106 : {
107 0 : rPassword = aPasswdDlg.GetPassword();
108 0 : bRes = true;
109 : }
110 0 : return bRes;
111 : }
112 :
113 :
114 0 : static bool lcl_IsPasswordCorrect( const String &rPassword )
115 : {
116 0 : bool bRes = false;
117 :
118 0 : SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
119 0 : uno::Sequence< sal_Int8 > aPasswordHash;
120 0 : pCurDocShell->GetProtectionHash( aPasswordHash );
121 :
122 : // check if supplied password was correct
123 0 : uno::Sequence< sal_Int8 > aNewPasswd( aPasswordHash );
124 0 : SvPasswordHelper::GetHashPassword( aNewPasswd, rPassword );
125 0 : if (SvPasswordHelper::CompareHashPassword( aPasswordHash, rPassword ))
126 0 : bRes = true; // password was correct
127 : else
128 0 : InfoBox( NULL, SfxResId( RID_SFX_INCORRECT_PASSWORD ).toString() ).Execute();
129 :
130 0 : return bRes;
131 : }
132 :
133 :
134 : struct SfxSecurityPage_Impl
135 : {
136 : SfxSecurityPage & m_rMyTabPage;
137 :
138 : FixedLine m_aNewPasswordToOpenFL;
139 : FixedText m_aNewPasswordToOpenFT;
140 : Edit m_aNewPasswordToOpenED;
141 : FixedText m_aConfirmPasswordToOpenFT;
142 : Edit m_aConfirmPasswordToOpenED;
143 : FixedText m_aNewPasswordInfoFT;
144 :
145 : FixedLine m_aNewPasswordToModifyFL;
146 : FixedText m_aNewPasswordToModifyFT;
147 : Edit m_aNewPasswordToModifyED;
148 : FixedText m_aConfirmPasswordToModifyFT;
149 : Edit m_aConfirmPasswordToModifyED;
150 :
151 : FixedLine m_aOptionsFL;
152 : CheckBox m_aOpenReadonlyCB;
153 : CheckBox m_aRecordChangesCB; // for record changes
154 : PushButton m_aChangeProtectionPB; // for record changes
155 : String m_aProtectSTR; // for record changes
156 : String m_aUnProtectSTR; // for record changes
157 : RedliningMode m_eRedlingMode; // for record changes
158 :
159 : bool m_bOrigPasswordIsConfirmed;
160 : bool m_bNewPasswordIsValid;
161 : String m_aNewPassword;
162 :
163 : String m_aEndRedliningWarning;
164 : bool m_bEndRedliningWarningDone;
165 :
166 : DECL_LINK( RecordChangesCBToggleHdl, void* );
167 : DECL_LINK( ChangeProtectionPBHdl, void* );
168 :
169 : SfxSecurityPage_Impl( SfxSecurityPage &rDlg, const SfxItemSet &rItemSet );
170 : ~SfxSecurityPage_Impl();
171 :
172 : sal_Bool FillItemSet_Impl( SfxItemSet & );
173 : void Reset_Impl( const SfxItemSet & );
174 : };
175 :
176 :
177 0 : SfxSecurityPage_Impl::SfxSecurityPage_Impl( SfxSecurityPage &rTabPage, const SfxItemSet & ) :
178 : m_rMyTabPage (rTabPage),
179 : m_aNewPasswordToOpenFL (&rTabPage, SfxResId( PASSWORD_TO_OPEN_FL ) ),
180 : m_aNewPasswordToOpenFT (&rTabPage, SfxResId( PASSWORD_TO_OPEN_FT ) ),
181 : m_aNewPasswordToOpenED (&rTabPage, SfxResId( PASSWORD_TO_OPEN_ED ) ),
182 : m_aConfirmPasswordToOpenFT (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_OPEN_FT ) ),
183 : m_aConfirmPasswordToOpenED (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_OPEN_ED ) ),
184 : m_aNewPasswordInfoFT (&rTabPage, SfxResId( PASSWORD_INFO_FT ) ),
185 : m_aNewPasswordToModifyFL (&rTabPage, SfxResId( PASSWORD_TO_MODIFY_FL ) ),
186 : m_aNewPasswordToModifyFT (&rTabPage, SfxResId( PASSWORD_TO_MODIFY_FT ) ),
187 : m_aNewPasswordToModifyED (&rTabPage, SfxResId( PASSWORD_TO_MODIFY_ED ) ),
188 : m_aConfirmPasswordToModifyFT (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_MODIFY_FT ) ),
189 : m_aConfirmPasswordToModifyED (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_MODIFY_ED ) ),
190 : m_aOptionsFL (&rTabPage, SfxResId( OPTIONS_FL ) ),
191 : m_aOpenReadonlyCB (&rTabPage, SfxResId( OPEN_READONLY_CB ) ),
192 : m_aRecordChangesCB (&rTabPage, SfxResId( RECORD_CHANGES_CB ) ),
193 : m_aChangeProtectionPB (&rTabPage, SfxResId( CHANGE_PROTECTION_PB ) ),
194 : m_aProtectSTR ( SfxResId( STR_PROTECT ).toString() ),
195 : m_aUnProtectSTR ( SfxResId( STR_UNPROTECT ).toString() ),
196 : m_eRedlingMode ( RL_NONE ),
197 : m_bOrigPasswordIsConfirmed ( false ),
198 : m_bNewPasswordIsValid ( false ),
199 : m_aEndRedliningWarning ( SfxResId( STR_END_REDLINING_WARNING ).toString() ),
200 0 : m_bEndRedliningWarningDone ( false )
201 : {
202 0 : m_aChangeProtectionPB.SetText( m_aProtectSTR );
203 :
204 : // force toggle hdl called before visual change of checkbox
205 0 : m_aRecordChangesCB.SetStyle( m_aRecordChangesCB.GetStyle() | WB_EARLYTOGGLE );
206 0 : m_aRecordChangesCB.SetToggleHdl( LINK( this, SfxSecurityPage_Impl, RecordChangesCBToggleHdl ) );
207 0 : m_aChangeProtectionPB.SetClickHdl( LINK( this, SfxSecurityPage_Impl, ChangeProtectionPBHdl ) );
208 :
209 :
210 : // #i112277: for the time being (OOO 3.3) the following options should not
211 : // be available. In the long run however it is planned to implement the yet
212 : // missing functionality. Thus now we hide them and move the remaining ones up.
213 0 : m_aNewPasswordToOpenFL.Hide();
214 0 : m_aNewPasswordToOpenFT.Hide();
215 0 : m_aNewPasswordToOpenED.Hide();
216 0 : m_aConfirmPasswordToOpenFT.Hide();
217 0 : m_aConfirmPasswordToOpenED.Hide();
218 0 : m_aNewPasswordInfoFT.Hide();
219 0 : m_aNewPasswordToModifyFL.Hide();
220 0 : m_aNewPasswordToModifyFT.Hide();
221 0 : m_aNewPasswordToModifyED.Hide();
222 0 : m_aConfirmPasswordToModifyFT.Hide();
223 0 : m_aConfirmPasswordToModifyED.Hide();
224 0 : const long nDelta = m_aOptionsFL.GetPosPixel().Y() - m_aNewPasswordToOpenFL.GetPosPixel().Y();
225 0 : Point aPos;
226 0 : aPos = m_aOptionsFL.GetPosPixel();
227 0 : aPos.Y() -= nDelta;
228 0 : m_aOptionsFL.SetPosPixel( aPos );
229 0 : aPos = m_aOpenReadonlyCB.GetPosPixel();
230 0 : aPos.Y() -= nDelta;
231 0 : m_aOpenReadonlyCB.SetPosPixel( aPos );
232 0 : aPos = m_aRecordChangesCB.GetPosPixel();
233 0 : aPos.Y() -= nDelta;
234 0 : m_aRecordChangesCB.SetPosPixel( aPos );
235 0 : aPos = m_aChangeProtectionPB.GetPosPixel();
236 0 : aPos.Y() -= nDelta;
237 0 : m_aChangeProtectionPB.SetPosPixel( aPos );
238 0 : }
239 :
240 :
241 0 : SfxSecurityPage_Impl::~SfxSecurityPage_Impl()
242 : {
243 0 : }
244 :
245 :
246 0 : sal_Bool SfxSecurityPage_Impl::FillItemSet_Impl( SfxItemSet & )
247 : {
248 0 : bool bModified = false;
249 :
250 0 : SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
251 0 : if (pCurDocShell&& !pCurDocShell->IsReadOnly())
252 : {
253 0 : if (m_eRedlingMode != RL_NONE )
254 : {
255 0 : const bool bDoRecordChanges = m_aRecordChangesCB.IsChecked();
256 0 : const bool bDoChangeProtection = m_aChangeProtectionPB.GetText() != m_aProtectSTR;
257 :
258 : // sanity checks
259 : DBG_ASSERT( bDoRecordChanges || !bDoChangeProtection, "no change recording should imply no change protection" );
260 : DBG_ASSERT( bDoChangeProtection || !bDoRecordChanges, "no change protection should imply no change recording" );
261 : DBG_ASSERT( !bDoChangeProtection || m_aNewPassword.Len() > 0, "change protection should imply password length is > 0" );
262 : DBG_ASSERT( bDoChangeProtection || m_aNewPassword.Len() == 0, "no change protection should imply password length is 0" );
263 :
264 : // change recording
265 0 : if (bDoRecordChanges != pCurDocShell->IsChangeRecording())
266 : {
267 0 : pCurDocShell->SetChangeRecording( bDoRecordChanges );
268 0 : bModified = true;
269 : }
270 :
271 : // change record protection
272 0 : if (m_bNewPasswordIsValid &&
273 0 : bDoChangeProtection != pCurDocShell->HasChangeRecordProtection())
274 : {
275 : DBG_ASSERT( !bDoChangeProtection || bDoRecordChanges,
276 : "change protection requires record changes to be active!" );
277 0 : pCurDocShell->SetProtectionPassword( m_aNewPassword );
278 0 : bModified = true;
279 : }
280 : }
281 :
282 : // open read-only?
283 0 : const sal_Bool bDoOpenReadonly = m_aOpenReadonlyCB.IsChecked();
284 0 : if (pCurDocShell->HasSecurityOptOpenReadOnly() &&
285 0 : bDoOpenReadonly != pCurDocShell->IsSecurityOptOpenReadOnly())
286 : {
287 0 : pCurDocShell->SetSecurityOptOpenReadOnly( bDoOpenReadonly );
288 0 : bModified = true;
289 : }
290 : }
291 :
292 0 : return bModified;
293 : }
294 :
295 :
296 0 : void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet & )
297 : {
298 0 : SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
299 :
300 0 : String sNewText = m_aProtectSTR;
301 0 : if (!pCurDocShell)
302 : {
303 : // no doc -> hide document settings
304 0 : m_aOpenReadonlyCB.Disable();
305 0 : m_aRecordChangesCB.Disable();
306 0 : m_aChangeProtectionPB.Disable();
307 : }
308 : else
309 : {
310 0 : bool bIsHTMLDoc = false;
311 0 : SfxViewShell* pViewSh = SfxViewShell::Current();
312 0 : if (pViewSh)
313 : {
314 : const SfxPoolItem* pItem;
315 0 : SfxDispatcher* pDisp = pViewSh->GetDispatcher();
316 0 : if (SFX_ITEM_AVAILABLE <= pDisp->QueryState( SID_HTML_MODE, pItem ))
317 : {
318 0 : sal_uInt16 nMode = static_cast< const SfxUInt16Item* >( pItem )->GetValue();
319 0 : bIsHTMLDoc = ( ( nMode & HTMLMODE_ON ) != 0 );
320 : }
321 : }
322 :
323 0 : sal_Bool bIsReadonly = pCurDocShell->IsReadOnly();
324 0 : if (pCurDocShell->HasSecurityOptOpenReadOnly() && !bIsHTMLDoc)
325 : {
326 0 : m_aOpenReadonlyCB.Check( pCurDocShell->IsSecurityOptOpenReadOnly() );
327 0 : m_aOpenReadonlyCB.Enable( !bIsReadonly );
328 : }
329 : else
330 0 : m_aOpenReadonlyCB.Disable();
331 :
332 : bool bRecordChanges;
333 0 : if (QueryRecordChangesState( RL_WRITER, bRecordChanges ) && !bIsHTMLDoc)
334 0 : m_eRedlingMode = RL_WRITER;
335 0 : else if (QueryRecordChangesState( RL_CALC, bRecordChanges ))
336 0 : m_eRedlingMode = RL_CALC;
337 : else
338 0 : m_eRedlingMode = RL_NONE;
339 :
340 0 : if (m_eRedlingMode != RL_NONE)
341 : {
342 : bool bProtection;
343 0 : QueryRecordChangesProtectionState( m_eRedlingMode, bProtection );
344 :
345 0 : m_aChangeProtectionPB.Enable( !bIsReadonly );
346 : // set the right text
347 0 : if (bProtection)
348 0 : sNewText = m_aUnProtectSTR;
349 :
350 0 : m_aRecordChangesCB.Check( bRecordChanges );
351 0 : m_aRecordChangesCB.Enable( /*!bProtection && */!bIsReadonly );
352 :
353 0 : m_bOrigPasswordIsConfirmed = true; // default case if no password is set
354 0 : uno::Sequence< sal_Int8 > aPasswordHash;
355 : // check if password is available
356 0 : if (pCurDocShell->GetProtectionHash( aPasswordHash ) &&
357 0 : aPasswordHash.getLength() > 0)
358 0 : m_bOrigPasswordIsConfirmed = false; // password found, needs to be confirmed later on
359 : }
360 : else
361 : {
362 : // A Calc document that is shared will have 'm_eRedlingMode == RL_NONE'
363 : // In shared documents change recording and protection must be disabled,
364 : // similar to documents that do not support change recording at all.
365 0 : m_aRecordChangesCB.Check( sal_False );
366 0 : m_aRecordChangesCB.Disable();
367 0 : m_aChangeProtectionPB.Check( sal_False );
368 0 : m_aChangeProtectionPB.Disable();
369 : }
370 : }
371 :
372 0 : m_aChangeProtectionPB.SetText( sNewText );
373 0 : }
374 :
375 :
376 0 : IMPL_LINK_NOARG(SfxSecurityPage_Impl, RecordChangesCBToggleHdl)
377 : {
378 : // when change recording gets disabled protection must be disabled as well
379 0 : if (!m_aRecordChangesCB.IsChecked()) // the new check state is already present, thus the '!'
380 : {
381 0 : bool bAlreadyDone = false;
382 0 : if (!m_bEndRedliningWarningDone)
383 : {
384 : WarningBox aBox( m_rMyTabPage.GetParent(), WinBits(WB_YES_NO | WB_DEF_NO),
385 0 : m_aEndRedliningWarning );
386 0 : if (aBox.Execute() != RET_YES)
387 0 : bAlreadyDone = true;
388 : else
389 0 : m_bEndRedliningWarningDone = true;
390 : }
391 :
392 0 : const bool bNeedPasssword = !m_bOrigPasswordIsConfirmed
393 0 : && m_aChangeProtectionPB.GetText() != m_aProtectSTR;
394 0 : if (!bAlreadyDone && bNeedPasssword)
395 : {
396 0 : String aPasswordText;
397 :
398 : // dialog canceled or no password provided
399 0 : if (!lcl_GetPassword( m_rMyTabPage.GetParent(), false, aPasswordText ))
400 0 : bAlreadyDone = true;
401 :
402 : // ask for password and if dialog is canceled or no password provided return
403 0 : if (lcl_IsPasswordCorrect( aPasswordText ))
404 0 : m_bOrigPasswordIsConfirmed = true;
405 : else
406 0 : bAlreadyDone = true;
407 : }
408 :
409 0 : if (bAlreadyDone)
410 0 : m_aRecordChangesCB.Check( true ); // restore original state
411 : else
412 : {
413 : // remember required values to change protection and change recording in
414 : // FillItemSet_Impl later on if password was correct.
415 0 : m_bNewPasswordIsValid = true;
416 0 : m_aNewPassword = String();
417 :
418 0 : m_aChangeProtectionPB.SetText( m_aProtectSTR );
419 : }
420 : }
421 :
422 0 : return 0;
423 : }
424 :
425 :
426 0 : IMPL_LINK_NOARG(SfxSecurityPage_Impl, ChangeProtectionPBHdl)
427 : {
428 0 : if (m_eRedlingMode == RL_NONE)
429 0 : return 0;
430 :
431 : // the push button text is always the opposite of the current state. Thus:
432 0 : const bool bCurrentProtection = m_aChangeProtectionPB.GetText() != m_aProtectSTR;
433 :
434 : // ask user for password (if still necessary)
435 0 : String aPasswordText;
436 0 : bool bNewProtection = !bCurrentProtection;
437 0 : const bool bNeedPassword = bNewProtection || !m_bOrigPasswordIsConfirmed;
438 0 : if (bNeedPassword)
439 : {
440 : // ask for password and if dialog is canceled or no password provided return
441 0 : if (!lcl_GetPassword( m_rMyTabPage.GetParent(), bNewProtection, aPasswordText ))
442 0 : return 0;
443 :
444 : // provided password still needs to be checked?
445 0 : if (!bNewProtection && !m_bOrigPasswordIsConfirmed)
446 : {
447 0 : if (lcl_IsPasswordCorrect( aPasswordText ))
448 0 : m_bOrigPasswordIsConfirmed = true;
449 : else
450 0 : return 0;
451 : }
452 : }
453 : DBG_ASSERT( m_bOrigPasswordIsConfirmed, "ooops... this should not have happened!" );
454 :
455 : // remember required values to change protection and change recording in
456 : // FillItemSet_Impl later on if password was correct.
457 0 : m_bNewPasswordIsValid = true;
458 0 : m_aNewPassword = bNewProtection? aPasswordText : String();
459 :
460 0 : m_aRecordChangesCB.Check( bNewProtection );
461 : // toggle text of button "Protect" <-> "Unprotect"
462 0 : m_aChangeProtectionPB.SetText( bNewProtection ? m_aUnProtectSTR : m_aProtectSTR );
463 :
464 0 : return 0;
465 : }
466 :
467 :
468 0 : SfxTabPage* SfxSecurityPage::Create( Window * pParent, const SfxItemSet & rItemSet )
469 : {
470 0 : return new SfxSecurityPage( pParent, rItemSet );
471 : }
472 :
473 :
474 0 : SfxSecurityPage::SfxSecurityPage( Window* pParent, const SfxItemSet& rItemSet ) :
475 0 : SfxTabPage( pParent, SfxResId( TP_DOCINFOSECURITY ), rItemSet )
476 : {
477 0 : m_pImpl = std::auto_ptr< SfxSecurityPage_Impl >(new SfxSecurityPage_Impl( *this, rItemSet ));
478 :
479 0 : FreeResource();
480 0 : }
481 :
482 :
483 0 : SfxSecurityPage::~SfxSecurityPage()
484 : {
485 0 : }
486 :
487 :
488 0 : sal_Bool SfxSecurityPage::FillItemSet( SfxItemSet & rItemSet )
489 : {
490 0 : bool bModified = false;
491 : DBG_ASSERT( m_pImpl.get(), "implementation pointer is 0. Still in c-tor?" );
492 0 : if (m_pImpl.get() != 0)
493 0 : bModified = m_pImpl->FillItemSet_Impl( rItemSet );
494 0 : return bModified;
495 : }
496 :
497 :
498 0 : void SfxSecurityPage::Reset( const SfxItemSet & rItemSet )
499 : {
500 : DBG_ASSERT( m_pImpl.get(), "implementation pointer is 0. Still in c-tor?" );
501 0 : if (m_pImpl.get() != 0)
502 0 : m_pImpl->Reset_Impl( rItemSet );
503 234 : }
504 :
505 :
506 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|