GUACAMOLE-354: Merge translation and definition for Swiss German keymap option.

diff --git a/doc/guacamole-example/pom.xml b/doc/guacamole-example/pom.xml
index f2f56f3..bb2ea68 100644
--- a/doc/guacamole-example/pom.xml
+++ b/doc/guacamole-example/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-example</artifactId>
     <packaging>war</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-example</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -106,7 +106,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>compile</scope>
         </dependency>
 
@@ -114,7 +114,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common-js</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <type>zip</type>
             <scope>runtime</scope>
         </dependency>
diff --git a/doc/guacamole-playback-example/pom.xml b/doc/guacamole-playback-example/pom.xml
index 1b31374..f7055d3 100644
--- a/doc/guacamole-playback-example/pom.xml
+++ b/doc/guacamole-playback-example/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-playback-example</artifactId>
     <packaging>war</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-playback-example</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -88,7 +88,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common-js</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <type>zip</type>
             <scope>runtime</scope>
         </dependency>
diff --git a/extensions/guacamole-auth-cas/pom.xml b/extensions/guacamole-auth-cas/pom.xml
index ae8bd67..69ecab5 100644
--- a/extensions/guacamole-auth-cas/pom.xml
+++ b/extensions/guacamole-auth-cas/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-cas</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-cas</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -210,7 +210,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
@@ -218,7 +218,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-cas/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-cas/src/main/resources/guac-manifest.json
index fbf8c09..d037fbb 100644
--- a/extensions/guacamole-auth-cas/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-cas/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "CAS Authentication Extension",
     "namespace" : "guac-cas",
diff --git a/extensions/guacamole-auth-duo/pom.xml b/extensions/guacamole-auth-duo/pom.xml
index 55de752..330f76e 100644
--- a/extensions/guacamole-auth-duo/pom.xml
+++ b/extensions/guacamole-auth-duo/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-duo</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-duo</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -213,7 +213,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json
index 4c87382..6de72fa 100644
--- a/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "Duo TFA Authentication Backend",
     "namespace" : "duo",
diff --git a/extensions/guacamole-auth-header/pom.xml b/extensions/guacamole-auth-header/pom.xml
index 9c07bab..cf65658 100644
--- a/extensions/guacamole-auth-header/pom.xml
+++ b/extensions/guacamole-auth-header/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-header</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-header</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -130,7 +130,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json
index c976eef..3c71028 100644
--- a/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "HTTP Header Authentication Extension",
     "namespace" : "guac-header",
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
index a3b7f92..fdc8003 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
@@ -36,7 +36,7 @@
     <parent>
         <groupId>org.apache.guacamole</groupId>
         <artifactId>guacamole-auth-jdbc</artifactId>
-        <version>1.0.0</version>
+        <version>1.1.0</version>
         <relativePath>../../</relativePath>
     </parent>
 
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java
index 68e2a47..ff605b9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java
@@ -96,6 +96,7 @@
 
         // Retrieve user account for already-authenticated user
         ModeledUser user = userService.retrieveUser(authenticationProvider, authenticatedUser);
+        ModeledUserContext context = userContextProvider.get();
         if (user != null && !user.isDisabled()) {
 
             // Enforce applicable account restrictions
@@ -118,24 +119,23 @@
                     userService.resetExpiredPassword(user, authenticatedUser.getCredentials());
             }
 
-            // Return all data associated with the authenticated user
-            ModeledUserContext context = userContextProvider.get();
-            context.init(user.getCurrentUser());
-            return context;
-
+        }
+        
+        // If no user account is found, and database-specific account
+        // restrictions do not apply, get an empty user.
+        else if (!databaseRestrictionsApplicable) {
+            user = userService.retrieveSkeletonUser(authenticationProvider, authenticatedUser);
         }
 
         // Veto authentication result only if database-specific account
         // restrictions apply in this situation
-        if (databaseRestrictionsApplicable)
+        else
             throw new GuacamoleInvalidCredentialsException("Invalid login",
                     CredentialsInfo.USERNAME_PASSWORD);
-
-        // There is no data to be returned for the user, either because they do
-        // not exist or because restrictions prevent their data from being
-        // retrieved, but no restrictions apply which should prevent the user
-        // from authenticating entirely
-        return null;
+        
+        // Initialize the UserContext with the user account and return it.
+        context.init(user.getCurrentUser());
+        return context;
 
     }
 
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
index 828b05e..5778ad0 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
@@ -19,6 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.user;
 
+import com.google.common.collect.Sets;
 import java.util.Collections;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -168,5 +169,11 @@
     public void setIdentifier(String identifier) {
         user.setIdentifier(identifier);
     }
+    
+    @Override
+    public Set<String> getEffectiveUserGroups() {
+        return Sets.union(user.getEffectiveUserGroups(),
+                super.getEffectiveUserGroups());
+    }
 
 }
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
index 194a26d..3d441d6 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
@@ -127,6 +127,17 @@
     public UserModel() {
         super(EntityType.USER);
     }
