00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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));
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
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
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
00146 if (ERR_BACKEND_NO_ERR != session->last_err)
00147 {
00148 return session->last_err;
00149 }
00150
00151
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
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
00265
00266
00267
00268 g_list_free (session->books);
00269 session->books = g_list_append (NULL, addbook);
00270 }
00271 else
00272 {
00273
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
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;
00389 QofEntityCopyData *context;
00390 QofEntityReference *reference;
00391 gboolean registered_type;
00392
00393 QofParam *cm_param;
00394 gchar *cm_string, *cm_char;
00395 const GUID *cm_guid;
00396 KvpFrame *cm_kvp;
00397 QofCollection *cm_col;
00398
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
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
00509 qof_collection_foreach(cm_col, col_ref_cb, context);
00510 }
00511 registered_type = TRUE;
00512 }
00513 if(registered_type == FALSE) {
00514
00515
00516
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
00850
00851
00852
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
00892 if (0 == strcasecmp (access_method, prov->access_method))
00893 {
00894
00895
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
00911 session->backend = (*(prov->backend_new))();
00912 session->backend->provider = prov;
00913
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
00939 char * msg = qof_backend_get_message (session->backend);
00940 g_free (msg);
00941
00942
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
00970 qof_session_clear_error (session);
00971
00972
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
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
00989 session->book_id = g_strdup (book_id);
00990
00991
00992 qof_session_destroy_backend(session);
00993
00994
00995
00996
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
01010 qof_session_load_backend(session, "file");
01011 }
01012
01013
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
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
01069
01070
01071 oldbooks = session->books;
01072
01073
01074
01075
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
01084
01085
01086
01087
01088
01089
01090 be = session->backend;
01091 qof_book_set_backend(newbook, be);
01092
01093
01094
01095
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
01109
01110
01111
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
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
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
01196 change_backend = FALSE;
01197 }
01198 else { change_backend = TRUE; }
01199 }
01200
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
01221
01222
01223 if (NULL == prov->backend_new) continue;
01224
01225 session->backend = (*(prov->backend_new))();
01226 session->backend->provider = prov;
01227 if (session->backend->session_begin)
01228 {
01229
01230
01231
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
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
01273
01274
01275
01276
01277
01278
01279
01280
01281 be = session->backend;
01282 if (be)
01283 {
01284 for (node = session->books; node; node=node->next)
01285 {
01286 abook = node->data;
01287
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
01297
01298
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
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
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
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