00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00292
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
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
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
00475 pref_unpack = p->db_pref_unpack;
00476
00477
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
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
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
00518 if ((attr & dlpRecAttrDeleted) || (attr & dlpRecAttrArchived))
00519 continue;
00520
00521 context->ent_category = category;
00522
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
00577
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
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
00693
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
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
00747
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
00758
00759
00760
00761
00762
00763 qof_main_moderate_query (&context->qof);
00764
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
00900
00901 qof_mod_convert_deprecated (1, &pilot_qof_context->qof);
00902 while ((optc = poptGetNextOpt (pc)) >= 0)
00903 {
00904 switch (optc)
00905 {
00906
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
00947 fprintf (stdout, _(" Build target............: %s\n"),
00948 HOST_OS);
00949
00950 fprintf (stdout, _(" Build date..............: %s %s\n"),
00951 __DATE__, __TIME__);
00952
00953 fprintf (stdout, _(" Built for pilot-link ...: %s\n"),
00954 PILOT_LINK_SUPPORT);
00955
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
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
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
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