写信:
一.在邮件编辑界面(在IMMailWriteWidget文件中定义)中编辑好信件,点击发送按钮,发出clicked信号
二.IMMailWriteWidget捕获到这个信号,调用槽函数onClickBtnSend
connect(m_btnSend, SIGNAL(clicked()),
this, SLOT(onClickBtnSend()));
三.在槽函数onClickBtnSend中调用getMailInformation函数取得消息输入框的信息,再让邮件控制器类IMMailCtrl调用requestSendMail函数
void IMMailWriteWidget::onClickBtnSend()
{
if (m_leReceiverAddress->text().isEmpty())
{
QMessageBox::about(NULL, tr("提示"), tr("收件人不能为空!"));
return;
}
if (m_leReceiverAddress->text().compare(m_myID) == 0)
{
QMessageBox::about(NULL, tr("提示"), tr("不能给自己发送邮件!"));
return;
}
if (m_leTheme->text().isEmpty())
{
QMessageBox::about(NULL, tr("提示"), tr("信件主题不能为空"));
return;
}
if (m_textInput->toPlainText().isEmpty())
{
QMessageBox::about(NULL, tr("提示"), tr("信件内容不能为空!"));
return;
}
// 获取信息输入框的信息
getMailInformation();
m_mailCtrl->requestSendMail(m_mail);
}
四.requestSendMail函数通过socket与服务器通信(并把消息类型标记为SEND_MAIL)
void IMMailCtrl::requestSendMail(const MailInformation &mail)
{
qDebug() << "send mail: " << mail.m_theme;
if (NULL == m_tcpSocket)
return;
m_blockSize = 0;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_8);
out << quint16(0) << int(SEND_MAIL) << mail;
out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));
m_tcpSocket->write(block);
}
服务器:
一.在客户端通信类(在IMClientSocket类中定义)的receiveMessage函数中识别到SEND_MAIL, 发出sendSignal信号
connect(this, &IMClientSocketCtrl::readyRead,
this, &IMClientSocketCtrl::receiveMessage);
connect(this, &IMClientSocketCtrl::disconnected,
this, &IMClientSocketCtrl::deleteScoket);
void IMClientSocketCtrl::receiveMessage()
{
switch (m_save.m_requestKind)
{
case SEND_MAIL:
{
in >> m_save.m_mail;
break;
}
}
emit sendSignal(m_save);
}
二.服务器类(在IMTcpServer类中定义)捕获到这个信号,调用sendMessage槽函数进行处理
connect(clientScoket, &IMClientSocketCtrl::sendSignal,
this, &IMTcpServer::sendMessage);
connect(clientScoket, &IMClientSocketCtrl::deleteSignal,
this, &IMTcpServer::clientDisconnected);
三.sendMessage识别到SEND_MAIL,通过操作数据库类(在IMDatabase中定义)往数据库中插入一条邮件记录,如果成功就返回SEND_MAIL_SUCCESS到relyKind,然后通过socket给发信方发送消息,告诉发信方信已成功发出。然后在服务器的邮箱用户表中找到收信人的socket, 把信件发送给收信人
int IMDatabaseCtrl::insertMail(MailInformation & mail)
{
if (!createConnection())
{
return SEND_MAIL_FAIL;
}
//sql 事务
QSqlDatabase::database().transaction();
QSqlQuery query(*m_db);
query.prepare(INSERT_MAIL_IN_MAIL);
query.addBindValue(mail.m_senderAddress);
query.addBindValue(MAIL_ADDRESS_FORMAT);
query.addBindValue(mail.m_receiverAddress);
query.addBindValue(MAIL_ADDRESS_FORMAT);
query.addBindValue(mail.m_theme);
query.addBindValue(mail.m_content);
query.addBindValue(mail.m_dateTime);
query.exec();
errorSQLOrder(query, "insert-mail");
if (!query.isActive())
{
qDebug() << "QUERY_FAIL::" << query.lastError().text();
m_db->close();
return SEND_MAIL_FAIL;
}
if (0 >= query.numRowsAffected())
{
return SEND_MAIL_FAIL;
}
QSqlDatabase::database().commit();
query.exec("select LAST_INSERT_ID() from Mail");
if (query.next())
{
mail.m_mailID = query.value(0).toInt();
}
// m_db->close();
return SEND_MAIL_SUCCESS;
}
void IMTcpServer::sendMessage(const SaveTmpInformation &save)
{
m_save.m_requestKind = save.m_requestKind;
switch(m_save.m_requestKind)
{
case SEND_MAIL:
{
m_save.m_mail = save.m_mail;
m_save.m_replyKind = m_database.insertMail(m_save.m_mail);
save.m_clientSocket->sendMessage(m_save);
if(SEND_MAIL_SUCCESS == m_save.m_replyKind)
{
QString mailAddress = m_save.m_mail.m_receiverAddress;
mailAddress.append(MAIL_ADDRESS_FORMAT);
QMap::iterator iter;
iter = m_userMailMap.find(mailAddress);
if(iter != m_userMailMap.end())
{
m_save.m_replyKind = RECEIVE_MAIL;
iter.value()->sendMessage(m_save);
}
}
break;
}
}
}
收信:
一.邮件通信控制类(在IMMailCtrl中定义)的socket与服务器连接成功并准备好读信息时,会调用readMessage槽函数
connect(m_tcpSocket, SIGNAL(connected()), this, SLOT(requestGetInMails()));
connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(readMessage()));
二.readMessage槽函数识别到RECEIVE_MAIL,发出getInMail信号
void IMMailCtrl::readMessage()
{
in >> type;
switch (type)
{
case RECEIVE_MAIL:
{
in >> m_mail;
if (m_mail.m_receiverAddress == m_myID)
emit getInMail(m_mail);
break;
}
}
}
三.邮件主界面(在IMMailWidget中定义)捕获信号, 调用addNewInMailButton
connect(m_mailCtrl, &IMMailCtrl::getInMail,
this, &IMMailWidget::addNewInMailButton);
bool IMMailWidget::addNewInMailButton(const MailInformation &mail)
{
if(m_inMailMap.contains(mail.m_mailID))
{
return false;
}
IMMailButton *button = new IMMailButton(mail, this, this);
m_inMailMap.insert(mail.m_mailID, button);
m_inWidget.insertItem(0, button);
return true;
}