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