一个Qt写的简单加密聊天程序

Signed-off-by: dmy@lab <dmy@lab.com>
This commit is contained in:
dmy@lab 2015-04-08 23:44:53 +08:00
commit e7a06273ac
22 changed files with 938 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
LanPaper.pro.*

62
Client.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "Client.h"
Client::Client(QObject *parent) :
QObject(parent)
{
tcpSocket = new QTcpSocket(this);
connect(tcpSocket,SIGNAL(connected()),this,SLOT(connected()) );
}
void Client::sendMessage(const QString& message)
{
Secret* secret=new Secret;
QString encodedText=secret->getEncodeString(message);
this->message=encodedText;
//qDebug()<<Config::getDesIP()<<"\n";
//qDebug()<<QString(Config::getDesPort()).toInt()<<"\n";
this->tcpSocket->close();
this->startConnection();
this->socketState=QTcpSocket::ConnectingState;
this->trialCount=1;
this->timer=this->startTimer(1000);
//qDebug()<<"start timer"<<"\n";
}
void Client::connected()
{
tcpSocket->write(message.toUtf8());
tcpSocket->waitForBytesWritten(10*1000);
//tcpSocket->write("\n\n\n\n\n");
tcpSocket->waitForBytesWritten(10*1000);
this->socketState=QTcpSocket::ConnectedState;
emit this->connectionSuccess(true);
this->killTimer(this->timer);
this->tcpSocket->close();
}
void Client::startConnection()
{
//qDebug()<<Config::getDesIP()<<"\n";
this->tcpSocket->connectToHost(Config::getDesIP(),QString(Config::getDesPort()).toInt() );
}
void Client::timerEvent(QTimerEvent *e)
{
//qDebug()<<"try"<<this->trialCount<<"\n";
if(this->trialCount==6)
{
this->tcpSocket->close();
this->killTimer(this->timer);
emit this->connectionSuccess(false);
}
if(this->socketState==QTcpSocket::ConnectingState)
{
//this->tcpSocket->close();
//this->startConnection();
this->trialCount+=1;
}
}

36
Client.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include <QString>
#include <QTcpSocket>
#include <secret.h>
#include "Config.h"
#include "LanPaper.h"
class LanPaper;
class Client : public QObject
{
Q_OBJECT
public:
explicit Client(QObject *parent = 0);
void sendMessage(const QString& message);
signals:
void connectionSuccess(bool success);
private:
void startConnection();
private:
QTcpSocket* tcpSocket;
QString message;
QTcpSocket::SocketState socketState;
int trialCount;
int timer;
void timerEvent(QTimerEvent *);
public slots:
private slots:
void connected();
};
#endif // CLIENT_H

83
Config.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "Config.h"
QHash<QString,QString>* Config::hash=NULL;
Config::Config()
{
}
QString Config::getSrcIP()
{
Config::read();
if(NULL!=Config::hash&&Config::hash->contains("SrcIP"))
{
return (*hash)["SrcIP"];
}
return "";
}
QString Config::getSrcPort()
{
Config::read();
if(NULL!=Config::hash&&Config::hash->contains("SrcPort"))
{
return (*hash)["SrcPort"];
}
return "";
}
QString Config::getDesIP()
{
Config::read();
if(NULL!=Config::hash&&Config::hash->contains("DesIP"))
{
return (*hash)["DesIP"];
}
return "";
}
QString Config::getDesPort()
{
Config::read();
if(NULL!=Config::hash&&Config::hash->contains("DesPort"))
{
return (*hash)["DesPort"];
}
return "";
}
void Config::read()
{
QString filePath="./rc.svt";
if(!QFile::exists(filePath))
{
return;
}
if(Config::hash!=NULL)
{
return;
}
Config::hash=new QHash<QString,QString>;
QFile file(filePath);
QString line;
QStringList sep;
QString key;
QString value;
file.open(QFile::ReadOnly);
if(file.isOpen())
{
QTextStream reader(&file);
while( (line=reader.readLine())!=NULL)
{
sep=line.split('#');
if(sep.length()!=2)
{
continue;
}
key=sep.at(0).trimmed();
value=sep.at(1).trimmed();
if(!Config::hash->contains(key))
{
Config::hash->insert(key,value);
}
}
file.close();
}
}

21
Config.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef CONFIG_H
#define CONFIG_H
#include<QHash>
#include <QString>
#include <QTextStream>
#include <QFile>
#include <QStringList>
class Config
{
public:
Config();
static QString getSrcIP();
static QString getSrcPort();
static QString getDesIP();
static QString getDesPort();
static void read();
private:
static QHash<QString,QString>* hash;
};
#endif // CONFIG_H