+    
+    /**
+     * Creates a new user having the provided identifier.
+     * 
+     * @param identifier
+     *     The identifier of the new user.
+     */
+    public UserModel(String identifier) {
+        super(EntityType.USER);
+        super.setIdentifier(identifier);
+    }
 
     /**
      * Returns the hash of this user's password and password salt. This may be
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index 60bd1e1..0cfe900 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -423,6 +423,43 @@
         return user;
 
     }
+    
+    /**
+     * Generates an empty (skeleton) user corresponding to the given
+     * AuthenticatedUser.  The user will not be stored in the database, and
+     * will only be available in-memory during the time the session is
+     * active.
+     * 
+     * @param authenticationProvider
+     *     The AuthenticationProvider on behalf of which the user is being
+     *     retrieved.
+     *
+     * @param authenticatedUser
+     *     The AuthenticatedUser to generate the skeleton account for.
+     *
+     * @return
+     *     The empty ModeledUser which corresponds to the given
+     *     AuthenticatedUser.
+     *
+     * @throws GuacamoleException
+     *     If a ModeledUser object for the user corresponding to the given
+     *     AuthenticatedUser cannot be created.
+     */
+    public ModeledUser retrieveSkeletonUser(AuthenticationProvider authenticationProvider,
+            AuthenticatedUser authenticatedUser) throws GuacamoleException {
+        
+        // Set up an empty user model
+        ModeledUser user = getObjectInstance(null,
+                new UserModel(authenticatedUser.getIdentifier()));
+        
+        // Create user object, and configure cyclic reference
+        user.setCurrentUser(new ModeledAuthenticatedUser(authenticatedUser,
+                authenticationProvider, user));
+        
+        // Return the new user.
+        return user;
+        
+    }
 
     /**
      * Resets the password of the given user to the new password specified via
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml
index a204c8e..ddb57a9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml
@@ -36,7 +36,7 @@
     <parent>
         <groupId>org.apache.guacamole</groupId>
         <artifactId>guacamole-auth-jdbc</artifactId>
-        <version>1.0.0</version>
+        <version>1.1.0</version>
         <relativePath>../../</relativePath>
     </parent>
 
@@ -99,21 +99,21 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-auth-jdbc-mysql</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
         <!-- PostgreSQL Authentication Extension -->
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-auth-jdbc-postgresql</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
         <!-- SQL Server Authentication Extension -->
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-auth-jdbc-sqlserver</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
     </dependencies>
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml
index b438735..8a7d68a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml
@@ -36,7 +36,7 @@
     <parent>
         <groupId>org.apache.guacamole</groupId>
         <artifactId>guacamole-auth-jdbc</artifactId>
-        <version>1.0.0</version>
+        <version>1.1.0</version>
         <relativePath>../../</relativePath>
     </parent>
 
@@ -120,7 +120,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-auth-jdbc-base</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
     </dependencies>
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json
index 7fb613c..d80b594 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "MySQL Authentication",
     "namespace" : "guac-mysql",
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index 21efb99..a292511 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -73,27 +73,31 @@
             JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
             WHERE
                 guacamole_user_group.disabled = false
-                AND (
-                    guacamole_user_group_member.member_entity_id = #{entity.entityID}
-                    <if test="!effectiveGroups.isEmpty()">
-                        OR guacamole_user_group_member.member_entity_id IN (
-                            SELECT entity_id FROM guacamole_entity
-                            WHERE type = 'USER_GROUP' AND name IN
-                                <foreach collection="effectiveGroups" item="effectiveGroup"
-                                         open="(" separator="," close=")">
-                                    #{effectiveGroup,jdbcType=VARCHAR}
-                                </foreach>
-                        )
-                        OR guacamole_user_group.entity_id IN (
-                            SELECT entity_id FROM guacamole_entity
-                            WHERE type = 'USER_GROUP' AND name IN
-                                <foreach collection="effectiveGroups" item="effectiveGroup"
-                                         open="(" separator="," close=")">
-                                    #{effectiveGroup,jdbcType=VARCHAR}
-                                </foreach>
-                        )
-                    </if>
-                )
+                AND guacamole_user_group_member.member_entity_id = #{entity.entityID}
+            <if test="!effectiveGroups.isEmpty()">
+                UNION SELECT
+                    guacamole_entity.name
+                FROM guacamole_user_group
+                JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+                JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                JOIN guacamole_entity member_entity ON guacamole_user_group_member.member_entity_id = member_entity.entity_id
+                WHERE
+                    guacamole_user_group.disabled = false
+                    AND member_entity.type = 'USER_GROUP' AND member_entity.name IN
+                        <foreach collection="effectiveGroups" item="effectiveGroup"
+                                 open="(" separator="," close=")">
+                            #{effectiveGroup,jdbcType=VARCHAR}
+                        </foreach>
+                UNION SELECT
+                    guacamole_entity.name
+                FROM guacamole_user_group
+                JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+                WHERE type = 'USER_GROUP' AND name IN
+                    <foreach collection="effectiveGroups" item="effectiveGroup"
+                             open="(" separator="," close=")">
+                        #{effectiveGroup,jdbcType=VARCHAR}
+                    </foreach>
+            </if>
         </if>
 
         <if test="recursive">
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml
index bfe4a3c..340eba7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml
@@ -36,7 +36,7 @@
     <parent>
         <groupId>org.apache.guacamole</groupId>
         <artifactId>guacamole-auth-jdbc</artifactId>
-        <version>1.0.0</version>
+        <version>1.1.0</version>
         <relativePath>../../</relativePath>
     </parent>
 
@@ -120,7 +120,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-auth-jdbc-base</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
     </dependencies>
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json
index b4047bc..6b2d17c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "PostgreSQL Authentication",
     "namespace" : "guac-postgresql",
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml
index 0a8468b..55455db 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml
@@ -36,7 +36,7 @@
     <parent>
         <groupId>org.apache.guacamole</groupId>
         <artifactId>guacamole-auth-jdbc</artifactId>
-        <version>1.0.0</version>
+        <version>1.1.0</version>
         <relativePath>../../</relativePath>
     </parent>
 
@@ -120,7 +120,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-auth-jdbc-base</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
     </dependencies>
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json
index c7a0caa..79286f1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "SQLServer Authentication",
     "namespace" : "guac-sqlserver",
diff --git a/extensions/guacamole-auth-jdbc/pom.xml b/extensions/guacamole-auth-jdbc/pom.xml
index 9aee2df..1325949 100644
--- a/extensions/guacamole-auth-jdbc/pom.xml
+++ b/extensions/guacamole-auth-jdbc/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-jdbc</artifactId>
     <packaging>pom</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-jdbc</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -81,7 +81,7 @@
             <dependency>
                 <groupId>org.apache.guacamole</groupId>
                 <artifactId>guacamole-ext</artifactId>
-                <version>1.0.0</version>
+                <version>1.1.0</version>
                 <scope>provided</scope>
             </dependency>
 
diff --git a/extensions/guacamole-auth-ldap/pom.xml b/extensions/guacamole-auth-ldap/pom.xml
index 856f630..79560f3 100644
--- a/extensions/guacamole-auth-ldap/pom.xml
+++ b/extensions/guacamole-auth-ldap/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-ldap</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-ldap</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -137,7 +137,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java
index 6a96d5b..2f2b674 100644
--- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java
@@ -178,7 +178,7 @@
 
                 // Store connection using cn for both identifier and name
                 String name = cn.getStringValue();
-                Connection connection = new SimpleConnection(name, name, config);
+                Connection connection = new SimpleConnection(name, name, config, true);
                 connection.setParentIdentifier(LDAPAuthenticationProvider.ROOT_CONNECTION_GROUP);
 
                 // Inject LDAP-specific tokens only if LDAP handled user
diff --git a/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json
index 2d4d090..7002388 100644
--- a/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "LDAP Authentication",
     "namespace" : "guac-ldap",
diff --git a/extensions/guacamole-auth-openid/pom.xml b/extensions/guacamole-auth-openid/pom.xml
index 63ecd51..967ad03 100644
--- a/extensions/guacamole-auth-openid/pom.xml
+++ b/extensions/guacamole-auth-openid/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-openid</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-openid</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -210,7 +210,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json
index 91d33f1..4bac126 100644
--- a/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "OpenID Authentication Extension",
     "namespace" : "guac-openid",
diff --git a/extensions/guacamole-auth-quickconnect/pom.xml b/extensions/guacamole-auth-quickconnect/pom.xml
index 8acf5f6..df290b8 100644
--- a/extensions/guacamole-auth-quickconnect/pom.xml
+++ b/extensions/guacamole-auth-quickconnect/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-quickconnect</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-quickconnect</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -188,7 +188,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json
index 7f1e4da..10c4f8a 100644
--- a/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json
@@ -1,5 +1,5 @@
 {
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"             : "Adhoc Guacamole Connections",
     "namespace"        : "quickconnect",
diff --git a/extensions/guacamole-auth-radius/pom.xml b/extensions/guacamole-auth-radius/pom.xml
index d07a60a..73c332a 100644
--- a/extensions/guacamole-auth-radius/pom.xml
+++ b/extensions/guacamole-auth-radius/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-radius</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-radius</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -178,7 +178,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
@@ -186,7 +186,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json
index 55a3a0c..ac1116b 100644
--- a/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "RADIUS Authentication Backend",
     "namespace" : "radius",
diff --git a/extensions/guacamole-auth-totp/pom.xml b/extensions/guacamole-auth-totp/pom.xml
index d34db07..11199df 100644
--- a/extensions/guacamole-auth-totp/pom.xml
+++ b/extensions/guacamole-auth-totp/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-auth-totp</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-auth-totp</name>
     <url>http://guacamole.incubator.apache.org/</url>
 
@@ -217,7 +217,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json
index fd62e14..31dda60 100644
--- a/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json
@@ -1,6 +1,6 @@
 {
 
-    "guacamoleVersion" : "1.0.0",
+    "guacamoleVersion" : "1.1.0",
 
     "name"      : "TOTP TFA Authentication Backend",
     "namespace" : "totp",
diff --git a/guacamole-common-js/pom.xml b/guacamole-common-js/pom.xml
index cf9c45d..e94271b 100644
--- a/guacamole-common-js/pom.xml
+++ b/guacamole-common-js/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-common-js</artifactId>
     <packaging>pom</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-common-js</name>
     <url>http://guacamole.apache.org/</url>
 
diff --git a/guacamole-common-js/src/main/webapp/modules/Version.js b/guacamole-common-js/src/main/webapp/modules/Version.js
index 737d8d2..9131165 100644
--- a/guacamole-common-js/src/main/webapp/modules/Version.js
+++ b/guacamole-common-js/src/main/webapp/modules/Version.js
@@ -27,4 +27,4 @@
  *
  * @type {String}
  */
