Backend
[Object: Dynamic Object Class Framework]


Detailed Description

The QOF Backend is a pseudo-object providing an interface between the engine and a persistant data store (e.g. a server, a database, or a file). Backends are not meant to be used directly by an application; instead the Session should be used to make a connection with some particular backend. There are no backend functions that are 'public' to users of the engine. The backend can, however, report errors to the GUI & other front-end users. This file defines these errors.

Backends are used to save and restore Entities in a Book.

The QOF Session encapsulates a connection to a storage backend. That is, it manages the connection to a persistant data store; whereas the backend is the thing that performs the actual datastore access.

This class provides several important services:

1) It resolves and loads the appropriate backend, based on the URL.

2) It reports backend errors (e.g. network errors, storage corruption errors) through a single, backend-independent API.

3) It reports non-error events received from the backend.

4) It helps manage global dataset locks. For example, for the file backend, the lock prevents multiple users from editing the same file at the same time, thus avoiding lost data due to race conditions. Thus, an open session implies that the associated file is locked.

5) Misc utilities, such as a search path for the file to be edited, and/or other URL resolution utilities. This should simplify install & maintenance problems for naive users who may not have a good grasp on what a file system is, or where they want to keep their data files.

6) In the future, this class is probably a good place to manage a portion of the user authentication process, and hold user credentials/cookies/keys/tokens. This is because at the coarsest level, authorization can happen at the datastore level: i.e. does this user even have the authority to connect to and open this datastore?

A brief note about books & sessions: A book encapsulates the datasets manipulated by QOF. A book holds the actual data. By contrast, the session mediates the connection between a book (the thing that lives in virtual memory in the local process) and the datastore (the place where book data lives permanently, e.g., file, database).

In the current design, a session may hold multiple books. For now, exactly what this means is somewhat vague, and code in various places makes some implicit assumptions: first, only one book is 'current' and open for editing. Next, its assumed that all of the books in a session are related in some way. i.e. that they are all earlier accounting periods of the currently open book. In particular, the backends probably make that assumption, in order to store the different accounting periods in a clump so that one can be found, given another.

If you want multiple books that are unrelated to each other, use multiple sessions.

The session now calls QofBackendProvider->check_data_type to check that the incoming path contains data that the backend provider can open. The backend provider should also check if it can contact it's storage media (disk, network, server, etc.) and abort if it can't. Malformed file URL's would be handled the same way.


Files

file  qofbackend.h
 API for data storage Backend.
file  qofsession.h
 Encapsulates a connection to a backend (persistent store).

Modules

 QOF Serialisation Format

Data Structures

struct  QofBackendOption_s

Backend Configuration using KVP

The backend uses qof_backend_get_config to pass back a KvpFrame of QofBackendOption that includes the translated strings that serve as description and tooltip for that option.

qof_backend_prepare_frame, qof_backend_prepare_option and qof_backend_complete_frame are intended to be used by the backend itself to create the options.

qof_backend_get_config, qof_backend_option_foreach and qof_backend_load_config are intended for either the backend or the frontend to retrieve the option data from the frame or set new data.

Backends are loaded using QofBackendProvider via the function specified in prov->backend_new. Before backend_new returns, you should ensure that your backend is fully configured and ready for use.

typedef QofBackendOption_s QofBackendOption
typedef void(* QofBackendOptionCB )(QofBackendOption *, gpointer data)
void qof_backend_prepare_frame (QofBackend *be)
void qof_backend_prepare_option (QofBackend *be, QofBackendOption *option)
KvpFrameqof_backend_complete_frame (QofBackend *be)
void qof_backend_option_foreach (KvpFrame *config, QofBackendOptionCB cb, gpointer data)
void qof_backend_load_config (QofBackend *be, KvpFrame *config)
 Load configuration options specific to this backend.
KvpFrameqof_backend_get_config (QofBackend *be)
 Get the available configuration options.

Allow access to the begin routine for this backend.

QOF_BEGIN_EDIT and QOF_COMMIT_EDIT_PART1 and part2 rely on calling QofBackend *be->begin and be->commit. This means the QofBackend struct becomes part of the public API. These function replaces those calls to allow the macros to be used when QOF is built as a library.

void qof_backend_run_begin (QofBackend *be, QofInstance *inst)
gboolean qof_backend_begin_exists (QofBackend *be)
void qof_backend_run_commit (QofBackend *be, QofInstance *inst)
gboolean qof_backend_commit_exists (QofBackend *be)

Session Errors

QofBackendError qof_session_get_error (QofSession *session)
const gchar * qof_session_get_error_message (QofSession *session)
QofBackendError qof_session_pop_error (QofSession *session)

Copying entities between sessions.

Only certain backends can cope with selective copying of entities and only fully defined QOF entities can be copied between sessions - see the QOF Serialisation Format (QSF) documentation (qsf_write_file) for more information.

The recommended backend for the new session is QSF or a future SQL backend. Using any of these entity copy functions sets a flag in the backend that this is now a partial QofBook. See Referring to entities outside a partial book.. When you save a session containing a partial QofBook, the session will check that the backend is able to handle the partial book. If not, the backend will be replaced by one that can handle partial books, preferably one using the same access_method. Currently, this means that a book using the GnuCash XML v2 file backend will be switched to QSF.

Copied entities are identical to the source entity, all parameters defined with QofAccessFunc and QofSetterFunc in QOF are copied and the GUID of the original QofEntity is set in the new entity. Sessions containing copied entities are intended for use as mechanisms for data export.

It is acceptable to add entities to new_session in batches. Note that any of these calls will fail if an entity already exists in new_session with the same GUID as any entity to be copied.

To merge a whole QofBook or where there is any possibility of collisions or requirement for user intervention, see Merging QofBook structures

gboolean qof_entity_copy_to_session (QofSession *new_session, QofEntity *original)
 Copy a single QofEntity to another session.
gboolean qof_entity_copy_list (QofSession *new_session, GList *entity_list)
 Copy a GList of entities to another session.
gboolean qof_entity_copy_coll (QofSession *new_session, QofCollection *entity_coll)
 Copy a QofCollection of entities.
gboolean qof_entity_copy_coll_r (QofSession *new_session, QofCollection *coll)
 Recursively copy a collection of entities to a session.
gboolean qof_entity_copy_one_r (QofSession *new_session, QofEntity *ent)
 Recursively copy a single entity to a new session.

Event Handling

