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

Generated on Tue Mar 6 00:08:09 2007 for pilot-qof by  doxygen 1.5.1