mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-02-07 12:24:21 +00:00
FEATURE: Added support for secure SMTP connection (SSL)
FEATURE: Added support for SMTP authentication
This commit is contained in:
parent
0a6f591cf5
commit
58bfa6f1bb
@ -1,6 +1,8 @@
|
|||||||
* Unreleased - Christophe Dumez <chris@qbittorrent.org> - v2.8.0
|
* Unreleased - Christophe Dumez <chris@qbittorrent.org> - v2.8.0
|
||||||
- FEATURE: Added monochrome icon for light themes
|
- FEATURE: Added support for secure SMTP connection (SSL)
|
||||||
|
- FEATURE: Added support for SMTP authentication
|
||||||
- BUGFIX: Change systray icon on the fly (no restart needed)
|
- BUGFIX: Change systray icon on the fly (no restart needed)
|
||||||
|
- COSMETIC: Added monochrome icon for light themes
|
||||||
|
|
||||||
* Sun Mar 20 2011 - Christophe Dumez <chris@qbittorrent.org> - v2.7.0
|
* Sun Mar 20 2011 - Christophe Dumez <chris@qbittorrent.org> - v2.7.0
|
||||||
- FEATURE: Added search field for torrent content
|
- FEATURE: Added search field for torrent content
|
||||||
|
@ -82,6 +82,7 @@ void qt_mac_set_dock_menu(QMenu *menu);
|
|||||||
#include "programupdater.h"
|
#include "programupdater.h"
|
||||||
#endif
|
#endif
|
||||||
#include "powermanagement.h"
|
#include "powermanagement.h"
|
||||||
|
#include "smtp.h"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
@ -97,6 +98,10 @@ using namespace libtorrent;
|
|||||||
// Constructor
|
// Constructor
|
||||||
MainWindow::MainWindow(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), m_posInitialized(false), force_exit(false) {
|
MainWindow::MainWindow(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), m_posInitialized(false), force_exit(false) {
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
// TODO: Remove this
|
||||||
|
Smtp *sender = new Smtp(this);
|
||||||
|
sender->sendMail("notification@qbittorrent.org", Preferences().getMailNotificationEmail(), "title", "content");
|
||||||
|
|
||||||
Preferences pref;
|
Preferences pref;
|
||||||
ui_locked = pref.isUILocked();
|
ui_locked = pref.isUILocked();
|
||||||
setWindowTitle(tr("qBittorrent %1", "e.g: qBittorrent v0.x").arg(QString::fromUtf8(VERSION)));
|
setWindowTitle(tr("qBittorrent %1", "e.g: qBittorrent v0.x").arg(QString::fromUtf8(VERSION)));
|
||||||
|
@ -506,9 +506,9 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>-344</y>
|
<y>-387</y>
|
||||||
<width>499</width>
|
<width>499</width>
|
||||||
<height>728</height>
|
<height>849</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
@ -853,26 +853,76 @@ QGroupBox {
|
|||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_15">
|
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
<property name="text">
|
<item row="0" column="0">
|
||||||
<string>Destination email:</string>
|
<widget class="QLabel" name="label_2">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>Destination email:</string>
|
||||||
</item>
|
</property>
|
||||||
<item row="0" column="1">
|
</widget>
|
||||||
<widget class="QLineEdit" name="dest_email_txt"/>
|
</item>
|
||||||
</item>
|
<item row="0" column="1">
|
||||||
<item row="1" column="0">
|
<widget class="QLineEdit" name="dest_email_txt"/>
|
||||||
<widget class="QLabel" name="label_3">
|
</item>
|
||||||
<property name="text">
|
<item row="1" column="0">
|
||||||
<string>SMTP server:</string>
|
<widget class="QLabel" name="label_3">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>SMTP server:</string>
|
||||||
</item>
|
</property>
|
||||||
<item row="1" column="1">
|
</widget>
|
||||||
<widget class="QLineEdit" name="smtp_server_txt"/>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="smtp_server_txt"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QGroupBox" name="groupMailNotifAuth">
|
||||||
|
<property name="title">
|
||||||
|
<string>Authentication</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Username:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="mailNotifUsername"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Password:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="mailNotifPassword">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QCheckBox" name="checkSmtpSSL">
|
||||||
|
<property name="text">
|
||||||
|
<string>This server requires a secure connection (SSL)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -927,7 +977,7 @@ QGroupBox {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>499</width>
|
<width>392</width>
|
||||||
<height>426</height>
|
<height>426</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -1407,8 +1457,8 @@ QGroupBox {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>514</width>
|
<width>328</width>
|
||||||
<height>384</height>
|
<height>306</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||||
@ -1786,7 +1836,7 @@ QGroupBox {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>499</width>
|
<width>486</width>
|
||||||
<height>408</height>
|
<height>408</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -2149,8 +2199,8 @@ QGroupBox {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>514</width>
|
<width>316</width>
|
||||||
<height>384</height>
|
<height>236</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_23">
|
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||||
@ -2298,8 +2348,8 @@ QGroupBox {
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>514</width>
|
<width>86</width>
|
||||||
<height>384</height>
|
<height>16</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_36"/>
|
<layout class="QVBoxLayout" name="verticalLayout_36"/>
|
||||||
@ -2365,5 +2415,38 @@ QGroupBox {
|
|||||||
<resources>
|
<resources>
|
||||||
<include location="../icons.qrc"/>
|
<include location="../icons.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>checkUploadLimit</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>spinUploadLimit</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>367</x>
|
||||||
|
<y>61</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>448</x>
|
||||||
|
<y>62</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>checkDownloadLimit</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>spinDownloadLimit</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>377</x>
|
||||||
|
<y>81</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>430</x>
|
||||||
|
<y>87</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -113,9 +113,6 @@ options_imp::options_imp(QWidget *parent):
|
|||||||
// Connect signals / slots
|
// Connect signals / slots
|
||||||
// General tab
|
// General tab
|
||||||
connect(checkShowSystray, SIGNAL(toggled(bool)), this, SLOT(setSystrayOptionsState(bool)));
|
connect(checkShowSystray, SIGNAL(toggled(bool)), this, SLOT(setSystrayOptionsState(bool)));
|
||||||
// Connection tab
|
|
||||||
connect(checkUploadLimit, SIGNAL(toggled(bool)), this, SLOT(enableUploadLimit(bool)));
|
|
||||||
connect(checkDownloadLimit, SIGNAL(toggled(bool)), this, SLOT(enableDownloadLimit(bool)));
|
|
||||||
// Bittorrent tab
|
// Bittorrent tab
|
||||||
connect(checkMaxConnecs, SIGNAL(toggled(bool)), this, SLOT(enableMaxConnecsLimit(bool)));
|
connect(checkMaxConnecs, SIGNAL(toggled(bool)), this, SLOT(enableMaxConnecsLimit(bool)));
|
||||||
connect(checkMaxConnecsPerTorrent, SIGNAL(toggled(bool)), this, SLOT(enableMaxConnecsLimitPerTorrent(bool)));
|
connect(checkMaxConnecsPerTorrent, SIGNAL(toggled(bool)), this, SLOT(enableMaxConnecsLimitPerTorrent(bool)));
|
||||||
@ -158,6 +155,10 @@ options_imp::options_imp(QWidget *parent):
|
|||||||
connect(groupMailNotification, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
connect(groupMailNotification, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||||
connect(dest_email_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
connect(dest_email_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||||
connect(smtp_server_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
connect(smtp_server_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||||
|
connect(checkSmtpSSL, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||||
|
connect(groupMailNotifAuth, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||||
|
connect(mailNotifUsername, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||||
|
connect(mailNotifPassword, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||||
connect(autoRunBox, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
connect(autoRunBox, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||||
connect(autoRun_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
connect(autoRun_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||||
// Connection tab
|
// Connection tab
|
||||||
@ -366,6 +367,10 @@ void options_imp::saveOptions(){
|
|||||||
pref.setMailNotificationEnabled(groupMailNotification->isChecked());
|
pref.setMailNotificationEnabled(groupMailNotification->isChecked());
|
||||||
pref.setMailNotificationEmail(dest_email_txt->text());
|
pref.setMailNotificationEmail(dest_email_txt->text());
|
||||||
pref.setMailNotificationSMTP(smtp_server_txt->text());
|
pref.setMailNotificationSMTP(smtp_server_txt->text());
|
||||||
|
pref.setMailNotificationSMTPSSL(checkSmtpSSL->isChecked());
|
||||||
|
pref.setMailNotificationSMTPAuth(groupMailNotifAuth->isChecked());
|
||||||
|
pref.setMailNotificationSMTPUsername(mailNotifUsername->text());
|
||||||
|
pref.setMailNotificationSMTPPassword(mailNotifPassword->text());
|
||||||
pref.setAutoRunEnabled(autoRunBox->isChecked());
|
pref.setAutoRunEnabled(autoRunBox->isChecked());
|
||||||
pref.setAutoRunProgram(autoRun_txt->text());
|
pref.setAutoRunProgram(autoRun_txt->text());
|
||||||
pref.setActionOnDblClOnTorrentDl(getActionOnDblClOnTorrentDl());
|
pref.setActionOnDblClOnTorrentDl(getActionOnDblClOnTorrentDl());
|
||||||
@ -522,6 +527,10 @@ void options_imp::loadOptions(){
|
|||||||
groupMailNotification->setChecked(pref.isMailNotificationEnabled());
|
groupMailNotification->setChecked(pref.isMailNotificationEnabled());
|
||||||
dest_email_txt->setText(pref.getMailNotificationEmail());
|
dest_email_txt->setText(pref.getMailNotificationEmail());
|
||||||
smtp_server_txt->setText(pref.getMailNotificationSMTP());
|
smtp_server_txt->setText(pref.getMailNotificationSMTP());
|
||||||
|
checkSmtpSSL->setChecked(pref.getMailNotificationSMTPSSL());
|
||||||
|
groupMailNotifAuth->setChecked(pref.getMailNotificationSMTPAuth());
|
||||||
|
mailNotifUsername->setText(pref.getMailNotificationSMTPUsername());
|
||||||
|
mailNotifPassword->setText(pref.getMailNotificationSMTPPassword());
|
||||||
autoRunBox->setChecked(pref.isAutoRunEnabled());
|
autoRunBox->setChecked(pref.isAutoRunEnabled());
|
||||||
autoRun_txt->setText(pref.getAutoRunProgram());
|
autoRun_txt->setText(pref.getAutoRunProgram());
|
||||||
intValue = pref.getActionOnDblClOnTorrentDl();
|
intValue = pref.getActionOnDblClOnTorrentDl();
|
||||||
@ -832,14 +841,6 @@ void options_imp::on_buttonBox_rejected(){
|
|||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void options_imp::enableDownloadLimit(bool checked){
|
|
||||||
if(checked){
|
|
||||||
spinDownloadLimit->setEnabled(true);
|
|
||||||
}else{
|
|
||||||
spinDownloadLimit->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool options_imp::useAdditionDialog() const{
|
bool options_imp::useAdditionDialog() const{
|
||||||
return checkAdditionDialog->isChecked();
|
return checkAdditionDialog->isChecked();
|
||||||
}
|
}
|
||||||
@ -880,10 +881,6 @@ void options_imp::enableMaxUploadsLimitPerTorrent(bool checked){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void options_imp::enableUploadLimit(bool checked){
|
|
||||||
spinUploadLimit->setEnabled(checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
void options_imp::enableApplyButton(){
|
void options_imp::enableApplyButton(){
|
||||||
applyButton->setEnabled(true);
|
applyButton->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,6 @@ public:
|
|||||||
QSize sizeFittingScreen();
|
QSize sizeFittingScreen();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void enableUploadLimit(bool checked);
|
|
||||||
void enableDownloadLimit(bool checked);
|
|
||||||
void enableProxy(int comboIndex);
|
void enableProxy(int comboIndex);
|
||||||
void enableProxyAuth(bool checked);
|
void enableProxyAuth(bool checked);
|
||||||
void enableMaxConnecsLimit(bool checked);
|
void enableMaxConnecsLimit(bool checked);
|
||||||
|
@ -306,6 +306,38 @@ public:
|
|||||||
setValue(QString::fromUtf8("Preferences/MailNotification/smtp_server"), smtp_server);
|
setValue(QString::fromUtf8("Preferences/MailNotification/smtp_server"), smtp_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getMailNotificationSMTPSSL() const {
|
||||||
|
return value(QString::fromUtf8("Preferences/MailNotification/req_ssl"), false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMailNotificationSMTPSSL(bool use) {
|
||||||
|
setValue(QString::fromUtf8("Preferences/MailNotification/req_ssl"), use);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getMailNotificationSMTPAuth() const {
|
||||||
|
return value(QString::fromUtf8("Preferences/MailNotification/req_auth"), false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMailNotificationSMTPAuth(bool use) {
|
||||||
|
setValue(QString::fromUtf8("Preferences/MailNotification/req_auth"), use);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getMailNotificationSMTPUsername() const {
|
||||||
|
return value(QString::fromUtf8("Preferences/MailNotification/username")).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMailNotificationSMTPUsername(const QString &username) {
|
||||||
|
setValue(QString::fromUtf8("Preferences/MailNotification/username"), username);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getMailNotificationSMTPPassword() const {
|
||||||
|
return value(QString::fromUtf8("Preferences/MailNotification/password")).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMailNotificationSMTPPassword(const QString &password) {
|
||||||
|
setValue(QString::fromUtf8("Preferences/MailNotification/password"), password);
|
||||||
|
}
|
||||||
|
|
||||||
int getActionOnDblClOnTorrentDl() const {
|
int getActionOnDblClOnTorrentDl() const {
|
||||||
return value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt();
|
return value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt();
|
||||||
}
|
}
|
||||||
|
@ -2004,7 +2004,8 @@ void QBtSession::sendNotificationEmail(const QTorrentHandle &h) {
|
|||||||
content += tr("The torrent was downloaded in %1.", "The torrent was downloaded in 1 hour and 20 seconds").arg(misc::userFriendlyDuration(h.active_time())) + "\n\n\n";
|
content += tr("The torrent was downloaded in %1.", "The torrent was downloaded in 1 hour and 20 seconds").arg(misc::userFriendlyDuration(h.active_time())) + "\n\n\n";
|
||||||
content += tr("Thank you for using qBittorrent.") + "\n";
|
content += tr("Thank you for using qBittorrent.") + "\n";
|
||||||
// Send the notification email
|
// Send the notification email
|
||||||
new Smtp("notification@qbittorrent.org", Preferences().getMailNotificationEmail(), tr("[qBittorrent] %1 has finished downloading").arg(h.name()), content);
|
Smtp *sender = new Smtp(this);
|
||||||
|
sender->sendMail("notification@qbittorrent.org", Preferences().getMailNotificationEmail(), tr("[qBittorrent] %1 has finished downloading").arg(h.name()), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read alerts sent by the Bittorrent session
|
// Read alerts sent by the Bittorrent session
|
||||||
|
476
src/smtp.cpp
476
src/smtp.cpp
@ -1,26 +1,105 @@
|
|||||||
/****************************************************************************
|
/*
|
||||||
** $Id: qt/smtp.h 3.3.6 edited Aug 31 2005 $
|
* Bittorrent Client using Qt4 and libtorrent.
|
||||||
**
|
* Copyright (C) 2011 Christophe Dumez
|
||||||
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
|
*
|
||||||
**
|
* This program is free software; you can redistribute it and/or
|
||||||
** This file is part of an example program for Qt. This example
|
* modify it under the terms of the GNU General Public License
|
||||||
** program may be used, distributed and modified without limitation.
|
* as published by the Free Software Foundation; either version 2
|
||||||
**
|
* of the License, or (at your option) any later version.
|
||||||
*****************************************************************************/
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*
|
||||||
|
* Contact : chris@qbittorrent.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on QxtSmtp from libqxt (http://libqxt.org)
|
||||||
|
*/
|
||||||
|
|
||||||
#include "smtp.h"
|
#include "smtp.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
|
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
#include <QSslSocket>
|
||||||
|
#else
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
#endif
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
Smtp::Smtp(const QString &from, const QString &to, const QString &subject, const QString &body) {
|
const short DEFAULT_PORT = 25;
|
||||||
|
const short DEFAULT_PORT_SSL = 465;
|
||||||
|
|
||||||
|
QByteArray hmacMD5(QByteArray key, const QByteArray &msg)
|
||||||
|
{
|
||||||
|
const int blockSize = 64; // HMAC-MD5 block size
|
||||||
|
if (key.length() > blockSize) { // if key is longer than block size (64), reduce key length with MD5 compression
|
||||||
|
key = QCryptographicHash::hash(key, QCryptographicHash::Md5);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
|
||||||
|
QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "\"
|
||||||
|
// ascii characters 0x36 ("6") and 0x5c ("\") are selected because they have large
|
||||||
|
// Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
|
||||||
|
|
||||||
|
for (int i = 0; i < key.length(); i++) {
|
||||||
|
innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
|
||||||
|
outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
|
||||||
|
}
|
||||||
|
|
||||||
|
// result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
|
||||||
|
QByteArray total = outerPadding;
|
||||||
|
QByteArray part = innerPadding;
|
||||||
|
part.append(msg);
|
||||||
|
total.append(QCryptographicHash::hash(part, QCryptographicHash::Md5));
|
||||||
|
return QCryptographicHash::hash(total, QCryptographicHash::Md5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Smtp::Smtp(QObject *parent): QObject(parent),
|
||||||
|
state(Init), use_ssl(false) {
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
socket = new QSslSocket(this);
|
||||||
|
#else
|
||||||
socket = new QTcpSocket(this);
|
socket = new QTcpSocket(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
connect( socket, SIGNAL( readyRead() ), this, SLOT( readyRead() ) );
|
connect(socket, SIGNAL(readyRead()), SLOT(readyRead()));
|
||||||
|
connect(socket, SIGNAL(disconnected()), SLOT(deleteLater()));
|
||||||
|
|
||||||
|
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
|
||||||
|
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
|
||||||
|
== "750c783e6ab0b503eaa86e310a5db738");
|
||||||
|
Q_ASSERT(hmacMD5(QByteArray::fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
|
||||||
|
"Hi There").toHex()
|
||||||
|
== "9294727a3638bb1c13f48ef8158bfc9d");
|
||||||
|
}
|
||||||
|
|
||||||
|
Smtp::~Smtp() {
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::sendMail(const QString &from, const QString &to, const QString &subject, const QString &body) {
|
||||||
|
Preferences pref;
|
||||||
QTextCodec* latin1 = QTextCodec::codecForName("latin1");
|
QTextCodec* latin1 = QTextCodec::codecForName("latin1");
|
||||||
message = "";
|
message = "";
|
||||||
message += encode_mime_header("Date", QDateTime::currentDateTime().toUTC().toString("ddd, d MMM yyyy hh:mm:ss UT"), latin1);
|
message += encode_mime_header("Date", QDateTime::currentDateTime().toUTC().toString("ddd, d MMM yyyy hh:mm:ss UT"), latin1);
|
||||||
@ -41,15 +120,135 @@ Smtp::Smtp(const QString &from, const QString &to, const QString &subject, const
|
|||||||
}
|
}
|
||||||
this->from = from;
|
this->from = from;
|
||||||
rcpt = to;
|
rcpt = to;
|
||||||
state = Init;
|
// Authentication
|
||||||
socket->connectToHost(Preferences().getMailNotificationSMTP(), 25);
|
if(pref.getMailNotificationSMTPAuth()) {
|
||||||
if(socket->waitForConnected ( 30000 )) {
|
username = pref.getMailNotificationSMTPUsername();
|
||||||
qDebug("connected");
|
password = pref.getMailNotificationSMTPPassword();
|
||||||
} else {
|
}
|
||||||
t = 0;
|
|
||||||
deleteLater();
|
// Connect to SMTP server
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
if(pref.getMailNotificationSMTPSSL()) {
|
||||||
|
socket->connectToHostEncrypted(pref.getMailNotificationSMTP(), DEFAULT_PORT_SSL);
|
||||||
|
use_ssl = true;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
socket->connectToHost(pref.getMailNotificationSMTP(), DEFAULT_PORT);
|
||||||
|
use_ssl = false;
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::readyRead()
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
// SMTP is line-oriented
|
||||||
|
buffer += socket->readAll();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int pos = buffer.indexOf("\r\n");
|
||||||
|
if (pos < 0) return; // Loop exit condition
|
||||||
|
QByteArray line = buffer.left(pos);
|
||||||
|
buffer = buffer.mid(pos + 2);
|
||||||
|
qDebug() << "Response line:" << line;
|
||||||
|
// Extract reponse code
|
||||||
|
QByteArray code = line.left(3);
|
||||||
|
|
||||||
|
switch(state) {
|
||||||
|
case Init: {
|
||||||
|
if(code[0] == '2') {
|
||||||
|
// Connection was successful
|
||||||
|
ehlo();
|
||||||
|
} else {
|
||||||
|
// TODO: Log something
|
||||||
|
qDebug() << "Connection failed, unrecognized reply:" << line;
|
||||||
|
state = Close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EhloSent:
|
||||||
|
case HeloSent:
|
||||||
|
case EhloGreetReceived:
|
||||||
|
parseEhloResponse(code, line[3] != ' ', line.mid(4));
|
||||||
|
break;
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
case StartTLSSent:
|
||||||
|
if (code == "220") {
|
||||||
|
socket->startClientEncryption();
|
||||||
|
ehlo();
|
||||||
|
} else {
|
||||||
|
authenticate();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case AuthRequestSent:
|
||||||
|
case AuthUsernameSent:
|
||||||
|
if (authType == AuthPlain) authPlain();
|
||||||
|
else if (authType == AuthLogin) authLogin();
|
||||||
|
else authCramMD5(line.mid(4));
|
||||||
|
break;
|
||||||
|
case AuthSent:
|
||||||
|
case Authenticated:
|
||||||
|
if (code[0] == '2') {
|
||||||
|
qDebug() << "Login was OK, send <mail from>...";
|
||||||
|
socket->write("mail from:<" + from.toAscii() + ">\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = Rcpt;
|
||||||
|
} else {
|
||||||
|
// Authentication failed!
|
||||||
|
// TODO: Log something
|
||||||
|
qDebug() << "Authentication not sent properly, aborting";
|
||||||
|
state = Close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Rcpt:
|
||||||
|
if (code[0] == '2') {
|
||||||
|
socket->write("rcpt to:<" + rcpt.toAscii() + ">\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = Data;
|
||||||
|
} else {
|
||||||
|
qDebug() << "<Mail from> not sent properly, aborting";
|
||||||
|
state = Close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Data:
|
||||||
|
if (code[0] == '2') {
|
||||||
|
socket->write("data\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = Body;
|
||||||
|
} else {
|
||||||
|
qDebug() << "<Rcpt to> not sent properly, aborting";
|
||||||
|
state = Close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Body:
|
||||||
|
if (code[0] == '3') {
|
||||||
|
socket->write(message + "\r\n.\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = Quit;
|
||||||
|
} else {
|
||||||
|
qDebug() << "data not sent properly, aborting";
|
||||||
|
state = Close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Quit:
|
||||||
|
if (code[0] == '2') {
|
||||||
|
socket->write("QUIT\r\n");
|
||||||
|
socket->flush();
|
||||||
|
// here, we just close.
|
||||||
|
state = Close;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Message not sent properly, aborting";
|
||||||
|
state = Close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qDebug() << "Disconnecting from host";
|
||||||
|
socket->disconnectFromHost();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t = new QTextStream(socket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix)
|
QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix)
|
||||||
@ -91,102 +290,163 @@ QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QT
|
|||||||
return rv + line + "\r\n";
|
return rv + line + "\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
Smtp::~Smtp()
|
void Smtp::ehlo()
|
||||||
{
|
{
|
||||||
if(t)
|
QByteArray address = "127.0.0.1";
|
||||||
delete t;
|
foreach(const QHostAddress& addr, QNetworkInterface::allAddresses())
|
||||||
delete socket;
|
{
|
||||||
|
if (addr == QHostAddress::LocalHost || addr == QHostAddress::LocalHostIPv6)
|
||||||
|
continue;
|
||||||
|
address = addr.toString().toAscii();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Send EHLO
|
||||||
|
socket->write("ehlo "+ address + "\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = EhloSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Smtp::readyRead()
|
void Smtp::parseEhloResponse(const QByteArray& code, bool continued, const QString& line)
|
||||||
{
|
{
|
||||||
|
if (code != "250") {
|
||||||
qDebug() << "readyRead";
|
// Error
|
||||||
// SMTP is line-oriented
|
if(state == EhloSent) {
|
||||||
|
// try to send HELO instead of EHLO
|
||||||
QString responseLine;
|
qDebug() << "EHLO failed, trying HELO instead...";
|
||||||
do
|
socket->write("helo\r\n");
|
||||||
{
|
socket->flush();
|
||||||
responseLine = socket->readLine();
|
state = HeloSent;
|
||||||
response += responseLine;
|
|
||||||
}
|
|
||||||
while ( socket->canReadLine() && responseLine[3] != ' ' );
|
|
||||||
|
|
||||||
qDebug("Response line: %s", qPrintable(response));
|
|
||||||
|
|
||||||
responseLine.truncate( 3 );
|
|
||||||
|
|
||||||
|
|
||||||
if ( state == Init && responseLine[0] == '2' )
|
|
||||||
{
|
|
||||||
// banner was okay, let's go on
|
|
||||||
QByteArray address = "127.0.0.1";
|
|
||||||
foreach(const QHostAddress& addr, QNetworkInterface::allAddresses())
|
|
||||||
{
|
|
||||||
if (addr == QHostAddress::LocalHost || addr == QHostAddress::LocalHostIPv6)
|
|
||||||
continue;
|
|
||||||
address = addr.toString().toAscii();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*t << "ehlo "+ address + "\r\n";
|
|
||||||
t->flush();
|
|
||||||
|
|
||||||
state = Mail;
|
|
||||||
}
|
|
||||||
else if ( state == Mail || state == Mail2 )
|
|
||||||
{
|
|
||||||
if(responseLine[0] == '2') {
|
|
||||||
// EHLO response was okay (well, it has to be)
|
|
||||||
*t << "mail from:<" << from << ">\r\n";
|
|
||||||
t->flush();
|
|
||||||
state = Rcpt;
|
|
||||||
} else {
|
} else {
|
||||||
if(state == Mail) {
|
// Both EHLO and HELO failed, chances are this is NOT
|
||||||
// ehlo did not work, try helo instead
|
// a SMTP server
|
||||||
*t << "helo\r\n";
|
// TODO: log something
|
||||||
t->flush();
|
qDebug() << "Both EHLO and HELO failed, aborting.";
|
||||||
state = Mail2;
|
state = Close;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ( state == Rcpt && responseLine[0] == '2' )
|
|
||||||
{
|
|
||||||
|
|
||||||
*t << "rcpt to:<" << rcpt << ">\r\n"; //r
|
|
||||||
t->flush();
|
|
||||||
state = Data;
|
|
||||||
}
|
|
||||||
else if ( state == Data && responseLine[0] == '2' )
|
|
||||||
{
|
|
||||||
|
|
||||||
*t << "data\r\n";
|
|
||||||
t->flush();
|
|
||||||
state = Body;
|
|
||||||
}
|
|
||||||
else if ( state == Body && responseLine[0] == '3' )
|
|
||||||
{
|
|
||||||
|
|
||||||
*t << message << "\r\n.\r\n";
|
|
||||||
t->flush();
|
|
||||||
state = Quit;
|
|
||||||
}
|
|
||||||
else if(state == Quit && responseLine[0] == '2')
|
|
||||||
{
|
|
||||||
|
|
||||||
*t << "QUIT\r\n";
|
|
||||||
t->flush();
|
|
||||||
// here, we just close.
|
|
||||||
state = Close;
|
|
||||||
}
|
|
||||||
else if ( state == Close )
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
if (state != EhloGreetReceived) {
|
||||||
{
|
if (!continued) {
|
||||||
// something broke.
|
// greeting only, no extensions
|
||||||
state = Close;
|
qDebug() << "No extension";
|
||||||
|
state = EhloDone;
|
||||||
|
} else {
|
||||||
|
// greeting followed by extensions
|
||||||
|
state = EhloGreetReceived;
|
||||||
|
qDebug () << "EHLO greet received";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Supported extension: " << line.section(' ', 0, 0).toUpper()
|
||||||
|
<< line.section(' ', 1);
|
||||||
|
extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1);
|
||||||
|
if (!continued)
|
||||||
|
state = EhloDone;
|
||||||
|
}
|
||||||
|
if (state != EhloDone) return;
|
||||||
|
if (extensions.contains("STARTTLS") && use_ssl) {
|
||||||
|
qDebug() << "STARTTLS";
|
||||||
|
startTLS();
|
||||||
|
} else {
|
||||||
|
authenticate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::authenticate()
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
if (!extensions.contains("AUTH") ||
|
||||||
|
username.isEmpty() || password.isEmpty()) {
|
||||||
|
// Skip authentication
|
||||||
|
qDebug() << "Skipping authentication...";
|
||||||
|
state = Authenticated;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// AUTH extension is supported, check which
|
||||||
|
// authentication modes are supported by
|
||||||
|
// the server
|
||||||
|
QStringList auth = extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts);
|
||||||
|
if (auth.contains("CRAM-MD5")) {
|
||||||
|
qDebug() << "Using CRAM-MD5 authentication...";
|
||||||
|
authCramMD5();
|
||||||
|
}
|
||||||
|
else if (auth.contains("PLAIN")) {
|
||||||
|
qDebug() << "Using PLAIN authentication...";
|
||||||
|
authPlain();
|
||||||
|
}
|
||||||
|
else if (auth.contains("LOGIN")) {
|
||||||
|
qDebug() << "Using LOGIN authentication...";
|
||||||
|
authLogin();
|
||||||
|
} else {
|
||||||
|
// Skip authentication
|
||||||
|
qDebug() << "Server does not support any of our AUTH modes, skip authentication...";
|
||||||
|
state = Authenticated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::startTLS()
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
socket->write("starttls\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = StartTLSSent;
|
||||||
|
#else
|
||||||
|
authenticate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::authCramMD5(const QByteArray& challenge)
|
||||||
|
{
|
||||||
|
if (state != AuthRequestSent) {
|
||||||
|
socket->write("auth cram-md5\r\n");
|
||||||
|
socket->flush();
|
||||||
|
authType = AuthCramMD5;
|
||||||
|
state = AuthRequestSent;
|
||||||
|
} else {
|
||||||
|
QByteArray response = username.toAscii() + ' '
|
||||||
|
+ hmacMD5(password.toAscii(), QByteArray::fromBase64(challenge)).toHex();
|
||||||
|
socket->write(response.toBase64() + "\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = AuthSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::authPlain()
|
||||||
|
{
|
||||||
|
if (state != AuthRequestSent) {
|
||||||
|
authType = AuthPlain;
|
||||||
|
// Prepare Auth string
|
||||||
|
QByteArray auth;
|
||||||
|
auth += '\0';
|
||||||
|
auth += username.toAscii();
|
||||||
|
qDebug() << "username: " << username.toAscii();
|
||||||
|
auth += '\0';
|
||||||
|
auth += password.toAscii();
|
||||||
|
qDebug() << "password: " << password.toAscii();
|
||||||
|
// Send it
|
||||||
|
socket->write("auth plain "+ auth.toBase64() + "\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = AuthSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Smtp::authLogin()
|
||||||
|
{
|
||||||
|
if (state != AuthRequestSent && state != AuthUsernameSent) {
|
||||||
|
socket->write("auth login\r\n");
|
||||||
|
socket->flush();
|
||||||
|
authType = AuthLogin;
|
||||||
|
state = AuthRequestSent;
|
||||||
|
}
|
||||||
|
else if (state == AuthRequestSent) {
|
||||||
|
socket->write(username.toAscii().toBase64() + "\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = AuthUsernameSent;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
socket->write(password.toAscii().toBase64() + "\r\n");
|
||||||
|
socket->flush();
|
||||||
|
state = AuthSent;
|
||||||
}
|
}
|
||||||
response = "";
|
|
||||||
}
|
}
|
||||||
|
78
src/smtp.h
78
src/smtp.h
@ -1,49 +1,97 @@
|
|||||||
/****************************************************************************
|
/*
|
||||||
** $Id: qt/smtp.h 3.3.6 edited Aug 31 2005 $
|
* Bittorrent Client using Qt4 and libtorrent.
|
||||||
**
|
* Copyright (C) 2011 Christophe Dumez
|
||||||
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
|
*
|
||||||
**
|
* This program is free software; you can redistribute it and/or
|
||||||
** This file is part of an example program for Qt. This example
|
* modify it under the terms of the GNU General Public License
|
||||||
** program may be used, distributed and modified without limitation.
|
* as published by the Free Software Foundation; either version 2
|
||||||
**
|
* of the License, or (at your option) any later version.
|
||||||
*****************************************************************************/
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*
|
||||||
|
* Contact : chris@qbittorrent.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on QxtSmtp from libqxt (http://libqxt.org)
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef SMTP_H
|
#ifndef SMTP_H
|
||||||
#define SMTP_H
|
#define SMTP_H
|
||||||
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
struct QTextStream;
|
struct QTextStream;
|
||||||
|
#ifndef QT_NO_OPENSSL
|
||||||
|
struct QSslSocket;
|
||||||
|
#else
|
||||||
struct QTcpSocket;
|
struct QTcpSocket;
|
||||||
class QTextCodec;
|
#endif
|
||||||
|
struct QTextCodec;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
class Smtp : public QObject {
|
class Smtp : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Smtp(const QString &from, const QString &to, const QString &subject, const QString &body);
|
Smtp(QObject *parent = 0);
|
||||||
~Smtp();
|
~Smtp();
|
||||||
|
void sendMail(const QString &from, const QString &to, const QString &subject, const QString &body);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyRead();
|
void readyRead();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix=QByteArray());
|
QByteArray encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix=QByteArray());
|
||||||
|
void ehlo();
|
||||||
|
void parseEhloResponse(const QByteArray& code, bool continued, const QString& line);
|
||||||
|
void authenticate();
|
||||||
|
void startTLS();
|
||||||
|
void authCramMD5(const QByteArray& challenge = QByteArray());
|
||||||
|
void authPlain();
|
||||||
|
void authLogin();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum states { Rcpt, EhloSent, HeloSent, EhloDone, EhloGreetReceived, AuthRequestSent, AuthSent,
|
||||||
|
AuthUsernameSent, Authenticated, StartTLSSent, Data, Init, Body, Quit, Close };
|
||||||
|
enum AuthType { AuthPlain, AuthLogin, AuthCramMD5 };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
QTextStream *t;
|
#ifndef QT_NO_OPENSSL
|
||||||
|
QSslSocket *socket;
|
||||||
|
#else
|
||||||
QTcpSocket *socket;
|
QTcpSocket *socket;
|
||||||
|
#endif
|
||||||
QString from;
|
QString from;
|
||||||
QString rcpt;
|
QString rcpt;
|
||||||
QString response;
|
QString response;
|
||||||
enum states{Rcpt,Mail,Mail2,Data,Init,Body,Quit,Close};
|
|
||||||
int state;
|
int state;
|
||||||
|
QHash<QString, QString> extensions;
|
||||||
|
QByteArray buffer;
|
||||||
|
bool use_ssl;
|
||||||
|
AuthType authType;
|
||||||
|
QString username;
|
||||||
|
QString password;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user