gboolean qof_session_events_pending (QofSession *session)
gboolean qof_session_process_events (QofSession *session)

Defines

#define QOF_MOD_BACKEND   "qof-backend"
#define QOF_MOD_SESSION   "qof-session"
#define QOF_STDOUT   "file:"
 Allow session data to be printed to stdout.

Typedefs

typedef QofBackendProvider_s QofBackendProvider
typedef QofBackend_s QofBackend
 Pseudo-object providing an interface between the framework and a persistant data store (e.g. a server, a database, or a file).
typedef void(* QofBePercentageFunc )(const gchar *message, double percent)
 DOCUMENT ME!
typedef _QofSession QofSession
typedef void(* QofPercentageFunc )(const gchar *message, double percent)

Enumerations

enum  QofBackendError {
  ERR_BACKEND_NO_ERR = 0, ERR_BACKEND_NO_HANDLER, ERR_BACKEND_NO_BACKEND, ERR_BACKEND_BAD_URL,
  ERR_BACKEND_NO_SUCH_DB, ERR_BACKEND_CANT_CONNECT, ERR_BACKEND_CONN_LOST, ERR_BACKEND_LOCKED,
  ERR_BACKEND_READONLY, ERR_BACKEND_TOO_NEW, ERR_BACKEND_DATA_CORRUPT, ERR_BACKEND_SERVER_ERR,
  ERR_BACKEND_ALLOC, ERR_BACKEND_PERM, ERR_BACKEND_MODIFIED, ERR_BACKEND_MOD_DESTROY,
  ERR_BACKEND_MISC, ERR_QSF_INVALID_OBJ, ERR_QSF_INVALID_MAP, ERR_QSF_BAD_OBJ_GUID,
  ERR_QSF_BAD_QOF_VERSION, ERR_QSF_BAD_MAP, ERR_QSF_NO_MAP, ERR_QSF_WRONG_MAP,
  ERR_QSF_MAP_NOT_OBJ, ERR_QSF_OVERFLOW, ERR_QSF_OPEN_NOT_MERGE, ERR_FILEIO_FILE_BAD_READ = 1000,
  ERR_FILEIO_FILE_EMPTY, ERR_FILEIO_FILE_LOCKERR, ERR_FILEIO_FILE_NOT_FOUND, ERR_FILEIO_FILE_TOO_OLD,
  ERR_FILEIO_UNKNOWN_FILE_TYPE, ERR_FILEIO_PARSE_ERROR, ERR_FILEIO_BACKUP_ERROR, ERR_FILEIO_WRITE_ERROR,
  ERR_FILEIO_READ_ERROR, ERR_FILEIO_NO_ENCODING, ERR_NETIO_SHORT_READ = 2000, ERR_NETIO_WRONG_CONTENT_TYPE,
  ERR_NETIO_NOT_GNCXML, ERR_SQL_MISSING_DATA = 3000, ERR_SQL_DB_TOO_OLD, ERR_SQL_DB_BUSY,
  ERR_RPC_HOST_UNK = 4000, ERR_RPC_CANT_BIND, ERR_RPC_CANT_ACCEPT, ERR_RPC_NO_CONNECTION,
  ERR_RPC_BAD_VERSION, ERR_RPC_FAILED, ERR_RPC_NOT_ADDED
}
 The errors that can be reported to the GUI & other front-end users. More...

Functions

gboolean qof_load_backend_library (const gchar *directory, const gchar *filename, const gchar *init_fcn)
 Load a QOF-compatible backend shared library.
QofBackendqof_book_get_backend (QofBook *book)
 Retrieve the backend used by this book.
void qof_book_set_backend (QofBook *book, QofBackend *)
 Set the backend used by this book.
QofSessionqof_session_new (void)
void qof_session_destroy (QofSession *session)
void qof_session_swap_data (QofSession *session_1, QofSession *session_2)
void qof_session_begin (QofSession *session, const char *book_id, gboolean ignore_lock, gboolean create_if_nonexistent)
void qof_session_load (QofSession *session, QofPercentageFunc percentage_func)
void qof_session_add_book (QofSession *session, QofBook *book)
QofBookqof_session_get_book (QofSession *session)
const gchar * qof_session_get_file_path (QofSession *session)
const gchar * qof_session_get_url (QofSession *session)
gboolean qof_session_not_saved (QofSession *session)
gboolean qof_session_save_may_clobber_data (QofSession *session)
void qof_session_save (QofSession *session, QofPercentageFunc percentage_func)
void qof_session_end (QofSession *session)
void qof_session_add_close_hook (GFunc fn, gpointer data)
void qof_session_call_close_hooks (QofSession *session)


Define Documentation

#define QOF_STDOUT   "file:"
 

Allow session data to be printed to stdout.

book_id can't be NULL and we do need to have an access_method, so use one to solve the other.

To print a session to stdout, use qof_session_begin. Example:

qof_session_begin(session,QOF_STDOUT,TRUE,FALSE);

When you call qof_session_save(session, NULL), the output will appear on stdout and can be piped or redirected to other processes.

Currently, only the QSF backend supports writing to stdout, other backends may return a QofBackendError.

Definition at line 400 of file qofsession.h.


Typedef Documentation

typedef struct QofBackend_s QofBackend
 

Pseudo-object providing an interface between the framework and a persistant data store (e.g. a server, a database, or a file).

There are no backend functions that are 'public' to users of the framework. The backend can, however, report errors to the GUI & other front-end users.

Definition at line 180 of file qofbackend.h.

typedef struct QofBackendOption_s QofBackendOption
 

A single Backend Configuration Option.

typedef void(* QofBackendOptionCB)(QofBackendOption *, gpointer data)
 

Backend configuration option foreach callback prototype.

Definition at line 245 of file qofbackend.h.

typedef struct QofBackendProvider_s QofBackendProvider
 

A structure that declares backend services that can be gotten. The Provider specifies a URL access method, and specifies the function to create a backend that can handle that URL access function.

Definition at line 171 of file qofbackend.h.

typedef void(* QofPercentageFunc)(const gchar *message, double percent)
 

The qof_session_load() method causes the QofBook to be made ready to to use with this URL/datastore. When the URL points at a file, then this routine would load the data from the file. With remote backends, e.g. network or SQL, this would load only enough data to make the book actually usable; it would not cause *all* of the data to be loaded.

XXX the current design tries to accomodate multiple calls to 'load' for each session, each time wiping out the old books; this seems wrong to me, and should be restricted to allow only one load per session.

