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