kpilot Library API Documentation

expense.cc

00001 /*expense.cc KPilot 00002 ** 00003 ** Copyright (C) 2000-2001 by Adriaan de Groot, Christopher Molnar 00004 ** 00005 ** This file is part of the Expense conduit, a conduit for KPilot that 00006 ** synchronises the Pilot's expense application with .. something? 00007 ** Actually it just writes a CSV file. 00008 */ 00009 00010 /* 00011 ** This program 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 2 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 in a file called COPYING; if not, write to 00023 ** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00024 ** MA 02111-1307, USA. 00025 */ 00026 00027 /* 00028 ** Bug reports and questions can be sent to kde-pim@kde.org 00029 */ 00030 00031 00032 #include "options.h" 00033 00034 // Only include what we really need: 00035 // First UNIX system stuff, then std C++, 00036 // then Qt, then KDE, then local includes. 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 /* This was copied out of the pilot-link package. 00072 * I just like it here for quick reference. 00073 struct Expense { 00074 struct tm date; 00075 enum ExpenseType type; 00076 enum ExpensePayment payment; 00077 int currency; 00078 char * amount; 00079 char * vendor; 00080 char * city; 00081 char * attendees; 00082 char * note; 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 // Something to allow us to check what revision 00178 // the modules are that make up a binary distribution. 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 /* virtual */ 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 // Change the flags value in the switch() below. 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 // Start the mechanism for reading one record 00285 // at a time while retaining responsiveness. 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 //format date for csv file 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 //write rest of record 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 // remove line breaks from list of attendees - 00327 // can't have in csv files 00328 // 00329 // 00330 QString tmpatt=PilotAppCategory::codec()->toUnicode(e->attendees); 00331 QString tmpatt2=tmpatt.simplifyWhiteSpace(); 00332 00333 (*out) << tmpatt2 << "," ; 00334 00335 // remove extra formatting from notes - 00336 // can't have in csv files 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 // next three lines just for debug purposes - 00409 // Remove for final creates a dump of table. 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 // int recordcount=0; 00438 // int index=0; 00439 // int syscall=0; 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 }
KDE Logo
This file is part of the documentation for kpilot Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:57:48 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003