Definition at line 163 of file qofsession.h.


Enumeration Type Documentation

enum QofBackendError
 

The errors that can be reported to the GUI & other front-end users.

Enumerator:
ERR_BACKEND_NO_HANDLER  no backend handler found for this access method (ENOSYS)
ERR_BACKEND_NO_BACKEND  Backend * pointer was unexpectedly null
ERR_BACKEND_BAD_URL  Can't parse url
ERR_BACKEND_NO_SUCH_DB  the named database doesn't exist
ERR_BACKEND_CANT_CONNECT  bad dbname/login/passwd or network failure
ERR_BACKEND_CONN_LOST  Lost connection to server
ERR_BACKEND_LOCKED  in use by another user (ETXTBSY)
ERR_BACKEND_READONLY  cannot write to file/directory
ERR_BACKEND_TOO_NEW  file/db version newer than what we can read
ERR_BACKEND_DATA_CORRUPT  data in db is corrupt
ERR_BACKEND_SERVER_ERR  error in response from server
ERR_BACKEND_ALLOC  internal memory allocation failure
ERR_BACKEND_PERM  user login successful, but no permissions to access the desired object
ERR_BACKEND_MODIFIED  commit of object update failed because another user has modified the object
ERR_BACKEND_MOD_DESTROY  commit of object update failed because another user has deleted the object
ERR_BACKEND_MISC  undetermined error
ERR_QSF_INVALID_OBJ  The QSF object failed to validate against the QSF object schema
ERR_QSF_INVALID_MAP  The QSF map failed to validate against the QSF map schema
ERR_QSF_BAD_OBJ_GUID  The QSF object contains one or more invalid GUIDs.
ERR_QSF_BAD_QOF_VERSION  QSF map or object doesn't match the current QOF_OBJECT_VERSION.
ERR_QSF_BAD_MAP  The selected map validates but is unusable.

This is usually because not all the required parameters for the defined objects have calculations described in the map.

ERR_QSF_NO_MAP  The QSF object file was loaded without a map.

The QSF Object file requires a map but it was not provided.

ERR_QSF_WRONG_MAP  The selected map validates but is for different objects.

The list of objects defined in this map does not include all the objects described in the current QSF object file.

ERR_QSF_MAP_NOT_OBJ  Selected file is a QSF map and cannot be opened as a QSF object
ERR_QSF_OVERFLOW  EOVERFLOW - generated by strtol or strtoll.

When converting XML strings into numbers, an overflow has been detected. The XML file contains invalid data in a field that is meant to hold a signed long integer or signed long long integer.

ERR_FILEIO_FILE_BAD_READ  QSF files cannot be opened alone. The data must be merged.

This error is more of a warning that can be ignored by any routine that uses qof_book_merge on the new session. read failed or file prematurely truncated

ERR_FILEIO_FILE_EMPTY  file exists, is readable, but is empty
ERR_FILEIO_FILE_LOCKERR  mangled locks (unspecified error)
ERR_FILEIO_FILE_NOT_FOUND  not found / no such file
ERR_FILEIO_FILE_TOO_OLD  file version so old we can't read it
ERR_FILEIO_UNKNOWN_FILE_TYPE  didn't recognize the file type
ERR_FILEIO_PARSE_ERROR  couldn't parse the data in the file
ERR_FILEIO_BACKUP_ERROR  couldn't make a backup of the file
ERR_FILEIO_WRITE_ERROR  couldn't write to the file
ERR_FILEIO_READ_ERROR  Could not open the file for reading.
ERR_FILEIO_NO_ENCODING  file does not specify encoding
ERR_NETIO_SHORT_READ  not enough bytes received
ERR_NETIO_WRONG_CONTENT_TYPE  wrong kind of server, wrong data served
ERR_NETIO_NOT_GNCXML 
Deprecated:
whatever it is, we can't parse it.
ERR_SQL_MISSING_DATA  database doesn't contain expected data
ERR_SQL_DB_TOO_OLD  database is old and needs upgrading
ERR_SQL_DB_BUSY  database is busy, cannot upgrade version
ERR_RPC_HOST_UNK  Host unknown
ERR_RPC_CANT_BIND  can't bind to address
ERR_RPC_CANT_ACCEPT  can't accept connection
ERR_RPC_NO_CONNECTION  no connection to server
ERR_RPC_BAD_VERSION  RPC Version Mismatch
ERR_RPC_FAILED  Operation failed
ERR_RPC_NOT_ADDED  object not added

Definition at line 54 of file qofbackend.h.

00055 {
00056     ERR_BACKEND_NO_ERR = 0,
00057     ERR_BACKEND_NO_HANDLER,   
00059     ERR_BACKEND_NO_BACKEND,   
00061     ERR_BACKEND_BAD_URL,      
00062     ERR_BACKEND_NO_SUCH_DB,   
00063     ERR_BACKEND_CANT_CONNECT, 
00065     ERR_BACKEND_CONN_LOST,    
00066     ERR_BACKEND_LOCKED,       
00067     ERR_BACKEND_READONLY,       
00068     ERR_BACKEND_TOO_NEW,      
00070     ERR_BACKEND_DATA_CORRUPT, 
00071     ERR_BACKEND_SERVER_ERR,   
00072     ERR_BACKEND_ALLOC,        
00073     ERR_BACKEND_PERM,         
00075     ERR_BACKEND_MODIFIED,     
00077     ERR_BACKEND_MOD_DESTROY,  
00079     ERR_BACKEND_MISC,         
00081     /* QSF add-ons */
00082     ERR_QSF_INVALID_OBJ,        
00084     ERR_QSF_INVALID_MAP,        
00086     ERR_QSF_BAD_OBJ_GUID,       
00088     ERR_QSF_BAD_QOF_VERSION,    
00090     ERR_QSF_BAD_MAP,            
00096     ERR_QSF_NO_MAP,     
00101     ERR_QSF_WRONG_MAP,      
00107     ERR_QSF_MAP_NOT_OBJ,        
00109     ERR_QSF_OVERFLOW,           
00117     ERR_QSF_OPEN_NOT_MERGE, 
00122     /* fileio errors */
00123     ERR_FILEIO_FILE_BAD_READ = 1000,  
00125     ERR_FILEIO_FILE_EMPTY,     
00127     ERR_FILEIO_FILE_LOCKERR,   
00128     ERR_FILEIO_FILE_NOT_FOUND, 
00129     ERR_FILEIO_FILE_TOO_OLD,   
00131     ERR_FILEIO_UNKNOWN_FILE_TYPE, 
00133     ERR_FILEIO_PARSE_ERROR,    
00135     ERR_FILEIO_BACKUP_ERROR,   
00137     ERR_FILEIO_WRITE_ERROR,    
00138     ERR_FILEIO_READ_ERROR,     
00140     ERR_FILEIO_NO_ENCODING,    
00142     /* network errors */
00143     ERR_NETIO_SHORT_READ = 2000,  
00144     ERR_NETIO_WRONG_CONTENT_TYPE, 
00146     ERR_NETIO_NOT_GNCXML,         
00149     /* database errors */
00150     ERR_SQL_MISSING_DATA = 3000,  
00152     ERR_SQL_DB_TOO_OLD,           
00154     ERR_SQL_DB_BUSY,              
00157     /* RPC errors */
00158     ERR_RPC_HOST_UNK = 4000,      
00159     ERR_RPC_CANT_BIND,            
00160     ERR_RPC_CANT_ACCEPT,          
00161     ERR_RPC_NO_CONNECTION,        
00162     ERR_RPC_BAD_VERSION,          
00163     ERR_RPC_FAILED,               
00164     ERR_RPC_NOT_ADDED,            
00165 } QofBackendError;