148
LanPaper.cpp Normal file
View File

@ -0,0 +1,148 @@
#include "LanPaper.h"
LanPaper::LanPaper(QWidget *parent) :
QMainWindow(parent),server(new Server(this))
{
setupUi(this);
this->server->listen(QHostAddress(Config::getSrcIP()),QString(Config::getSrcPort()).toInt() );
//install message key filter
this->pTEMessage->installEventFilter(this);
this->installEventFilter(this);
this->trayIco=new TrayIco(this);
connect(this->actionAbout,SIGNAL(triggered()),this,SLOT(aboutClick()) );
QScrollBar* scrollBar=this->pTEChatText->verticalScrollBar();
scrollBar->setTracking(true);
}
void LanPaper::addChatContentToThereSide(const QString& content)
{
QTime time=QTime::currentTime();
QString displayTime=QString("%1:%2:%3").arg(time.hour()).arg(time.minute()).arg(time.second());
this->pTEChatText->appendPlainText(displayTime+":There");
this->pTEChatText->appendPlainText(content);
this->pTEChatText->appendPlainText(" ");
if(this->isHidden()||this->isMinimized()||!this->isWindowsActivated())
{
this->trayIco->setFlash(true);
}
this->scrollToBottom();
}
QString LanPaper::getMessage()
{
return this->pTEMessage->toPlainText();
}
void LanPaper::on_pBTSendMessage_clicked()
{
QString text=this->pTEMessage->toPlainText();
if(text.trimmed()=="")
{
QMessageBox::information(this,"warning","no empty message allowed.");
return;
}
this->addChatContentToMeSide(text);
this->client=new Client(this);
connect(this->client,SIGNAL(connectionSuccess(bool)),this,SLOT(clientSuccess(bool)) );
this->client->sendMessage(text);
this->pBTSendMessage->setEnabled(false);
}
void LanPaper::addChatContentToMeSide(const QString& content)
{
QTime time=QTime::currentTime();
QString displayTime=QString("%1:%2:%3").arg(time.hour()).arg(time.minute()).arg(time.second());
this->pTEChatText->appendPlainText(" Me:"+displayTime);
this->pTEChatText->appendPlainText(" "+content);
this->pTEChatText->appendPlainText(" ");
this->scrollToBottom();
}
bool LanPaper::eventFilter(QObject *obj, QEvent *event)
{
if(obj==this->pTEMessage)
{
if(event->type()==QEvent::KeyPress)
{
QKeyEvent* keyEvent=(QKeyEvent*)event;
if(keyEvent->key()==Qt::Key_Return||keyEvent->key()==Qt::Key_Enter)
{
this->on_pBTSendMessage_clicked();
event->accept();
return true;
}
}
}
if(obj==this)
{
if(event->type()==QEvent::WindowActivate)
{
this->trayIco->setFlash(false);
}
}
return false;
}
void LanPaper::changeEvent(QEvent *e)
{
if((e->type()==QEvent::WindowStateChange)&&this->isMinimized())
{
this->hide();
}
}
void LanPaper::aboutClick()
{
QString srcIP=Config::getSrcIP();
QString srcPort=Config::getSrcPort();
QString desIP=Config::getDesIP();
QString desPort=Config::getDesPort();
QString info;
info=QString("src %1:%2\n des %3:%4").arg(srcIP).arg(srcPort).arg(desIP).arg(desPort);
QMessageBox::about(this,"about",info);
}
void LanPaper::clientSuccess(bool success)
{
if(success)
{
this->pTEMessage->setPlainText("");
}
else
{
QMessageBox::warning(this,"warning","message send failed.");
}
this->pBTSendMessage->setEnabled(true);
this->pTEMessage->setFocus();
this->client->deleteLater();
}
bool LanPaper::isWindowsActivated()
{
if(this->isActiveWindow())
{
return true;
}
if(this->pTEChatText->isActiveWindow())
{
return true;
}
if(this->pTEChatText->isActiveWindow())
{
return true;
}
return false;
}
void LanPaper::scrollToBottom()
{
QScrollBar* scrollBar=this->pTEChatText->verticalScrollBar();
scrollBar->setValue(scrollBar->maximum());
}

