2017-12-27 Fred Gleason <fredg@paravelsystems.com>

* 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 <fredg@paravelsystems.com>
	* Added log locking logic to the voice tracker in rdlogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Added log locking logic to rdclilogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Modified the behavior of the 'new' command in rdclilogedit(1) to
	match that of rdlogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* 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 <fredg@paravelsystems.com>
	* Cleaned up 'log in use" messages in rdlogedit(1) and
	rdclilogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Added log locking logic to the 'SaveLog' Web API call.
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Added log locking logic to rdlogmanager(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Added a lock check for before deleting logs in rdlogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Added a lock check for before deleting logs in rdclilogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
	* Added log locking logic to rdairplay(1).
This commit is contained in:
Fred Gleason 2017-12-27 15:09:06 -05:00
commit c285801fbd
66 changed files with 1677 additions and 150 deletions

View File

@ -16521,3 +16521,34 @@
* Updated 'INSTALL'.
* Updated 'NEWS'.
* Incremented the package version to 2.18.1.
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* 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 <fredg@paravelsystems.com>
* Added log locking logic to the voice tracker in rdlogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Added log locking logic to rdclilogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Modified the behavior of the 'new' command in rdclilogedit(1) to
match that of rdlogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* 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 <fredg@paravelsystems.com>
* Cleaned up 'log in use" messages in rdlogedit(1) and
rdclilogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Added log locking logic to the 'SaveLog' Web API call.
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Added log locking logic to rdlogmanager(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Added a lock check for before deleting logs in rdlogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Added a lock check for before deleting logs in rdclilogedit(1).
2017-12-27 Fred Gleason <fredg@paravelsystems.com>
* Added log locking logic to rdairplay(1).

View File

@ -2669,6 +2669,63 @@
</table>
</sect1>
<sect1>
<title>LockLog</title>
<subtitle>Set / Update / Clear a log lock</subtitle>
<para>
Command Code: <code>RDXPORT_COMMAND_LOCKLOG</code>
</para>
<para>
Required User Permissions: none
</para>
<table xml:id="ex.locklog" frame="all">
<title>LockLog Call Fields</title>
<tgroup cols="3" align="left" colsep="1" rowsep="1">
<colspec colname="FIELD NAME" />
<colspec colname="MEANING" />
<colspec colname="REMARKS" />
<thead>
<row>
<entry>FIELD NAME</entry>
<entry>MEANING</entry>
<entry>REMARKS</entry>
</row>
</thead>
<tbody>
<row>
<entry>COMMAND</entry>
<entry>34</entry>
<entry>Mandatory</entry>
</row>
<row>
<entry>OPERATION</entry>
<entry>Operation to Perform</entry>
<entry>
<para>
Mandatory. Possible values:
</para>
<simplelist>
<member>CREATE</member>
<member>UPDATE</member>
<member>CLEAR</member>
</simplelist>
</entry>
</row>
<row>
<entry>LOG_NAME</entry>
<entry>Name of log</entry>
<entry>Mandatory</entry>
</row>
<row>
<entry>LOCK_GUID</entry>
<entry>Opaque GUID string, returned by the CREATE operation.</entry>
<entry>Mandatory. For CREATE, send an empty string.</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1>
<title>Rehash</title>
<subtitle>Generate a SHA-1 hash for a cut and write it to the database</subtitle>
@ -2923,6 +2980,18 @@
Mandatory. String, 10 characters max.
</entry>
</row>
<row>
<entry>
LOCK_GUID
</entry>
<entry>
The GUID string, obtained from the LockLog API call.
</entry>
<entry>
Optional. If not provided, the service will attempt to acquire
a lock before processing the save.
</entry>
</row>
<row>
<entry>
DESCRIPTION

View File

@ -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)

View File

@ -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\

View File

@ -24,7 +24,7 @@
/*
* Current Database Version
*/
#define RD_VERSION_DATABASE 272
#define RD_VERSION_DATABASE 274
#endif // DBVERSION_H

View File

@ -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

View File

@ -2438,5 +2438,13 @@ Zkuste to, prosím, znovu!</translation>
</source>
<translation>Chyba plnění události</translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -2433,5 +2433,13 @@ bitte erneut versuchen!</translation>
</source>
<translation>Event-Füllfehler</translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -2425,5 +2425,13 @@ please try again!</source>
<translation>Errores al llenar eventos
</translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -2019,5 +2019,13 @@ please try again!</source>
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -2370,5 +2370,13 @@ prøv ein gong til!</translation>
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -2370,5 +2370,13 @@ prøv ein gong til!</translation>
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -2384,5 +2384,13 @@ por favor, tente novamente!</translation>
<translation>Erros de Auto Preenchimento
</translation>
</message>
<message>
<source>Log in use by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import failed</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -567,4 +567,10 @@
*/
#define RD_LOGFILTER_LIMIT_QUAN 14
/*
* Log Locking Timeout
*/
#define RD_LOG_LOCK_TIMEOUT 30000
#endif // RD_H

201
lib/rdloglock.cpp Normal file
View File

@ -0,0 +1,201 @@
// rdloglock.cpp
//
// Log locking routines for Rivendell
//
// (C) Copyright 2017 Fred Gleason <fredg@paravelsystems.com>
//
// 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 <syslog.h>
#endif // WIN32
#include <qdatetime.h>
#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");
}