-Guacamole.API_VERSION = "1.0.0";
+Guacamole.API_VERSION = "1.1.0";
diff --git a/guacamole-common/pom.xml b/guacamole-common/pom.xml
index 219d694..2b4f353 100644
--- a/guacamole-common/pom.xml
+++ b/guacamole-common/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-common</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-common</name>
     <url>http://guacamole.apache.org/</url>
 
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java
index cf43b68..fe4efca 100644
--- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java
+++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java
@@ -19,7 +19,6 @@
 
 package org.apache.guacamole.protocol;
 
-
 import java.util.List;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleServerException;
@@ -57,6 +56,15 @@
     private String id;
     
     /**
+     * The protocol version that will be used to communicate with guacd.  The
+     * default is 1.0.0, and, if the server does not provide a specific version
+     * it will be assumed that it operates at this version and certain features
+     * may be unavailable.
+     */
+    private GuacamoleProtocolVersion protocolVersion =
+            GuacamoleProtocolVersion.VERSION_1_0_0;
+    
+    /**
      * Waits for the instruction having the given opcode, returning that
      * instruction once it has been read. If the instruction is never read,
      * an exception is thrown.
@@ -142,6 +150,23 @@
 
             // Retrieve argument name
             String arg_name = arg_names.get(i);
+            
+            // Check for valid protocol version as first argument
+            if (i == 0) {
+                GuacamoleProtocolVersion version = GuacamoleProtocolVersion.parseVersion(arg_name);
+                if (version != null) {
+
+                    // Use the lowest common version supported
+                    if (version.atLeast(GuacamoleProtocolVersion.LATEST))
+                        version = GuacamoleProtocolVersion.LATEST;
+
+                    // Respond with the version selected
+                    arg_values[i] = version.toString();
+                    protocolVersion = version;
+                    continue;
+
+                }
+            }
 
             // Get defined value for name
             String value = config.getParameter(arg_name);
@@ -184,6 +209,13 @@
                     "image",
                     info.getImageMimetypes().toArray(new String[0])
                 ));
+        
+        // Send client timezone, if supported and available
+        if (GuacamoleProtocolCapability.TIMEZONE_HANDSHAKE.isSupported(protocolVersion)) {
+            String timezone = info.getTimezone();
+            if (timezone != null)
+                writer.writeInstruction(new GuacamoleInstruction("timezone", info.getTimezone()));
+        }
 
         // Send args
         writer.writeInstruction(new GuacamoleInstruction("connect", arg_values));
@@ -221,6 +253,20 @@
         return id;
     }
 
+    /**
+     * Returns the version of the Guacamole protocol associated with the
+     * Guacamole connection negotiated by this ConfiguredGuacamoleSocket. This
+     * version is the lowest version common to both ConfiguredGuacamoleSocket
+     * and the relevant Guacamole proxy instance (guacd).
+     *
+     * @return
+     *     The protocol version that this ConfiguredGuacamoleSocket will use to
+     *     communicate with guacd.
+     */
+    public GuacamoleProtocolVersion getProtocolVersion() {
+        return protocolVersion;
+    }
+
     @Override
     public GuacamoleWriter getWriter() {
         return socket.getWriter();
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java
index d90d05d..6d54a2f 100644
--- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java
+++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java
@@ -58,6 +58,11 @@
      * The list of image mimetypes reported by the client to be supported.
      */
     private final List<String> imageMimetypes = new ArrayList<String>();
+    
+    /**
+     * The timezone reported by the client.
+     */
+    private String timezone;
 
     /**
      * Returns the optimal screen width requested by the client, in pixels.
@@ -144,5 +149,31 @@
     public List<String> getImageMimetypes() {
         return imageMimetypes;
     }
+    
+    /**
+     * 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,
+     * also known as Olson time zone database or TZ Database.
+     * 
+     * @return
+     *     A string value of the timezone reported by the client.
+     */
+    public String getTimezone() {
+        return timezone;
+    }
+    
+    /**
+     * 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
+     * key format (aka Olson time zone database or tz database).
+     * 
+     * @param timezone
+     *     The string value of the timezone reported by the client, in tz
+     *     database format, or null if the timezone is not provided by the
+     *     client.
+     */
+    public void setTimezone(String timezone) {
+        this.timezone = timezone;
+    }
 
 }
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java
new file mode 100644
index 0000000..79f73f8
--- /dev/null
+++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package org.apache.guacamole.protocol;
+
+/**
+ * Capabilities which may not be present in all versions of the Guacamole
+ * protocol.
+ */
+public enum GuacamoleProtocolCapability {
+    
+    /**
+     * The protocol does not require handshake instructions to be sent in a
+     * specific order, nor that all handshake instructions be sent. Arbitrary
+     * handshake order was introduced in
+     * {@link GuacamoleProtocolVersion#VERSION_1_1_0}.
+     */
+    ARBITRARY_HANDSHAKE_ORDER(GuacamoleProtocolVersion.VERSION_1_1_0),
+    
+    /**
+     * Negotiation of Guacamole protocol version between client and server
+     * during the protocol handshake. The ability to negotiate protocol
+     * versions was introduced in
+     * {@link GuacamoleProtocolVersion#VERSION_1_1_0}.
+     */
+    PROTOCOL_VERSION_DETECTION(GuacamoleProtocolVersion.VERSION_1_1_0),
+    
+    /**
+     * Support for the "timezone" handshake instruction. The "timezone"
+     * instruction allows the client to request that the server forward their
+     * local timezone for use within the remote desktop session. Support for
+     * forwarding the client timezone was introduced in
+     * {@link GuacamoleProtocolVersion#VERSION_1_1_0}.
+     */
+    TIMEZONE_HANDSHAKE(GuacamoleProtocolVersion.VERSION_1_1_0);
+    
+    /**
+     * The minimum protocol version required to support this capability.
+     */
+    private final GuacamoleProtocolVersion version;
+    
+    /**
+     * Create a new enum value with the given protocol version as the minimum
+     * required to support the capability.
+     * 
+     * @param version
+     *     The minimum required protocol version for supporting the
+     *     capability.
+     */
+    private GuacamoleProtocolCapability(GuacamoleProtocolVersion version) {
+        this.version = version;
+    }
+
+    /**
+     * Returns whether this capability is supported in the given Guacamole
+     * protocol version.
+     *
+     * @param version
+     *     The Guacamole protocol version to check.
+     *
+     * @return
+     *     true if this capability is supported by the given protocol version,
+     *     false otherwise.
+     */
+    public boolean isSupported(GuacamoleProtocolVersion version) {
+        return version.atLeast(this.version);
+    }
+
+}
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java
new file mode 100644
index 0000000..c1d50ba
--- /dev/null
+++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+package org.apache.guacamole.protocol;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Representation of a Guacamole protocol version. Convenience methods are
+ * provided for parsing and comparing versions, as is necessary when
+ * determining the version of the Guacamole protocol common to guacd and a
+ * client.
+ */
+public class GuacamoleProtocolVersion {
+    
+    /**
+     * Protocol version 1.0.0 and older.  Any client that doesn't explicitly
+     * set the protocol version will negotiate down to this protocol version.
+     * This requires that handshake instructions be ordered correctly, and
+     * lacks support for certain protocol-related features introduced in later
+     * versions.
+     */
+    public static final GuacamoleProtocolVersion VERSION_1_0_0 = new GuacamoleProtocolVersion(1, 0, 0);
+
+    /**
+     * Protocol version 1.1.0, which introduces Client-Server version
+     * detection, arbitrary handshake instruction order, and support
+     * for passing the client timezone to the server during the handshake.
+     */
+    public static final GuacamoleProtocolVersion VERSION_1_1_0 = new GuacamoleProtocolVersion(1, 1, 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_1_0;
+    
+    /**
+     * A regular expression that matches the VERSION_X_Y_Z pattern, where
+     * X is the major version component, Y is the minor version component,
+     * and Z is the patch version component.  This expression puts each of
+     * the version components in their own group so that they can be easily
+     * used later.
+     */
+    private static final Pattern VERSION_PATTERN =
+            Pattern.compile("^VERSION_([0-9]+)_([0-9]+)_([0-9]+)$");
+    
+    /**
+     * The major version component of the protocol version.
+     */
+    private final int major;
+
+    /**
+     * The minor version component of the protocol version.
+     */
+    private final int minor;
+
+    /**
+     * The patch version component of the protocol version.
+     */
+    private final int patch;
+    
+    /**
+     * Generate a new GuacamoleProtocolVersion object with the given
+     * major version, minor version, and patch version.
+     * 
+     * @param major
+     *     The integer representation of the major version component.
+     * 
+     * @param minor
+     *     The integer representation of the minor version component.
+     * 
+     * @param patch 
+     *     The integer representation of the patch version component.
+     */
+    public GuacamoleProtocolVersion(int major, int minor, int patch) {
+        this.major = major;
+        this.minor = minor;
+        this.patch = patch;
+    }
+    
+    /**
+     * Return the major version component of the protocol version.
+     * 
+     * @return 
+     *     The integer major version component.
+     */
+    public int getMajor() {
+        return major;
+    }
+    
+    /**
+     * Return the minor version component of the protocol version.
+     * 
+     * @return 
+     *     The integer minor version component.
+     */
+    public int getMinor() {
+        return minor;
+    }
+    
+    /**
+     * Return the patch version component of the protocol version.
+     * 
+     * @return 
+     *     The integer patch version component.
+     */
+    public int getPatch() {
+        return patch;
+    }
+    
+    /**
+     * Returns whether this GuacamoleProtocolVersion is at least as recent as
+     * (greater than or equal to) the given version.
+     *
+     * @param otherVersion
+     *     The version to which this GuacamoleProtocolVersion should be compared.
+     * 
+     * @return 
+     *     true if this object is at least as recent as the given version,
+     *     false if the given version is newer.
+     */
+    public boolean atLeast(GuacamoleProtocolVersion otherVersion) {
+        
+        // If major is not the same, return inequality
+        if (major != otherVersion.getMajor())
+            return this.major > otherVersion.getMajor();
+        
+        // Major is the same, but minor is not, return minor inequality
+        if (minor != otherVersion.getMinor())
+            return this.minor > otherVersion.getMinor();
+        
+        // Major and minor are equal, so return patch inequality
+        return patch >= otherVersion.getPatch();
+        
+    }
+    
+    /**
+     * Parse the String format of the version provided and return the
+     * the enum value matching that version.  If no value is provided, return
+     * null.
+     * 
+     * @param version
+     *     The String format of the version to parse.
+     * 
+     * @return
+     *     The enum value that matches the specified version, VERSION_1_0_0
+     *     if no match is found, or null if no comparison version is provided.
+     */
+    public static GuacamoleProtocolVersion parseVersion(String version) {
+
+        // Validate format of version string
+        Matcher versionMatcher = VERSION_PATTERN.matcher(version);
+        if (!versionMatcher.matches())
+            return null;
+
+        // Parse version number from version string
+        return new GuacamoleProtocolVersion(
+            Integer.parseInt(versionMatcher.group(1)),
+            Integer.parseInt(versionMatcher.group(2)),
+            Integer.parseInt(versionMatcher.group(3))
+        );
+
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 61 * hash + this.major;
+        hash = 61 * hash + this.minor;
+        hash = 61 * hash + this.patch;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+
+        if (obj == null || !(obj instanceof GuacamoleProtocolVersion))
+            return false;
+
+        // Versions are equal if all major/minor/patch components are identical
+        final GuacamoleProtocolVersion otherVersion = (GuacamoleProtocolVersion) obj;
+        return this.major == otherVersion.getMajor()
+            && this.minor == otherVersion.getMinor()
+            && this.patch == otherVersion.getPatch();
+
+    }
+
+    @Override
+    public String toString() {
+        return "VERSION_" + getMajor() + "_" + getMinor() + "_" + getPatch();
+    }
+    
+}
diff --git a/guacamole-common/src/test/java/org/apache/guacamole/protocol/GuacamoleProtocolVersionTest.java b/guacamole-common/src/test/java/org/apache/guacamole/protocol/GuacamoleProtocolVersionTest.java
new file mode 100644
index 0000000..d5082b5
--- /dev/null
+++ b/guacamole-common/src/test/java/org/apache/guacamole/protocol/GuacamoleProtocolVersionTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+package org.apache.guacamole.protocol;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Unit test for GuacamoleProtocolVersion. Verifies that Guacamole protocol
+ * version string parsing works as required.
+ */
+public class GuacamoleProtocolVersionTest {
+
+    /**
+     * Verifies that valid version strings are parsed successfully.
+     */
+    @Test
+    public void testValidVersionParse() {
+        GuacamoleProtocolVersion version = GuacamoleProtocolVersion.parseVersion("VERSION_012_102_398");
+        Assert.assertNotNull(version);
+        Assert.assertEquals(12, version.getMajor());
+        Assert.assertEquals(102, version.getMinor());
+        Assert.assertEquals(398, version.getPatch());
+    }
+
+    /**
+     * Verifies that invalid version strings fail to parse.
+     */
+    @Test
+    public void testInvalidVersionParse() {
+
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("potato"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION_"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION___"));
+
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION__2_3"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION_1__3"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION_1_2_"));
+
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION_A_2_3"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION_1_B_3"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("VERSION_1_2_C"));
+
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("_1_2_3"));
+        Assert.assertNull(GuacamoleProtocolVersion.parseVersion("version_1_2_3"));
+
+    }
+
+    /**
+     * Verifies that the atLeast() function defined by GuacamoleProtocolVersion
+     * behaves as required for a series of three versions which are in strictly
+     * increasing order (a &lt; b &lt; c).
+     *
+     * @param a
+     *     The String representation of the version which is known to be the
+     *     smaller than versions b and c.
+     *
+     * @param b
+     *     The String representation of the version which is known to be
+     *     larger than version a but smaller than version c.
+     *
+     * @param c
+     *     The String representation of the version which is known to be the
+     *     larger than versions a and b.
+     */
+    private void testVersionCompare(String a, String b, String c) {
+
+        GuacamoleProtocolVersion verA = GuacamoleProtocolVersion.parseVersion(a);
+        GuacamoleProtocolVersion verB = GuacamoleProtocolVersion.parseVersion(b);
+        GuacamoleProtocolVersion verC = GuacamoleProtocolVersion.parseVersion(c);
+
+        Assert.assertTrue(verC.atLeast(verB));
+        Assert.assertTrue(verC.atLeast(verA));
+        Assert.assertTrue(verB.atLeast(verA));
+
+        Assert.assertFalse(verB.atLeast(verC));
+        Assert.assertFalse(verA.atLeast(verC));
+        Assert.assertFalse(verA.atLeast(verB));
+
+        Assert.assertTrue(verA.atLeast(verA));
+        Assert.assertTrue(verB.atLeast(verB));
+        Assert.assertTrue(verC.atLeast(verC));
+
+    }
+
+    /**
+     * Verifies that version order comparisons using atLeast() behave as
+     * required.
+     */
+    @Test
+    public void testVersionCompare() {
+        testVersionCompare("VERSION_0_0_1", "VERSION_0_0_2", "VERSION_0_0_3");
+        testVersionCompare("VERSION_0_1_0", "VERSION_0_2_0", "VERSION_0_3_0");
+        testVersionCompare("VERSION_1_0_0", "VERSION_2_0_0", "VERSION_3_0_0");
+        testVersionCompare("VERSION_1_2_3", "VERSION_1_3_3", "VERSION_2_0_0");
+    }
+
+    /**
+     * Verifies that versions can be tested for equality using equals().
+     */
+    @Test
+    public void testVersionEquals() {
+
+        GuacamoleProtocolVersion version;
+
+        version = GuacamoleProtocolVersion.parseVersion("VERSION_012_102_398");
+        Assert.assertTrue(version.equals(version));
+        Assert.assertTrue(version.equals(new GuacamoleProtocolVersion(12, 102, 398)));
+        Assert.assertFalse(version.equals(new GuacamoleProtocolVersion(12, 102, 399)));
+        Assert.assertFalse(version.equals(new GuacamoleProtocolVersion(12, 103, 398)));
+        Assert.assertFalse(version.equals(new GuacamoleProtocolVersion(11, 102, 398)));
+
+        version = GuacamoleProtocolVersion.parseVersion("VERSION_1_0_0");
+        Assert.assertTrue(version.equals(GuacamoleProtocolVersion.VERSION_1_0_0));
+        Assert.assertFalse(version.equals(GuacamoleProtocolVersion.VERSION_1_1_0));
+
+        version = GuacamoleProtocolVersion.parseVersion("VERSION_1_1_0");
+        Assert.assertTrue(version.equals(GuacamoleProtocolVersion.VERSION_1_1_0));
+        Assert.assertFalse(version.equals(GuacamoleProtocolVersion.VERSION_1_0_0));
+
+    }
+
+    /**
+     * Verifies that versions can be converted to their Guacamole protocol
+     * representation through calling toString().
+     */
+    @Test
+    public void testToString() {
+        Assert.assertEquals("VERSION_1_0_0", GuacamoleProtocolVersion.VERSION_1_0_0.toString());
+        Assert.assertEquals("VERSION_1_1_0", GuacamoleProtocolVersion.VERSION_1_1_0.toString());
+        Assert.assertEquals("VERSION_12_103_398", new GuacamoleProtocolVersion(12, 103, 398).toString());
+    }
+
+}
diff --git a/guacamole-docker/bin/start.sh b/guacamole-docker/bin/start.sh
index 6d5af95..be97901 100755
--- a/guacamole-docker/bin/start.sh
+++ b/guacamole-docker/bin/start.sh
@@ -575,6 +575,7 @@
 start_guacamole() {
 
     # Install webapp
+    rm -Rf /usr/local/tomcat/webapps/${WEBAPP_CONTEXT:-guacamole}
     ln -sf /opt/guacamole/guacamole.war /usr/local/tomcat/webapps/${WEBAPP_CONTEXT:-guacamole}.war
 
     # Start tomcat
diff --git a/guacamole-ext/pom.xml b/guacamole-ext/pom.xml
index e123b9f..a4e7b07 100644
--- a/guacamole-ext/pom.xml
+++ b/guacamole-ext/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-ext</artifactId>
     <packaging>jar</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-ext</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -155,7 +155,7 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <scope>compile</scope>
         </dependency>
 
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java b/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java
index 19f1ead..9fe76a4 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java
@@ -92,6 +92,14 @@
         public static String TIMEZONE = "TIMEZONE";
 
         /**
+         * Field type which allows selection of languages. The languages
+         * displayed are the set of languages supported by the Guacamole web
+         * application. Legal values are valid language IDs, as dictated by
+         * the filenames of Guacamole's available translations.
+         */
+        public static String LANGUAGE = "LANGUAGE";
+
+        /**
          * A date field whose legal values conform to the pattern "YYYY-MM-DD",
          * zero-padded.
          */
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/form/LanguageField.java b/guacamole-ext/src/main/java/org/apache/guacamole/form/LanguageField.java
new file mode 100644
index 0000000..a87d772
--- /dev/null
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/form/LanguageField.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package org.apache.guacamole.form;
+
+/**
+ * Represents a language field. The field may contain only valid language
+ * identifiers as used by the Guacamole web application for its translations.
+ * Language identifiers are defined by the filenames of the JSON files
+ * containing the translation.
+ */
+public class LanguageField extends Field {
+
+    /**
+     * Creates a new LanguageField with the given name.
+     *
+     * @param name
+     *     The unique name to associate with this field.
+     */
+    public LanguageField(String name) {
+        super(name, Field.Type.LANGUAGE);
+    }
+
+    /**
+     * Parses the given string into a language ID string. As any string may be
+     * a valid language ID as long as it has a corresponding translation, the
+     * only transformation currently performed by this function is to ensure
+     * that a blank language string is parsed into null.
+     *
+     * @param language
+     *     The language string to parse, which may be null.
+     *
+     * @return
+     *     The ID of the language corresponding to the given string, or null if
+     *     if the given language string was null or blank.
+     */
+    public static String parse(String language) {
+
+        // Return null if no language is provided
+        if (language == null || language.isEmpty())
+            return null;
+
+        // Otherwise, assume language is already a valid language ID
+        return language;
+
+    }
+
+}
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/form/TimeZoneField.java b/guacamole-ext/src/main/java/org/apache/guacamole/form/TimeZoneField.java
index 9305410..90084e4 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/form/TimeZoneField.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/form/TimeZoneField.java
@@ -20,8 +20,9 @@
 package org.apache.guacamole.form;
 
 /**
- * Represents a time zone field. The field may contain only valid time zone IDs,
- * as dictated by TimeZone.getAvailableIDs().
+ * Represents a time zone field. The field may contain only valid time zone
+ * identifiers, as defined by the IANA time zone database. Such identifiers are
+ * also valid Java time zone IDs as dictated by TimeZone.getAvailableIDs().
  */
 public class TimeZoneField extends Field {
 
diff --git a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json
index dde853d..3c9d4fe 100644
--- a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json
+++ b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json
@@ -103,10 +103,15 @@
                         "ja-jp-qwerty",
                         "pt-br-qwerty",
                         "sv-se-qwerty",
+                        "da-dk-qwerty",
                         "tr-tr-qwerty"
                     ]
                 },
                 {
+                    "name"  : "timezone",
+                    "type"  : "TIMEZONE"
+                },
+                {
                     "name"    : "console",
                     "type"    : "BOOLEAN",
                     "options" : [ "true" ]
diff --git a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json
index a71e1fb..a16648f 100644
--- a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json
+++ b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json
@@ -75,6 +75,14 @@
                     "type"  : "TEXT"
                 },
                 {
+                    "name"  : "locale",
+                    "type"  : "TEXT"
+                },
+                {
+                    "name"  : "timezone",
+                    "type"  : "TIMEZONE"
+                },
+                {
                     "name"  : "server-alive-interval",
                     "type"  : "NUMERIC"
                 }
