3 * kPPP: A pppd front end for the KDE project
7 * Copyright (C) 1997 Bernd Johannes Wuebben
8 * wuebben@math.cornell.edu
10 * This file contributed by: Mario Weilguni, <mweilguni@sime.com>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this program; if not, write to the Free
25 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <sys/types.h>
34 #include <QTimerEvent>
37 #include <kstandarddirs.h>
42 #include "accounting.h"
46 // defines the maximum duration until the current costs
47 // are saved again (to prevent loss due to "kill")
48 // specifying -1 disables the features
49 #define UPDATE_TIME (5*60*1000)
51 extern PPPData gpppdata
;
53 /////////////////////////////////////////////////////////////////////////////
57 /////////////////////////////////////////////////////////////////////////////
58 static QString
timet2qstring(time_t t
) {
66 /////////////////////////////////////////////////////////////////////////////
68 // The base class for the accounting system provides a base set of useful
69 // and common functions, but does not do any accounting by itself. The
70 // accounting is accomplished withing it's derived classes
72 /////////////////////////////////////////////////////////////////////////////
73 AccountingBase::AccountingBase(QObject
*parent
) :
78 QDate dt
= QDate::currentDate();
79 LogFileName
= QString("%1-%2.log")
80 .arg(QDate::shortMonthName(dt
.month()))
83 LogFileName
= KGlobal::dirs()->saveLocation("appdata", "Log")
86 kDebug(5002) << "LogFileName: " << LogFileName
;
89 AccountingBase::~AccountingBase() {
95 double AccountingBase::total() const {
96 return _total
+ _session
;
101 double AccountingBase::session() const {
106 // set costs back to zero ( typically once per month)
107 void AccountingBase::resetCosts(const QString
& accountname
){
108 QString prev_account
= gpppdata
.accname();
110 gpppdata
.setAccount(accountname
);
111 gpppdata
.setTotalCosts("");
113 gpppdata
.setAccount(prev_account
);
117 void AccountingBase::resetVolume(const QString
& accountname
){
118 QString prev_account
= gpppdata
.accname();
120 gpppdata
.setAccount(accountname
);
121 gpppdata
.setTotalBytes(0);
123 gpppdata
.setAccount(prev_account
);
127 void AccountingBase::logMessage(const QString
&s
, bool newline
) {
128 int old_umask
= umask(0077);
130 QFile
f(LogFileName
);
132 bool result
= f
.open(QIODevice::ReadWrite
);
134 // move to eof, and place \n if necessary
146 Q3CString tmp
= s
.toLocal8Bit();
147 f
.write(tmp
, tmp
.length());
156 QString
AccountingBase::getCosts(const QString
& accountname
) {
157 QString prev_account
= gpppdata
.accname();
159 gpppdata
.setAccount(accountname
);
160 QString val
= gpppdata
.totalCosts();
161 // ### currency from rule file
162 // QString val = KGlobal::locale()->formatMoney(gpppdata.totalCosts().toDouble(), currency);
164 gpppdata
.setAccount(prev_account
);
171 bool AccountingBase::saveCosts() {
172 if(!_name
.isNull() && _name
.length() > 0) {
176 gpppdata
.setTotalCosts(val
);
185 bool AccountingBase::loadCosts() {
186 QString val
= gpppdata
.totalCosts();
188 if(val
.isNull()) // QString will segfault if isnull and toDouble called
192 _total
= val
.toDouble(&ok
);
201 QString
AccountingBase::getAccountingFile(const QString
&accountname
) {
202 QString f
= "kppp/Rules/";
204 QString d
= KStandardDirs::locate("data", f
);
213 /////////////////////////////////////////////////////////////////////////////
215 // Accounting class for ruleset files
217 /////////////////////////////////////////////////////////////////////////////
218 Accounting::Accounting(QObject
*parent
, PPPStats
*st
) :
219 AccountingBase(parent
),
227 bool Accounting::running() const {
228 return (bool)(acct_timer_id
!= 0);
232 void Accounting::timerEvent(QTimerEvent
*t
) {
233 if(t
->timerId() == acct_timer_id
) {
237 double connect_time
= difftime(time(0), start_time
);
239 rules
.getActiveRule(QDateTime::currentDateTime(), connect_time
, newCosts
, newLen
);
240 if(newLen
< 1) { // changed to < 1
242 return; // no default rule found
245 // check if we have a new rule. If yes,
246 // kill the timer and restart it with new
248 if((newCosts
!= _lastcosts
) || (newLen
!= _lastlen
)) {
250 kDebug(5002) << "SWITCHING RULES, new costs = "
251 << fixed
<< qSetRealNumberPrecision(2) << newCosts
252 << "new len = " << newLen
;
254 killTimer(acct_timer_id
);
256 acct_timer_id
= startTimer((int)(newLen
* 1000.0));
259 _lastcosts
= newCosts
;
262 // emit changed() signal if necessary
264 _session
+= newCosts
;
265 emit
changed(rules
.currencyString(total()),
266 rules
.currencyString(session()));
270 } // if(t->timerId() == acct_timer_id)...
272 if(t
->timerId() == update_timer_id
) {
273 // just to be sure, save the current costs
274 // every n seconds (see UPDATE_TIME)
280 void Accounting::slotStart() {
285 _session
= rules
.perConnectionCosts();
286 rules
.setStartTime(QDateTime::currentDateTime());
287 acct_timer_id
= startTimer(1);
289 update_timer_id
= startTimer(UPDATE_TIME
);
291 start_time
= time(0);
293 s
= timet2qstring(start_time
);
295 s
+= gpppdata
.accname();
297 s
+= rules
.currencySymbol();
304 void Accounting::slotStop() {
306 killTimer(acct_timer_id
);
307 if(update_timer_id
!= 0)
308 killTimer(update_timer_id
);
313 s
.sprintf(":%s:%0.4e:%0.4e:%u:%u\n",
314 timet2qstring(time(0)).toUtf8().data(),
320 logMessage(s
, false);
326 bool Accounting::loadRuleSet(const QString
& name
) {
328 if (name
.isEmpty()) {
329 rules
.load(""); // delete old rules
333 QString d
= AccountingBase::getAccountingFile(name
);
337 int ret
= rules
.load(d
);
338 _name
= rules
.name();
339 return (bool)(ret
== 0);
346 double Accounting::total() const {
347 if(rules
.minimumCosts() <= _session
)
348 return _total
+ _session
;
350 return _total
+ rules
.minimumCosts();
355 double Accounting::session() const {
356 if(rules
.minimumCosts() <= _session
)
359 return rules
.minimumCosts();
365 ExecutableAccounting::ExecutableAccounting(PPPStats
*st
, QObject
*parent
) :
366 AccountingBase(parent
),
373 bool ExecutableAccounting::running() const
375 return proc
&& proc
->isRunning();
379 bool ExecutableAccounting::loadRuleSet(const QString
&) {
380 QString s
= AccountingBase::getAccountingFile(gpppdata
.accountingFile());
381 return (access(QFile::encodeName(s
), X_OK
) == 0);
385 void ExecutableAccounting::gotData(K3Process */
*proc*/
, char *buffer
, int /*buflen*/) {
388 int pos
, last_pos
= 0;
392 pos
= b
.indexOf(':');
393 while(pos
!= -1 && nFields
< 8) {
394 field
[nFields
++] = b
.mid(last_pos
, pos
-last_pos
);
396 pos
= b
.indexOf(':', last_pos
);
399 for(int i
= 0; i
< nFields
;i
++)
400 fprintf(stderr
, "FIELD[%d] = %s\n", i
, field
[i
].toLocal8Bit().data());
402 QString __total
, __session
;
404 int del1
, del2
, del3
;
406 del1
= s
.indexOf(':');
407 del2
= s
.indexOf(':', del1
+1);
408 del3
= s
.indexOf(':', del2
+1);
409 if(del1
== -1 || del2
== -1 || del3
== -1) {
410 // TODO: do something useful here
414 provider
= s
.left(del1
);
415 currency
= s
.mid(del1
, del2
-del1
);
416 __total
= s
.mid(del2
, del2
-del1
);
417 __session
= s
.mid(del3
, s
.length()-del3
+1);
420 _total
= __total
.toDouble(&ok1
);
421 _session
= __session
.toDouble(&ok2
);
424 // TODO: do something useful here
428 printf("PROVIDER=%s, CURRENCY=%s, TOTAL=%0.3e, SESSION=%0.3e\n",
429 provider
.toLocal8Bit().data(),
430 currency
.toLocal8Bit().data(),
436 void ExecutableAccounting::slotStart() {
438 slotStop(); // just to make sure
441 QString s
= AccountingBase::getAccountingFile(gpppdata
.accountingFile());
442 proc
= new K3Process
;
445 s_total
.sprintf("%0.8f", total());
446 *proc
<< s
<< s_total
;
447 connect(proc
, SIGNAL(receivedStdout(K3Process
*, char *, int)),
448 this, SLOT(gotData(K3Process
*, char *, int)));
451 time_t start_time
= time(0);
452 s
= timet2qstring(start_time
);
454 s
+= gpppdata
.accname();
462 void ExecutableAccounting::slotStop() {
469 s
.sprintf(":%s:%0.4e:%0.4e:%u:%u\n",
470 timet2qstring(time(0)).toLocal8Bit().data(),
476 logMessage(s
, false);
481 #include "accounting.moc"