62
lib/rdloglock.h Normal file
View File

@ -0,0 +1,62 @@
// rdloglock.h
//
// Log locking routines for Rivendell
//
// (C) Copyright 2017 Fred Gleason <fredg@paravelsystems.com>
//
// 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 <qhostaddress.h>
#include <qobject.h>
#include <qtimer.h>
#include <rd.h>
#include <rduser.h>
#include <rdstation.h>
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

View File

@ -20,16 +20,15 @@
#include <qmessagebox.h>
#include <rdconf.h>
#include <rd.h>
#include <rdsvc.h>
#include <rddatedecode.h>
#include <rdcreate_log.h>
#include <rdclock.h>
#include <rdlog.h>
#include <rdconf.h>
#include <rdcreate_log.h>
#include <rddatedecode.h>
#include <rddb.h>
#include <rd.h>
#include <rdescape_string.h>
#include <rdlog.h>
#include <rdsvc.h>
#include <rdweb.h>
//
@ -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<int> 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;

View File

@ -27,6 +27,7 @@
#include <qsqldatabase.h>
#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;

View File

@ -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

View File

@ -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:

View File

@ -2,7 +2,7 @@
//
// The full log list for RDAirPlay
//
// (C) Copyright 2002-2006,2016 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2002-2006,2016-2017 Fred Gleason <fredg@paravelsystems.com>
//
// 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;
}
}

View File

@ -18,6 +18,7 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <qmessagebox.h>
#include <qpushbutton.h>
#include <rdadd_log.h>
@ -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;
}

View File

@ -27,6 +27,7 @@
#include <qpushbutton.h>
#include <rdlogfilter.h>
#include <rdloglock.h>
#include <log_play.h>
@ -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;
};

View File

@ -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];

View File

@ -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();

View File

@ -456,6 +456,22 @@ poslechu</translation>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -456,6 +456,22 @@ vorhören</translation>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -456,6 +456,22 @@ Final</translation>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -456,6 +456,22 @@ la Fin</translation>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -462,6 +462,22 @@ Tail</source>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -462,6 +462,22 @@ Tail</source>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -457,6 +457,22 @@ Log</source>
<source>Save As</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You must refresh the log before it can be saved.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LogLineBox</name>

View File

@ -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;i<edit_clipboard->size();i++) {
edit_clipboard->at(i).clearExternalData();
}
done(0);
done(true);
}
@ -1224,7 +1247,7 @@ void EditLog::cancelData()
for(unsigned i=0;i<edit_clipboard->size();i++) {
edit_clipboard->at(i).clearExternalData();
}
done(1);
done(false);
}

View File

@ -33,12 +33,13 @@
#include <qlabel.h>
#include <rdcart_dialog.h>
#include <rdtransportbutton.h>
#include <rdgroup_list.h>
#include <rdlog.h>
#include <rdlog_event.h>
#include <rduser.h>
#include <rdgroup_list.h>
#include <rdloglock.h>
#include <rdsimpleplayer.h>
#include <rdtransportbutton.h>
#include <rduser.h>
#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;

View File