@@ -89,7 +97,7 @@
                     "options" : [ "", "127", "8" ]
                 },
                 {
-                    "name"  : "terminal-type",
+                    "name"    : "terminal-type",
                     "type"    : "ENUM",
                     "options" : [ "", "xterm", "xterm-256color", "vt220", "vt100", "ansi", "linux" ]
                 }
diff --git a/guacamole/pom.xml b/guacamole/pom.xml
index e1a2b47..7a68606 100644
--- a/guacamole/pom.xml
+++ b/guacamole/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole</artifactId>
     <packaging>war</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole</name>
     <url>http://guacamole.apache.org/</url>
 
@@ -264,21 +264,21 @@
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
         <!-- Guacamole Extension API -->
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-ext</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
         </dependency>
 
         <!-- Guacamole JavaScript API -->
         <dependency>
             <groupId>org.apache.guacamole</groupId>
             <artifactId>guacamole-common-js</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.0</version>
             <type>zip</type>
             <scope>runtime</scope>
         </dependency>
@@ -493,6 +493,13 @@
             </exclusions>
 
         </dependency>
+        
+        <!-- JSTZ for TimeZone Detection -->
+        <dependency>
+            <groupId>org.webjars.npm</groupId>
+            <artifactId>jstz</artifactId>
+            <version>1.0.10</version>
+        </dependency>
 
     </dependencies>
 
