1 /*
2  * Copyright (C) 2018 Rafael Ostertag
3  *
4  * This file is part of YAPET.
5  *
6  * YAPET is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * YAPET is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * YAPET.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Additional permission under GNU GPL version 3 section 7
20  *
21  * If you modify this program, or any covered work, by linking or combining it
22  * with the OpenSSL project's OpenSSL library (or a modified version of that
23  * library), containing parts covered by the terms of the OpenSSL or SSLeay
24  * licenses, Rafael Ostertag grants you additional permission to convey the
25  * resulting work.  Corresponding Source for a non-source form of such a
26  * combination shall include the source code for the parts of OpenSSL used as
27  * well as that of the covered work.
28  */
29 
30 #include <cassert>
31 #include <memory>
32 #include <typeinfo>
33 
34 #include "aes256factory.hh"
35 #include "consts.h"
36 #include "createfile.h"
37 #include "globals.h"
38 #include "intl.h"
39 #include "utils.hh"
40 
41 //
42 // Private
43 //
44 
window_close_handler(YACURS::Event & e)45 void CreateFile::window_close_handler(YACURS::Event& e) {
46     assert(e == YACURS::EVT_WINDOW_CLOSE);
47 
48     YACURS::EventEx<YACURS::WindowBase*>& evt =
49         dynamic_cast<YACURS::EventEx<YACURS::WindowBase*>&>(e);
50 
51     if (evt.data() == filesavedialog) {
52         if (filesavedialog->dialog_state() == YACURS::DIALOG_OK) {
53             _filepath = filesavedialog->filepath();
54             assert(promptpassword == nullptr);
55             promptpassword = new NewPasswordDialog(_filepath);
56             promptpassword->show();
57         } else {
58             YACURS::EventQueue::submit(
59                 YACURS::EventEx<CreateFile*>(YAPET::EVT_APOPTOSIS, this));
60         }
61 
62         yapet::deleteAndZero(&filesavedialog);
63 
64         return;
65     }
66 
67     if (evt.data() == promptpassword) {
68         if (promptpassword->dialog_state() == YACURS::DIALOG_OK) {
69             assert(promptpassword->match());
70             assert(!_filepath.empty());
71 
72             // Set file into configuration, so that it receives .pet
73             // suffix
74             YAPET::Globals::config.petfile.set(_filepath);
75 
76             try {
77                 auto password{yapet::toSecureArray(promptpassword->password())};
78                 auto keyingParameters{yapet::Key256::newDefaultKeyingParameters()};
79                 std::shared_ptr<yapet::AbstractCryptoFactory> cryptoFactory{
80                     new yapet::Aes256Factory{password, keyingParameters}};
81                 mainwindow.load_password_file(YAPET::Globals::config.petfile,
82                                               cryptoFactory, true);
83 
84                 YACURS::EventQueue::submit(
85                     YACURS::EventEx<CreateFile*>(YAPET::EVT_APOPTOSIS, this));
86             } catch (std::exception& ex) {
87                 assert(generror == nullptr);
88                 generror = new YACURS::MessageBox2(_("Error"),
89                                                    _("Got following error"),
90                                                    ex.what(), YACURS::OK_ONLY);
91                 generror->show();
92             }
93 
94         } else {
95             YACURS::EventQueue::submit(
96                 YACURS::EventEx<CreateFile*>(YAPET::EVT_APOPTOSIS, this));
97         }
98 
99         // Do not put aptoptosis here, since here we can't decide
100         // whether we had an exception or not. And if we had an
101         // exception, generror is active and we have to wait for the
102         // user to close it. If we have an exception, generror handler
103         // takes care
104 
105         yapet::deleteAndZero(&promptpassword);
106         return;
107     }
108 
109     if (evt.data() == confirmsave) {
110         switch (confirmsave->dialog_state()) {
111             case YACURS::DIALOG_YES:
112                 if (mainwindow.save_records())
113                     run();
114                 else
115                     YACURS::EventQueue::submit(YACURS::EventEx<CreateFile*>(
116                         YAPET::EVT_APOPTOSIS, this));
117                 break;
118             case YACURS::DIALOG_NO:
119                 ignore_unsaved_file = true;
120                 run();
121                 break;
122             case YACURS::DIALOG_CANCEL:
123                 YACURS::EventQueue::submit(
124                     YACURS::EventEx<CreateFile*>(YAPET::EVT_APOPTOSIS, this));
125                 break;
126             default:
127                 throw std::runtime_error{
128                     _("Unexpected dialog state for confirmsave dialog")};
129                 break;
130         }
131 
132         yapet::deleteAndZero(&confirmsave);
133         return;
134     }
135 
136     if (evt.data() == generror) {
137         yapet::deleteAndZero(&generror);
138         YACURS::EventQueue::submit(
139             YACURS::EventEx<CreateFile*>(YAPET::EVT_APOPTOSIS, this));
140     }
141 }
142 
143 //
144 // Public
145 //
146 
CreateFile(MainWindow & mw)147 CreateFile::CreateFile(MainWindow& mw)
148     : mainwindow{mw},
149       promptpassword{nullptr},
150       filesavedialog{nullptr},
151       confirmsave{nullptr},
152       generror{nullptr},
153       _currentLoadedFile{mw.currentFilename()},
154       _filepath{},
155       ignore_unsaved_file{false} {
156     YACURS::EventQueue::connect_event(YACURS::EventConnectorMethod1<CreateFile>(
157         YACURS::EVT_WINDOW_CLOSE, this, &CreateFile::window_close_handler));
158 }
159 
~CreateFile()160 CreateFile::~CreateFile() {
161     if (promptpassword) delete promptpassword;
162     if (filesavedialog) delete filesavedialog;
163     if (confirmsave) delete confirmsave;
164     if (generror) delete generror;
165 
166     YACURS::EventQueue::disconnect_event(
167         YACURS::EventConnectorMethod1<CreateFile>(
168             YACURS::EVT_WINDOW_CLOSE, this, &CreateFile::window_close_handler));
169 }
170 
run()171 void CreateFile::run() {
172     if (!ignore_unsaved_file && YAPET::Globals::records_changed) {
173         assert(confirmsave == nullptr);
174         confirmsave = new YACURS::MessageBox2(
175             _("Unsaved Changes"), _currentLoadedFile,
176             _("has unsaved changes. Do you want to save?"),
177             YACURS::YESNOCANCEL);
178         confirmsave->show();
179     } else {
180         assert(filesavedialog == nullptr);
181         // FileSaveDialog uses chdir().
182         filesavedialog = new YACURS::FileSaveDialog(std::string(), true);
183         filesavedialog->suffix(YAPET::Consts::DEFAULT_FILE_SUFFIX);
184         filesavedialog->show();
185     }
186 }
187