44
LanPaper.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef LANPAPER_H
#define LANPAPER_H
#include "Server.h"
#include "ui_LanPaper.h"
#include <QHostAddress>
#include "Client.h"
#include <QTime>
#include <QKeyEvent>
#include "TrayIco.h"
#include "Config.h"
#include <QScrollBar>
//#include "Secret.h"
class Server;
class TrayIco;
class Client;
class LanPaper : public QMainWindow, private Ui::LanPaper
{
Q_OBJECT
public:
explicit LanPaper(QWidget *parent = 0);
void addChatContentToThereSide(const QString &content);
QString getMessage();
private:
void addChatContentToMeSide(const QString& content);
virtual bool eventFilter(QObject *, QEvent *);
virtual void changeEvent(QEvent *);
bool isWindowsActivated();
void scrollToBottom();
private slots:
void on_pBTSendMessage_clicked();
void aboutClick();
void clientSuccess(bool success);
private:
Server* server;
TrayIco* trayIco;
Client *client;
};
#endif // LANPAPER_H

40
LanPaper.pro Normal file
View File

@ -0,0 +1,40 @@
#-------------------------------------------------
#
# Project created by QtCreator 2013-12-01T10:03:18
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = LanPaper
TEMPLATE = app
LIBS+=-static
#LIBS+=C:/Qt5Lib/plugins/imageformats/libqico.a
SOURCES += main.cpp\
LanPaper.cpp \
Server.cpp \
ThreadedServerConnection.cpp \
Client.cpp \
TrayIco.cpp \
Secret.cpp \
Config.cpp
HEADERS += LanPaper.h \
Server.h \
ThreadedServerConnection.h \
Client.h \
TrayIco.h \
Secret.h \
Config.h
FORMS += LanPaper.ui
RESOURCES += \
resource.qrc
#QTPLUGIN+=qico
#CONFIG += staticlib

81
LanPaper.ui Normal file
View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LanPaper</class>
<widget class="QMainWindow" name="LanPaper">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>582</width>
<height>706</height>
</rect>
</property>
<property name="windowTitle">
<string>LanPaper</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QPlainTextEdit" name="pTEChatText">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>281</width>
<height>631</height>
</rect>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<widget class="QPlainTextEdit" name="pTEMessage">
<property name="geometry">
<rect>
<x>310</x>
<y>30</y>
<width>261</width>
<height>121</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pBTSendMessage">
<property name="geometry">
<rect>
<x>400</x>
<y>160</y>
<width>91</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>Send</string>
</property>
</widget>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>582</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuAbout">
<property name="title">
<string>More</string>
</property>
<addaction name="actionAbout"/>
</widget>
<addaction name="menuAbout"/>
</widget>
<action name="actionAbout">
<property name="text">
<string>about</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

133
Secret.cpp Normal file
View File