@ -40,25 +40,25 @@
#include <qpixmap.h>
#include <qpainter.h>
#include <dbversion.h>
#include <rd.h>
#include <rdadd_log.h>
#include <rdcheck_daemons.h>
#include <rdcmd_switch.h>
#include <rdconf.h>
#include <rddb.h>
#include <rdescape_string.h>
#include <rdloglock.h>
#include <rdmixer.h>
#include <rdripc.h>
#include <rdstation.h>
#include <rdcheck_daemons.h>
//#include <rdcreate_log.h>
#include <rdadd_log.h>
#include <rdcmd_switch.h>
#include <rddb.h>
#include <rdtextfile.h>
#include <rdmixer.h>
#include <dbversion.h>
#include <rdescape_string.h>
#include <rdlogedit.h>
#include <edit_log.h>
#include <globals.h>
#include "edit_log.h"
#include "globals.h"
#include "rdlogedit.h"
#ifndef WIN32
#include <voice_tracker.h>
#include "voice_tracker.h"
#endif // WIN32
//
@ -455,8 +455,9 @@ void MainWidget::editData()
}
std::vector<QString> 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;i<items.size();i++) {
RDLog *log=new RDLog(items.at(i)->text(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;
}
}
}

View File

@ -425,6 +425,18 @@ jež jsou pro vybranou službu zakázány!</translation>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>User</source>
<translation type="obsolete">Uživatel</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -927,6 +939,14 @@ Vyhledejte svého správce systému kvůli aktualizaci!</translation>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1250,5 +1270,13 @@ therefore only existing transitions will be editable.</source>
<source>LABEL</source>
<translation type="unfinished">ŠTÍTEK</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -425,6 +425,18 @@ die für den gewählten Service ungültig sind!</translation>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>User</source>
<translation type="obsolete">Benutzer</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -926,6 +938,14 @@ See your system administrator for an update!</source>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1249,5 +1269,13 @@ therefore only existing transitions will be editable.</source>
<source>LABEL</source>
<translation type="unfinished">LABEL</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -425,6 +425,18 @@ desactivados para el servicio actual!
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>User</source>
<translation type="obsolete">Usuario</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -923,6 +935,14 @@ See your system administrator for an update!</source>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1252,5 +1272,13 @@ sólo podrás editar transiciones ya existentes.</translation>
<source>LABEL</source>
<translation type="unfinished">ETIQUETA</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -403,6 +403,14 @@ for the selected service!</source>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -843,6 +851,14 @@ See your system administrator for an update!</source>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1166,5 +1182,13 @@ therefore only existing transitions will be editable.</source>
<source>LABEL</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -432,6 +432,18 @@ skrudd av for denne tenesta!</translation>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>User</source>
<translation type="obsolete">Brukar</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -944,6 +956,14 @@ See your system administrator for an update!</source>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1267,5 +1287,13 @@ therefore only existing transitions will be editable.</source>
<source>LABEL</source>
<translation type="unfinished">SELSKAP</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -432,6 +432,18 @@ skrudd av for denne tenesta!</translation>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>User</source>
<translation type="obsolete">Brukar</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -944,6 +956,14 @@ See your system administrator for an update!</source>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1267,5 +1287,13 @@ therefore only existing transitions will be editable.</source>
<source>LABEL</source>
<translation type="unfinished">SELSKAP</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -427,6 +427,18 @@ para o serviço selecionado!</translation>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>User</source>
<translation type="obsolete">Usuário</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditLogLine</name>
@ -923,6 +935,14 @@ See your system administrator for an update!</source>
<source>Windows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>is in use by</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RenderDialog</name>
@ -1253,5 +1273,13 @@ Assim sendo, somente transições existentes serão editáveis.</translation>
<source>LABEL</source>
<translation type="unfinished">SELO</translation>
</message>
<message>
<source>Log Locked</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Log already being edited by</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -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()) {

View File

@ -2,7 +2,7 @@
//
// A Rivendell Voice Tracker
//
// (C) Copyright 2002-2006,2016 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2002-2006,2016-2017 Fred Gleason <fredg@paravelsystems.com>
//
// 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 <qcursor.h>
#include <qpopupmenu.h>
#include <rdtransportbutton.h>
#include <rdstereometer.h>
#include <rdcart.h>
#include <rdcut.h>
#include <rdevent_player.h>
#include <rdgroup.h>
#include <rdlog.h>
#include <rdlog_event.h>
#include <rdloglock.h>
#include <rdplay_deck.h>
#include <log_listview.h>
#include <rdevent_player.h>
#include <rdwavepainter.h>
#include <rdsettings.h>
#include <rdstereometer.h>
#include <rdtransportbutton.h>
#include <rdwavepainter.h>
#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

View File

@ -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));
*/
}
}