diff --git a/guacamole/src/licenses/LICENSE b/guacamole/src/licenses/LICENSE
index 51f5b21..1e228d2 100644
--- a/guacamole/src/licenses/LICENSE
+++ b/guacamole/src/licenses/LICENSE
@@ -605,6 +605,36 @@
 terms above.
 
 
+JSTZ (https://pellepim.bitbucket.io/jstz/)
+------------------------------------------
+
+    Version: 1.0.10
+    From: 'Jon Nylander' (https://pellepim.bitbucket.io/jstz/)
+    License(s):
+        MIT (bundled/jstz-1.0.10/LICENSE)
+
+Copyright (c) 2012 Jon Nylander, project maintained at 
+https://bitbucket.org/pellepim/jstimezonedetect
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the "Software"), to deal 
+in the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
+of the Software, and to permit persons to whom the Software is furnished to 
+do so, subject to the following conditions: 
+
+The above copyright notice and this permission notice shall be included in 
+all copies or substantial portions of the Software. 
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+THE SOFTWARE.
+
+
 Logback (http://logback.qos.ch/)
 --------------------------------
 
diff --git a/guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE b/guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE
new file mode 100644
index 0000000..c48af16
--- /dev/null
+++ b/guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE
@@ -0,0 +1,22 @@
+MIT License 
+
+Copyright (c) 2012 Jon Nylander, project maintained at 
+https://bitbucket.org/pellepim/jstimezonedetect
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the "Software"), to deal 
+in the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
+of the Software, and to permit persons to whom the Software is furnished to 
+do so, subject to the following conditions: 
+
+The above copyright notice and this permission notice shall be included in 
+all copies or substantial portions of the Software. 
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+THE SOFTWARE.
\ No newline at end of file
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
index ae8c463..0a424ab 100644
--- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
@@ -62,7 +62,8 @@
     private static final List<String> ALLOWED_GUACAMOLE_VERSIONS =
         Collections.unmodifiableList(Arrays.asList(
             "*",
-            "1.0.0"
+            "1.0.0",
+            "1.1.0"
         ));
 
     /**
diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java
index 8c23dab..74e3b4d 100644
--- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java
+++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java
@@ -95,6 +95,11 @@
      * once for each mimetype.
      */
     public static final String IMAGE_PARAMETER = "GUAC_IMAGE";
+    
+    /**
+     * The name of the parameter specifying the timezone of the client.
+     */
+    public static final String TIMEZONE_PARAMETER = "GUAC_TIMEZONE";
 
     /**
      * All supported object types that can be used as the destination of a
@@ -365,5 +370,16 @@
     public List<String> getImageMimetypes() {
         return getParameterValues(IMAGE_PARAMETER);
     }
-
+    
+    /**
+     * Returns the tz database value of the timezone declared by the client
+     * within the tunnel request.
+     * 
+     * @return 
+     *     The tz database value of the timezone parameter as reported by
+     *     the client.
+     */
+    public String getTimezone() {
+        return getParameter(TIMEZONE_PARAMETER);
+    }
 }
diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
index 1479d82..598a4e5 100644
--- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
+++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
@@ -166,6 +166,11 @@
         List<String> imageMimetypes = request.getImageMimetypes();
         if (imageMimetypes != null)
             info.getImageMimetypes().addAll(imageMimetypes);
+        
+        // Set timezone if provided
+        String timezone = request.getTimezone();
+        if (timezone != null && !timezone.isEmpty())
+            info.setTimezone(timezone);
 
         return info;
     }
diff --git a/guacamole/src/main/webapp/app/client/types/ManagedClient.js b/guacamole/src/main/webapp/app/client/types/ManagedClient.js
index a9bc3be..b4637e9 100644
--- a/guacamole/src/main/webapp/app/client/types/ManagedClient.js
+++ b/guacamole/src/main/webapp/app/client/types/ManagedClient.js
@@ -42,6 +42,7 @@
     var authenticationService  = $injector.get('authenticationService');
     var connectionGroupService = $injector.get('connectionGroupService');
     var connectionService      = $injector.get('connectionService');
+    var preferenceService      = $injector.get('preferenceService');
     var requestService         = $injector.get('requestService');
     var tunnelService          = $injector.get('tunnelService');
     var guacAudio              = $injector.get('guacAudio');
@@ -225,6 +226,7 @@
             + "&GUAC_WIDTH="       + Math.floor(optimal_width)
             + "&GUAC_HEIGHT="      + Math.floor(optimal_height)
             + "&GUAC_DPI="         + Math.floor(optimal_dpi)
+            + "&GUAC_TIMEZONE="    + encodeURIComponent(preferenceService.preferences.timezone)
             + (connectionParameters ? '&' + connectionParameters : '');
 
         // Add audio mimetypes to connect string
