Fri, 06 Dec 2019 10:26:43 GMT

master
大蒟蒻 6 years ago
parent 20ff2f745d
commit ba1069a462

@ -0,0 +1,3 @@
{
"python.formatting.provider": "yapf"
}

@ -0,0 +1,16 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: 当前文件",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"gevent": true
}
]
}

@ -0,0 +1,3 @@
{
"python.formatting.provider": "yapf"
}

@ -0,0 +1,77 @@
import threading
import os
import sys
from socket import *
from PyQt5.Qt import *
from main_window_ui import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.btnSend.clicked.connect(self.btnSend_onclicked)
self.btnConnect.clicked.connect(self.btnConnect_onclicked)
self.statusbar.showMessage("Disconnected")
self.socket: socket = None
self.isConnected = False
def closeEvent(self, event):
if self.isConnected:
self.btnConnect.click()
self.close()
def btnConnect_onclicked(self):
if not self.isConnected:
server_addr = self.txtServerInput.text()
sp = server_addr.rfind(':')
if sp in [-1, 0, len(server_addr) - 1]:
QMessageBox.critical(self, "Error", "Invalid address")
return
addr, port = server_addr[:sp], server_addr[sp + 1:]
try:
port = int(port)
except:
QMessageBox.critical(self, "Error", "Invalid port")
return
try:
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect((addr, port))
except:
QMessageBox.critical(self, "Error", "Connect failed")
return
self.btnConnect.setText('Disconnect')
self.statusbar.showMessage("Connected")
self.isConnected = True
threading.Thread(target=self.recvmsg_loop).start()
else:
self.socket.close()
self.btnConnect.setText('Connect')
self.statusbar.showMessage("Disonnected")
self.isConnected = False
def btnSend_onclicked(self):
msg = ':'.join([self.txtIDInput.text(), self.txtNewMsg.toPlainText()])
self.txtNewMsg.clear()
self.socket.send(msg.encode())
def recvmsg_loop(self):
while True:
if not self.isConnected:
return
msg = self.socket.recv(1 << 20).decode()
print(msg)
sp1 = msg.find(':')
sp2 = msg.find(':', sp1 + 1)
msg = "{}@{}:\n{}".format(msg[sp1 + 1:sp2], msg[:sp1],
msg[sp2 + 1:])
self.txtList.append(msg)
self.txtList.moveCursor(QTextCursor.End)
if __name__ == "__main__":
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
app.exec()

@ -0,0 +1,3 @@
@echo off
pushd %~dp0
for %%i in (*.ui) do pyuic5 "%%i" -o "%%~ni_ui.py"

@ -0,0 +1,12 @@
import { readdir, watchFile } from "fs";
import { extname } from 'path';
import { exec } from 'child_process';
readdir('.', (_, files) => {
files.filter(file => extname(file) == '.ui').forEach(file => {
console.log(`Setup modify hook for ${file}`);
watchFile(file, (curr, _) => {
console.log(`${file} modified at ${curr.mtime}.`);
exec('compile_ui');
});
})
});

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,7,1,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Server:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtServerInput">
<property name="text">
<string>127.0.0.1:34567</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnConnect">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTextBrowser" name="txtList"/>
</item>
<item>
<widget class="QPlainTextEdit" name="txtNewMsg"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>ID:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtIDInput"/>
</item>
<item>
<widget class="QPushButton" name="btnSend">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main_window.ui'
#
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.txtServerInput = QtWidgets.QLineEdit(self.centralwidget)
self.txtServerInput.setObjectName("txtServerInput")
self.horizontalLayout.addWidget(self.txtServerInput)
self.btnConnect = QtWidgets.QPushButton(self.centralwidget)
self.btnConnect.setObjectName("btnConnect")
self.horizontalLayout.addWidget(self.btnConnect)
self.verticalLayout.addLayout(self.horizontalLayout)
self.txtList = QtWidgets.QTextBrowser(self.centralwidget)
self.txtList.setObjectName("txtList")
self.verticalLayout.addWidget(self.txtList)
self.txtNewMsg = QtWidgets.QPlainTextEdit(self.centralwidget)
self.txtNewMsg.setObjectName("txtNewMsg")
self.verticalLayout.addWidget(self.txtNewMsg)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setObjectName("label_2")
self.horizontalLayout_2.addWidget(self.label_2)
self.txtIDInput = QtWidgets.QLineEdit(self.centralwidget)
self.txtIDInput.setObjectName("txtIDInput")
self.horizontalLayout_2.addWidget(self.txtIDInput)
self.btnSend = QtWidgets.QPushButton(self.centralwidget)
self.btnSend.setObjectName("btnSend")
self.horizontalLayout_2.addWidget(self.btnSend)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.verticalLayout.setStretch(1, 7)
self.verticalLayout.setStretch(2, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "Server:"))
self.txtServerInput.setText(_translate("MainWindow", "127.0.0.1:34567"))
self.btnConnect.setText(_translate("MainWindow", "Connect"))
self.label_2.setText(_translate("MainWindow", "ID:"))
self.btnSend.setText(_translate("MainWindow", "Send"))

