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
10 #include <officecfg/Office/Common.hxx>
11 #include <osl/file.hxx>
12 #include <osl/security.hxx>
13 #include <osl/thread.h>
14 #include <tools/diagnose_ex.h>
15 #include "certpath.hxx"
16
17 #include <com/sun/star/mozilla/MozillaBootstrap.hpp>
18 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
19 #include <com/sun/star/ui/dialogs/FolderPicker.hpp>
20 #include <comphelper/processfactory.hxx>
21
22 using namespace ::com::sun::star;
23
CertPathDialog(weld::Window * pParent)24 CertPathDialog::CertPathDialog(weld::Window* pParent)
25 : GenericDialogController(pParent, "cui/ui/certdialog.ui", "CertDialog")
26 , m_xManualButton(m_xBuilder->weld_button("add"))
27 , m_xOKButton(m_xBuilder->weld_button("ok"))
28 , m_xCertPathList(m_xBuilder->weld_tree_view("paths"))
29 {
30 // these are just used to get translated strings
31 m_sAddDialogText = m_xBuilder->weld_label("certdir")->get_label();
32 m_sManualLabel = m_xBuilder->weld_label("manual")->get_label();
33
34 m_xCertPathList->set_size_request(m_xCertPathList->get_approximate_digit_width() * 70,
35 m_xCertPathList->get_height_rows(6));
36
37 std::vector<int> aWidths;
38 aWidths.push_back(m_xCertPathList->get_checkbox_column_width());
39 aWidths.push_back(m_xCertPathList->get_approximate_digit_width() * 20);
40 m_xCertPathList->set_column_fixed_widths(aWidths);
41
42 std::vector<int> aRadioColumns;
43 aRadioColumns.push_back(0);
44 m_xCertPathList->set_toggle_columns_as_radio(aRadioColumns);
45
46 m_xCertPathList->connect_toggled(LINK(this, CertPathDialog, CheckHdl_Impl));
47 m_xManualButton->connect_clicked( LINK( this, CertPathDialog, ManualHdl_Impl ) );
48 m_xOKButton->connect_clicked( LINK( this, CertPathDialog, OKHdl_Impl ) );
49
50 try
51 {
52 // In the reverse order of preference for the default selected profile
53 mozilla::MozillaProductType const productTypes[3] = {
54 mozilla::MozillaProductType_Thunderbird,
55 mozilla::MozillaProductType_Firefox,
56 mozilla::MozillaProductType_Mozilla };
57 const char* const productNames[3] = {
58 "thunderbird",
59 "firefox",
60 "mozilla" };
61 bool bSelected = false;
62
63 uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap = mozilla::MozillaBootstrap::create( comphelper::getProcessComponentContext() );
64
65 for (sal_Int32 i = 0; i < sal_Int32(SAL_N_ELEMENTS(productTypes)); ++i)
66 {
67 sal_Int32 nProfileCount = xMozillaBootstrap->getProfileCount(productTypes[i]);
68 if (nProfileCount <= 0)
69 continue;
70 OUString sDefaultProfile = xMozillaBootstrap->getDefaultProfile(productTypes[i]);
71 uno::Sequence<OUString> aProfileList(nProfileCount);
72 #ifndef NDEBUG
73 sal_Int32 nListLen =
74 #endif
75 xMozillaBootstrap->getProfileList(productTypes[i], aProfileList);
76 assert((nProfileCount == nListLen) && (nListLen == aProfileList.getLength()));
77
78 for (const auto& sProfileName : std::as_const(aProfileList))
79 {
80 OUString sEntry = OUString::createFromAscii(productNames[i]) + ":" + sProfileName;
81 OUString sProfilePath = xMozillaBootstrap->getProfilePath(productTypes[i], sProfileName);
82 const bool bSelectDefaultProfile = !bSelected && sProfileName == sDefaultProfile;
83 AddCertPath(sEntry, sProfilePath, bSelectDefaultProfile);
84 if (bSelectDefaultProfile)
85 bSelected = true;
86 }
87 }
88 }
89 catch (const uno::Exception&)
90 {
91 }
92
93 try
94 {
95 AddManualCertPath(officecfg::Office::Common::Security::Scripting::CertDir::get().get_value_or(OUString()));
96 if (m_sManualPath.isEmpty())
97 AddManualCertPath(officecfg::Office::Common::Security::Scripting::ManualCertDir::get(), false);
98 }
99 catch (const uno::Exception &)
100 {
101 TOOLS_WARN_EXCEPTION("cui.options", "CertPathDialog::CertPathDialog()");
102 }
103
104 const char* pEnv = getenv("MOZILLA_CERTIFICATE_FOLDER");
105 if (pEnv)
106 AddCertPath("$MOZILLA_CERTIFICATE_FOLDER", OUString(pEnv, strlen(pEnv), osl_getThreadTextEncoding()));
107 }
108
AddManualCertPath(const OUString & sUserSetCertPath,bool bSelect)109 void CertPathDialog::AddManualCertPath(const OUString& sUserSetCertPath, bool bSelect)
110 {
111 if (sUserSetCertPath.isEmpty())
112 return;
113
114 // check existence
115 ::osl::DirectoryItem aUserPathItem;
116 OUString sUserSetCertURLPath;
117 osl::FileBase::getFileURLFromSystemPath(sUserSetCertPath, sUserSetCertURLPath);
118 if (::osl::FileBase::E_None == ::osl::DirectoryItem::get(sUserSetCertURLPath, aUserPathItem))
119 {
120 ::osl::FileStatus aStatus( osl_FileStatus_Mask_Validate );
121 if (::osl::FileBase::E_None == aUserPathItem.getFileStatus(aStatus))
122 // the cert path exists
123 AddCertPath(m_sManualLabel, sUserSetCertPath, bSelect);
124 }
125 }
126
IMPL_LINK_NOARG(CertPathDialog,OKHdl_Impl,weld::Button &,void)127 IMPL_LINK_NOARG(CertPathDialog, OKHdl_Impl, weld::Button&, void)
128 {
129 try
130 {
131 std::shared_ptr< comphelper::ConfigurationChanges > batch(
132 comphelper::ConfigurationChanges::create());
133 officecfg::Office::Common::Security::Scripting::CertDir::set(
134 getDirectory(), batch);
135 officecfg::Office::Common::Security::Scripting::ManualCertDir::set(m_sManualPath, batch);
136 batch->commit();
137 }
138 catch (const uno::Exception &)
139 {
140 TOOLS_WARN_EXCEPTION("cui.options", "CertPathDialog::OKHdl_Impl()");
141 }
142
143 m_xDialog->response(RET_OK);
144 }
145
getDirectory() const146 OUString CertPathDialog::getDirectory() const
147 {
148 int nEntry = m_xCertPathList->get_selected_index();
149 if (nEntry == -1)
150 return OUString();
151 return m_xCertPathList->get_id(nEntry);
152 }
153
~CertPathDialog()154 CertPathDialog::~CertPathDialog()
155 {
156 }
157
IMPL_LINK(CertPathDialog,CheckHdl_Impl,const row_col &,rRowCol,void)158 IMPL_LINK(CertPathDialog, CheckHdl_Impl, const row_col&, rRowCol, void)
159 {
160 HandleEntryChecked(rRowCol.first);
161 }
162
HandleEntryChecked(int nRow)163 void CertPathDialog::HandleEntryChecked(int nRow)
164 {
165 const bool bChecked = m_xCertPathList->get_toggle(nRow, 0) == TRISTATE_TRUE;
166 if (bChecked)
167 {
168 // we have radio button behavior -> so uncheck the other entries
169 m_xCertPathList->select(nRow);
170 const int nCount = m_xCertPathList->n_children();
171 for (int i = 0; i < nCount; ++i)
172 {
173 if (i != nRow)
174 m_xCertPathList->set_toggle(i, TRISTATE_FALSE, 0);
175 }
176 }
177 }
178
AddCertPath(const OUString & rProfile,const OUString & rPath,const bool bSelect)179 void CertPathDialog::AddCertPath(const OUString &rProfile, const OUString &rPath, const bool bSelect)
180 {
181 int nRow = -1;
182 for (int i = 0, nCount = m_xCertPathList->n_children(); i < nCount; ++i)
183 {
184 OUString sCertPath = m_xCertPathList->get_id(i);
185 //already exists, just select the original one
186 if (sCertPath == rPath)
187 {
188 const bool bWantSelected = bSelect || m_xCertPathList->get_toggle(i, 0);
189 m_xCertPathList->set_toggle(i, bWantSelected ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
190 HandleEntryChecked(i);
191 return;
192 }
193 else if (m_xCertPathList->get_text(i, 1) == rProfile)
194 nRow = i;
195 }
196
197 if (m_sManualLabel == rProfile)
198 m_sManualPath = rPath;
199
200 if (nRow < 0)
201 {
202 m_xCertPathList->append();
203 nRow = m_xCertPathList->n_children() - 1;
204 }
205 m_xCertPathList->set_toggle(nRow, bSelect ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
206 m_xCertPathList->set_text(nRow, rProfile, 1);
207 m_xCertPathList->set_text(nRow, rPath, 2);
208 m_xCertPathList->set_id(nRow, rPath);
209 HandleEntryChecked(nRow);
210 }
211
IMPL_LINK_NOARG(CertPathDialog,ManualHdl_Impl,weld::Button &,void)212 IMPL_LINK_NOARG(CertPathDialog, ManualHdl_Impl, weld::Button&, void)
213 {
214 try
215 {
216 uno::Reference<ui::dialogs::XFolderPicker2> xFolderPicker = ui::dialogs::FolderPicker::create(comphelper::getProcessComponentContext());
217
218 OUString sURL;
219 if (!m_sManualPath.isEmpty())
220 osl::FileBase::getFileURLFromSystemPath(m_sManualPath, sURL);
221 if (sURL.isEmpty())
222 osl::Security().getHomeDir(sURL);
223 xFolderPicker->setDisplayDirectory(sURL);
224 xFolderPicker->setDescription(m_sAddDialogText);
225
226 if (xFolderPicker->execute() == ui::dialogs::ExecutableDialogResults::OK)
227 {
228 sURL = xFolderPicker->getDirectory();
229 OUString aPath;
230 if (osl::FileBase::E_None == osl::FileBase::getSystemPathFromFileURL(sURL, aPath))
231 AddCertPath(m_sManualLabel, aPath);
232 }
233 }
234 catch (const uno::Exception &)
235 {
236 TOOLS_WARN_EXCEPTION("cui.options", "");
237 }
238 }
239
240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
241