@ -0,0 +1,133 @@
#include "Secret.h"
Secret::Secret():
secretkey(NULL)
{
this->secretkey=new char[36];
this->secretkey[0]=0x2b;
this->secretkey[1]=0xef;
this->secretkey[2]=0x33;
this->secretkey[3]=0xaf;
this->secretkey[4]=0x2b;
this->secretkey[5]=0x4c;
this->secretkey[6]=0x91;
this->secretkey[7]=0xb6;
this->secretkey[8]=0xac;
this->secretkey[9]=0xe5;
this->secretkey[10]=0xca;
this->secretkey[11]=0x21;
this->secretkey[12]=0xc4;
this->secretkey[13]=0xb5;
this->secretkey[14]=0xbe;
this->secretkey[15]=0x5d;
this->secretkey[16]=0x7c;
this->secretkey[17]=0x3c;
this->secretkey[18]=0xc3;
this->secretkey[19]=0x16;
this->secretkey[20]=0x29;
this->secretkey[21]=0x7b;
this->secretkey[22]=0x8a;
this->secretkey[23]=0x99;
this->secretkey[24]=0x3e;
this->secretkey[25]=0x90;
this->secretkey[26]=0xce;
this->secretkey[27]=0x37;
this->secretkey[28]=0xf8;
this->secretkey[29]=0x8f;
this->secretkey[30]=0xec;
this->secretkey[31]=0x84;
this->secretkey[32]=0xcf;
this->secretkey[33]=0xf1;
this->secretkey[34]=0x74;
this->secretkey[35]=0x26;
}
Secret::~Secret()
{
if(NULL!=this->secretkey)
{
delete[] this->secretkey;
}
}
QByteArray Secret::getEncodeString(const QString& str)
{
QByteArray data(str.toUtf8());
QDate currentDate=QDate::currentDate();
int day;
day=currentDate.day()%16+1;
QByteArray newData;
int keyInd=0;
//newData.reserve(data.size()+data.size()/day+10);
for(int i=0;i<data.size();i++)
{
newData.push_back( (data.at(i)^(this->secretkey[keyInd%36]) )+500);
keyInd++;
//qDebug()<<this->secretkey[keyInd%1]<<"\n";
//newData.push_back( (data.at(i))+00);
if(i%day==0)
{
QTime t;
t= QTime::currentTime();
for(int k=0;k<3;k++)
{
qsrand(t.msec()+t.second()*1000);
int n = qrand();
QByteArray md5=QCryptographicHash::hash(QString("%1").arg(n).toLatin1(), QCryptographicHash::Md5);
newData.push_back(md5[0]);
newData.push_back(md5[1]);
newData.push_back(md5[2]);
newData.push_back(md5[3]);
newData.push_back(md5[4]);
newData.push_back(md5[5]);
qsrand(t.msec()+t.second()*1000+n);
md5=QCryptographicHash::hash(QString("%1").arg(n).toLatin1(), QCryptographicHash::Md5);
newData.push_back(md5[6]);
newData.push_back(md5[7]);
newData.push_back(md5[8]);
newData.push_back(md5[9]);
newData.push_back(md5[10]);
newData.push_back(md5[11]);
md5=QCryptographicHash::hash(QString("%1").arg(n).toLatin1(), QCryptographicHash::Md5);
newData.push_back(md5[12]);
newData.push_back(md5[0]);
newData.push_back(md5[2]);
newData.push_back(md5[4]);
newData.push_back(md5[6]);
newData.push_back(md5[8]);
}
}
}
return newData.toHex();
}
QString Secret::getDecodeString(const QByteArray& code)
{
QByteArray data=QByteArray::fromHex(code);
QByteArray newData;
QDate currentDate=QDate::currentDate();
int day;
day=currentDate.day()%16+1;
int keyInd=0;
for(int i=0;i<data.size();i++)
{
if(i<data.size())
{
newData.push_back( (data.at(i)-500)^(this->secretkey[keyInd%36]));
keyInd++;
}
if(i%day==0)
{
i+=54;
continue;
}
}
//return data;
return QString(newData);
}

21
Secret.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef SECRET_H
#define SECRET_H
#include <QString>
#include <QByteArray>
#include <QDate>
#include <QDebug>
#include <QCryptographicHash>
class Secret
{
public:
Secret();
~Secret();
QByteArray getEncodeString(const QString& str);
QString getDecodeString(const QByteArray& code);
private:
char* secretkey;
};
#endif // SECRET_H

73
Server.cpp Normal file
View File

@ -0,0 +1,73 @@
#include "Server.h"
Server::Server(QObject *parent) :
QTcpServer(parent)
{
connect(this,SIGNAL(newConnection()), this,SLOT(newConnection()) );
}
void Server::newConnection()
{
this->tcpSocket=this->nextPendingConnection();
if(this->tcpSocket!=NULL)
{
this->tcpSocket=tcpSocket;
connect(this->tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead()) );
}
else
{
QMessageBox::aboutQt(0);
}
}
void Server::readyRead()
{
QByteArray data=this->tcpSocket->readAll();
if(this->receivedData.size()==0)//first section of data
{
this->timer=this->startTimer(1000*10);
}
this->receivedData.push_back(data);
// char a1=data.at(data.size()-1);
// char a2=data.at(data.size()-2);
// char a3=data.at(data.size()-3);
// char a4=data.at(data.size()-4);
// char a5=data.at(data.size()-5);
if(this->tcpSocket->atEnd())
//if(data.at(data.size()-1)=='\n'&&data.at(data.size()-2)=='\n'&&data.at(data.size()-3)=='\n'&&data.at(data.size()-4)=='\n'&&data.at(data.size()-5)=='\n')
{
//this->receivedData.remove(this->receivedData.size()-5,5);
// QByteArray f=this->receivedData;
LanPaper *mainWin=(LanPaper *)(this->parent());
if(NULL!=mainWin)
{
//tcpSocket->waitForReadyRead(5*1000);
//qDebug()<<"read buff"<<this->tcpSocket->readBufferSize()<<"\n";
//this->tcpSocket->setReadBufferSize(1024*100);
//QByteArray data=this->tcpSocket->readAll();
//qDebug()<<data.size()<<"\n";
Secret secret;
QString decodedText=secret.getDecodeString(this->receivedData);
mainWin->addChatContentToThereSide(decodedText);
this->resetConnection();
this->killTimer(this->timer);
}
}
}
void Server::timerEvent(QTimerEvent *e)
{
this->killTimer(this->timer);
this->resetConnection();
//qDebug()<<"recei failed\n";
}
void Server::resetConnection()
{
this->receivedData.clear();
this->tcpSocket->close();
this->tcpSocket->deleteLater();
}