diff --git a/guacamole/src/main/webapp/app/form/controllers/languageFieldController.js b/guacamole/src/main/webapp/app/form/controllers/languageFieldController.js
new file mode 100644
index 0000000..fdab137
--- /dev/null
+++ b/guacamole/src/main/webapp/app/form/controllers/languageFieldController.js
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * Controller for the language field type. The language field type allows the
+ * user to select a language from the set of languages supported by the
+ * Guacamole web application.
+ */
+angular.module('form').controller('languageFieldController', ['$scope', '$injector',
+    function languageFieldController($scope, $injector) {
+
+    // Required services
+    var languageService = $injector.get('languageService');
+    var requestService  = $injector.get('requestService');
+
+    /**
+     * A map of all available language keys to their human-readable
+     * names.
+     *
+     * @type Object.<String, String>
+     */
+    $scope.languages = null;
+
+    // Retrieve defined languages
+    languageService.getLanguages().then(function languagesRetrieved(languages) {
+        $scope.$apply(function updateLanguageOptions() {
+            $scope.languages = languages;
+        });
+    }, requestService.DIE);
+
+    // Interpret undefined/null as empty string
+    $scope.$watch('model', function setModel(model) {
+        if (!model && model !== '')
+            $scope.model = '';
+    });
+
+}]);
diff --git a/guacamole/src/main/webapp/app/form/controllers/timeZoneFieldController.js b/guacamole/src/main/webapp/app/form/controllers/timeZoneFieldController.js
index 5f17915..39f0c38 100644
--- a/guacamole/src/main/webapp/app/form/controllers/timeZoneFieldController.js
+++ b/guacamole/src/main/webapp/app/form/controllers/timeZoneFieldController.js
@@ -19,8 +19,9 @@
 
 
 /**
- * Controller for time zone fields. Time zone fields use Java IDs as the
- * standard representation for each supported time zone.
+ * Controller for time zone fields. Time zone fields use IANA time zone
+ * database identifiers as the standard representation for each supported time
+ * zone. These identifiers are also legal Java time zone IDs.
  */
 angular.module('form').controller('timeZoneFieldController', ['$scope', '$injector',
     function timeZoneFieldController($scope, $injector) {
@@ -418,7 +419,6 @@
         "Canada" : {
             "Atlantic"          : "Canada/Atlantic",
             "Central"           : "Canada/Central",
-            "East-Saskatchewan" : "Canada/East-Saskatchewan",
             "Eastern"           : "Canada/Eastern",
             "Mountain"          : "Canada/Mountain",
             "Newfoundland"      : "Canada/Newfoundland",
diff --git a/guacamole/src/main/webapp/app/form/formModule.js b/guacamole/src/main/webapp/app/form/formModule.js
index 7e6ede9..1135118 100644
--- a/guacamole/src/main/webapp/app/form/formModule.js
+++ b/guacamole/src/main/webapp/app/form/formModule.js
@@ -20,4 +20,7 @@
 /**
  * Module for displaying dynamic forms.
  */
-angular.module('form', ['locale']);
+angular.module('form', [
+    'locale',
+    'rest'
+]);
diff --git a/guacamole/src/main/webapp/app/form/services/formService.js b/guacamole/src/main/webapp/app/form/services/formService.js
index 168a1ef..6019e74 100644
--- a/guacamole/src/main/webapp/app/form/services/formService.js
+++ b/guacamole/src/main/webapp/app/form/services/formService.js
@@ -131,6 +131,21 @@
         },
 
         /**
+         * Field type which allows selection of languages. The languages
+         * displayed are the set of languages supported by the Guacamole web
+         * application. Legal values are valid language IDs, as dictated by
+         * the filenames of Guacamole's available translations.
+         *
+         * @see {@link Field.Type.LANGUAGE}
+         * @type FieldType
+         */
+        'LANGUAGE' : {
+            module      : 'form',
+            controller  : 'languageFieldController',
+            templateUrl : 'app/form/templates/languageField.html'
+        },
+
+        /**
          * Field type which allows selection of time zones.
          *
          * @see {@link Field.Type.TIMEZONE}
diff --git a/guacamole/src/main/webapp/app/form/templates/languageField.html b/guacamole/src/main/webapp/app/form/templates/languageField.html
new file mode 100644
index 0000000..404f74e
--- /dev/null
+++ b/guacamole/src/main/webapp/app/form/templates/languageField.html
@@ -0,0 +1 @@
+<select ng-model="model" ng-options="language.key as language.value for language in languages | toArray | orderBy: key"></select>
\ No newline at end of file
diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js
index 71e7af7..aad0a2e 100644
--- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js
+++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js
@@ -39,7 +39,6 @@
             var $translate            = $injector.get('$translate');
             var authenticationService = $injector.get('authenticationService');
             var guacNotification      = $injector.get('guacNotification');
-            var languageService       = $injector.get('languageService');
             var permissionService     = $injector.get('permissionService');
             var preferenceService     = $injector.get('preferenceService');
             var requestService        = $injector.get('requestService');
@@ -78,21 +77,23 @@
              * @type Object.<String, Object>
              */
             $scope.preferences = preferenceService.preferences;
-            
+
             /**
-             * A map of all available language keys to their human-readable
-             * names.
-             * 
-             * @type Object.<String, String>
+             * The fields which should be displayed for choosing locale
+             * preferences. Each field name must be a property on
+             * $scope.preferences.
+             *
+             * @type Field[]
              */
-            $scope.languages = null;
-            
-            /**
-             * Switches the active display langugae to the chosen language.
-             */
-            $scope.changeLanguage = function changeLanguage() {
-                $translate.use($scope.preferences.language);
-            };
+            $scope.localeFields = [
+                { 'type' : 'LANGUAGE', 'name' : 'language' },
+                { 'type' : 'TIMEZONE', 'name' : 'timezone' }
+            ];
+
+            // Automatically update applied translation when language preference is changed
+            $scope.$watch('preferences.language', function changeLanguage(language) {
+                $translate.use(language);
+            });
 
             /**
              * The new password for the user.
@@ -169,17 +170,6 @@
                 
             };
 
-            // Retrieve defined languages
-            languageService.getLanguages()
-            .then(function languagesRetrieved(languages) {
-                $scope.languages = Object.keys(languages).map(function(key) {
-                    return {
-                        key: key,
-                        value: languages[key]
-                    };
-                });
-            }, requestService.DIE);
-
             // Retrieve current permissions
             permissionService.getEffectivePermissions(dataSource, username)
             .then(function permissionsRetrieved(permissions) {
diff --git a/guacamole/src/main/webapp/app/settings/services/preferenceService.js b/guacamole/src/main/webapp/app/settings/services/preferenceService.js
index bcd8633..9c4d5fc 100644
--- a/guacamole/src/main/webapp/app/settings/services/preferenceService.js
+++ b/guacamole/src/main/webapp/app/settings/services/preferenceService.js
@@ -98,6 +98,18 @@
         return language.replace(/-/g, '_');
 
     };
+    
+    /**
+     * Return the timezone detected for the current browser session
+     * by the JSTZ timezone library.
+     * 
+     * @returns String
+     *     The name of the currently-detected timezone in IANA zone key
+     *     format (Olson time zone database).
+     */
+    var getDetectedTimezone = function getDetectedTimezone() {
+        return jstz.determine().name();
+    };
 
     /**
      * All currently-set preferences, as name/value pairs. Each property name
@@ -128,7 +140,15 @@
          * 
          * @type String
          */
-        language : getDefaultLanguageKey()
+        language : getDefaultLanguageKey(),
+        
+        /**
+         * The timezone set by the user, in IANA zone key format (Olson time
+         * zone database).
+         * 
+         * @type String
+         */
+        timezone : getDetectedTimezone()
 
     };
 
diff --git a/guacamole/src/main/webapp/app/settings/styles/preferences.css b/guacamole/src/main/webapp/app/settings/styles/preferences.css
index ed8460d..dbb2330 100644
--- a/guacamole/src/main/webapp/app/settings/styles/preferences.css
+++ b/guacamole/src/main/webapp/app/settings/styles/preferences.css
@@ -17,8 +17,23 @@
  * under the License.
  */
 
-.preferences .update-password .form, 
-.preferences .language .form {
+.preferences .form .fields {
+    display: table;
     padding-left: 0.5em;
-    border-left: 3px solid rgba(0, 0, 0, 0.125);
-}
\ No newline at end of file
+    border-left: 3px solid rgba(0,0,0,0.125);
+}
+
+.preferences .form .fields .labeled-field {
+    display: table-row;
+}
+
+.preferences .form .fields .field-header,
+.preferences .form .fields .form-field {
+    display: table-cell;
+    padding: 0.125em;
+    vertical-align: top;
+}
+
+.preferences .form .fields .field-header {
+    padding-right: 1em;
+}
diff --git a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html
index 826a5cd..581a66e 100644
--- a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html
+++ b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html
@@ -1,18 +1,9 @@
 <div class="preferences" ng-class="{loading: !isLoaded()}">
 
-    <!-- Language settings -->
-    <div class="settings section language">
-        <p>{{'SETTINGS_PREFERENCES.HELP_LANGUAGE' | translate}}</p>
-
-        <!-- Language selection -->
-        <div class="form">
-            <table class="fields">
-                <tr>
-                    <th>{{'SETTINGS_PREFERENCES.FIELD_HEADER_LANGUAGE' | translate}}</th>
-                    <td><select ng-model="preferences.language" ng-change="changeLanguage()" ng-options="language.key as language.value for language in languages | orderBy: key"></select></td>
-                </tr>
-            </table>
-        </div>
+    <!-- Locale settings -->
+    <div class="settings section locale">
+        <p>{{'SETTINGS_PREFERENCES.HELP_LOCALE' | translate}}</p>
+        <guac-form content="localeFields" model="preferences" namespace="'SETTINGS_PREFERENCES'"></guac-form>
     </div>
     
     <!-- Password update -->
diff --git a/guacamole/src/main/webapp/index.html b/guacamole/src/main/webapp/index.html
index 1d51606..e675546 100644
--- a/guacamole/src/main/webapp/index.html
+++ b/guacamole/src/main/webapp/index.html
@@ -85,6 +85,9 @@
         <script type="text/javascript" src="webjars/angular-translate-interpolation-messageformat/2.16.0/angular-translate-interpolation-messageformat.min.js"></script>
         <script type="text/javascript" src="webjars/angular-translate-loader-static-files/2.16.0/angular-translate-loader-static-files.min.js"></script>
 
+        <!-- JSTZ -->
+        <script type="text/javascript" src="webjars/jstz/1.0.10/dist/jstz.min.js"></script>
+        
         <!-- Polyfills for the "datalist" element, Blob and the FileSaver API -->
         <script type="text/javascript" src="webjars/blob-polyfill/1.0.20150320/Blob.js"></script>
         <script type="text/javascript" src="webjars/datalist-polyfill/1.14.0/datalist-polyfill.min.js"></script>
diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json
index eed9473..2123de0 100644
--- a/guacamole/src/main/webapp/translations/en.json
+++ b/guacamole/src/main/webapp/translations/en.json
@@ -428,6 +428,7 @@
         "FIELD_HEADER_SFTP_ROOT_DIRECTORY"        : "File browser root directory:",
         "FIELD_HEADER_SFTP_USERNAME"              : "Username:",
         "FIELD_HEADER_STATIC_CHANNELS" : "Static channel names:",
+        "FIELD_HEADER_TIMEZONE"        : "Time zone:",
         "FIELD_HEADER_USERNAME"        : "Username:",
         "FIELD_HEADER_WIDTH"           : "Width:",
 
@@ -460,6 +461,7 @@
         "FIELD_OPTION_SERVER_LAYOUT_JA_JP_QWERTY" : "Japanese (Qwerty)",
         "FIELD_OPTION_SERVER_LAYOUT_PT_BR_QWERTY" : "Portuguese Brazilian (Qwerty)",
         "FIELD_OPTION_SERVER_LAYOUT_SV_SE_QWERTY" : "Swedish (Qwerty)",
+        "FIELD_OPTION_SERVER_LAYOUT_DA_DK_QWERTY" : "Danish (Qwerty)",
         "FIELD_OPTION_SERVER_LAYOUT_TR_TR_QWERTY" : "Turkish-Q (Qwerty)",
 
         "NAME" : "RDP",
@@ -491,6 +493,7 @@
         "FIELD_HEADER_ENABLE_SFTP"   : "Enable SFTP:",
         "FIELD_HEADER_HOST_KEY"      : "Public host key (Base64):",
         "FIELD_HEADER_HOSTNAME"      : "Hostname:",
+        "FIELD_HEADER_LOCALE"        : "Language/Locale ($LANG):",
         "FIELD_HEADER_USERNAME"      : "Username:",
         "FIELD_HEADER_PASSWORD"      : "Password:",
         "FIELD_HEADER_PASSPHRASE"    : "Passphrase:",
@@ -505,6 +508,7 @@
         "FIELD_HEADER_SERVER_ALIVE_INTERVAL" : "Server keepalive interval:",
         "FIELD_HEADER_SFTP_ROOT_DIRECTORY"   : "File browser root directory:",
         "FIELD_HEADER_TERMINAL_TYPE"   : "Terminal type:",
+        "FIELD_HEADER_TIMEZONE"        : "Time zone ($TZ):",
         "FIELD_HEADER_TYPESCRIPT_NAME" : "Typescript name:",
         "FIELD_HEADER_TYPESCRIPT_PATH" : "Typescript path:",
 
@@ -754,6 +758,7 @@
         "FIELD_HEADER_PASSWORD_OLD"       : "Current Password:",
         "FIELD_HEADER_PASSWORD_NEW"       : "New Password:",
         "FIELD_HEADER_PASSWORD_NEW_AGAIN" : "Confirm New Password:",
+        "FIELD_HEADER_TIMEZONE"           : "Timezone:",
         "FIELD_HEADER_USERNAME"           : "Username:",
         
         "HELP_DEFAULT_INPUT_METHOD" : "The default input method determines how keyboard events are received by Guacamole. Changing this setting may be necessary when using a mobile device, or when typing through an IME. This setting can be overridden on a per-connection basis within the Guacamole menu.",
@@ -761,7 +766,7 @@
         "HELP_INPUT_METHOD_NONE"    : "@:CLIENT.HELP_INPUT_METHOD_NONE",
         "HELP_INPUT_METHOD_OSK"     : "@:CLIENT.HELP_INPUT_METHOD_OSK",
         "HELP_INPUT_METHOD_TEXT"    : "@:CLIENT.HELP_INPUT_METHOD_TEXT",
-        "HELP_LANGUAGE"             : "Select a different language below to change the language of all text within Guacamole. Available choices will depend on which languages are installed.",
+        "HELP_LOCALE"               : "Options below are related to the locale of the user and will impact how various parts of the interface are displayed.",
         "HELP_MOUSE_MODE_ABSOLUTE"  : "@:CLIENT.HELP_MOUSE_MODE_ABSOLUTE",
         "HELP_MOUSE_MODE_RELATIVE"  : "@:CLIENT.HELP_MOUSE_MODE_RELATIVE",
         "HELP_UPDATE_PASSWORD"      : "If you wish to change your password, enter your current password and the desired new password below, and click \"Update Password\". The change will take effect immediately.",
diff --git a/guacamole/src/main/webapp/translations/zh.json b/guacamole/src/main/webapp/translations/zh.json
index eca8656..b940418 100644
--- a/guacamole/src/main/webapp/translations/zh.json
+++ b/guacamole/src/main/webapp/translations/zh.json
@@ -4,9 +4,6 @@
     
     "APP" : {
 
-        "NAME"    : "Apache Guacamole",
-        "VERSION" : "${project.version}",
-
         "ACTION_ACKNOWLEDGE"        : "确定",
         "ACTION_CANCEL"             : "取消",
         "ACTION_CLONE"              : "克隆",
diff --git a/pom.xml b/pom.xml
index 480eb23..83cfa8e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
     <groupId>org.apache.guacamole</groupId>
     <artifactId>guacamole-client</artifactId>
     <packaging>pom</packaging>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
     <name>guacamole-client</name>
     <url>http://guacamole.apache.org/</url>