Function Documentation

KvpFrame* qof_backend_complete_frame QofBackend be  ) 
 

Complete the backend_configuration and return the frame.

Definition at line 280 of file qofbackend.c.

00281 {
00282     g_return_val_if_fail (be, NULL);
00283     be->config_count = 0;
00284     return be->backend_configuration;
00285 }

KvpFrame* qof_backend_get_config QofBackend be  ) 
 

Get the available configuration options.

To retrieve the options from the returned KvpFrame, the caller needs to parse the XML file that documents the option names and data types. The XML file itself is part of the backend and is installed in a directory determined by the backend. Therefore, loading a new backend requires two paths: the path to the .la file and the path to the xml. Both paths are available by including a generated header file, e.g. gncla-dir.h defines GNC_LIB_DIR for the location of the .la file and GNC_XML_DIR for the xml.

Parameters:
be The QofBackend to be configured.
Returns:
A new KvpFrame containing the available options or NULL on failure.

Definition at line 482 of file qofbackend.c.

00483 {
00484     if (!be)
00485         return NULL;
00486     if (!be->get_config)
00487         return NULL;
00488     return (be->get_config) (be);
00489 }

void qof_backend_load_config QofBackend be,
KvpFrame config
 

Load configuration options specific to this backend.

Parameters:
be The backend to configure.
config A KvpFrame of QofBackendOptions that this backend will recognise. Each backend needs to document their own config types and acceptable values.

Definition at line 472 of file qofbackend.c.

00473 {
00474     if (!be || !config)
00475         return;
00476     if (!be->load_config)
00477         return;
00478     (be->load_config) (be, config);
00479 }

void qof_backend_option_foreach KvpFrame config,
QofBackendOptionCB  cb,
gpointer  data
 

Iterate over the frame and process each option.

Definition at line 455 of file qofbackend.c.

00457 {
00458     struct config_iterate helper;
00459 
00460     if (!config || !cb)
00461         return;
00462     ENTER (" ");
00463     helper.fcn = cb;
00464     helper.count = 1;
00465     helper.data = data;
00466     helper.recursive = config;
00467     kvp_frame_for_each_slot (config, config_foreach_cb, &helper);
00468     LEAVE (" ");
00469 }

void qof_backend_prepare_frame QofBackend be  ) 
 

Initialise the backend_configuration

Definition at line 183 of file qofbackend.c.

00184 {
00185     g_return_if_fail (be);
00186     if (!kvp_frame_is_empty (be->backend_configuration))
00187     {
00188         kvp_frame_delete (be->backend_configuration);
00189         be->backend_configuration = kvp_frame_new ();
00190     }
00191     be->config_count = 0;
00192 }

void qof_backend_prepare_option QofBackend be,
QofBackendOption option
 

Add an option to the backend_configuration. Repeat for more.

Definition at line 195 of file qofbackend.c.

00197 {
00198     KvpValue *value;
00199     gchar *temp;
00200     gint count;
00201 
00202     g_return_if_fail (be || option);
00203     count = be->config_count;
00204     count++;
00205     value = NULL;
00206     switch (option->type)
00207     {
00208     case KVP_TYPE_GINT64:
00209         {
00210             value = kvp_value_new_gint64 (*(gint64 *) option->value);
00211             break;
00212         }
00213     case KVP_TYPE_DOUBLE:
00214         {
00215             value = kvp_value_new_double (*(double *) option->value);
00216             break;
00217         }
00218     case KVP_TYPE_NUMERIC:
00219         {
00220             value = kvp_value_new_numeric (*(gnc_numeric *) option->value);
00221             break;
00222         }
00223     case KVP_TYPE_STRING:
00224         {
00225             value = kvp_value_new_string ((const char *) option->value);
00226             break;
00227         }
00228     case KVP_TYPE_GUID:
00229         {
00230             break;
00231         }                       /* unsupported */
00232     case KVP_TYPE_TIME :
00233         {
00234             value = kvp_value_new_time ((QofTime*) option->value);
00235             break;
00236         }
00237 #ifndef QOF_DISABLE_DEPRECATED
00238     case KVP_TYPE_TIMESPEC:
00239         {
00240             value = kvp_value_new_timespec (*(Timespec *) option->value);
00241             break;
00242         }
00243 #endif
00244     case KVP_TYPE_BINARY:
00245         {
00246             break;
00247         }                       /* unsupported */
00248     case KVP_TYPE_GLIST:
00249         {
00250             break;
00251         }                       /* unsupported */
00252     case KVP_TYPE_FRAME:
00253         {
00254             break;
00255         }                       /* unsupported */
00256     }
00257     if (value)
00258     {
00259         temp = g_strdup_printf ("/%s", option->option_name);
00260         kvp_frame_set_value (be->backend_configuration, temp, value);
00261         g_free (temp);
00262         temp =
00263             g_strdup_printf ("/%s/%s", QOF_CONFIG_DESC,
00264             option->option_name);
00265         kvp_frame_set_string (be->backend_configuration, temp,
00266             option->description);
00267         g_free (temp);
00268         temp =
00269             g_strdup_printf ("/%s/%s", QOF_CONFIG_TIP,
00270             option->option_name);
00271         kvp_frame_set_string (be->backend_configuration, temp,
00272             option->tooltip);
00273         g_free (temp);
00274         /* only increment the counter if successful */
00275         be->config_count = count;
00276     }
00277 }

