pilot-qof 0.2.3
|
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 G_GNUC_UNUSED 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