gboolean qof_commit_edit_part2(QofInstance *inst, void (*on_error)(QofInstance *, QofBackendError), void (*on_done)(QofInstance *), void (*on_free)(QofInstance *)) { QofInstancePrivate *priv; QofBackend * be; gboolean dirty; priv = GET_PRIVATE(inst); dirty = priv->dirty; /* See if there's a backend. If there is, invoke it. */ be = qof_book_get_backend(priv->book); if (be && qof_backend_commit_exists(be)) { QofBackendError errcode; /* clear errors */ do { errcode = qof_backend_get_error(be); } while (ERR_BACKEND_NO_ERR != errcode); qof_backend_run_commit(be, inst); errcode = qof_backend_get_error(be); if (ERR_BACKEND_NO_ERR != errcode) { /* XXX Should perform a rollback here */ priv->do_free = FALSE; /* Push error back onto the stack */ qof_backend_set_error (be, errcode); if (on_error) on_error(inst, errcode); return FALSE; } /* XXX the backend commit code should clear dirty!! */ priv->dirty = FALSE; } // if (dirty && qof_get_alt_dirty_mode() && // !(priv->infant && priv->do_free)) { // qof_collection_mark_dirty(priv->collection); // qof_book_mark_dirty(priv->book); // } priv->infant = FALSE; if (priv->do_free) { if (on_free) on_free(inst); return TRUE; } if (on_done) on_done(inst); return TRUE; }
static gboolean save_error_handler(QofBackend *be, QofSession *session) { QofBackendError err; err = qof_backend_get_error(be); if (ERR_BACKEND_NO_ERR != err) { qof_session_push_error (session, err, NULL); return TRUE; } return FALSE; }
void qof_session_ensure_all_data_loaded (QofSession *session) { QofBackend* backend; if (session == NULL) return; backend = qof_session_get_backend(session); if (backend == NULL) return; if (backend->load == NULL) return; backend->load(backend, qof_session_get_book(session), LOAD_TYPE_LOAD_ALL); qof_session_push_error (session, qof_backend_get_error(backend), NULL); }
static void qof_session_clear_error (QofSession *session) { QofBackendError err; session->last_err = ERR_BACKEND_NO_ERR; g_free(session->error_message); session->error_message = NULL; /* pop the stack on the backend as well. */ if (session->backend) { do { err = qof_backend_get_error (session->backend); } while (ERR_BACKEND_NO_ERR != err); } }
void qof_session_safe_save(QofSession *session, QofPercentageFunc percentage_func) { QofBackend *be = session->backend; gint err; char *msg = NULL; g_return_if_fail( be != NULL ); g_return_if_fail( be->safe_sync != NULL ); be->percentage = percentage_func; (be->safe_sync)( be, qof_session_get_book( session )); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); } }
QofBackendError qof_session_get_error (QofSession * session) { QofBackendError err; if (!session) return ERR_BACKEND_NO_BACKEND; /* if we have a local error, return that. */ if (ERR_BACKEND_NO_ERR != session->last_err) { return session->last_err; } /* maybe we should return a no-backend error ??? */ if (! session->backend) return ERR_BACKEND_NO_ERR; err = qof_backend_get_error (session->backend); session->last_err = err; return err; }
/* XXX This exports the list of accounts to a file. It does not * export any transactions. It's a place-holder until full * book-closing is implemented. */ gboolean qof_session_export (QofSession *tmp_session, QofSession *real_session, QofPercentageFunc percentage_func) { QofBook *book, *book2; QofBackend *be; if ((!tmp_session) || (!real_session)) return FALSE; book = qof_session_get_book (real_session); ENTER ("tmp_session=%p real_session=%p book=%p book_id=%s", tmp_session, real_session, book, qof_session_get_url(tmp_session) ? qof_session_get_url(tmp_session) : "(null)"); /* There must be a backend or else. (It should always be the file * backend too.) */ book2 = qof_session_get_book(tmp_session); be = qof_book_get_backend(book2); if (!be) return FALSE; be->percentage = percentage_func; if (be->export_fn) { int err; (be->export_fn)(be, book); err = qof_backend_get_error(be); if (ERR_BACKEND_NO_ERR != err) { return FALSE; } } return TRUE; }
void qof_session_load (QofSession *session, QofPercentageFunc percentage_func) { QofBook *newbook, *oldbook; QofBackend *be; QofBackendError err; if (!session) return; if (!session->book_id) return; ENTER ("sess=%p book_id=%s", session, session->book_id ? session->book_id : "(null)"); /* At this point, we should are supposed to have a valid book * id and a lock on the file. */ oldbook = session->book; /* XXX why are we creating a book here? I think the books * need to be handled by the backend ... especially since * the backend may need to load multiple books ... XXX. FIXME. */ newbook = qof_book_new(); session->book = newbook; PINFO ("new book=%p", newbook); qof_session_clear_error (session); /* This code should be sufficient to initialize *any* backend, * whether http, postgres, or anything else that might come along. * Basically, the idea is that by now, a backend has already been * created & set up. At this point, we only need to get the * top-level account group out of the backend, and that is a * generic, backend-independent operation. */ be = session->backend; qof_book_set_backend(newbook, be); /* Starting the session should result in a bunch of accounts * and currencies being downloaded, but probably no transactions; * The GUI will need to do a query for that. */ if (be) { be->percentage = percentage_func; if (be->load) { be->load (be, newbook, LOAD_TYPE_INITIAL_LOAD); qof_session_push_error (session, qof_backend_get_error(be), NULL); } } /* XXX if the load fails, then we try to restore the old set of books; * however, we don't undo the session id (the URL). Thus if the * user attempts to save after a failed load, they weill be trying to * save to some bogus URL. This is wrong. XXX FIXME. */ err = qof_session_get_error(session); if ((err != ERR_BACKEND_NO_ERR) && (err != ERR_FILEIO_FILE_TOO_OLD) && (err != ERR_FILEIO_NO_ENCODING) && (err != ERR_FILEIO_FILE_UPGRADE) && (err != ERR_SQL_DB_TOO_OLD) && (err != ERR_SQL_DB_TOO_NEW)) { /* Something broke, put back the old stuff */ qof_book_set_backend (newbook, NULL); qof_book_destroy (newbook); session->book = oldbook; LEAVE("error from backend %d", qof_session_get_error(session)); return; } qof_book_set_backend (oldbook, NULL); qof_book_destroy (oldbook); LEAVE ("sess = %p, book_id=%s", session, session->book_id ? session->book_id : "(null)"); }
void qof_session_begin (QofSession *session, const char * book_id, gboolean ignore_lock, gboolean create, gboolean force) { gchar *scheme = NULL, *filename = NULL; if (!session) return; ENTER (" sess=%p ignore_lock=%d, book-id=%s", session, ignore_lock, book_id ? book_id : "(null)"); /* Clear the error condition of previous errors */ qof_session_clear_error (session); /* Check to see if this session is already open */ if (session->book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL); LEAVE("push error book is already open "); return; } /* seriously invalid */ if (!book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE("push error missing book_id"); return; } scheme = g_uri_parse_scheme (book_id); if (g_strcmp0 (scheme, "file") == 0) filename = g_filename_from_uri (book_id, NULL, NULL); else if (!scheme) filename = g_strdup (book_id); if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR)) { if (ERR_BACKEND_NO_ERR == qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); g_free (filename); g_free (scheme); LEAVE("Can't open a directory"); return; } /* destroy the old backend */ qof_session_destroy_backend(session); /* Store the session URL */ session->book_id = g_strdup (book_id); if (filename) qof_session_load_backend(session, "file"); else /* access method found, load appropriate backend */ qof_session_load_backend(session, scheme); g_free (filename); g_free (scheme); /* No backend was found. That's bad. */ if (NULL == session->backend) { g_free(session->book_id); session->book_id = NULL; if (ERR_BACKEND_NO_ERR == qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE (" BAD: no backend: sess=%p book-id=%s", session, book_id ? book_id : "(null)"); return; } /* If there's a begin method, call that. */ if (session->backend->session_begin) { char *msg; QofBackendError err; (session->backend->session_begin)(session->backend, session, session->book_id, ignore_lock, create, force); PINFO("Done running session_begin on backend"); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE(" backend error %d %s", err, msg ? msg : "(null)"); return; } if (msg != NULL) { PWARN("%s", msg); g_free(msg); } } LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)"); }
void qof_session_save (QofSession *session, QofPercentageFunc percentage_func) { GList *node; QofBackend *be; gboolean partial, change_backend; QofBackendProvider *prov; GSList *p; QofBook *book, *abook; int err; gint num; char *msg = NULL; char *book_id; if (!session) return; if (!g_atomic_int_dec_and_test(&session->lock)) goto leave; ENTER ("sess=%p book_id=%s", session, session->book_id ? session->book_id : "(null)"); /* Partial book handling. */ book = qof_session_get_book(session); partial = (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK)); change_backend = FALSE; msg = g_strdup_printf(" "); book_id = g_strdup(session->book_id); if (partial == TRUE) { if (session->backend && session->backend->provider) { prov = session->backend->provider; if (TRUE == prov->partial_book_supported) { /* if current backend supports partial, leave alone. */ change_backend = FALSE; } else { change_backend = TRUE; } } /* If provider is undefined, assume partial not supported. */ else { change_backend = TRUE; } } if (change_backend == TRUE) { qof_session_destroy_backend(session); if (!qof_providers_initialized) { qof_providers_initialized = TRUE; } p = provider_list; while (p != NULL) { prov = p->data; if (TRUE == prov->partial_book_supported) { /** \todo check the access_method too, not in scope here, yet. */ /* if((TRUE == prov->partial_book_supported) && (0 == g_ascii_strcasecmp (access_method, prov->access_method))) {*/ if (NULL == prov->backend_new) continue; /* Use the providers creation callback */ session->backend = (*(prov->backend_new))(); session->backend->provider = prov; if (session->backend->session_begin) { /* Call begin - backend has been changed, so make sure a file can be written, use ignore_lock and force create */ g_free(session->book_id); session->book_id = NULL; (session->backend->session_begin)(session->backend, session, book_id, TRUE, TRUE, TRUE); PINFO("Done running session_begin on changed backend"); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE("changed backend error %d", err); goto leave; } if (msg != NULL) { PWARN("%s", msg); g_free(msg); msg = NULL; } } /* Tell the books about the backend that they'll be using. */ for (node = session->books; node; node = node->next) { book = node->data; qof_book_set_backend (book, session->backend); } p = NULL; } if (p) { p = p->next; } } if (!session->backend) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) { msg = g_strdup_printf("failed to load backend"); qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); } goto leave; } } /* If there is a backend, and the backend is reachable * (i.e. we can communicate with it), then synchronize with * the backend. If we cannot contact the backend (e.g. * because we've gone offline, the network has crashed, etc.) * then give the user the option to save to the local disk. * * hack alert -- FIXME -- XXX the code below no longer * does what the words above say. This needs fixing. */ be = session->backend; if (be) { for (node = session->books; node; node = node->next) { abook = node->data; /* if invoked as SaveAs(), then backend not yet set */ qof_book_set_backend (abook, be); be->percentage = percentage_func; if (be->sync) { (be->sync)(be, abook); if (save_error_handler(be, session)) goto leave; } } /* If we got to here, then the backend saved everything * just fine, and we are done. So return. */ /* Return the book_id to previous value. */ qof_session_clear_error (session); LEAVE("Success"); goto leave; } else { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) { msg = g_strdup_printf("failed to load backend"); qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); } } LEAVE("error -- No backend!"); leave: if (msg != NULL) g_free(msg); g_atomic_int_inc(&session->lock); return; }
void qof_session_begin (QofSession *session, const char * book_id, gboolean ignore_lock, gboolean create, gboolean force) { gchar **splituri; if (!session) return; ENTER (" sess=%p ignore_lock=%d, book-id=%s", session, ignore_lock, book_id ? book_id : "(null)"); /* Clear the error condition of previous errors */ qof_session_clear_error (session); /* Check to see if this session is already open */ if (session->book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL); LEAVE("push error book is already open "); return; } /* seriously invalid */ if (!book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE("push error missing book_id"); return; } /* destroy the old backend */ qof_session_destroy_backend(session); /* Store the session URL */ session->book_id = g_strdup (book_id); /* Look for something of the form of "file://", "http://" or * "postgres://". Everything before the colon is the access * method. Load the first backend found for that access method. */ splituri = g_strsplit ( book_id, "://", 2 ); if ( splituri[1] == NULL ) /* no access method in the uri, use generic "file" backend */ qof_session_load_backend(session, "file"); else /* access method found, load appropriate backend */ qof_session_load_backend(session, splituri[0]); g_strfreev ( splituri ); /* No backend was found. That's bad. */ if (NULL == session->backend) { g_free(session->book_id); session->book_id = NULL; if (ERR_BACKEND_NO_ERR == qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE (" BAD: no backend: sess=%p book-id=%s", session, book_id ? book_id : "(null)"); return; } /* If there's a begin method, call that. */ if (session->backend->session_begin) { char *msg; int err; (session->backend->session_begin)(session->backend, session, session->book_id, ignore_lock, create, force); PINFO("Done running session_begin on backend"); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE(" backend error %d %s", err, msg ? msg : "(null)"); return; } if (msg != NULL) { PWARN("%s", msg); g_free(msg); } } LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)"); }