up_uploader_qt.cpp

Go to the documentation of this file.
00001 /*
00002  !concept {:name => "Multipart HTTP posting (Qt)",
00003    :desc => "Multipart HTTP(S) POSTing using the QtNetwork API."}
00004 */
00005 
00006 #include "up_uploader_qt_private.hpp"
00007 
00008 #include "cf_query.h"
00009 #include "er_errors.h"
00010 #include "ld_log_db.h"
00011 #include "up_private.h"
00012 #include "ut_exceptions.hpp"
00013 #include "utils_cl2.h"
00014 
00015 #include "moment_parser.h"
00016 
00017 #include "common/assertions.h"
00018 #include "common/error_list.h"
00019 #include "common/gx_exception.hpp"
00020 #include "common/logging_qt.hpp"
00021 #include "common/logging-time.h"
00022 #include "common/platform_error.h"
00023 
00024 #include <errno.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 
00028 #include <QNetworkConfiguration>
00029 #include <QNetworkConfigurationManager>
00030 
00031 #include <QtDebug>
00032 
00033 #if defined(__SYMBIAN32__)
00034 #include "epoc-iap.h"
00035 #include "common/epoc-time.h"
00036 #endif /* __SYMBIAN32__ */
00037 
00038 // --------------------------------------------------
00039 // CUploader
00040 // --------------------------------------------------
00041 
00042 static time_t TimeNow()
00043 {
00044   time_t now = time(NULL);
00045   if (now == -1)
00046     er_log_errno(er_FATAL, "time(NULL) failed");
00047   return now;
00048 }
00049 
00050 static void DataChanged(bb_Blackboard* bb, enum bb_DataType dt,
00051       gpointer data, int len, gpointer arg)
00052 {
00053   (void)dt;
00054   (void)len;
00055   CUploader* self = (CUploader*)arg;
00056   bb_Board* bd = bb_Blackboard_board(bb);
00057   bool val = bd->uploads_allowed;
00058   self->Set_uploads_allowed(val);
00059 }
00060 
00061 void CUploader::Set_uploads_allowed(bool val)
00062 {
00063   i_uploads_allowed = val;
00064   StateChanged();
00065 }
00066 
00067 void CUploader::BbRegisterL()
00068 {
00069   // Initial value (internal).
00070   bb_Blackboard* bb = ac_global_Blackboard;
00071   bb_Board* bd = bb_Blackboard_board(bb);
00072   i_uploads_allowed = bd->uploads_allowed;
00073 
00074   // Closure init.
00075   iClosure.changed = DataChanged;
00076   iClosure.arg = this;
00077 
00078   // Registration proper.
00079   if (!bb_Blackboard_register(bb,
00080             bb_dt_uploads_allowed,
00081             iClosure, NULL))
00082     throw std::bad_alloc();
00083 }
00084 
00085 void CUploader::BbUnregister()
00086 {
00087   bb_Blackboard_unregister(ac_global_Blackboard, iClosure);
00088 }
00089 
00090 // The effect is not immediate. Will only take effect when the next
00091 // poster is created.
00092 // 
00093 // We do logging here to make it possible to find out if the setting
00094 // change succeeded.
00095 void CUploader::RefreshIap(bool aNotInitial)
00096 {
00097 #if defined(__SYMBIAN32__)
00098   // TUint32 coercion hopefully okay.
00099   iIapId = (TUint32)get_config_iap_id();
00100   if (aNotInitial)
00101     log_db_log_status(GetLogDb(), NULL, "Uploader IAP changed to %d", iIapId);
00102 #endif /* __SYMBIAN32__ */
00103 }
00104 
00105 void CUploader::RefreshSnapshotTimeExpr(bool aNotInitial)
00106 {
00107   GError* localError = NULL;
00108   gchar* newOne = NULL;
00109   if (!get_ConfigDb_str("uploader.time_expr", 
00110       &newOne, __UPLOAD_TIME_EXPR__, 
00111       &localError)) {
00112     if (aNotInitial)
00113       gx_dblog_error_free_check(GetLogDb(), localError, NULL);
00114     else
00115       gx_error_free(localError);
00116   } else {
00117     assert(newOne != NULL);
00118     g_free(iSnapshotTimeExpr);
00119     iSnapshotTimeExpr = newOne;
00120     logt("got time expression");
00121     logt(iSnapshotTimeExpr);
00122     if (aNotInitial) {
00123       log_db_log_status(GetLogDb(), NULL, "Upload time expression set to '%s'",
00124       newOne);
00125 
00126       // We may need to recompute the next snapshot time based on the
00127       // new expression. But if a previosly set time has already
00128       // passed, then that is not affected by the expression change.
00129       // What is past is past.
00130       {
00131   if (iSnapshotTimerAo.isActive())
00132     iSnapshotTimerAo.stop();
00133   iNoNextSnapshotTime = false;
00134   StateChanged();
00135       }
00136     }
00137   }
00138 }
00139 
00140 static const char* KBoundary = "-----AaB03xeql7dsxeql7ds";
00141 
00142 CUploader::CUploader(ac_AppContext* aAppContext) :
00143   iAppContext(aAppContext), iNoConfig(false),
00144   iNoOldFiles(false),
00145   iNumPostFailures(0),
00146   iPostSession(NULL), iFileToPost(NULL), 
00147   iSnapshotTimePassed(false), iSnapshotTimeExpr(NULL),
00148   iNoNextSnapshotTime(false)
00149 {
00150   // Ensure that uploads directory exists.
00151   GError* mdError = NULL;
00152   if (!mkdir_p(LOG_UPLOADS_DIR, &mdError)) {
00153     er_log_gerror(er_FATAL|er_FREE, mdError, 
00154       "failure creating uploads directory");
00155   }
00156 
00157   const gchar* upload_url = ac_STATIC_GET(upload_url);
00158   if (!upload_url) {
00159     iNoConfig = true;
00160     logt("uploads disabled: no upload URL");
00161   } else {
00162     logg("upload URL: %s", upload_url);
00163     iNetworkRequest.setUrl(QUrl(upload_url));
00164     QByteArray ct("multipart/form-data, boundary=");
00165     ct.append(KBoundary);
00166     iNetworkRequest.setHeader(QNetworkRequest::ContentTypeHeader, ct);
00167     iNetworkRequest.setRawHeader("Connection", "close");
00168 
00169     // On Symbian we currently assume that CA public certs are
00170     // installed system wide.
00171 #if !defined(__SYMBIAN32__)
00172     iSslConfiguration = QSslConfiguration::defaultConfiguration();
00173     QList<QSslCertificate> caList = iSslConfiguration.caCertificates();
00174     QList<QSslCertificate> myList = QSslCertificate::fromPath("etc/ca-certs/*.crt", QSsl::Pem, QRegExp::Wildcard);
00175     caList.append(myList);
00176 #if 1
00177     foreach (const QSslCertificate& cert, myList) {
00178       qxDebug() << cert.issuerInfo(QSslCertificate::Organization);
00179     }
00180 #endif
00181 #if 1
00182     // This should make server authentication succeed, but it does not, due to Qt bug http://bugreports.qt.nokia.com/browse/QTBUG-13684. See ./src/network/ssl/qsslerror.cpp. It is wrong to say that our "root CA certificate is not trusted for this purpose" as it is a CA certificate that we have specified as such.
00183     iSslConfiguration.setCaCertificates(caList);
00184     iNetworkRequest.setSslConfiguration(iSslConfiguration);
00185 #else
00186     // So let us try this global setting instead. Of course we do not want to do this more than once as it is a global setting. But no, this does not work either.
00187     QList<QSslCertificate> curList = QSslSocket::defaultCaCertificates();
00188     foreach (const QSslCertificate& cert, myList) {
00189       if (!curList.contains(cert)) {
00190   qxDebug() << "globally adding CA" << cert.issuerInfo(QSslCertificate::Organization);
00191   QSslSocket::addDefaultCaCertificates(myList);
00192       }
00193     }
00194 #endif
00195 #endif /* not __SYMBIAN32__ */
00196   }
00197 
00198   RefreshIap(false);
00199 #if defined(__SYMBIAN32__)
00200   logg("uploader using IAP %d", iIapId);
00201 #endif /* __SYMBIAN32__ */
00202 
00203   //qxDebug() << "testing qxDebug";
00204 #if defined(__SYMBIAN32__)
00205   // Beware of naming clashes, as both Mobility and Qt Network have these classes. 
00206   // Requires Qt 4.7, unless using the Mobility version.
00207   // http://doc.qt.nokia.com/qtmobility-1.1.0-beta/bearer-management.html
00208   QNetworkConfigurationManager mgr;
00209   QList<QNetworkConfiguration> cfgList = mgr.allConfigurations();
00210   // We want to print out the list of configurations. Perhaps we can
00211   // select one by platform specific ID, which we already have. It
00212   // seems that currently on Symbian^3 we get no configurations even if
00213   // IAP entries do exist.
00214   logt("network config list begin");
00215   foreach (const QNetworkConfiguration& cfg, cfgList) {
00216     logt("config entry:");
00217     qxDebug() << cfg.identifier() << cfg.name() << cfg.bearerTypeName();
00218   }
00219   logt("network config list end");
00220   //iNetworkAccessManager.setConfiguration(cfg);
00221 #endif /* __SYMBIAN32__ */
00222 
00223   iPostTimerAo.setSingleShot(true);
00224   connect(&iPostTimerAo, SIGNAL(timeout()), 
00225     this, SLOT(handlePosterTimerEvent()));
00226   connect(&iSnapshotTimerAo, SIGNAL(timeout()), 
00227     this, SLOT(handleSnapshotTimerEvent()));
00228 
00229   RefreshSnapshotTimeExpr(false);
00230   iSnapshotTimeCtx = TimeNow();
00231   //logg("using snapshot time '%s'", iSnapshotTimeExpr);
00232 
00233   // Note that if this ConstructL() leaves, the dtor of this will
00234   // unregister us. xxx
00235   BbRegisterL();
00236 
00237   StateChangedL();
00238 }
00239 
00240 CUploader::~CUploader()
00241 {
00242   BbUnregister();
00243   DestroyPosterAo();
00244   g_free(iSnapshotTimeExpr); // safe when NULL
00245 }
00246 
00247 void CUploader::Inactivate()
00248 {
00249   DestroyPosterAo();
00250   if (iSnapshotTimerAo.isActive()) 
00251     iSnapshotTimerAo.stop();
00252   if (iPostTimerAo.isActive()) 
00253     iPostTimerAo.stop();
00254 }
00255 
00256 void CUploader::FatalError(const std::exception &ex)
00257 {
00258   Inactivate();
00259   er_log_none(er_FATAL, "error in uploader: %s", ex.what());
00260 }
00261 
00262 #define CATCH_FATAL(_act)     \
00263   try {           \
00264     _act ;          \
00265   } catch (const std::exception &_ex) {   \
00266     FatalError(_ex);        \
00267   }
00268 
00269 void CUploader::StateChanged()
00270 {
00271   CATCH_FATAL(StateChangedL());
00272 }
00273 
00274 struct ScopedPointerGfree
00275 {
00276   static inline void cleanup(gchar* pointer)
00277   {
00278     g_free(pointer);
00279   }
00280 };
00281 
00282 void CUploader::NextOldFileL()
00283 {
00284   if (iNoOldFiles) return;
00285 
00286   DELETE_Z(iFileToPost);
00287 
00288   GError* error = NULL;
00289   gchar* pathname = NULL;
00290   if (getNextOldLogFile(&pathname, &error)) {
00291     if (pathname) {
00292       dblogg("found old log file '%s'", pathname);
00293       QScopedPointer<gchar, ScopedPointerGfree> pn(pathname);
00294       QString qs = QString::fromUtf8(pathname);
00295       //qDebug() << qs;
00296       iFileToPost = q_check_ptr(new QFile(qs));
00297       //qDebug() << (iFileToPost->fileName().toLocal8Bit());
00298       return;
00299     } else {
00300       iNoOldFiles = true;
00301       dblogt("no more old files to upload");
00302     }
00303   } else {
00304     er_log_gerror(er_FATAL|er_FREE, error, "getting next log file");
00305   }
00306 }
00307 
00308 // External API.
00309 void CUploader::RequestSnapshot()
00310 {
00311   iSnapshotTimePassed = true;
00312   if (iSnapshotTimerAo.isActive())
00313     iSnapshotTimerAo.stop();
00314   StateChanged();
00315 }
00316 
00317 // Computes next snapshot time (if any), and sets a timer for it as
00318 // appropriate.
00319 void CUploader::SetSnapshotTimerL()
00320 {
00321   assert(!iSnapshotTimePassed);
00322   if (iSnapshotTimerAo.isActive())
00323     iSnapshotTimerAo.stop();
00324   if (iNoNextSnapshotTime) 
00325     return; // flag to avoid needless computation
00326   time_t now = TimeNow();
00327   time_t ctx = iSnapshotTimeCtx;
00328   time_t snaptime;
00329   GError* parseError = NULL;
00330   if (!parse_moment(iSnapshotTimeExpr, ctx, now, &snaptime, &parseError)) {
00331     gx_dblog_error_free(GetLogDb(), parseError);
00332     iNoNextSnapshotTime = true;
00333     return;
00334   }
00335   if (!snaptime) {
00336     dblogt("no snapshot time upcoming");
00337     iNoNextSnapshotTime = true;
00338     return;
00339   }
00340   logt("next snapshot time computed");
00341   log_time(snaptime);
00342 
00343   QDateTime atTime;
00344   atTime.setTime_t(snaptime);
00345   atTime = atTime.toUTC();
00346 #if __DO_LOGGING__
00347   int diffTime = snaptime - now;
00348   logg("snapshot %d secs from now", diffTime);
00349   qxDebug() << "snapshot time at" << atTime << " UTC";
00350 #endif
00351   iSnapshotTimerAo.start(atTime);
00352 }
00353 
00354 static int SecsToMsecs(int secs)
00355 {
00356   long long ms64 = (long long)(secs) * 1000LL;
00357   if (ms64 > 0x7fffffffLL) ms64 = 0x7fffffffLL;
00358   return (int)ms64;
00359 }
00360 
00361 void CUploader::SetPostTimer()
00362 {
00363   assert(iNumPostFailures > 0);
00364 
00365   if (iPostTimerAo.isActive())
00366     iPostTimerAo.stop();
00367 
00368   // Roughly num_failures * 5 mins.
00369   int secs = 5 * 60 * iNumPostFailures + (rand() % 60);
00370   int interval = SecsToMsecs(secs);
00371   dblogg("retrying upload in %d secs / %d msecs", secs, interval);
00372 
00373   iPostTimerAo.start(interval);
00374 }
00375 
00376 // Make sure this method does not leave.
00377 void CUploader::handlePosterTimerEvent()
00378 {
00379   logt("posting timer event");
00380   StateChanged();
00381 }
00382 
00383 // Make sure this method does not leave.
00384 void CUploader::handleSnapshotTimerEvent()
00385 {
00386   logt("snapshot timer event");
00387   iSnapshotTimePassed = true;
00388   StateChanged();
00389 }
00390 
00391 bool CUploader::PosterAoIsActive()
00392 {
00393   return iPostSession && 
00394     iPostSession->iNetworkReply && 
00395     iPostSession->iNetworkReply->isRunning();
00396 }
00397 
00398 void CUploader::postingSslErrors(const QList<QSslError> & errors)
00399 {
00400 #if 1
00401   foreach (const QSslError& err, errors) {
00402     const QSslCertificate& cert = err.certificate();
00403     qxDebug() << err.errorString() << (int)err.error() << cert.issuerInfo(QSslCertificate::Organization);
00404   }
00405 #endif
00406   // We do want security, and hence do not make any exceptions here. A
00407   // self-signed CA is only okay if we have a locally registered copy.
00408   // For now we only do a bug workaround here. Essentially, we want
00409   // all CA certificates to be accepted as such, and accept no errors
00410   // regarding any of them. Even this workaround only works if the
00411   // server can give us the CA cert, as only then will the comparison
00412   // succeed.
00413 #if !defined(__SYMBIAN32__) && (QT_VERSION <= 0x040701)
00414   {
00415     QList<QSslCertificate> caList = iSslConfiguration.caCertificates();
00416     int trueErrors = 0;
00417     //qxDebug() << "ca" << caList.last();
00418     foreach (const QSslError& err, errors) {
00419       const QSslCertificate& cert = err.certificate();
00420       //qxDebug() << "cert" << cert;
00421       //qxDebug() << "equal" << (caList.last() == cert);
00422       if (!caList.contains(cert)) {
00423   trueErrors++;
00424       } else {
00425   qxDebug() << "cert is a CA cert, ignoring errors regarding it:" << 
00426     cert;
00427       }
00428     }
00429     if (!trueErrors) {
00430       logt("ignoring all SSL errors");
00431       iPostSession->iNetworkReply->ignoreSslErrors();
00432     }
00433   }
00434 #endif /* __SYMBIAN32__ */
00435 }
00436 
00437 void CUploader::postingFinished()
00438 {
00439   QNetworkReply::NetworkError errCode = iPostSession->iNetworkReply->error();
00440   dblogg("poster finished with %d", errCode);
00441 
00442   // Cannot delete while still open.
00443   iFileToPost->close();
00444 
00445   iPostSession->iFileToPost = NULL;
00446   iPostSession->deleteLater();
00447   iPostSession = NULL;
00448 
00449   switch (errCode)
00450     {
00451       //// success
00452     case QNetworkReply::NoError:
00453       {
00454   GError* localError = NULL;
00455   QByteArray ba = (iFileToPost->fileName().toLocal8Bit());
00456   const char* pathname = ba.data();
00457   if (!rm_file(pathname, &localError)) {
00458     FatalError(GException(localError));
00459   } else {
00460     log_db_log_status(GetLogDb(), NULL, "posted log file '%s'", pathname);
00461     iNumPostFailures = 0;
00462     DELETE_Z(iFileToPost);
00463 
00464     {
00465       time_t t = TimeNow();
00466       ac_global_Registry->last_upload_time = t;
00467     }
00468 
00469     StateChanged();
00470   }
00471         break;
00472       }
00473       //// aborted (do we ever get these signals)
00474     case QNetworkReply::OperationCanceledError:
00475       {
00476   logt("upload operation cancelled event");
00477   break;
00478       }
00479       //// transient failure
00480     case QNetworkReply::ConnectionRefusedError:
00481     case QNetworkReply::RemoteHostClosedError:
00482     case QNetworkReply::HostNotFoundError:
00483     case QNetworkReply::TimeoutError:
00484     case QNetworkReply::SslHandshakeFailedError:
00485     case QNetworkReply::TemporaryNetworkFailureError:
00486     case QNetworkReply::ProxyConnectionRefusedError:
00487     case QNetworkReply::ProxyConnectionClosedError:
00488     case QNetworkReply::ProxyNotFoundError:
00489     case QNetworkReply::ProxyTimeoutError:
00490     case QNetworkReply::ProxyAuthenticationRequiredError:
00491     case QNetworkReply::ContentAccessDenied:
00492     case QNetworkReply::ContentOperationNotPermittedError:
00493     case QNetworkReply::ContentNotFoundError:
00494     case QNetworkReply::ContentReSendError:
00495     case QNetworkReply::ProtocolUnknownError:
00496     case QNetworkReply::ProtocolInvalidOperationError:
00497     case QNetworkReply::UnknownNetworkError:
00498     case QNetworkReply::UnknownProxyError:
00499     case QNetworkReply::UnknownContentError:
00500     case QNetworkReply::ProtocolFailure:
00501       {
00502   // Retry later.
00503   logg("upload failure %d, retrying later", errCode);
00504   iNumPostFailures++;
00505   SetPostTimer();
00506         break;
00507       }
00508       //// permanent failure
00509     case QNetworkReply::AuthenticationRequiredError:
00510       {
00511         // We must be doing something wrong. Better stop altogether,
00512         // barring external intervention.
00513   er_log_none(0, "inactivating uploader due to a permanent posting failure (%d)", errCode);
00514   Inactivate();
00515         break;
00516       }
00517       //// unknown failure
00518     default:
00519       {
00520   logg("unknown upload failure %d, retrying later", errCode);
00521   iNumPostFailures++;
00522   SetPostTimer();
00523         break;
00524       }
00525     }
00526 }
00527 
00528 PostSession::PostSession() : 
00529   iNetworkReply(NULL), iFileToPost(NULL), 
00530   iPrologue(NULL), iEpilogue(NULL), 
00531   iPostData(NULL)
00532 {
00533 }  
00534 
00535 PostSession::~PostSession()
00536 {
00537   //logh();
00538   if (iNetworkReply) {
00539     iNetworkReply->abort();
00540     DELETE_Z(iNetworkReply);
00541   }
00542   DELETE_Z(iPostData);
00543   iPostElems.clear();
00544   if (iFileToPost) {
00545     iFileToPost->close();
00546   }
00547   DELETE_Z(iPrologue);
00548   DELETE_Z(iEpilogue);
00549 }
00550 
00551 void CUploader::DestroyPosterAo()
00552 {
00553   DELETE_Z(iPostSession);
00554 }
00555 
00556 void CUploader::CreatePosterAoL()
00557 {
00558   assert(!iPostSession);
00559   assert(iFileToPost);
00560 
00561   QByteArray ba = (iFileToPost->fileName().toLocal8Bit());
00562   const char* pathname = ba.data();
00563   dblogg("asking poster to post '%s'", pathname);
00564 
00565   iPostSession = q_check_ptr(new PostSession());
00566 
00567   iPostSession->iFileToPost = iFileToPost;
00568 
00569   iPostSession->iPrologue = q_check_ptr(new QBuffer());
00570   iPostSession->iEpilogue = q_check_ptr(new QBuffer());
00571 
00572   const gchar* username = get_config_username();
00573   logg("uploader using username '%s'", username);
00574 
00575   static const char* KSep = "--";
00576   static const char* KCrLf = "\r\n";
00577 
00578   QByteArray& prologue = iPostSession->iPrologue->buffer();
00579   prologue.append(KSep);
00580   prologue.append(KBoundary);
00581   prologue.append(KCrLf);
00582   prologue.append("Content-Disposition: form-data; name=\"logdata\"; filename=\"");
00583   prologue.append(username);
00584   prologue.append(".db\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n\r\n");
00585 
00586   QByteArray& epilogue = iPostSession->iEpilogue->buffer();
00587   epilogue.append(KCrLf);
00588   epilogue.append(KSep);
00589   epilogue.append(KBoundary);
00590   epilogue.append(KCrLf);
00591   epilogue.append("Content-Disposition: form-data; name=\"logdata_submit\"\r\n\r\nUpload\r\n");
00592   epilogue.append(KSep);
00593   epilogue.append(KBoundary);
00594   epilogue.append(KSep);
00595   epilogue.append(KCrLf);
00596 
00597   if (!iFileToPost->open(QIODevice::ReadOnly)) {
00598     int errCode = (iFileToPost->error());
00599     gx_throw(gx_error_new(domain_qt, errCode, 
00600         "failed to open file '%s': QFile::FileError %d", 
00601         pathname, errCode));
00602   }
00603 
00604 #define CHECKBUFOPEN(x) throw_cstr_unless(x, "QBuffer open failed")
00605   CHECKBUFOPEN(iPostSession->iPrologue->open(QIODevice::ReadOnly));
00606   CHECKBUFOPEN(iPostSession->iEpilogue->open(QIODevice::ReadOnly));
00607 
00608   iPostSession->iPostElems.append(iPostSession->iPrologue);
00609   iPostSession->iPostElems.append(iPostSession->iFileToPost);
00610   iPostSession->iPostElems.append(iPostSession->iEpilogue);
00611 
00612   iPostSession->iPostData = q_check_ptr(new QIODeviceSeq(iPostSession->iPostElems));
00613 
00614   // Note that the file object (or the file) may not be deleted until
00615   // we get the finished() signal for this reply.
00616   iPostSession->iNetworkReply = 
00617     iNetworkAccessManager.post(iNetworkRequest, iPostSession->iPostData);
00618 
00619   connect(iPostSession->iNetworkReply, SIGNAL(sslErrors(const QList<QSslError> &)),
00620     this, SLOT(postingSslErrors(const QList<QSslError> &)));
00621   connect(iPostSession->iNetworkReply, SIGNAL(finished()),
00622     this, SLOT(postingFinished()));
00623 }
00624 
00625 void CUploader::PostNowL()
00626 {
00627   CreatePosterAoL();
00628 }
00629 
00630 void CUploader::TakeSnapshotNowL()
00631 {
00632   dblogt("taking snapshot now");
00633 
00634   // LOG_UPLOADS_DIR and LOGDB_DIR must be on the same device to allow
00635   // for renaming rather than copying.
00636   char* pathname = tempnam(LOG_UPLOADS_DIR, "log_"); // caller must free 'pathname'
00637   if (!pathname) {
00638     er_log_errno(er_FATAL, "failure in tempnam");
00639   }
00640   
00641   gboolean wasRenamed = FALSE;
00642   GError* snapError = NULL;
00643   if (!log_db_take_snapshot(GetLogDb(), pathname, &wasRenamed, &snapError)) {
00644     logg("failure taking snapshot to file '%s'", pathname);
00645     free(pathname);
00646     logg("snapshot file was%s created", wasRenamed ? "" : " not");
00647     er_log_gerror(er_FATAL|er_FREE, snapError, "taking snapshot");
00648   }
00649 
00650   log_db_log_status(GetLogDb(), NULL, "snapshot taken as '%s'", pathname);
00651 
00652   assert(!iFileToPost);
00653   iFileToPost = q_check_ptr(new QFile(QString::fromUtf8(pathname)));
00654   iSnapshotTimePassed = false;
00655   StateChangedL();
00656 }
00657 
00658 // Better by careful not to run out of stack calling this recursively.
00659 // Can always use an "ImmediateAo" if necessary to avoid such a risk.
00660 void CUploader::StateChangedL()
00661 {
00662   if (iNoConfig)
00663     return;
00664 
00665   if (!iSnapshotTimePassed &&
00666       !iNoNextSnapshotTime &&
00667       !iSnapshotTimerAo.isActive()) {
00668     SetSnapshotTimerL();
00669   }
00670 
00671   if (!PosterAoIsActive())
00672     DestroyPosterAo(); // make sure no connection remains
00673 
00674  again:
00675   if (iFileToPost) {
00676     if (PosterAoIsActive() || iPostTimerAo.isActive())
00677       return;
00678     if (i_uploads_allowed) {
00679       PostNowL(); // not called elsewhere
00680     }
00681   } else if (!iNoOldFiles) {
00682     NextOldFileL();
00683     goto again;
00684   } else if (iSnapshotTimePassed) {
00685     TakeSnapshotNowL(); // not called elsewhere
00686   }
00687 }
00688 
00689 // --------------------------------------------------
00690 // global system state
00691 // --------------------------------------------------
00692 
00693 EXTERN_C gboolean up_global_init(GError** error)
00694 {
00695   // Nothing to do.
00696   return TRUE;
00697 }
00698 
00699 EXTERN_C void up_global_cleanup()
00700 {
00701   // Nothing to do.
00702 }
00703 
00704 // --------------------------------------------------
00705 // API
00706 // --------------------------------------------------
00707 
00708 EXTERN_C gboolean up_Uploader_upload_now(up_Uploader* object, GError** error)
00709 {
00710   ((CUploader*)object)->RequestSnapshot();
00711   return TRUE;
00712 }
00713 
00714 EXTERN_C gboolean up_Uploader_reconfigure(up_Uploader* object,
00715             const gchar* key,
00716             const gchar* value, 
00717             GError** error)
00718 {
00719   if (strcmp(key, "iap") == 0) {
00720     ((CUploader*)object)->RefreshIap(true);
00721   } else if (strcmp(key, "uploader.time_expr") == 0) {
00722     ((CUploader*)object)->RefreshSnapshotTimeExpr(true);
00723   }
00724   return TRUE;
00725 }
00726 
00727 EXTERN_C up_Uploader* up_Uploader_new(ac_AppContext* aAppContext, GError** error)
00728 {
00729   CUploader* object = NULL;
00730   try {
00731     object = q_check_ptr(new CUploader(aAppContext));
00732   } catch (const std::exception &ex) {
00733     if (error)
00734       *error = gx_error_new(domain_qt, -1, "Uploader init failure: %s", ex.what());
00735     return NULL;
00736   }
00737   return (up_Uploader*)object;
00738 }
00739 
00740 EXTERN_C void up_Uploader_destroy(up_Uploader* object)
00741 {
00742   delete ((CUploader*)object);
00743 }
00744 
00745 /**
00746 
00747 Copyright 2009 Helsinki Institute for Information Technology (HIIT)
00748 and the authors. All rights reserved.
00749 
00750 Authors: Tero Hasu <tero.hasu@hut.fi>
00751 
00752 Permission is hereby granted, free of charge, to any person
00753 obtaining a copy of this software and associated documentation files
00754 (the "Software"), to deal in the Software without restriction,
00755 including without limitation the rights to use, copy, modify, merge,
00756 publish, distribute, sublicense, and/or sell copies of the Software,
00757 and to permit persons to whom the Software is furnished to do so,
00758 subject to the following conditions:
00759 
00760 The above copyright notice and this permission notice shall be
00761 included in all copies or substantial portions of the Software.
00762 
00763 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00764 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00765 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00766 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
00767 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00768 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00769 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00770 SOFTWARE.
00771 
00772  **/

ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:57 2011 by Doxygen 1.6.1