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

Generated on Fri Sep 15 14:24:57 2006 for QOF by  doxygen 1.4.7