diff --git a/ChangeLog b/ChangeLog index ebd6b68e..dd1d560e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16521,3 +16521,34 @@ * Updated 'INSTALL'. * Updated 'NEWS'. * Incremented the package version to 2.18.1. +2017-12-27 Fred Gleason + * Added a 'LOGS.LOCK_USER_NAME' field to the database. + * Added a 'LOGS.LOCK_STATION_NAME' field to the database. + * Added a 'LOGS.LOCK_IPV4_ADDRESS' field to the database. + * Added a 'LOGS.LOCK_DATETIME' field to the database. + * Incremented the database version to 273. + * Added log locking logic to rdlogedit(1). +2017-12-27 Fred Gleason + * Added log locking logic to the voice tracker in rdlogedit(1). +2017-12-27 Fred Gleason + * Added log locking logic to rdclilogedit(1). +2017-12-27 Fred Gleason + * Modified the behavior of the 'new' command in rdclilogedit(1) to + match that of rdlogedit(1). +2017-12-27 Fred Gleason + * Added a 'LOGS.LOCK_GUID' field to the database. + * Incremented the database version to 274. + * Added a 'LockLog' call to the Web API. +2017-12-27 Fred Gleason + * Cleaned up 'log in use" messages in rdlogedit(1) and + rdclilogedit(1). +2017-12-27 Fred Gleason + * Added log locking logic to the 'SaveLog' Web API call. +2017-12-27 Fred Gleason + * Added log locking logic to rdlogmanager(1). +2017-12-27 Fred Gleason + * Added a lock check for before deleting logs in rdlogedit(1). +2017-12-27 Fred Gleason + * Added a lock check for before deleting logs in rdclilogedit(1). +2017-12-27 Fred Gleason + * Added log locking logic to rdairplay(1). diff --git a/docs/apis/web_api.xml b/docs/apis/web_api.xml index 9008cdb2..a3fd266f 100644 --- a/docs/apis/web_api.xml +++ b/docs/apis/web_api.xml @@ -2669,6 +2669,63 @@ + + LockLog + Set / Update / Clear a log lock + + Command Code: RDXPORT_COMMAND_LOCKLOG + + + Required User Permissions: none + + + LockLog Call Fields + + + + + + + FIELD NAME + MEANING + REMARKS + + + + + COMMAND + 34 + Mandatory + + + OPERATION + Operation to Perform + + + Mandatory. Possible values: + + + CREATE + UPDATE + CLEAR + + + + + LOG_NAME + Name of log + Mandatory + + + LOCK_GUID + Opaque GUID string, returned by the CREATE operation. + Mandatory. For CREATE, send an empty string. + + + +
+
+ Rehash Generate a SHA-1 hash for a cut and write it to the database @@ -2923,6 +2980,18 @@ Mandatory. String, 10 characters max. + + + LOCK_GUID + + + The GUID string, obtained from the LockLog API call. + + + Optional. If not provided, the service will attempt to acquire + a lock before processing the save. + + DESCRIPTION diff --git a/docs/tables/logs.txt b/docs/tables/logs.txt index a4ec85d3..a83951f2 100644 --- a/docs/tables/logs.txt +++ b/docs/tables/logs.txt @@ -6,7 +6,7 @@ table: FIELD NAME TYPE REMARKS ------------------------------------------------------------------- -NAME char(64) Table name, ends with '_LOG' +NAME char(64) LOG_EXISTS enum('N','Y') TYPE int(11) 0=Log, 1=Event, 2=Clock, 3=Grid SERVICE char(10) From SERVICES.NAME @@ -26,3 +26,9 @@ MUSIC_LINKS int MUSIC_LINKED enum('N','Y') TRAFFIC_LINKS int TRAFFIC_LINKED enum('N','Y') +NEXT_ID int(11) +LOCK_USER_NAME char(255) From USER.LOGIN_NAME +LOCK_STATION_NAME char(64) From STATIONS.NAME +LOCK_IPV4_ADDRESS char(16) +LOCK_DATETIME datetime +LOCK_GUID char(82) diff --git a/lib/Makefile.am b/lib/Makefile.am index 669fda28..0c999bf7 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -166,10 +166,11 @@ dist_librd_la_SOURCES = dbversion.h\ rdlivewiredestination.cpp rdlivewiredestination.h\ rdlivewiresource.cpp rdlivewiresource.h\ rdlog.cpp rdlog.h\ - rdlogfilter.cpp rdlogfilter.h\ - rdlogedit_conf.cpp rdlogedit_conf.h\ rdlog_event.cpp rdlog_event.h\ rdlog_line.cpp rdlog_line.h\ + rdlogedit_conf.cpp rdlogedit_conf.h\ + rdlogfilter.cpp rdlogfilter.h\ + rdloglock.cpp rdloglock.h\ rdmacro.cpp rdmacro.h\ rdmacro_event.cpp rdmacro_event.h\ rdmarker_bar.cpp rdmarker_bar.h\ @@ -302,6 +303,7 @@ nodist_librd_la_SOURCES = moc_rdadd_cart.cpp\ moc_rdlistview.cpp\ moc_rdlivewire.cpp\ moc_rdlogfilter.cpp\ + moc_rdloglock.cpp\ moc_rdmacro_event.cpp\ moc_rdmarker_bar.cpp\ moc_rdmarker_edit.cpp\ diff --git a/lib/dbversion.h b/lib/dbversion.h index d9652274..111c8deb 100644 --- a/lib/dbversion.h +++ b/lib/dbversion.h @@ -24,7 +24,7 @@ /* * Current Database Version */ -#define RD_VERSION_DATABASE 272 +#define RD_VERSION_DATABASE 274 #endif // DBVERSION_H diff --git a/lib/lib.pro b/lib/lib.pro index 46497f34..744cd316 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -89,6 +89,7 @@ SOURCES += rdlog_event.cpp SOURCES += rdlog_line.cpp SOURCES += rdlogedit_conf.cpp SOURCES += rdlogfilter.cpp +SOURCES += rdloglock.cpp SOURCES += rdmacro.cpp SOURCES += rdmacro_event.cpp SOURCES += rdoneshot.cpp @@ -230,6 +231,7 @@ HEADERS += rdlog_event.h HEADERS += rdlog_line.h HEADERS += rdlogedit_conf.h HEADERS += rdlogfilter.h +HEADERS += rdloglock.h HEADERS += rdmacro.h HEADERS += rdmacro_event.h HEADERS += rdoneshot.h diff --git a/lib/librd_cs.ts b/lib/librd_cs.ts index 9cacf4e6..8eae3c4f 100644 --- a/lib/librd_cs.ts +++ b/lib/librd_cs.ts @@ -2438,5 +2438,13 @@ Zkuste to, prosím, znovu! Chyba plnění události + + Log in use by + + + + Import failed + + diff --git a/lib/librd_de.ts b/lib/librd_de.ts index 44e28f4e..24608ed4 100644 --- a/lib/librd_de.ts +++ b/lib/librd_de.ts @@ -2433,5 +2433,13 @@ bitte erneut versuchen! Event-Füllfehler + + Log in use by + + + + Import failed + + diff --git a/lib/librd_es.ts b/lib/librd_es.ts index 5136c045..ed782c76 100644 --- a/lib/librd_es.ts +++ b/lib/librd_es.ts @@ -2425,5 +2425,13 @@ please try again! Errores al llenar eventos + + Log in use by + + + + Import failed + + diff --git a/lib/librd_fr.ts b/lib/librd_fr.ts index 6d424b2b..0c87c518 100644 --- a/lib/librd_fr.ts +++ b/lib/librd_fr.ts @@ -2019,5 +2019,13 @@ please try again! + + Log in use by + + + + Import failed + + diff --git a/lib/librd_nb.ts b/lib/librd_nb.ts index 41ab2692..deb236ec 100644 --- a/lib/librd_nb.ts +++ b/lib/librd_nb.ts @@ -2370,5 +2370,13 @@ prøv ein gong til! + + Log in use by + + + + Import failed + + diff --git a/lib/librd_nn.ts b/lib/librd_nn.ts index 41ab2692..deb236ec 100644 --- a/lib/librd_nn.ts +++ b/lib/librd_nn.ts @@ -2370,5 +2370,13 @@ prøv ein gong til! + + Log in use by + + + + Import failed + + diff --git a/lib/librd_pt_BR.ts b/lib/librd_pt_BR.ts index d6974c59..268518cd 100644 --- a/lib/librd_pt_BR.ts +++ b/lib/librd_pt_BR.ts @@ -2384,5 +2384,13 @@ por favor, tente novamente! Erros de Auto Preenchimento + + Log in use by + + + + Import failed + + diff --git a/lib/rd.h b/lib/rd.h index 417296c4..5adf8c1d 100644 --- a/lib/rd.h +++ b/lib/rd.h @@ -567,4 +567,10 @@ */ #define RD_LOGFILTER_LIMIT_QUAN 14 +/* + * Log Locking Timeout + */ +#define RD_LOG_LOCK_TIMEOUT 30000 + + #endif // RD_H diff --git a/lib/rdloglock.cpp b/lib/rdloglock.cpp new file mode 100644 index 00000000..65b1c972 --- /dev/null +++ b/lib/rdloglock.cpp @@ -0,0 +1,201 @@ +// rdloglock.cpp +// +// Log locking routines for Rivendell +// +// (C) Copyright 2017 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include +#endif // WIN32 + +#include + +#include "rddb.h" +#include "rdescape_string.h" +#include "rdloglock.h" + +RDLogLock::RDLogLock(const QString &log_name,RDUser *user,RDStation *station, + QObject *parent) + : QObject(parent) +{ + lock_log_name=log_name; + lock_user=user; + lock_station=station; + lock_locked=false; + + lock_timer=new QTimer(this); + connect(lock_timer,SIGNAL(timeout()),this,SLOT(updateLock())); +} + + +RDLogLock::~RDLogLock() +{ + if(lock_locked) { + clearLock(); + } + delete lock_timer; +} + + +bool RDLogLock::isLocked() const +{ + return lock_locked; +} + + +bool RDLogLock::tryLock(QString *username,QString *stationname, + QHostAddress *addr) +{ + bool ret=false; + QString guid=RDLogLock::makeGuid(lock_station->name()); + + *username=lock_user->name(); + *stationname=lock_station->name(); + addr->setAddress(lock_station->address().toString()); + + if(RDLogLock::tryLock(username,stationname,addr,lock_log_name,guid)) { + lock_timer->start(RD_LOG_LOCK_TIMEOUT/2); + lock_guid=guid; + lock_locked=true; + ret=true; + } + + return ret; +} + + +void RDLogLock::clearLock() +{ + RDLogLock::clearLock(lock_guid); + lock_guid=QString(); + lock_timer->stop(); + lock_locked=false; +} + + +void RDLogLock::updateLock() +{ + RDLogLock::updateLock(lock_log_name,lock_guid); +} + + +bool RDLogLock::tryLock(QString *username,QString *stationname, + QHostAddress *addr,const QString &log_name, + const QString &guid) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + bool ret=false; + QDateTime now=QDateTime::currentDateTime(); + + sql=QString("update LOGS set ")+ + "LOCK_USER_NAME=\""+RDEscapeString(*username)+"\","+ + "LOCK_STATION_NAME=\""+RDEscapeString(*stationname)+"\","+ + "LOCK_IPV4_ADDRESS=\""+RDEscapeString(addr->toString())+ + "\","+ + "LOCK_GUID=\""+RDEscapeString(guid)+"\","+ + "LOCK_DATETIME=now() where "+ + "(NAME=\""+RDEscapeString(log_name)+"\")&&"+ + "((LOCK_DATETIME is null)||"+ + "(LOCK_DATETIME<\""+RDEscapeString(now.addSecs(-RD_LOG_LOCK_TIMEOUT/1000).toString("yyyy-MM-dd hh:mm:ss"))+"\"))"; + q=new RDSqlQuery(sql); + if(q->numRowsAffected()>0) { + ret=true; + } + else { + sql=QString("select ")+ + "LOCK_USER_NAME,"+ + "LOCK_STATION_NAME,"+ + "LOCK_IPV4_ADDRESS "+ + "from LOGS where "+ + "NAME=\""+RDEscapeString(log_name)+"\""; + q1=new RDSqlQuery(sql); + if(q1->first()) { + *username=q1->value(0).toString(); + *stationname=q1->value(1).toString(); + addr->setAddress(q1->value(2).toString()); + } + delete q1; + } + delete q; + + return ret; +} + + +void RDLogLock::updateLock(const QString &log_name,const QString &guid) +{ + QString sql; + RDSqlQuery *q; + + sql=QString("update LOGS set ")+ + "LOCK_DATETIME=now() where "+ + "LOCK_GUID=\""+RDEscapeString(guid)+"\""; + q=new RDSqlQuery(sql); +#ifndef WIN32 + if(q->numRowsAffected()==0) { + syslog(LOG_WARNING,"lock on log \"%s\" has evaporated!", + (const char *)log_name); + } +#endif // WIN32 + delete q; +} + + +void RDLogLock::clearLock(const QString &guid) +{ + QString sql; + RDSqlQuery *q; + + sql=QString("update LOGS set ")+ + "LOCK_USER_NAME=null,"+ + "LOCK_STATION_NAME=null,"+ + "LOCK_IPV4_ADDRESS=null,"+ + "LOCK_GUID=null,"+ + "LOCK_DATETIME=null where "+ + "LOCK_GUID=\""+RDEscapeString(guid)+"\""; + q=new RDSqlQuery(sql); + delete q; +} + + +bool RDLogLock::validateLock(const QString &log_name,const QString &guid) +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + QDateTime now=QDateTime::currentDateTime(); + + sql=QString("select NAME from LOGS where ")+ + "(NAME=\""+RDEscapeString(log_name)+"\")&&"+ + "(LOCK_GUID=\""+RDEscapeString(guid)+"\")&&"+ + "(LOCK_DATETIME>\""+RDEscapeString(now.addSecs(-RD_LOG_LOCK_TIMEOUT/1000). + toString("yyyy-MM-dd hh:mm:ss"))+"\")"; + q=new RDSqlQuery(sql); + ret=q->first(); + delete q; + + return ret; +} + + +QString RDLogLock::makeGuid(const QString &stationname) +{ + return stationname+QDateTime::currentDateTime(). + toString("yyyyMMddhhmmsszzz"); +} diff --git a/lib/rdloglock.h b/lib/rdloglock.h new file mode 100644 index 00000000..4b36d6b6 --- /dev/null +++ b/lib/rdloglock.h @@ -0,0 +1,62 @@ +// rdloglock.h +// +// Log locking routines for Rivendell +// +// (C) Copyright 2017 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLOGLOCK_H +#define RDLOGLOCK_H + +#include +#include +#include + +#include +#include +#include + +class RDLogLock : public QObject +{ + Q_OBJECT; + public: + RDLogLock(const QString &log_name,RDUser *user,RDStation *station, + QObject *parent=0); + ~RDLogLock(); + bool isLocked() const; + bool tryLock(QString *username,QString *stationname,QHostAddress *addr); + void clearLock(); + static bool tryLock(QString *username,QString *stationname,QHostAddress *addr, + const QString &log_name,const QString &guid); + static void updateLock(const QString &log_name,const QString &guid); + static void clearLock(const QString &guid); + static bool validateLock(const QString &log_name,const QString &guid); + static QString makeGuid(const QString &stationname); + + private slots: + void updateLock(); + + private: + QString lock_log_name; + RDUser *lock_user; + RDStation *lock_station; + QTimer *lock_timer; + bool lock_locked; + QString lock_guid; +}; + + +#endif // RDLOGLOCK_H diff --git a/lib/rdsvc.cpp b/lib/rdsvc.cpp index 77f8d071..48bd486c 100644 --- a/lib/rdsvc.cpp +++ b/lib/rdsvc.cpp @@ -20,16 +20,15 @@ #include -#include -#include -#include -#include -#include #include -#include - +#include +#include +#include #include +#include #include +#include +#include #include // @@ -710,13 +709,15 @@ bool RDSvc::import(ImportSource src,const QDate &date,const QString &break_str, bool RDSvc::generateLog(const QDate &date,const QString &logname, - const QString &nextname,QString *report,RDUser *user) + const QString &nextname,QString *report,RDUser *user, + QString *err_msg) { QString sql; RDSqlQuery *q; RDClock clock; - QString err_msg; + // QString err_msg; RDLog *log=NULL; + RDLogLock *log_lock=NULL; if((!date.isValid()||logname.isEmpty())) { return false; @@ -728,9 +729,20 @@ bool RDSvc::generateLog(const QDate &date,const QString &logname, // Generate Log Structure // if(RDLog::exists(logname)) { + log_lock=new RDLogLock(logname,user,svc_station,this); + if(!TryLock(log_lock,err_msg)) { + delete log_lock; + return false; + } RDLog::remove(logname,svc_station,user,svc_config); + delete log_lock; + } + RDLog::create(logname,svc_name,"RDLogManager",err_msg,svc_config); + log_lock=new RDLogLock(logname,user,svc_station,this); + if(!TryLock(log_lock,err_msg)) { + delete log_lock; + return false; } - RDLog::create(logname,svc_name,"RDLogManager",&err_msg,svc_config); log=new RDLog(logname); log->setDescription(RDDateDecode(descriptionTemplate(),date,svc_station, svc_config,svc_name)); @@ -792,18 +804,26 @@ bool RDSvc::generateLog(const QDate &date,const QString &logname, log->setNextId(count); log->setAutoRefresh(autoRefresh()); delete log; + delete log_lock; return true; } bool RDSvc::linkLog(RDSvc::ImportSource src,const QDate &date, - const QString &logname,QString *report) + const QString &logname,QString *report,RDUser *user, + QString *err_msg) { QString sql; RDSqlQuery *q; QString autofill_errors; + RDLogLock *log_lock=new RDLogLock(logname,user,svc_station,this); + if(!TryLock(log_lock,err_msg)) { + delete log_lock; + return false; + } + emit generationProgress(0); // @@ -822,6 +842,8 @@ bool RDSvc::linkLog(RDSvc::ImportSource src,const QDate &date, import_name.replace(" ","_"); if(!import(src,date,breakString(),trackString(src),import_name)) { + *err_msg=tr("Import failed"); + delete log_lock; return false; } @@ -943,13 +965,20 @@ bool RDSvc::linkLog(RDSvc::ImportSource src,const QDate &date, sql=QString().sprintf("drop table `%s`",(const char *)import_name); q=new RDSqlQuery(sql); delete q; + delete log_lock; return true; } -void RDSvc::clearLogLinks(RDSvc::ImportSource src,const QString &logname) +bool RDSvc::clearLogLinks(RDSvc::ImportSource src,const QString &logname, + RDUser *user,QString *err_msg) { + RDLogLock *log_lock=new RDLogLock(logname,user,svc_station,this); + if(!TryLock(log_lock,err_msg)) { + delete log_lock; + return false; + } std::vector cleared_ids; RDLogLine::Type event_type=RDLogLine::UnknownType; RDLogLine::Source event_source=RDLogLine::Manual; @@ -1012,7 +1041,9 @@ void RDSvc::clearLogLinks(RDSvc::ImportSource src,const QString &logname) log->setLinkState(RDLog::SourceMusic,false); } delete log; - + delete log_lock; + *err_msg="OK"; + return true; } @@ -1447,6 +1478,23 @@ QString RDSvc::timeString(int hour,int secs) } +bool RDSvc::TryLock(RDLogLock *lock,QString *err_msg) +{ + QString username; + QString stationname; + QHostAddress addr; + + if(!lock->tryLock(&username,&stationname,&addr)) { + *err_msg=tr("Log in use by")+" "+username+"@"+stationname; + if(stationname!=addr.toString()) { + *err_msg+=" ["+addr.toString()+"]"; + } + return false; + } + return true; +} + + QString RDSvc::SourceString(ImportSource src) const { QString fieldname; diff --git a/lib/rdsvc.h b/lib/rdsvc.h index 91e72f50..1e036030 100644 --- a/lib/rdsvc.h +++ b/lib/rdsvc.h @@ -27,6 +27,7 @@ #include #include "rdconfig.h" +#include "rdloglock.h" #include "rdstation.h" #include "rduser.h" @@ -86,10 +87,13 @@ class RDSvc : public QObject const QString &track_str,const QString &dest_table) const; bool generateLog(const QDate &date,const QString &logname, - const QString &nextname,QString *report,RDUser *user); + const QString &nextname,QString *report,RDUser *user, + QString *err_msg); bool linkLog(RDSvc::ImportSource src,const QDate &date, - const QString &logname,QString *report); - void clearLogLinks(RDSvc::ImportSource src,const QString &logname); + const QString &logname,QString *report,RDUser *user, + QString *err_msg); + bool clearLogLinks(RDSvc::ImportSource src,const QString &logname, + RDUser *user,QString *err_msg); void create(const QString exemplar) const; void remove() const; QString xml() const; @@ -104,6 +108,7 @@ class RDSvc : public QObject void generationProgress(int step); private: + bool TryLock(RDLogLock *lock,QString *err_msg); QString SourceString(ImportSource src) const; QString OsString(ImportOs os) const; QString FieldString(ImportField field) const; diff --git a/lib/rdxport_interface.h b/lib/rdxport_interface.h index 199e28f2..016034af 100644 --- a/lib/rdxport_interface.h +++ b/lib/rdxport_interface.h @@ -54,6 +54,7 @@ #define RDXPORT_COMMAND_CREATETICKET 31 #define RDXPORT_COMMAND_REHASH 32 #define RDXPORT_COMMAND_LISTSYSTEMSETTINGS 33 +#define RDXPORT_COMMAND_LOCKLOG 34 #endif // RDXPORT_INTERFACE_H diff --git a/rdadmin/createdb.cpp b/rdadmin/createdb.cpp index f2144fd0..50514c9f 100644 --- a/rdadmin/createdb.cpp +++ b/rdadmin/createdb.cpp @@ -984,13 +984,19 @@ bool CreateDb(QString name,QString pwd,RDConfig *config) "TRAFFIC_LINKS int default 0,"+ "TRAFFIC_LINKED enum('N','Y') default 'N',"+ "NEXT_ID int default 0,"+ + "LOCK_USER_NAME char(255),"+ + "LOCK_STATION_NAME char(64),"+ + "LOCK_IPV4_ADDRESS char(16),"+ + "LOCK_DATETIME datetime,"+ + "LOCK_GUID char(82),"+ "index NAME_IDX (NAME,LOG_EXISTS),"+ "index SERVICE_IDX (SERVICE),"+ "index DESCRIPTION_IDX (DESCRIPTION),"+ "index ORIGIN_USER_IDX (ORIGIN_USER),"+ "index START_DATE_IDX (START_DATE),"+ "index END_DATE_IDX (END_DATE),"+ - "index TYPE_IDX(TYPE,LOG_EXISTS))"+ + "index TYPE_IDX(TYPE,LOG_EXISTS),"+ + "index LOCK_GUID_IDX(LOCK_GUID))"+ config->createTablePostfix(); if(!RunQuery(sql)) { return false; @@ -7974,6 +7980,39 @@ int UpdateDb(int ver,RDConfig *config) delete q; } + if(ver<273) { + sql=QString("alter table LOGS ")+ + "add column LOCK_USER_NAME char(255) after NEXT_ID"; + q=new RDSqlQuery(sql,false); + delete q; + + sql=QString("alter table LOGS ")+ + "add column LOCK_STATION_NAME char(64) after LOCK_USER_NAME"; + q=new RDSqlQuery(sql,false); + delete q; + + sql=QString("alter table LOGS ")+ + "add column LOCK_IPV4_ADDRESS char(16) after LOCK_STATION_NAME"; + q=new RDSqlQuery(sql,false); + delete q; + + sql=QString("alter table LOGS ")+ + "add column LOCK_DATETIME datetime after LOCK_IPV4_ADDRESS"; + q=new RDSqlQuery(sql,false); + delete q; + } + + if(ver<274) { + sql=QString("alter table LOGS ")+ + "add column LOCK_GUID char(82) after LOCK_DATETIME"; + q=new RDSqlQuery(sql,false); + delete q; + + sql=QString("alter table LOGS add index LOCK_GUID_IDX(LOCK_GUID)"); + q=new RDSqlQuery(sql,false); + delete q; + } + // // Maintainer's Note: diff --git a/rdairplay/list_log.cpp b/rdairplay/list_log.cpp index 543f4ec6..dc918e5e 100644 --- a/rdairplay/list_log.cpp +++ b/rdairplay/list_log.cpp @@ -2,7 +2,7 @@ // // The full log list for RDAirPlay // -// (C) Copyright 2002-2006,2016 Fred Gleason +// (C) Copyright 2002-2006,2016-2017 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -856,21 +856,22 @@ void ListLog::loadButtonData() QString svcname=list_log->serviceName(); QString err_msg; RDLog *edit_log; + RDLogLock *log_lock=NULL; - switch(list_logs_dialog->exec(&name,&svcname)) { - case 0: + switch((ListLogs::Operation)list_logs_dialog->exec(&name,&svcname,&log_lock)) { + case ListLogs::Load: list_log->setLogName(RDLog::tableName(name)); list_log->load(); break; - case 2: + case ListLogs::Save: list_log->save(); edit_log= new RDLog(list_log->logName().left(list_log->logName().length()-4)); delete edit_log; break; - case 3: + case ListLogs::SaveAs: if(!RDLog::create(name,svcname,rdripc->user(),&err_msg,air_config)) { QMessageBox::warning(this,"RDAirPlay - "+tr("Error"),err_msg); return; @@ -880,9 +881,15 @@ void ListLog::loadButtonData() list_log->save(); break; - case -1: + case ListLogs::Unload: list_log->clear(); break; + + case ListLogs::Cancel: + break; + } + if(log_lock!=NULL) { + delete log_lock; } } diff --git a/rdairplay/list_logs.cpp b/rdairplay/list_logs.cpp index fe95b4cc..0ab8ef1e 100644 --- a/rdairplay/list_logs.cpp +++ b/rdairplay/list_logs.cpp @@ -18,6 +18,7 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // +#include #include #include @@ -121,10 +122,11 @@ QSizePolicy ListLogs::sizePolicy() const } -int ListLogs::exec(QString *logname,QString *svcname) +int ListLogs::exec(QString *logname,QString *svcname,RDLogLock **log_lock) { list_logname=logname; list_svcname=svcname; + list_log_lock=log_lock; list_saveas_button->setEnabled(rduser->createLog()); QStringList services_list; QString sql=QString("select SERVICE_NAME from SERVICE_PERMS where ")+ @@ -149,7 +151,7 @@ void ListLogs::filterChangedData(const QString &where_sql) void ListLogs::closeEvent(QCloseEvent *e) { - done(1); + done(ListLogs::Cancel); } @@ -166,7 +168,8 @@ void ListLogs::loadButtonData() return; } *list_logname=item->text(0); - done(0); + *list_log_lock=NULL; + done(ListLogs::Load); } @@ -176,7 +179,20 @@ void ListLogs::saveButtonData() saveAsButtonData(); } else { - done(2); + *list_log_lock=new RDLogLock(*list_logname,rduser,rdstation_conf,this); + if(!TryLock(*list_log_lock)) { + delete *list_log_lock; + *list_log_lock=NULL; + return; + } + if(list_log->isRefreshable()) { + QMessageBox::warning(this,"RDAirPlay - "+tr("Error"), + tr("You must refresh the log before it can be saved.")); + delete *list_log_lock; + *list_log_lock=NULL; + return; + } + done(ListLogs::Save); } } @@ -188,7 +204,6 @@ void ListLogs::saveAsButtonData() RDAddLog *log; log=new RDAddLog(&logname,&svcname,RDLogFilter::StationFilter,rduser, rdstation_conf,tr("Rename Log"),this); - if(log->exec()<0) { delete log; return; @@ -196,19 +211,21 @@ void ListLogs::saveAsButtonData() delete log; *list_logname=logname; *list_svcname=svcname; - done(3); + done(ListLogs::SaveAs); } void ListLogs::unloadButtonData() { - done(-1); + *list_log_lock=NULL; + done(ListLogs::Unload); } void ListLogs::cancelButtonData() { - done(1); + *list_log_lock=NULL; + done(ListLogs::Cancel); } @@ -252,3 +269,22 @@ void ListLogs::RefreshList() } delete q; } + + +bool ListLogs::TryLock(RDLogLock *lock) +{ + QString username; + QString stationname; + QHostAddress addr; + + if(!lock->tryLock(&username,&stationname,&addr)) { + QString msg=tr("Log already being edited by")+" "+username+"@"+stationname; + if(stationname!=addr.toString()) { + msg+=" ["+addr.toString()+"]"; + } + msg+="."; + QMessageBox::warning(this,"RDAirPlay - "+tr("Log Locked"),msg); + return false; + } + return true; +} diff --git a/rdairplay/list_logs.h b/rdairplay/list_logs.h index 44969f45..d5bb3266 100644 --- a/rdairplay/list_logs.h +++ b/rdairplay/list_logs.h @@ -27,6 +27,7 @@ #include #include +#include #include @@ -35,12 +36,13 @@ class ListLogs : public QDialog Q_OBJECT public: + enum Operation {Load=0,Cancel=1,Save=2,SaveAs=3,Unload=4}; ListLogs(LogPlay *log,QWidget *parent=0); QSize sizeHint() const; QSizePolicy sizePolicy() const; public slots: - int exec(QString *logname,QString *svcname); + int exec(QString *logname,QString *svcname,RDLogLock **loglock); private slots: void filterChangedData(const QString &where_sql); @@ -57,6 +59,7 @@ class ListLogs : public QDialog private: void RefreshList(); + bool TryLock(RDLogLock *lock); RDLogFilter *list_filter_widget; QListView *list_log_list; QString *list_logname; @@ -67,6 +70,7 @@ class ListLogs : public QDialog QPushButton *list_saveas_button; QPushButton *list_cancel_button; LogPlay *list_log; + RDLogLock **list_log_lock; }; diff --git a/rdairplay/log_play.cpp b/rdairplay/log_play.cpp index 46322f00..60bd96f7 100644 --- a/rdairplay/log_play.cpp +++ b/rdairplay/log_play.cpp @@ -1361,6 +1361,14 @@ void LogPlay::resync() } +bool LogPlay::isRefreshable() const +{ + return (play_log->exists())&& + (play_log->linkDatetime()==play_link_datetime)&& + (play_log->modifiedDatetime()>play_modified_datetime); +} + + void LogPlay::transTimerData() { int lines[TRANSPORT_QUANTITY]; diff --git a/rdairplay/log_play.h b/rdairplay/log_play.h index 4d42b401..fad97d08 100644 --- a/rdairplay/log_play.h +++ b/rdairplay/log_play.h @@ -115,6 +115,7 @@ class LogPlay : public QObject,public RDLogEvent QTime nextStop() const; bool running(bool include_paused=true); void resync(); + bool isRefreshable() const; private slots: void transTimerData(); diff --git a/rdairplay/rdairplay_cs.ts b/rdairplay/rdairplay_cs.ts index 2711d6ad..e17b9a00 100644 --- a/rdairplay/rdairplay_cs.ts +++ b/rdairplay/rdairplay_cs.ts @@ -456,6 +456,22 @@ poslechu Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdairplay/rdairplay_de.ts b/rdairplay/rdairplay_de.ts index 824f5bf0..28158dfc 100644 --- a/rdairplay/rdairplay_de.ts +++ b/rdairplay/rdairplay_de.ts @@ -456,6 +456,22 @@ vorhören Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdairplay/rdairplay_es.ts b/rdairplay/rdairplay_es.ts index bd5dfbef..e256758e 100644 --- a/rdairplay/rdairplay_es.ts +++ b/rdairplay/rdairplay_es.ts @@ -456,6 +456,22 @@ Final Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdairplay/rdairplay_fr.ts b/rdairplay/rdairplay_fr.ts index e8709923..57f475eb 100644 --- a/rdairplay/rdairplay_fr.ts +++ b/rdairplay/rdairplay_fr.ts @@ -456,6 +456,22 @@ la Fin Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdairplay/rdairplay_nb.ts b/rdairplay/rdairplay_nb.ts index 3390a9cb..5c09cdc0 100644 --- a/rdairplay/rdairplay_nb.ts +++ b/rdairplay/rdairplay_nb.ts @@ -462,6 +462,22 @@ Tail Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdairplay/rdairplay_nn.ts b/rdairplay/rdairplay_nn.ts index 3390a9cb..5c09cdc0 100644 --- a/rdairplay/rdairplay_nn.ts +++ b/rdairplay/rdairplay_nn.ts @@ -462,6 +462,22 @@ Tail Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdairplay/rdairplay_pt_BR.ts b/rdairplay/rdairplay_pt_BR.ts index 8a59c643..07f6a956 100644 --- a/rdairplay/rdairplay_pt_BR.ts +++ b/rdairplay/rdairplay_pt_BR.ts @@ -457,6 +457,22 @@ Log Save As + + Log already being edited by + + + + Log Locked + + + + Error + + + + You must refresh the log before it can be saved. + + LogLineBox diff --git a/rdlogedit/edit_log.cpp b/rdlogedit/edit_log.cpp index c3d8c090..13f05a4d 100644 --- a/rdlogedit/edit_log.cpp +++ b/rdlogedit/edit_log.cpp @@ -147,8 +147,9 @@ EditLog::EditLog(QString logname,QString *filter,QString *group, edit_log=new RDLog(edit_logname); // - // Log Events + // Log Data Structures // + edit_log_lock=new RDLogLock(edit_logname,rduser,rdstation_conf,this); edit_log_event=new RDLogEvent(RDLog::tableName(edit_logname)); edit_log_event->load(true); @@ -624,6 +625,8 @@ EditLog::EditLog(QString logname,QString *filter,QString *group, EditLog::~EditLog() { + delete edit_log_event; + delete edit_log_lock; } @@ -639,6 +642,26 @@ QSizePolicy EditLog::sizePolicy() const } +int EditLog::exec() +{ + QString username; + QString stationname; + QHostAddress addr; + + if(!edit_log_lock->tryLock(&username,&stationname,&addr)) { + QString msg=tr("Log already being edited by")+" "+username+"@"+stationname; + if(stationname!=addr.toString()) { + msg+=" ["+addr.toString()+"]"; + } + msg+="."; + QMessageBox::warning(this,"RDLogEdit - "+tr("Log Locked"),msg); + return false; + } + + return QDialog::exec(); +} + + void EditLog::descriptionChangedData(const QString &) { SetLogModified(true); @@ -1191,7 +1214,7 @@ void EditLog::okData() for(unsigned i=0;isize();i++) { edit_clipboard->at(i).clearExternalData(); } - done(0); + done(true); } @@ -1224,7 +1247,7 @@ void EditLog::cancelData() for(unsigned i=0;isize();i++) { edit_clipboard->at(i).clearExternalData(); } - done(1); + done(false); } diff --git a/rdlogedit/edit_log.h b/rdlogedit/edit_log.h index 447433e7..d0e0853c 100644 --- a/rdlogedit/edit_log.h +++ b/rdlogedit/edit_log.h @@ -33,12 +33,13 @@ #include #include -#include +#include #include #include -#include -#include +#include #include +#include +#include #include "drop_listview.h" #include "list_reports.h" @@ -61,6 +62,9 @@ class EditLog : public QDialog ~EditLog(); QSize sizeHint() const; QSizePolicy sizePolicy() const; + + public slots: + int exec(); private slots: void descriptionChangedData(const QString &); @@ -187,6 +191,7 @@ class EditLog : public QDialog QLabel *edit_purgedate_label; QDateEdit *edit_purgedate_edit; QPushButton *edit_purgedate_button; + RDLogLock *edit_log_lock; #ifndef WIN32 QPushButton *edit_renderas_button; RenderDialog *edit_render_dialog; diff --git a/rdlogedit/rdlogedit.cpp b/rdlogedit/rdlogedit.cpp index 0c80523f..3df0537d 100644 --- a/rdlogedit/rdlogedit.cpp +++ b/rdlogedit/rdlogedit.cpp @@ -40,25 +40,25 @@ #include #include +#include #include +#include +#include +#include #include +#include +#include +#include +#include #include #include -#include -//#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include "edit_log.h" +#include "globals.h" +#include "rdlogedit.h" #ifndef WIN32 -#include +#include "voice_tracker.h" #endif // WIN32 // @@ -455,8 +455,9 @@ void MainWidget::editData() } std::vector newlogs; - EditLog *log=new EditLog(items.at(0)->text(1),&log_filter,&log_group,&log_schedcode, - &log_clipboard,&newlogs,this); + EditLog *log= + new EditLog(items.at(0)->text(1),&log_filter,&log_group,&log_schedcode, + &log_clipboard,&newlogs,this); log->exec(); delete log; RefreshItem(items.at(0)); @@ -530,17 +531,33 @@ void MainWidget::deleteData() } for(unsigned i=0;itext(1)); - if(log->remove(rdstation_conf,rduser,log_config)) { - delete items.at(i); + QString username; + QString stationname; + QHostAddress addr; + RDLogLock *log_lock=new RDLogLock(items.at(i)->text(1),rduser, + rdstation_conf,this); + if(log_lock->tryLock(&username,&stationname,&addr)) { + RDLog *log=new RDLog(items.at(i)->text(1)); + if(log->remove(rdstation_conf,rduser,log_config)) { + delete items.at(i); + } + else { + QMessageBox::warning(this,"RDLogEdit - "+tr("Error"), + tr("Unable to delete log")+" \""+ + items.at(i)->text(1)+"\", "+ + tr("audio deletion error!")); + } + delete log; } else { - QMessageBox::warning(this,"RDLogEdit - "+tr("Error"), - tr("Unable to delete log")+" \""+ - items.at(i)->text(1)+"\", "+ - tr("audio deletion error!")); + QString msg=tr("Log")+" "+items.at(i)->text(1)+"\" "+ + tr("is in use by")+" "+username+"@"+stationname; + if(stationname!=addr.toString()) { + msg+=" ["+addr.toString()+"]"; + } + QMessageBox::warning(this,"RDLogEdit - "+tr("Error"),msg); } - delete log; + delete log_lock; } } } diff --git a/rdlogedit/rdlogedit_cs.ts b/rdlogedit/rdlogedit_cs.ts index e01e1853..2c521683 100644 --- a/rdlogedit/rdlogedit_cs.ts +++ b/rdlogedit/rdlogedit_cs.ts @@ -425,6 +425,18 @@ jež jsou pro vybranou službu zakázány! Error + + User + Uživatel + + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -927,6 +939,14 @@ Vyhledejte svého správce systému kvůli aktualizaci! Windows + + Log + + + + is in use by + + RenderDialog @@ -1250,5 +1270,13 @@ therefore only existing transitions will be editable. LABEL ŠTÍTEK + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/rdlogedit_de.ts b/rdlogedit/rdlogedit_de.ts index f3c9c202..1e5048a5 100644 --- a/rdlogedit/rdlogedit_de.ts +++ b/rdlogedit/rdlogedit_de.ts @@ -425,6 +425,18 @@ die für den gewählten Service ungültig sind! Error + + User + Benutzer + + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -926,6 +938,14 @@ See your system administrator for an update! Windows + + Log + + + + is in use by + + RenderDialog @@ -1249,5 +1269,13 @@ therefore only existing transitions will be editable. LABEL LABEL + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/rdlogedit_es.ts b/rdlogedit/rdlogedit_es.ts index d778c88c..f67ceb66 100644 --- a/rdlogedit/rdlogedit_es.ts +++ b/rdlogedit/rdlogedit_es.ts @@ -425,6 +425,18 @@ desactivados para el servicio actual! Error + + User + Usuario + + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -923,6 +935,14 @@ See your system administrator for an update! Windows + + Log + + + + is in use by + + RenderDialog @@ -1252,5 +1272,13 @@ sólo podrás editar transiciones ya existentes. LABEL ETIQUETA + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/rdlogedit_fr.ts b/rdlogedit/rdlogedit_fr.ts index 3da60855..c172d309 100644 --- a/rdlogedit/rdlogedit_fr.ts +++ b/rdlogedit/rdlogedit_fr.ts @@ -403,6 +403,14 @@ for the selected service! Error + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -843,6 +851,14 @@ See your system administrator for an update! Windows + + Log + + + + is in use by + + RenderDialog @@ -1166,5 +1182,13 @@ therefore only existing transitions will be editable. LABEL + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/rdlogedit_nb.ts b/rdlogedit/rdlogedit_nb.ts index 45d909a6..77780d34 100644 --- a/rdlogedit/rdlogedit_nb.ts +++ b/rdlogedit/rdlogedit_nb.ts @@ -432,6 +432,18 @@ skrudd av for denne tenesta! Error + + User + Brukar + + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -944,6 +956,14 @@ See your system administrator for an update! Windows + + Log + + + + is in use by + + RenderDialog @@ -1267,5 +1287,13 @@ therefore only existing transitions will be editable. LABEL SELSKAP + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/rdlogedit_nn.ts b/rdlogedit/rdlogedit_nn.ts index 45d909a6..77780d34 100644 --- a/rdlogedit/rdlogedit_nn.ts +++ b/rdlogedit/rdlogedit_nn.ts @@ -432,6 +432,18 @@ skrudd av for denne tenesta! Error + + User + Brukar + + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -944,6 +956,14 @@ See your system administrator for an update! Windows + + Log + + + + is in use by + + RenderDialog @@ -1267,5 +1287,13 @@ therefore only existing transitions will be editable. LABEL SELSKAP + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/rdlogedit_pt_BR.ts b/rdlogedit/rdlogedit_pt_BR.ts index a58dd26f..ffff457b 100644 --- a/rdlogedit/rdlogedit_pt_BR.ts +++ b/rdlogedit/rdlogedit_pt_BR.ts @@ -427,6 +427,18 @@ para o serviço selecionado! Error + + User + Usuário + + + Log Locked + + + + Log already being edited by + + EditLogLine @@ -923,6 +935,14 @@ See your system administrator for an update! Windows + + Log + + + + is in use by + + RenderDialog @@ -1253,5 +1273,13 @@ Assim sendo, somente transições existentes serão editáveis. LABEL SELO + + Log Locked + + + + Log already being edited by + + diff --git a/rdlogedit/voice_tracker.cpp b/rdlogedit/voice_tracker.cpp index 1c81744c..0cd5cfba 100644 --- a/rdlogedit/voice_tracker.cpp +++ b/rdlogedit/voice_tracker.cpp @@ -246,8 +246,9 @@ VoiceTracker::VoiceTracker(const QString &logname,QString *import_path, this,SLOT(recordUnloadedData(int,int,unsigned))); // - // Log Machine + // Log Data Structures // + track_log_lock=new RDLogLock(edit_log_name,rduser,rdstation_conf,this); track_log=new RDLog(edit_log_name); track_log_event=new RDLogEvent(RDLog::tableName(edit_log_name)); track_log_event->load(); @@ -522,6 +523,7 @@ VoiceTracker::~VoiceTracker() delete wpg[i]; wpg[i]=NULL; } + delete track_log_lock; } @@ -537,6 +539,24 @@ QSizePolicy VoiceTracker::sizePolicy() const } +int VoiceTracker::exec() +{ + QString username; + QString stationname; + QHostAddress addr; + + if(!track_log_lock->tryLock(&username,&stationname,&addr)) { + QMessageBox::warning(this,"RDLogEdit - "+tr("Log Locked"), + tr("Log already being edited by")+" "+ + username+"@"+stationname+" ["+ + addr.toString()+"]."); + return false; + } + + return QDialog::exec(); +} + + void VoiceTracker::keyPressEvent(QKeyEvent *e) { switch(e->key()) { diff --git a/rdlogedit/voice_tracker.h b/rdlogedit/voice_tracker.h index 84c7fda7..0ac01b8b 100644 --- a/rdlogedit/voice_tracker.h +++ b/rdlogedit/voice_tracker.h @@ -2,7 +2,7 @@ // // A Rivendell Voice Tracker // -// (C) Copyright 2002-2006,2016 Fred Gleason +// (C) Copyright 2002-2006,2016-2017 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -34,18 +34,20 @@ #include #include -#include -#include #include #include +#include #include #include #include +#include #include -#include -#include -#include #include +#include +#include +#include + +#include "log_listview.h" // // Widget Settings @@ -80,7 +82,10 @@ class VoiceTracker : public QDialog ~VoiceTracker(); QSize sizeHint() const; QSizePolicy sizePolicy() const; - + + public slots: + int exec(); + private slots: void updateMenuData(); void hideMenuData(); @@ -199,7 +204,6 @@ class VoiceTracker : public QDialog QPixmap *edit_wave_map[3]; QString edit_wave_name[3]; RDWavePainter *wpg[3]; - //int edit_wave_pos[3]; int edit_scroll_pos[3]; int edit_wave_origin[3]; RDLogLine *edit_logline[3]; @@ -212,10 +216,7 @@ class VoiceTracker : public QDialog bool track_redraw[3]; unsigned track_redraw_count; RDCart *edit_track_cart; - - //RDCut *edit_track_cut; RDCut *edit_track_cuts[3]; - RDGroup *track_group; int edit_wave_width; int edit_cursor_pos; @@ -284,7 +285,8 @@ class VoiceTracker : public QDialog int track_target_track[VoiceTracker::TargetSize]; VoiceTracker::Target track_current_target; bool edit_shift_pressed; + RDLogLock *track_log_lock; }; -#endif +#endif // VOICE_TRACKER_H diff --git a/rdlogmanager/commandline_ops.cpp b/rdlogmanager/commandline_ops.cpp index c885061d..63a95ff5 100644 --- a/rdlogmanager/commandline_ops.cpp +++ b/rdlogmanager/commandline_ops.cpp @@ -45,6 +45,7 @@ int RunLogOperation(int argc,char *argv[],const QString &svcname, QString svcname_table=svcname; svcname_table.replace(" ","_"); unsigned schema=0; + QString err_msg; QApplication a(argc,argv,false); @@ -112,8 +113,8 @@ int RunLogOperation(int argc,char *argv[],const QString &svcname, rdstation_conf,config,svc->name()), RDDateDecode(svc->nameTemplate(),start_date.addDays(1), rdstation_conf,config,svc->name()), - &unused_report,rduser)) { - fprintf(stderr,"rdlogmanager: unable to generate log\n"); + &unused_report,rduser,&err_msg)) { + fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg); return 256; } log->updateTracks(); @@ -147,15 +148,24 @@ int RunLogOperation(int argc,char *argv[],const QString &svcname, } report=""; log->removeTracks(rdstation_conf,rduser,config); - svc->clearLogLinks(RDSvc::Traffic,logname); - svc->clearLogLinks(RDSvc::Music,logname); - if(svc->linkLog(RDSvc::Music,start_date,logname,&report)) { + if(!svc->clearLogLinks(RDSvc::Traffic,logname,rduser,&err_msg)) { + fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg); + return 256; + } + if(!svc->clearLogLinks(RDSvc::Music,logname,rduser,&err_msg)) { + fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg); + return 256; + } + if(svc->linkLog(RDSvc::Music,start_date,logname,&report,rduser,&err_msg)) { printf("%s\n",(const char*)report); } else { + fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg); + /* fprintf(stderr, "rdlogmanager: unable to open music schedule file at \"%s\"\n", (const char *)svc->importFilename(RDSvc::Music,start_date)); + */ exit(256); } } @@ -176,14 +186,21 @@ int RunLogOperation(int argc,char *argv[],const QString &svcname, return 256; } report=""; - svc->clearLogLinks(RDSvc::Traffic,logname); - if(svc->linkLog(RDSvc::Traffic,start_date,logname,&report)) { + if(!svc->clearLogLinks(RDSvc::Traffic,logname,rduser,&err_msg)) { + fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg); + return 256; + } + if(svc->linkLog(RDSvc::Traffic,start_date,logname,&report,rduser, + &err_msg)) { printf("%s\n",(const char*)report); } else { + fprintf(stderr,"rdlogmanager: %s\n",(const char *)err_msg); + /* fprintf(stderr, "rdlogmanager: unable to open traffic schedule file at \"%s\"\n", (const char *)svc->importFilename(RDSvc::Traffic,start_date)); + */ } } diff --git a/rdlogmanager/generate_log.cpp b/rdlogmanager/generate_log.cpp index 8efcc0f5..8e0d038c 100644 --- a/rdlogmanager/generate_log.cpp +++ b/rdlogmanager/generate_log.cpp @@ -298,6 +298,7 @@ void GenerateLog::createData() QString str1; QString str2; unsigned tracks=0; + QString err_msg; // // Generate Log @@ -359,13 +360,20 @@ void GenerateLog::createData() connect(svc,SIGNAL(generationProgress(int)), gen_progress_dialog,SLOT(setProgress(int))); - svc->generateLog(gen_date_edit->date(), - RDDateDecode(svc->nameTemplate(),gen_date_edit->date(), - rdstation_conf,log_config,svc->name()), - RDDateDecode(svc->nameTemplate(),gen_date_edit->date(). - addDays(1),rdstation_conf,log_config, - svc->name()), - &unused_report,rduser); + if(!svc->generateLog(gen_date_edit->date(), + RDDateDecode(svc->nameTemplate(),gen_date_edit->date(), + rdstation_conf,log_config,svc->name()), + RDDateDecode(svc->nameTemplate(),gen_date_edit->date(). + addDays(1),rdstation_conf,log_config, + svc->name()), + &unused_report,rduser,&err_msg)) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("Unable to generate log")+": "+err_msg); + gen_progress_dialog->setProgress(gen_progress_dialog->totalSteps()); + delete svc; + delete log; + return; + } log->updateTracks(); delete log; delete svc; @@ -392,6 +400,7 @@ void GenerateLog::createData() void GenerateLog::musicData() { unsigned tracks=0; + QString err_msg; RDSvc *svc= new RDSvc(gen_service_box->currentText(),rdstation_conf,log_config,this); @@ -428,13 +437,33 @@ void GenerateLog::musicData() } } log->removeTracks(rdstation_conf,rduser,log_config); - svc->clearLogLinks(RDSvc::Traffic,logname); - svc->clearLogLinks(RDSvc::Music,logname); + if(!svc->clearLogLinks(RDSvc::Traffic,logname,rduser,&err_msg)) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("Unable to clear traffic links")+": "+err_msg); + delete log; + delete svc; + return; + } + if(!svc->clearLogLinks(RDSvc::Music,logname,rduser,&err_msg)) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("Unable to clear music links")+": "+err_msg); + delete log; + delete svc; + return; + } } connect(svc,SIGNAL(generationProgress(int)), gen_progress_dialog,SLOT(setProgress(int))); QString report; - svc->linkLog(RDSvc::Music,gen_date_edit->date(),logname,&report); + if(!svc->linkLog(RDSvc::Music,gen_date_edit->date(),logname,&report,rduser, + &err_msg)) { + + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("Unable to link music log")+": "+err_msg); + delete log; + delete svc; + return; + } delete log; delete svc; if(!report.isEmpty()) { @@ -446,6 +475,7 @@ void GenerateLog::musicData() void GenerateLog::trafficData() { + QString err_msg; RDSvc *svc= new RDSvc(gen_service_box->currentText(),rdstation_conf,log_config,this); QString logname=RDDateDecode(svc->nameTemplate(),gen_date_edit->date(), @@ -464,13 +494,26 @@ void GenerateLog::trafficData() delete svc; return; } - svc->clearLogLinks(RDSvc::Traffic,logname); + if(!svc->clearLogLinks(RDSvc::Traffic,logname,rduser,&err_msg)) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("Unable to clear traffic links")+": "+err_msg); + delete log; + delete svc; + return; + } } connect(svc,SIGNAL(generationProgress(int)), gen_progress_dialog,SLOT(setProgress(int))); QString report; - svc->linkLog(RDSvc::Traffic,gen_date_edit->date(),logname,&report); + if(!svc->linkLog(RDSvc::Traffic,gen_date_edit->date(),logname,&report,rduser, + &err_msg)) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("Unable to link traffic log")+": "+err_msg); + delete log; + delete svc; + return; + } delete log; delete svc; if(!report.isEmpty()) { diff --git a/rdlogmanager/rdlogmanager_cs.ts b/rdlogmanager/rdlogmanager_cs.ts index 1d0fb702..35878718 100644 --- a/rdlogmanager/rdlogmanager_cs.ts +++ b/rdlogmanager/rdlogmanager_cs.ts @@ -855,6 +855,30 @@ Opětovné sloučení tato data smaže. Sloučit znovu? Generate Log - User: Vytvořit zápis - Uživatel: + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/rdlogmanager/rdlogmanager_de.ts b/rdlogmanager/rdlogmanager_de.ts index 2a894e31..dd6b4676 100644 --- a/rdlogmanager/rdlogmanager_de.ts +++ b/rdlogmanager/rdlogmanager_de.ts @@ -855,6 +855,30 @@ Einbinden wird diese entfernen. Fortfahren? Generate Log - User: Generiere Log - User: + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/rdlogmanager/rdlogmanager_es.ts b/rdlogmanager/rdlogmanager_es.ts index b8d82f51..a6e737a0 100644 --- a/rdlogmanager/rdlogmanager_es.ts +++ b/rdlogmanager/rdlogmanager_es.ts @@ -857,6 +857,30 @@ removerá estos datos. ¿Remezclar? Generate Log - User: Generar lista - Usuario: + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/rdlogmanager/rdlogmanager_fr.ts b/rdlogmanager/rdlogmanager_fr.ts index c246b056..128b1de7 100644 --- a/rdlogmanager/rdlogmanager_fr.ts +++ b/rdlogmanager/rdlogmanager_fr.ts @@ -837,6 +837,30 @@ will remove this data. Remerge? Generate Log - User: + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/rdlogmanager/rdlogmanager_nb.ts b/rdlogmanager/rdlogmanager_nb.ts index cc79a241..c27f8be2 100644 --- a/rdlogmanager/rdlogmanager_nb.ts +++ b/rdlogmanager/rdlogmanager_nb.ts @@ -868,6 +868,30 @@ Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt? Generate Log - User: + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/rdlogmanager/rdlogmanager_nn.ts b/rdlogmanager/rdlogmanager_nn.ts index cc79a241..c27f8be2 100644 --- a/rdlogmanager/rdlogmanager_nn.ts +++ b/rdlogmanager/rdlogmanager_nn.ts @@ -868,6 +868,30 @@ Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt? Generate Log - User: + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/rdlogmanager/rdlogmanager_pt_BR.ts b/rdlogmanager/rdlogmanager_pt_BR.ts index e567db4e..7222cd6d 100644 --- a/rdlogmanager/rdlogmanager_pt_BR.ts +++ b/rdlogmanager/rdlogmanager_pt_BR.ts @@ -857,6 +857,30 @@ Re-agregar removerá estes dados. Re-agregar? Traffic Exists Tráfego Existente + + Error + + + + Unable to generate log + + + + Unable to clear traffic links + + + + Unable to clear music links + + + + Unable to link music log + + + + Unable to link traffic log + + ImportListView diff --git a/tests/log_unlink_test.cpp b/tests/log_unlink_test.cpp index 5059c8ab..d17f871d 100644 --- a/tests/log_unlink_test.cpp +++ b/tests/log_unlink_test.cpp @@ -37,10 +37,7 @@ MainObject::MainObject(QObject *parent) :QObject(parent) { - QString log_name=""; - RDSvc::ImportSource import_source=RDSvc::Traffic; - RDConfig *config=NULL; - RDStation *station=NULL; + test_import_source=RDSvc::Traffic; unsigned schema=0; // @@ -51,16 +48,16 @@ MainObject::MainObject(QObject *parent) LOG_UNLINK_TEST_USAGE); for(unsigned i=0;ikeys();i++) { if(cmd->key(i)=="--log") { - log_name=cmd->value(i); + test_log_name=cmd->value(i); cmd->setProcessed(i,true); } if(cmd->key(i)=="--source") { if(cmd->value(i).lower()=="traffic") { - import_source=RDSvc::Traffic; + test_import_source=RDSvc::Traffic; } else { if(cmd->value(i).lower()=="music") { - import_source=RDSvc::Music; + test_import_source=RDSvc::Music; } else { fprintf(stderr, @@ -76,7 +73,7 @@ MainObject::MainObject(QObject *parent) exit(256); } } - if(log_name.isEmpty()) { + if(test_log_name.isEmpty()) { fprintf(stderr,"log_unlink_test: you must specify a log name with \"--log=\"\n"); exit(1); } @@ -84,9 +81,9 @@ MainObject::MainObject(QObject *parent) // // Load Configuration // - config=new RDConfig(); - config->load(); - config->setModuleName("reserve_carts_test"); + test_config=new RDConfig(); + test_config->load(); + test_config->setModuleName("reserve_carts_test"); // // Open Database @@ -98,18 +95,31 @@ MainObject::MainObject(QObject *parent) delete cmd; exit(256); } - station=new RDStation(config->stationName()); + test_station=new RDStation(test_config->stationName()); + test_ripc=new RDRipc(test_station,test_config,this); + connect(test_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + test_ripc->connectHost("localhost",RIPCD_TCP_PORT,test_config->password()); +} + + +void MainObject::userData() +{ + QString err_msg; // // Run the Test // - if(!RDLog::exists(log_name)) { + if(!RDLog::exists(test_log_name)) { fprintf(stderr,"log_unlink_test: no such log\n"); exit(1); } - RDLog *log=new RDLog(log_name); - RDSvc *svc=new RDSvc(log->service(),station,config,this); - svc->clearLogLinks(import_source,log_name); + RDLog *log=new RDLog(test_log_name); + RDSvc *svc=new RDSvc(log->service(),test_station,test_config,this); + if(!svc->clearLogLinks(test_import_source,test_log_name, + new RDUser(test_ripc->user()),&err_msg)) { + fprintf(stderr,"log_unlink_test: %s\n",(const char *)err_msg); + exit(1); + } exit(0); } diff --git a/tests/log_unlink_test.h b/tests/log_unlink_test.h index 6da8b2b3..c1af8b2e 100644 --- a/tests/log_unlink_test.h +++ b/tests/log_unlink_test.h @@ -23,12 +23,25 @@ #include +#include +#include + #define LOG_UNLINK_TEST_USAGE "[options]\n\nTest the Rivendell log unlinker methods\n\nOptions are:\n--log=\n Name of log to unlink.\n\n--source=music|traffic\n Data source to unlink\n\n" class MainObject : public QObject { public: MainObject(QObject *parent=0); + + private slots: + void userData(); + + private: + RDSvc::ImportSource test_import_source; + QString test_log_name; + RDStation *test_station; + RDRipc *test_ripc; + RDConfig *test_config; }; diff --git a/utils/rdclilogedit/operations.cpp b/utils/rdclilogedit/operations.cpp index c08e114b..75e03760 100644 --- a/utils/rdclilogedit/operations.cpp +++ b/utils/rdclilogedit/operations.cpp @@ -107,16 +107,24 @@ void MainObject::Deletelog(QString logname) delete q; if((edit_log==NULL)||(edit_log->name()!=logname)) { + RDLogLock *log_lock=new RDLogLock(logname,edit_user,edit_station,this); + QString err_msg; RDLog *log=new RDLog(logname); if(log->exists()) { - if(!log->remove(edit_station,edit_user,edit_config)) { - fprintf(stderr,"deletelog: audio deletion error, log not deleted\n"); + if(TryLock(log_lock,logname)) { + if(!log->remove(edit_station,edit_user,edit_config)) { + fprintf(stderr, + "deletelog: audio deletion error, log not deleted\n"); + } } + else { + delete log_lock; + } + delete log; } else { fprintf(stderr,"deletelog: no such log\n"); } - delete log; } else { fprintf(stderr,"deletelog: log currently loaded (try \"unload\" first)\n"); @@ -208,6 +216,10 @@ void MainObject::Load(QString logname) delete edit_log_event; edit_log_event=NULL; } + if(edit_log_lock!=NULL) { + delete edit_log_lock; + edit_log_lock=NULL; + } // // Normalize log name case @@ -223,6 +235,16 @@ void MainObject::Load(QString logname) } delete q; + QString username; + QString stationname; + QHostAddress addr; + edit_log_lock=new RDLogLock(logname,edit_user,edit_station,this); + if(!TryLock(edit_log_lock,logname)) { + delete edit_log_lock; + edit_log_lock=NULL; + return; + } + edit_log=new RDLog(logname); if(edit_log->exists()) { edit_log_event=new RDLogEvent(RDLog::tableName(logname)); @@ -332,6 +354,9 @@ void MainObject::New(const QString &logname) if(edit_log_event!=NULL) { delete edit_log_event; } + if(edit_log_lock!=NULL) { + delete edit_log_lock; + } edit_log=new RDLog(logname); if(!edit_log->exists()) { edit_log_event=new RDLogEvent(RDLog::tableName(logname)); @@ -346,8 +371,14 @@ void MainObject::New(const QString &logname) edit_end_date=QDate(); edit_purge_date=QDate(); edit_auto_refresh=false; - edit_new_log=true; + // edit_new_log=true; edit_modified=false; + Saveas(edit_log->name()); + edit_log_lock=new RDLogLock(edit_log->name(),edit_user,edit_station,this); + if(!TryLock(edit_log_lock,edit_log->name())) { + fprintf(stderr,"FATAL ERROR: unable to lock new log!\n"); + exit(256); + } } else { fprintf(stderr,"new: log already exists\n"); @@ -364,21 +395,16 @@ void MainObject::Remove(int line) void MainObject::Save() { - if(edit_new_log) { - Saveas(edit_log->name()); - } - else { - edit_log_event->save(edit_config); - edit_log->setDescription(edit_description); - edit_log->setStartDate(edit_start_date); - edit_log->setEndDate(edit_end_date); - edit_log->setPurgeDate(edit_purge_date); - edit_log->setAutoRefresh(edit_auto_refresh); - edit_log->setService(edit_service); - edit_log-> - setModifiedDatetime(QDateTime(QDate::currentDate(),QTime::currentTime())); - edit_modified=false; - } + edit_log_event->save(edit_config); + edit_log->setDescription(edit_description); + edit_log->setStartDate(edit_start_date); + edit_log->setEndDate(edit_end_date); + edit_log->setPurgeDate(edit_purge_date); + edit_log->setAutoRefresh(edit_auto_refresh); + edit_log->setService(edit_service); + edit_log-> + setModifiedDatetime(QDateTime(QDate::currentDate(),QTime::currentTime())); + edit_modified=false; } @@ -410,7 +436,6 @@ void MainObject::Saveas(const QString &logname) delete edit_log; edit_log=log; edit_modified=false; - edit_new_log=false; } else { fprintf(stderr,"saveas: log already exists\n"); @@ -555,5 +580,9 @@ void MainObject::Unload() delete edit_log_event; edit_log_event=NULL; } + if(edit_log_lock!=NULL) { + delete edit_log_lock; + edit_log_lock=NULL; + } edit_modified=false; } diff --git a/utils/rdclilogedit/parser.cpp b/utils/rdclilogedit/parser.cpp index 4748172b..bc7c1207 100644 --- a/utils/rdclilogedit/parser.cpp +++ b/utils/rdclilogedit/parser.cpp @@ -62,6 +62,9 @@ void MainObject::DispatchCommand(QString cmd) if((verb=="exit")||(verb=="quit")||(verb=="bye")) { if(overwrite) { + if(edit_log_lock!=NULL) { + delete edit_log_lock; + } exit(0); } else { diff --git a/utils/rdclilogedit/rdclilogedit.cpp b/utils/rdclilogedit/rdclilogedit.cpp index 63eb0ee8..22e3061a 100644 --- a/utils/rdclilogedit/rdclilogedit.cpp +++ b/utils/rdclilogedit/rdclilogedit.cpp @@ -43,7 +43,7 @@ MainObject::MainObject(QObject *parent) edit_log=NULL; edit_log_event=NULL; edit_modified=false; - edit_new_log=false; + edit_log_lock=NULL; // // Read Command Options @@ -137,10 +137,32 @@ void MainObject::userData() if(!edit_quiet_option) { printf("\n"); } + if(edit_log_lock!=NULL) { + delete edit_log_lock; + } exit(0); } +bool MainObject::TryLock(RDLogLock *lock,const QString &logname) +{ + QString username; + QString stationname; + QHostAddress addr; + bool ret; + + ret=lock->tryLock(&username,&stationname,&addr); + if(!ret) { + QString msg="log \""+logname+"\" in use by "+username+"@"+stationname; + if(stationname!=addr.toString()) { + msg+=" ["+addr.toString()+"]"; + } + fprintf(stderr,"%s\n",(const char *)msg); + } + return ret; +} + + void MainObject::OverwriteError(const QString &cmd) const { fprintf(stderr,"%s: buffer not saved (append \"!\" to override)\n", diff --git a/utils/rdclilogedit/rdclilogedit.h b/utils/rdclilogedit/rdclilogedit.h index 84013888..61dd3904 100644 --- a/utils/rdclilogedit/rdclilogedit.h +++ b/utils/rdclilogedit/rdclilogedit.h @@ -2,7 +2,7 @@ // // A Command-line log editor for Rivendell // -// (C) Copyright 2016 Fred Gleason +// (C) Copyright 2016-2017 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,7 @@ class MainObject : public QObject void Settime(int line,RDLogLine::TimeType type,const QTime &time=QTime()); void Settrans(int line,RDLogLine::TransType type); void Unload(); + bool TryLock(RDLogLock *lock,const QString &logname); void OverwriteError(const QString &cmd) const; void DispatchCommand(QString cmd); QString ListLine(RDLogEvent *evt,int line) const; @@ -78,7 +80,7 @@ class MainObject : public QObject bool edit_quiet_option; QString edit_accum; bool edit_modified; - bool edit_new_log; + // bool edit_new_log; RDLog *edit_log; RDLogEvent *edit_log_event; QString edit_description; @@ -92,6 +94,7 @@ class MainObject : public QObject RDRipc *edit_ripc; RDAirPlayConf *edit_airplay_conf; RDConfig *edit_config; + RDLogLock *edit_log_lock; }; diff --git a/utils/rdrevert/rdrevert.cpp b/utils/rdrevert/rdrevert.cpp index cda04f80..f858fafb 100644 --- a/utils/rdrevert/rdrevert.cpp +++ b/utils/rdrevert/rdrevert.cpp @@ -247,6 +247,14 @@ void MainObject::Revert(int schema) const case 272: Revert272(); break; + + case 273: + Revert273(); + break; + + case 274: + Revert274(); + break; } } @@ -758,6 +766,48 @@ void MainObject::Revert272() const } +void MainObject::Revert273() const +{ + QString sql; + QSqlQuery *q; + + sql=QString("alter table LOGS drop column LOCK_DATETIME"); + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table LOGS drop column LOCK_IPV4_ADDRESS"); + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table LOGS drop column LOCK_STATION_NAME"); + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table LOGS drop column LOCK_USER_NAME"); + q=new QSqlQuery(sql); + delete q; + + SetVersion(272); +} + + +void MainObject::Revert274() const +{ + QString sql; + RDSqlQuery *q; + + sql=QString("alter table LOGS drop index LOCK_GUID_IDX"); + q=new RDSqlQuery(sql,false); + delete q; + + sql=QString("alter table LOGS drop column LOCK_GUID"); + q=new RDSqlQuery(sql,false); + delete q; + + SetVersion(273); +} + + int MainObject::GetVersion() const { QString sql; @@ -803,6 +853,7 @@ int MainObject::MapSchema(const QString &ver) version_map["2.16"]=263; version_map["2.17"]=268; version_map["2.18"]=272; + version_map["2.19"]=274; // // Normalize String diff --git a/utils/rdrevert/rdrevert.h b/utils/rdrevert/rdrevert.h index 0bd18362..575ad2fb 100644 --- a/utils/rdrevert/rdrevert.h +++ b/utils/rdrevert/rdrevert.h @@ -68,6 +68,8 @@ class MainObject : public QObject void Revert270() const; void Revert271() const; void Revert272() const; + void Revert273() const; + void Revert274() const; int GetVersion() const; void SetVersion(int schema) const; int MapSchema(const QString &ver); diff --git a/web/rdxport/logs.cpp b/web/rdxport/logs.cpp index 3cb3ce51..2b448a7b 100644 --- a/web/rdxport/logs.cpp +++ b/web/rdxport/logs.cpp @@ -24,18 +24,19 @@ #include #include +#include #include #include +#include #include -#include -#include #include #include #include -#include -#include +#include +#include +#include -#include +#include "rdxport.h" void Xport::AddLog() { @@ -245,6 +246,7 @@ void Xport::SaveLog() QString log_name; QString service_name; + QString lock_guid; QString description; QDate purge_date; bool auto_refresh; @@ -262,6 +264,7 @@ void Xport::SaveLog() XmlExit("Missing SERVICE_NAME",400,"logs.cpp",LINE_NUMBER); } GetLogService(service_name); + xport_post->getValue("LOCK_GUID",&lock_guid); if(!xport_post->getValue("DESCRIPTION",&description)) { XmlExit("Missing DESCRIPTION",400,"logs.cpp",LINE_NUMBER); } @@ -494,21 +497,130 @@ void Xport::SaveLog() if(!log->exists()) { XmlExit("No such log",404,"logs.cpp",LINE_NUMBER); } - log->setService(service_name); - log->setDescription(description); - log->setPurgeDate(purge_date); - log->setAutoRefresh(auto_refresh); - log->setStartDate(start_date); - log->setEndDate(end_date); - log->setModifiedDatetime(QDateTime::currentDateTime()); - - logevt->save(xport_config); - + if(lock_guid.isEmpty()) { + QString username=xport_user->name(); + QString stationname=xport_remote_hostname; + QHostAddress addr=xport_remote_address; + lock_guid=RDLogLock::makeGuid(stationname); + if(RDLogLock::tryLock(&username,&stationname,&addr,log_name,lock_guid)) { + log->setService(service_name); + log->setDescription(description); + log->setPurgeDate(purge_date); + log->setAutoRefresh(auto_refresh); + log->setStartDate(start_date); + log->setEndDate(end_date); + log->setModifiedDatetime(QDateTime::currentDateTime()); + logevt->save(xport_config); + RDLogLock::clearLock(lock_guid); + } + else { + XmlExit("unable to get log lock",404); + } + } + else { + if(RDLogLock::validateLock(log_name,lock_guid)) { + log->setService(service_name); + log->setDescription(description); + log->setPurgeDate(purge_date); + log->setAutoRefresh(auto_refresh); + log->setStartDate(start_date); + log->setEndDate(end_date); + log->setModifiedDatetime(QDateTime::currentDateTime()); + logevt->save(xport_config); + } + else { + XmlExit("invalid log lock",400); + } + } XmlExit(QString().sprintf("OK Saved %d events",logevt->size()), 200,"logs.cpp",LINE_NUMBER); } +void Xport::LockLog() +{ + RDLog *log; + QString log_name=""; + Xport::LockLogOperation op_type=Xport::LockLogClear; + QString op_string; + QString lock_guid; + QString username; + QString stationname; + QHostAddress addr; + + // + // Get Options + // + if(!xport_post->getValue("LOG_NAME",&log_name)) { + XmlExit("Missing LOG_NAME",400,"logs.cpp",LINE_NUMBER); + } + if(!xport_post->getValue("OPERATION",&op_string)) { + XmlExit("Missing OPERATION",400,"logs.cpp",LINE_NUMBER); + } + if(op_string.lower()=="create") { + op_type=Xport::LockLogCreate; + } + else { + if(op_string.lower()=="update") { + op_type=Xport::LockLogUpdate; + } + else { + if(op_string.lower()=="clear") { + op_type=Xport::LockLogClear; + } + else { + XmlExit("Unrecognized OPERATION type",400,"logs.cpp",LINE_NUMBER); + } + } + } + if(!xport_post->getValue("LOCK_GUID",&lock_guid)) { + XmlExit("Missing LOCK_GUID",400,"logs.cpp",LINE_NUMBER); + } + + // + // Verify that log exists + // + log=new RDLog(log_name); + if((!ServiceUserValid(log->service()))||(!log->exists())) { + delete log; + XmlExit("No such log",404,"logs.cpp",LINE_NUMBER); + } + + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + switch(op_type) { + case Xport::LockLogCreate: + username=xport_user->name(); + stationname=xport_remote_hostname; + addr=xport_remote_address; + lock_guid=RDLogLock::makeGuid(xport_remote_hostname); + if(RDLogLock::tryLock(&username,&stationname,&addr,log_name,lock_guid)) { + printf("%s",(const char *)LogLockXml(true,log_name,lock_guid,"","",addr)); + } + else { + printf("%s",(const char *)LogLockXml(false,log_name,"",username, + stationname,addr)); + } + Exit(0); + break; + + case Xport::LockLogUpdate: + RDLogLock::updateLock(log_name,lock_guid); + printf("%s",(const char *)LogLockXml(true,log_name,lock_guid,"","",addr)); + Exit(0); + break; + + case Xport::LockLogClear: + RDLogLock::clearLock(lock_guid); + printf("%s",(const char *)LogLockXml(true,log_name,lock_guid,"","",addr)); + Exit(0); + break; + } + + XmlExit("Unexpected exit",500); +} + + RDSvc *Xport::GetLogService(const QString &svc_name) { QString sql=QString("select SERVICE_NAME from USER_SERVICE_PERMS where ")+ @@ -541,3 +653,31 @@ bool Xport::ServiceUserValid(const QString &svc_name) return ret; } + + +QString Xport::LogLockXml(bool result,const QString &log_name, + const QString &guid,const QString &username, + const QString &stationname, + const QHostAddress addr) const +{ + QString xml=""; + + xml+="\n"; + xml+="\n"; + xml+=RDXmlField("result",result); + xml+=RDXmlField("logName",log_name); + if(!guid.isEmpty()) { + xml+=RDXmlField("lockGuid",guid); + } + if(!username.isEmpty()) { + xml+=RDXmlField("userName",username); + } + if(!stationname.isEmpty()) { + xml+=RDXmlField("stationName",stationname); + } + xml+=RDXmlField("address",addr.toString()); + xml+=RDXmlField("lockTimeout",RD_LOG_LOCK_TIMEOUT); + xml+="\n"; + + return xml; +} diff --git a/web/rdxport/rdxport.cpp b/web/rdxport/rdxport.cpp index 6637639d..7c96781b 100644 --- a/web/rdxport/rdxport.cpp +++ b/web/rdxport/rdxport.cpp @@ -119,6 +119,15 @@ Xport::Xport(QObject *parent) db->removeDatabase(xport_config->mysqlDbname()); Exit(0); } + if(getenv("REMOTE_ADDR")!=NULL) { + xport_remote_address.setAddress(getenv("REMOTE_ADDR")); + } + if(getenv("REMOTE_HOST")!=NULL) { + xport_remote_hostname=getenv("REMOTE_HOST"); + } + if(xport_remote_hostname.isEmpty()) { + xport_remote_hostname=xport_remote_address.toString(); + } // // Load System Settings @@ -272,6 +281,10 @@ Xport::Xport(QObject *parent) ListSystemSettings(); break; + case RDXPORT_COMMAND_LOCKLOG: + LockLog(); + break; + case RDXPORT_COMMAND_REHASH: Rehash(); break; diff --git a/web/rdxport/rdxport.h b/web/rdxport/rdxport.h index 92675981..5aa28119 100644 --- a/web/rdxport/rdxport.h +++ b/web/rdxport/rdxport.h @@ -39,6 +39,7 @@ class Xport : public QObject { public: + enum LockLogOperation {LockLogCreate=0,LockLogUpdate=1,LockLogClear=2}; Xport(QObject *parent=0); private: @@ -80,6 +81,10 @@ class Xport : public QObject void ListCartSchedCodes(); void ListServices(); void ListSystemSettings(); + void LockLog(); + QString LogLockXml(bool result,const QString &log_name,const QString &guid, + const QString &username,const QString &stationname, + const QHostAddress addr) const; void Exit(int code); void XmlExit(const QString &msg,int code, const QString &srcfile="",int line=-1, @@ -89,6 +94,8 @@ class Xport : public QObject RDConfig *xport_config; RDSystem *xport_system; RDStation *xport_station; + QString xport_remote_hostname; + QHostAddress xport_remote_address; }; diff --git a/web/tests/Makefile.am b/web/tests/Makefile.am index 56c5cbaa..ebdccd22 100644 --- a/web/tests/Makefile.am +++ b/web/tests/Makefile.am @@ -51,6 +51,7 @@ install-exec-am: cp listschedcodes.html $(DESTDIR)@libexecdir@ cp listservices.html $(DESTDIR)@libexecdir@ cp listsystemsettings.html $(DESTDIR)@libexecdir@ + cp locklog.html $(DESTDIR)@libexecdir@ cp rehash.html $(DESTDIR)@libexecdir@ cp removecart.html $(DESTDIR)@libexecdir@ cp removecut.html $(DESTDIR)@libexecdir@ @@ -89,6 +90,7 @@ uninstall-local: rm -f $(DESTDIR)@libexecdir@/listschedcodes.html rm -f $(DESTDIR)@libexecdir@/listservices.html rm -f $(DESTDIR)@libexecdir@/listsystemsettings.html + rm -f $(DESTDIR)@libexecdir@/locklog.html rm -f $(DESTDIR)@libexecdir@/rehash.html rm -f $(DESTDIR)@libexecdir@/removecart.html rm -f $(DESTDIR)@libexecdir@/removecut.html @@ -126,6 +128,7 @@ EXTRA_DIST = addcart.html\ listschedcodes.html\ listservices.html\ listsystemsettings.html\ + locklog.html\ rehash.html\ removecart.html\ removecut.html\ diff --git a/web/tests/locklog.html b/web/tests/locklog.html new file mode 100644 index 00000000..5deedd66 --- /dev/null +++ b/web/tests/locklog.html @@ -0,0 +1,48 @@ + + +Rivendell LOCKLOG Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
TICKET:
OPERATION: + +
LOG_NAME:
LOCK_GUID:
 
+
+ +