@ -0,0 +1,3 @@
{
"python.formatting.provider": "yapf"
}

@ -0,0 +1,3 @@
@echo off
pushd %~dp0
for %%i in (*.ui) do pyuic5 "%%i" -o "%%~ni_ui.py"

@ -0,0 +1,12 @@
import { readdir, watchFile } from "fs";
import { extname } from 'path';
import { exec } from 'child_process';
readdir('.', (_, files) => {
files.filter(file => extname(file) == '.ui').forEach(file => {
console.log(`Setup modify hook for ${file}`);
watchFile(file, (curr, _) => {
console.log(`${file} modified at ${curr.mtime}.`);
exec('compile_ui');
});
})
});

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>SendLog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTextBrowser" name="textBrowser"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'log_window.ui'
#
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.textBrowser = QtWidgets.QTextBrowser(Dialog)
self.textBrowser.setObjectName("textBrowser")
self.gridLayout.addWidget(self.textBrowser, 0, 0, 1, 1)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "SendLog"))

@ -0,0 +1,90 @@
import sys
import re
import threading
from base64 import b64encode
from typing import *
from socket import *
from PyQt5.Qt import *
from main_window_ui import Ui_MainWindow
from log_window_ui import Ui_Dialog
def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
@static_vars(
matcher=re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"))
def validate_email(email: str):
return validate_email.matcher.fullmatch(email)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.btnSendMail.clicked.connect(self.send_mail)
self.txtFrom.textChanged.connect(self.mail_changed)
def mail_changed(self):
pass
def send_mail(self):
servaddr = self.txtServer.text()
username = self.txtFrom.text()
password = self.txtPassword.text()
receiver = self.txtTo.text()
subjects = self.txtSubject.text()
contents = self.txtContent.toPlainText()
if not validate_email(username) or not validate_email(receiver):
QMessageBox.critical(self, "Invalid address", "Invalid From or To")
return
lw = LogWindow(
(servaddr, username, password, receiver, subjects, contents))
lw.exec()
class LogWindow(QDialog, Ui_Dialog):
def __init__(self, data):
super(LogWindow, self).__init__()
self.setupUi(self)
threading.Thread(target=self.do_update_status, args=(data, )).start()
def do_update_status(self, data):
(servaddr, username, password, receiver, subjects, contents) = data
ss = socket(AF_INET, SOCK_STREAM)
try:
ss.connect((servaddr, 25))
except Exception:
QMessageBox.critical(self, "Connection Failed",
"Failed connecting smtp server")
return
def comm(msg: str):
msg += "\r\n"
ss.sendall(msg.encode())
self.textBrowser.append("C: " + msg)
self.textBrowser.append("S: " + ss.recv(1 << 20).decode())
comm("HELO " + servaddr)
comm("AUTH LOGIN")
comm(b64encode(username.encode()).decode())
comm(b64encode(password.encode()).decode())
comm("MAIL FROM:<{}>".format(username))
comm("RCPT TO:<{}>".format(receiver))
comm("DATA")
comm('\r\n'.join(["Subject: " + subjects, "", contents, "."]))
comm("QUIT")
if __name__ == "__main__":
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
app.exec()

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>SimpleMailSender</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Server:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>From:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>To:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Subject:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLineEdit" name="txtServer">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtFrom">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtPassword">
<property name="echoMode">
<enum>QLineEdit::PasswordEchoOnEdit</enum>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtTo">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtSubject">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="txtContent"/>
</item>
<item>
<widget class="QPushButton" name="btnSendMail">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main_window.ui'
#
# Created by: PyQt5 UI code generator 5.13.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setObjectName("label_5")
self.verticalLayout.addWidget(self.label_5)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setObjectName("label_2")
self.verticalLayout.addWidget(self.label_2)
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setObjectName("label_3")
self.verticalLayout.addWidget(self.label_3)
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setObjectName("label_4")
self.verticalLayout.addWidget(self.label_4)
self.horizontalLayout.addLayout(self.verticalLayout)
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.txtServer = QtWidgets.QLineEdit(self.centralwidget)
self.txtServer.setClearButtonEnabled(True)
self.txtServer.setObjectName("txtServer")
self.verticalLayout_2.addWidget(self.txtServer)
self.txtFrom = QtWidgets.QLineEdit(self.centralwidget)
self.txtFrom.setClearButtonEnabled(True)
self.txtFrom.setObjectName("txtFrom")
self.verticalLayout_2.addWidget(self.txtFrom)
self.txtPassword = QtWidgets.QLineEdit(self.centralwidget)
self.txtPassword.setEchoMode(QtWidgets.QLineEdit.PasswordEchoOnEdit)
self.txtPassword.setClearButtonEnabled(True)
self.txtPassword.setObjectName("txtPassword")
self.verticalLayout_2.addWidget(self.txtPassword)
self.txtTo = QtWidgets.QLineEdit(self.centralwidget)
self.txtTo.setClearButtonEnabled(True)
self.txtTo.setObjectName("txtTo")
self.verticalLayout_2.addWidget(self.txtTo)
self.txtSubject = QtWidgets.QLineEdit(self.centralwidget)
self.txtSubject.setClearButtonEnabled(True)
self.txtSubject.setObjectName("txtSubject")
self.verticalLayout_2.addWidget(self.txtSubject)
self.horizontalLayout.addLayout(self.verticalLayout_2)
self.verticalLayout_3.addLayout(self.horizontalLayout)
self.txtContent = QtWidgets.QPlainTextEdit(self.centralwidget)
self.txtContent.setObjectName("txtContent")
self.verticalLayout_3.addWidget(self.txtContent)
self.btnSendMail = QtWidgets.QPushButton(self.centralwidget)
self.btnSendMail.setObjectName("btnSendMail")
self.verticalLayout_3.addWidget(self.btnSendMail)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "SimpleMailSender"))
self.label_5.setText(_translate("MainWindow", "Server:"))
self.label.setText(_translate("MainWindow", "From:"))
self.label_2.setText(_translate("MainWindow", "Password:"))
self.label_3.setText(_translate("MainWindow", "To:"))
self.label_4.setText(_translate("MainWindow", "Subject:"))
self.btnSendMail.setText(_translate("MainWindow", "Send"))

@ -0,0 +1,38 @@
from gevent import monkey, spawn
monkey.patch_all()
from socket import *
from typing import *
conns: Set[Tuple[socket, Any]] = set()
def boardcast(message: str):
print(message)
for conn, addr in conns:
print('send to ', conn, addr)
conn.send(message.encode())
def process_connection(conn: socket, addr):
conns.add((conn, addr))
boardcast('server:global:{} connected.'.format(addr))
while True:
try:
res_raw = conn.recv(1 << 20)
if not res_raw:
raise
except Exception:
conns.remove((conn, addr))
boardcast('server:global:{} disconnected.'.format(addr))
return
res = res_raw.decode()
boardcast('{}:{}'.format(addr, res))
if __name__ == "__main__":
with socket(AF_INET, SOCK_STREAM) as s:
s.bind(('0.0.0.0', 34567))
s.listen(1 << 16)
while True:
conn, addr = s.accept()
spawn(process_connection, conn, addr)
Loading…
Cancel
Save