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

Generated on Fri Sep 1 15:13:11 2006 for QOF by  doxygen 1.4.7