mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 17:13:21 +00:00 
			
		
		
		
	Merge 1.5.0 changes back to master.
This commit is contained in:
		| @@ -709,6 +709,21 @@ Guacamole.Client = function(tunnel) { | ||||
|      *     A status object which describes the error. | ||||
|      */ | ||||
|     this.onerror = null; | ||||
|      | ||||
|     /** | ||||
|      * Fired when an arbitrary message is received from the tunnel that should | ||||
|      * be processed by the client. | ||||
|      *  | ||||
|      * @event | ||||
|      * @param {!number} msgcode | ||||
|      *     A status code sent by the remote server that indicates the nature of | ||||
|      *     the message that is being sent to the client. | ||||
|      *      | ||||
|      * @param {string[]} args | ||||
|      *     An array of arguments to be processed with the message sent to the | ||||
|      *     client. | ||||
|      */ | ||||
|     this.onmsg = null; | ||||
|  | ||||
|     /** | ||||
|      * Fired when a audio stream is created. The stream provided to this event | ||||
| @@ -1427,6 +1442,12 @@ Guacamole.Client = function(tunnel) { | ||||
|             } | ||||
|  | ||||
|         }, | ||||
|          | ||||
|         "msg" : function(parameters) { | ||||
|              | ||||
|             if (guac_client.onmsg) guac_client.onmsg(parseInt(parameters[0]), parameters.slice(1)); | ||||
|              | ||||
|         }, | ||||
|  | ||||
|         "name": function(parameters) { | ||||
|             if (guac_client.onname) guac_client.onname(parameters[0]); | ||||
| @@ -1954,3 +1975,31 @@ Guacamole.Client.DefaultTransferFunction = { | ||||
|     } | ||||
|  | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * A list of possible messages that can be sent by the server for processing | ||||
|  * by the client. | ||||
|  *  | ||||
|  * @type {!Object.<string, number>} | ||||
|  */ | ||||
| Guacamole.Client.Message = { | ||||
|      | ||||
|     /** | ||||
|      * A client message that indicates that a user has joined an existing | ||||
|      * connection. This message expects a single additional argument - the | ||||
|      * name of the user who has joined the connection. | ||||
|      *  | ||||
|      * @type {!number} | ||||
|      */ | ||||
|     "USER_JOINED": 0x0001, | ||||
|      | ||||
|     /** | ||||
|      * A client message that indicates that a user has left an existing | ||||
|      * connection. This message expects a single additional argument - the | ||||
|      * name of the user who has left the connection. | ||||
|      *  | ||||
|      * @type {!number} | ||||
|      */ | ||||
|     "USER_LEFT": 0x0002 | ||||
|      | ||||
| }; | ||||
|   | ||||
| @@ -293,7 +293,14 @@ public class ConfiguredGuacamoleSocket extends DelegatingGuacamoleSocket { | ||||
|         if (GuacamoleProtocolCapability.TIMEZONE_HANDSHAKE.isSupported(protocolVersion)) { | ||||
|             String timezone = info.getTimezone(); | ||||
|             if (timezone != null) | ||||
|                 writer.writeInstruction(new GuacamoleInstruction("timezone", info.getTimezone())); | ||||
|                 writer.writeInstruction(new GuacamoleInstruction("timezone", timezone)); | ||||
|         } | ||||
|          | ||||
|         // Send client name, if supported and available | ||||
|         if (GuacamoleProtocolCapability.NAME_HANDSHAKE.isSupported(protocolVersion)) { | ||||
|             String name = info.getName(); | ||||
|             if (name != null) | ||||
|                 writer.writeInstruction(new GuacamoleInstruction("name", name)); | ||||
|         } | ||||
|  | ||||
|         // Send args | ||||
|   | ||||
| @@ -47,17 +47,22 @@ public class GuacamoleClientInformation { | ||||
|     /** | ||||
|      * The list of audio mimetypes reported by the client to be supported. | ||||
|      */ | ||||
|     private final List<String> audioMimetypes = new ArrayList<String>(); | ||||
|     private final List<String> audioMimetypes = new ArrayList<>(); | ||||
|  | ||||
|     /** | ||||
|      * The list of video mimetypes reported by the client to be supported. | ||||
|      */ | ||||
|     private final List<String> videoMimetypes = new ArrayList<String>(); | ||||
|     private final List<String> videoMimetypes = new ArrayList<>(); | ||||
|  | ||||
|     /** | ||||
|      * The list of image mimetypes reported by the client to be supported. | ||||
|      */ | ||||
|     private final List<String> imageMimetypes = new ArrayList<String>(); | ||||
|     private final List<String> imageMimetypes = new ArrayList<>(); | ||||
|      | ||||
|     /** | ||||
|      * The name of the user reported by the client. | ||||
|      */ | ||||
|     private String name; | ||||
|      | ||||
|     /** | ||||
|      * The timezone reported by the client. | ||||
| @@ -150,6 +155,17 @@ public class GuacamoleClientInformation { | ||||
|         return imageMimetypes; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Returns the name of the Guacamole user as reported by the client, or null | ||||
|      * if the user name is not set. | ||||
|      *  | ||||
|      * @return  | ||||
|      *     A string value of the human-readable name reported by the client. | ||||
|      */ | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Return the timezone as reported by the client, or null if the timezone | ||||
|      * is not set.  Valid timezones are specified in IANA zone key format, | ||||
| @@ -162,6 +178,16 @@ public class GuacamoleClientInformation { | ||||
|         return timezone; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Set the human-readable name of the user associated with this client. | ||||
|      *  | ||||
|      * @param name  | ||||
|      *     The human-readable name of the user associated with this client. | ||||
|      */ | ||||
|     public void setName(String name) { | ||||
|         this.name = name; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Set the string value of the timezone, or null if the timezone will not | ||||
|      * be provided by the client.  Valid timezones are specified in IANA zone | ||||
|   | ||||
| @@ -33,6 +33,21 @@ public enum GuacamoleProtocolCapability { | ||||
|      */ | ||||
|     ARBITRARY_HANDSHAKE_ORDER(GuacamoleProtocolVersion.VERSION_1_1_0), | ||||
|      | ||||
|     /** | ||||
|      * Support for the "msg" instruction. The "msg" instruction allows the | ||||
|      * server to send messages to the client. Support for this instruction was | ||||
|      * introduced in {@link GuacamoleProtocolVersion#VERSION_1_5_0}. | ||||
|      */ | ||||
|     MSG_INSTRUCTION(GuacamoleProtocolVersion.VERSION_1_5_0), | ||||
|      | ||||
|     /** | ||||
|      * Support for the "name" handshake instruction, allowing clients to send | ||||
|      * the name of the Guacamole user to be passed to guacd and associated with | ||||
|      * connections. Support for this instruction was introduced in | ||||
|      * {@link GuacamoleProtocolVersion#VERSION_1_5_0}. | ||||
|      */ | ||||
|     NAME_HANDSHAKE(GuacamoleProtocolVersion.VERSION_1_5_0), | ||||
|      | ||||
|     /** | ||||
|      * Negotiation of Guacamole protocol version between client and server | ||||
|      * during the protocol handshake. The ability to negotiate protocol | ||||
|   | ||||
| @@ -53,11 +53,20 @@ public class GuacamoleProtocolVersion { | ||||
|      */ | ||||
|     public static final GuacamoleProtocolVersion VERSION_1_3_0 = new GuacamoleProtocolVersion(1, 3, 0); | ||||
|  | ||||
|     /** | ||||
|      * Protocol version 1.5.0, which introduces the "msg" instruction, allowing | ||||
|      * the server to send message notifications that will be displayed on the | ||||
|      * client. The version also adds support for the "name" handshake | ||||
|      * instruction, allowing guacd to store the name of the user who is | ||||
|      * accessing the connection. | ||||
|      */ | ||||
|     public static final GuacamoleProtocolVersion VERSION_1_5_0 = new GuacamoleProtocolVersion(1, 5, 0); | ||||
|      | ||||
|     /** | ||||
|      * The most recent version of the Guacamole protocol at the time this | ||||
|      * version of GuacamoleProtocolVersion was built. | ||||
|      */ | ||||
|     public static final GuacamoleProtocolVersion LATEST = VERSION_1_3_0; | ||||
|     public static final GuacamoleProtocolVersion LATEST = VERSION_1_5_0; | ||||
|      | ||||
|     /** | ||||
|      * A regular expression that matches the VERSION_X_Y_Z pattern, where | ||||
|   | ||||
| @@ -791,6 +791,24 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams | ||||
|             ManagedClient.uploadFile($scope.filesystemMenuContents.client, files[i], $scope.filesystemMenuContents); | ||||
|  | ||||
|     }; | ||||
|      | ||||
|     /** | ||||
|      * Determines whether the attached client group has any associated client | ||||
|      * messages to display. | ||||
|      *  | ||||
|      * @returns {Boolean} | ||||
|      *     true if there are messages to display; otherwise false. | ||||
|      */ | ||||
|     $scope.hasMessages = function hasMessages() { | ||||
|          | ||||
|         // No client group means no messages | ||||
|         if (!$scope.clientGroup) | ||||
|             return false; | ||||
|          | ||||
|         // Otherwise, find messages within the clients in the group. | ||||
|         return _.findIndex($scope.clientGroup.clients, ManagedClient.hasMessages) !== -1; | ||||
|          | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Determines whether the attached client group has any associated file | ||||
|   | ||||
| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  * Licensed to the Apache Software Foundation (ASF) under one | ||||
|  * or more contributor license agreements.  See the NOTICE file | ||||
|  * distributed with this work for additional information | ||||
|  * regarding copyright ownership.  The ASF licenses this file | ||||
|  * to you 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Directive which displays a message for the client. | ||||
|  */ | ||||
| angular.module('client').directive('guacClientMessage', [function guacClientMessage() { | ||||
|  | ||||
|     return { | ||||
|         restrict: 'E', | ||||
|         replace: true, | ||||
|         scope: { | ||||
|  | ||||
|             /** | ||||
|              * The message to display to the client. | ||||
|              *  | ||||
|              * @type {!ManagedClientMessage} | ||||
|              */ | ||||
|             message : '=' | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         templateUrl: 'app/client/templates/guacClientMessage.html', | ||||
|          | ||||
|         controller: ['$scope', '$injector', '$element', | ||||
|                 function guacClientMessageController($scope, $injector, $element) { | ||||
|              | ||||
|             // Required types | ||||
|             const ManagedClientMessage = $injector.get('ManagedClientMessage'); | ||||
|              | ||||
|             // Required services | ||||
|             var translationStringService = $injector.get('translationStringService'); | ||||
|              | ||||
|             /** | ||||
|              * Uses the msgcode to retrieve the correct translation key for | ||||
|              * the client message. | ||||
|              *  | ||||
|              * @returns {string} | ||||
|              */ | ||||
|             $scope.getMessageKey = function getMessageKey() { | ||||
|                  | ||||
|                 let msgString = "DEFAULT"; | ||||
|                 if (Object.values(Guacamole.Client.Message).includes($scope.message.msgcode)) | ||||
|                     msgString = Object.keys(Guacamole.Client.Message).find(key => Guacamole.Client.Message[key] === $scope.message.msgcode); | ||||
|                  | ||||
|                 return "CLIENT.MESSAGE_" + translationStringService.canonicalize(msgString); | ||||
|             }; | ||||
|              | ||||
|             /** | ||||
|              * Returns a set of key/value object pairs that represent the | ||||
|              * arguments provided as part of the message in the form | ||||
|              * "ARGS_0 = value". Guacamole's translation system relies on | ||||
|              * the arguments being available in this format in order to be able | ||||
|              * to handle substituting values for an arbitrary list of arguments. | ||||
|              *  | ||||
|              * @returns {Object} | ||||
|              */ | ||||
|             $scope.getMessageArgs = function getMessageArgs() { | ||||
|                 return $scope.message.args.reduce( | ||||
|                     function(acc, value, index) { | ||||
|                         acc[`ARGS_${index}`] = value; | ||||
|                         return acc; | ||||
|                     }, | ||||
|                     {} | ||||
|                 ); | ||||
|             }; | ||||
|                  | ||||
|         }] | ||||
|  | ||||
|     }; | ||||
| }]); | ||||
| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * Licensed to the Apache Software Foundation (ASF) under one | ||||
|  * or more contributor license agreements.  See the NOTICE file | ||||
|  * distributed with this work for additional information | ||||
|  * regarding copyright ownership.  The ASF licenses this file | ||||
|  * to you 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Directive which displays all client messages. | ||||
|  */ | ||||
| angular.module('client').directive('guacMessageDialog', [function guacMessageDialog() { | ||||
|  | ||||
|     return { | ||||
|         restrict: 'E', | ||||
|         replace: true, | ||||
|         scope: { | ||||
|  | ||||
|             /** | ||||
|              * The client group whose messages should be managed by this | ||||
|              * directive. | ||||
|              *  | ||||
|              * @type ManagedClientGroup | ||||
|              */ | ||||
|             clientGroup : '=' | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         templateUrl: 'app/client/templates/guacMessageDialog.html', | ||||
|         controller: ['$scope', '$injector', function guacMessageDialogController($scope, $injector) { | ||||
|  | ||||
|             // Required types | ||||
|             const ManagedClient            = $injector.get('ManagedClient'); | ||||
|             const ManagedClientGroup       = $injector.get('ManagedClientGroup'); | ||||
|  | ||||
|             /** | ||||
|              * Removes all messages. | ||||
|              */ | ||||
|             $scope.clearAllMessages = function clearAllMessages() { | ||||
|                  | ||||
|                 // Nothing to clear if no client group attached | ||||
|                 if (!$scope.clientGroup) | ||||
|                     return; | ||||
|  | ||||
|                 // Remove each client's messages | ||||
|                 $scope.clientGroup.clients.forEach(client =>  { | ||||
|                     client.messages = []; | ||||
|                 }); | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * @borrows ManagedClientGroup.hasMultipleClients | ||||
|              */ | ||||
|             $scope.hasMultipleClients = ManagedClientGroup.hasMultipleClients; | ||||
|  | ||||
|             /** | ||||
|              * @borrows ManagedClient.hasMessages | ||||
|              */ | ||||
|             $scope.hasMessages = ManagedClient.hasMessages; | ||||
|  | ||||
|         }] | ||||
|  | ||||
|     }; | ||||
| }]); | ||||
| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Licensed to the Apache Software Foundation (ASF) under one | ||||
|  * or more contributor license agreements.  See the NOTICE file | ||||
|  * distributed with this work for additional information | ||||
|  * regarding copyright ownership.  The ASF licenses this file | ||||
|  * to you 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. | ||||
|  */ | ||||
|  | ||||
| p.client-message-text { | ||||
|     margin: 5px; | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,122 @@ | ||||
| /* | ||||
|  * Licensed to the Apache Software Foundation (ASF) under one | ||||
|  * or more contributor license agreements.  See the NOTICE file | ||||
|  * distributed with this work for additional information | ||||
|  * regarding copyright ownership.  The ASF licenses this file | ||||
|  * to you 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. | ||||
|  */ | ||||
|  | ||||
| #message-dialog { | ||||
|  | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
|     bottom: 0; | ||||
|     z-index: 20; | ||||
|  | ||||
|     font-size: 0.8em; | ||||
|  | ||||
|     width: 3in; | ||||
|     max-width: 100%; | ||||
|     max-height: 3in; | ||||
|      | ||||
|     background: white; | ||||
|     opacity: 0.75; | ||||
|  | ||||
| } | ||||
|  | ||||
| #message-dialog .message-dialog-box { | ||||
|  | ||||
|     /* IE10 */ | ||||
|     display: -ms-flexbox; | ||||
|     -ms-flex-align: stretch; | ||||
|     -ms-flex-direction: column; | ||||
|  | ||||
|     /* Ancient Mozilla */ | ||||
|     display: -moz-box; | ||||
|     -moz-box-align: stretch; | ||||
|     -moz-box-orient: vertical; | ||||
|  | ||||
|     /* Ancient WebKit */ | ||||
|     display: -webkit-box; | ||||
|     -webkit-box-align: stretch; | ||||
|     -webkit-box-orient: vertical; | ||||
|  | ||||
|     /* Old WebKit */ | ||||
|     display: -webkit-flex; | ||||
|     -webkit-align-items: stretch; | ||||
|     -webkit-flex-direction: column; | ||||
|  | ||||
|     /* W3C */ | ||||
|     display: flex; | ||||
|     align-items: stretch; | ||||
|     flex-direction: column; | ||||
|  | ||||
|     max-width: inherit; | ||||
|     max-height: inherit; | ||||
|  | ||||
|     border: 1px solid rgba(0, 0, 0, 0.5); | ||||
|     box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25); | ||||
|  | ||||
| } | ||||
|  | ||||
| #message-dialog .message-dialog-box .header { | ||||
|     -ms-flex: 0 0 auto; | ||||
|     -moz-box-flex: 0; | ||||
|     -webkit-box-flex: 0; | ||||
|     -webkit-flex: 0 0 auto; | ||||
|     flex: 0 0 auto; | ||||
|     margin-bottom: 5px; | ||||
| } | ||||
|  | ||||
| #message-dialog .message-dialog-box .client-message-body { | ||||
|  | ||||
|     -ms-flex: 1 1 auto; | ||||
|     -moz-box-flex: 1; | ||||
|     -webkit-box-flex: 1; | ||||
|     -webkit-flex: 1 1 auto; | ||||
|     flex: 1 1 auto; | ||||
|  | ||||
|     overflow: auto; | ||||
|  | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Shrink maximum height if viewport is too small for default 3in dialog. | ||||
|  */ | ||||
| @media all and (max-height: 3in) { | ||||
|  | ||||
|     #message-dialog { | ||||
|         max-height: 1.5in; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * If viewport is too small for even the 1.5in dialog, fit all available space. | ||||
|  */ | ||||
| @media all and (max-height: 1.5in) { | ||||
|  | ||||
|     #message-dialog { | ||||
|         height: 100%; | ||||
|     } | ||||
|  | ||||
|     #message-dialog .message-dialog-box { | ||||
|         position: absolute; | ||||
|         left:   0.5em; | ||||
|         top:    0.5em; | ||||
|         right:  0.5em; | ||||
|         bottom: 0.5em; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -44,6 +44,11 @@ | ||||
|     <div id="connection-warning" ng-show="isConnectionUnstable()"> | ||||
|         {{'CLIENT.TEXT_CLIENT_STATUS_UNSTABLE' | translate}} | ||||
|     </div> | ||||
|      | ||||
|     <!-- Message dialog --> | ||||
|     <div id="message-dialog" ng-show="hasMessages()"> | ||||
|         <guac-message-dialog client-group="clientGroup"></guac-message-dialog> | ||||
|     </div> | ||||
|  | ||||
|     <!-- Menu --> | ||||
|     <div class="menu" ng-class="{open: menu.shown}" id="guac-menu"> | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| <div class="client-message" ng-click="clear()"> | ||||
|  | ||||
|     <!-- Message text --> | ||||
|     <p class="client-message-text" | ||||
|        translate="{{ getMessageKey() }}" | ||||
|        translate-values="{{ getMessageArgs() }}"></p> | ||||
|  | ||||
| </div> | ||||
| @@ -0,0 +1,21 @@ | ||||
| <div class="message-dialog-box"> | ||||
|      | ||||
|     <!-- Message dialog header --> | ||||
|     <div class="header"> | ||||
|         <h2>{{'CLIENT.SECTION_HEADER_CLIENT_MESSAGES' | translate}}</h2> | ||||
|         <button ng-click="clearAllMessages()">{{'CLIENT.ACTION_CLEAR_CLIENT_MESSAGES' | translate}}</button> | ||||
|     </div> | ||||
|  | ||||
|     <!-- Received messages --> | ||||
|     <div class="client-messages-body"> | ||||
|         <div class="client-messages-body-section" ng-repeat="client in clientGroup.clients" ng-show="hasMessages(client)"> | ||||
|             <h3 ng-show="hasMultipleClients(clientGroup)">{{ client.name }}</h3> | ||||
|             <div class="messages"> | ||||
|                 <guac-client-message | ||||
|                     message="message" | ||||
|                     ng-repeat="message in client.messages"> | ||||
|                 </guac-client-message> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| @@ -28,6 +28,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector', | ||||
|     const ClientIdentifier       = $injector.get('ClientIdentifier'); | ||||
|     const ClipboardData          = $injector.get('ClipboardData'); | ||||
|     const ManagedArgument        = $injector.get('ManagedArgument'); | ||||
|     const ManagedClientMessage   = $injector.get('ManagedClientMessage'); | ||||
|     const ManagedClientState     = $injector.get('ManagedClientState'); | ||||
|     const ManagedClientThumbnail = $injector.get('ManagedClientThumbnail'); | ||||
|     const ManagedDisplay         = $injector.get('ManagedDisplay'); | ||||
| @@ -173,6 +174,14 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector', | ||||
|          * @type ManagedFilesystem[] | ||||
|          */ | ||||
|         this.filesystems = template.filesystems || []; | ||||
|          | ||||
|         /** | ||||
|          * All messages that have been sent to the client that should be | ||||
|          * displayed. | ||||
|          *  | ||||
|          * @type ManagedClientMessage[] | ||||
|          */ | ||||
|         this.messages = template.messages || []; | ||||
|  | ||||
|         /** | ||||
|          * All available share links generated for the this ManagedClient via | ||||
| @@ -486,6 +495,19 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector', | ||||
|  | ||||
|             }); | ||||
|         }; | ||||
|          | ||||
|         // Handle messages received from guacd to display to the client. | ||||
|         client.onmsg = function clientMessage(msgcode, args) { | ||||
|              | ||||
|             msg = new ManagedClientMessage(); | ||||
|             msg.msgcode = msgcode; | ||||
|             msg.args = args; | ||||
|              | ||||
|             $rootScope.$apply(function updateMessages() { | ||||
|                 managedClient.messages.push(msg); | ||||
|             }); | ||||
|              | ||||
|         }; | ||||
|  | ||||
|         // Automatically update the client thumbnail | ||||
|         client.onsync = function syncReceived() { | ||||
| @@ -892,11 +914,27 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector', | ||||
|         return false; | ||||
|  | ||||
|     }; | ||||
|      | ||||
|     /** | ||||
|      * Returns whether the given client has any associated messages to display. | ||||
|      *  | ||||
|      * @param {GuacamoleClient} client | ||||
|      *     The client for which messages should be checked. | ||||
|      *      | ||||
|      * @returns {Boolean} | ||||
|      *     true if the given client has any messages, otherwise false. | ||||
|      */ | ||||
|     ManagedClient.hasMessages = function hasMessages(client) { | ||||
|         return !!(client && client.messages && client.messages.length); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Returns whether the given client has any associated file transfers, | ||||
|      * regardless of those file transfers' state. | ||||
|      * | ||||
|      * @param {GuacamoleClient} client | ||||
|      *     The client for which file transfers should be checked. | ||||
|      *  | ||||
|      * @returns {boolean} | ||||
|      *     true if there are any file transfers associated with the | ||||
|      *     given client, false otherwise. | ||||
|   | ||||
| @@ -0,0 +1,59 @@ | ||||
| /* | ||||
|  * Licensed to the Apache Software Foundation (ASF) under one | ||||
|  * or more contributor license agreements.  See the NOTICE file | ||||
|  * distributed with this work for additional information | ||||
|  * regarding copyright ownership.  The ASF licenses this file | ||||
|  * to you 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Provides the ManagedClientMessage class used for messages displayed in | ||||
|  * a ManagedClient. | ||||
|  */ | ||||
| angular.module('client').factory('ManagedClientMessage', [function defineManagedClientMessage() { | ||||
|  | ||||
|     /** | ||||
|      * Object which represents a message to be displayed to a Guacamole client. | ||||
|      * | ||||
|      * @constructor | ||||
|      * @param {ManagedClientMessage|Object} [template={}] | ||||
|      *     The object whose properties should be copied within the new | ||||
|      *     ManagedClientMessage. | ||||
|      */ | ||||
|     var ManagedClientMessage = function ManagedClientMessage(template) { | ||||
|  | ||||
|         // Use empty object by default | ||||
|         template = template || {}; | ||||
|  | ||||
|         /** | ||||
|          * The message code sent by the server that will be used to locate the | ||||
|          * message within the Guacamole translation framework. | ||||
|          *  | ||||
|          * @type Number | ||||
|          */ | ||||
|         this.msgcode = template.msgcode; | ||||
|          | ||||
|         /** | ||||
|          * Any arguments that should be passed through the translation system | ||||
|          * and displayed as part of the message. | ||||
|          *  | ||||
|          * @type String[] | ||||
|          */ | ||||
|         this.args = template.args; | ||||
|          | ||||
|     }; | ||||
|  | ||||
|     return ManagedClientMessage; | ||||
|  | ||||
| }]); | ||||
| @@ -60,6 +60,7 @@ | ||||
|  | ||||
|         "ACTION_ACKNOWLEDGE"               : "@:APP.ACTION_ACKNOWLEDGE", | ||||
|         "ACTION_CANCEL"                    : "@:APP.ACTION_CANCEL", | ||||
|         "ACTION_CLEAR_CLIENT_MESSAGES"     : "Clear", | ||||
|         "ACTION_CLEAR_COMPLETED_TRANSFERS" : "Clear", | ||||
|         "ACTION_CONTINUE"                  : "@:APP.ACTION_CONTINUE", | ||||
|         "ACTION_DISCONNECT"                : "Disconnect", | ||||
| @@ -128,6 +129,10 @@ | ||||
|         "INFO_CONNECTION_SHARED" : "This connection is now shared.", | ||||
|         "INFO_NO_FILE_TRANSFERS" : "No file transfers.", | ||||
|  | ||||
|         "MESSAGE_DEFAULT"      : "", | ||||
|         "MESSAGE_USER_JOINED"  : "User {ARGS_1} has joined the connection.", | ||||
|         "MESSAGE_USER_LEFT"    : "User {ARGS_1} has left the connection.", | ||||
|  | ||||
|         "NAME_INPUT_METHOD_NONE"   : "None", | ||||
|         "NAME_INPUT_METHOD_OSK"    : "On-screen keyboard", | ||||
|         "NAME_INPUT_METHOD_TEXT"   : "Text input", | ||||
| @@ -138,11 +143,13 @@ | ||||
|         "NAME_MOUSE_MODE_ABSOLUTE" : "Touchscreen", | ||||
|         "NAME_MOUSE_MODE_RELATIVE" : "Touchpad", | ||||
|  | ||||
|         "SECTION_HEADER_CLIPBOARD"      : "Clipboard", | ||||
|         "SECTION_HEADER_DEVICES"        : "Devices", | ||||
|         "SECTION_HEADER_DISPLAY"        : "Display", | ||||
|         "SECTION_HEADER_FILE_TRANSFERS" : "File Transfers", | ||||
|         "SECTION_HEADER_INPUT_METHOD"   : "Input method", | ||||
|         "SECTION_HEADER_CLIENT_MESSAGES" : "Messages", | ||||
|         "SECTION_HEADER_CLIPBOARD"       : "Clipboard", | ||||
|         "SECTION_HEADER_DEVICES"         : "Devices", | ||||
|         "SECTION_HEADER_DISPLAY"         : "Display", | ||||
|         "SECTION_HEADER_FILE_TRANSFERS"  : "File Transfers", | ||||
|         "SECTION_HEADER_INPUT_METHOD"    : "Input method", | ||||
|          | ||||
|         "SECTION_HEADER_MOUSE_MODE"     : "Mouse emulation mode", | ||||
|  | ||||
|         "TEXT_ZOOM_AUTO_FIT"              : "Automatically fit to browser window", | ||||
|   | ||||
| @@ -340,6 +340,11 @@ public class TunnelRequestService { | ||||
|         GuacamoleSession session = authenticationService.getGuacamoleSession(authToken); | ||||
|         AuthenticatedUser authenticatedUser = session.getAuthenticatedUser(); | ||||
|         UserContext userContext = session.getUserContext(authProviderIdentifier); | ||||
|          | ||||
|         // Attempt to get the user's name and set it for the tunnel client. | ||||
|         String name = authenticatedUser.getIdentifier(); | ||||
|         if (name != null) | ||||
|             info.setName(name); | ||||
|  | ||||
|         try { | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user