qsf-backend.c

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

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4