View File

@ -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()) {

View File

@ -855,6 +855,30 @@ Opětovné sloučení tato data smaže. Sloučit znovu?</translation>
<source>Generate Log - User: </source>
<translation>Vytvořit zápis - Uživatel: </translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -855,6 +855,30 @@ Einbinden wird diese entfernen. Fortfahren?</translation>
<source>Generate Log - User: </source>
<translation>Generiere Log - User: </translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -857,6 +857,30 @@ removerá estos datos. ¿Remezclar?</translation>
<source>Generate Log - User: </source>
<translation>Generar lista - Usuario: </translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -837,6 +837,30 @@ will remove this data. Remerge?</source>
<source>Generate Log - User: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -868,6 +868,30 @@ Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt?</translation>
<source>Generate Log - User: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -868,6 +868,30 @@ Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt?</translation>
<source>Generate Log - User: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -857,6 +857,30 @@ Re-agregar removerá estes dados. Re-agregar? </translation>
<source>Traffic Exists</source>
<translation>Tráfego Existente</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to generate log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear traffic links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to clear music links</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link music log</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to link traffic log</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportListView</name>

View File

@ -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;i<cmd->keys();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);
}

View File

@ -23,12 +23,25 @@
#include <qobject.h>
#include <rdripc.h>
#include <rdstation.h>
#define LOG_UNLINK_TEST_USAGE "[options]\n\nTest the Rivendell log unlinker methods\n\nOptions are:\n--log=<log-name>\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;
};

View File

@ -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;
}

View File

@ -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 {

View File

@ -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",

View File

@ -2,7 +2,7 @@
//
// A Command-line log editor for Rivendell
//
// (C) Copyright 2016 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2016-2017 Fred Gleason <fredg@paravelsystems.com>
//
// 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 <rddb.h>
#include <rdlog.h>
#include <rdlog_event.h>
#include <rdloglock.h>
#include <rdripc.h>
#include <rduser.h>
@ -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;
};

View File

@ -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

View File

@ -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);

View File

@ -24,18 +24,19 @@
#include <fcntl.h>
#include <errno.h>
#include <rdconf.h>
#include <rdcreate_log.h>
#include <rddb.h>
#include <rdescape_string.h>
#include <rdformpost.h>
#include <rdweb.h>
#include <rduser.h>
#include <rdlog.h>
#include <rdlog_event.h>
#include <rdlog_line.h>
#include <rdconf.h>
#include <rdescape_string.h>
#include <rdloglock.h>
#include <rduser.h>
#include <rdweb.h>
#include <rdxport.h>
#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+="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
xml+="<logLock>\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+="</logLock>\n";
return xml;
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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\

48
web/tests/locklog.html Normal file
View File

@ -0,0 +1,48 @@
<html>
<head>
<title>Rivendell LOCKLOG Service Test Harness</title>
<body>
<form action="/rd-bin/rdxport.cgi" method="post" enctype="multipart/form-data">
<input type="hidden" name="COMMAND" value="34">
<table cellpadding="0" cellspacing="2" border="0">
<tr>
<td align="right">LOGIN NAME:</td>
<td><input type="text" name="LOGIN_NAME" size="20" maxlength="255"></td>
</tr>
<tr>
<td align="right">PASSWORD:</td>
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr>
<tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">OPERATION:</td>
<td>
<select name="OPERATION">
<option value="CREATE">CREATE</option>
<option value="UPDATE">UPDATE</option>
<option value="CLEAR">CLEAR</option>
</select>
</td>
</tr>
<tr>
<td align="right">LOG_NAME:</td>
<td><input type="text" name="LOG_NAME" size="40" maxlength="64"></td>
</tr>
<tr>
<td align="right">LOCK_GUID:</td>
<td><input type="text" name="LOCK_GUID" size="40" maxlength="82"></td>
</tr>
<tr>
<td colspan="2" align="right">&nbsp;</td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="OK"></td>
</tr>
</table>
</form>
</body>
</html>