void qof_book_set_backend QofBook book,
QofBackend
 

Set the backend used by this book.

Should only be used within a backend itself.

Definition at line 170 of file qofbook.c.

00171 {
00172     if (!book)
00173         return;
00174     ENTER ("book=%p be=%p", book, be);
00175     book->backend = be;
00176     LEAVE (" ");
00177 }

gboolean qof_entity_copy_coll QofSession new_session,
QofCollection entity_coll
 

Copy a QofCollection of entities.

The QofBook in the new_session must not contain any entities with the same GUID as any entities in the collection - there is no support for handling collisions - instead, use Merging QofBook structures

Parameters:
new_session - the target session
entity_coll - a QofCollection of any QofIdType.
Returns:
FALSE, without copying, if new_session contains any entities with the same GUID. Otherwise TRUE.

Definition at line 806 of file qofsession.c.

00806 {
00807     QofSession *session;
00808     gboolean success;
00809     GList *ref_list;
00810     GList *ent_list;
00811 };
00812 
00813 static void
00814 recurse_collection_cb (QofEntity * ent, gpointer user_data)
00815 {
00816     struct recurse_s *store;
00817 
00818     if (user_data == NULL)
00819     {
00820         return;
00821     }
00822     store = (struct recurse_s *) user_data;
00823     if (!ent || !store)
00824     {
00825         return;
00826     }
00827     store->success = qof_entity_copy_to_session (store->session, ent);
00828     if (store->success)
00829     {
00830         store->ent_list = g_list_append (store->ent_list, ent);

gboolean qof_entity_copy_coll_r QofSession new_session,
QofCollection coll
 

Recursively copy a collection of entities to a session.

Note:
This function creates a partial QofBook. See qof_entity_copy_to_session for more information.
The QofBook in the new_session must not contain any entities with the same GUID as any entities to be copied - there is no support for handling collisions - instead, use Merging QofBook structures

Objects can be defined solely in terms of QOF data types or as a mix of data types and other objects, which may in turn include other objects. These references can be copied recursively down to the third level. See QofEntityReference.

Note:
This is a deep recursive copy - every referenced entity is copied to the new session, including all parameters. The starting point is all entities in the top level collection. It can take some time.
Parameters:
coll A QofCollection of entities that may or may not have references.
new_session The QofSession to receive the copied entities.
Returns:
TRUE on success; if any individual copy fails, returns FALSE. Note : Some entities may have been copied successfully even if one of the references fails to copy.

Definition at line 1007 of file qofsession.c.

01012 {
01013     const gchar *libdir;
01014     const gchar *filename;
01015     const gchar *init_fcn;
01016 };
01017 
01018 /* All available QOF backends need to be described here
01019 and the last entry must be three NULL's.
01020 Remember: Use the libdir from the current build environment
01021 and use JUST the module name without .so - .so is not portable! */
01022 struct backend_providers backend_list[] = {
01023     {QOF_LIB_DIR, QSF_BACKEND_LIB, QSF_MODULE_INIT},
01024 #ifdef HAVE_DWI
01025     {QOF_LIB_DIR, "libqof_backend_dwi", "dwiend_provider_init"},
01026 #endif
01027     {NULL, NULL, NULL}
01028 };

gboolean qof_entity_copy_list QofSession new_session,
GList *  entity_list
 

Copy a GList of entities to another session.

The QofBook in the new_session must not contain any entities with the same GUID as any of the source entities - there is no support for handling collisions, instead use Merging QofBook structures

Note that the GList (e.g. from qof_sql_query_run) can contain QofEntity pointers of any QofIdType, in any sequence. As long as all members of the list are QofEntity*, and all GUID's are unique, the list can be copied.

Parameters:
new_session - the target session
entity_list - a GList of QofEntity pointers of any type(s).
Returns:
FALSE, without copying, if new_session contains any entities with the same GUID. Otherwise TRUE.

Definition at line 780 of file qofsession.c.

00781 {
00782     QofEntityCopyData qecd;
00783 
00784     g_return_val_if_fail (new_session, FALSE);
00785     if (!entity_coll)
00786     {
00787         return FALSE;
00788     }
00789     qof_event_suspend ();
00790     qecd.param_list = NULL;
00791     qecd.new_session = new_session;
00792     qof_book_set_partial (qof_session_get_book (qecd.new_session));
00793     qof_collection_foreach (entity_coll, qof_entity_coll_foreach, &qecd);
00794     qof_class_param_foreach (qof_collection_get_type (entity_coll),
00795         qof_entity_param_cb, &qecd);
00796     qof_collection_foreach (entity_coll, qof_entity_coll_copy, &qecd);
00797     if (qecd.param_list != NULL)
00798     {
00799         g_slist_free (qecd.param_list);
00800     }
00801     qof_event_resume ();
00802     return TRUE;
00803 }

gboolean qof_entity_copy_one_r QofSession new_session,
QofEntity ent
 

Recursively copy a single entity to a new session.

Copy the single entity and all referenced entities to the second level.

Only entities that are directly referenced by the top level entity are copied.

This is a deep copy - all parameters of all referenced entities are copied. If the top level entity has no references, this is identical to qof_entity_copy_to_session.

Parameters:
ent A single entity that may or may not have references.
new_session The QofSession to receive the copied entities.
Returns:
TRUE on success; if any individual copy fails, returns FALSE. Note : Some entities may have been copied successfully even if one of the references fails to copy.

Definition at line 1031 of file qofsession.c.

01032 {
01033     GSList *p;
01034     GList *node;
01035     QofBackendProvider *prov;
01036     QofBook *book;
01037     char *msg;
01038     gint num;
01039     gboolean prov_type;
01040     gboolean (*type_check) (const char *);
01041 
01042     ENTER (" list=%d", g_slist_length (provider_list));
01043     prov_type = FALSE;
01044     if (NULL == provider_list)
01045     {
01046         for (num = 0; backend_list[num].filename != NULL; num++)
01047         {
01048             if (!qof_load_backend_library (backend_list[num].libdir,
01049                     backend_list[num].filename,
01050                     backend_list[num].init_fcn))
01051             {
01052                 PWARN (" failed to load %s from %s using %s",
01053                     backend_list[num].filename, backend_list[num].libdir,
01054                     backend_list[num].init_fcn);
01055             }
01056         }
01057     }

gboolean qof_entity_copy_to_session QofSession new_session,
QofEntity original
 

Copy a single QofEntity to another session.

Checks first that no entity in the session book contains the GUID of the source entity.

Parameters:
new_session - the target session
original - the QofEntity* to copy
Returns:
FALSE without copying if the session contains an entity with the same GUID already, otherwise TRUE.

Definition at line 746 of file qofsession.c.

00754 {
00755     QofEntityCopyData *qecd;
00756 
00757     if (!new_session || !entity_list)
00758     {
00759         return FALSE;
00760     }
00761     ENTER (" list=%d", g_list_length (entity_list));
00762     qecd = g_new0 (QofEntityCopyData, 1);
00763     qof_event_suspend ();
00764     qecd->param_list = NULL;
00765     qecd->new_session = new_session;
00766     qof_book_set_partial (qof_session_get_book (new_session));
00767     g_list_foreach (entity_list, qof_entity_list_foreach, qecd);
00768     qof_event_resume ();
00769     if (qecd->error)
00770     {
00771         PWARN (" some/all entities in the list could not be copied.");
00772     }
00773     g_free (qecd);
00774     LEAVE (" ");
00775     return TRUE;
00776 }
00777 

gboolean qof_load_backend_library const gchar *  directory,
const gchar *  filename,
const gchar *  init_fcn
 

Load a QOF-compatible backend shared library.

Parameters:
directory Can be NULL if filename is a complete path.
filename Name of the .la file that describes the shared library. This provides platform independence, courtesy of libtool.
init_fcn The QofBackendProvider init function.
Returns:
FALSE in case or error, otherwise TRUE.

Definition at line 503 of file qofbackend.c.

00505 {
00506     gchar *fullpath;
00507     typedef void (*backend_init) (void);
00508     GModule *backend;
00509     backend_init gmod_init;
00510     gpointer g;
00511 
00512     g_return_val_if_fail (g_module_supported (), FALSE);
00513     fullpath = g_module_build_path (directory, filename);
00514     backend = g_module_open (fullpath, G_MODULE_BIND_LAZY);
00515     if (!backend)
00516     {
00517         g_message ("%s: %s\n", PACKAGE, g_module_error ());
00518         return FALSE;
00519     }
00520     g = &gmod_init;
00521     if (!g_module_symbol (backend, init_fcn, g))
00522     {
00523         g_message ("%s: %s\n", PACKAGE, g_module_error ());
00524         return FALSE;
00525     }
00526     g_module_make_resident (backend);
00527     gmod_init ();
00528     g_free (fullpath);
00529     return TRUE;
00530 }

void qof_session_add_book QofSession session,
QofBook book
 

The qof_session_add_book() allows additional books to be added to a session. XXX Under construction, clarify the following when done: XXX There must already be an open book in the session already!? XXX Only one open book at a time per session is allowed!? XXX each book gets its own unique backend ???

Definition at line 233 of file qofsession.c.

00234 {
00235     GList *node;
00236     if (!session)
00237         return;
00238 
00239     ENTER (" sess=%p book=%p", session, addbook);
00240 
00241     /* See if this book is already there ... */
00242     for (node = session->books; node; node = node->next)
00243     {
00244         QofBook *book = node->data;
00245         if (addbook == book)
00246             return;
00247     }
00248 
00249     if ('y' == addbook->book_open)
00250     {
00251         /* hack alert -- someone should free all the books in the list,
00252          * but it should probably not be us ... since the books backends
00253          * should be shutdown first, etc */
00254 /* XXX this should probably be an error XXX */
00255         g_list_free (session->books);
00256         session->books = g_list_append (NULL, addbook);
00257     }
00258     else
00259     {
00260 /* XXX Need to tell the backend to add a book as well */
00261         session->books = g_list_append (session->books, addbook);
00262     }
00263 
00264     qof_book_set_backend (addbook, session->backend);
00265     LEAVE (" ");
00266 }

void qof_session_add_close_hook GFunc  fn,
gpointer  data
 

Register a function to be called just before a session is closed.

Parameters:
fn The function to be called. The function definition must be func(gpointer session, gpointer user_data);
data The data to be passed to the function.

Definition at line 66 of file qofsession.c.

00067 {
00068     GHook *hook;
00069 
00070     if (session_closed_hooks == NULL)
00071     {
00072         session_closed_hooks = malloc (sizeof (GHookList)); /* LEAKED */
00073         g_hook_list_init (session_closed_hooks, sizeof (GHook));
00074     }
00075 
00076     hook = g_hook_alloc (session_closed_hooks);
00077     if (!hook)
00078         return;
00079 
00080     hook->func = (GHookFunc) fn;
00081     hook->data = data;
00082     g_hook_append (session_closed_hooks, hook);
00083 }

void qof_session_begin QofSession session,
const char *  book_id,
gboolean  ignore_lock,
gboolean  create_if_nonexistent
 

The qof_session_begin () method begins a new session. It takes as an argument the book id. The book id must be a string in the form of a URI/URL. The access method specified depends on the loaded backends. In the absence of a customised backend, only QSF XML would be accepted). Paths may be relative or absolute. If the path is relative; that is, if the argument is "file:somefile.xml" then the current working directory is assumed. Customised backends can choose to search other, application-specific, directories as well.

The 'ignore_lock' argument, if set to TRUE, will cause this routine to ignore any global-datastore locks (e.g. file locks) that it finds. If set to FALSE, then file/database-global locks will be tested and obeyed.

If the datastore exists, can be reached (e.g over the net), connected to, opened and read, and a lock can be obtained then a lock will be obtained. Note that multi-user datastores (e.g. the SQL backend) typically will not need to get a global lock, and thus, the user will not be locked out. That's the whole point of 'multi-user'.

If the file/database doesn't exist, and the create_if_nonexistent flag is set to TRUE, then the database is created.

If an error occurs, it will be pushed onto the session error stack, and that is where it should be examined.

Definition at line 1185 of file qofsession.c.

01189     {
01190         qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
01191         LEAVE (" BAD: no backend: sess=%p book-id=%s",
01192             session, book_id ? book_id : "(null)");
01193         return;
01194     }
01195 
01196     /* If there's a begin method, call that. */
01197     if (session->backend->session_begin)
01198     {
01199 
01200         (session->backend->session_begin) (session->backend, session,
01201             session->book_id, ignore_lock, create_if_nonexistent);
01202         PINFO ("Done running session_begin on backend");
01203         err = qof_backend_get_error (session->backend);
01204         msg = qof_backend_get_message (session->backend);
01205         if (err != ERR_BACKEND_NO_ERR)
01206         {
01207             g_free (session->book_id);
01208             session->book_id = NULL;
01209             qof_session_push_error (session, err, msg);
01210             LEAVE (" backend error %d %s", err, msg);
01211             return;
01212         }
01213         if (msg != NULL)
01214         {
01215             PWARN ("%s", msg);
01216             g_free (msg);
01217         }
01218     }
01219 
01220     LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)");
01221 }
01222 
01223 /* ====================================================================== */
01224 
01225 void
01226 qof_session_load (QofSession * session, QofPercentageFunc percentage_func)
01227 {
01228     QofBook *newbook, *ob;
01229     QofBookList *oldbooks, *node;
01230     QofBackend *be;
01231     QofBackendError err;
01232 
01233     if (!session)
01234         return;
01235     if (!session->book_id)
01236         return;
01237 
01238     ENTER ("sess=%p book_id=%s", session, session->book_id
01239         ? session->book_id : "(null)");
01240 
01241     /* At this point, we should are supposed to have a valid book 
01242      * id and a lock on the file. */
01243 
01244     oldbooks = session->books;
01245 
01246     /* XXX why are we creating a book here? I think the books
01247      * need to be handled by the backend ... especially since 
01248      * the backend may need to load multiple books ... XXX. FIXME.
01249      */
01250     newbook = qof_book_new ();
01251     session->books = g_list_append (NULL, newbook);
01252     PINFO ("new book=%p", newbook);
01253 
01254     qof_session_clear_error (session);
01255 
01256     /* This code should be sufficient to initialize *any* backend,
01257      * whether http, postgres, or anything else that might come along.
01258      * Basically, the idea is that by now, a backend has already been
01259      * created & set up.  At this point, we only need to get the
01260      * top-level account group out of the backend, and that is a
01261      * generic, backend-independent operation.
01262      */
01263     be = session->backend;
01264     qof_book_set_backend (newbook, be);
01265 
01266     /* Starting the session should result in a bunch of accounts
01267      * and currencies being downloaded, but probably no transactions;
01268      * The GUI will need to do a query for that.
01269      */
01270     if (be)
01271     {
01272         be->percentage = percentage_func;
01273 
01274         if (be->load)
01275         {

void qof_session_call_close_hooks QofSession session  ) 
 

Call all registered session close hooks, informing them that the specified session is about to be closed.

Parameters:
session A pointer to the session being closed.

Definition at line 86 of file qofsession.c.

00087 {
00088     GHook *hook;
00089     GFunc fn;
00090 
00091     if (session_closed_hooks == NULL)
00092         return;
00093 
00094     hook = g_hook_first_valid (session_closed_hooks, FALSE);
00095     while (hook)
00096     {
00097         fn = (GFunc) hook->func;
00098         fn (session, hook->data);
00099         hook = g_hook_next_valid (session_closed_hooks, hook, FALSE);
00100     }
00101 }

void qof_session_end QofSession session  ) 
 

The qof_session_end() method will release the session lock. For the file backend, it will *not* save the data to a file. Thus, this method acts as an "abort" or "rollback" primitive. However, for other backends, such as the sql backend, the data would have been written out before this, and so this routines wouldn't roll-back anything; it would just shut the connection.

Definition at line 1559 of file qofsession.c.

01565 {
01566     GList *books_1, *books_2, *node;
01567 
01568     if (session_1 == session_2)
01569         return;
01570     if (!session_1 || !session_2)
01571         return;
01572 
01573     ENTER ("sess1=%p sess2=%p", session_1, session_2);
01574 
01575     books_1 = session_1->books;
01576     books_2 = session_2->books;
01577 
01578     session_1->books = books_2;
01579     session_2->books = books_1;
01580 

gboolean qof_session_events_pending QofSession session  ) 
 

The qof_session_events_pending() method will return TRUE if the backend has pending events which must be processed to bring the engine up to date with the backend.

Definition at line 1652 of file qofsession.c.

QofBackendError qof_session_get_error QofSession session  ) 
 

