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

Generated on Fri Oct 21 15:49:56 2005 for QOF by  doxygen 1.4.5