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