00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
#include "options.h"
00033
00034
00035
00036
00037
00038
00039
#include <time.h>
00040
#include <stdlib.h>
00041
#include <stdio.h>
00042
#include <string.h>
00043
00044
00045
#include <qdir.h>
00046
#include <qmap.h>
00047
#include <qcstring.h>
00048
#include <qobject.h>
00049
#include <qdatetime.h>
00050
#include <qtextstream.h>
00051
#include <qtextcodec.h>
00052
00053
#include <kconfig.h>
00054
#include <kdebug.h>
00055
#include <kprocess.h>
00056
00057
#include <pi-expense.h>
00058
00059
00060
00061
00062
00063
#include "pilotSerialDatabase.h"
00064
#include "pilotRecord.h"
00065
#include "pilotAppCategory.h"
00066
00067
#include "setupDialog.h"
00068
#include "expense.moc"
00069
#include <qtimer.h>
00070
#define DATESIZE 10
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
const char *
00087 get_entry_type(
enum ExpenseType type)
00088 {
00089
switch(type) {
00090
case etAirfare:
00091
return "Airfare";
00092
case etBreakfast:
00093
return "Breakfast";
00094
case etBus:
00095
return "Bus";
00096
case etBusinessMeals:
00097
return "BusinessMeals";
00098
case etCarRental:
00099
return "CarRental";
00100
case etDinner:
00101
return "Dinner";
00102
case etEntertainment:
00103
return "Entertainment";
00104
case etFax:
00105
return "Fax";
00106
case etGas:
00107
return "Gas";
00108
case etGifts:
00109
return "Gifts";
00110
case etHotel:
00111
return "Hotel";
00112
case etIncidentals:
00113
return "Incidentals";
00114
case etLaundry:
00115
return "Laundry";
00116
case etLimo:
00117
return "Limo";
00118
case etLodging:
00119
return "Lodging";
00120
case etLunch:
00121
return "Lunch";
00122
case etMileage:
00123
return "Mileage";
00124
case etOther:
00125
return "Other";
00126
case etParking:
00127
return "Parking";
00128
case etPostage:
00129
return "Postage";
00130
case etSnack:
00131
return "Snack";
00132
case etSubway:
00133
return "Subway";
00134
case etSupplies:
00135
return "Supplies";
00136
case etTaxi:
00137
return "Taxi";
00138
case etTelephone:
00139
return "Telephone";
00140
case etTips:
00141
return "Tips";
00142
case etTolls:
00143
return "Tolls";
00144
case etTrain:
00145
return "Train";
00146
default:
00147
return NULL;
00148 }
00149 }
00150
00151
const char *
00152 get_pay_type(
enum ExpensePayment type)
00153 {
00154
switch (type) {
00155
case epAmEx:
00156
return "AmEx";
00157
case epCash:
00158
return "Cash";
00159
case epCheck:
00160
return "Check";
00161
case epCreditCard:
00162
return "CreditCard";
00163
case epMasterCard:
00164
return "MasterCard";
00165
case epPrepaid:
00166
return "Prepaid";
00167
case epVISA:
00168
return "VISA";
00169
case epUnfiled:
00170
return "Unfiled";
00171
default:
00172
return NULL;
00173 }
00174 }
00175
00176
00177
00178
00179
00180
00181
static const char *expense_id =
00182
"$Id: expense.cc,v 1.32 2003/06/24 06:58:32 adridg Exp $";
00183
00184
00185
00186
00187 ExpenseConduit::ExpenseConduit(KPilotDeviceLink *d,
00188
const char *name,
00189
const QStringList &l) :
00190
ConduitAction(d,name,l),
00191 fDatabase(0L),
00192 fCSVFile(0L),
00193 fCSVStream(0L)
00194 {
00195 FUNCTIONSETUP;
00196
#ifdef DEBUG
00197
DEBUGCONDUIT<<expense_id<<endl;
00198
#endif
00199
fConduitName=i18n(
"Expense");
00200 }
00201
00202 ExpenseConduit::~ExpenseConduit()
00203 {
00204 FUNCTIONSETUP;
00205 cleanup();
00206 }
00207
00208
bool ExpenseConduit::exec()
00209 {
00210 FUNCTIONSETUP;
00211 DEBUGCONDUIT<<expense_id<<endl;
00212
00213
if (!fConfig)
00214 {
00215 kdWarning() << k_funcinfo
00216 <<
": No configuration set for expense conduit."
00217 << endl;
00218 cleanup();
00219
return false;
00220 }
00221
00222 fDatabase=
new PilotSerialDatabase(pilotSocket(),CSL1(
"ExpenseDB"),
00223
this,
"ExpenseDB");
00224
00225 fConfig->setGroup(
"Expense-conduit");
00226
00227 fDBType = fConfig->readNumEntry(
"DBTypePolicy",
00228 ExpenseWidgetSetup::PolicyNone);
00229
00230
#ifdef DEBUG
00231
DEBUGCONDUIT << fname
00232 <<
": Syncing with policy "
00233 << fDBType
00234 << endl;
00235
#endif
00236
00237 fDBnm=fConfig->readEntry(
"DBname");
00238 fDBsrv=fConfig->readEntry(
"DBServer");
00239 fDBtable=fConfig->readEntry(
"DBtable");
00240 fDBlogin=fConfig->readEntry(
"DBlogin");
00241 fDBpasswd=fConfig->readEntry(
"DBpasswd");
00242
00243 fRecordCount = 0;
00244
00245
if (isTest())
00246 {
00247 doTest();
00248 cleanup();
00249 emit syncDone(
this);
00250
return true;
00251 }
00252
else
00253 {
00254 QString CSVName=fConfig->readEntry(
"CSVFileName");
00255
if (!CSVName.isEmpty())
00256 {
00257 fCSVFile =
new QFile(CSVName);
00258
00259
00260
00261
00262
int flags = 0;
00263
int logPolicy = fConfig->readNumEntry(
"CSVRotatePolicy",
00264 ExpenseWidgetSetup::PolicyAppend);
00265
00266
switch(logPolicy)
00267 {
00268
case ExpenseWidgetSetup::PolicyAppend :
00269 flags = IO_ReadWrite | IO_Append;
00270
break;
00271
case ExpenseWidgetSetup::PolicyOverwrite :
00272 flags = IO_WriteOnly | IO_Truncate;
00273
break;
00274
default :
00275 flags = IO_ReadWrite | IO_Append;
00276 }
00277
00278
if (fCSVFile && fCSVFile->open(flags))
00279 {
00280 fCSVStream =
new QTextStream(fCSVFile);
00281 }
00282 }
00283
00284
00285
00286
00287
00288 QTimer::singleShot(0,
this,SLOT(slotNextRecord()));
00289 }
00290
return true;
00291 }
00292
00293
void ExpenseConduit::doTest()
00294 {
00295
#ifdef DEBUG
00296
DEBUGCONDUIT << k_funcinfo
00297 <<
": Got settings "
00298 << fDBType <<
" "
00299 << fDBnm <<
" "
00300 << fDBsrv <<
" "
00301 << fDBtable <<
" "
00302 << fDBlogin
00303 << endl;
00304
#endif
00305
}
00306
00307
void ExpenseConduit::csvOutput(QTextStream *out,Expense *e)
00308 {
00309 FUNCTIONSETUP;
00310
00311
00312
int tmpyr=e->date.tm_year+1900;
00313
int tmpday=e->date.tm_mday;
00314
int tmpmon=e->date.tm_mon+1;
00315
00316 (*out) << tmpyr <<
"-" << tmpmon <<
"-" << tmpday <<
"," ;
00317
00318
00319 (*out) << e->amount <<
","
00320 << get_pay_type(e->payment) <<
","
00321 << e->vendor <<
","
00322 << get_entry_type(e->type) <<
","
00323 << e->city <<
","
00324 ;
00325
00326
00327
00328
00329
00330 QString tmpatt=PilotAppCategory::codec()->toUnicode(e->attendees);
00331 QString tmpatt2=tmpatt.simplifyWhiteSpace();
00332
00333 (*out) << tmpatt2 <<
"," ;
00334
00335
00336
00337 QString tmpnotes=PilotAppCategory::codec()->toUnicode(e->note);
00338 QString tmpnotes2=tmpnotes.simplifyWhiteSpace();
00339
00340 (*out) << tmpnotes2 << endl;
00341 }
00342
00343
void ExpenseConduit::slotNextRecord()
00344 {
00345 FUNCTIONSETUP;
00346
00347 Expense e;
00348
00349 PilotRecord *rec=fDatabase->readNextModifiedRec();
00350
if (!rec)
00351 {
00352
#ifdef DEBUG
00353
DEBUGCONDUIT << fname
00354 <<
": No more records left."
00355 << endl;
00356
#endif
00357
00358 QString msg(i18n(
"Synced one record.",
00359
"Synced %n records.",fRecordCount));
00360 addSyncLogEntry(msg);
00361
00362 fDatabase->resetSyncFlags();
00363
00364 cleanup();
00365 emit syncDone(
this);
00366
return;
00367 }
00368
else
00369 {
00370 fRecordCount++;
00371
#ifdef DEBUG
00372
DEBUGCONDUIT << fname
00373 <<
": Got record "
00374 << fRecordCount
00375 <<
" @"
00376 << (
int) rec
00377 << endl;
00378
#endif
00379
}
00380
00381 (
void) unpack_Expense(&e,
00382 (
unsigned char *)rec->getData(),rec->getLen());
00383
00384
delete rec;
00385 rec = 0L;
00386
00387
if (fCSVStream)
00388 {
00389 csvOutput(fCSVStream,&e);
00390 }
00391
00392
switch(fDBType)
00393 {
00394
case ExpenseWidgetSetup::PolicyPostgresql :
00395 postgresOutput(&e);
00396
break;
00397 }
00398
00399 QTimer::singleShot(0,
this,SLOT(slotNextRecord()));
00400 }
00401
00402
00403
void ExpenseConduit::dumpPostgresTable()
00404 {
00405 FUNCTIONSETUP;
00406
00407
#ifdef DEBUG
00408
00409
00410
00411
00412 QString query = CSL1(
"select * from \"%1\";").arg(fDBtable);
00413
00414 QString cmd = CSL1(
"echo ");
00415 cmd += KShellProcess::quote(fDBpasswd);
00416 cmd += CSL1(
"|psql -h ");
00417 cmd += KShellProcess::quote(fDBsrv);
00418 cmd += CSL1(
" -U ");
00419 cmd += KShellProcess::quote(fDBlogin);
00420 cmd += CSL1(
" -c ");
00421 cmd += KShellProcess::quote(query);
00422 cmd += CSL1(
" ");
00423 cmd += KShellProcess::quote(fDBnm);
00424 cmd += CSL1(
" > ~/testpg.txt");
00425
00426 KShellProcess shproc;
00427 shproc.clearArguments();
00428 shproc << cmd;
00429 shproc.start(KShellProcess::Block, KShellProcess::NoCommunication);
00430
#endif
00431
}
00432
00433
void ExpenseConduit::postgresOutput(Expense *e)
00434 {
00435 FUNCTIONSETUP;
00436
00437
00438
00439
00440
00441
00442
int tmpyr=e->date.tm_year+1900;
00443
char dtstng[DATESIZE];
00444
int tmpday=e->date.tm_mday;
00445
int tmpmon=e->date.tm_mon+1;
00446 sprintf(dtstng,
"%d-%d-%d",tmpyr,tmpmon,tmpday);
00447 QString tmpnotes=PilotAppCategory::codec()->toUnicode(e->note);
00448 QString tmpnotes2=tmpnotes.simplifyWhiteSpace();
00449
const char* nmsg=tmpnotes2.local8Bit();
00450
00451 QString tmpatt=PilotAppCategory::codec()->toUnicode(e->attendees);
00452 QString tmpatt2=tmpatt.simplifyWhiteSpace();
00453
const char* amesg=tmpatt2.local8Bit();
00454
const char* etmsg=get_entry_type(e->type);
00455
const char* epmsg=get_pay_type(e->payment);
00456
00457 QString query;
00458 query.sprintf(
00459
"INSERT INTO \"%s\" (\"fldTdate\", \"fldAmount\", \"fldPType\", "
00460
"\"fldVName\", \"fldEType\", \"fldLocation\", \"fldAttendees\", "
00461
"\"fldNotes\") VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');",
00462 fDBtable.latin1(),
00463 dtstng,
00464 e->amount,epmsg,e->vendor,etmsg,e->city,amesg,nmsg);
00465
00466 QString cmd = CSL1(
"echo ");
00467 cmd += KShellProcess::quote(fDBpasswd);
00468 cmd += CSL1(
"|psql -h ");
00469 cmd += KShellProcess::quote(fDBsrv);
00470 cmd += CSL1(
" -U ");
00471 cmd += KShellProcess::quote(fDBlogin);
00472 cmd += CSL1(
" -c ");
00473 cmd += KShellProcess::quote(query);
00474 cmd += CSL1(
" ");
00475 cmd += KShellProcess::quote(fDBnm);
00476
00477 KShellProcess shproc;
00478 shproc.clearArguments();
00479 shproc << cmd;
00480 shproc.start(KShellProcess::Block, KShellProcess::NoCommunication);
00481 }
00482
00483
void ExpenseConduit::cleanup()
00484 {
00485 FUNCTIONSETUP;
00486
00487 KPILOT_DELETE(fCSVStream);
00488 KPILOT_DELETE(fCSVFile);
00489 KPILOT_DELETE(fDatabase);
00490 }