QOF  0.8.7
qsf-backend.c
00001 /*******************************************************************
00002  *            qsf-backend.c
00003  *
00004  *  Sat Jan  1 15:07:14 2005
00005  *  Copyright  2005-2008  Neil Williams
00006  *  linux@codehelp.co.uk
00007  *******************************************************************/
00008 /*
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  */
00023 
00024 #include "config.h"
00025 #include <errno.h>
00026 #include <sys/stat.h>
00027 #include <glib.h>
00028 #include <libxml/xmlmemory.h>
00029 #include <libxml/tree.h>
00030 #include <libxml/parser.h>
00031 #include <libxml/xmlschemas.h>
00032 #include "qof.h"
00033 #include "qofobject-p.h"
00034 #include "qof-backend-qsf.h"
00035 #include "qsf-xml.h"
00036 #include "kvputil-p.h"
00037 
00038 #define QSF_TYPE_BINARY "binary"
00039 #define QSF_TYPE_GLIST  "glist"
00040 #define QSF_TYPE_FRAME  "frame"
00041 
00042 static QofLogModule log_module = QOF_MOD_QSF;
00043 
00044 static void qsf_object_commitCB (gpointer key, gpointer value,
00045     gpointer data);
00046 
00047 struct QSFBackend_s
00048 {
00049     QofBackend be;
00050     QsfParam *params;
00051     gchar *fullpath;
00052 };
00053 
00054 typedef struct QSFBackend_s QSFBackend;
00055 
00056 static void
00057 option_cb (QofBackendOption * option, gpointer data)
00058 {
00059     QsfParam *params;
00060 
00061     params = (QsfParam *) data;
00062     g_return_if_fail (params);
00063     if (0 == safe_strcmp (QSF_COMPRESS, option->option_name))
00064     {
00065         params->use_gz_level = (*(gint64 *) option->value);
00066         PINFO (" compression=%" G_GINT64_FORMAT, params->use_gz_level);
00067     }
00068     if (0 == safe_strcmp (QSF_MAP_FILES, option->option_name))
00069     {
00070         params->map_files = g_list_copy ((GList *) option->value);
00071     }
00072     if (0 == safe_strcmp (QSF_ENCODING, option->option_name))
00073     {
00074         params->encoding = g_strdup (option->value);
00075         PINFO (" encoding=%s", params->encoding);
00076     }
00077     if (0 == safe_strcmp (QSF_DATE_CONVERT, option->option_name))
00078     {
00079         params->convert = (*(double *) option->value);
00080         if (params->convert > 0)
00081             PINFO (" converting date into time on file write.");
00082     }
00083 }
00084 
00085 static void
00086 qsf_load_config (QofBackend * be, KvpFrame * config)
00087 {
00088     QSFBackend *qsf_be;
00089     QsfParam *params;
00090 
00091     ENTER (" ");
00092     qsf_be = (QSFBackend *) be;
00093     g_return_if_fail (qsf_be->params);
00094     params = qsf_be->params;
00095     qof_backend_option_foreach (config, option_cb, params);
00096     LEAVE (" ");
00097 }
00098 
00099 static KvpFrame *
00100 qsf_get_config (QofBackend * be)
00101 {
00102     QofBackendOption *option;
00103     QSFBackend *qsf_be;
00104     QsfParam *params;
00105 
00106     if (!be)
00107     {
00108         return NULL;
00109     }
00110     ENTER (" ");
00111     qsf_be = (QSFBackend *) be;
00112     g_return_val_if_fail (qsf_be->params, NULL);
00113     params = qsf_be->params;
00114     qof_backend_prepare_frame (be);
00115     option = g_new0 (QofBackendOption, 1);
00116     option->option_name = QSF_COMPRESS;
00117     option->description =
00118         _("Level of compression to use: 0 for none, 9 for highest.");
00119     option->tooltip =
00120         _("QOF can compress QSF XML files using gzip. "
00121         "Note that compression is not used when outputting to STDOUT.");
00122     option->type = KVP_TYPE_GINT64;
00123     /* GINT_TO_POINTER can only be used for 32bit values. */
00124     option->value = (gpointer) & params->use_gz_level;
00125     qof_backend_prepare_option (be, option);
00126     g_free (option);
00127     option = g_new0 (QofBackendOption, 1);
00128     option->option_name = QSF_MAP_FILES;
00129     option->description =
00130         _("List of QSF map files to use for this session.");
00131     option->tooltip =
00132         _("QOF can convert objects within QSF XML files "
00133         "using a map of the changes required.");
00134     option->type = KVP_TYPE_GLIST;
00135     option->value = (gpointer) params->map_files;
00136     qof_backend_prepare_option (be, option);
00137     g_free (option);
00138     option = g_new0 (QofBackendOption, 1);
00139     option->option_name = QSF_ENCODING;
00140     option->description =
00141         _("Encoding string to use when writing the XML file.");
00142     option->tooltip =
00143         _("QSF defaults to UTF-8. Other encodings are supported by "
00144         "passing the encoding string in this option.");
00145     option->type = KVP_TYPE_STRING;
00146     option->value = (gpointer) params->encoding;
00147     qof_backend_prepare_option (be, option);
00148     g_free (option);
00149     option = g_new0 (QofBackendOption, 1);
00150     option->option_name = QSF_DATE_CONVERT;
00151     option->description = 
00152         _("Convert deprecated date values to time values.");
00153     option->tooltip = 
00154         _("Applications that support the new QOF time format "
00155         "need to enable this option to convert older date values into time. "
00156         "Applications that still use date should not set this option "
00157         "until time values are supported.");
00158     option->type = KVP_TYPE_GINT64;
00159     option->value = &params->convert;
00160     qof_backend_prepare_option (be, option);
00161     g_free (option);
00162     LEAVE (" ");
00163     return qof_backend_complete_frame (be);
00164 }
00165 
00166 GList **
00167 qsf_map_prepare_list (GList ** maps)
00168 {
00169     /* Add new map filenames here. */
00171     *maps = g_list_prepend (*maps, "pilot-qsf-GnuCashInvoice.xml");
00172     *maps = g_list_prepend (*maps, "pilot-qsf-gncCustomer.xml");
00173     return maps;
00174 }
00175 
00176 static void
00177 qsf_param_init (QsfParam * params)
00178 {
00179     gchar *qsf_time_string;
00180     gchar *qsf_enquiry_date;
00181     gchar * G_GNUC_UNUSED qsf_time_now;
00182     gchar * G_GNUC_UNUSED qsf_time_precision;
00183 
00184     g_return_if_fail (params != NULL);
00185     params->count = 0;
00186     params->convert = 1;
00187     params->use_gz_level = 0;
00188     params->supported_types = NULL;
00189     params->file_type = QSF_UNDEF;
00190     params->qsf_ns = NULL;
00191     params->output_doc = NULL;
00192     params->output_node = NULL;
00193     params->lister = NULL;
00194     params->full_kvp_path = NULL;
00195     params->map_ns = NULL;
00196     params->map_files = NULL;
00197     params->map_path = NULL;
00198     params->encoding = "UTF-8";
00199     params->qsf_object_list = NULL;
00200     params->qsf_parameter_hash =
00201         g_hash_table_new (g_str_hash, g_str_equal);
00202     params->qsf_default_hash = g_hash_table_new (g_str_hash, g_str_equal);
00203     params->qsf_define_hash = g_hash_table_new (g_str_hash, g_str_equal);
00204     params->qsf_calculate_hash =
00205         g_hash_table_new (g_str_hash, g_str_equal);
00206     params->referenceList = NULL;
00207     params->supported_types =
00208         g_slist_append (params->supported_types, QOF_TYPE_STRING);
00209     params->supported_types =
00210         g_slist_append (params->supported_types, QOF_TYPE_GUID);
00211     params->supported_types =
00212         g_slist_append (params->supported_types, QOF_TYPE_BOOLEAN);
00213     params->supported_types =
00214         g_slist_append (params->supported_types, QOF_TYPE_NUMERIC);
00215     params->supported_types = 
00216         g_slist_append (params->supported_types, QOF_TYPE_TIME);
00217     params->supported_types =
00218         g_slist_append (params->supported_types, QOF_TYPE_INT32);
00219     params->supported_types =
00220         g_slist_append (params->supported_types, QOF_TYPE_INT64);
00221     params->supported_types =
00222         g_slist_append (params->supported_types, QOF_TYPE_DOUBLE);
00223     params->supported_types =
00224         g_slist_append (params->supported_types, QOF_TYPE_CHAR);
00225     params->supported_types =
00226         g_slist_append (params->supported_types, QOF_TYPE_KVP);
00227     params->supported_types =
00228         g_slist_append (params->supported_types, QOF_TYPE_COLLECT);
00229     params->supported_types =
00230         g_slist_append (params->supported_types, QOF_TYPE_CHOICE);
00231     qsf_time_precision = "%j";
00232     qsf_enquiry_date = qof_time_stamp_now ();
00233     qsf_time_string = qof_date_print (qof_date_get_current(), 
00234         QOF_DATE_FORMAT_ISO);
00235     qsf_time_now  = qof_time_stamp_now ();
00236 
00237     g_hash_table_insert (params->qsf_default_hash, "qsf_enquiry_date",
00238         qsf_enquiry_date);
00239     g_hash_table_insert (params->qsf_default_hash, "qsf_time_now",
00240         qof_time_get_current());
00241     g_hash_table_insert (params->qsf_default_hash, "qsf_time_string",
00242         qsf_time_string);
00243     /* default map files */
00244     params->map_files = *qsf_map_prepare_list (&params->map_files);
00245     params->err_nomap = qof_error_register 
00246     (_("The selected QSF Object file '%s' requires a "
00247     "map but it was not provided."), TRUE);
00248     params->err_overflow = qof_error_register
00249     (_("When converting XML strings into numbers, an "
00250      "overflow has been detected. The QSF object file "
00251      "'%s' contains invalid data in a field that is "
00252      "meant to hold a number."), TRUE);
00253 }
00254 
00255 static gboolean
00256 qsf_determine_file_type (const gchar * path)
00257 {
00258     struct stat sbuf;
00259 
00260     if (!path)
00261         return TRUE;
00262     if (0 == safe_strcmp (path, QOF_STDOUT))
00263         return TRUE;
00264     if (stat (path, &sbuf) < 0)
00265     {
00266     /* in case the error is that the file does not exist */
00267         FILE * f;
00268         f = fopen (path, "a+");
00269         if (f)
00270         {
00271             fclose (f);
00272             return TRUE;
00273         }
00274         return FALSE;
00275     }
00276     if (sbuf.st_size == 0)
00277         return TRUE;
00278     if (is_our_qsf_object (path))
00279         return TRUE;
00280     else if (is_qsf_object (path))
00281         return TRUE;
00282     else if (is_qsf_map (path))
00283         return TRUE;
00284     return FALSE;
00285 }
00286 
00287 static void
00288 qsf_session_begin (QofBackend * be, QofSession * session,
00289     const gchar * book_path, gboolean ignore_lock,
00290     gboolean create_if_nonexistent)
00291 {
00292     QSFBackend *qsf_be;
00293     gchar *p, *path;
00294 
00295     PINFO (" ignore_lock=%d create_if_nonexistent=%d", ignore_lock,
00296         create_if_nonexistent);
00297     g_return_if_fail (be != NULL);
00298     g_return_if_fail (session);
00299     be->fullpath = g_strdup (book_path);
00300     qsf_be = (QSFBackend *) be;
00301     g_return_if_fail (qsf_be->params != NULL);
00302     qsf_be->fullpath = NULL;
00303     if (book_path == NULL)
00304     {
00305         /* allow use of stdout */
00306         qof_error_set_be (be, QOF_SUCCESS);
00307         return;
00308     }
00309     p = strchr (book_path, ':');
00310     if (p)
00311     {
00312         path = g_strdup (book_path);
00313         if (!g_ascii_strncasecmp (path, "file:", 5))
00314         {
00315             p = g_new0 (gchar, strlen (path) - 5 + 1);
00316             strcpy (p, path + 5);
00317         }
00318         qsf_be->fullpath = g_strdup (p);
00319         g_free (path);
00320     }
00321     else
00322         qsf_be->fullpath = g_strdup (book_path);
00323     if (create_if_nonexistent)
00324     {
00325         FILE *f;
00326 
00327         f = fopen (qsf_be->fullpath, "a+");
00328         if (f)
00329             fclose (f);
00330         else
00331         {
00332             qof_error_set_be (be, qof_error_register
00333             (_("could not write to '%s'. "
00334              "That database may be on a read-only file system, "
00335              "or you may not have write permission for the "
00336             "directory.\n"), TRUE));
00337             return;
00338         }
00339     }
00340     qof_error_set_be (be, QOF_SUCCESS);
00341 }
00342 
00343 static void
00344 qsf_free_params (QsfParam * params)
00345 {
00346     g_hash_table_destroy (params->qsf_calculate_hash);
00347     g_hash_table_destroy (params->qsf_default_hash);
00348     if (params->referenceList)
00349         g_list_free (params->referenceList);
00350     g_slist_free (params->supported_types);
00351     if (params->map_ns)
00352         xmlFreeNs (params->map_ns);
00353     if (params->output_doc)
00354         xmlFreeDoc (params->output_doc);
00355 }
00356 
00357 static void
00358 qsf_session_end (QofBackend * be)
00359 {
00360     QSFBackend *qsf_be;
00361 
00362     qsf_be = (QSFBackend *) be;
00363     g_return_if_fail (qsf_be != NULL);
00364     qsf_free_params (qsf_be->params);
00365     g_free (qsf_be->fullpath);
00366     qsf_be->fullpath = NULL;
00367     xmlCleanupParser ();
00368 }
00369 
00370 static void
00371 qsf_destroy_backend (QofBackend * be)
00372 {
00373     g_free (be);
00374 }
00375 
00376 static void
00377 ent_ref_cb (QofEntity * ent, gpointer user_data)
00378 {
00379     QsfParam *params;
00380     QofEntityReference *ref;
00381     void (*reference_setter) (QofEntity *, QofEntity *);
00382     QofEntity *reference;
00383     QofCollection *coll;
00384     QofIdType type;
00385 
00386     params = (QsfParam *) user_data;
00387     g_return_if_fail (params);
00388     while (params->referenceList)
00389     {
00390         ref = (QofEntityReference *) params->referenceList->data;
00391         if (qof_object_is_choice (ent->e_type))
00392             type = ref->choice_type;
00393         else
00394             type = ref->type;
00395         coll = qof_book_get_collection (params->book, type);
00396         reference = qof_collection_lookup_entity (coll, ref->ref_guid);
00397         reference_setter =
00398             (void (*)(QofEntity *, QofEntity *)) ref->param->param_setfcn;
00399         if (reference_setter != NULL)
00400         {
00401             qof_util_param_edit ((QofInstance *) ent, ref->param);
00402             qof_util_param_edit ((QofInstance *) reference, ref->param);
00403             reference_setter (ent, reference);
00404             qof_util_param_commit ((QofInstance *) ent, ref->param);
00405             qof_util_param_commit ((QofInstance *) reference, ref->param);
00406         }
00407         params->referenceList = g_list_next (params->referenceList);
00408     }
00409 }
00410 
00411 static void
00412 insert_ref_cb (QofObject * obj, gpointer user_data)
00413 {
00414     QsfParam *params;
00415 
00416     params = (QsfParam *) user_data;
00417     g_return_if_fail (params);
00418     qof_object_foreach (obj->e_type, params->book, ent_ref_cb, params);
00419 }
00420 
00421 /*================================================
00422     Load QofEntity into QofBook from XML in memory
00423 ==================================================*/
00424 
00425 static gboolean
00426 qsfdoc_to_qofbook (QsfParam * params)
00427 {
00428     QofInstance *inst;
00429     struct QsfNodeIterate qiter;
00430     QofBook *book;
00431     GList *object_list;
00432     xmlNodePtr qsf_root;
00433     xmlNsPtr qsf_ns;
00434 
00435     g_return_val_if_fail (params != NULL, FALSE);
00436     g_return_val_if_fail (params->input_doc != NULL, FALSE);
00437     g_return_val_if_fail (params->book != NULL, FALSE);
00438     g_return_val_if_fail (params->file_type == OUR_QSF_OBJ, FALSE);
00439     qsf_root = xmlDocGetRootElement (params->input_doc);
00440     if (!qsf_root)
00441         return FALSE;
00442     qsf_ns = qsf_root->ns;
00443     qiter.ns = qsf_ns;
00444     book = params->book;
00445     params->referenceList =
00446         (GList *) qof_book_get_data (book, ENTITYREFERENCE);
00447     qsf_node_foreach (qsf_root, qsf_book_node_handler, &qiter, params);
00448     object_list = g_list_copy (params->qsf_object_list);
00449     while (object_list != NULL)
00450     {
00451         params->object_set = object_list->data;
00452         object_list = g_list_next (object_list);
00453         params->qsf_parameter_hash = params->object_set->parameters;
00454         if (!qof_class_is_registered (params->object_set->object_type))
00455             continue;
00456         inst =
00457             (QofInstance *) qof_object_new_instance (params->object_set->
00458             object_type, book);
00459         g_return_val_if_fail (inst != NULL, FALSE);
00460         params->qsf_ent = &inst->entity;
00461         g_hash_table_foreach (params->qsf_parameter_hash,
00462             qsf_object_commitCB, params);
00463     }
00464     qof_object_foreach_type (insert_ref_cb, params);
00465     qof_book_set_data (book, ENTITYREFERENCE, params->referenceList);
00466     return TRUE;
00467 }
00468 
00469 /* QofBackend routine to load from file - needs a map.
00470 */
00471 static gboolean
00472 load_qsf_object (QofBook * book, const gchar * fullpath,
00473                  QsfParam * params)
00474 {
00475     xmlNodePtr qsf_root, map_root;
00476     xmlDocPtr mapDoc, foreign_doc;
00477     gchar *map_path, *map_file;
00478 
00479     map_file = params->map_path;
00480     mapDoc = NULL;
00481     /* use selected map */
00482     if (!map_file)
00483     {
00484         qof_error_set_be (params->be, params->err_nomap);
00485         return FALSE;
00486     }
00487     foreign_doc = xmlParseFile (fullpath);
00488     if (foreign_doc == NULL)
00489     {
00490         qof_error_set_be (params->be, qof_error_register
00491         (_("There was an error parsing the file '%s'.\n"), TRUE));
00492         return FALSE;
00493     }
00494     qsf_root = NULL;
00495     qsf_root = xmlDocGetRootElement (foreign_doc);
00496     params->qsf_ns = qsf_root->ns;
00497     params->book = book;
00498     map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
00499     if (!map_path)
00500     {
00501         qof_error_set_be (params->be, params->err_nomap);
00502         return FALSE;
00503     }
00504     mapDoc = xmlParseFile (map_path);
00505     if (!mapDoc)
00506     {
00507         qof_error_set_be (params->be, params->err_nomap);
00508         return FALSE;
00509     }
00510     map_root = xmlDocGetRootElement (mapDoc);
00511     params->map_ns = map_root->ns;
00512     params->input_doc = qsf_object_convert (mapDoc, qsf_root, params);
00513     qsfdoc_to_qofbook (params);
00514     return TRUE;
00515 }
00516 
00517 static gboolean
00518 load_our_qsf_object (const gchar * fullpath, QsfParam * params)
00519 {
00520     xmlNodePtr qsf_root;
00521 
00522     params->input_doc = xmlParseFile (fullpath);
00523     if (params->input_doc == NULL)
00524     {
00525         qof_error_set_be (params->be, qof_error_register
00526         (_("There was an error parsing the file '%s'."), TRUE));
00527         return FALSE;
00528     }
00529     qsf_root = NULL;
00530     qsf_root = xmlDocGetRootElement (params->input_doc);
00531     params->qsf_ns = qsf_root->ns;
00532     return qsfdoc_to_qofbook (params);
00533 }
00534 
00535 /* Determine the type of QSF and load it into the QofBook
00536 
00537 - is_our_qsf_object, OUR_QSF_OBJ, QSF object file using only QOF objects known
00538     to the calling process. No map is required.
00539 - is_qsf_object, IS_QSF_OBJ, QSF object file that may or may not have a QSF map
00540     to convert external objects. This temporary type will be set to HAVE_QSF_MAP 
00541     if a suitable map exists, or an error value returned: ERR_QSF_NO_MAP, 
00542     ERR_QSF_BAD_MAP or ERR_QSF_WRONG_MAP. This allows the calling process to inform 
00543     the user that the QSF itself is valid but a suitable map cannot be found.
00544 - is_qsf_map, IS_QSF_MAP, QSF map file. In the backend, this generates 
00545     ERR_QSF_MAP_NOT_OBJ but it can be used internally when processing maps to 
00546     match a QSF object.
00547 
00548 returns NULL on error, otherwise a pointer to the QofBook. Use
00549 the qof_book_merge API to merge the new data into the current
00550 QofBook. 
00551 */
00552 static void
00553 qsf_file_type (QofBackend * be, QofBook * book)
00554 {
00555     QSFBackend *qsf_be;
00556     QofErrorId parse_err;
00557     QsfParam *params;
00558     FILE *f;
00559     gchar *path;
00560     gboolean result;
00561 
00562     g_return_if_fail (be != NULL);
00563     g_return_if_fail (book != NULL);
00564     qsf_be = (QSFBackend *) be;
00565     g_return_if_fail (qsf_be != NULL);
00566     g_return_if_fail (qsf_be->fullpath != NULL);
00567     g_return_if_fail (qsf_be->params != NULL);
00568     parse_err = qof_error_register
00569         (_("There was an error parsing the file '%s'."), TRUE);
00570     params = qsf_be->params;
00571     params->book = book;
00572     DEBUG (" qsf_be->fullpath=%s", qsf_be->fullpath);
00573     path = g_strdup (qsf_be->fullpath);
00574     f = fopen (path, "r");
00575     if (!f)
00576         qof_error_set_be (be, qof_error_register
00577         (_("There was an error reading the file '%s'."), TRUE));
00578     else
00579         fclose (f);
00580     params->filepath = g_strdup (path);
00581     result = is_our_qsf_object_be (params);
00582     if (result)
00583     {
00584         params->file_type = OUR_QSF_OBJ;
00585         result = load_our_qsf_object (path, params);
00586         if (!result)
00587             qof_error_set_be (be, parse_err);
00588         return;
00589     }
00590     else if (is_qsf_object_be (params))
00591     {
00592         params->file_type = IS_QSF_OBJ;
00593         result = load_qsf_object (book, path, params);
00594         if (!result)
00595             qof_error_set_be (be, parse_err);
00596         return;
00597     }
00598     if (qof_error_check_be (be) == params->err_nomap)
00599     {
00600         /* usable QSF object but no map available */
00601         params->file_type = IS_QSF_OBJ;
00602         result = TRUE;
00603     }
00604     if (result == FALSE)
00605     {
00606         if (is_qsf_map_be (params))
00607         {
00608             params->file_type = IS_QSF_MAP;
00609             qof_error_set_be (be, qof_error_register
00610             (_("The selected file '%s' is a QSF map and cannot "
00611                 "be opened as a QSF object."), TRUE));
00612         }
00613     }
00614 }
00615 
00616 static void
00617 qsf_object_sequence (QofParam * qof_param, gpointer data)
00618 {
00619     QsfParam *params;
00620     GSList *checklist, *result;
00621 
00622     g_return_if_fail (data != NULL);
00623     params = (QsfParam *) data;
00624     result = NULL;
00625     checklist = NULL;
00626     params->knowntype = FALSE;
00627     checklist = g_slist_copy (params->supported_types);
00628     for (result = checklist; result != NULL; result = result->next)
00629     {
00630         if (0 ==
00631             safe_strcmp ((QofIdType) result->data, 
00632             qof_param->param_type))
00633             params->knowntype = TRUE;
00634     }
00635     g_slist_free (checklist);
00636     if (0 == safe_strcmp (qof_param->param_type, params->qof_type))
00637     {
00638         params->qsf_sequence =
00639             g_slist_append (params->qsf_sequence, qof_param);
00640         params->knowntype = TRUE;
00641     }
00642     /* handle params->qof_type = QOF_TYPE_GUID and qof_param->param_type != known type */
00643     if (0 == safe_strcmp (params->qof_type, QOF_TYPE_GUID)
00644         && (params->knowntype == FALSE))
00645     {
00646         params->qsf_sequence =
00647             g_slist_append (params->qsf_sequence, qof_param);
00648         params->knowntype = TRUE;
00649     }
00650 }
00651 
00652 /* receives each entry from supported_types in sequence
00653     type = qof data type from supported list
00654     user_data = params. Holds object type
00655 */
00656 static void
00657 qsf_supported_parameters (gpointer type, gpointer user_data)
00658 {
00659     QsfParam *params;
00660 
00661     g_return_if_fail (user_data != NULL);
00662     params = (QsfParam *) user_data;
00663     params->qof_type = (QofIdType) type;
00664     params->knowntype = FALSE;
00665     qof_class_param_foreach (params->qof_obj_type, qsf_object_sequence,
00666         params);
00667 }
00668 
00669 static KvpValueType
00670 qsf_to_kvp_helper (const char *type_string)
00671 {
00672     KvpValueType kvt;
00673     kvt = qof_id_to_kvp_value_type (type_string);
00674     if (kvt != 0)
00675         return kvt;
00676     if (0 == safe_strcmp (QSF_TYPE_BINARY, type_string))
00677         return KVP_TYPE_BINARY;
00678     if (0 == safe_strcmp (QSF_TYPE_GLIST, type_string))
00679         return KVP_TYPE_GLIST;
00680     if (0 == safe_strcmp (QSF_TYPE_FRAME, type_string))
00681         return KVP_TYPE_FRAME;
00682     return 0;
00683 }
00684 
00685 static QofIdTypeConst
00686 kvp_value_to_qof_type_helper (KvpValueType n)
00687 {
00688     QofIdTypeConst qtc;
00689     qtc = kvp_value_type_to_qof_id (n);
00690     if (qtc)
00691         return qtc;
00692     switch (n)
00693     {
00694         case KVP_TYPE_BINARY:
00695         {
00696             return QSF_TYPE_BINARY;
00697             break;
00698         }
00699         case KVP_TYPE_GLIST:
00700         {
00701             return QSF_TYPE_GLIST;
00702             break;
00703         }
00704         case KVP_TYPE_FRAME:
00705         {
00706             return QSF_TYPE_FRAME;
00707             break;
00708         }
00709         default:
00710         {
00711             return NULL;
00712         }
00713     }
00714 }
00715 
00716 
00717 static void
00718 qsf_from_kvp_helper (const gchar * path, KvpValue * content, 
00719                      gpointer data)
00720 {
00721     QsfParam *params;
00722     QofParam *qof_param;
00723     xmlNodePtr node;
00724     KvpValueType n;
00725     gchar *full_path;
00726 
00727     params = (QsfParam *) data;
00728     qof_param = params->qof_param;
00729     full_path = NULL;
00730     g_return_if_fail (params && path && content);
00731     n = kvp_value_get_type (content);
00732     switch (n)
00733     {
00734         case KVP_TYPE_GINT64:
00735         case KVP_TYPE_DOUBLE:
00736         case KVP_TYPE_NUMERIC:
00737         case KVP_TYPE_STRING:
00738         case KVP_TYPE_GUID:
00739         case KVP_TYPE_TIME :
00740         case KVP_TYPE_BOOLEAN :
00741         case KVP_TYPE_BINARY:
00742         case KVP_TYPE_GLIST:
00743         {
00744             node =
00745                 xmlAddChild (params->output_node,
00746                 xmlNewNode (params->qsf_ns,
00747                     BAD_CAST qof_param->param_type));
00748             xmlNodeAddContent (node,
00749                 BAD_CAST kvp_value_to_bare_string (content));
00750             xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE,
00751                 BAD_CAST qof_param->param_name);
00752             full_path =
00753                 g_strconcat (params->full_kvp_path, "/", path, NULL);
00754             xmlNewProp (node, BAD_CAST QSF_OBJECT_KVP, BAD_CAST full_path);
00755             xmlNewProp (node, BAD_CAST QSF_OBJECT_VALUE,
00756                 BAD_CAST kvp_value_to_qof_type_helper (n));
00757             break;
00758         }
00759         case KVP_TYPE_FRAME:
00760         {
00761             if (!params->full_kvp_path)
00762                 params->full_kvp_path = g_strdup (path);
00763             else
00764                 params->full_kvp_path = g_strconcat (params->full_kvp_path,
00765                     "/", path, NULL);
00766             kvp_frame_for_each_slot (kvp_value_get_frame (content),
00767                 qsf_from_kvp_helper, params);
00768             g_free (params->full_kvp_path);
00769             params->full_kvp_path = NULL;
00770             break;
00771         }
00772         default:
00773         {
00774             PERR (" unsupported value = %d", kvp_value_get_type (content));
00775             break;
00776         }
00777     }
00778 }
00779 
00780 static void
00781 qsf_from_coll_cb (QofEntity * ent, gpointer user_data)
00782 {
00783     QsfParam *params;
00784     QofParam *qof_param;
00785     xmlNodePtr node;
00786     gchar qsf_guid[GUID_ENCODING_LENGTH + 1];
00787 
00788     params = (QsfParam *) user_data;
00789     if (!ent || !params)
00790         return;
00791     qof_param = params->qof_param;
00792     guid_to_string_buff (qof_entity_get_guid (ent), qsf_guid);
00793     node = xmlAddChild (params->output_node, xmlNewNode (params->qsf_ns,
00794             BAD_CAST qof_param->param_type));
00795     xmlNodeAddContent (node, BAD_CAST qsf_guid);
00796     xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE,
00797         BAD_CAST qof_param->param_name);
00798 }
00799 
00800 /******* reference handling ***********/
00801 
00802 static gint
00803 qof_reference_list_cb (gconstpointer a, gconstpointer b)
00804 {
00805     const QofEntityReference *aa;
00806     const QofEntityReference *bb;
00807 
00808     aa = (QofEntityReference *) a;
00809     bb = (QofEntityReference *) b;
00810     if (aa == NULL)
00811         return 1;
00812     g_return_val_if_fail ((bb != NULL), 1);
00813     g_return_val_if_fail ((aa->type != NULL), 1);
00814     if ((0 == guid_compare (bb->ent_guid, aa->ent_guid))
00815         && (0 == safe_strcmp (bb->type, aa->type))
00816         && (0 == safe_strcmp (bb->param->param_name,
00817                 aa->param->param_name)))
00818         return 0;
00819     return 1;
00820 }
00821 
00822 static QofEntityReference *
00823 qof_reference_lookup (GList * referenceList, QofEntityReference * find)
00824 {
00825     GList *single_ref;
00826     QofEntityReference *ent_ref;
00827 
00828     if (referenceList == NULL)
00829         return NULL;
00830     g_return_val_if_fail (find != NULL, NULL);
00831     single_ref = NULL;
00832     ent_ref = NULL;
00833     single_ref =
00834         g_list_find_custom (referenceList, find, qof_reference_list_cb);
00835     if (single_ref == NULL)
00836         return ent_ref;
00837     ent_ref = (QofEntityReference *) single_ref->data;
00838     g_list_free (single_ref);
00839     return ent_ref;
00840 }
00841 
00842 static void
00843 reference_list_lookup (gpointer data, gpointer user_data)
00844 {
00845     QofEntity *ent;
00846     QofParam *ref_param;
00847     QofEntityReference *reference, *starter;
00848     QsfParam *params;
00849     const GUID *guid;
00850     xmlNodePtr node, object_node;
00851     xmlNsPtr ns;
00852     GList *copy_list;
00853     gchar qsf_guid[GUID_ENCODING_LENGTH + 1], *ref_name;
00854 
00855     params = (QsfParam *) user_data;
00856     ref_param = (QofParam *) data;
00857     object_node = params->output_node;
00858     ent = params->qsf_ent;
00859     ns = params->qsf_ns;
00860     starter = g_new0 (QofEntityReference, 1);
00861     starter->ent_guid = qof_entity_get_guid (ent);
00862     starter->type = g_strdup (ent->e_type);
00863     starter->param = ref_param;
00864     starter->ref_guid = NULL;
00865     copy_list = g_list_copy (params->referenceList);
00866     reference = qof_reference_lookup (copy_list, starter);
00867     g_free (starter);
00868     if (reference != NULL)
00869     {
00870         if ((ref_param->param_getfcn == NULL)
00871             || (ref_param->param_setfcn == NULL))
00872             return;
00873         ref_name = g_strdup (reference->param->param_name);
00874         node =
00875             xmlAddChild (object_node,
00876             xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID));
00877         guid_to_string_buff (reference->ref_guid, qsf_guid);
00878         xmlNodeAddContent (node, BAD_CAST qsf_guid);
00879         xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_name);
00880         g_free (ref_name);
00881     }
00882     else
00883     {
00884         ent = (QofEntity *) ref_param->param_getfcn (ent, ref_param);
00885         if (!ent)
00886             return;
00887         if ((0 == safe_strcmp (ref_param->param_type, QOF_TYPE_COLLECT)) ||
00888             (0 == safe_strcmp (ref_param->param_type, QOF_TYPE_CHOICE)))
00889             return;
00890         node =
00891             xmlAddChild (object_node,
00892             xmlNewNode (ns, BAD_CAST QOF_TYPE_GUID));
00893         guid = qof_entity_get_guid (ent);
00894         guid_to_string_buff (guid, qsf_guid);
00895         xmlNodeAddContent (node, BAD_CAST qsf_guid);
00896         xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE,
00897             BAD_CAST ref_param->param_name);
00898     }
00899 }
00900 
00901 /*=====================================
00902     Convert QofEntity to QSF XML node
00903 qof_param holds the parameter sequence.
00904 =======================================*/
00905 static void
00906 qsf_entity_foreach (QofEntity * ent, gpointer data)
00907 {
00908     QsfParam *params;
00909     GSList *param_list, *supported;
00910     GList *ref;
00911     xmlNodePtr node, object_node;
00912     xmlNsPtr ns;
00913     gchar *string_buffer;
00914     QofParam *qof_param;
00915     QofEntity *choice_ent;
00916     KvpFrame *qsf_kvp;
00917     QofCollection *qsf_coll;
00918     gint param_count;
00919     gboolean own_guid;
00920     const GUID *cm_guid;
00921     gchar cm_sa[GUID_ENCODING_LENGTH + 1];
00922 
00923     g_return_if_fail (data != NULL);
00924     params = (QsfParam *) data;
00925     param_count = ++params->count;
00926     ns = params->qsf_ns;
00927     qsf_kvp = NULL;
00928     own_guid = FALSE;
00929     choice_ent = NULL;
00930     object_node = xmlNewChild (params->book_node, params->qsf_ns,
00931         BAD_CAST QSF_OBJECT_TAG, NULL);
00932     xmlNewProp (object_node, BAD_CAST QSF_OBJECT_TYPE,
00933         BAD_CAST ent->e_type);
00934     string_buffer = g_strdup_printf ("%i", param_count);
00935     xmlNewProp (object_node, BAD_CAST QSF_OBJECT_COUNT,
00936         BAD_CAST string_buffer);
00937     g_free (string_buffer);
00938     param_list = g_slist_copy (params->qsf_sequence);
00939     while (param_list != NULL)
00940     {
00941         qof_param = (QofParam *) param_list->data;
00942         g_return_if_fail (qof_param != NULL);
00943         if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_GUID))
00944         {
00945             if (!own_guid)
00946             {
00947                 cm_guid = qof_entity_get_guid (ent);
00948                 node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST
00949                         QOF_TYPE_GUID));
00950                 guid_to_string_buff (cm_guid, cm_sa);
00951                 string_buffer = g_strdup (cm_sa);
00952                 xmlNodeAddContent (node, BAD_CAST string_buffer);
00953                 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST
00954                     QOF_PARAM_GUID);
00955                 g_free (string_buffer);
00956                 own_guid = TRUE;
00957             }
00958             params->qsf_ent = ent;
00959             params->output_node = object_node;
00960             ref = qof_class_get_referenceList (ent->e_type);
00961             if (ref != NULL)
00962                 g_list_foreach (ref, reference_list_lookup, params);
00963         }
00964         if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_COLLECT))
00965         {
00966             qsf_coll = qof_param->param_getfcn (ent, qof_param);
00967             if (qsf_coll)
00968             {
00969                 params->qof_param = qof_param;
00970                 params->output_node = object_node;
00971                 if (qof_collection_count (qsf_coll) > 0)
00972                     qof_collection_foreach (qsf_coll, qsf_from_coll_cb,
00973                         params);
00974             }
00975             param_list = g_slist_next (param_list);
00976             continue;
00977         }
00978         if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_CHOICE))
00979         {
00981             choice_ent =
00982                 (QofEntity *) qof_param->param_getfcn (ent, qof_param);
00983             if (!choice_ent)
00984             {
00985                 param_list = g_slist_next (param_list);
00986                 continue;
00987             }
00988             node = xmlAddChild (object_node, xmlNewNode (ns, BAD_CAST
00989                     qof_param->param_type));
00990             cm_guid = qof_entity_get_guid (choice_ent);
00991             guid_to_string_buff (cm_guid, cm_sa);
00992             string_buffer = g_strdup (cm_sa);
00993             xmlNodeAddContent (node, BAD_CAST string_buffer);
00994             xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST
00995                 qof_param->param_name);
00996             xmlNewProp (node, BAD_CAST "name",
00997                 BAD_CAST choice_ent->e_type);
00998             g_free (string_buffer);
00999             param_list = g_slist_next (param_list);
01000             continue;
01001         }
01002         if (0 == safe_strcmp (qof_param->param_type, QOF_TYPE_KVP))
01003         {
01004             qsf_kvp =
01005                 (KvpFrame *) qof_param->param_getfcn (ent, qof_param);
01006             if (kvp_frame_is_empty (qsf_kvp))
01007                 return;
01008             params->qof_param = qof_param;
01009             params->output_node = object_node;
01010             kvp_frame_for_each_slot (qsf_kvp, qsf_from_kvp_helper, params);
01011         }
01012         if ((qof_param->param_setfcn != NULL)
01013             && (qof_param->param_getfcn != NULL))
01014         {
01015             for (supported = g_slist_copy (params->supported_types);
01016                 supported != NULL; supported = g_slist_next (supported))
01017             {
01018                 if (0 == safe_strcmp ((const gchar *) supported->data,
01019                         (const gchar *) qof_param->param_type))
01020                 {
01021                     node = xmlAddChild (object_node,
01022                         xmlNewNode (ns, BAD_CAST qof_param->param_type));
01023                     string_buffer =
01024                         g_strdup (qof_util_param_to_string
01025                         (ent, qof_param));
01026                     xmlNodeAddContent (node, BAD_CAST string_buffer);
01027                     xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST
01028                         qof_param->param_name);
01029                     g_free (string_buffer);
01030                 }
01031             }
01032         }
01033         param_list = g_slist_next (param_list);
01034     }
01035 }
01036 
01037 static void
01038 qsf_foreach_obj_type (QofObject * qsf_obj, gpointer data)
01039 {
01040     QsfParam *params;
01041     QofBook *book;
01042     GSList *support;
01043 
01044     g_return_if_fail (data != NULL);
01045     params = (QsfParam *) data;
01046     /* Skip unsupported objects */
01047     if ((qsf_obj->create == NULL) || (qsf_obj->foreach == NULL))
01048     {
01049         PINFO (" qsf_obj QOF support failed %s", qsf_obj->e_type);
01050         return;
01051     }
01052     params->qof_obj_type = qsf_obj->e_type;
01053     params->qsf_sequence = NULL;
01054     book = params->book;
01055     support = g_slist_copy (params->supported_types);
01056     g_slist_foreach (support, qsf_supported_parameters, params);
01057     qof_object_foreach (qsf_obj->e_type, book, qsf_entity_foreach, params);
01058 }
01059 
01060 /*=====================================================
01061     Take a QofBook and prepare a QSF XML doc in memory
01062 =======================================================*/
01063 /*  QSF only uses one QofBook per file - count may be removed later. */
01064 static xmlDocPtr
01065 qofbook_to_qsf (QofBook * book, QsfParam * params)
01066 {
01067     xmlNodePtr top_node, node;
01068     xmlDocPtr doc;
01069     gchar buffer[GUID_ENCODING_LENGTH + 1];
01070     const GUID *book_guid;
01071 
01072     g_return_val_if_fail (book != NULL, NULL);
01073     params->book = book;
01074     params->referenceList =
01075         g_list_copy ((GList *) qof_book_get_data (book, 
01076         ENTITYREFERENCE));
01077     doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION);
01078     top_node = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG);
01079     xmlDocSetRootElement (doc, top_node);
01080     xmlSetNs (top_node, xmlNewNs (top_node, BAD_CAST QSF_DEFAULT_NS,
01081             NULL));
01082     params->qsf_ns = top_node->ns;
01083     node =
01084         xmlNewChild (top_node, params->qsf_ns, BAD_CAST QSF_BOOK_TAG,
01085         NULL);
01086     params->book_node = node;
01087     xmlNewProp (node, BAD_CAST QSF_BOOK_COUNT, BAD_CAST "1");
01088     book_guid = qof_entity_get_guid ((QofEntity*)book);
01089     guid_to_string_buff (book_guid, buffer);
01090     xmlNewChild (params->book_node, params->qsf_ns,
01091         BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
01092     params->output_doc = doc;
01093     params->book_node = node;
01094     qof_object_foreach_type (qsf_foreach_obj_type, params);
01095     return params->output_doc;
01096 }
01097 
01098 static void
01099 write_qsf_from_book (const gchar *path, QofBook * book, 
01100                      QsfParam * params)
01101 {
01102     xmlDocPtr qsf_doc;
01103     gint write_result;
01104     QofBackend *be;
01105 
01106     be = qof_book_get_backend (book);
01107     qsf_doc = qofbook_to_qsf (book, params);
01108     write_result = 0;
01109     PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
01110         params->use_gz_level, params->encoding);
01111     if ((params->use_gz_level > 0) && (params->use_gz_level <= 9))
01112         xmlSetDocCompressMode (qsf_doc, params->use_gz_level);
01113     g_return_if_fail (qsf_is_valid
01114         (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
01115     write_result =
01116         xmlSaveFormatFileEnc (path, qsf_doc, params->encoding, 1);
01117     if (write_result < 0)
01118     {
01119         qof_error_set_be (be, qof_error_register
01120             (_("Could not write to '%s'. Check that you have "
01121              "permission to write to this file and that there is "
01122              "sufficient space to create it."), TRUE));
01123         return;
01124     }
01125     qof_object_mark_clean (book);
01126 }
01127 
01128 static void
01129 write_qsf_to_stdout (QofBook * book, QsfParam * params)
01130 {
01131     xmlDocPtr qsf_doc;
01132 
01133     qsf_doc = qofbook_to_qsf (book, params);
01134     g_return_if_fail (qsf_is_valid
01135         (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, qsf_doc) == TRUE);
01136     PINFO (" use_gz_level=%" G_GINT64_FORMAT " encoding=%s",
01137         params->use_gz_level, params->encoding);
01138     xmlSaveFormatFileEnc ("-", qsf_doc, params->encoding, 1);
01139     fprintf (stdout, "\n");
01140     qof_object_mark_clean (book);
01141 }
01142 
01143 static void
01144 qsf_write_file (QofBackend * be, QofBook * book)
01145 {
01146     QSFBackend *qsf_be;
01147     QsfParam *params;
01148     gchar *path;
01149 
01150     qsf_be = (QSFBackend *) be;
01151     params = qsf_be->params;
01152     /* if fullpath is blank, book_id was set to QOF_STDOUT */
01153     if (!qsf_be->fullpath || (*qsf_be->fullpath == '\0'))
01154     {
01155         write_qsf_to_stdout (book, params);
01156         return;
01157     }
01158     path = strdup (qsf_be->fullpath);
01159     write_qsf_from_book (path, book, params);
01160     g_free (path);
01161 }
01162 
01163 KvpValue *
01164 string_to_kvp_value (const gchar * content, KvpValueType type)
01165 {
01166     gchar *tail;
01167     gint64 cm_i64;
01168     gdouble cm_double;
01169     QofNumeric cm_numeric;
01170     GUID *cm_guid;
01171 
01172     switch (type)
01173     {
01174         case KVP_TYPE_GINT64:
01175         {
01176             errno = 0;
01177             cm_i64 = strtoll (content, &tail, 0);
01178             if (errno == 0)
01179             {
01180                 return kvp_value_new_gint64 (cm_i64);
01181             }
01182             break;
01183         }
01184         case KVP_TYPE_DOUBLE:
01185         {
01186             errno = 0;
01187             cm_double = strtod (content, &tail);
01188             if (errno == 0)
01189                 return kvp_value_new_double (cm_double);
01190             break;
01191         }
01192         case KVP_TYPE_NUMERIC:
01193         {
01194             qof_numeric_from_string (content, &cm_numeric);
01195             return kvp_value_new_numeric (cm_numeric);
01196             break;
01197         }
01198         case KVP_TYPE_STRING:
01199         {
01200             return kvp_value_new_string (content);
01201             break;
01202         }
01203         case KVP_TYPE_GUID:
01204         {
01205             cm_guid = g_new0 (GUID, 1);
01206             if (TRUE == string_to_guid (content, cm_guid))
01207                 return kvp_value_new_guid (cm_guid);
01208             break;
01209         }
01210         case KVP_TYPE_TIME :
01211         {
01212             QofDate *qd;
01213             QofTime *qt;
01214             KvpValue *retval;
01215 
01216             qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC);
01217             if(qd)
01218             {
01219                 qt = qof_date_to_qtime (qd);
01220                 retval = kvp_value_new_time (qt);
01221                 qof_date_free (qd);
01222                 qof_time_free (qt);
01223                 return retval;
01224             }
01225             else
01226                 PERR (" failed to parse date");
01227         }
01228         case KVP_TYPE_BOOLEAN :
01229         {
01230             gboolean val;
01231             val = qof_util_bool_to_int (content);
01232             return kvp_value_new_boolean (val);
01233         }
01234         case KVP_TYPE_BINARY:
01235 //        return kvp_value_new_binary(value->value.binary.data,
01236 //                                  value->value.binary.datasize);
01237             break;
01238         case KVP_TYPE_GLIST:
01239 //          return kvp_value_new_glist(value->value.list);
01240             break;
01241         case KVP_TYPE_FRAME:
01242 //        return kvp_value_new_frame(value->value.frame);
01243             break;
01244     }
01245     return NULL;
01246 }
01247 
01248 /* ======================================================
01249     Commit XML data from file to QofEntity in a QofBook
01250 ========================================================= */
01251 void
01252 qsf_object_commitCB (gpointer key, gpointer value, gpointer data)
01253 {
01254     QsfParam *params;
01255     QsfObject * G_GNUC_UNUSED object_set;
01256     xmlNodePtr node;
01257     QofEntityReference *reference;
01258     QofEntity *qsf_ent;
01259     QofBook * G_GNUC_UNUSED targetBook;
01260     const gchar *qof_type, *parameter_name;
01261     QofIdType obj_type, reference_type;
01262     gchar *tail;
01263     /* cm_ prefix used for variables that hold the data to commit */
01264     QofNumeric cm_numeric;
01265     gdouble cm_double;
01266     gboolean cm_boolean;
01267     gint32 cm_i32;
01268     gint64 cm_i64;
01269     gchar cm_char, (*char_getter) (xmlNodePtr);
01270     GUID *cm_guid;
01271     KvpFrame *cm_kvp;
01272     KvpValue *cm_value;
01273     KvpValueType cm_type;
01274     QofSetterFunc cm_setter;
01275     const QofParam *cm_param;
01276     void (*string_setter) (QofEntity *, const gchar *);
01277     void (*time_setter) (QofEntity *, QofTime *);
01278     void (*numeric_setter) (QofEntity *, QofNumeric);
01279     void (*double_setter) (QofEntity *, gdouble);
01280     void (*boolean_setter) (QofEntity *, gboolean);
01281     void (*i32_setter) (QofEntity *, gint32);
01282     void (*i64_setter) (QofEntity *, gint64);
01283     void (*char_setter) (QofEntity *, gchar);
01284 
01285     g_return_if_fail (data && value && key);
01286     params = (QsfParam *) data;
01287     node = (xmlNodePtr) value;
01288     parameter_name = (const gchar *) key;
01289     qof_type = (gchar *) node->name;
01290     qsf_ent = params->qsf_ent;
01291     targetBook = params->book;
01292     obj_type =
01293         (gchar *) xmlGetProp (node->parent, BAD_CAST QSF_OBJECT_TYPE);
01294     if (0 == safe_strcasecmp (obj_type, parameter_name))
01295     {
01296         return;
01297     }
01298     cm_setter = qof_class_get_parameter_setter (obj_type, parameter_name);
01299     cm_param = qof_class_get_parameter (obj_type, parameter_name);
01300     object_set = params->object_set;
01301     if (safe_strcmp (qof_type, QOF_TYPE_STRING) == 0)
01302     {
01303         string_setter = (void (*)(QofEntity *, const gchar *)) cm_setter;
01304         if (string_setter != NULL)
01305         {
01306             qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01307             string_setter (qsf_ent, (gchar *) xmlNodeGetContent (node));
01308             qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01309         }
01310     }
01311     if (safe_strcmp (qof_type, QOF_TYPE_TIME) == 0)
01312     {
01313         time_setter = (void (*)(QofEntity *, QofTime*)) cm_setter;
01314         if (time_setter != NULL)
01315         {
01316             QofDate *qd;
01317             QofTime *qt;
01318 
01319             qd = qof_date_parse (
01320                 (const gchar*) xmlNodeGetContent (node),
01321                 QOF_DATE_FORMAT_UTC);
01322             if(qd)
01323             {
01324                 qt = qof_date_to_qtime (qd);
01325                 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01326                 time_setter (qsf_ent, qt);
01327                 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01328                 qof_date_free (qd);
01329             }
01330             else
01331                 PERR (" failed to parse date string");
01332         }
01333     }
01334     if ((safe_strcmp (qof_type, QOF_TYPE_NUMERIC) == 0) ||
01335         (safe_strcmp (qof_type, QOF_TYPE_DEBCRED) == 0))
01336     {
01337         gchar *tmp;
01338         numeric_setter = (void (*)(QofEntity *, QofNumeric)) cm_setter;
01339         tmp = (char *) xmlNodeGetContent (node);
01340         qof_numeric_from_string (tmp, &cm_numeric);
01341         g_free (tmp);
01342         if (numeric_setter != NULL)
01343         {
01344             qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01345             numeric_setter (qsf_ent, cm_numeric);
01346             qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01347         }
01348     }
01349     if (safe_strcmp (qof_type, QOF_TYPE_GUID) == 0)
01350     {
01351         cm_guid = g_new0 (GUID, 1);
01352         if (TRUE !=
01353             string_to_guid ((gchar *) xmlNodeGetContent (node), cm_guid))
01354         {
01355             qof_error_set_be (params->be, qof_error_register(
01356             _("The selected QSF object file '%s' contains one or "
01357              "more invalid GUIDs. The file cannot be processed - "
01358              "please check the source of the file and try again."),
01359             TRUE));
01360             PINFO (" string to guid conversion failed for %s:%s:%s",
01361                 xmlNodeGetContent (node), obj_type, qof_type);
01362             return;
01363         }
01364         reference_type =
01365             (gchar *) xmlGetProp (node, BAD_CAST QSF_OBJECT_TYPE);
01366         if (0 == safe_strcmp (QOF_PARAM_GUID, reference_type))
01367         {
01368             qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01369             qof_entity_set_guid (qsf_ent, cm_guid);
01370             qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01371         }
01372         else
01373         {
01374             reference = qof_entity_get_reference_from (qsf_ent, cm_param);
01375             if (reference)
01376             {
01377                 params->referenceList =
01378                     g_list_append (params->referenceList, reference);
01379             }
01380         }
01381     }
01382     if (safe_strcmp (qof_type, QOF_TYPE_INT32) == 0)
01383     {
01384         errno = 0;
01385         cm_i32 =
01386             (gint32) strtol ((char *) xmlNodeGetContent (node), &tail, 0);
01387         if (errno == 0)
01388         {
01389             i32_setter = (void (*)(QofEntity *, gint32)) cm_setter;
01390             if (i32_setter != NULL)
01391             {
01392                 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01393                 i32_setter (qsf_ent, cm_i32);
01394                 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01395             }
01396         }
01397         else
01398             qof_error_set_be (params->be, params->err_overflow);
01399     }
01400     if (safe_strcmp (qof_type, QOF_TYPE_INT64) == 0)
01401     {
01402         errno = 0;
01403         cm_i64 = strtoll ((gchar *) xmlNodeGetContent (node), &tail, 0);
01404         if (errno == 0)
01405         {
01406             i64_setter = (void (*)(QofEntity *, gint64)) cm_setter;
01407             if (i64_setter != NULL)
01408             {
01409                 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01410                 i64_setter (qsf_ent, cm_i64);
01411                 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01412             }
01413         }
01414         else
01415             qof_error_set_be (params->be, params->err_overflow);
01416     }
01417     if (safe_strcmp (qof_type, QOF_TYPE_DOUBLE) == 0)
01418     {
01419         errno = 0;
01420         cm_double = strtod ((gchar *) xmlNodeGetContent (node), &tail);
01421         if (errno == 0)
01422         {
01423             double_setter = (void (*)(QofEntity *, gdouble)) cm_setter;
01424             if (double_setter != NULL)
01425             {
01426                 qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01427                 double_setter (qsf_ent, cm_double);
01428                 qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01429             }
01430         }
01431     }
01432     if (safe_strcmp (qof_type, QOF_TYPE_BOOLEAN) == 0)
01433     {
01434         if (0 == safe_strcasecmp ((gchar *) xmlNodeGetContent (node),
01435                 QSF_XML_BOOLEAN_TEST))
01436             cm_boolean = TRUE;
01437         else
01438             cm_boolean = FALSE;
01439         boolean_setter = (void (*)(QofEntity *, gboolean)) cm_setter;
01440         if (boolean_setter != NULL)
01441         {
01442             qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01443             boolean_setter (qsf_ent, cm_boolean);
01444             qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01445         }
01446     }
01447     if (safe_strcmp (qof_type, QOF_TYPE_KVP) == 0)
01448     {
01449         cm_type =
01450             qsf_to_kvp_helper ((gchar *)
01451             xmlGetProp (node, BAD_CAST QSF_OBJECT_VALUE));
01452         if (!cm_type)
01453             return;
01454         qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01455         cm_value =
01456             string_to_kvp_value ((gchar *) xmlNodeGetContent (node),
01457             cm_type);
01458         cm_kvp = (KvpFrame *) cm_param->param_getfcn (qsf_ent, cm_param);
01459         cm_kvp = kvp_frame_set_value (cm_kvp, (gchar *) xmlGetProp (node,
01460                 BAD_CAST QSF_OBJECT_KVP), cm_value);
01461         qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01462         g_free (cm_value);
01463     }
01464     if (safe_strcmp (qof_type, QOF_TYPE_COLLECT) == 0)
01465     {
01466         QofCollection *qsf_coll;
01467         QofIdType G_GNUC_UNUSED type;
01468         QofEntityReference *reference;
01469         QofParam *copy_param;
01470         /* retrieve the *type* of the collection, ignore any contents. */
01471         qsf_coll = cm_param->param_getfcn (qsf_ent, cm_param);
01472         type = qof_collection_get_type (qsf_coll);
01473         cm_guid = g_new0 (GUID, 1);
01474         if (TRUE !=
01475             string_to_guid ((gchar *) xmlNodeGetContent (node), cm_guid))
01476         {
01477             qof_error_set_be (params->be, (qof_error_register(
01478             _("The selected QSF object file '%s' contains one or "
01479              "more invalid 'collect' values. The file cannot be processed - "
01480              "please check the source of the file and try again."),
01481             TRUE)));
01482             PINFO (" string to guid collect failed for %s",
01483                 xmlNodeGetContent (node));
01484             return;
01485         }
01486         /* create a QofEntityReference with this type and GUID.
01487            there is only one entity each time.
01488            cm_guid contains the GUID of the reference.
01489            type is the type of the reference. */
01490         reference = g_new0 (QofEntityReference, 1);
01491         reference->type = g_strdup (qsf_ent->e_type);
01492         reference->ref_guid = cm_guid;
01493         reference->ent_guid = &qsf_ent->guid;
01494         copy_param = g_new0 (QofParam, 1);
01495         copy_param->param_name = g_strdup (cm_param->param_name);
01496         copy_param->param_type = g_strdup (cm_param->param_type);
01497         reference->param = copy_param;
01498         params->referenceList =
01499             g_list_append (params->referenceList, reference);
01500     }
01501     if (safe_strcmp (qof_type, QOF_TYPE_CHAR) == 0)
01502     {
01503         char_getter = (gchar (*)(xmlNodePtr)) xmlNodeGetContent;
01504         cm_char = char_getter (node);
01505         char_setter = (void (*)(QofEntity *, gchar)) cm_setter;
01506         if (char_setter != NULL)
01507         {
01508             qof_util_param_edit ((QofInstance *) qsf_ent, cm_param);
01509             char_setter (qsf_ent, cm_char);
01510             qof_util_param_commit ((QofInstance *) qsf_ent, cm_param);
01511         }
01512     }
01513 }
01514 
01515 static QofBackend *
01516 qsf_backend_new (void)
01517 {
01518     QSFBackend *qsf_be;
01519     QofBackend *be;
01520 
01521     qsf_be = g_new0 (QSFBackend, 1);
01522     be = (QofBackend *) qsf_be;
01523     qof_backend_init (be);
01524     qsf_be->params = g_new0 (QsfParam, 1);
01525     qsf_be->params->be = be;
01526     qsf_param_init (qsf_be->params);
01527     qsf_be->be.session_begin = qsf_session_begin;
01528 
01529     be->session_end = qsf_session_end;
01530     be->destroy_backend = qsf_destroy_backend;
01531     be->load = qsf_file_type;
01532     be->save_may_clobber_data = NULL;
01533     /* The QSF backend will always load and save the entire QSF XML file. */
01534     be->begin = NULL;
01535     be->commit = NULL;
01536     be->rollback = NULL;
01537     /* QSF uses the built-in SQL, not a dedicated SQL server. */
01538     be->compile_query = NULL;
01539     be->free_query = NULL;
01540     be->run_query = NULL;
01541     be->counter = NULL;
01542     /* The QSF backend is not multi-user. */
01543     be->events_pending = NULL;
01544     be->process_events = NULL;
01545 
01546     be->sync = qsf_write_file;
01547     /* use for maps, later. */
01548     be->load_config = qsf_load_config;
01549     be->get_config = qsf_get_config;
01550 
01551     qsf_be->fullpath = NULL;
01552     return be;
01553 }
01554 
01555 /* The QOF method of loading each backend.
01556 QSF is loaded as a GModule using the QOF method - QofBackendProvider.
01557 */
01558 static void
01559 qsf_provider_free (QofBackendProvider * prov)
01560 {
01561     prov->provider_name = NULL;
01562     prov->access_method = NULL;
01563     g_free (prov);
01564 }
01565 
01566 void
01567 qsf_provider_init (void)
01568 {
01569     QofBackendProvider *prov;
01570 
01571     bindtextdomain (PACKAGE, LOCALE_DIR);
01572     prov = g_new0 (QofBackendProvider, 1);
01573     prov->provider_name = "QSF Backend Version 0.4";
01574     prov->access_method = "file";
01575     prov->partial_book_supported = TRUE;
01576     prov->backend_new = qsf_backend_new;
01577     prov->check_data_type = qsf_determine_file_type;
01578     prov->provider_free = qsf_provider_free;
01579     qof_backend_register_provider (prov);
01580 }