mirror of
https://github.com/jie65535/IM.git
synced 2024-07-27 19:05:11 +08:00
提交源码
This commit is contained in:
29
IM Porject/IMService/IMService.pro
Normal file
29
IM Porject/IMService/IMService.pro
Normal file
@@ -0,0 +1,29 @@
|
||||
QT -= gui
|
||||
QT += network
|
||||
|
||||
CONFIG += c++11 console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which as been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
imservice.cpp
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
HEADERS += \
|
||||
imservice.h \
|
||||
protocol.h
|
||||
322
IM Porject/IMService/IMService.pro.user
Normal file
322
IM Porject/IMService/IMService.pro.user
Normal file
@@ -0,0 +1,322 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.7.2, 2018-12-08T20:06:10. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{2d03fc4c-541a-4fa5-8f5c-ae92a1998dce}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey">
|
||||
<value type="QString">-fno-delayed-template-parsing</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.11.2 MinGW 32bit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.11.2 MinGW 32bit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5112.win32_mingw53_kit</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Profile</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">部署</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">IMService</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:E:/C++/Qt/IMService/IMService.pro</value>
|
||||
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">IMService.pro</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Debug</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">18</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">18</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
229
IM Porject/IMService/imservice.cpp
Normal file
229
IM Porject/IMService/imservice.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
#include "imservice.h"
|
||||
#include "protocol.h"
|
||||
#include <QDebug>
|
||||
|
||||
// 构造函数
|
||||
IMService::IMService(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_server(new QTcpServer),
|
||||
m_clientSocket(new QMap<QString, QTcpSocket *>),
|
||||
m_clientNames(new QMap<QTcpSocket *, QString>)
|
||||
{
|
||||
connect(this->m_server, &QTcpServer::newConnection, this, &IMService::newConnection);
|
||||
if (this->m_server->listen(QHostAddress::Any, 9876))
|
||||
qDebug() << "Service open SUCCESS!";
|
||||
else
|
||||
qDebug() << this->m_server->errorString(); //错误信息
|
||||
|
||||
}
|
||||
|
||||
IMService::~IMService()
|
||||
{
|
||||
m_server->close();
|
||||
delete m_server;
|
||||
delete m_clientSocket;
|
||||
delete m_clientNames;
|
||||
qDebug() << "Service Close!";
|
||||
}
|
||||
|
||||
void IMService::closeService()
|
||||
{
|
||||
// 遍历并关闭所有Socket连接
|
||||
for (auto it : *(this->m_clientSocket))
|
||||
it->close();
|
||||
// 清空表
|
||||
this->m_clientSocket->clear();
|
||||
this->m_clientNames->clear();
|
||||
}
|
||||
|
||||
// 当有新连接进入时
|
||||
void IMService::newConnection()
|
||||
{
|
||||
// 获取这个连接的Socket
|
||||
QTcpSocket *socketTemp = this->m_server->nextPendingConnection();
|
||||
|
||||
// 当接收到数据时触发readyRead
|
||||
connect(socketTemp, &QTcpSocket::readyRead, this, &IMService::readyRead);
|
||||
|
||||
// 当连接断开时触发disconnected
|
||||
connect(socketTemp, &QTcpSocket::disconnected, this, &IMService::disconnected);
|
||||
|
||||
qDebug() << "newConnection!";
|
||||
}
|
||||
|
||||
// 当连接断开时触发
|
||||
void IMService::disconnected()
|
||||
{
|
||||
qDebug() << "disconnected!";
|
||||
|
||||
// 获取断开连接的对象
|
||||
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
|
||||
// 释放内存
|
||||
sender->deleteLater();
|
||||
|
||||
// 先查一下这个连接是否存在表中,如果没在,说明这个连接没上线,直接return即可
|
||||
if (!this->m_clientNames->contains(sender))
|
||||
return;
|
||||
|
||||
// 否则说明这是一个在线用户断开连接
|
||||
// 记录这个用户的昵称
|
||||
QString senderName = this->m_clientNames->value(sender);
|
||||
|
||||
// 将这个用户从表中移除
|
||||
this->m_clientSocket->remove(senderName);
|
||||
this->m_clientNames->remove(sender);
|
||||
|
||||
// 通知其他人该用户离线
|
||||
this->userOffline(senderName);
|
||||
}
|
||||
|
||||
// 当接收到数据时触发
|
||||
void IMService::readyRead()
|
||||
{
|
||||
// 获取接收到数据的对象
|
||||
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
|
||||
// 获取数据
|
||||
QByteArray data = sender->readAll();
|
||||
QTextStream in(data, QIODevice::ReadOnly);
|
||||
qDebug() << "readyread:" << data;
|
||||
|
||||
|
||||
// 进行协议分析与任务调度
|
||||
int functionID = 0;
|
||||
in >> functionID;
|
||||
|
||||
// 如果是登录的功能码
|
||||
if (functionID == ClientFunctionCode::Login)
|
||||
{
|
||||
QString name;
|
||||
in >> name;
|
||||
// 执行登录
|
||||
this->userLogin(name, sender);
|
||||
}
|
||||
// 检测这个连接有没有登录
|
||||
else if (this->m_clientNames->contains(sender))
|
||||
{
|
||||
// 如果是私聊消息
|
||||
if (functionID == ClientFunctionCode::SendPrivateMessage)
|
||||
{
|
||||
// 获取要发送的用户昵称
|
||||
QString toName;
|
||||
in >> toName;
|
||||
in.seek(in.pos() + 1);
|
||||
|
||||
// 将剩下的内容全部发送
|
||||
this->sendPrivateMessage(this->m_clientNames->value(sender), toName, in.readAll());
|
||||
}
|
||||
// 否则如果是群聊消息
|
||||
else if (functionID == ClientFunctionCode::SendGroupMessage)
|
||||
{
|
||||
in.seek(in.pos() + 1);
|
||||
this->sendGroupMessage(this->m_clientNames->value(sender), in.readAll());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IMService::sendData(QTcpSocket *socket, QString data)
|
||||
{
|
||||
if (socket != nullptr && socket->isOpen())
|
||||
socket->write(data.toUtf8());
|
||||
}
|
||||
|
||||
/*
|
||||
enum ServerFunctionCode {
|
||||
// 私聊消息
|
||||
PrivateMessage = 1,
|
||||
|
||||
// 群聊消息
|
||||
GroupMessage = 2,
|
||||
|
||||
// 用户上线
|
||||
UserOnline = 3,
|
||||
|
||||
// 用户下线
|
||||
UserOffline = 4,
|
||||
|
||||
// 登录结果
|
||||
LoginResult = 10
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
// 用户登录
|
||||
// 参数:name 用户昵称
|
||||
void IMService::userLogin(QString name, QTcpSocket *socket)
|
||||
{
|
||||
qDebug() << "userLogin(): user name:" << name << "\tsocket:" << socket;
|
||||
// 如果这个昵称或者连接已经登录了
|
||||
if (this->m_clientSocket->contains(name) || this->m_clientNames->contains(socket))
|
||||
{
|
||||
qDebug() << "Login failed!";
|
||||
// 发送登录结果:登录失败
|
||||
this->sendData(this->m_clientSocket->value(name), QString("%1 1").arg(ServerFunctionCode::LoginResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Login success!";
|
||||
// 获取当前在线的用户昵称
|
||||
QList<QString> temp = this->m_clientSocket->keys();
|
||||
this->m_clientSocket->insert(name, socket);
|
||||
this->m_clientNames->insert(socket, name);
|
||||
// 将所有在线用户的昵称组合
|
||||
QString ret = QString("%1 0 %2").arg(ServerFunctionCode::LoginResult).arg(temp.length());
|
||||
QTextStream ts(&ret);
|
||||
for (QString it : temp)
|
||||
ts << ' ' << it;
|
||||
qDebug() << "ret:" << ret;
|
||||
// 发送登录结果:登录成功! 并返回当前在线人员数据
|
||||
this->sendData(this->m_clientSocket->value(name), ret);
|
||||
|
||||
// 通知其他人改用户上线
|
||||
this->userOnline(name);
|
||||
}
|
||||
}
|
||||
|
||||
// 发送私聊消息
|
||||
// 参数:fromName 发送者昵称
|
||||
// 参数:toName 接收者昵称
|
||||
// 参数:content 内容
|
||||
void IMService::sendPrivateMessage(QString fromName, QString toName, QString content)
|
||||
{
|
||||
qDebug() << "sendPrivateMessage(): fromName:" << fromName << "\ttoName" << toName << "\tcontent" << content;
|
||||
// 如果该用户存在才发送
|
||||
if (this->m_clientSocket->contains(toName))
|
||||
this->sendData(this->m_clientSocket->value(toName), QString("%1 %2 %3").arg(ServerFunctionCode::PrivateMessage).arg(fromName).arg(content));
|
||||
}
|
||||
|
||||
// 发送群聊消息
|
||||
// 参数:fromName 发送者昵称
|
||||
// 参数:content 内容
|
||||
void IMService::sendGroupMessage(QString fromName, QString content)
|
||||
{
|
||||
qDebug() << "sendGroupMessage(): fromName:" << fromName << "\tcontent" << content;
|
||||
QString data = QString("%1 %2 %3").arg(ServerFunctionCode::GroupMessage).arg(fromName).arg(content);
|
||||
for (auto it = this->m_clientSocket->begin(); it != this->m_clientSocket->end(); it++)
|
||||
if (it.key() != fromName)
|
||||
this->sendData(it.value(), data);
|
||||
}
|
||||
|
||||
// 用户上线
|
||||
// 参数:name 用户昵称
|
||||
void IMService::userOnline(QString name)
|
||||
{
|
||||
qDebug() << "userOnline(): name:" << name;
|
||||
QString data = QString("%1 %2").arg(ServerFunctionCode::UserOnline).arg(name);
|
||||
for (auto it = this->m_clientSocket->begin(); it != this->m_clientSocket->end(); it++)
|
||||
if (it.key() != name)
|
||||
this->sendData(it.value(), data);
|
||||
}
|
||||
|
||||
// 用户离线
|
||||
// 参数:name 用户昵称
|
||||
void IMService::userOffline(QString name)
|
||||
{
|
||||
qDebug() << "userOffline(): name:" << name;
|
||||
QString data = QString("%1 %2").arg(ServerFunctionCode::UserOffline).arg(name);
|
||||
for (auto it = this->m_clientSocket->begin(); it != this->m_clientSocket->end(); it++)
|
||||
if (it.key() != name)
|
||||
this->sendData(it.value(), data);
|
||||
}
|
||||
129
IM Porject/IMService/imservice.h
Normal file
129
IM Porject/IMService/imservice.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef IMSERVICE_H
|
||||
#define IMSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtNetwork>
|
||||
#include <QMap>
|
||||
|
||||
/***********************************
|
||||
*
|
||||
* Class IMService
|
||||
* IM服务端类
|
||||
*
|
||||
* 用于与客户端交互的封装类
|
||||
*
|
||||
* 公开方法有:
|
||||
* login 登录
|
||||
* sendPrivateMessage 发送私聊消息
|
||||
* sendGroupMessage 发送群聊消息
|
||||
*
|
||||
* 发出的信号有:
|
||||
* receivedPrivateMessage 接收到私聊消息信号
|
||||
* receivedGroupMessage 接收到群聊消息信号
|
||||
* userOnline 用户上线信号
|
||||
* userOffline 用户下线信号
|
||||
* serverClose 服务器关闭信号
|
||||
*
|
||||
**********************************/
|
||||
|
||||
class IMService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
// 公开成员函数
|
||||
public:
|
||||
explicit IMService(QObject *parent = nullptr);
|
||||
|
||||
~IMService();
|
||||
|
||||
/**
|
||||
* @brief closeService 关闭服务 断开所有Socket连接
|
||||
*/
|
||||
void closeService();
|
||||
// 信号
|
||||
signals:
|
||||
|
||||
|
||||
// 槽
|
||||
public slots:
|
||||
/**
|
||||
* @brief newConnection 当有新连接进入时
|
||||
*/
|
||||
void newConnection();
|
||||
|
||||
/**
|
||||
* @brief disconnected 当连接断开时触发
|
||||
*/
|
||||
void disconnected();
|
||||
|
||||
/**
|
||||
* @brief readyRead 当接收到数据时触发
|
||||
*/
|
||||
void readyRead();
|
||||
|
||||
// 私有成员函数
|
||||
private:
|
||||
// 发送数据到socket对象中
|
||||
/**
|
||||
* @brief sendData 发送数据到socket对象中
|
||||
* @param socket 指定socket对象
|
||||
* @param data 要发送的数据
|
||||
*/
|
||||
void sendData(QTcpSocket *socket, QString data);
|
||||
|
||||
/**
|
||||
* @brief userLogin 用户登录
|
||||
* @param name 用户昵称
|
||||
* @param socket socket对象
|
||||
*/
|
||||
void userLogin(QString name, QTcpSocket *socket);
|
||||
|
||||
/**
|
||||
* @brief sendPrivateMessage 发送私聊消息
|
||||
* @param fromName 发送者昵称
|
||||
* @param toName 接收者昵称
|
||||
* @param content 内容
|
||||
*/
|
||||
void sendPrivateMessage(QString fromName, QString toName, QString content);
|
||||
|
||||
/**
|
||||
* @brief sendGroupMessage 发送群聊消息
|
||||
* @param fromName 发送者昵称
|
||||
* @param content 内容
|
||||
*/
|
||||
void sendGroupMessage(QString fromName, QString content);
|
||||
|
||||
/**
|
||||
* @brief userOnline 用户上线
|
||||
* @param name 用户昵称
|
||||
*/
|
||||
void userOnline(QString name);
|
||||
|
||||
/**
|
||||
* @brief userOffline 用户离线
|
||||
* @param name 用户昵称
|
||||
*/
|
||||
void userOffline(QString name);
|
||||
|
||||
// 私有成员变量
|
||||
private:
|
||||
/**
|
||||
* @brief m_server 服务端的Tcp Server对象
|
||||
*/
|
||||
QTcpServer *m_server;
|
||||
|
||||
// 客户端的Tcp Socket连接列表
|
||||
// QMap是一个键值对容器,在这里key是用户的昵称,value是用户的Socket连接对象
|
||||
// 每当一个新用户上线,将会添加到该容器中
|
||||
// 当用户下线时则从容器中删除
|
||||
/**
|
||||
* @brief m_clientSocket 客户端的Tcp Socket连接列表
|
||||
*/
|
||||
QMap<QString, QTcpSocket *> *m_clientSocket;
|
||||
/**
|
||||
* @brief m_clientNames 客户端的昵称列表
|
||||
*/
|
||||
QMap<QTcpSocket *, QString> *m_clientNames;
|
||||
};
|
||||
|
||||
#endif // IMSERVICE_H
|
||||
13
IM Porject/IMService/main.cpp
Normal file
13
IM Porject/IMService/main.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QTextCodec>
|
||||
#include "imservice.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
||||
QTextCodec::setCodecForLocale(codec);
|
||||
static IMService imService;
|
||||
return a.exec();
|
||||
}
|
||||
59
IM Porject/IMService/protocol.h
Normal file
59
IM Porject/IMService/protocol.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
/************************************************
|
||||
* IM通讯协议规定
|
||||
*
|
||||
* 功能码 [参数]
|
||||
*
|
||||
* 客户端功能码规定: 参数: 例子: 说明:
|
||||
* 1 = 请求登录 用户昵称 1 张三 当客户端登录时必须先发送这条命令,告诉服务端自己的昵称
|
||||
* 2 = 发送私聊消息 私聊对象 消息内容 2 李四 你妈喊你回家吃饭 当A向B发送一条私聊消息时,A要向服务器发送这条指令,告诉服务器消息发给谁和发什么消息
|
||||
* 3 = 发送群聊消息 消息内容 3 大家好,我是张三 当A向群聊发送一条消息时,直接告诉服务端需要发什么内容即可
|
||||
*
|
||||
* 服务端功能码规定: 参数: 例子: 说明:
|
||||
* 1 = 发送私聊消息 用户昵称 消息内容 1 张三 你妈喊你回家吃饭 当A向B发送一条私聊消息时,B会收到这条指令,其中昵称是指A(发送者)的昵称
|
||||
* 2 = 发送群聊消息 用户昵称 消息内容 2 张三 大家好,我是张三 当A向群聊发送一条消息时,所有人都会收到这条指令,其中昵称是指A(发送者)的昵称
|
||||
* 3 = 某人上线 用户昵称 3 张三 当A上线时,所有人都会收到这条指令,其中昵称是A(上线者)的昵称
|
||||
* 4 = 某人下线 用户昵称 4 张三 当A下线时,所有人都会手套这条指令,其中昵称是A(下线者)的昵称
|
||||
* 10 = 登录结果 是否成功(0:成功,!0:失败) [当前在线人数] [当前在线人员列表]
|
||||
* 成功时 10 0 4 张三 李四 王五 赵六 当客户端发送登录请求后,如果登录成功则返回当前在线人数与昵称列表,如果失败就返回一个!0值
|
||||
* 失败时 10 1
|
||||
*
|
||||
***********************************************/
|
||||
|
||||
/**
|
||||
* @brief 服务端功能码
|
||||
*/
|
||||
enum ServerFunctionCode {
|
||||
// 私聊消息
|
||||
PrivateMessage = 1,
|
||||
|
||||
// 群聊消息
|
||||
GroupMessage = 2,
|
||||
|
||||
// 用户上线
|
||||
UserOnline = 3,
|
||||
|
||||
// 用户下线
|
||||
UserOffline = 4,
|
||||
|
||||
// 登录结果
|
||||
LoginResult = 10
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 客户端功能码
|
||||
*/
|
||||
enum ClientFunctionCode {
|
||||
// 登录
|
||||
Login = 1,
|
||||
|
||||
// 发送私聊消息
|
||||
SendPrivateMessage = 2,
|
||||
|
||||
// 发送群聊消息
|
||||
SendGroupMessage = 3
|
||||
};
|
||||
|
||||
#endif // PROTOCOL_H
|
||||
Reference in New Issue
Block a user