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