Branch data Line data Source code
1 : : /********************************************************************\
2 : : * qofsession.cpp -- session access (connection to backend) *
3 : : * *
4 : : * This program is free software; you can redistribute it and/or *
5 : : * modify it under the terms of the GNU General Public License as *
6 : : * published by the Free Software Foundation; either version 2 of *
7 : : * the License, or (at your option) any later version. *
8 : : * *
9 : : * This program is distributed in the hope that it will be useful, *
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 : : * GNU General Public License for more details. *
13 : : * *
14 : : * You should have received a copy of the GNU General Public License*
15 : : * along with this program; if not, contact: *
16 : : * *
17 : : * Free Software Foundation Voice: +1-617-542-5942 *
18 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
20 : : \********************************************************************/
21 : :
22 : : /**
23 : : * @file qofsession.cpp
24 : : * @brief Encapsulate a connection to a storage backend.
25 : : *
26 : : * HISTORY:
27 : : * Created by Linas Vepstas December 1998
28 : :
29 : : @author Copyright (c) 1998-2004 Linas Vepstas <linas@linas.org>
30 : : @author Copyright (c) 2000 Dave Peticolas
31 : : @author Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
32 : : @author Copyright (c) 2016 Aaron Laws
33 : : */
34 : : #include <glib.h>
35 : :
36 : : #include <config.h>
37 : :
38 : : #include <stdlib.h>
39 : : #include <sys/types.h>
40 : : #include <sys/stat.h>
41 : : #ifdef HAVE_UNISTD_H
42 : : # include <unistd.h>
43 : : #else
44 : : # ifdef __GNUC__
45 : : # warning "<unistd.h> required."
46 : : # endif
47 : : #endif
48 : :
49 : : #include "qof.h"
50 : : #include "qofobject-p.h"
51 : :
52 : : static QofLogModule log_module = QOF_MOD_SESSION;
53 : :
54 : : #include "qofbook-p.h"
55 : : #include "qof-backend.hpp"
56 : : #include "qofsession.hpp"
57 : : #include "gnc-backend-prov.hpp"
58 : :
59 : : #include <vector>
60 : : #include <boost/algorithm/string.hpp>
61 : : #include <vector>
62 : : #include <algorithm>
63 : : #include <string>
64 : : #include <sstream>
65 : :
66 : : using ProviderVec = std::vector<QofBackendProvider_ptr>;
67 : : static ProviderVec s_providers;
68 : : static const std::string empty_string{};
69 : : /*
70 : : * These getters are used in tests to reach static vars from outside
71 : : * They should be removed when no longer needed
72 : : */
73 : :
74 : : ProviderVec& get_providers (void );
75 : : bool get_providers_initialized (void );
76 : :
77 : : ProviderVec&
78 : 0 : get_providers (void)
79 : : {
80 : 0 : return s_providers;
81 : : }
82 : :
83 : : bool
84 : 0 : get_providers_initialized (void)
85 : : {
86 : 0 : return !s_providers.empty();
87 : : }
88 : :
89 : : void
90 : 244 : qof_backend_register_provider (QofBackendProvider_ptr&& prov)
91 : : {
92 : 244 : s_providers.emplace_back(std::move(prov));
93 : 244 : }
94 : :
95 : : void
96 : 0 : qof_backend_unregister_all_providers ()
97 : : {
98 : 0 : s_providers.clear ();
99 : 0 : }
100 : :
101 : : /* Called from C so we have to keep the GList for now. */
102 : : GList*
103 : 6 : qof_backend_get_registered_access_method_list(void)
104 : : {
105 : 6 : GList* list = NULL;
106 : 6 : std::for_each(s_providers.begin(), s_providers.end(),
107 : 0 : [&list](QofBackendProvider_ptr& provider) {
108 : 0 : gpointer method = reinterpret_cast<gpointer>(const_cast<char*>(provider->access_method));
109 : 0 : list = g_list_prepend(list, method);
110 : 0 : });
111 : 6 : return list;
112 : : }
113 : :
114 : : /* QofSessionImpl */
115 : : /* ====================================================================== */
116 : : /* Constructor/Destructor ----------------------------------*/
117 : :
118 : 241 : QofSessionImpl::QofSessionImpl (QofBook* book) noexcept
119 : 241 : : m_backend {},
120 : 241 : m_book {book},
121 : 241 : m_uri {},
122 : 241 : m_saving {false},
123 : 241 : m_last_err {},
124 : 241 : m_error_message {}
125 : : {
126 : 241 : }
127 : :
128 : 139 : QofSessionImpl::~QofSessionImpl () noexcept
129 : : {
130 : 139 : ENTER ("sess=%p uri=%s", this, m_uri.c_str ());
131 : 139 : end ();
132 : 139 : destroy_backend ();
133 : 139 : qof_book_set_backend (m_book, nullptr);
134 : 139 : qof_book_destroy (m_book);
135 : 139 : m_book = nullptr;
136 : 139 : LEAVE ("sess=%p", this);
137 : 139 : }
138 : :
139 : : void
140 : 139 : qof_session_destroy (QofSession * session)
141 : : {
142 : 139 : delete session;
143 : 139 : }
144 : :
145 : : QofSession *
146 : 241 : qof_session_new (QofBook* book)
147 : : {
148 : 241 : return new QofSessionImpl(book);
149 : : }
150 : :
151 : : void
152 : 179 : QofSessionImpl::destroy_backend () noexcept
153 : : {
154 : 179 : if (m_backend)
155 : : {
156 : 18 : clear_error ();
157 : 18 : delete m_backend;
158 : 18 : m_backend = nullptr;
159 : 18 : qof_book_set_backend (m_book, nullptr);
160 : : }
161 : 179 : }
162 : :
163 : : /* ====================================================================== */
164 : :
165 : : void
166 : 40 : QofSessionImpl::load_backend (std::string access_method) noexcept
167 : : {
168 : 40 : std::ostringstream s;
169 : 40 : s << " list=" << s_providers.size();
170 : 40 : ENTER ("%s", s.str().c_str());
171 : 81 : for (auto const & prov : s_providers)
172 : : {
173 : 80 : if (!boost::iequals (access_method, prov->access_method))
174 : : {
175 : 38 : PINFO ("The provider providers access_method, %s, but we're loading for access_method, %s. Skipping.",
176 : : prov->access_method, access_method.c_str ());
177 : 38 : continue;
178 : : }
179 : 42 : PINFO (" Selected provider %s", prov->provider_name);
180 : : // Only do a type check when trying to open an existing file
181 : : // When saving over an existing file the contents of the original file don't matter
182 : 42 : if (!m_creating && !prov->type_check (m_uri.c_str ()))
183 : : {
184 : 3 : PINFO("Provider, %s, reported not being usable for book, %s.",
185 : : prov->provider_name, m_uri.c_str ());
186 : 3 : continue;
187 : : }
188 : 39 : m_backend = prov->create_backend();
189 : 39 : LEAVE (" ");
190 : 39 : return;
191 : : }
192 : 1 : std::string msg {"failed to get_backend using access method \"" + access_method + "\""};
193 : 1 : push_error (ERR_BACKEND_NO_HANDLER, msg);
194 : 1 : LEAVE (" ");
195 : 40 : }
196 : :
197 : : void
198 : 27 : QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
199 : : {
200 : : /* We must have an empty book to load into or bad things will happen. */
201 : 27 : g_return_if_fail(m_book && qof_book_empty(m_book));
202 : :
203 : 26 : if (!m_uri.size ()) return;
204 : 26 : ENTER ("sess=%p uri=%s", this, m_uri.c_str ());
205 : :
206 : : /* At this point, we should are supposed to have a valid book
207 : : * id and a lock on the file. */
208 : 26 : clear_error ();
209 : :
210 : : /* This code should be sufficient to initialize *any* backend,
211 : : * whether http, postgres, or anything else that might come along.
212 : : * Basically, the idea is that by now, a backend has already been
213 : : * created & set up. At this point, we only need to get the
214 : : * top-level account group out of the backend, and that is a
215 : : * generic, backend-independent operation.
216 : : */
217 : 26 : qof_book_set_backend (m_book, m_backend);
218 : :
219 : : /* Starting the session should result in a bunch of accounts
220 : : * and currencies being downloaded, but probably no transactions;
221 : : * The GUI will need to do a query for that.
222 : : */
223 : 26 : if (m_backend)
224 : : {
225 : 26 : m_backend->set_percentage(percentage_func);
226 : 26 : m_backend->load (m_book, LOAD_TYPE_INITIAL_LOAD);
227 : 26 : push_error (m_backend->get_error(), {});
228 : : }
229 : :
230 : 26 : auto err = get_error ();
231 : 26 : if ((err != ERR_BACKEND_NO_ERR) &&
232 : 2 : (err != ERR_FILEIO_FILE_TOO_OLD) &&
233 : 2 : (err != ERR_FILEIO_NO_ENCODING) &&
234 : 2 : (err != ERR_FILEIO_FILE_UPGRADE) &&
235 : 1 : (err != ERR_SQL_DB_TOO_OLD) &&
236 : : (err != ERR_SQL_DB_TOO_NEW))
237 : : {
238 : : // Something failed, delete and restore new ones.
239 : 0 : destroy_backend();
240 : 0 : qof_book_destroy (m_book);
241 : 0 : m_book = qof_book_new();
242 : 0 : LEAVE ("error from backend %d", get_error ());
243 : 0 : return;
244 : : }
245 : :
246 : 26 : LEAVE ("sess = %p, uri=%s", this, m_uri.c_str ());
247 : : }
248 : :
249 : : void
250 : 40 : QofSessionImpl::begin (const char* new_uri, SessionOpenMode mode) noexcept
251 : : {
252 : :
253 : :
254 : 40 : ENTER (" sess=%p mode=%d, URI=%s", this, mode, new_uri);
255 : 40 : clear_error ();
256 : : /* Check to see if this session is already open */
257 : 40 : if (m_uri.size ())
258 : : {
259 : 0 : if (ERR_BACKEND_NO_ERR != get_error ())
260 : 0 : push_error (ERR_BACKEND_LOCKED, {});
261 : 0 : LEAVE("push error book is already open ");
262 : 0 : return;
263 : : }
264 : :
265 : : /* seriously invalid */
266 : 40 : if (!new_uri)
267 : : {
268 : 0 : if (ERR_BACKEND_NO_ERR != get_error ())
269 : 0 : push_error (ERR_BACKEND_BAD_URL, {});
270 : 0 : LEAVE("push error missing new_uri");
271 : 0 : return;
272 : : }
273 : :
274 : 40 : char * scheme {g_uri_parse_scheme (new_uri)};
275 : 40 : char * filename {nullptr};
276 : 40 : if (g_strcmp0 (scheme, "file") == 0)
277 : 2 : filename = g_filename_from_uri (new_uri, nullptr, nullptr);
278 : 38 : else if (!scheme)
279 : 32 : filename = g_strdup (new_uri);
280 : :
281 : 40 : if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR))
282 : : {
283 : 0 : if (ERR_BACKEND_NO_ERR == get_error ())
284 : 0 : push_error (ERR_BACKEND_BAD_URL, {});
285 : 0 : g_free (filename);
286 : 0 : g_free (scheme);
287 : 0 : LEAVE("Can't open a directory");
288 : 0 : return;
289 : : }
290 : : /* destroy the old backend */
291 : 40 : destroy_backend ();
292 : : /* Store the session URL */
293 : 40 : m_uri = new_uri;
294 : 40 : m_creating = mode == SESSION_NEW_STORE || mode == SESSION_NEW_OVERWRITE;
295 : 40 : if (filename)
296 : 68 : load_backend ("file");
297 : : else /* access method found, load appropriate backend */
298 : 12 : load_backend (scheme);
299 : 40 : g_free (filename);
300 : 40 : g_free (scheme);
301 : :
302 : : /* No backend was found. That's bad. */
303 : 40 : if (m_backend == nullptr)
304 : : {
305 : 1 : m_uri = {};
306 : 1 : if (ERR_BACKEND_NO_ERR == get_error ())
307 : 0 : push_error (ERR_BACKEND_BAD_URL, {});
308 : 1 : LEAVE (" BAD: no backend: sess=%p book-id=%s",
309 : : this, new_uri);
310 : 1 : return;
311 : : }
312 : :
313 : : /* If there's a begin method, call that. */
314 : 39 : m_backend->session_begin(this, m_uri.c_str(), mode);
315 : 39 : PINFO ("Done running session_begin on backend");
316 : 39 : QofBackendError const err {m_backend->get_error()};
317 : 39 : auto msg (m_backend->get_message());
318 : 39 : if (err != ERR_BACKEND_NO_ERR)
319 : : {
320 : 2 : m_uri = {};
321 : 2 : push_error (err, msg);
322 : 2 : LEAVE (" backend error %d %s", err, msg.empty() ? "(null)" : msg.c_str());
323 : 2 : return;
324 : : }
325 : 37 : if (!msg.empty())
326 : : {
327 : 0 : PWARN("%s", msg.c_str());
328 : : }
329 : :
330 : 37 : LEAVE (" sess=%p book-id=%s", this, new_uri);
331 : 39 : }
332 : :
333 : : void
334 : 204 : QofSessionImpl::end () noexcept
335 : : {
336 : 204 : ENTER ("sess=%p uri=%s", this, m_uri.c_str ());
337 : 204 : auto backend = qof_book_get_backend (m_book);
338 : 204 : if (backend != nullptr)
339 : 42 : backend->session_end();
340 : 204 : clear_error ();
341 : 204 : m_uri.clear();
342 : 204 : LEAVE ("sess=%p uri=%s", this, m_uri.c_str ());
343 : 204 : }
344 : :
345 : : /* error handling functions --------------------------------*/
346 : :
347 : : void
348 : 300 : QofSessionImpl::clear_error () noexcept
349 : : {
350 : 300 : m_last_err = ERR_BACKEND_NO_ERR;
351 : 300 : m_error_message = {};
352 : :
353 : : /* pop the stack on the backend as well. */
354 : 300 : if (auto backend = qof_book_get_backend (m_book))
355 : : {
356 : 66 : QofBackendError err = ERR_BACKEND_NO_ERR;
357 : : do
358 : 66 : err = backend->get_error();
359 : 66 : while (err != ERR_BACKEND_NO_ERR);
360 : : }
361 : 300 : }
362 : :
363 : : void
364 : 30 : QofSessionImpl::push_error (QofBackendError const err, std::string message) noexcept
365 : : {
366 : 30 : m_last_err = err;
367 : 30 : m_error_message = message;
368 : 30 : }
369 : :
370 : : QofBackendError
371 : 109 : QofSessionImpl::get_error () noexcept
372 : : {
373 : : /* if we have a local error, return that. */
374 : 109 : if (m_last_err != ERR_BACKEND_NO_ERR)
375 : 9 : return m_last_err;
376 : 100 : auto qof_be = qof_book_get_backend (m_book);
377 : 100 : if (qof_be == nullptr) return ERR_BACKEND_NO_ERR;
378 : :
379 : 65 : m_last_err = qof_be->get_error();
380 : 65 : return m_last_err;
381 : : }
382 : :
383 : : const std::string&
384 : 0 : QofSessionImpl::get_error_message () const noexcept
385 : : {
386 : 0 : return m_error_message;
387 : : }
388 : :
389 : : QofBackendError
390 : 4 : QofSessionImpl::pop_error () noexcept
391 : : {
392 : 4 : QofBackendError err {get_error ()};
393 : 4 : clear_error ();
394 : 4 : return err;
395 : : }
396 : :
397 : : /* Accessors (getters/setters) -----------------------------*/
398 : :
399 : : QofBook *
400 : 41638 : QofSessionImpl::get_book () const noexcept
401 : : {
402 : 41638 : if (!m_book) return nullptr;
403 : 41638 : if ('y' == m_book->book_open)
404 : 41638 : return m_book;
405 : 0 : return nullptr;
406 : : }
407 : :
408 : : QofBackend *
409 : 3 : QofSession::get_backend () const noexcept
410 : : {
411 : 3 : return m_backend;
412 : : }
413 : :
414 : : const std::string&
415 : 0 : QofSessionImpl::get_file_path () const noexcept
416 : : {
417 : 0 : auto backend = qof_book_get_backend (m_book);
418 : 0 : if (!backend) return empty_string;
419 : 0 : return backend->get_uri();
420 : : }
421 : :
422 : : std::string const &
423 : 0 : QofSessionImpl::get_uri () const noexcept
424 : : {
425 : 0 : return m_uri;
426 : : }
427 : :
428 : : bool
429 : 0 : QofSessionImpl::is_saving () const noexcept
430 : : {
431 : 0 : return m_saving;
432 : : }
433 : :
434 : : /* Manipulators (save, load, etc.) -------------------------*/
435 : :
436 : : void
437 : 14 : QofSessionImpl::save (QofPercentageFunc percentage_func) noexcept
438 : : {
439 : 14 : if (!qof_book_session_not_saved (m_book)) //Clean book, nothing to do.
440 : 6 : return;
441 : 8 : m_saving = true;
442 : 8 : ENTER ("sess=%p uri=%s", this, m_uri.c_str ());
443 : :
444 : : /* If there is a backend, the book is dirty, and the backend is reachable
445 : : * (i.e. we can communicate with it), then synchronize with the backend. If
446 : : * we cannot contact the backend (e.g. because we've gone offline, the
447 : : * network has crashed, etc.) then raise an error so that the controlling
448 : : * dialog can offer the user a chance to save in a different way.
449 : : */
450 : 8 : if (m_backend)
451 : : {
452 : : /* if invoked as SaveAs(), then backend not yet set */
453 : 8 : if (qof_book_get_backend (m_book) != m_backend)
454 : 8 : qof_book_set_backend (m_book, m_backend);
455 : 8 : m_backend->set_percentage(percentage_func);
456 : 8 : m_backend->sync(m_book);
457 : 8 : auto err = m_backend->get_error();
458 : 8 : if (err != ERR_BACKEND_NO_ERR)
459 : : {
460 : 0 : push_error (err, {});
461 : 0 : m_saving = false;
462 : 0 : return;
463 : : }
464 : : /* If we got to here, then the backend saved everything
465 : : * just fine, and we are done. So return. */
466 : 8 : clear_error ();
467 : 8 : LEAVE("Success");
468 : : }
469 : : else
470 : : {
471 : 0 : push_error (ERR_BACKEND_NO_HANDLER, "failed to load backend");
472 : 0 : LEAVE("error -- No backend!");
473 : : }
474 : 8 : m_saving = false;
475 : : }
476 : :
477 : : void
478 : 1 : QofSessionImpl::safe_save (QofPercentageFunc percentage_func) noexcept
479 : : {
480 : 1 : if (!(m_backend && m_book)) return;
481 : 1 : if (qof_book_get_backend (m_book) != m_backend)
482 : 0 : qof_book_set_backend (m_book, m_backend);
483 : 1 : m_backend->set_percentage(percentage_func);
484 : 1 : m_backend->safe_sync(get_book ());
485 : 1 : auto err = m_backend->get_error();
486 : 1 : auto msg = m_backend->get_message();
487 : 1 : if (err != ERR_BACKEND_NO_ERR)
488 : : {
489 : 0 : m_uri = "";
490 : 0 : push_error (err, msg);
491 : : }
492 : 1 : }
493 : :
494 : : void
495 : 1 : QofSessionImpl::ensure_all_data_loaded () noexcept
496 : : {
497 : 1 : if (!(m_backend && m_book)) return;
498 : 1 : if (qof_book_get_backend (m_book) != m_backend)
499 : 0 : qof_book_set_backend (m_book, m_backend);
500 : 1 : m_backend->load(m_book, LOAD_TYPE_LOAD_ALL);
501 : 1 : push_error (m_backend->get_error(), {});
502 : : }
503 : :
504 : : void
505 : 8 : QofSessionImpl::swap_books (QofSessionImpl & other) noexcept
506 : : {
507 : 8 : ENTER ("sess1=%p sess2=%p", this, &other);
508 : : // don't swap (that is, double-swap) read_only flags
509 : 8 : if (m_book && other.m_book)
510 : 3 : std::swap (m_book->read_only, other.m_book->read_only);
511 : 8 : std::swap (m_book, other.m_book);
512 : 8 : auto mybackend = qof_book_get_backend (m_book);
513 : 8 : qof_book_set_backend (m_book, qof_book_get_backend (other.m_book));
514 : 8 : qof_book_set_backend (other.m_book, mybackend);
515 : 8 : LEAVE (" ");
516 : 8 : }
517 : :
518 : : bool
519 : 0 : QofSessionImpl::events_pending () const noexcept
520 : : {
521 : 0 : return false;
522 : : }
523 : :
524 : : bool
525 : 0 : QofSessionImpl::process_events () const noexcept
526 : : {
527 : 0 : return false;
528 : : }
529 : :
530 : : /* XXX This exports the list of accounts to a file. It does not
531 : : * export any transactions. It's a place-holder until full
532 : : * book-closing is implemented.
533 : : */
534 : : bool
535 : 0 : QofSessionImpl::export_session (QofSessionImpl & real_session,
536 : : QofPercentageFunc percentage_func) noexcept
537 : : {
538 : 0 : auto real_book = real_session.get_book ();
539 : 0 : ENTER ("tmp_session=%p real_session=%p book=%p uri=%s",
540 : : this, &real_session, real_book, m_uri.c_str ());
541 : :
542 : : /* There must be a backend or else. (It should always be the file
543 : : * backend too.)
544 : : */
545 : 0 : if (!m_backend) return false;
546 : :
547 : 0 : m_backend->set_percentage(percentage_func);
548 : :
549 : 0 : m_backend->export_coa(real_book);
550 : 0 : auto err = m_backend->get_error();
551 : 0 : if (err != ERR_BACKEND_NO_ERR)
552 : 0 : return false;
553 : 0 : return true;
554 : : }
555 : :
556 : : /* C Wrapper Functions */
557 : : /* ====================================================================== */
558 : :
559 : : const char *
560 : 0 : qof_session_get_error_message (const QofSession * session)
561 : : {
562 : 0 : if (!session) return "";
563 : 0 : return session->get_error_message ().c_str ();
564 : : }
565 : :
566 : : QofBackendError
567 : 4 : qof_session_pop_error (QofSession * session)
568 : : {
569 : 4 : if (!session) return ERR_BACKEND_NO_BACKEND;
570 : 4 : return session->pop_error ();
571 : : }
572 : :
573 : : QofBook *
574 : 41637 : qof_session_get_book (const QofSession *session)
575 : : {
576 : 41637 : if (!session) return NULL;
577 : 41637 : return session->get_book ();
578 : : }
579 : :
580 : : const char *
581 : 0 : qof_session_get_file_path (const QofSession *session)
582 : : {
583 : 0 : if (!session) return nullptr;
584 : 0 : auto& path{session->get_file_path()};
585 : 0 : return path.empty() ? nullptr : path.c_str ();
586 : : }
587 : :
588 : : void
589 : 1 : qof_session_ensure_all_data_loaded (QofSession *session)
590 : : {
591 : 1 : if (session == nullptr) return;
592 : 1 : return session->ensure_all_data_loaded ();
593 : : }
594 : :
595 : : const char *
596 : 0 : qof_session_get_url (const QofSession *session)
597 : : {
598 : 0 : if (!session) return NULL;
599 : 0 : return session->get_uri ().c_str ();
600 : : }
601 : :
602 : : QofBackend *
603 : 3 : qof_session_get_backend (const QofSession *session)
604 : : {
605 : 3 : if (!session) return NULL;
606 : 3 : return session->get_backend ();
607 : : }
608 : :
609 : : void
610 : 40 : qof_session_begin (QofSession *session, const char * uri, SessionOpenMode mode)
611 : : {
612 : 40 : if (!session) return;
613 : 40 : session->begin(uri, mode);
614 : : }
615 : :
616 : : void
617 : 27 : qof_session_load (QofSession *session,
618 : : QofPercentageFunc percentage_func)
619 : : {
620 : 27 : if (!session) return;
621 : 27 : session->load (percentage_func);
622 : : }
623 : :
624 : : void
625 : 14 : qof_session_save (QofSession *session,
626 : : QofPercentageFunc percentage_func)
627 : : {
628 : 14 : if (!session) return;
629 : 14 : session->save (percentage_func);
630 : : }
631 : :
632 : : void
633 : 1 : qof_session_safe_save(QofSession *session, QofPercentageFunc percentage_func)
634 : : {
635 : 1 : if (!session) return;
636 : 1 : session->safe_save (percentage_func);
637 : : }
638 : :
639 : : gboolean
640 : 0 : qof_session_save_in_progress(const QofSession *session)
641 : : {
642 : 0 : if (!session) return false;
643 : 0 : return session->is_saving ();
644 : : }
645 : :
646 : : void
647 : 65 : qof_session_end (QofSession *session)
648 : : {
649 : 65 : if (!session) return;
650 : 65 : session->end ();
651 : : }
652 : :
653 : : void
654 : 8 : qof_session_swap_data (QofSession *session_1, QofSession *session_2)
655 : : {
656 : 8 : if (session_1 == session_2) return;
657 : 8 : if (!session_1 || !session_2) return;
658 : 8 : session_1->swap_books (*session_2);
659 : : }
660 : :
661 : : gboolean
662 : 0 : qof_session_events_pending (const QofSession *session)
663 : : {
664 : 0 : if (!session) return false;
665 : 0 : return session->events_pending ();
666 : : }
667 : :
668 : : gboolean
669 : 0 : qof_session_process_events (QofSession *session)
670 : : {
671 : 0 : if (!session) return FALSE;
672 : 0 : return session->process_events ();
673 : : }
674 : :
675 : : gboolean
676 : 0 : qof_session_export (QofSession *tmp_session,
677 : : QofSession *real_session,
678 : : QofPercentageFunc percentage_func)
679 : : {
680 : 0 : if ((!tmp_session) || (!real_session)) return FALSE;
681 : 0 : return tmp_session->export_session (*real_session, percentage_func);
682 : : }
683 : :
684 : : /* ================= Static function access for testing ================= */
685 : :
686 : : void init_static_qofsession_pointers (void);
687 : :
688 : 0 : void qof_session_load_backend (QofSession * session, const char * access_method)
689 : : {
690 : 0 : session->load_backend (access_method);
691 : 0 : }
692 : :
693 : : static void
694 : 0 : qof_session_clear_error (QofSession * session)
695 : : {
696 : 0 : session->clear_error ();
697 : 0 : }
698 : :
699 : : static void
700 : 0 : qof_session_destroy_backend (QofSession * session)
701 : : {
702 : 0 : session->destroy_backend ();
703 : 0 : }
704 : :
705 : 0 : void qof_session_set_uri (QofSession * session, char const * uri)
706 : : {
707 : 0 : if (!uri)
708 : 0 : session->m_uri = "";
709 : : else
710 : 0 : session->m_uri = uri;
711 : 0 : }
712 : :
713 : : void (*p_qof_session_load_backend) (QofSession *, const char * access_method);
714 : : void (*p_qof_session_clear_error) (QofSession *);
715 : : void (*p_qof_session_destroy_backend) (QofSession *);
716 : : void (*p_qof_session_set_uri) (QofSession *, char const * uri);
717 : :
718 : : void
719 : 0 : init_static_qofsession_pointers (void)
720 : : {
721 : 0 : p_qof_session_load_backend = &qof_session_load_backend;
722 : 0 : p_qof_session_clear_error = &qof_session_clear_error;
723 : 0 : p_qof_session_destroy_backend = &qof_session_destroy_backend;
724 : 0 : p_qof_session_set_uri = &qof_session_set_uri;
725 : 0 : }
726 : :
727 : : QofBackendError
728 : 78 : qof_session_get_error (QofSession * session)
729 : : {
730 : 78 : if (!session) return ERR_BACKEND_NO_BACKEND;
731 : 78 : return session->get_error();
732 : : }
|