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.24.4.9 2003/03/12 23:31:10 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 }
00200
00201 ExpenseConduit::~ExpenseConduit()
00202 {
00203 FUNCTIONSETUP;
00204 cleanup();
00205 }
00206
00207 bool ExpenseConduit::exec()
00208 {
00209 FUNCTIONSETUP;
00210 DEBUGCONDUIT<<expense_id<<endl;
00211
00212 if (!fConfig)
00213 {
00214 kdWarning() << k_funcinfo
00215 << ": No configuration set for expense conduit."
00216 << endl;
00217 cleanup();
00218 return false;
00219 }
00220
00221 fDatabase=new PilotSerialDatabase(pilotSocket(),CSL1("ExpenseDB"),
00222 this,"ExpenseDB");
00223
00224 fConfig->setGroup("Expense-conduit");
00225
00226 fDBType = fConfig->readNumEntry("DBTypePolicy",
00227 ExpenseWidgetSetup::PolicyNone);
00228
00229 #ifdef DEBUG
00230 DEBUGCONDUIT << fname
00231 << ": Syncing with policy "
00232 << fDBType
00233 << endl;
00234 #endif
00235
00236 fDBnm=fConfig->readEntry("DBname");
00237 fDBsrv=fConfig->readEntry("DBServer");
00238 fDBtable=fConfig->readEntry("DBtable");
00239 fDBlogin=fConfig->readEntry("DBlogin");
00240 fDBpasswd=fConfig->readEntry("DBpasswd");
00241
00242 fRecordCount = 0;
00243
00244 if (isTest())
00245 {
00246 doTest();
00247 cleanup();
00248 emit syncDone(this);
00249 return true;
00250 }
00251 else
00252 {
00253 QString CSVName=fConfig->readEntry("CSVFileName");
00254 if (!CSVName.isEmpty())
00255 {
00256 fCSVFile = new QFile(CSVName);
00257
00258
00259
00260
00261 int flags = 0;
00262 int logPolicy = fConfig->readNumEntry("CSVRotatePolicy",
00263 ExpenseWidgetSetup::PolicyAppend);
00264
00265 switch(logPolicy)
00266 {
00267 case ExpenseWidgetSetup::PolicyAppend :
00268 flags = IO_ReadWrite | IO_Append;
00269 break;
00270 case ExpenseWidgetSetup::PolicyOverwrite :
00271 flags = IO_WriteOnly | IO_Truncate;
00272 break;
00273 default :
00274 flags = IO_ReadWrite | IO_Append;
00275 }
00276
00277 if (fCSVFile && fCSVFile->open(flags))
00278 {
00279 fCSVStream = new QTextStream(fCSVFile);
00280 }
00281 }
00282
00283
00284
00285
00286
00287 QTimer::singleShot(0,this,SLOT(slotNextRecord()));
00288 }
00289 return true;
00290 }
00291
00292 void ExpenseConduit::doTest()
00293 {
00294 #ifdef DEBUG
00295 DEBUGCONDUIT << k_funcinfo
00296 << ": Got settings "
00297 << fDBType << " "
00298 << fDBnm << " "
00299 << fDBsrv << " "
00300 << fDBtable << " "
00301 << fDBlogin
00302 << endl;
00303 #endif
00304 }
00305
00306 void ExpenseConduit::csvOutput(QTextStream *out,Expense *e)
00307 {
00308 FUNCTIONSETUP;
00309
00310
00311 int tmpyr=e->date.tm_year+1900;
00312 int tmpday=e->date.tm_mday;
00313 int tmpmon=e->date.tm_mon+1;
00314
00315 (*out) << tmpyr << "-" << tmpmon << "-" << tmpday << "," ;
00316
00317
00318 (*out) << e->amount << ","
00319 << get_pay_type(e->payment) << ","
00320 << e->vendor << ","
00321 << get_entry_type(e->type) << ","
00322 << e->city << ","
00323 ;
00324
00325
00326
00327
00328
00329 QString tmpatt=PilotAppCategory::codec()->toUnicode(e->attendees);
00330 QString tmpatt2=tmpatt.simplifyWhiteSpace();
00331
00332 (*out) << tmpatt2 << "," ;
00333
00334
00335
00336 QString tmpnotes=PilotAppCategory::codec()->toUnicode(e->note);
00337 QString tmpnotes2=tmpnotes.simplifyWhiteSpace();
00338
00339 (*out) << tmpnotes2 << endl;
00340 }
00341
00342 void ExpenseConduit::slotNextRecord()
00343 {
00344 FUNCTIONSETUP;
00345
00346 Expense e;
00347
00348 PilotRecord *rec=fDatabase->readNextModifiedRec();
00349 if (!rec)
00350 {
00351 #ifdef DEBUG
00352 DEBUGCONDUIT << fname
00353 << ": No more records left."
00354 << endl;
00355 #endif
00356
00357 QString msg(i18n("Synced one record.",
00358 "Synced %n records.",fRecordCount));
00359 addSyncLogEntry(msg);
00360
00361 fDatabase->resetSyncFlags();
00362
00363 cleanup();
00364 emit syncDone(this);
00365 return;
00366 }
00367 else
00368 {
00369 fRecordCount++;
00370 #ifdef DEBUG
00371 DEBUGCONDUIT << fname
00372 << ": Got record "
00373 << fRecordCount
00374 << " @"
00375 << (int) rec
00376 << endl;
00377 #endif
00378 }
00379
00380 (void) unpack_Expense(&e,
00381 (unsigned char *)rec->getData(),rec->getLen());
00382
00383 delete rec;
00384 rec = 0L;
00385
00386 if (fCSVStream)
00387 {
00388 csvOutput(fCSVStream,&e);
00389 }
00390
00391 switch(fDBType)
00392 {
00393 case ExpenseWidgetSetup::PolicyPostgresql :
00394 postgresOutput(&e);
00395 break;
00396 }
00397
00398 QTimer::singleShot(0,this,SLOT(slotNextRecord()));
00399 }
00400
00401
00402 void ExpenseConduit::dumpPostgresTable()
00403 {
00404 FUNCTIONSETUP;
00405
00406 #ifdef DEBUG
00407
00408
00409
00410
00411 QString query = CSL1("select * from \"%1\";").arg(fDBtable);
00412
00413 QString cmd = CSL1("echo ");
00414 cmd += KShellProcess::quote(fDBpasswd);
00415 cmd += CSL1("|psql -h ");
00416 cmd += KShellProcess::quote(fDBsrv);
00417 cmd += CSL1(" -U ");
00418 cmd += KShellProcess::quote(fDBlogin);
00419 cmd += CSL1(" -c ");
00420 cmd += KShellProcess::quote(query);
00421 cmd += CSL1(" ");
00422 cmd += KShellProcess::quote(fDBnm);
00423 cmd += CSL1(" > ~/testpg.txt");
00424
00425 KShellProcess shproc;
00426 shproc.clearArguments();
00427 shproc << cmd;
00428 shproc.start(KShellProcess::Block, KShellProcess::NoCommunication);
00429 #endif
00430 }
00431
00432 void ExpenseConduit::postgresOutput(Expense *e)
00433 {
00434 FUNCTIONSETUP;
00435
00436
00437
00438
00439
00440
00441 int tmpyr=e->date.tm_year+1900;
00442 char dtstng[DATESIZE];
00443 int tmpday=e->date.tm_mday;
00444 int tmpmon=e->date.tm_mon+1;
00445 sprintf(dtstng,"%d-%d-%d",tmpyr,tmpmon,tmpday);
00446 QString tmpnotes=PilotAppCategory::codec()->toUnicode(e->note);
00447 QString tmpnotes2=tmpnotes.simplifyWhiteSpace();
00448 const char* nmsg=tmpnotes2.local8Bit();
00449
00450 QString tmpatt=PilotAppCategory::codec()->toUnicode(e->attendees);
00451 QString tmpatt2=tmpatt.simplifyWhiteSpace();
00452 const char* amesg=tmpatt2.local8Bit();
00453 const char* etmsg=get_entry_type(e->type);
00454 const char* epmsg=get_pay_type(e->payment);
00455
00456 QString query;
00457 query.sprintf(
00458 "INSERT INTO \"%s\" (\"fldTdate\", \"fldAmount\", \"fldPType\", "
00459 "\"fldVName\", \"fldEType\", \"fldLocation\", \"fldAttendees\", "
00460 "\"fldNotes\") VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');",
00461 fDBtable.latin1(),
00462 dtstng,
00463 e->amount,epmsg,e->vendor,etmsg,e->city,amesg,nmsg);
00464
00465 QString cmd = CSL1("echo ");
00466 cmd += KShellProcess::quote(fDBpasswd);
00467 cmd += CSL1("|psql -h ");
00468 cmd += KShellProcess::quote(fDBsrv);
00469 cmd += CSL1(" -U ");
00470 cmd += KShellProcess::quote(fDBlogin);
00471 cmd += CSL1(" -c ");
00472 cmd += KShellProcess::quote(query);
00473 cmd += CSL1(" ");
00474 cmd += KShellProcess::quote(fDBnm);
00475
00476 KShellProcess shproc;
00477 shproc.clearArguments();
00478 shproc << cmd;
00479 shproc.start(KShellProcess::Block, KShellProcess::NoCommunication);
00480 }
00481
00482 void ExpenseConduit::cleanup()
00483 {
00484 FUNCTIONSETUP;
00485
00486 KPILOT_DELETE(fCSVStream);
00487 KPILOT_DELETE(fCSVFile);
00488 KPILOT_DELETE(fDatabase);
00489 }