The qof_session_get_error() routine can be used to obtain the reason for any failure. Calling this routine returns the current error.

Definition at line 140 of file qofsession.c.

00141 {
00142     QofBackendError err;
00143 
00144     if (!session)
00145         return ERR_BACKEND_NO_BACKEND;
00146 
00147     /* if we have a local error, return that. */
00148     if (ERR_BACKEND_NO_ERR != session->last_err)
00149     {
00150         return session->last_err;
00151     }
00152 
00153     /* maybe we should return a no-backend error ??? */
00154     if (!session->backend)
00155         return ERR_BACKEND_NO_ERR;
00156 
00157     err = qof_backend_get_error (session->backend);
00158     session->last_err = err;
00159     return err;
00160 }

const gchar* qof_session_get_file_path QofSession session  ) 
 

The qof_session_get_file_path() routine returns the fully-qualified file path for the session. That is, if a relative or partial filename was for the session, then it had to have been fully resolved to open the session. This routine returns the result of this resolution. The path is always guaranteed to reside in the local file system, even if the session itself was opened as a URL. (currently, the filepath is derived from the url by substituting commas for slashes).

The qof_session_get_url() routine returns the url that was opened. URL's for local files take the form of file:/some/where/some/file.gml

Definition at line 277 of file qofsession.c.

