MultiUserChat::~MultiUserChat() { if (!FUsers.isEmpty()) closeChat(IPresence::Offline, QString::null); if (FStanzaProcessor) { FStanzaProcessor->removeStanzaHandle(FSHIPresence); FStanzaProcessor->removeStanzaHandle(FSHIMessage); } if (FMessageProcessor) { FMessageProcessor->removeMessageEditor(MEO_MULTIUSERCHAT,this); } emit chatDestroyed(); }
//群聊窗口 void Widget::on_btnAll_clicked() { if(list.contains("NULL"))//窗口存在 { list["NULL"]->raise(); list["NULL"]->activateWindow(); list["NULL"]->show(); } else { ChatWidgit *chatView = new ChatWidgit(); list.insert("NULL", chatView); connect(chatView, SIGNAL(closeChat(QString)), this, SLOT(closeFromChat(QString))); connect(this, SIGNAL(sendMessagesZ(QString, QString, QString)), chatView, SLOT(setMessage(QString, QString, QString))); connect(chatView, SIGNAL(sendMessagesFromChat(QString, QString)), this, SLOT(sendMessagesToMain(QString, QString))); chatView->setSecAddr("NULL", Name); chatView->show(); } }
//聊天窗口关闭时发送信号,让主窗口删除Qmap表项中相对应的数据 void ChatWidgit::closeEvent(QCloseEvent *) { emit closeChat(secretAddress); }
Client::Client(QWidget *parent) : QDialog(parent) { hostLabel = new QLabel(tr("&Server name:")); portLabel = new QLabel(tr("S&erver port:")); nameLabel = new QLabel(tr("&Client name:")); // Find out which IP to connect to QString ipAddress; QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); // Use the first non-localhost IPv4 address for (int i = 0; i < ipAddressesList.size(); ++i) { if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) { ipAddress = ipAddressesList.at(i).toString(); break; } } // If we did not find one, use IPv4 localhost if (ipAddress.isEmpty()) ipAddress = QHostAddress(QHostAddress::LocalHost).toString(); hostLineEdit = new QLineEdit(ipAddress); portLineEdit = new QLineEdit; clientNameLineEdit = new QLineEdit; portLineEdit->setValidator(new QIntValidator(1, 65535, this)); hostLabel->setBuddy(hostLineEdit); portLabel->setBuddy(portLineEdit); nameLabel->setBuddy(clientNameLineEdit); connectButton = new QPushButton(tr("Connect")); connectButton->setDefault(true); connectButton->setEnabled(false); // Make the quit button exit chat sessions quitButton = new QPushButton(tr("Quit")); buttonBox = new QDialogButtonBox; buttonBox->addButton(connectButton, QDialogButtonBox::ActionRole); buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); secureSocket = new QSslSocket(this); // Special slot to handle errors with the certificates // in particular the fact that they are self-signed connect(secureSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(handleSSLError(QList<QSslError>))); // Connect signals to slots for the chat window connect(hostLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableConnectButton())); connect(portLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableConnectButton())); connect(clientNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableConnectButton())); connect(connectButton, SIGNAL(clicked()), this, SLOT(connectToChatServer())); connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); connect(secureSocket, SIGNAL(readyRead()), this, SLOT(messageComing())); connect(secureSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); QGridLayout *mainLayout = new QGridLayout; mainLayout->addWidget(hostLabel, 0, 0); mainLayout->addWidget(hostLineEdit, 0, 1); mainLayout->addWidget(portLabel, 1, 0); mainLayout->addWidget(portLineEdit, 1, 1); mainLayout->addWidget(nameLabel, 2, 0); mainLayout->addWidget(clientNameLineEdit, 2, 1); mainLayout->addWidget(buttonBox, 3, 0, 1, 2); setLayout(mainLayout); QVBoxLayout* vlay = new QVBoxLayout(); vlay->addWidget(&clientChatLog); vlay->addWidget(&clientMessage); closeChatWindow.setText("Quit"); vlay->addWidget(&closeChatWindow); chatWindow.setLayout(vlay); connect(&clientMessage, SIGNAL(returnPressed()), this, SLOT(sendMessage())); connect(&userList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(clientSelected(QListWidgetItem*))); setWindowTitle(tr("Secure Chatp2p Client")); portLineEdit->setFocus(); connect(&closeChatWindow, SIGNAL(clicked()), this, SLOT(closeChat())); }
//接收UDP信息信号的处理函数//接收数据,并根据type分类 槽函数 void Widget::processPendingDatagrams()//接收数据处理过程 { while(udpSocket->hasPendingDatagrams())//是否有数据报等待阅读//hasPendingDatagrams返回true时表示至少有一个数据报在等待被读取 { QByteArray datagram;//缓存字节数组 //pendingDatagramSize为返回第一个在等待读取报文的size,resize函数是把datagram的size归一化到参数size的大小一样 datagram.resize(udpSocket->pendingDatagramSize());//获取缓存大小 //将读取到的不大于datagram.size()大小数据输入到datagram.data()中,datagram.data()返回的是一个字节数组中存储数据位置的指针 udpSocket->readDatagram(datagram.data(), datagram.size());//读取数据 QDataStream in(&datagram, QIODevice::ReadOnly);//Qt的I/O设备接口类 从&datagram中读取串行化的数据 只读 序列化的二进制数据 int messageType;//此处的int为qint32,在Qt中,qint8为char,qint16为uint in >> messageType;//读取1个32位长度的整型数据到messageTyep中//提取出messageType QString localHostName, ipAddress, message, secretAddress;//消息发送方昵称名,IP地址,消息内容和消息接受方IP地址 QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");//获取当前时间//将当前的时间转化到括号中的形式 switch(messageType) { case RefuseChat://拒绝聊天 //in>>后面如果为Qstring,则表示读取一个直到出现'\0'的字符串 in >> localHostName >> ipAddress >> secretAddress;//提取出消息发送方昵称名,IP和消息接收方IP if(secretAddress == getIP())//是发给自己的 { QMessageBox::information(this, tr("拒绝"), tr("来自(%1)的%2 拒绝你的聊天").arg(ipAddress).arg(localHostName)); } break; case StartChat://开始聊天 in >> localHostName >> ipAddress >> secretAddress; if(secretAddress == getIP()) { ChatWidgit *chatView = new ChatWidgit(); list.insert(ipAddress, chatView);//插入聊天窗口列表 connect(chatView, SIGNAL(closeChat(QString)), this, SLOT(closeFromChat(QString))); connect(this, SIGNAL(sendMessagesZ(QString, QString, QString)), chatView, SLOT(setMessage(QString, QString, QString))); connect(chatView, SIGNAL(sendMessagesFromChat(QString, QString)), this, SLOT(sendMessagesToMain(QString, QString))); connect(chatView, SIGNAL(sendFile(QString, QString)), this, SLOT(hasFileToSend(QString, QString))); chatView->setSecAddr(ipAddress, Name);//设置具体聊天窗口(chatView) chatView->show(); } break; case AskStartChat://申请聊天 in >> localHostName >> ipAddress >> secretAddress; if(secretAddress == getIP()) { int btn = QMessageBox::information(this, tr("同意聊天"), tr("来自%1(%2)的聊天,是否接收?")\ .arg(ipAddress).arg(localHostName), QMessageBox::Yes, QMessageBox::No); if(btn == QMessageBox::Yes) { ChatWidgit *chatView = new ChatWidgit(); list.insert(ipAddress, chatView); connect(chatView, SIGNAL(closeChat(QString)), this, SLOT(closeFromChat(QString))); connect(this, SIGNAL(sendMessagesZ(QString, QString, QString)), chatView, SLOT(setMessage(QString, QString, QString))); connect(chatView, SIGNAL(sendMessagesFromChat(QString, QString)), this, SLOT(sendMessagesToMain(QString, QString))); connect(chatView, SIGNAL(sendFile(QString, QString)), this, SLOT(hasFileToSend(QString, QString))); chatView->setSecAddr(ipAddress, Name); chatView->show(); sendMessage(StartChat, ipAddress); } else if(btn == QMessageBox::No) { sendMessage(RefuseChat, ipAddress); } } break; case Message://聊天消息 in >> localHostName >> ipAddress >> secretAddress >> message; //QMessageBox::information(this, tr("0"), tr("%1sec\n%2").arg(secretAddress).arg(ipAddress)); if(secretAddress == getIP() )//发给自己的私有聊天 { //QMessageBox::information(this, tr("0"), tr("%1sec").arg(secretAddress)); if(list.contains(ipAddress)) { list[ipAddress]->show(); emit sendMessagesZ(ipAddress, tr("[ %1 ] %2").arg(localHostName).arg(time), message);//主窗口向具体聊天窗口发送聊天消息的信号 } else { ChatWidgit *chatView = new ChatWidgit(); list.insert(ipAddress, chatView); connect(chatView, SIGNAL(closeChat(QString)), this, SLOT(closeFromChat(QString))); connect(this, SIGNAL(sendMessagesZ(QString, QString, QString)), chatView, SLOT(setMessage(QString, QString, QString))); connect(chatView, SIGNAL(sendMessagesFromChat(QString, QString)), this, SLOT(sendMessagesToMain(QString, QString))); connect(chatView, SIGNAL(sendFile(QString, QString)), this, SLOT(hasFileToSend(QString, QString))); chatView->setSecAddr(ipAddress, Name); chatView->show(); emit sendMessagesZ(ipAddress, tr("[ %1 ] %2").arg(localHostName).arg(time), message); } } else if(secretAddress == "NULL")//群消息 { if(list.contains("NULL")) { list["NULL"]->show(); emit sendMessagesZ(secretAddress, tr("[ %1 ] %2").arg(localHostName).arg(time), message); } else { ChatWidgit *chatView = new ChatWidgit(); list.insert(secretAddress, chatView); connect(chatView, SIGNAL(closeChat(QString)), this, SLOT(closeFromChat(QString))); connect(this, SIGNAL(sendMessagesZ(QString, QString, QString)), chatView, SLOT(setMessage(QString, QString, QString))); connect(chatView, SIGNAL(sendMessagesFromChat(QString, QString)), this, SLOT(sendMessagesToMain(QString, QString))); connect(chatView, SIGNAL(sendFile(QString, QString)), this, SLOT(hasFileToSend(QString, QString))); chatView->setSecAddr(secretAddress, Name); chatView->show(); emit sendMessagesZ(secretAddress, tr("[ %1 ] %2").arg(localHostName).arg(time), message); } } break; case NewParticipant://新用户加入 in >> localHostName >> ipAddress; newParticipant(localHostName, ipAddress);//主窗口登记新用户 break; case ParticipantLeft://用户离开 in >> localHostName; //participantLeft(localHostName, time); participantLeft(localHostName);//主窗口处理用户离开 break; case FileName://发送文件 { in >> localHostName >> ipAddress; QString clientAddress, fileName;// in >> clientAddress >> fileName; QMessageBox::information(this, tr(""), tr("%1ipaddr\n%2sev\n%3file").arg(ipAddress).arg(clientAddress).arg(message));// hasPendingFile(localHostName, ipAddress, clientAddress, fileName);//有文件需要接收 break; } case Refuse://拒绝接收文件 in >> localHostName; QString serverAddress;// in >> ipAddress >> serverAddress; if(serverAddress == getIP()) { this->Sender->refused(); } break; } } }