From dc7bb1b907e0354f2bb6393b2505434e67494f6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 18:54:12 +0000 Subject: [PATCH 1/9] Bump commons-fileupload:commons-fileupload from 1.5 to 1.6.0 Bumps commons-fileupload:commons-fileupload from 1.5 to 1.6.0. --- updated-dependencies: - dependency-name: commons-fileupload:commons-fileupload dependency-version: 1.6.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 43a166573..7c554d1d6 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ commons-fileupload commons-fileupload - 1.5 + 1.6.0 From 1e3cae4c0e566d7a19a49097bd361386d2baf38a Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 21:54:20 +0200 Subject: [PATCH 2/9] spark-form.jsp: fix active checkbox for Mac and Linux --- src/web/spark-form.jsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/spark-form.jsp b/src/web/spark-form.jsp index 998b59055..96fb0c836 100644 --- a/src/web/spark-form.jsp +++ b/src/web/spark-form.jsp @@ -240,7 +240,7 @@ <% for (Path clientFile : list) { Date buildDate = Date.from(Files.getLastModifiedTime(clientFile).toInstant()); - Boolean isSelected = clientFile.getFileName().toString().equals(windowClient); + Boolean isSelected = clientFile.getFileName().toString().equals(macClient); request.setAttribute("fileName", clientFile.getFileName().toString()); request.setAttribute("selected", isSelected); request.setAttribute("buildDate", buildDate); @@ -286,7 +286,7 @@ <% for (Path clientFile : list) { Date buildDate = Date.from(Files.getLastModifiedTime(clientFile).toInstant()); - Boolean isSelected = clientFile.getFileName().toString().equals(windowClient); + Boolean isSelected = clientFile.getFileName().toString().equals(linuxClient); request.setAttribute("fileName", clientFile.getFileName().toString()); request.setAttribute("selected", isSelected); request.setAttribute("buildDate", buildDate); From 7326774d5bbd978492c41b806326bda742f39415 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 21:54:39 +0200 Subject: [PATCH 3/9] remove unused SparkUtil class --- .../openfire/plugin/spark/SparkUtil.java | 338 ------------------ 1 file changed, 338 deletions(-) delete mode 100644 src/java/org/jivesoftware/openfire/plugin/spark/SparkUtil.java diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/SparkUtil.java b/src/java/org/jivesoftware/openfire/plugin/spark/SparkUtil.java deleted file mode 100644 index 74084c5ff..000000000 --- a/src/java/org/jivesoftware/openfire/plugin/spark/SparkUtil.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 1999-2008 Jive Software. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jivesoftware.openfire.plugin.spark; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -/** - * Utility methods frequently used by data classes and design-time - * classes. - */ -public final class SparkUtil { - - private SparkUtil() { - // Prevent instantiation. - } - - /** - * This is a utility method that compares two objects when one or - * both of the objects might be null The result of - * this method is determined as follows: - *
    - *
  1. If o1 and o2 are the same object - * according to the == operator, return - * true. - *
  2. Otherwise, if either o1 or o2 is - * null, return false. - *
  3. Otherwise, return o1.equals(o2). - *
- *

- * This method produces the exact logically inverted result as the - * {@link #areDifferent(Object, Object)} method.

- *

- * For array types, one of the equals methods in - * {@link java.util.Arrays} should be used instead of this method. - * Note that arrays with more than one dimension will require some - * custom code in order to implement equals properly. - */ - public static final boolean areEqual(Object o1, Object o2) { - if (o1 == o2) { - return true; - } - else if (o1 == null || o2 == null) { - return false; - } - else { - return o1.equals(o2); - } - } - - /** - * This is a utility method that compares two Booleans when one or - * both of the objects might be null The result of - * this method is determined as follows: - *

    - *
  1. If b1 and b2 are both TRUE or - * neither b1 nor b2 is TRUE, - * return true. - *
  2. Otherwise, return false. - *
- *

- * This method produces the exact logically inverted result as the - * areDifferent(Boolean, Boolean) method.

- */ - public static final boolean areBooleansEqual(Boolean b1, Boolean b2) { - // !jwetherb treat NULL the same as Boolean.FALSE - return (b1 == Boolean.TRUE && b2 == Boolean.TRUE) || - (b1 != Boolean.TRUE && b2 != Boolean.TRUE); - } - - /** - * This is a utility method that compares two objects when one or - * both of the objects might be null. The result - * returned by this method is determined as follows: - *

    - *
  1. If o1 and o2 are the same object - * according to the == operator, return - * false. - *
  2. Otherwise, if either o1 or o2 is - * null, return true. - *
  3. Otherwise, return !o1.equals(o2). - *
- *

- * This method produces the exact logically inverted result as the - * {@link #areEqual(Object, Object)} method.

- *

- * For array types, one of the equals methods in - * {@link java.util.Arrays} should be used instead of this method. - * Note that arrays with more than one dimension will require some - * custom code in order to implement equals properly. - */ - public static final boolean areDifferent(Object o1, Object o2) { - return !areEqual(o1, o2); - } - - - /** - * This is a utility method that compares two Booleans when one or - * both of the objects might be null The result of - * this method is determined as follows: - *

    - *
  1. If b1 and b2 are both TRUE or - * neither b1 nor b2 is TRUE, - * return false. - *
  2. Otherwise, return true. - *
- *

- * This method produces the exact logically inverted result as the - * {@link #areBooleansEqual(Boolean, Boolean)} method.

- */ - public static final boolean areBooleansDifferent(Boolean b1, Boolean b2) { - return !areBooleansEqual(b1, b2); - } - - - /** - * Returns true if the specified array is not null - * and contains a non-null element. Returns false - * if the array is null or if all the array elements are null. - */ - public static final boolean hasNonNullElement(Object[] array) { - if (array != null) { - final int n = array.length; - for (int i = 0; i < n; i++) { - if (array[i] != null) { - return true; - } - } - } - return false; - } - - /** - * Returns a single string that is the concatenation of all the - * strings in the specified string array. A single space is - * put between each string array element. Null array elements - * are skipped. If the array itself is null, the empty string - * is returned. This method is guaranteed to return a non-null - * value, if no expections are thrown. - */ - public static final String concat(String[] strs) { - return concat(strs, " "); //NOTRANS - } - - /** - * Returns a single string that is the concatenation of all the - * strings in the specified string array. The strings are separated - * by the specified delimiter. Null array elements are skipped. If - * the array itself is null, the empty string is returned. This - * method is guaranteed to return a non-null value, if no expections - * are thrown. - */ - public static final String concat(String[] strs, String delim) { - if (strs != null) { - final StringBuffer buf = new StringBuffer(); - final int n = strs.length; - for (int i = 0; i < n; i++) { - final String str = strs[i]; - if (str != null) { - buf.append(str).append(delim); - } - } - final int length = buf.length(); - if (length > 0) { - // Trim trailing space. - buf.setLength(length - 1); - } - return buf.toString(); - } - else { - return ""; // NOTRANS - } - } - - /** - * Returns true if the specified {@link String} is not - * null and has a length greater than zero. This is - * a very frequently occurring check. - */ - public static final boolean hasLength(String s) { - return (s != null && s.length() > 0); - } - - - /** - * Returns null if the specified string is empty or - * null. Otherwise the string itself is returned. - */ - public static final String nullifyIfEmpty(String s) { - return hasLength(s) ? s : null; - } - - /** - * Returns null if the specified object is null - * or if its toString() representation is empty. - * Otherwise, the toString() representation of the - * object itself is returned. - */ - public static final String nullifyingToString(Object o) { - return o != null ? nullifyIfEmpty(o.toString()) : null; - } - - /** - * Determines if a string has been changed. - * - * @param oldString is the initial value of the String - * @param newString is the new value of the String - * @return true If both oldString and newString are null or if they are - * both not null and equal to each other. Otherwise returns false. - */ - public static boolean hasStringChanged(String oldString, String newString) { - if (oldString == null && newString == null) { - return false; - } - else if ((oldString == null && newString != null) - || (oldString != null && newString == null)) { - return true; - } - else { - return !oldString.equals(newString); - } - } - - /** - * Returns a formatted String from time. - * - * @param diff the amount of elapsed time. - * @return the formatte String. - */ - public static String getTimeFromLong(long diff) { - final String HOURS = "h"; - final String MINUTES = "min"; - //final String SECONDS = "sec"; - - final long MS_IN_A_DAY = 1000 * 60 * 60 * 24; - final long MS_IN_AN_HOUR = 1000 * 60 * 60; - final long MS_IN_A_MINUTE = 1000 * 60; - final long MS_IN_A_SECOND = 1000; - //Date currentTime = new Date(); - //long numDays = diff / MS_IN_A_DAY; - diff = diff % MS_IN_A_DAY; - long numHours = diff / MS_IN_AN_HOUR; - diff = diff % MS_IN_AN_HOUR; - long numMinutes = diff / MS_IN_A_MINUTE; - diff = diff % MS_IN_A_MINUTE; - //long numSeconds = diff / MS_IN_A_SECOND; - diff = diff % MS_IN_A_SECOND; - //long numMilliseconds = diff; - - StringBuffer buf = new StringBuffer(); - if (numHours > 0) { - buf.append(numHours + " " + HOURS + ", "); - } - - if (numMinutes > 0) { - buf.append(numMinutes + " " + MINUTES); - } - - //buf.append(numSeconds + " " + SECONDS); - - String result = buf.toString(); - - if (numMinutes < 1) { - result = "< 1 minute"; - } - - return result; - } - - - /** - * Build a List of all elements in an Iterator. - */ - public static List iteratorAsList(Iterator i) { - ArrayList list = new ArrayList(10); - while (i.hasNext()) { - list.add(i.next()); - } - return list; - } - - /** - * Creates an Iterator that is the reverse of a ListIterator. - */ - public static Iterator reverseListIterator(ListIterator i) { - return new ReverseListIterator(i); - } -} - -/** - * An Iterator that is the reverse of a ListIterator. - */ -class ReverseListIterator implements Iterator { - private ListIterator listIterator; - - ReverseListIterator(ListIterator i) { - listIterator = i; - while (listIterator.hasNext()) listIterator.next(); - } - - public boolean hasNext() { - return listIterator.hasPrevious(); - } - - public E next() { - return listIterator.previous(); - } - - public void remove() { - listIterator.remove(); - } -} - - - - - - - - - - From 4b7f7453e5c226216ff3de0e12b94075ea3d486a Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 21:56:04 +0200 Subject: [PATCH 4/9] Fix linter warnings: missing @Override, JavaDoc tags --- .../openfire/plugin/ClientControlPlugin.java | 3 +- .../openfire/plugin/spark/SparkManager.java | 11 ++++++++ .../openfire/plugin/spark/TaskEngine.java | 28 +++++++++---------- .../spark/manager/SparkDownloadServlet.java | 7 ++--- .../spark/manager/SparkVersionManager.java | 11 ++++++-- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/java/org/jivesoftware/openfire/plugin/ClientControlPlugin.java b/src/java/org/jivesoftware/openfire/plugin/ClientControlPlugin.java index 6f1629195..b58af77be 100644 --- a/src/java/org/jivesoftware/openfire/plugin/ClientControlPlugin.java +++ b/src/java/org/jivesoftware/openfire/plugin/ClientControlPlugin.java @@ -45,6 +45,7 @@ public ClientControlPlugin() { // Plugin Interface + @Override public void initializePlugin(PluginManager manager, File pluginDirectory) { taskEngine = TaskEngine.getInstance(); sparkManager = new SparkManager(taskEngine); @@ -56,13 +57,13 @@ public void initializePlugin(PluginManager manager, File pluginDirectory) { fileTransferFilterManager = new FileTransferFilterManager(); fileTransferFilterManager.start(); - } public FileTransferFilterManager getFileTransferFilterManager() { return fileTransferFilterManager; } + @Override public void destroyPlugin() { if (sparkManager != null) { sparkManager.stop(); diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/SparkManager.java b/src/java/org/jivesoftware/openfire/plugin/spark/SparkManager.java index f5b61588d..433e2b8b3 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/SparkManager.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/SparkManager.java @@ -114,10 +114,12 @@ public SparkManager(TaskEngine taskEngine) { } + @Override public String getName() { return "Features Component"; } + @Override public String getDescription() { return "Allows for discovery of certain features."; } @@ -129,6 +131,7 @@ public String getDescription() { * * @param packet the packet */ + @Override public void processPacket(Packet packet) { if (packet instanceof IQ) { IQ iqPacket = (IQ)packet; @@ -241,10 +244,12 @@ private void handleClientVersion(IQ iq) { } } + @Override public void initialize(JID jid, ComponentManager componentManager) throws ComponentException { // Do nothing. } + @Override public void start() { // Do nothing. } @@ -270,6 +275,7 @@ public void stop() { * Remove any resources SparkManager was using. This will allow * for a clean reload. */ + @Override public void shutdown() { // Cleanup SessionEventDispatcher.removeListener(sessionEventListener); @@ -614,6 +620,7 @@ private class SparkSessionListener implements SessionEventListener { * * @param session the newly created session. */ + @Override public void sessionCreated(final Session session) { // Check to see if Spark is required. String clientsAllowed = JiveGlobals.getProperty("clients.allowed", "all"); @@ -636,18 +643,22 @@ public void run() { * * @param session the session destroyed. */ + @Override public void sessionDestroyed(Session session) { } + @Override public void resourceBound(Session session) { // Do nothing. } + @Override public void anonymousSessionCreated(Session session) { // Ignore. } + @Override public void anonymousSessionDestroyed(Session session) { // Ignore. } diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/TaskEngine.java b/src/java/org/jivesoftware/openfire/plugin/spark/TaskEngine.java index df437339a..5b045bdec 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/TaskEngine.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/TaskEngine.java @@ -68,7 +68,7 @@ private TaskEngine() { * * @param task the task to submit. * @return a Future representing pending completion of the task, - * and whose get() method will return null + * and whose get() method will return null * upon completion. * @throws java.util.concurrent.RejectedExecutionException if task cannot be scheduled * for execution. @@ -83,8 +83,8 @@ public Future submit(Runnable task) { * * @param task task to be scheduled. * @param delay delay in milliseconds before task is to be executed. - * @throws IllegalArgumentException if delay is negative, or - * delay + System.currentTimeMillis() is negative. + * @throws IllegalArgumentException if delay is negative, or + * delay + System.currentTimeMillis() is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, or timer was cancelled. */ @@ -98,7 +98,7 @@ public void schedule(TimerTask task, long delay) { * * @param task task to be scheduled. * @param time time at which task is to be executed. - * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalArgumentException if time.getTime() is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. */ @@ -117,7 +117,7 @@ public void schedule(TimerTask task, Date time) { * background activity), subsequent executions will be delayed as well. * In the long run, the frequency of execution will generally be slightly * lower than the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). + * clock underlying Object.wait(long) is accurate). * *

Fixed-delay execution is appropriate for recurring activities * that require "smoothness." In other words, it is appropriate for @@ -131,8 +131,8 @@ public void schedule(TimerTask task, Date time) { * @param task task to be scheduled. * @param delay delay in milliseconds before task is to be executed. * @param period time in milliseconds between successive task executions. - * @throws IllegalArgumentException if delay is negative, or - * delay + System.currentTimeMillis() is negative. + * @throws IllegalArgumentException if delay is negative, or + * delay + System.currentTimeMillis() is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. */ @@ -153,7 +153,7 @@ public void schedule(TimerTask task, long delay, long period) { * background activity), subsequent executions will be delayed as well. * In the long run, the frequency of execution will generally be slightly * lower than the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). + * clock underlying Object.wait(long) is accurate). * *

Fixed-delay execution is appropriate for recurring activities * that require "smoothness." In other words, it is appropriate for @@ -167,7 +167,7 @@ public void schedule(TimerTask task, long delay, long period) { * @param task task to be scheduled. * @param firstTime First time at which task is to be executed. * @param period time in milliseconds between successive task executions. - * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalArgumentException if time.getTime() is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. */ @@ -188,7 +188,7 @@ public void schedule(TimerTask task, Date firstTime, long period) { * activity), two or more executions will occur in rapid succession to * "catch up." In the long run, the frequency of execution will be * exactly the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). + * clock underlying Object.wait(long) is accurate). * *

Fixed-rate execution is appropriate for recurring activities that * are sensitive to absolute time, such as ringing a chime every @@ -203,8 +203,8 @@ public void schedule(TimerTask task, Date firstTime, long period) { * @param task task to be scheduled. * @param delay delay in milliseconds before task is to be executed. * @param period time in milliseconds between successive task executions. - * @throws IllegalArgumentException if delay is negative, or - * delay + System.currentTimeMillis() is negative. + * @throws IllegalArgumentException if delay is negative, or + * delay + System.currentTimeMillis() is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. */ @@ -225,7 +225,7 @@ public void scheduleAtFixedRate(TimerTask task, long delay, long period) { * activity), two or more executions will occur in rapid succession to * "catch up." In the long run, the frequency of execution will be * exactly the reciprocal of the specified period (assuming the system - * clock underlying Object.wait(long) is accurate). + * clock underlying Object.wait(long) is accurate). * *

Fixed-rate execution is appropriate for recurring activities that * are sensitive to absolute time, such as ringing a chime every @@ -240,7 +240,7 @@ public void scheduleAtFixedRate(TimerTask task, long delay, long period) { * @param task task to be scheduled. * @param firstTime First time at which task is to be executed. * @param period time in milliseconds between successive task executions. - * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalArgumentException if time.getTime() is negative. * @throws IllegalStateException if task was already scheduled or * cancelled, timer was cancelled, or timer thread terminated. */ diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java index 4286845e4..56ea82f4f 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java @@ -33,9 +33,8 @@ import java.util.List; /** - * Provides support for downloading the Jive Spark IM client. - * (Spark).

- *

+ * Provides support for downloading the Spark IM client. + * (Spark). * * @author Derek DeMoro */ @@ -91,7 +90,7 @@ else if(clientFile.getName().endsWith(".tar.gz") && "linux".equals(os)){ private void sendClientBuild(HttpServletResponse resp, final String clientBuild) throws IOException { // Determine release location. All builds should be put into the document_root/releases directory - // and be named appropriatly (ex. spark_1_0_0.exe, spark_1_0_1.dmg) + // and be named appropriately (ex. spark_1_0_0.exe, spark_1_0_1.dmg) Path clientFile = JiveGlobals.getHomePath().resolve("enterprise").resolve("spark").resolve(clientBuild); // Set content size diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java index 0e30b4aff..c55ce08a3 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java @@ -37,12 +37,11 @@ /** * Provides support for server administrators to control the global updating of the Jive Spark IM client. - * (Spark).

- *

+ * (Spark). + *

* The basic functionality is to query the server for the latest client * version and return that information. The version comparison is left to * the client itself, so as to keep the SparkVersionManager simple. - *

* * @author Derek DeMoro */ @@ -66,6 +65,7 @@ public SparkVersionManager() { * * @return the name of this plugin. */ + @Override public String getName() { return "Spark Version Manager"; } @@ -75,10 +75,12 @@ public String getName() { * * @return a brief description of this plugin. */ + @Override public String getDescription() { return "Allow admins to control the updating of the Spark IM Client."; } + @Override public void processPacket(Packet packet) { if (packet instanceof IQ) { IQ iqPacket = (IQ)packet; @@ -219,14 +221,17 @@ private void handleDiscoInfo(IQ packet) { sendPacket(replyPacket); } + @Override public void initialize(JID jid, ComponentManager componentManager) throws ComponentException { // Do nothing. } + @Override public void start() { // Do nothing } + @Override public void shutdown() { // Do nothing. } From b00df47ea552a8f3385ebb3ef504443db9573a77 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 21:56:53 +0200 Subject: [PATCH 5/9] SparkVersionManager: add error descriptions --- .../openfire/plugin/spark/manager/SparkVersionManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java index c55ce08a3..b6a06c9bd 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java @@ -130,7 +130,7 @@ private void handleSparkIQ(IQ packet) { // Handle Invalid Requests if (os == null || (!os.equals("windows") && !os.equals("mac") && !os.equals("linux"))) { reply.setChildElement(packet.getChildElement().createCopy()); - reply.setError(new PacketError(PacketError.Condition.not_acceptable)); + reply.setError(new PacketError(PacketError.Condition.not_acceptable, PacketError.Type.modify, "Invalid OS")); sendPacket(reply); return; } @@ -168,7 +168,7 @@ else if (os.equals("linux")) { Path clientFile = JiveGlobals.getHomePath().resolve("enterprise").resolve("spark").resolve(client); if (!Files.exists(clientFile)) { reply.setChildElement(packet.getChildElement().createCopy()); - reply.setError(new PacketError(PacketError.Condition.item_not_found)); + reply.setError(new PacketError(PacketError.Condition.item_not_found, PacketError.Type.cancel, "Client package not found")); sendPacket(reply); return; } @@ -192,7 +192,7 @@ else if (os.equals("linux")) { } else { reply.setChildElement(packet.getChildElement().createCopy()); - reply.setError(new PacketError(PacketError.Condition.item_not_found)); + reply.setError(new PacketError(PacketError.Condition.item_not_found, PacketError.Type.cancel, "OS client unsupported")); sendPacket(reply); return; } From 5afa5ff5bbd6dc041b1edff51e5f329c3aae9f44 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Wed, 1 Apr 2026 22:30:57 +0300 Subject: [PATCH 6/9] Improve comments --- .../spark/manager/SparkDownloadServlet.java | 4 +-- .../spark/manager/SparkVersionManager.java | 30 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java index 56ea82f4f..6c291861f 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkDownloadServlet.java @@ -48,7 +48,7 @@ public void init(ServletConfig config) throws ServletException { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // Handle Version Request. Only handle windows and mac version at this time. + // Handle Version Request final String clientBuild = request.getParameter("client"); final String os = request.getParameter("os"); @@ -89,7 +89,7 @@ else if(clientFile.getName().endsWith(".tar.gz") && "linux".equals(os)){ } private void sendClientBuild(HttpServletResponse resp, final String clientBuild) throws IOException { - // Determine release location. All builds should be put into the document_root/releases directory + // Determine release location. All builds should be put into the C:\Program files\Openfire\enterprise\spark or /usr/share/enterprise/spark directory // and be named appropriately (ex. spark_1_0_0.exe, spark_1_0_1.dmg) Path clientFile = JiveGlobals.getHomePath().resolve("enterprise").resolve("spark").resolve(clientBuild); diff --git a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java index b6a06c9bd..97a689a0a 100644 --- a/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java +++ b/src/java/org/jivesoftware/openfire/plugin/spark/manager/SparkVersionManager.java @@ -37,7 +37,7 @@ /** * Provides support for server administrators to control the global updating of the Jive Spark IM client. - * (Spark). + * (Spark). *

* The basic functionality is to query the server for the latest client * version and return that information. The version comparison is left to @@ -123,7 +123,8 @@ private void handleSparkIQ(IQ packet) { Element iq = packet.getChildElement(); // Define default values - String os = iq.element("os").getText(); + Element osElement = iq.element("os"); + String os = osElement != null ? osElement.getText() : null; reply = IQ.createResultIQ(packet); @@ -137,19 +138,16 @@ private void handleSparkIQ(IQ packet) { Element sparkElement = reply.setChildElement("query", "jabber:iq:spark"); String client = null; - - // Handle Windows clients - if (os.equals("windows")) { - client = JiveGlobals.getProperty("spark.windows.client"); - } - // Handle Mac clients. - else if (os.equals("mac")) { - client = JiveGlobals.getProperty("spark.mac.client"); - } - - // Handle Linux Client. - else if (os.equals("linux")) { - client = JiveGlobals.getProperty("spark.linux.client"); + switch (os) { + case "windows": // Handle Windows clients + client = JiveGlobals.getProperty("spark.windows.client"); + break; + case "mac": // Handle Mac clients. + client = JiveGlobals.getProperty("spark.mac.client"); + break; + case "linux": // Handle Linux Client. + client = JiveGlobals.getProperty("spark.linux.client"); + break; } if (client != null) { @@ -160,7 +158,7 @@ else if (os.equals("linux")) { int indexOfPeriod = versionNumber.indexOf("."); versionNumber = versionNumber.substring(0, indexOfPeriod); - versionNumber = versionNumber.replaceAll("_", "."); + versionNumber = versionNumber.replace("_", "."); sparkElement.addElement("version").setText(versionNumber); From 59714024339bbc685fb88cf0240df2e9a37f102a Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 22:13:05 +0200 Subject: [PATCH 7/9] permitted-clients.jsp: remove obsolete clients, add few popular --- src/web/images/client-icon_atalk.png | Bin 0 -> 6083 bytes src/web/images/client-icon_conversations.png | Bin 0 -> 660 bytes src/web/images/client-icon_exodus.gif | Bin 552 -> 0 bytes src/web/images/client-icon_gajim.png | Bin 0 -> 3147 bytes src/web/images/client-icon_ichat.gif | Bin 1033 -> 0 bytes src/web/images/client-icon_jbother.gif | Bin 363 -> 0 bytes src/web/images/client-icon_kaidan.png | Bin 0 -> 1610 bytes src/web/images/client-icon_pandion.gif | Bin 94 -> 0 bytes src/web/permitted-clients.jsp | 18 +++++++++--------- 9 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 src/web/images/client-icon_atalk.png create mode 100644 src/web/images/client-icon_conversations.png delete mode 100644 src/web/images/client-icon_exodus.gif create mode 100644 src/web/images/client-icon_gajim.png delete mode 100644 src/web/images/client-icon_ichat.gif delete mode 100644 src/web/images/client-icon_jbother.gif create mode 100644 src/web/images/client-icon_kaidan.png delete mode 100644 src/web/images/client-icon_pandion.gif diff --git a/src/web/images/client-icon_atalk.png b/src/web/images/client-icon_atalk.png new file mode 100644 index 0000000000000000000000000000000000000000..153c124308ab9ddac0802adf371f7ed8513b36df GIT binary patch literal 6083 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 JPDHLkV1h6y(9i$? literal 0 HcmV?d00001 diff --git a/src/web/images/client-icon_conversations.png b/src/web/images/client-icon_conversations.png new file mode 100644 index 0000000000000000000000000000000000000000..23006f8d98a938b5b5fa55e08f2685ebfc66e37a GIT binary patch literal 660 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 IM6N<$f)D-}c>n+a literal 0 HcmV?d00001 diff --git a/src/web/images/client-icon_pandion.gif b/src/web/images/client-icon_pandion.gif deleted file mode 100644 index 7a71da5f7d3cb2fbbc1f66109cdd2075e6c93cda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94 zcmZ?wbhEHb6krfwn8?6z;J|@~hKB$D|1&T!DE?#tk_-$wAOa-Mz@$H?UtHm(_9ADU uQ<)2no-oS`iQmL>^H~V{tObrN3eOg#6<6H%Uy^K4@yb{1z@sG$4Aua1XCUDK diff --git a/src/web/permitted-clients.jsp b/src/web/permitted-clients.jsp index 5c40775c8..527a1cb10 100644 --- a/src/web/permitted-clients.jsp +++ b/src/web/permitted-clients.jsp @@ -17,15 +17,15 @@ * Enumeration of possible clients. */ enum Clients { - Spark("Spark", "spark", "http://www.igniterealtime.org/projects/spark/index.jsp", "images/client-icon_spark.gif"), - Adium("Adium", "libgaim", "http://www.adiumx.com/", "images/client-icon_adium.gif"), - Exodus("Exodus", "exodus", "http://exodus.jabberstudio.org/", "images/client-icon_exodus.gif"), - Pidgin("Pidgin", "pidgin", "http://www.pidgin.im/", "images/client-icon_pidgin.gif"), - IChat("IChat", "ichat", "http://www.mac.com/1/ichat.html", "images/client-icon_ichat.gif"), - JBother("JBother", "jbother", "http://www.jbother.org/", "images/client-icon_jbother.gif"), - Pandion("Pandion", "pandion", "http://www.pandion.be/", "images/client-icon_pandion.gif"), - PSI("PSI", "psi", "http://psi-im.org", "images/client-icon_psi.gif"), - Trillian("Trillian", "trillian", "http://www.ceruleanstudios.com/", "images/client-icon_trillian.gif"); + Spark("Spark", "spark", "https://igniterealtime.org/projects/spark/", "images/client-icon_spark.gif"), + Adium("Adium", "libgaim", "https://adium.im/", "images/client-icon_adium.gif"), + Atalk("aTalk", "atalk", "https://cmeng-git.github.io/atalk/", "images/client-icon_atalk.png"), + Conversations("Conversations", "conversations", "https://conversations.im/", "images/client-icon_conversations.png"), + Gajim("Gajim", "gajim", "https://gajim.org/", "images/client-icon_gajim.png"), + Kaidan("Kaidan", "kaidan", "https://kaidan.im/", "images/client-icon_kaidan.png"), + Pidgin("Pidgin", "pidgin", "https://pidgin.im/", "images/client-icon_pidgin.gif"), + PSI("PSI", "psi", "https://psi-im.org", "images/client-icon_psi.gif"), + Trillian("Trillian", "trillian", "https://www.trillian.im/", "images/client-icon_trillian.gif"); private String name; private String version; From a566e0dcb08f0904dfd97506ed203fa4c3610324 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 22:17:57 +0200 Subject: [PATCH 8/9] Denote 2.2.0 Release --- changelog.html | 5 ++++- pom.xml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/changelog.html b/changelog.html index 27cd5726d..2e89159ad 100644 --- a/changelog.html +++ b/changelog.html @@ -44,8 +44,11 @@

Client Control Plugin Changelog

-

2.1.11 Unreleased version

+

2.2.0 March 15, 2026

    +
  • Fix Spark Version activation for Linux and macOS
  • +
  • Permitted clients page: Remove old clients and add new
  • +
  • Bump commons-fileupload from 1.5 to 1.6.

2.1.10 June 24, 2025

diff --git a/pom.xml b/pom.xml index 7c554d1d6..205ab8dcd 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.igniterealtime.openfire.plugins clientControl - 2.1.11-SNAPSHOT + 2.2.0 ClientControl Plugin Controls clients allowed to connect and available features From a084c66b69bcdd54939a9b65d19cac3326016475 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 15 Mar 2026 22:22:37 +0200 Subject: [PATCH 9/9] March version to 2.2.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 205ab8dcd..bb46bfd89 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.igniterealtime.openfire.plugins clientControl - 2.2.0 + 2.2.1-SNAPSHOT ClientControl Plugin Controls clients allowed to connect and available features