00278 {
00279     if (!session)
00280         return NULL;
00281     if (!session->backend)
00282         return NULL;
00283     return session->backend->fullpath;
00284 }

gboolean qof_session_not_saved QofSession session  ) 
 

The qof_session_not_saved() subroutine will return TRUE if any data in the session hasn't been saved to long-term storage.

QofBackendError qof_session_pop_error QofSession session  ) 
 

The qof_session_pop_error() routine can be used to obtain the reason for any failure. Calling this routine resets the error value.

This routine allows an implementation of multiple error values, e.g. in a stack, where this routine pops the top value. The current implementation has a stack that is one-deep.

See qofbackend.h for a listing of returned errors.

Definition at line 179 of file qofsession.c.

00180 {
00181     QofBackendError err;
00182 
00183     if (!session)
00184         return ERR_BACKEND_NO_BACKEND;
00185 
00186     err = qof_session_get_error (session);
00187     qof_session_clear_error (session);
00188 
00189     return err;
00190 }

gboolean qof_session_process_events QofSession session  ) 
 

The qof_session_process_events() method will process any events indicated by the qof_session_events_pending() method. It returns TRUE if the engine was modified while engine events were suspended.

Definition at line 1665 of file qofsession.c.

void qof_session_save QofSession session,
QofPercentageFunc  percentage_func
 

