qofsession.c

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

Generated on Fri May 12 18:00:33 2006 for QOF by  doxygen 1.4.4