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 }