31
Server.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QTcpServer>
#include "LanPaper.h"
#include "ThreadedServerConnection.h"
#include <QMessageBox>
#include "Secret.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
private:
virtual void timerEvent(QTimerEvent *);
void resetConnection();
private:
QByteArray receivedData;
int timer;
protected:
QTcpSocket* tcpSocket;
signals:
public slots:
private slots:
void newConnection();
void readyRead();
};
#endif // SERVER_H

View File

@ -0,0 +1,30 @@
#include "ThreadedServerConnection.h"
ThreadedServerConnection::ThreadedServerConnection(int socketDescriptor, const QString &fortune, QObject *parent) :
QThread(parent), socketDescriptor(socketDescriptor), text(fortune)
{
}
void ThreadedServerConnection::run()
{
QTcpSocket tcpSocket;
//! [1] //! [2]
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
return;
}
//! [2] //! [3]
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_1);
//out << (quint16)0;
out << text;
//out.device()->seek(0);
//out << (quint16)(block.size() - sizeof(quint16));
//! [3] //! [4]
tcpSocket.write(block);
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
}

View File

@ -0,0 +1,23 @@
#ifndef THREADEDSERVERCONNECTION_H
#define THREADEDSERVERCONNECTION_H
#include <QObject>
#include <QThread>
#include <QTcpSocket>
#include <QDataStream>
class ThreadedServerConnection : public QThread
{
Q_OBJECT
public:
explicit ThreadedServerConnection(int socketDescriptor, const QString &fortune, QObject *parent=0);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
private:
int socketDescriptor;
QString text;
public slots:
};
#endif // THREADEDSERVERCONNECTION_H

56
TrayIco.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "TrayIco.h"
TrayIco::TrayIco(QObject *parent) :
QObject(parent),normalIcon(":/ico/smileico"),flashIcon(":/ico/flashsmileico"),timer(0)
//QObject(parent),normalIcon("c:/bpa/emoticon.ico"),flashIcon("c:/bpa/big_smile.ico"),timer(0)
{
this->trayIco.setIcon(this->normalIcon);
this->trayIco.show();
connect(&this->trayIco,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(activated(QSystemTrayIcon::ActivationReason)) );
}
void TrayIco::activated(QSystemTrayIcon::ActivationReason reason)
{
if(reason==QSystemTrayIcon::Trigger)
{
LanPaper *mainWin=(LanPaper *)this->parent();
this->setFlash(false);
mainWin->showNormal();
mainWin->activateWindow();
}
}
void TrayIco::setFlash(bool flash)
{
if(flash)
{
if(this->timer!=0)
{
return;
}
this->flashFlag=true;
this->timer=this->startTimer(500);
}
else
{
this->trayIco.setIcon(this->normalIcon);
this->killTimer(this->timer);
this->timer=0;
}
}
void TrayIco::timerEvent(QTimerEvent *e)
{
if(this->flashFlag)
{
this->trayIco.setIcon(this->flashIcon);
this->flashFlag=false;
}
else
{
this->trayIco.setIcon(this->normalIcon);
this->flashFlag=true;
}
}

31
TrayIco.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef TRAYICO_H
#define TRAYICO_H
#include "LanPaper.h"
#include <QObject>
#include <QSystemTrayIcon>
#include <QIcon>
class TrayIco : public QObject
{
Q_OBJECT
public:
explicit TrayIco(QObject *parent = 0);
void setFlash(bool);
private:
void timerEvent(QTimerEvent *);
private:
QSystemTrayIcon trayIco;
QIcon normalIcon;
QIcon flashIcon;
int timer;
bool flashFlag;
signals:
public slots:
private slots:
void activated(QSystemTrayIcon::ActivationReason);
};
#endif // TRAYICO_H

BIN
big_smile.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
emoticon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

14
main.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "LanPaper.h"
#include <QApplication>
//#include <QtPlugin>
//Q_IMPORT_PLUGIN(qico)
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LanPaper w;
w.show();
return a.exec();
}

4
rc.svt Normal file
View File

@ -0,0 +1,4 @@
SrcIP#localhost
SrcPort#100
DesIP#12.21.12.21
DesPort#100

6
resource.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/ico">
<file alias="smileico">emoticon.ico</file>
<file alias="flashsmileico">big_smile.ico</file>
</qresource>
</RCC>