2018-07-31 Fred Gleason <fredg@paravelsystems.com>

* Fixed bugs in 'RDCmdSwitch' that caused corruption in UTF-8
	strings.
	* Refactored rmlsend(1) to handle UTF-8 strings correctly.
This commit is contained in:
Fred Gleason 2018-07-31 08:42:05 -04:00
parent ad639bc79e
commit dbb0d9c415
4 changed files with 113 additions and 110 deletions

View File

@ -17283,3 +17283,7 @@
'RDAudioStore', 'RDCart', 'RDCopyAudio', 'RDPeakExport', 'RDAudioStore', 'RDCart', 'RDCopyAudio', 'RDPeakExport',
'RDRehash', and 'RDTrimAudio' that caused credentials encoded in 'RDRehash', and 'RDTrimAudio' that caused credentials encoded in
UTF-8 to be corrupted. UTF-8 to be corrupted.
2018-07-31 Fred Gleason <fredg@paravelsystems.com>
* Fixed bugs in 'RDCmdSwitch' that caused corruption in UTF-8
strings.
* Refactored rmlsend(1) to handle UTF-8 strings correctly.

View File

@ -29,38 +29,35 @@
RDCmdSwitch::RDCmdSwitch(int argc,char *argv[],const char *modname, RDCmdSwitch::RDCmdSwitch(int argc,char *argv[],const char *modname,
const char *usage) const char *usage)
{ {
unsigned l=0;
bool handled=false;
bool debug=false; bool debug=false;
for(int i=1;i<argc;i++) { for(int i=1;i<argc;i++) {
QString value=QString::fromUtf8(argv[i]);
#ifndef WIN32 #ifndef WIN32
if(!strcmp(argv[i],"--version")) { if(value=="--version") {
printf("Rivendell v%s [%s]\n",VERSION,modname); printf("Rivendell v%s [%s]\n",VERSION,modname);
exit(0); exit(0);
} }
#endif // WIN32 #endif // WIN32
if(!strcmp(argv[i],"--help")) { if(value=="--help") {
printf("\n%s %s\n",modname,usage); printf("\n%s %s\n",modname,usage);
exit(0); exit(0);
} }
if(!strcmp(argv[i],"-d")) { if(value=="-d") {
debug=true; debug=true;
} }
l=strlen(argv[i]); QStringList f0=f0.split("=",value,true);
handled=false; if(f0.size()>=2) {
for(unsigned j=0;j<l;j++) { switch_keys.push_back(f0[0]);
if(argv[i][j]=='=') { for(unsigned i=2;i<f0.size();i++) {
switch_keys.push_back(QString(argv[i]).left(j)); f0[1]+="="+f0[i];
switch_values.push_back(QString(argv[i]).right(l-(j+1)));
switch_processed.push_back(false);
j=l;
handled=true;
} }
switch_values.push_back(f0[1]);
switch_processed.push_back(false);
} }
if(!handled) { else {
switch_keys.push_back(QString(argv[i])); switch_keys.push_back(value);
switch_values.push_back(QString("")); switch_values.push_back("");
switch_processed.push_back(false); switch_processed.push_back(false);
} }
} }

View File

@ -2,7 +2,7 @@
// //
// A utility for sending RML Commands // A utility for sending RML Commands
// //
// (C) Copyright 2002-2005,2016 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2002-2005,2016-2018 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License version 2 as
@ -100,10 +100,10 @@ MainWidget::MainWidget(QWidget *parent)
setCaption(QString("RMLSend")+" v"+VERSION+" - "+tr("Macro Command Utility")); setCaption(QString("RMLSend")+" v"+VERSION+" - "+tr("Macro Command Utility"));
host=new QLineEdit(this,"host"); host=new QLineEdit(this);
host->setGeometry(80,10,180,25); host->setGeometry(80,10,180,25);
host->setFont(main_font); host->setFont(main_font);
QLabel *label=new QLabel(host,"Sent To:",this,"host_label"); QLabel *label=new QLabel(host,"Sent To:",this);
label->setGeometry(10,16,65,14); label->setGeometry(10,16,65,14);
label->setFont(label_font); label->setFont(label_font);
label->setAlignment(AlignRight); label->setAlignment(AlignRight);
@ -114,10 +114,10 @@ MainWidget::MainWidget(QWidget *parent)
} }
} }
port_box=new QComboBox(this,"port_box"); port_box=new QComboBox(this);
port_box->setGeometry(305,10,130,25); port_box->setGeometry(305,10,130,25);
port_box->setEditable(false); port_box->setEditable(false);
label=new QLabel(port_box,"Dest:",this,"port_label"); label=new QLabel(port_box,"Dest:",this);
label->setGeometry(270,16,30,14); label->setGeometry(270,16,30,14);
label->setFont(label_font); label->setFont(label_font);
label->setAlignment(AlignRight); label->setAlignment(AlignRight);
@ -127,33 +127,33 @@ MainWidget::MainWidget(QWidget *parent)
port_box->setCurrentItem(1); port_box->setCurrentItem(1);
connect(port_box,SIGNAL(activated(int)),this,SLOT(destChangedData(int))); connect(port_box,SIGNAL(activated(int)),this,SLOT(destChangedData(int)));
port_edit=new QLineEdit(this,"port_edit"); port_edit=new QLineEdit(this);
port_edit->setGeometry(sizeHint().width()-60,10,50,25); port_edit->setGeometry(sizeHint().width()-60,10,50,25);
port_edit->setFont(main_font); port_edit->setFont(main_font);
port_edit->setDisabled(true); port_edit->setDisabled(true);
port_edit_label=new QLabel(port_edit,tr("UDP Port:"),this,"port_edit_label"); port_edit_label=new QLabel(port_edit,tr("UDP Port:"),this);
port_edit_label->setGeometry(sizeHint().width()-130,16,65,14); port_edit_label->setGeometry(sizeHint().width()-130,16,65,14);
port_edit_label->setFont(label_font); port_edit_label->setFont(label_font);
port_edit_label->setAlignment(AlignRight); port_edit_label->setAlignment(AlignRight);
port_edit_label->setDisabled(true); port_edit_label->setDisabled(true);
command=new QLineEdit(this,"command"); command=new QLineEdit(this);
command->setGeometry(80,40,sizeHint().width()-90,25); command->setGeometry(80,40,sizeHint().width()-90,25);
command->setFont(main_font); command->setFont(main_font);
label=new QLabel(command,tr("Command:"),this,"host_label"); label=new QLabel(command,tr("Command:"),this);
label->setGeometry(10,46,65,14); label->setGeometry(10,46,65,14);
label->setFont(label_font); label->setFont(label_font);
label->setAlignment(AlignRight); label->setAlignment(AlignRight);
response=new QLineEdit(this,"response"); response=new QLineEdit(this);
response->setGeometry(80,70,sizeHint().width()-90,25); response->setGeometry(80,70,sizeHint().width()-90,25);
response->setFont(main_font); response->setFont(main_font);
response_label=new QLabel(response,tr("Response:"),this,"response_label"); response_label=new QLabel(response,tr("Response:"),this);
response_label->setGeometry(10,76,65,14); response_label->setGeometry(10,76,65,14);
response_label->setFont(label_font); response_label->setFont(label_font);
response_label->setAlignment(AlignRight); response_label->setAlignment(AlignRight);
send=new QPushButton(tr("&Send Command"),this,"send"); send=new QPushButton(tr("&Send Command"),this);
send->setGeometry(10,sizeHint().height()-50,120,40); send->setGeometry(10,sizeHint().height()-50,120,40);
send->setFont(main_font); send->setFont(main_font);
connect(send,SIGNAL(clicked()),this,SLOT(sendCommand())); connect(send,SIGNAL(clicked()),this,SLOT(sendCommand()));
@ -186,18 +186,18 @@ MainWidget::MainWidget(QWidget *parent)
port=rdcmdswitch->value(i).toUInt(&ok); port=rdcmdswitch->value(i).toUInt(&ok);
if(ok&&(port<0xFFFF)) { if(ok&&(port<0xFFFF)) {
switch(rdcmdswitch->value(i).toUInt()) { switch(rdcmdswitch->value(i).toUInt()) {
case RD_RML_ECHO_PORT: case RD_RML_ECHO_PORT:
port_box->setCurrentItem(0); port_box->setCurrentItem(0);
break; break;
case RD_RML_NOECHO_PORT: case RD_RML_NOECHO_PORT:
port_box->setCurrentItem(1); port_box->setCurrentItem(1);
break; break;
default: default:
port_box->setCurrentItem(2); port_box->setCurrentItem(2);
port_edit->setText(rdcmdswitch->value(i)); port_edit->setText(rdcmdswitch->value(i));
break; break;
} }
} }
} }
@ -225,22 +225,21 @@ void MainWidget::sendCommand()
bool ok=true; bool ok=true;
switch((MainWidget::DestMode)port_box->currentItem()) { switch((MainWidget::DestMode)port_box->currentItem()) {
case MainWidget::Rml: case MainWidget::Rml:
port=RD_RML_ECHO_PORT; port=RD_RML_ECHO_PORT;
break; break;
case MainWidget::RmlNoEcho: case MainWidget::RmlNoEcho:
port=RD_RML_NOECHO_PORT; port=RD_RML_NOECHO_PORT;
break; break;
case MainWidget::Manual: case MainWidget::Manual:
port=port_edit->text().toInt(&ok); port=port_edit->text().toInt(&ok);
if((!ok)||(port>0xFFFF)) { if((!ok)||(port>0xFFFF)) {
QMessageBox::information(this,tr("RMLSend"), QMessageBox::information(this,tr("RMLSend"),tr("Invalid Port Number!"));
tr("Invalid Port Number!")); return;
return; }
} break;
break;
} }
response->setText(""); response->setText("");
#ifndef WIN32 #ifndef WIN32
@ -261,7 +260,7 @@ void MainWidget::sendCommand()
host_addr.setAddress(host->text()); host_addr.setAddress(host->text());
#endif // WIN32 #endif // WIN32
dcl_command=command->text(); dcl_command=command->text();
if(!udp_command->writeBlock(dcl_command,dcl_command.length(), if(!udp_command->writeBlock(dcl_command.utf8(),dcl_command.utf8().length(),
host_addr,(Q_UINT16)port)) { host_addr,(Q_UINT16)port)) {
QMessageBox::warning(this,tr("RMLSend"),tr("Connection Failed!")); QMessageBox::warning(this,tr("RMLSend"),tr("Connection Failed!"));
return; return;
@ -299,31 +298,31 @@ void MainWidget::readResponse()
void MainWidget::destChangedData(int id) void MainWidget::destChangedData(int id)
{ {
switch((MainWidget::DestMode)id) { switch((MainWidget::DestMode)id) {
case MainWidget::Rml: case MainWidget::Rml:
port_edit->setDisabled(true); port_edit->setDisabled(true);
port_edit_label->setDisabled(true); port_edit_label->setDisabled(true);
response->setEnabled(true); response->setEnabled(true);
response_label->setEnabled(true); response_label->setEnabled(true);
timer->start(100); timer->start(100);
break; break;
case MainWidget::RmlNoEcho: case MainWidget::RmlNoEcho:
port_edit->setDisabled(true); port_edit->setDisabled(true);
port_edit_label->setDisabled(true); port_edit_label->setDisabled(true);
response->setText(""); response->setText("");
response->setDisabled(true); response->setDisabled(true);
response_label->setDisabled(true); response_label->setDisabled(true);
timer->stop(); timer->stop();
break; break;
case MainWidget::Manual: case MainWidget::Manual:
port_edit->setEnabled(true); port_edit->setEnabled(true);
port_edit_label->setEnabled(true); port_edit_label->setEnabled(true);
response->setText(""); response->setText("");
response->setDisabled(true); response->setDisabled(true);
response_label->setDisabled(true); response_label->setDisabled(true);
timer->stop(); timer->stop();
break; break;
} }
} }
@ -331,6 +330,7 @@ void MainWidget::destChangedData(int id)
MainObject::MainObject(QObject *parent,const char *name) MainObject::MainObject(QObject *parent,const char *name)
{ {
input_fd=-1; input_fd=-1;
input_stream=NULL;
dest_hostname=RMLSEND_DEFAULT_ADDR; dest_hostname=RMLSEND_DEFAULT_ADDR;
dest_port=RMLSEND_DEFAULT_PORT; dest_port=RMLSEND_DEFAULT_PORT;
rml_ptr=0; rml_ptr=0;
@ -380,13 +380,6 @@ void MainObject::ReadSwitches()
rdcmdswitch->setProcessed(rdcmdswitch->keys()-1,true); rdcmdswitch->setProcessed(rdcmdswitch->keys()-1,true);
rml_cmd=rdcmdswitch->key(rdcmdswitch->keys()-1); rml_cmd=rdcmdswitch->key(rdcmdswitch->keys()-1);
} }
for(unsigned i=0;i<rdcmdswitch->keys();i++) {
if(!rdcmdswitch->processed(i)) {
printf("\nrmlsend %s\n",RMLSEND_USAGE);
exit(256);
}
}
} }
@ -411,18 +404,22 @@ void MainObject::ResolveName()
void MainObject::InitStream() void MainObject::InitStream()
{ {
if(!rml_cmd.isNull()) { FILE *f=NULL;
if(!rml_cmd.isEmpty()) {
return; return;
} }
if(input_file=="-") { if(input_file=="-") {
input_fd=0; f=stdin;
} }
else { else {
if((input_fd=open(input_file,O_RDONLY))<0) { if((f=fopen(input_file,"r"))==NULL) {
perror("rmlsend"); perror("rmlsend");
exit(256); exit(1);
} }
} }
input_stream=new QTextStream(f,IO_ReadOnly);
input_stream->setEncoding(QTextStream::UnicodeUTF8);
} }
@ -434,52 +431,55 @@ void MainObject::CloseStream()
} }
bool MainObject::GetNextChar(char *c) bool MainObject::GetNextChar(QChar *c)
{ {
if(input_stream!=NULL) {
if(input_stream->atEnd()) {
return true;
}
*input_stream >> *c;
return false;
}
/*
if(rml_cmd.isNull()) { if(rml_cmd.isNull()) {
if(read(input_fd,c,1)<=0) { if(read(input_fd,c,1)<=0) {
return true; return true;
} }
return false; return false;
} }
*/
if(rml_ptr>=rml_cmd.length()) { if(rml_ptr>=rml_cmd.length()) {
return true; return true;
} }
*c=rml_cmd.at(rml_ptr++).latin1(); *c=rml_cmd.at(rml_ptr++);
return false; return false;
} }
void MainObject::ProcessCommands() void MainObject::ProcessCommands()
{ {
char c; QChar c;
QSocketDevice *udp_command=new QSocketDevice(QSocketDevice::Datagram); QSocketDevice *udp_command=new QSocketDevice(QSocketDevice::Datagram);
char rml[RD_RML_MAX_LENGTH]; QString rml="";
unsigned ptr=0;
bool active=false; bool active=false;
while(!GetNextChar(&c)) { while(!GetNextChar(&c)) {
if(active) { if(active) {
if(c=='!') { if(c=='!') {
rml[ptr++]=c; rml+=c;
rml[ptr]=0; udp_command->writeBlock(rml.utf8(),rml.utf8().length(),
udp_command->writeBlock(rml,ptr,*dest_addr,dest_port); *dest_addr,dest_port);
ptr=0; rml="";
active=false; active=false;
} }
else { else {
rml[ptr++]=c; rml+=c;
}
if(ptr==RD_RML_MAX_LENGTH) {
fprintf(stderr,"rmlsend: rml command too long\n");
CloseStream();
exit(256);
} }
} }
else { else {
if(isalpha(c)) { if(c.isLetterOrNumber()) {
rml[ptr++]=c; rml+=c;
active=true; active=true;
} }
} }

View File

@ -21,14 +21,15 @@
#ifndef RMLSEND_H #ifndef RMLSEND_H
#define RMLSEND_H #define RMLSEND_H
#include <qcombobox.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qmainwindow.h> #include <qmainwindow.h>
#include <qpushbutton.h>
#include <qsize.h> #include <qsize.h>
#include <qsizepolicy.h> #include <qsizepolicy.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qcombobox.h>
#include <qsocketdevice.h> #include <qsocketdevice.h>
#include <qlabel.h> #include <qtextstream.h>
#include <qtimer.h> #include <qtimer.h>
#include <rd.h> #include <rd.h>
@ -82,10 +83,11 @@ class MainObject : public QObject
void ResolveName(); void ResolveName();
void InitStream(); void InitStream();
void CloseStream(); void CloseStream();
bool GetNextChar(char *c); bool GetNextChar(QChar *c);
void ProcessCommands(); void ProcessCommands();
int input_fd; int input_fd;
QString input_file; QString input_file;
QTextStream *input_stream;
QString dest_hostname; QString dest_hostname;
QHostAddress *dest_addr; QHostAddress *dest_addr;
unsigned dest_port; unsigned dest_port;