Todo:
check the access_method too, not in scope here, yet.

Definition at line 1397 of file qofsession.c.

01402         {
01403             prov = p->data;
01404             if (TRUE == prov->partial_book_supported)
01405             {
01407                 /*  if((TRUE == prov->partial_book_supported) && 
01408                    (0 == strcasecmp (access_method, prov->access_method)))
01409                    { */
01410                 if (NULL == prov->backend_new)
01411                     continue;
01412                 /* Use the providers creation callback */
01413                 session->backend = (*(prov->backend_new)) ();
01414                 session->backend->provider = prov;
01415                 if (session->backend->session_begin)
01416                 {
01417                     /* Call begin - backend has been changed,
01418                        so make sure a file can be written,
01419                        use ignore_lock and create_if_nonexistent */
01420                     g_free (session->book_id);
01421                     session->book_id = NULL;
01422                     (session->backend->session_begin) (session->backend,
01423                         session, book_id, TRUE, TRUE);
01424                     PINFO
01425                         ("Done running session_begin on changed backend");
01426                     err = qof_backend_get_error (session->backend);
01427                     msg = qof_backend_get_message (session->backend);
01428                     if (err != ERR_BACKEND_NO_ERR)
01429                     {
01430                         g_free (session->book_id);
01431                         session->book_id = NULL;
01432                         qof_session_push_error (session, err, msg);
01433                         LEAVE ("changed backend error %d", err);
01434                         return;
01435                     }
01436                     if (msg != NULL)
01437                     {
01438                         PWARN ("%s", msg);
01439                         g_free (msg);
01440                     }
01441                 }
01442                 /* Tell the books about the backend that they'll be using. */
01443                 for (node = session->books; node; node = node->next)
01444                 {
01445                     book = node->data;
01446                     qof_book_set_backend (book, session->backend);
01447                 }
01448                 p = NULL;
01449             }
01450             if (p)
01451             {
01452                 p = p->next;
01453             }
01454         }
01455         if (!session->backend)
01456         {
01457             msg = g_strdup_printf ("failed to load backend");
01458             qof_session_push_error (session, ERR_BACKEND_NO_HANDLER, msg);
01459             return;
01460         }
01461     }
01462     /* If there is a backend, and the backend is reachable
01463      * (i.e. we can communicate with it), then synchronize with 
01464      * the backend.  If we cannot contact the backend (e.g.
01465      * because we've gone offline, the network has crashed, etc.)
01466      * then give the user the option to save to the local disk. 
01467      *
01468      * hack alert -- FIXME -- XXX the code below no longer
01469      * does what the words above say.  This needs fixing.
01470      */
01471     be = session->backend;
01472     if (be)
01473     {
01474         for (node = session->books; node; node = node->next)
01475         {
01476             abook = node->data;
01477             /* if invoked as SaveAs(), then backend not yet set */
01478             qof_book_set_backend (abook, be);
01479             be->percentage = percentage_func;
01480             if (be->sync)
01481             {
01482                 (be->sync) (be, abook);
01483                 if (save_error_handler (be, session))
01484                     return;
01485             }
01486         }
01487         /* If we got to here, then the backend saved everything 
01488          * just fine, and we are done. So return. */
01489         /* Return the book_id to previous value. */
01490         qof_session_clear_error (session);
01491         LEAVE ("Success");
01492         return;
01493     }
01494     else
01495     {
01496         msg = g_strdup_printf ("failed to load backend");
01497         qof_session_push_error (session, ERR_BACKEND_NO_HANDLER, msg);
01498     }
01499     LEAVE ("error -- No backend!");
01500 }
01501 
01502 /* ====================================================================== */
01503 
01504 void
01505 qof_session_end (QofSession * session)
01506 {
01507     if (!session)
01508         return;
01509 
01510     ENTER ("sess=%p book_id=%s", session, session->book_id
01511         ? session->book_id : "(null)");
01512 
01513     /* close down the backend first */
01514     if (session->backend && session->backend->session_end)
01515     {
01516         (session->backend->session_end) (session->backend);
01517     }
01518 
01519     qof_session_clear_error (session);
01520 
01521     g_free (session->book_id);
01522     session->book_id = NULL;
01523 
01524     LEAVE ("sess=%p book_id=%s", session, session->book_id
01525         ? session->book_id : "(null)");
01526 }
01527 
01528 void
01529 qof_session_destroy (QofSession * session)
01530 {
01531     GList *node;
01532     if (!session)
01533         return;
01534 
01535     ENTER ("sess=%p book_id=%s", session, session->book_id
01536         ? session->book_id : "(null)");
01537 
01538     qof_session_end (session);
01539 
01540     /* destroy the backend */
01541     qof_session_destroy_backend (session);
01542 
01543     for (node = session->books; node; node = node->next)
01544     {
01545         QofBook *book = node->data;
01546         qof_book_set_backend (book, NULL);
01547         qof_book_destroy (book);
01548     }
01549 
01550     session->books = NULL;
01551 #ifndef QOF_DISABLE_DEPRECATED
01552     if (session == qof_session_get_current_session())
01553         qof_session_clear_current_session();
01554 #endif

gboolean qof_session_save_may_clobber_data QofSession session  ) 
 

Allows the backend to warn the user if a dataset already exists.

Definition at line 1370 of file qofsession.c.

01370         {
01371             prov = session->backend->provider;
01372             if (TRUE == prov->partial_book_supported)
01373             {
01374                 /* if current backend supports partial, leave alone. */
01375                 change_backend = FALSE;
01376             }
01377             else
01378             {
01379                 change_backend = TRUE;
01380             }

void qof_session_swap_data QofSession session_1,
QofSession session_2
 

The qof_session_swap_data () method swaps the book of the two given sessions. It is useful for 'Save As' type functionality.

Definition at line 1618 of file qofsession.c.


Generated on Fri Sep 1 15:37:33 2006 for QOF by  doxygen 1.4.6