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 Sat May 1 11:36:47 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003