GnuCash 2.4.99
qofsession.c
Go to the documentation of this file.
00001 /********************************************************************\
00002  * qofsesssion.c -- session access (connection to backend)          *
00003  *                                                                  *
00004  * This program is free software; you can redistribute it and/or    *
00005  * modify it under the terms of the GNU General Public License as   *
00006  * published by the Free Software Foundation; either version 2 of   *
00007  * the License, or (at your option) any later version.              *
00008  *                                                                  *
00009  * This program is distributed in the hope that it will be useful,  *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00012  * GNU General Public License for more details.                     *
00013  *                                                                  *
00014  * You should have received a copy of the GNU General Public License*
00015  * along with this program; if not, contact:                        *
00016  *                                                                  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942       *
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00020 \********************************************************************/
00021 
00034 #include "config.h"
00035 
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #ifdef HAVE_UNISTD_H
00041 # include <unistd.h>
00042 #else
00043 # ifdef __GNUC__
00044 #  warning "<unistd.h> required."
00045 # endif
00046 #endif
00047 
00048 #include <glib.h>
00049 #include "qof.h"
00050 #include "qofbackend-p.h"
00051 #include "qofbook-p.h"
00052 #include "qofsession-p.h"
00053 #include "qofobject-p.h"
00054 
00055 static GHookList * session_closed_hooks = NULL;
00056 static QofLogModule log_module = QOF_MOD_SESSION;
00057 static GSList *provider_list = NULL;
00058 static gboolean qof_providers_initialized = FALSE;
00059 
00060 /*
00061  * These getters are used in tests to reach static vars from outside
00062  * They should be removed when no longer needed
00063  */
00064 
00065 GHookList* get_session_closed_hooks (void );
00066 GSList* get_provider_list (void );
00067 gboolean get_qof_providers_initialized (void );
00068 void unregister_all_providers (void );
00069 
00070 GHookList*
00071 get_session_closed_hooks (void)
00072 {
00073     return session_closed_hooks;
00074 }
00075 
00076 GSList*
00077 get_provider_list (void)
00078 {
00079     return provider_list;
00080 }
00081 
00082 gboolean
00083 get_qof_providers_initialized (void)
00084 {
00085     return qof_providers_initialized;
00086 }
00087 
00088 void
00089 unregister_all_providers (void)
00090 {
00091     if (provider_list)
00092     {
00093         g_slist_foreach (provider_list, (GFunc) g_free, NULL);
00094         g_slist_free (provider_list);
00095         provider_list = NULL;
00096     }
00097 }
00098 
00099 /* ====================================================================== */
00100 
00101 void
00102 qof_backend_register_provider (QofBackendProvider *prov)
00103 {
00104     provider_list = g_slist_append (provider_list, prov);
00105 }
00106 
00107 GList*
00108 qof_backend_get_registered_access_method_list(void)
00109 {
00110     GList* list = NULL;
00111     GSList* node;
00112 
00113     for ( node = provider_list; node != NULL; node = node->next )
00114     {
00115         QofBackendProvider *prov = node->data;
00116         list = g_list_append( list, (gchar*)prov->access_method );
00117     }
00118 
00119     return list;
00120 }
00121 
00122 /* ====================================================================== */
00123 
00124 /* hook routines */
00125 
00126 void
00127 qof_session_add_close_hook (GFunc fn, gpointer data)
00128 {
00129     GHook *hook;
00130 
00131     if (session_closed_hooks == NULL)
00132     {
00133         session_closed_hooks = malloc(sizeof(GHookList)); /* LEAKED */
00134         g_hook_list_init (session_closed_hooks, sizeof(GHook));
00135     }
00136 
00137     hook = g_hook_alloc(session_closed_hooks);
00138     if (!hook)
00139         return;
00140 
00141     hook->func = (GHookFunc)fn;
00142     hook->data = data;
00143     g_hook_append(session_closed_hooks, hook);
00144 }
00145 
00146 void
00147 qof_session_call_close_hooks (QofSession *session)
00148 {
00149     GHook *hook;
00150     GFunc fn;
00151 
00152     if (session_closed_hooks == NULL)
00153         return;
00154 
00155     hook = g_hook_first_valid (session_closed_hooks, FALSE);
00156     while (hook)
00157     {
00158         fn = (GFunc)hook->func;
00159         fn(session, hook->data);
00160         hook = g_hook_next_valid (session_closed_hooks, hook, FALSE);
00161     }
00162 }
00163 
00164 /* ====================================================================== */
00165 /* error handling routines */
00166 
00167 static void
00168 qof_session_clear_error (QofSession *session)
00169 {
00170     QofBackendError err;
00171 
00172     session->last_err = ERR_BACKEND_NO_ERR;
00173     g_free(session->error_message);
00174     session->error_message = NULL;
00175 
00176     /* pop the stack on the backend as well. */
00177     if (session->backend)
00178     {
00179         do
00180         {
00181             err = qof_backend_get_error (session->backend);
00182         }
00183         while (ERR_BACKEND_NO_ERR != err);
00184     }
00185 }
00186 
00187 void
00188 qof_session_push_error (QofSession *session, QofBackendError err,
00189                         const char *message)
00190 {
00191     if (!session) return;
00192 
00193     g_free (session->error_message);
00194 
00195     session->last_err = err;
00196     session->error_message = g_strdup (message);
00197 }
00198 
00199 QofBackendError
00200 qof_session_get_error (QofSession * session)
00201 {
00202     QofBackendError err;
00203 
00204     if (!session) return ERR_BACKEND_NO_BACKEND;
00205 
00206     /* if we have a local error, return that. */
00207     if (ERR_BACKEND_NO_ERR != session->last_err)
00208     {
00209         return session->last_err;
00210     }
00211 
00212     /* maybe we should return a no-backend error ??? */
00213     if (! session->backend) return ERR_BACKEND_NO_ERR;
00214 
00215     err = qof_backend_get_error (session->backend);
00216     session->last_err = err;
00217     return err;
00218 }
00219 
00220 static const char *
00221 get_default_error_message(QofBackendError err)
00222 {
00223     return "";
00224 }
00225 
00226 const char *
00227 qof_session_get_error_message(const QofSession *session)
00228 {
00229     if (!session) return "";
00230     if (!session->error_message)
00231         return get_default_error_message(session->last_err);
00232     return session->error_message;
00233 }
00234 
00235 QofBackendError
00236 qof_session_pop_error (QofSession * session)
00237 {
00238     QofBackendError err;
00239 
00240     if (!session) return ERR_BACKEND_NO_BACKEND;
00241 
00242     err = qof_session_get_error(session);
00243     qof_session_clear_error(session);
00244 
00245     return err;
00246 }
00247 
00248 /* ====================================================================== */
00249 
00250 static void
00251 qof_session_init (QofSession *session)
00252 {
00253     if (!session) return;
00254 
00255     session->entity.e_type = QOF_ID_SESSION;
00256     session->book = qof_book_new ();
00257     session->book_id = NULL;
00258     session->backend = NULL;
00259     session->lock = 1;
00260 
00261     qof_session_clear_error (session);
00262 }
00263 
00264 QofSession *
00265 qof_session_new (void)
00266 {
00267     QofSession *session = g_new0(QofSession, 1);
00268     qof_session_init(session);
00269     return session;
00270 }
00271 
00272 QofBook *
00273 qof_session_get_book (const QofSession *session)
00274 {
00275     GList *node;
00276     if (!session) return NULL;
00277     if (!session->book) return NULL;
00278 
00279     if ('y' == session->book->book_open)
00280     {
00281         return session->book;
00282     }
00283     else
00284     {
00285         return NULL;
00286     }
00287 }
00288 
00289 QofBackend *
00290 qof_session_get_backend (const QofSession *session)
00291 {
00292     if (!session) return NULL;
00293     return session->backend;
00294 }
00295 
00296 const char *
00297 qof_session_get_file_path (const QofSession *session)
00298 {
00299     if (!session) return NULL;
00300     if (!session->backend) return NULL;
00301     return session->backend->fullpath;
00302 }
00303 
00304 const char *
00305 qof_session_get_url (const QofSession *session)
00306 {
00307     if (!session) return NULL;
00308     return session->book_id;
00309 }
00310 
00311 void
00312 qof_session_ensure_all_data_loaded (QofSession *session)
00313 {
00314     QofBackend* backend;
00315 
00316     if (session == NULL) return;
00317     backend = qof_session_get_backend(session);
00318     if (backend == NULL) return;
00319 
00320     if (backend->load == NULL) return;
00321     backend->load(backend, qof_session_get_book(session), LOAD_TYPE_LOAD_ALL);
00322     qof_session_push_error (session, qof_backend_get_error(backend), NULL);
00323 }
00324 
00325 /* =============================================================== */
00326 
00327 static void
00328 qof_book_set_partial (QofBook *book)
00329 {
00330     gboolean partial;
00331 
00332     partial =
00333         (gboolean)GPOINTER_TO_INT (qof_book_get_data (book, PARTIAL_QOFBOOK));
00334     if (!partial)
00335     {
00336         qof_book_set_data (book, PARTIAL_QOFBOOK, GINT_TO_POINTER (TRUE));
00337     }
00338 }
00339 
00347 static void
00348 qof_session_update_reference_list (QofSession *session,
00349                                    QofInstanceReference *reference)
00350 {
00351     QofBook  *book;
00352     GList    *book_ref_list;
00353 
00354     book = qof_session_get_book (session);
00355     book_ref_list = (GList*)qof_book_get_data (book, ENTITYREFERENCE);
00356     book_ref_list = g_list_append (book_ref_list, reference);
00357     qof_book_set_data (book, ENTITYREFERENCE, book_ref_list);
00358     qof_book_set_partial (book);
00359 }
00360 
00361 static void
00362 qof_instance_param_cb (QofParam *param, gpointer data)
00363 {
00364     QofInstanceCopyData *qecd;
00365 
00366     g_return_if_fail (data != NULL);
00367     qecd = (QofInstanceCopyData*)data;
00368     g_return_if_fail (param != NULL);
00369     /* KVP doesn't need a set routine to be copied. */
00370     if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
00371     {
00372         qecd->param_list = g_slist_prepend (qecd->param_list, param);
00373         return;
00374     }
00375     if ((param->param_getfcn != NULL) && (param->param_setfcn != NULL))
00376     {
00377         qecd->param_list = g_slist_prepend (qecd->param_list, param);
00378     }
00379 }
00380 
00381 static void
00382 col_ref_cb (QofInstance* ref_ent, gpointer user_data)
00383 {
00384     QofInstanceReference *ref;
00385     QofInstanceCopyData  *qecd;
00386     QofInstance *ent;
00387     const GncGUID   *cm_guid;
00388     char         cm_sa[GUID_ENCODING_LENGTH + 1];
00389     gchar        *cm_string;
00390 
00391     g_return_if_fail (user_data);
00392     qecd = (QofInstanceCopyData*)user_data;
00393     ent = qecd->from;
00394     g_return_if_fail (ent);
00395     ref = g_new0 (QofInstanceReference, 1);
00396     ref->type = ent->e_type;
00397     ref->ref_guid = g_new (GncGUID, 1);
00398     ref->ent_guid = qof_instance_get_guid (ent);
00399     ref->param = qof_class_get_parameter (ent->e_type,
00400                                           qecd->param->param_name);
00401     cm_guid = qof_entity_get_guid (ref_ent);
00402     guid_to_string_buff (cm_guid, cm_sa);
00403     cm_string = g_strdup (cm_sa);
00404     if (TRUE == string_to_guid (cm_string, ref->ref_guid))
00405     {
00406         g_free (cm_string);
00407         qof_session_update_reference_list (qecd->new_session, ref);
00408     }
00409 }
00410 
00411 static void
00412 qof_instance_foreach_copy (gpointer data, gpointer user_data)
00413 {
00414     QofInstance          *importEnt, *targetEnt/*, *referenceEnt*/;
00415     QofInstanceCopyData         *context;
00416     QofInstanceReference  *reference;
00417     gboolean            registered_type;
00418     /* cm_ prefix used for variables that hold the data to commit */
00419     QofParam            *cm_param;
00420     gchar                       *cm_string, *cm_char;
00421     const GncGUID               *cm_guid;
00422     KvpFrame            *cm_kvp;
00423     QofCollection *cm_col;
00424     /* function pointers and variables for parameter getters that don't
00425      * use pointers normally */
00426     gnc_numeric cm_numeric, (*numeric_getter) (QofInstance*, QofParam*);
00427     double cm_double, (*double_getter) (QofInstance*, QofParam*);
00428     gboolean cm_boolean, (*boolean_getter) (QofInstance*, QofParam*);
00429     gint32 cm_i32, (*int32_getter) (QofInstance*, QofParam*);
00430     gint64 cm_i64, (*int64_getter) (QofInstance*, QofParam*);
00431     Timespec cm_date, (*date_getter) (QofInstance*, QofParam*);
00432     /* function pointers to the parameter setters */
00433     void (*string_setter) (QofInstance*, const char*);
00434     void (*date_setter) (QofInstance*, Timespec);
00435     void (*numeric_setter) (QofInstance*, gnc_numeric);
00436     void (*guid_setter) (QofInstance*, const GncGUID*);
00437     void (*double_setter) (QofInstance*, double);
00438     void (*boolean_setter) (QofInstance*, gboolean);
00439     void (*i32_setter) (QofInstance*, gint32);
00440     void (*i64_setter) (QofInstance*, gint64);
00441     void (*char_setter) (QofInstance*, char*);
00442     void (*kvp_frame_setter) (QofInstance*, KvpFrame*);
00443 
00444     g_return_if_fail (user_data != NULL);
00445     context = (QofInstanceCopyData*) user_data;
00446     cm_date.tv_nsec = 0;
00447     cm_date.tv_sec = 0;
00448     importEnt = context->from;
00449     targetEnt = context->to;
00450     registered_type = FALSE;
00451     cm_param = (QofParam*) data;
00452     g_return_if_fail (cm_param != NULL);
00453     context->param = cm_param;
00454     if (safe_strcmp (cm_param->param_type, QOF_TYPE_STRING) == 0)
00455     {
00456         cm_string = (gchar*)cm_param->param_getfcn (importEnt, cm_param);
00457         if (cm_string)
00458         {
00459             string_setter = (void (*)(QofInstance*, const char*))cm_param->param_setfcn;
00460             if (string_setter != NULL)
00461             {
00462                 string_setter (targetEnt, cm_string);
00463             }
00464         }
00465         registered_type = TRUE;
00466     }
00467     if (safe_strcmp (cm_param->param_type, QOF_TYPE_DATE) == 0)
00468     {
00469         date_getter = (Timespec (*)(QofInstance*, QofParam*))cm_param->param_getfcn;
00470         cm_date = date_getter (importEnt, cm_param);
00471         date_setter = (void (*)(QofInstance*, Timespec))cm_param->param_setfcn;
00472         if (date_setter != NULL)
00473         {
00474             date_setter (targetEnt, cm_date);
00475         }
00476         registered_type = TRUE;
00477     }
00478     if ((safe_strcmp (cm_param->param_type, QOF_TYPE_NUMERIC) == 0)  ||
00479             (safe_strcmp (cm_param->param_type, QOF_TYPE_DEBCRED) == 0))
00480     {
00481         numeric_getter = (gnc_numeric (*)(QofInstance*, QofParam*))cm_param->param_getfcn;
00482         cm_numeric = numeric_getter (importEnt, cm_param);
00483         numeric_setter = (void (*)(QofInstance*, gnc_numeric))cm_param->param_setfcn;
00484         if (numeric_setter != NULL)
00485         {
00486             numeric_setter (targetEnt, cm_numeric);
00487         }
00488         registered_type = TRUE;
00489     }
00490     if (safe_strcmp (cm_param->param_type, QOF_TYPE_GUID) == 0)
00491     {
00492         cm_guid = (const GncGUID*)cm_param->param_getfcn (importEnt, cm_param);
00493         guid_setter = (void (*)(QofInstance*, const GncGUID*))cm_param->param_setfcn;
00494         if (guid_setter != NULL)
00495         {
00496             guid_setter (targetEnt, cm_guid);
00497         }
00498         registered_type = TRUE;
00499     }
00500     if (safe_strcmp (cm_param->param_type, QOF_TYPE_INT32) == 0)
00501     {
00502         int32_getter = (gint32 (*)(QofInstance*, QofParam*)) cm_param->param_getfcn;
00503         cm_i32 = int32_getter (importEnt, cm_param);
00504         i32_setter = (void (*)(QofInstance*, gint32))cm_param->param_setfcn;
00505         if (i32_setter != NULL)
00506         {
00507             i32_setter (targetEnt, cm_i32);
00508         }
00509         registered_type = TRUE;
00510     }
00511     if (safe_strcmp (cm_param->param_type, QOF_TYPE_INT64) == 0)
00512     {
00513         int64_getter = (gint64 (*)(QofInstance*, QofParam*)) cm_param->param_getfcn;
00514         cm_i64 = int64_getter (importEnt, cm_param);
00515         i64_setter = (void (*)(QofInstance*, gint64))cm_param->param_setfcn;
00516         if (i64_setter != NULL)
00517         {
00518             i64_setter (targetEnt, cm_i64);
00519         }
00520         registered_type = TRUE;
00521     }
00522     if (safe_strcmp (cm_param->param_type, QOF_TYPE_DOUBLE) == 0)
00523     {
00524         double_getter = (double (*)(QofInstance*, QofParam*)) cm_param->param_getfcn;
00525         cm_double = double_getter (importEnt, cm_param);
00526         double_setter = (void (*)(QofInstance*, double))cm_param->param_setfcn;
00527         if (double_setter != NULL)
00528         {
00529             double_setter (targetEnt, cm_double);
00530         }
00531         registered_type = TRUE;
00532     }
00533     if (safe_strcmp (cm_param->param_type, QOF_TYPE_BOOLEAN) == 0)
00534     {
00535         boolean_getter = (gboolean (*)(QofInstance*, QofParam*)) cm_param->param_getfcn;
00536         cm_boolean = boolean_getter (importEnt, cm_param);
00537         boolean_setter = (void (*)(QofInstance*, gboolean))cm_param->param_setfcn;
00538         if (boolean_setter != NULL)
00539         {
00540             boolean_setter (targetEnt, cm_boolean);
00541         }
00542         registered_type = TRUE;
00543     }
00544     if (safe_strcmp (cm_param->param_type, QOF_TYPE_KVP) == 0)
00545     {
00546         cm_kvp = (KvpFrame*)cm_param->param_getfcn (importEnt, cm_param);
00547         kvp_frame_setter = (void (*)(QofInstance*, KvpFrame*))cm_param->param_setfcn;
00548         if (kvp_frame_setter != NULL)
00549         {
00550             kvp_frame_setter (targetEnt, cm_kvp);
00551         }
00552         else
00553         {
00554             QofInstance *target_inst;
00555 
00556             target_inst = (QofInstance*)targetEnt;
00557             kvp_frame_delete (target_inst->kvp_data);
00558             target_inst->kvp_data = kvp_frame_copy (cm_kvp);
00559         }
00560         registered_type = TRUE;
00561     }
00562     if (safe_strcmp (cm_param->param_type, QOF_TYPE_CHAR) == 0)
00563     {
00564         cm_char = (gchar*)cm_param->param_getfcn (importEnt, cm_param);
00565         char_setter = (void (*)(QofInstance*, char*))cm_param->param_setfcn;
00566         if (char_setter != NULL)
00567         {
00568             char_setter (targetEnt, cm_char);
00569         }
00570         registered_type = TRUE;
00571     }
00572     if (safe_strcmp (cm_param->param_type, QOF_TYPE_COLLECT) == 0)
00573     {
00574         cm_col = (QofCollection*)cm_param->param_getfcn (importEnt, cm_param);
00575         if (cm_col)
00576         {
00577             /* create one reference for each member of the collection. */
00578             qof_collection_foreach (cm_col, col_ref_cb, context);
00579         }
00580         registered_type = TRUE;
00581     }
00582     if (registered_type == FALSE)
00583     {
00584         /* referenceEnt = QOF_INSTANCE (cm_param->param_getfcn (importEnt, cm_param));
00585         if (!referenceEnt) { return; }
00586         if (!referenceEnt->e_type) { return; }*/
00587         reference = qof_instance_get_reference_from (importEnt, cm_param);
00588         if (reference)
00589         {
00590             qof_session_update_reference_list (context->new_session, reference);
00591         }
00592     }
00593 }
00594 
00595 static gboolean
00596 qof_instance_guid_match (QofSession *new_session, QofInstance *original)
00597 {
00598     QofInstance *copy;
00599     const GncGUID *g;
00600     QofIdTypeConst type;
00601     QofBook *targetBook;
00602     QofCollection *coll;
00603 
00604     copy = NULL;
00605     g_return_val_if_fail (original != NULL, FALSE);
00606     targetBook = qof_session_get_book (new_session);
00607     g_return_val_if_fail (targetBook != NULL, FALSE);
00608     g = qof_instance_get_guid (original);
00609     type = g_strdup (original->e_type);
00610     coll = qof_book_get_collection (targetBook, type);
00611     copy = qof_collection_lookup_entity (coll, g);
00612     if (copy)
00613     {
00614         return TRUE;
00615     }
00616     return FALSE;
00617 }
00618 
00619 static void
00620 qof_instance_list_foreach (gpointer data, gpointer user_data)
00621 {
00622     QofInstanceCopyData *qecd;
00623     QofInstance *original;
00624     QofInstance *inst;
00625     QofBook *book;
00626     const GncGUID *g;
00627 
00628     g_return_if_fail (data != NULL);
00629     original = QOF_INSTANCE (data);
00630     g_return_if_fail (user_data != NULL);
00631     qecd = (QofInstanceCopyData*)user_data;
00632     if (qof_instance_guid_match (qecd->new_session, original))
00633     {
00634         return;
00635     }
00636     qecd->from = original;
00637     if (!qof_object_compliance (original->e_type, FALSE))
00638     {
00639         qecd->error = TRUE;
00640         return;
00641     }
00642     book = qof_session_get_book (qecd->new_session);
00643     inst = (QofInstance*)qof_object_new_instance (original->e_type, book);
00644     if (!inst)
00645     {
00646         PERR (" failed to create new entity type=%s.", original->e_type);
00647         qecd->error = TRUE;
00648         return;
00649     }
00650     qecd->to = inst;
00651     g = qof_instance_get_guid (original);
00652     qof_instance_set_guid (qecd->to, g);
00653     if (qecd->param_list != NULL)
00654     {
00655         g_slist_free (qecd->param_list);
00656         qecd->param_list = NULL;
00657     }
00658     qof_class_param_foreach (original->e_type, qof_instance_param_cb, qecd);
00659     qof_begin_edit (inst);
00660     g_slist_foreach (qecd->param_list, qof_instance_foreach_copy, qecd);
00661     qof_commit_edit (inst);
00662 }
00663 
00664 static void
00665 qof_instance_coll_foreach (QofInstance *original, gpointer user_data)
00666 {
00667     QofInstanceCopyData *qecd;
00668     const GncGUID *g;
00669     QofBook *targetBook;
00670     QofCollection *coll;
00671     QofInstance *copy;
00672 
00673     g_return_if_fail (original != NULL);
00674     g_return_if_fail (user_data != NULL);
00675     copy = NULL;
00676     qecd = (QofInstanceCopyData*)user_data;
00677     targetBook = qof_session_get_book (qecd->new_session);
00678     g = qof_instance_get_guid (original);
00679     coll = qof_book_get_collection (targetBook, original->e_type);
00680     copy = qof_collection_lookup_entity (coll, g);
00681     if (copy)
00682     {
00683         qecd->error = TRUE;
00684     }
00685 }
00686 
00687 static void
00688 qof_instance_coll_copy (QofInstance *original, gpointer user_data)
00689 {
00690     QofInstanceCopyData *qecd;
00691     QofBook *book;
00692     QofInstance *inst;
00693     const GncGUID *g;
00694 
00695     g_return_if_fail (original != NULL);
00696     g_return_if_fail (user_data != NULL);
00697     qecd = (QofInstanceCopyData*)user_data;
00698     book = qof_session_get_book (qecd->new_session);
00699     if (!qof_object_compliance (original->e_type, TRUE))
00700     {
00701         return;
00702     }
00703     inst = (QofInstance*)qof_object_new_instance (original->e_type, book);
00704     qecd->to = inst;
00705     qecd->from = original;
00706     g = qof_instance_get_guid (original);
00707     qof_instance_set_guid (qecd->to, g);
00708     qof_begin_edit (inst);
00709     g_slist_foreach (qecd->param_list, qof_instance_foreach_copy, qecd);
00710     qof_commit_edit (inst);
00711 }
00712 
00713 static gboolean
00714 qof_instance_copy_to_session (QofSession* new_session, QofInstance* original)
00715 {
00716     QofInstanceCopyData qecd;
00717     QofInstance *inst;
00718     QofBook *book;
00719 
00720     if (!new_session || !original)
00721     {
00722         return FALSE;
00723     }
00724     if (qof_instance_guid_match (new_session, original))
00725     {
00726         return FALSE;
00727     }
00728     if (!qof_object_compliance (original->e_type, TRUE))
00729     {
00730         return FALSE;
00731     }
00732     qof_event_suspend ();
00733     qecd.param_list = NULL;
00734     book = qof_session_get_book (new_session);
00735     qecd.new_session = new_session;
00736     qof_book_set_partial (book);
00737     inst = (QofInstance*)qof_object_new_instance (original->e_type, book);
00738     qecd.to = inst;
00739     qecd.from = original;
00740     qof_instance_set_guid (qecd.to, qof_instance_get_guid (original));
00741     qof_begin_edit (inst);
00742     qof_class_param_foreach (original->e_type, qof_instance_param_cb, &qecd);
00743     qof_commit_edit (inst);
00744     if (g_slist_length (qecd.param_list) == 0)
00745     {
00746         return FALSE;
00747     }
00748     g_slist_foreach (qecd.param_list, qof_instance_foreach_copy, &qecd);
00749     g_slist_free (qecd.param_list);
00750     qof_event_resume ();
00751     return TRUE;
00752 }
00753 
00754 static gboolean
00755 qof_instance_copy_list (QofSession *new_session, GList *entity_list)
00756 {
00757     QofInstanceCopyData *qecd;
00758 
00759     if (!new_session || !entity_list)
00760     {
00761         return FALSE;
00762     }
00763     ENTER (" list=%d", g_list_length (entity_list));
00764     qecd = g_new0 (QofInstanceCopyData, 1);
00765     qof_event_suspend ();
00766     qecd->param_list = NULL;
00767     qecd->new_session = new_session;
00768     qof_book_set_partial (qof_session_get_book (new_session));
00769     g_list_foreach (entity_list, qof_instance_list_foreach, qecd);
00770     qof_event_resume ();
00771     if (qecd->error)
00772     {
00773         PWARN (" some/all entities in the list could not be copied.");
00774     }
00775     g_free (qecd);
00776     LEAVE (" ");
00777     return TRUE;
00778 }
00779 
00780 static gboolean
00781 qof_instance_copy_coll (QofSession *new_session, QofCollection *entity_coll)
00782 {
00783     QofInstanceCopyData qecd;
00784 
00785     g_return_val_if_fail (new_session, FALSE);
00786     if (!entity_coll)
00787     {
00788         return FALSE;
00789     }
00790     qof_event_suspend ();
00791     qecd.param_list = NULL;
00792     qecd.new_session = new_session;
00793     qof_book_set_partial (qof_session_get_book (qecd.new_session));
00794     qof_collection_foreach (entity_coll, qof_instance_coll_foreach, &qecd);
00795     qof_class_param_foreach (qof_collection_get_type (entity_coll),
00796                              qof_instance_param_cb, &qecd);
00797     qof_collection_foreach (entity_coll, qof_instance_coll_copy, &qecd);
00798     if (qecd.param_list != NULL)
00799     {
00800         g_slist_free (qecd.param_list);
00801     }
00802     qof_event_resume ();
00803     return TRUE;
00804 }
00805 
00806 struct recurse_s
00807 {
00808     QofSession *session;
00809     gboolean   success;
00810     GList      *ref_list;
00811     GList      *ent_list;
00812 };
00813 
00814 static void
00815 recurse_collection_cb (QofInstance *ent, gpointer user_data)
00816 {
00817     struct recurse_s *store;
00818 
00819     if (user_data == NULL)
00820     {
00821         return;
00822     }
00823     store = (struct recurse_s*)user_data;
00824     if (!ent || !store)
00825     {
00826         return;
00827     }
00828     store->success = qof_instance_copy_to_session (store->session, ent);
00829     if (store->success)
00830     {
00831         store->ent_list = g_list_append (store->ent_list, ent);
00832     }
00833 }
00834 
00835 static void
00836 recurse_ent_cb (QofInstance *ent, gpointer user_data)
00837 {
00838     GList      *ref_list, *i, *j, *ent_list, *child_list;
00839     QofParam   *ref_param;
00840     QofInstance  *ref_ent, *child_ent;
00841     QofSession *session;
00842     struct recurse_s *store;
00843     gboolean   success;
00844 
00845     if (user_data == NULL)
00846     {
00847         return;
00848     }
00849     store = (struct recurse_s*)user_data;
00850     session = store->session;
00851     success = store->success;
00852     ref_list = NULL;
00853     child_ent = NULL;
00854     ref_list = g_list_copy (store->ref_list);
00855     if ((!session) || (!ent))
00856     {
00857         return;
00858     }
00859     ent_list = NULL;
00860     child_list = NULL;
00861     i = NULL;
00862     j = NULL;
00863     for (i = ref_list; i != NULL; i = i->next)
00864     {
00865         if (i->data == NULL)
00866         {
00867             continue;
00868         }
00869         ref_param = (QofParam*)i->data;
00870         if (ref_param->param_name == NULL)
00871         {
00872             continue;
00873         }
00874         if (0 == safe_strcmp (ref_param->param_type, QOF_TYPE_COLLECT))
00875         {
00876             QofCollection *col;
00877 
00878             col = ref_param->param_getfcn (ent, ref_param);
00879             if (col)
00880             {
00881                 qof_collection_foreach (col, recurse_collection_cb, store);
00882             }
00883             continue;
00884         }
00885         ref_ent = QOF_INSTANCE (ref_param->param_getfcn (ent, ref_param));
00886         if ((ref_ent) && (ref_ent->e_type))
00887         {
00888             store->success = qof_instance_copy_to_session (session, ref_ent);
00889             if (store->success)
00890             {
00891                 ent_list = g_list_append (ent_list, ref_ent);
00892             }
00893         }
00894     }
00895     for (i = ent_list; i != NULL; i = i->next)
00896     {
00897         if (i->data == NULL)
00898         {
00899             continue;
00900         }
00901         child_ent = QOF_INSTANCE (i->data);
00902         if (child_ent == NULL)
00903         {
00904             continue;
00905         }
00906         ref_list = qof_class_get_referenceList (child_ent->e_type);
00907         for (j = ref_list; j != NULL; j = j->next)
00908         {
00909             if (j->data == NULL)
00910             {
00911                 continue;
00912             }
00913             ref_param = (QofParam*)j->data;
00914             ref_ent = ref_param->param_getfcn (child_ent, ref_param);
00915             if (ref_ent != NULL)
00916             {
00917                 success = qof_instance_copy_to_session (session, ref_ent);
00918                 if (success)
00919                 {
00920                     child_list = g_list_append (child_list, ref_ent);
00921                 }
00922             }
00923         }
00924     }
00925     for (i = child_list; i != NULL; i = i->next)
00926     {
00927         if (i->data == NULL)
00928         {
00929             continue;
00930         }
00931         ref_ent = QOF_INSTANCE (i->data);
00932         if (ref_ent == NULL)
00933         {
00934             continue;
00935         }
00936         ref_list = qof_class_get_referenceList (ref_ent->e_type);
00937         for (j = ref_list; j != NULL; j = j->next)
00938         {
00939             if (j->data == NULL)
00940             {
00941                 continue;
00942             }
00943             ref_param = (QofParam*)j->data;
00944             child_ent = ref_param->param_getfcn (ref_ent, ref_param);
00945             if (child_ent != NULL)
00946             {
00947                 qof_instance_copy_to_session (session, child_ent);
00948             }
00949         }
00950     }
00951 }
00952 
00953 static gboolean
00954 qof_instance_copy_coll_r (QofSession *new_session, QofCollection *coll)
00955 {
00956     struct recurse_s store;
00957     gboolean success;
00958 
00959     if ((!new_session) || (!coll))
00960     {
00961         return FALSE;
00962     }
00963     store.session = new_session;
00964     success = TRUE;
00965     store.success = success;
00966     store.ent_list = NULL;
00967     store.ref_list = qof_class_get_referenceList (qof_collection_get_type (coll));
00968     success = qof_instance_copy_coll (new_session, coll);
00969     if (success)
00970     {
00971         qof_collection_foreach (coll, recurse_ent_cb, &store);
00972     }
00973     return success;
00974 }
00975 
00976 static gboolean
00977 qof_instance_copy_one_r (QofSession *new_session, QofInstance *ent)
00978 {
00979     struct recurse_s store;
00980     QofCollection *coll;
00981     gboolean success;
00982 
00983     if ((!new_session) || (!ent))
00984     {
00985         return FALSE;
00986     }
00987     store.session = new_session;
00988     success = TRUE;
00989     store.success = success;
00990     store.ref_list = qof_class_get_referenceList (ent->e_type);
00991     success = qof_instance_copy_to_session (new_session, ent);
00992     if (success == TRUE)
00993     {
00994         coll = qof_book_get_collection (qof_session_get_book (new_session), ent->e_type);
00995         if (coll)
00996         {
00997             qof_collection_foreach (coll, recurse_ent_cb, &store);
00998         }
00999     }
01000     return success;
01001 }
01002 
01003 
01004 /* ====================================================================== */
01005 
01009 struct backend_providers
01010 {
01011     const char *libdir;
01012     const char *filename;
01013 };
01014 
01015 static void
01016 qof_session_load_backend(QofSession * session, const char * access_method)
01017 {
01018     GSList *p;
01019     QofBackendProvider *prov;
01020     char *msg;
01021     gboolean prov_type;
01022     gboolean (*type_check) (const char*);
01023 
01024     ENTER (" list=%d, initted=%s", g_slist_length(provider_list),
01025            qof_providers_initialized ? "true" : "false");
01026     prov_type = FALSE;
01027     if (!qof_providers_initialized)
01028     {
01029         qof_providers_initialized = TRUE;
01030     }
01031     p = provider_list;
01032     while (p != NULL)
01033     {
01034         prov = p->data;
01035         /* Does this provider handle the desired access method? */
01036         if (0 == g_ascii_strcasecmp (access_method, prov->access_method))
01037         {
01038             /* More than one backend could provide this
01039             access method, check file type compatibility. */
01040             type_check = (gboolean (*)(const char*)) prov->check_data_type;
01041             if (type_check)
01042             {
01043                 prov_type = (type_check)(session->book_id);
01044                 if (!prov_type)
01045                 {
01046                     PINFO(" %s not usable", prov->provider_name);
01047                     p = p->next;
01048                     continue;
01049                 }
01050             }
01051             PINFO (" selected %s", prov->provider_name);
01052             if (NULL == prov->backend_new)
01053             {
01054                 p = p->next;
01055                 continue;
01056             }
01057             /* Use the providers creation callback */
01058             session->backend = (*(prov->backend_new))();
01059             session->backend->provider = prov;
01060             /* Tell the book about the backend that they'll be using. */
01061             qof_book_set_backend (session->book, session->backend);
01062             LEAVE (" ");
01063             return;
01064         }
01065         p = p->next;
01066     }
01067     msg = g_strdup_printf("failed to load '%s' using access_method", access_method);
01068     qof_session_push_error (session, ERR_BACKEND_NO_HANDLER, msg);
01069     g_free(msg);
01070     LEAVE (" ");
01071 }
01072 
01073 /* ====================================================================== */
01074 
01075 static void
01076 qof_session_destroy_backend (QofSession *session)
01077 {
01078     g_return_if_fail (session);
01079 
01080     if (session->backend)
01081     {
01082         /* clear any error message */
01083         char * msg = qof_backend_get_message (session->backend);
01084         g_free (msg);
01085 
01086         /* Then destroy the backend */
01087         if (session->backend->destroy_backend)
01088         {
01089             session->backend->destroy_backend(session->backend);
01090         }
01091         else
01092         {
01093             g_free(session->backend);
01094         }
01095     }
01096 
01097     session->backend = NULL;
01098 }
01099 
01100 void
01101 qof_session_begin (QofSession *session, const char * book_id,
01102                    gboolean ignore_lock, gboolean create, gboolean force)
01103 {
01104     gchar *scheme = NULL, *filename = NULL;
01105 
01106     if (!session) return;
01107 
01108     ENTER (" sess=%p ignore_lock=%d, book-id=%s",
01109            session, ignore_lock,
01110            book_id ? book_id : "(null)");
01111 
01112     /* Clear the error condition of previous errors */
01113     qof_session_clear_error (session);
01114 
01115     /* Check to see if this session is already open */
01116     if (session->book_id)
01117     {
01118         if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
01119             qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL);
01120         LEAVE("push error book is already open ");
01121         return;
01122     }
01123 
01124     /* seriously invalid */
01125     if (!book_id)
01126     {
01127         if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
01128             qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
01129         LEAVE("push error missing book_id");
01130         return;
01131     }
01132     scheme = g_uri_parse_scheme (book_id);
01133     if (g_strcmp0 (scheme, "file") == 0)
01134         filename = g_filename_from_uri (book_id, NULL, NULL);
01135     else if (!scheme)
01136         filename = g_strdup (book_id);
01137 
01138     if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR))
01139     {
01140         if (ERR_BACKEND_NO_ERR == qof_session_get_error(session))
01141             qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
01142         g_free (filename);
01143         g_free (scheme);
01144         LEAVE("Can't open a directory");
01145         return;
01146     }
01147 
01148 
01149     /* destroy the old backend */
01150     qof_session_destroy_backend(session);
01151 
01152     /* Store the session URL  */
01153     session->book_id = g_strdup (book_id);
01154 
01155     if (filename)
01156         qof_session_load_backend(session, "file");
01157     else                       /* access method found, load appropriate backend */
01158         qof_session_load_backend(session, scheme);
01159     g_free (filename);
01160     g_free (scheme);
01161 
01162     /* No backend was found. That's bad. */
01163     if (NULL == session->backend)
01164     {
01165         g_free(session->book_id);
01166         session->book_id = NULL;
01167         if (ERR_BACKEND_NO_ERR == qof_session_get_error(session))
01168             qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
01169         LEAVE (" BAD: no backend: sess=%p book-id=%s",
01170                session,  book_id ? book_id : "(null)");
01171         return;
01172     }
01173 
01174     /* If there's a begin method, call that. */
01175     if (session->backend->session_begin)
01176     {
01177         char *msg;
01178         int err;
01179 
01180         (session->backend->session_begin)(session->backend, session,
01181                                           session->book_id, ignore_lock,
01182                                           create, force);
01183         PINFO("Done running session_begin on backend");
01184         err = qof_backend_get_error(session->backend);
01185         msg = qof_backend_get_message(session->backend);
01186         if (err != ERR_BACKEND_NO_ERR)
01187         {
01188             g_free(session->book_id);
01189             session->book_id = NULL;
01190             qof_session_push_error (session, err, msg);
01191             LEAVE(" backend error %d %s", err, msg ? msg : "(null)");
01192             return;
01193         }
01194         if (msg != NULL)
01195         {
01196             PWARN("%s", msg);
01197             g_free(msg);
01198         }
01199     }
01200 
01201     LEAVE (" sess=%p book-id=%s",
01202            session,  book_id ? book_id : "(null)");
01203 }
01204 
01205 /* ====================================================================== */
01206 
01207 void
01208 qof_session_load (QofSession *session,
01209                   QofPercentageFunc percentage_func)
01210 {
01211     QofBook *newbook, *oldbook;
01212     QofBackend *be;
01213     QofBackendError err;
01214 
01215     if (!session) return;
01216     if (!session->book_id) return;
01217 
01218     ENTER ("sess=%p book_id=%s", session, session->book_id
01219            ? session->book_id : "(null)");
01220 
01221     /* At this point, we should are supposed to have a valid book
01222     * id and a lock on the file. */
01223 
01224     oldbook = session->book;
01225 
01226     /* XXX why are we creating a book here? I think the books
01227     * need to be handled by the backend ... especially since
01228     * the backend may need to load multiple books ... XXX. FIXME.
01229     */
01230     newbook = qof_book_new();
01231     session->book = newbook;
01232     PINFO ("new book=%p", newbook);
01233 
01234     qof_session_clear_error (session);
01235 
01236     /* This code should be sufficient to initialize *any* backend,
01237     * whether http, postgres, or anything else that might come along.
01238     * Basically, the idea is that by now, a backend has already been
01239     * created & set up.  At this point, we only need to get the
01240     * top-level account group out of the backend, and that is a
01241     * generic, backend-independent operation.
01242     */
01243     be = session->backend;
01244     qof_book_set_backend(newbook, be);
01245 
01246     /* Starting the session should result in a bunch of accounts
01247     * and currencies being downloaded, but probably no transactions;
01248     * The GUI will need to do a query for that.
01249     */
01250     if (be)
01251     {
01252         be->percentage = percentage_func;
01253 
01254         if (be->load)
01255         {
01256             be->load (be, newbook, LOAD_TYPE_INITIAL_LOAD);
01257             qof_session_push_error (session, qof_backend_get_error(be), NULL);
01258         }
01259     }
01260 
01261     /* XXX if the load fails, then we try to restore the old set of books;
01262     * however, we don't undo the session id (the URL).  Thus if the
01263     * user attempts to save after a failed load, they weill be trying to
01264     * save to some bogus URL.   This is wrong. XXX  FIXME.
01265     */
01266     err = qof_session_get_error(session);
01267     if ((err != ERR_BACKEND_NO_ERR) &&
01268             (err != ERR_FILEIO_FILE_TOO_OLD) &&
01269             (err != ERR_FILEIO_NO_ENCODING) &&
01270             (err != ERR_FILEIO_FILE_UPGRADE) &&
01271             (err != ERR_SQL_DB_TOO_OLD) &&
01272             (err != ERR_SQL_DB_TOO_NEW))
01273     {
01274         /* Something broke, put back the old stuff */
01275         qof_book_set_backend (newbook, NULL);
01276         qof_book_destroy (newbook);
01277         session->book = oldbook;
01278         LEAVE("error from backend %d", qof_session_get_error(session));
01279         return;
01280     }
01281     qof_book_set_backend (oldbook, NULL);
01282     qof_book_destroy (oldbook);
01283 
01284     LEAVE ("sess = %p, book_id=%s", session, session->book_id
01285            ? session->book_id : "(null)");
01286 }
01287 
01288 /* ====================================================================== */
01289 
01290 static gboolean
01291 save_error_handler(QofBackend *be, QofSession *session)
01292 {
01293     int err;
01294     err = qof_backend_get_error(be);
01295 
01296     if (ERR_BACKEND_NO_ERR != err)
01297     {
01298         qof_session_push_error (session, err, NULL);
01299         return TRUE;
01300     }
01301     return FALSE;
01302 }
01303 
01304 void
01305 qof_session_save (QofSession *session,
01306                   QofPercentageFunc percentage_func)
01307 {
01308     QofBackend *be;
01309     gboolean partial, change_backend;
01310     QofBackendProvider *prov;
01311     GSList *p;
01312     QofBook *book;
01313     int err;
01314     gint num;
01315     char *msg = NULL;
01316     char *book_id;
01317 
01318     if (!session) return;
01319     if (!g_atomic_int_dec_and_test(&session->lock))
01320         goto leave;
01321     ENTER ("sess=%p book_id=%s",
01322            session, session->book_id ? session->book_id : "(null)");
01323     /* Partial book handling. */
01324     book = qof_session_get_book(session);
01325     partial = (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
01326     change_backend = FALSE;
01327     msg = g_strdup_printf(" ");
01328     book_id = g_strdup(session->book_id);
01329     if (partial == TRUE)
01330     {
01331         if (session->backend && session->backend->provider)
01332         {
01333             prov = session->backend->provider;
01334             if (TRUE == prov->partial_book_supported)
01335             {
01336                 /* if current backend supports partial, leave alone. */
01337                 change_backend = FALSE;
01338             }
01339             else
01340             {
01341                 change_backend = TRUE;
01342             }
01343         }
01344         /* If provider is undefined, assume partial not supported. */
01345         else
01346         {
01347             change_backend = TRUE;
01348         }
01349     }
01350     if (change_backend == TRUE)
01351     {
01352         qof_session_destroy_backend(session);
01353         if (!qof_providers_initialized)
01354         {
01355             qof_providers_initialized = TRUE;
01356         }
01357         p = provider_list;
01358         while (p != NULL)
01359         {
01360             prov = p->data;
01361             if (TRUE == prov->partial_book_supported)
01362             {
01364                 /*      if((TRUE == prov->partial_book_supported) &&
01365                 (0 == g_ascii_strcasecmp (access_method, prov->access_method)))
01366                 {*/
01367                 if (NULL == prov->backend_new) continue;
01368                 /* Use the providers creation callback */
01369                 session->backend = (*(prov->backend_new))();
01370                 session->backend->provider = prov;
01371                 if (session->backend->session_begin)
01372                 {
01373                     /* Call begin - backend has been changed,
01374                        so make sure a file can be written,
01375                        use ignore_lock and force create */
01376                     g_free(session->book_id);
01377                     session->book_id = NULL;
01378                     (session->backend->session_begin)(session->backend, session,
01379                                                       book_id, TRUE, TRUE, TRUE);
01380                     PINFO("Done running session_begin on changed backend");
01381                     err = qof_backend_get_error(session->backend);
01382                     msg = qof_backend_get_message(session->backend);
01383                     if (err != ERR_BACKEND_NO_ERR)
01384                     {
01385                         g_free(session->book_id);
01386                         session->book_id = NULL;
01387                         qof_session_push_error (session, err, msg);
01388                         LEAVE("changed backend error %d", err);
01389                         goto leave;
01390                     }
01391                     if (msg != NULL)
01392                     {
01393                         PWARN("%s", msg);
01394                         g_free(msg);
01395                         msg = NULL;
01396                     }
01397                 }
01398                 /* Tell the book about the backend that they'll be using. */
01399                 qof_book_set_backend (session->book, session->backend);
01400                 p = NULL;
01401             }
01402             if (p)
01403             {
01404                 p = p->next;
01405             }
01406         }
01407         if (!session->backend)
01408         {
01409             if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
01410             {
01411                 msg = g_strdup_printf("failed to load backend");
01412                 qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg);
01413             }
01414             goto leave;
01415         }
01416     }
01417     /* If there is a backend, and the backend is reachable
01418     * (i.e. we can communicate with it), then synchronize with
01419     * the backend.  If we cannot contact the backend (e.g.
01420     * because we've gone offline, the network has crashed, etc.)
01421     * then give the user the option to save to the local disk.
01422     *
01423     * hack alert -- FIXME -- XXX the code below no longer
01424     * does what the words above say.  This needs fixing.
01425     */
01426     be = session->backend;
01427     if (be)
01428     {
01429         /* if invoked as SaveAs(), then backend not yet set */
01430         qof_book_set_backend (session->book, be);
01431         be->percentage = percentage_func;
01432         if (be->sync)
01433         {
01434             (be->sync)(be, session->book);
01435             if (save_error_handler(be, session))
01436                 goto leave;
01437         }
01438 
01439         /* If we got to here, then the backend saved everything
01440         * just fine, and we are done. So return. */
01441         /* Return the book_id to previous value. */
01442         qof_session_clear_error (session);
01443         LEAVE("Success");
01444         goto leave;
01445     }
01446     else
01447     {
01448         if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
01449         {
01450             msg = g_strdup_printf("failed to load backend");
01451             qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg);
01452         }
01453     }
01454     LEAVE("error -- No backend!");
01455 leave:
01456     if (msg != NULL) g_free(msg);
01457     g_atomic_int_inc(&session->lock);
01458     return;
01459 }
01460 
01461 void
01462 qof_session_safe_save(QofSession *session, QofPercentageFunc percentage_func)
01463 {
01464     QofBackend *be = session->backend;
01465     gint err;
01466     char *msg = NULL;
01467     g_return_if_fail( be != NULL );
01468     g_return_if_fail( be->safe_sync != NULL );
01469     be->percentage = percentage_func;
01470     (be->safe_sync)( be, qof_session_get_book( session ));
01471     err = qof_backend_get_error(session->backend);
01472     msg = qof_backend_get_message(session->backend);
01473     if (err != ERR_BACKEND_NO_ERR)
01474     {
01475         g_free(session->book_id);
01476         session->book_id = NULL;
01477         qof_session_push_error (session, err, msg);
01478     }
01479 }
01480 
01481 
01482 /* ====================================================================== */
01483 gboolean
01484 qof_session_save_in_progress(const QofSession *session)
01485 {
01486     return (session && g_atomic_int_get(&session->lock) != 1);
01487 }
01488 
01489 void
01490 qof_session_end (QofSession *session)
01491 {
01492     if (!session) return;
01493 
01494     ENTER ("sess=%p book_id=%s", session, session->book_id
01495            ? session->book_id : "(null)");
01496 
01497     /* close down the backend first */
01498     if (session->backend && session->backend->session_end)
01499     {
01500         (session->backend->session_end)(session->backend);
01501     }
01502 
01503     qof_session_clear_error (session);
01504 
01505     g_free (session->book_id);
01506     session->book_id = NULL;
01507 
01508     LEAVE ("sess=%p book_id=%s", session, session->book_id
01509            ? session->book_id : "(null)");
01510 }
01511 
01512 void
01513 qof_session_destroy (QofSession *session)
01514 {
01515     if (!session) return;
01516 
01517     ENTER ("sess=%p book_id=%s", session, session->book_id
01518            ? session->book_id : "(null)");
01519 
01520     qof_session_end (session);
01521 
01522     /* destroy the backend */
01523     qof_session_destroy_backend(session);
01524 
01525     qof_book_set_backend (session->book, NULL);
01526     qof_book_destroy (session->book);
01527     session->book  = NULL;
01528 
01529     g_free (session);
01530 
01531     LEAVE ("sess=%p", session);
01532 }
01533 
01534 /* ====================================================================== */
01535 /* this call is weird. */
01536 
01537 void
01538 qof_session_swap_data (QofSession *session_1, QofSession *session_2)
01539 {
01540     QofBook *book_1, *book_2;
01541     gboolean tmp;
01542 
01543     if (session_1 == session_2) return;
01544     if (!session_1 || !session_2) return;
01545 
01546     ENTER ("sess1=%p sess2=%p", session_1, session_2);
01547 
01548     book_1 = session_1->book;
01549     book_2 = session_2->book;
01550 
01551     // Swap the read_only flags backwards.
01552     tmp = book_1->read_only;
01553     book_1->read_only = book_2->read_only;
01554     book_2->read_only = tmp;
01555 
01556     session_1->book = book_2;
01557     session_2->book = book_1;
01558 
01559     qof_book_set_backend (book_1, session_2->backend);
01560     qof_book_set_backend (book_2, session_1->backend);
01561 
01562     LEAVE (" ");
01563 }
01564 
01565 /* ====================================================================== */
01566 
01567 gboolean
01568 qof_session_events_pending (const QofSession *session)
01569 {
01570     if (!session) return FALSE;
01571     if (!session->backend) return FALSE;
01572     if (!session->backend->events_pending) return FALSE;
01573 
01574     return session->backend->events_pending (session->backend);
01575 }
01576 
01577 gboolean
01578 qof_session_process_events (QofSession *session)
01579 {
01580     if (!session) return FALSE;
01581     if (!session->backend) return FALSE;
01582     if (!session->backend->process_events) return FALSE;
01583 
01584     return session->backend->process_events (session->backend);
01585 }
01586 
01587 /* XXX This exports the list of accounts to a file.  It does not
01588  * export any transactions.  It's a place-holder until full
01589  * book-closing is implemented.
01590  */
01591 gboolean
01592 qof_session_export (QofSession *tmp_session,
01593                     QofSession *real_session,
01594                     QofPercentageFunc percentage_func)
01595 {
01596     QofBook *book, *book2;
01597     QofBackend *be;
01598 
01599     if ((!tmp_session) || (!real_session)) return FALSE;
01600 
01601     book = qof_session_get_book (real_session);
01602     ENTER ("tmp_session=%p real_session=%p book=%p book_id=%s",
01603            tmp_session, real_session, book,
01604            qof_session_get_url(tmp_session)
01605            ? qof_session_get_url(tmp_session) : "(null)");
01606 
01607     /* There must be a backend or else.  (It should always be the file
01608      * backend too.)
01609      */
01610     book2 = qof_session_get_book(tmp_session);
01611     be = qof_book_get_backend(book2);
01612     if (!be)
01613         return FALSE;
01614 
01615     be->percentage = percentage_func;
01616     if (be->export_fn)
01617     {
01618         int err;
01619 
01620         (be->export_fn)(be, book);
01621         err = qof_backend_get_error(be);
01622 
01623         if (ERR_BACKEND_NO_ERR != err)
01624         {
01625             return FALSE;
01626         }
01627     }
01628 
01629     return TRUE;
01630 }
01631 
01632 /* ================= Static function access for testing ================= */
01633 
01634 void init_static_qofsession_pointers (void);
01635 
01636 void (*p_qof_session_load_backend) (QofSession * session, const char * access_method);
01637 void (*p_qof_session_clear_error) (QofSession *session);
01638 void (*p_qof_session_destroy_backend) (QofSession *session);
01639 
01640 void
01641 init_static_qofsession_pointers (void)
01642 {
01643     p_qof_session_load_backend = qof_session_load_backend;
01644     p_qof_session_clear_error = qof_session_clear_error;
01645     p_qof_session_destroy_backend = qof_session_destroy_backend;
01646 }
01647 
01648 /* =================== END OF FILE ====================================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines