• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

pilot-qof.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *            pilot-qof.c
00003  *
00004  *   Sat Feb  5 10:40:03 GMT 2005
00005  *  Copyright  2005, 2006  Neil Williams <linux@codehelp.co.uk>
00006  *
00007  *  plu_connect and pq_findcategory based on pilot-link/src/userland.c
00008  *  Copyright  2004 Adriaan de Groot <groot@kde.org>
00009  ****************************************************************************/
00010 /*
00011     This package is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation; either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023  */
00035 #define _GNU_SOURCE
00036 #include "config.h"
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <regex.h>
00040 #include <ctype.h>
00041 #include <glib.h>
00042 #include <glib/gi18n.h>
00043 #include <glib/gprintf.h>
00044 #include <qof.h>
00045 #include <popt.h>
00046 #include "pi-source.h"
00047 #include "pi-debug.h"
00048 #include "pi-socket.h"
00049 #include "pi-file.h"
00050 #include "pi-header.h"
00051 #include "pi-util.h"
00052 #include "qof-main.h"
00053 #include "palm.h"
00054 #include "pilot-qof.h"
00055 #include "pilot-todo.h"
00056 #include "qof-address.h"
00057 #include "qof-datebook.h"
00058 #ifdef HAVE_QOFEXPENSES
00059 #include <qof-expenses.h>
00060 #endif
00061 #include "pilot-expenses.h"
00062 
00064 static QofLogModule log_module = PQ_MOD_CLI;
00066 static GList *pilot_modules = NULL;
00067 
00068 static const gchar *env_pilotport = "PILOTPORT";
00069 
00070 #define ARGUMENT_BAD_OPTION 17227
00071 
00072 #define EXCLUDE_REPEATER_SQL "SELECT * from pilot_datebook " \
00073 "where DATEBOOK_REPEATER == TRUE;"
00074 
00075 #define ENUM_LIST_Q(_)    \
00076     _(qof_op_noop, = 0)   \
00077     _(qof_op_offline, )   \
00078     _(qof_op_list,)       \
00079     _(qof_op_hotsync,)    \
00080     _(qof_op_empty,)      \
00081     _(qof_op_category,)   \
00082     _(qof_op_database,)   \
00083     _(qof_op_time,)       \
00084     _(qof_op_exclude,)    \
00085     _(qof_op_sql,)        \
00086     _(qof_op_sql_file,)   \
00087     _(qof_op_write, )     \
00088     _(qof_op_upload, )    \
00089     _(qof_op_explain,)    \
00090     _(qof_op_vers,)       \
00091     _(qof_op_compress,)   \
00092     _(qof_op_debug,)      \
00093     _(qof_op_inv_city,)   \
00094     _(qof_op_inv_vendor,) \
00095     _(qof_op_use_locale,)
00096 
00097 DEFINE_ENUM (qof_op_type, ENUM_LIST_Q)
00098 
00099 static PQContext *
00100 pilot_qof_create (void)
00101 {
00102     PQContext *context;
00103     gint name_count;
00104 
00105     context = g_new0 (PQContext, 1);
00106     for (name_count = 0; name_count < 16; name_count++)
00107     {
00108         g_sprintf (context->names[name_count], "%s", "");
00109     }
00110     return context;
00111 }
00112 
00113 PQContext *
00114 pilot_qof_init (void)
00115 {
00116     qof_init ();
00117     g_return_val_if_fail (AddressRegister (), NULL);
00120 #ifdef HAVE_QOFEXPENSES
00121     g_return_val_if_fail (ExpensesRegister (), NULL);
00122 #endif
00123     g_return_val_if_fail (PQExpensesRegister (), NULL);
00124     g_return_val_if_fail (DateBookRegister (), NULL);
00125     g_return_val_if_fail (ToDoRegister (), NULL);
00126     g_return_val_if_fail (packing_registration(), NULL);
00127     return pilot_qof_create ();
00128 }
00129 
00130 typedef enum {
00131     PLU_CAT_NOFLAGS = 0,
00132     PLU_CAT_CASE_INSENSITIVE = 0x0001,
00133     PLU_CAT_DEFAULT_UNFILED = 0x0002,
00134     PLU_CAT_MATCH_NUMBERS = 0x0004,
00135     PLU_CAT_WARN_UNKNOWN = 0x0008
00136 } plu_findcategory_flags_t;
00137 
00138 /* copied from pilot-link 0.12 source */
00139 static gint 
00140 plu_connect(gchar* plu_port, gint plu_quiet)
00141 {
00142     gint sd = -1;
00143     gint result;
00144 
00145     struct  SysInfo sys_info;
00146 
00147     if (plu_port == NULL)
00148         plu_port = getenv(env_pilotport);
00149     if (plu_port == NULL) {
00150         fprintf (stderr, "\n   ");
00151         fprintf (stderr, _("Unable to determine port to bind"));
00152         fprintf (stderr, "\n   ");
00153         fprintf (stderr, _("Please use --help for more information"));
00154         fprintf (stderr, "\n\n");
00155         return -1;
00156     }
00157 
00158     if ((sd = pi_socket(PI_AF_PILOT,
00159             PI_SOCK_STREAM, PI_PF_DLP)) < 0) {
00160         fprintf(stderr, "\n   ");
00161         fprintf(stderr, _("Unable to create socket '%s'"), plu_port);
00162         fprintf(stderr, "\n");
00163         return -1;
00164     }
00165 
00166     result = pi_bind(sd, plu_port);
00167 
00168     if (result < 0) {
00169         fprintf (stderr, "\n   ");
00170         fprintf (stderr, _("Unable to bind to port: %s"), plu_port);;
00171         fprintf (stderr, "\n   ");
00172         fprintf (stderr, _("Please use --help for more information"));
00173         fprintf (stderr, "\n\n");
00174         return result;
00175     }
00176 
00177     if (!plu_quiet && isatty(fileno(stdout))) {
00178         fprintf (stdout, "\n   ");
00179         fprintf (stdout, _("Listening for incoming connection on %s... "),
00180             plu_port);
00181         fflush(stdout);
00182     }
00183 
00184     if (pi_listen(sd, 1) < 0) {
00185         fprintf (stderr, "\n   ");
00186         fprintf(stderr, _("Error listening on %s"), plu_port);
00187         fprintf (stderr, "\n   ");
00188         pi_close(sd);
00189         return -1;
00190     }
00191 
00192     sd = pi_accept(sd, 0, 0);
00193     if (sd < 0) {
00194         fprintf (stderr, "\n   ");
00195         fprintf(stderr, _("Error accepting data on %s"), plu_port);
00196         fprintf (stderr, "\n   ");
00197         pi_close(sd);
00198         return -1;
00199     }
00200 
00201     if (!plu_quiet && isatty(fileno(stdout))) {
00202         fprintf(stdout, _("connected!"));
00203         fprintf(stdout, "\n\n");
00204     }
00205 
00206     if (dlp_ReadSysInfo(sd, &sys_info) < 0) {
00207         fprintf (stderr, "\n   ");
00208         fprintf (stderr, _("Error read system info on %s"), plu_port);
00209         fprintf (stderr, "\n   ");
00210         pi_close(sd);
00211         return -1;
00212     }
00213 
00214     dlp_OpenConduit(sd);
00215     return sd;
00216 }
00217 
00218 static gint 
00219 pq_findcategory(PQContext *context, const gchar *name, gint flags)
00220 {
00221     gint cat_index, match_category;
00222 
00223     match_category = -1;
00224     for (cat_index = 0; cat_index < 16; cat_index += 1) {
00225         if (context->names[cat_index][0]) {
00226             if (flags & PLU_CAT_CASE_INSENSITIVE) {
00227                 if (strncasecmp(context->names[cat_index], name, 15) == 0) {
00228                     match_category = cat_index;
00229                     break;
00230                 }
00231             } else {
00232                 if (strncmp(context->names[cat_index],name,15) == 0) {
00233                     match_category = cat_index;
00234                     break;
00235                 }
00236             }
00237         }
00238     }
00239     
00240     if ((match_category == -1)  && (flags & PLU_CAT_MATCH_NUMBERS)) {
00241         while (isspace(*name)) {
00242             name++;
00243         }
00244         if (isdigit(*name)) {
00245             match_category = atoi(name);
00246         }
00247     
00248         if ((match_category < 0) || (match_category > 15)) {
00249             match_category = -1;
00250         }
00251     }
00252     
00253     if (flags & PLU_CAT_WARN_UNKNOWN) {
00254         if (match_category == -1) {
00255             fprintf(stderr, _("WARNING: Unknown category '%s'%s.\n"),
00256                 name,
00257                 (flags & PLU_CAT_DEFAULT_UNFILED) ? _(", using 'Unfiled'") : "");
00258         }
00259     }
00260     
00261     if (flags & PLU_CAT_DEFAULT_UNFILED) {
00262         if (match_category == -1) {
00263             match_category = 0;
00264         }
00265     }
00266     
00267     return match_category;
00268 }
00269 
00270 void
00271 pilot_qof_pack (QofEntity * ent, gpointer user_data)
00272 {
00273     const gchar *category_name;
00274     const QofParam *param;
00275     gint size, result;
00276     QofPack pack_func;
00277     PQContext *context;
00278     const PQPack *p; 
00279 
00280     context = (PQContext *) user_data;
00281     size = result = 0;
00282     g_return_if_fail (context != NULL);
00283     p = pilot_qof_pack_lookup (ent->e_type);
00284     if (!p)
00285         return;
00286     context->pi_buf = pi_buffer_new (PQ_DEF_BUFSZ);
00287     pack_func = p->pack_func;
00288     if (pack_func == NULL)
00289     {
00290         context->qof.error = TRUE;
00291         return;
00292     }
00293     size = pack_func (ent, context);
00294     if (size == -1)
00295         return;
00296     param = qof_class_get_parameter (ent->e_type, CATEGORY_NAME);
00297     category_name = (const gchar *) param->param_getfcn (ent, param);
00298     context->ent_category = pq_findcategory(context, 
00299         category_name, PLU_CAT_CASE_INSENSITIVE | PLU_CAT_DEFAULT_UNFILED);
00300 /*  context->ent_category = plu_findcategory (context->pi_cat,
00301         category_name, PLU_CAT_CASE_INSENSITIVE | PLU_CAT_DEFAULT_UNFILED);*/
00302     if (context->ent_category == 0)
00303         PWARN (" Category: '%s' not found or not set, using 'Unfiled'",
00304             category_name);
00305     result = dlp_WriteRecord (context->sd, context->db,
00306         PQ_DLP_REC_ATTR, PQ_DLP_NEW_REC, context->ent_category,
00307         context->pi_buf->data, size, PQ_DLP_SET_ID);
00308     if (result < 0)
00309     {
00310         PERR (" record could not be written: error %d", result);
00311         return;
00312     }
00313 }
00314 
00315 void
00316 pilot_qof_unpack (QofEntity * ent, gpointer user_data)
00317 {
00318     QofPack unpack_func;
00319     const PQPack *p;
00320     PQContext *context;
00321     gint result;
00322 
00323     context = (PQContext *) user_data;
00324     g_return_if_fail (context && ent);
00325     p = pilot_qof_pack_lookup (ent->e_type);
00326     g_return_if_fail (p);
00327     unpack_func = p->unpack_func;
00328     if (unpack_func == NULL)
00329     {
00330         context->qof.error = TRUE;
00331         PERR ("No unpack routine was defined for the %s object!",
00332             ent->e_type);
00333         return;
00334     }
00335     result = unpack_func (ent, context);
00336     if (result < 0)
00337     {
00338         qof_entity_release (ent);
00339         g_free (ent);
00340     }
00341 }
00342 
00343 void
00344 pilot_app_unpack (QofIdTypeConst e_type, gpointer user_data)
00345 {
00346     PQContext *context;
00347     QofPack app_unpack;
00348     const PQPack *p;
00349 
00350     context = (PQContext *) user_data;
00351     g_return_if_fail (context != NULL);
00352     p = pilot_qof_pack_lookup (e_type);
00353     if (!p)
00354         return;
00355     app_unpack = p->app_info_unpack;
00356     if (app_unpack == NULL)
00357     {
00358         context->qof.error = TRUE;
00359         PERR (" no app_info_unpack routine for %s", e_type);
00360         return;
00361     }
00362     /* no entity available for the appInfo, pass NULL and work only in the context. */
00363     app_unpack (NULL, context);
00364 }
00365 
00366 static void
00367 pilot_entity_free (QofEntity * ent, gpointer user_data)
00368 {
00369     QofPack free_pack_func;
00370     const PQPack *p;
00371 
00372     p = pilot_qof_pack_lookup (ent->e_type);
00373     if (!p)
00374         return;
00375     free_pack_func = p->free_pack_func;
00376     free_pack_func (ent, NULL);
00377 }
00378 
00379 static void
00380 pilot_object_free (QofObject * obj, gpointer user_data)
00381 {
00382     QofBook *book;
00383 
00384     book = (QofBook *) user_data;
00385     qof_object_foreach (obj->e_type, book, pilot_entity_free, NULL);
00386 }
00387 
00388 void
00389 pilot_entity_finaliser (QofBook * book, gpointer key, gpointer data)
00390 {
00391     qof_object_foreach_type (pilot_object_free, book);
00392 }
00393 
00394 gboolean
00395 pilot_qof_pack_register (const PQPack * p)
00396 {
00397     if (g_list_index (pilot_modules, (gpointer) p) == -1)
00398         pilot_modules = g_list_prepend (pilot_modules, (gpointer) p);
00399     else
00400         return FALSE;
00401     return TRUE;
00402 }
00403 
00404 const PQPack *
00405 pilot_qof_pack_lookup (QofIdTypeConst object_type)
00406 {
00407     GList *piter;
00408     PQPack *p;
00409 
00410     if (!object_type)
00411         return NULL;
00412     for (piter = pilot_modules; piter; piter = piter->next)
00413     {
00414         p = piter->data;
00415         if (0 == safe_strcmp (p->e_type, object_type))
00416             return p;
00417     }
00418     return NULL;
00419 }
00420 
00421 static void
00422 pilot_qof_free (PQContext * data)
00423 {
00424     gint name_count;
00425 
00426     for (name_count = 0; name_count < 16; name_count++)
00427         g_sprintf (data->names[name_count], "%s", "");
00428     qof_main_free (&data->qof);
00429 }
00430 
00431 static void
00432 write_ent_cb (QofEntity * ent, gpointer user_data)
00433 {
00434     PQContext *context;
00435 
00436     context = (PQContext *) user_data;
00437     g_return_if_fail (context && ent);
00438     if (context->qof.error)
00439         return;
00440     context->pi_buf = pi_buffer_new (PQ_DEF_BUFSZ);
00441     pilot_qof_pack (ent, context);
00442 }
00443 
00444 static void
00445 pilot_database_open (QofObject * obj, gpointer user_data)
00446 {
00447     gchar *db_name, *log;
00448     PQContext *context;
00449     const PQPack *p;
00450     QofPack pref_unpack;
00451     gint db, attr, category, i, len;
00452     QofBook *book;
00453     QofEntity *ent;
00454     QofInstance *inst;
00455 
00456     context = (PQContext *) user_data;
00457     if (context->qof.error)
00458     {
00459         return;
00460     }
00461     pref_unpack = NULL;
00462     len = 0;
00463     i = 0;
00464     p = pilot_qof_pack_lookup (obj->e_type);
00465     if (!p)
00466         return;
00467     db_name = g_strdup (p->palm_db_name);
00468     if (db_name == NULL)
00469     {
00470         context->qof.error = TRUE;
00471         PERR (" object %s has no database name", obj->e_type);
00472         return;
00473     }
00474     if (0 == safe_strcmp (obj->e_type, context->qof.exclude))
00475         return;
00476     /* If no database specified, query all except any excluded database. */
00477     if ((context->qof.database != NULL) &&
00478         (0 != safe_strcmp (obj->e_type, context->qof.database)))
00479         return;
00480     if (p->db_pref_unpack)
00481     {
00482         gchar * creator;
00483         gint pref_result = 0;
00484         /* Optionally, unpack preferences here */
00485         pref_unpack = p->db_pref_unpack;
00486         /* no entity available for the preferences, */
00487         /* pass NULL and work only in the context. */
00488         creator = g_strdup (p->pref_creator);
00489         pref_result = dlp_ReadAppPreference (context->sd,
00490             makelong (creator), p->pref_flag,
00491             PQ_PREF_USE_BACKUP, PQ_DEF_BUFSZ, context->pref_buf,
00492             PQ_PREF_USE_SIZE, PQ_PREF_VERSION);
00493         pref_unpack (NULL, context);
00494         g_free (creator);
00495     }
00496     if (dlp_OpenDB (context->sd, PQ_DLP_CARD,
00497             PI_DLP_ARG_FLAG_SHORT | PI_DLP_ARG_FLAG_LONG,
00498             db_name, &db) < 0)
00499     {
00500         PWARN (" Unable to open %s database on Palm.\n", db_name);
00501         log =
00502             g_strdup_printf (_
00503             ("%s: Unable to open %s database on Palm.\n"),
00504             PACKAGE, db_name);
00505         dlp_AddSyncLogEntry (context->sd, log);
00506         pi_close (context->sd);
00507         g_free (log);
00508         context->qof.error = TRUE;
00509         return;
00510     }
00511     context->db = db;
00512     context->app_buf = pi_buffer_new (PQ_DEF_BUFSZ);
00513     /* each database has it's own category list. */
00514     dlp_ReadAppBlock (context->sd, context->db, PQ_DLP_OFFSET,
00515         PQ_DLP_APPREAD, context->app_buf);
00516     pilot_app_unpack (obj->e_type, context);
00517     /* Write each entity if an upload file was specified. */
00518     if (context->qof.input_file)
00519     {
00520         book = qof_session_get_book (context->qof.input_session);
00521         qof_object_foreach (obj->e_type, book, write_ent_cb, context);
00522     }
00523     context->pi_buf = pi_buffer_new (PQ_DEF_BUFSZ);
00524     book = qof_session_get_book (context->qof.input_session);
00525     for (i = 0; len >= 0; i++)
00526     {
00527         len = dlp_ReadRecordByIndex (context->sd, context->db, i,
00528             context->pi_buf, PQ_DLP_RECORD, &attr, &category);
00529         /* attr holds archive - when deleted from Palm with option to archive on PC */
00530         if ((attr & dlpRecAttrDeleted) || (attr & dlpRecAttrArchived))
00531             continue;
00532         /* category holds the index of the category in this database category list. */
00533         context->ent_category = category;
00534         /* Create new entity to hold the unpacked data. */
00535         inst = (QofInstance *) qof_object_new_instance (obj->e_type, book);
00536         g_return_if_fail (inst != NULL);
00537         ent = &inst->entity;
00538         pilot_qof_unpack (ent, context);
00539         if (context->qof.error == TRUE)
00540         {
00541             len = -1;
00542             break;
00543         }
00544     }
00545     pi_buffer_free (context->app_buf);
00546     pi_buffer_free (context->pi_buf);
00547     g_free (db_name);
00548     dlp_CloseDB (context->sd, context->db);
00549 }
00550 
00551 static void
00552 pilot_error (PQContext * context, const gchar * message)
00553 {
00554     PERR (" %s - Error code: %d", message, pi_error(context->sd));
00555     if(context->sd > 0)
00556     {
00557         pi_close(context->sd);
00558     }
00559     qof_session_end(context->qof.input_session);
00560     qof_session_end(context->qof.export_session);
00561     context->qof.error = TRUE;
00562 }
00563 
00564 static void
00565 find_invoice_contact (QofEntity * ent, gpointer data)
00566 {
00567     GSList *field_list, *category_param_list;
00568     QofQueryPredData *appt_pred, *exp_pred, *category_pred;
00569     PQContext *context;
00570     const QofParam *param;
00571     const gchar *string;
00572     GList *results;
00573     QofBook *book;
00574 
00575     context = (PQContext *) data;
00576     g_return_if_fail (context && ent);
00577     param = NULL;
00578     string = NULL;
00579     results = NULL;
00580     category_param_list = NULL;
00581     if (0 != safe_strcmp (ent->e_type, PILOT_LINK_QOF_EXPENSES)
00582         && (0 != safe_strcmp (ent->e_type, PILOT_LINK_QOF_DATEBOOK)))
00583         return;
00584     ENTER (" ent=%s", ent->e_type);
00585     book = qof_session_get_book (context->qof.input_session);
00586     qof_query_set_book (context->qof.query, book);
00587     field_list = NULL;
00588     /* remember: query runs in address using strings from 
00589     expenses or datebook. */
00590     if (context->qof.category)
00591     {
00592         category_param_list =
00593             qof_query_build_param_list (CATEGORY_NAME, NULL);
00594         category_pred =
00595             qof_query_string_predicate (QOF_COMPARE_EQUAL,
00596             context->qof.category,
00597             QOF_STRING_MATCH_CASEINSENSITIVE, FALSE);
00598         qof_query_add_term (context->qof.query, category_param_list,
00599             category_pred, QOF_QUERY_AND);
00600     }
00601     /* lookup appointment or expenses strings */
00602     if (0 == safe_strcmp (ent->e_type, PILOT_LINK_QOF_EXPENSES))
00603     {
00604         if (context->invoice_vendor)
00605         {
00606             param = qof_class_get_parameter (ent->e_type, EXP_VENDOR);
00607             string = param->param_getfcn (ent, param);
00608             field_list = qof_query_build_param_list (ADDR_CITY, NULL);
00609         }
00610         if (context->invoice_city)
00611         {
00612             param = qof_class_get_parameter (ent->e_type, EXP_CITY);
00613             string = param->param_getfcn (ent, param);
00614             field_list =
00615                 qof_query_build_param_list (ADDR_COMPANY, ADDR_TITLE,
00616                 NULL);
00617         }
00618         if (string)
00619         {
00620             exp_pred = qof_query_string_predicate (QOF_COMPARE_EQUAL,
00621                 string, QOF_STRING_MATCH_CASEINSENSITIVE, FALSE);
00622             qof_query_add_term (context->qof.query, field_list,
00623                 exp_pred, QOF_QUERY_AND);
00624             results = qof_query_run (context->qof.query);
00625             if (results != NULL)
00626                 qof_entity_copy_list (context->qof.export_session,
00627                     results);
00628         }
00629     }
00630     if (0 == safe_strcmp (ent->e_type, PILOT_LINK_QOF_DATEBOOK))
00631     {
00632         param =
00633             qof_class_get_parameter (ent->e_type, DATEBOOK_DESCRIPTION);
00634         string = param->param_getfcn (ent, param);
00635         field_list = qof_query_build_param_list (ADDR_COMPANY,
00636             ADDR_CITY, ADDR_TITLE, NULL);
00637         if (string)
00638         {
00639             appt_pred = qof_query_string_predicate (QOF_COMPARE_EQUAL,
00640                 string, QOF_STRING_MATCH_CASEINSENSITIVE, FALSE);
00641             qof_query_add_term (context->qof.query, field_list,
00642                 appt_pred, QOF_QUERY_AND);
00643             results = qof_query_run (context->qof.query);
00644             if (results != NULL)
00645                 qof_entity_copy_list (context->qof.export_session,
00646                     results);
00647         }
00648     }
00649     if (context->qof.query)
00650         qof_query_clear (context->qof.query);
00651     LEAVE (" ");
00652 }
00653 
00654 static void
00655 check_invoice_handler (PQContext * context)
00656 {
00657     if (!context->qof.min_qt)
00658     {
00659         fprintf (stderr, _("%s: Error: Please specify a time period "
00660                 "using -t."), PACKAGE);
00661         fprintf (stderr, "\n\n");
00662         qof_session_end (context->qof.input_session);
00663         context->qof.error = TRUE;
00664         return;
00665     }
00666     if (context->qof.exclude)
00667     {
00668         g_free (context->qof.exclude);
00669         context->qof.exclude = NULL;
00670     }
00671     context->qof.exclude = g_strdup (PILOT_LINK_QOF_TODO);
00672     if (context->qof.database)
00673     {
00674         g_free (context->qof.database);
00675         context->qof.database = NULL;
00676     }
00677     if (context->qof.input_file)
00678     {
00679         g_free (context->qof.input_file);
00680         context->qof.input_file = NULL;
00681     }
00682     if (context->qof.sql_str)
00683     {
00684         g_free (context->qof.sql_str);
00685         context->qof.sql_str = NULL;
00686     }
00687     if (context->qof.sql_list)
00688     {
00689         g_list_free (context->qof.sql_list);
00690         context->qof.sql_list = NULL;
00691     }
00692 }
00693 
00694 void
00695 qof_cmd_hotsync (PQContext * context)
00696 {
00697     struct PilotUser QUser;
00698     QofBook *book;
00699     gchar *log_msg;
00700 
00701     if (0 == safe_strcmp (context->qof.exclude, context->qof.database)
00702         && (context->qof.exclude != NULL))
00703     {
00704         /* Translators: The first string is the package name.
00705            The second and third are database names. */
00706         qof_main_wrap_line (stderr, ERR_INDENT,
00707             _("%s: Error: Cannot exclude "
00708                 "database \"%s\" with option -e because option -d is set to the "
00709                 "same database: \"%s\""), PACKAGE, context->qof.exclude,
00710             context->qof.database);
00711         qof_session_end (context->qof.input_session);
00712         return;
00713     }
00714     if ((context->invoice_city) || (context->invoice_vendor))
00715         check_invoice_handler (context);
00716     if (context->qof.error)
00717         return;
00718     if (context->qof.input_file)
00719     {
00720         PINFO (" Trying to upload %s", context->qof.input_file);
00721         qof_session_begin (context->qof.input_session,
00722             context->qof.input_file, TRUE, FALSE);
00723         qof_session_load (context->qof.input_session, NULL);
00724     }
00725     else
00726         qof_session_begin (context->qof.input_session, QOF_STDOUT, TRUE,
00727             FALSE);
00728     context->qof.export_session = qof_session_new ();
00729 
00730     context->sd = plu_connect (context->port, context->quiet);
00731 
00732     if (context->sd < 0)
00733     {
00734         pilot_error (context, _("Unable to connect to the Palm"));
00735         return;
00736     }
00737     if (dlp_ReadUserInfo (context->sd, &QUser) < 0)
00738     {
00739         pilot_error (context, _("Unable to read Palm user info"));
00740         return;
00741     }
00742     context->qof.error = FALSE;
00743     qof_object_foreach_type (pilot_database_open, context);
00744     QUser.lastSyncPC = 0x00010000;
00745     QUser.lastSyncDate = QUser.successfulSyncDate = time (0);
00746     if (dlp_WriteUserInfo (context->sd, &QUser) < 0)
00747     {
00748         pilot_error (context, _("Unable to write user info"));
00749         return;
00750     }
00751     /* Translators: each string is the package name. */
00752     log_msg = g_strdup_printf (_("%s hotsync\n\n"
00753             "Thank you for using %s.\n"), PACKAGE, PACKAGE);
00754     dlp_AddSyncLogEntry (context->sd, log_msg);
00755     g_free (log_msg);
00756     dlp_EndOfSync (context->sd, 0);
00757     pi_close (context->sd);
00758     /* Now run the query, copy the objects, destroy the input session */
00759     /*and write out export_session */
00760     if (context->qof.write_file)
00761     {
00762         qof_session_begin (context->qof.export_session,
00763             context->qof.write_file, TRUE, TRUE);
00764         qof_mod_compression (context->qof.gz_level, &context->qof);
00765     }
00766     else
00767         qof_session_begin (context->qof.export_session, QOF_STDOUT, TRUE,
00768             FALSE);
00769     /* Note if no query is given, ignore repeater clones?
00770        Nice idea, but in practice, difficult. It also makes recursive
00771        queries of the XML harder as the XML needs to understand datebook
00772        repeats. Instead, we simply ignore all repeater clones when it comes
00773        to write data to the Palm by a simple check in datebook_pack.
00774      */
00775     qof_main_moderate_query (&context->qof);
00776     /* if invoice_hook, create a second query and lookup in contacts */
00777     if ((context->invoice_city) || (context->invoice_vendor))
00778     {
00779         book = qof_session_get_book (context->qof.export_session);
00780         context->qof.query = qof_query_create_for (PILOT_LINK_QOF_ADDRESS);
00781         qof_object_foreach (PILOT_LINK_QOF_DATEBOOK, book,
00782             find_invoice_contact, context);
00783         qof_object_foreach (PILOT_LINK_QOF_EXPENSES, book,
00784             find_invoice_contact, context);
00785     }
00786     qof_session_save (context->qof.export_session, NULL);
00787     qof_main_show_error (context->qof.export_session);
00788     qof_session_end (context->qof.input_session);
00789     qof_session_end (context->qof.export_session);
00790 }
00791 
00792 static void
00793 pq_invoice_xmlfile (PQContext * context)
00794 {
00795     QofBook *book;
00796 
00797     ENTER (" ");
00798     qof_session_begin (context->qof.input_session, context->qof.filename,
00799         TRUE, FALSE);
00800     qof_session_load (context->qof.input_session, NULL);
00801     context->qof.export_session = qof_session_new ();
00802     if (context->qof.write_file)
00803     {
00804         qof_session_begin (context->qof.export_session,
00805             context->qof.write_file, TRUE, TRUE);
00806         qof_mod_compression (context->qof.gz_level, &context->qof);
00807     }
00808     else
00809         qof_session_begin (context->qof.export_session, QOF_STDOUT,
00810             TRUE, TRUE);
00811     qof_main_moderate_query (&context->qof);
00812     book = qof_session_get_book (context->qof.export_session);
00813     context->qof.query = qof_query_create_for (PILOT_LINK_QOF_ADDRESS);
00814     qof_object_foreach (PILOT_LINK_QOF_DATEBOOK, book,
00815         find_invoice_contact, context);
00816     qof_object_foreach (PILOT_LINK_QOF_EXPENSES, book,
00817         find_invoice_contact, context);
00818     qof_session_save (context->qof.export_session, NULL);
00819     qof_main_show_error (context->qof.export_session);
00820     qof_main_show_error (context->qof.input_session);
00821     qof_session_end (context->qof.input_session);
00822     qof_session_end (context->qof.export_session);
00823     LEAVE (" ");
00824 }
00825 
00826 int
00827 main (int argc, const char *argv[])
00828 {
00829     const gchar *help_header_text, *input_file, *plu_port;
00830     gint plu_quiet, optc;
00831     PQContext *pilot_qof_context;
00832     gboolean debug_on;
00833     poptContext pc;
00834     gint64 gz_level;
00835     qof_op_type palm_command;
00836 
00837     QOF_OP_VARS struct poptOption options[] = {
00838         {"port", 'p', POPT_ARG_STRING, &plu_port, 0,
00839             _("Use the device <port> to communicate with Palm"),
00840                 "<port>"},
00841         { "quiet",   'q', POPT_ARG_NONE,  &plu_quiet,  0 ,
00842          _("Suppress HotSync connection messages"), NULL},
00843         {"input-file", 'i', POPT_ARG_STRING, &filename, qof_op_offline,
00844          _("Query the data in <filename>"), _("filename")},
00845         QOF_CLI_OPTIONS 
00846         {"hot-query", 'a', POPT_ARG_NONE,
00847                 NULL, qof_op_hotsync,
00848             _("Activate/HotSync and query the Palm."), NULL},
00849         {"upload", 'u', POPT_ARG_STRING, &input_file, qof_op_upload,
00850             _("Upload data from <filename> to the Palm. Requires -a"),
00851                 "filename"},
00852         {"invoice-vendor", 0, POPT_ARG_NONE, NULL, qof_op_inv_vendor,
00853             _
00854             ("Shorthand to relate an event or expense to a contact, by vendor. "
00855                     "Requires -t."), NULL},
00856         {"invoice-city", 0, POPT_ARG_NONE, NULL, qof_op_inv_city,
00857             _
00858             ("Shorthand to relate an event or expense to a contact, by city. "
00859                     "Requires -t."), NULL},
00860         {"use-locale", 0, POPT_ARG_NONE, NULL, qof_op_use_locale,
00861                 _
00862             ("Write XML using the current locale encoding instead of UTF-8."),
00863             NULL},
00864         POPT_TABLEEND
00865     };
00866 
00867     palm_command = qof_op_noop;
00868     debug_on = FALSE;
00869     QOF_OP_INIT;
00870     input_file = NULL;
00871     plu_quiet = 0;
00872     plu_port = NULL;
00873 
00874 #ifdef ENABLE_NLS
00875     setlocale (LC_ALL, "");
00876     bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
00877     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
00878     textdomain (GETTEXT_PACKAGE);
00879 #endif
00880 
00881     help_header_text = _("\n"
00882         "   Query Palm databases as objects and save to XML.\n"
00883 
00884         "   pilot-qof provides a query interface to data on a Palm device,\n"
00885         "   using pilot-link and QOF - the Query Object Framework.\n\n"
00886         "   pilot-qof supports reading addressbook, datebook, expenses and\n"
00887         "   ToDo data from a Palm device to XML files. pilot-qof runs SQL-type\n"
00888         "   queries on the live data or a QSF XML file and results can be imported\n"
00889         "   into other QOF applications or converted to other text based formats,\n"
00890         "   including non-XML formats like vcard.\n"
00891         "   See http://pilot-qof.sourceforge.net/\n\n"
00892         "   Commands are -x -a -l --explain -s or -f.\n"
00893         "   Options are -c -t -w, -d or -e.\n"
00894         "   option -u requires -a\n\n");
00895 
00896     pc = poptGetContext (PACKAGE, argc, argv, options, 0);
00897 
00898     poptSetOtherOptionHelp (pc, help_header_text);
00899 
00900     if (argc < 2)
00901     {
00902         poptPrintUsage (pc, stderr, 0);
00903         return EXIT_FAILURE;
00904     }
00905     pilot_qof_context = pilot_qof_init ();
00906     if (!pilot_qof_context)
00907     {
00908         qof_main_wrap_line (stderr, ERR_INDENT,
00909             _("%s: Failed to initialise "
00910                 "the query object framework."), PACKAGE);
00911         return EXIT_FAILURE;
00912     }
00913     /* convert deprecated date fields into the newly supported
00914     time values. */
00915     qof_mod_convert_deprecated (1, &pilot_qof_context->qof);
00916     while ((optc = poptGetNextOpt (pc)) >= 0)
00917     {
00918         switch (optc)
00919         {
00920             /* commands - mutually exclusive */
00921         case qof_op_offline:
00922         case qof_op_list:
00923         case qof_op_explain:
00924         case qof_op_hotsync:
00925             {
00926                 palm_command = optc;
00927                 break;
00928             }
00929         case qof_op_sql:
00930             {
00931                 qof_mod_sql (sql_query, &pilot_qof_context->qof);
00932                 if (!filename)
00933                 {
00934                     filename = g_strdup (QOF_STDOUT);
00935                 }
00936                 palm_command = qof_op_empty;
00937                 break;
00938             }
00939         case qof_op_sql_file:
00940             {
00941                 qof_mod_sql_file (sql_file, &pilot_qof_context->qof);
00942                 palm_command = qof_op_empty;
00943                 break;
00944             }
00945         case qof_op_vers:
00946             {
00947                 fprintf (stdout, _("\n This is %s v%s\n"), PACKAGE,
00948                     VERSION);
00949                 fprintf (stdout,
00950                     _
00951                     (" Query interface for Palm databases as objects.\n"));
00952                 fprintf (stdout,
00953                     "\n Copyright (c) 2005-2006 "
00954                     "Neil Williams <linux@codehelp.co.uk>\n");
00955                 fprintf (stdout,
00956                     _(" For %s support, join the QOF-devel "
00957                         "mailing list at\n"), PACKAGE);
00958                 fprintf (stdout,
00959                     " http://lists.sourceforge.net/mailman/listinfo/qof-devel\n\n");
00960 /* Translators: Add or subtract dots to keep the translated lines aligned vertically */
00961                 fprintf (stdout, _(" Build target............: %s\n"),
00962                     HOST_OS);
00963 /* Translators: Add or subtract dots to keep the translated lines aligned vertically */
00964                 fprintf (stdout, _(" Build date..............: %s %s\n"),
00965                     __DATE__, __TIME__);
00966 /* Translators: Add or subtract dots to keep the translated lines aligned vertically */
00967                 fprintf (stdout, _(" Built for pilot-link ...: %s\n"),
00968                     PILOT_LINK_SUPPORT);
00969 /* Translators: Add or subtract dots to keep the translated lines aligned vertically */
00970                 fprintf (stdout, _(" --debug logs to.........: %s/%s\n\n"),
00971                     g_get_tmp_dir (), PILOT_QOF_LOG);
00972                 fprintf (stdout,
00973                     _
00974                     (" Please use --help for more detailed options.\n\n"));
00975                 return EXIT_SUCCESS;
00976             }
00977             /* optional modifiers - store to act on later. */
00978         case qof_op_category:
00979             {
00980                 qof_mod_category (category, &pilot_qof_context->qof);
00981                 break;
00982             }
00983         case qof_op_database:
00984             {
00985                 qof_mod_database (database, &pilot_qof_context->qof);
00986                 break;
00987             }
00988         case qof_op_time:
00989             {
00990                 qof_mod_time (date_time, &pilot_qof_context->qof);
00991                 break;
00992             }
00993         case qof_op_exclude:
00994             {
00995                 qof_mod_exclude (exclude, &pilot_qof_context->qof);
00996                 break;
00997             }
00998         case qof_op_write:
00999             {
01000                 qof_mod_write (write_file, &pilot_qof_context->qof);
01001                 break;
01002             }
01003         case qof_op_upload:
01004             {
01005                 if (palm_command != qof_op_hotsync)
01006                 {
01007                     fprintf (stderr,
01008                         _("%s: Error: Please specify -a if you use -u\n"),
01009                         PACKAGE);
01010                     poptPrintUsage (pc, stderr, 0);
01011                     return EXIT_FAILURE;
01012                 }
01013                 pilot_qof_context->qof.input_file = g_strdup (input_file);
01014                 break;
01015             }
01016         case qof_op_debug:
01017             {
01018                 gchar *log;
01019 
01020                 log =
01021                     g_strconcat (g_get_tmp_dir (), "/", PILOT_QOF_LOG,
01022                     NULL);
01023                 qof_log_init_filename (log);
01024                 g_free (log);
01025                 qof_log_set_default (QOF_LOG_DETAIL);
01026                 qof_log_set_level (PQ_MOD_CLI, QOF_LOG_DETAIL);
01027                 qof_log_set_level (PQ_MOD_PILOT, QOF_LOG_DETAIL);
01028                 qof_log_set_level (QOF_MAIN_CLI, QOF_LOG_DETAIL);
01029                 qof_log_set_level (QOF_MOD_QSF, QOF_LOG_DETAIL);
01030                 qof_log_set_level ("qof-sqlite-module", QOF_LOG_DETAIL);
01031                 debug_on = TRUE;
01033                 break;
01034             }
01035         case qof_op_compress:
01036             {
01037                 pilot_qof_context->qof.gz_level = gz_level;
01038                 break;
01039             }
01040         case qof_op_inv_vendor:
01041             {
01042                 if (!pilot_qof_context->invoice_city)
01043                     pilot_qof_context->invoice_vendor = TRUE;
01044                 break;
01045             }
01046         case qof_op_inv_city:
01047             {
01048                 pilot_qof_context->invoice_city = TRUE;
01049                 pilot_qof_context->invoice_vendor = FALSE;
01050                 break;
01051             }
01052         case qof_op_use_locale:
01053             {
01054                 const gchar *locale_encoding;
01055                 gboolean test;
01056                 locale_encoding = NULL;
01057                 test = g_get_charset (&locale_encoding);
01058                 if (!test)
01059                     qof_mod_encoding (locale_encoding,
01060                         &pilot_qof_context->qof);
01061                 break;
01062             }
01063         default:
01064             {
01065                 fprintf (stderr, _("%s: ERROR: got option %d, arg %s\n"),
01066                     PACKAGE, optc, poptGetOptArg (pc));
01067                 return EXIT_FAILURE;
01068             }
01069         }
01070     }
01071     if (qof_op_noop == palm_command)
01072     {
01073         qof_main_wrap_line (stderr, ERR_INDENT,
01074             _("%s: ERROR: specify a command "
01075                 "-x, -a, -l, -s or -f, or --explain.\n"), PACKAGE);
01076         poptPrintUsage (pc, stderr, 0);
01077         return EXIT_FAILURE;
01078     }
01079     if (qof_op_noop == palm_command)
01080     {
01081         fprintf (stderr, _("%s: ERROR: specify a command "
01082         "-x, -a, -l, -s or -f, or --explain.\n"), PACKAGE);
01083         poptPrintUsage(pc, stderr, 0);
01084         return EXIT_FAILURE;
01085     }
01086     if (optc < -1)
01087     {
01088         fprintf (stderr, "%s: %s %s\n\n", PACKAGE,
01089             poptBadOption (pc, POPT_BADOPTION_NOALIAS),
01090             poptStrerror (optc));
01091         poptPrintUsage (pc, stderr, 0);
01092         return EXIT_FAILURE;
01093     }
01094     /* If we get this far, we should have sensible options: start the work. */
01095     pilot_qof_context->qof.input_session = qof_session_new ();
01096     switch (palm_command)
01097     {
01098     case qof_op_empty:
01099     {
01100         pilot_qof_context->qof.filename = g_strdup (filename);
01101         if ((pilot_qof_context->invoice_city)
01102             || (pilot_qof_context->invoice_vendor))
01103         {
01104             check_invoice_handler (pilot_qof_context);
01105             if (pilot_qof_context->qof.error)
01106                 return EXIT_FAILURE;
01107             pq_invoice_xmlfile (pilot_qof_context);
01108         }
01109         else
01110             qof_cmd_xmlfile (&pilot_qof_context->qof);
01111         break;
01112     }
01113     case qof_op_offline:
01114         {
01115             pilot_qof_context->qof.filename = g_strdup (filename);
01116             if ((pilot_qof_context->invoice_city)
01117                 || (pilot_qof_context->invoice_vendor))
01118             {
01119                 check_invoice_handler (pilot_qof_context);
01120                 if (pilot_qof_context->qof.error)
01121                     return EXIT_FAILURE;
01122                 pq_invoice_xmlfile (pilot_qof_context);
01123             }
01124             else
01125                 qof_cmd_xmlfile (&pilot_qof_context->qof);
01126             break;
01127         }
01128     case qof_op_list:
01129         {
01130             DEBUG (" list mode");
01131             qof_cmd_list ();
01132             break;
01133         }
01134     case qof_op_explain:
01135         {
01136             if (!pilot_qof_context->qof.database)
01137             {
01138                 qof_main_wrap_line (stderr, ERR_INDENT,
01139                     _("%s: Error: please specify which database "
01140                         "you would like explained.\n\n"), PACKAGE);
01141                 break;
01142             }
01143             DEBUG (" explain mode");
01144             qof_cmd_explain (&pilot_qof_context->qof);
01145             break;
01146         }
01147     case qof_op_hotsync:
01148         {
01149             DEBUG (" hotsync mode");
01150             pilot_qof_context->port = g_strdup (plu_port);
01151             pilot_qof_context->quiet = plu_quiet;
01152             qof_cmd_hotsync (pilot_qof_context);
01153             break;
01154         }
01155     case qof_op_noop:
01156     case qof_op_category:
01157     case qof_op_database:
01158     case qof_op_time:
01159     case qof_op_exclude:
01160     case qof_op_sql:
01161     case qof_op_sql_file:
01162     case qof_op_write:
01163     case qof_op_upload:
01164     case qof_op_vers:
01165     case qof_op_compress:
01166     case qof_op_debug:
01167     case qof_op_inv_city:
01168     case qof_op_inv_vendor:
01169     case qof_op_use_locale:
01170     default:
01171             break;
01172     }
01173     poptFreeContext (pc);
01174     pilot_qof_free (pilot_qof_context);
01175     if (debug_on)
01176         qof_log_shutdown ();
01177     qof_close ();
01178     return EXIT_SUCCESS;
01179 }
01180 

Generated on Wed Jul 28 2010 21:39:21 for pilot-qof by  doxygen 1.7.1