cmd.exe: Add ASSOC command.
diff --git a/programs/cmd/Cs.rc b/programs/cmd/Cs.rc
index 390d875..f4a436f 100644
--- a/programs/cmd/Cs.rc
+++ b/programs/cmd/Cs.rc
@@ -234,4 +234,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/De.rc b/programs/cmd/De.rc
index 50a69bc..3dca9d8 100644
--- a/programs/cmd/De.rc
+++ b/programs/cmd/De.rc
@@ -251,4 +251,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/En.rc b/programs/cmd/En.rc
index 10891a5..e0310dd 100644
--- a/programs/cmd/En.rc
+++ b/programs/cmd/En.rc
@@ -238,4 +238,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Es.rc b/programs/cmd/Es.rc
index 4822007..591c217 100644
--- a/programs/cmd/Es.rc
+++ b/programs/cmd/Es.rc
@@ -246,4 +246,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Fr.rc b/programs/cmd/Fr.rc
index 78f206d..058cda7 100644
--- a/programs/cmd/Fr.rc
+++ b/programs/cmd/Fr.rc
@@ -228,4 +228,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Ja.rc b/programs/cmd/Ja.rc
index 1937480..cbad955 100644
--- a/programs/cmd/Ja.rc
+++ b/programs/cmd/Ja.rc
@@ -232,4 +232,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Ko.rc b/programs/cmd/Ko.rc
index fa6b83f..a62e688 100644
--- a/programs/cmd/Ko.rc
+++ b/programs/cmd/Ko.rc
@@ -223,4 +223,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Makefile.in b/programs/cmd/Makefile.in
index 97aedf1..3a81838 100644
--- a/programs/cmd/Makefile.in
+++ b/programs/cmd/Makefile.in
@@ -4,7 +4,7 @@
 VPATH     = @srcdir@
 MODULE    = cmd.exe
 APPMODE   = -mconsole
-IMPORTS   = shell32 user32 kernel32
+IMPORTS   = shell32 user32 advapi32 kernel32
 
 C_SRCS = \
 	batch.c \
diff --git a/programs/cmd/Nl.rc b/programs/cmd/Nl.rc
index 8e8d1c4..fb43206 100644
--- a/programs/cmd/Nl.rc
+++ b/programs/cmd/Nl.rc
@@ -231,4 +231,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/No.rc b/programs/cmd/No.rc
index c98dd15..bf2f52e 100644
--- a/programs/cmd/No.rc
+++ b/programs/cmd/No.rc
@@ -229,4 +229,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Pl.rc b/programs/cmd/Pl.rc
index 5b49433..d0e7fd2 100644
--- a/programs/cmd/Pl.rc
+++ b/programs/cmd/Pl.rc
@@ -225,4 +225,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Pt.rc b/programs/cmd/Pt.rc
index 13a9b4c..b544db1 100644
--- a/programs/cmd/Pt.rc
+++ b/programs/cmd/Pt.rc
@@ -438,4 +438,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Ru.rc b/programs/cmd/Ru.rc
index 4118102..8f3bdea 100644
--- a/programs/cmd/Ru.rc
+++ b/programs/cmd/Ru.rc
@@ -229,4 +229,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Si.rc b/programs/cmd/Si.rc
index 7623beb..426a8d4 100644
--- a/programs/cmd/Si.rc
+++ b/programs/cmd/Si.rc
@@ -230,4 +230,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/Tr.rc b/programs/cmd/Tr.rc
index bdecde3..6977407 100644
--- a/programs/cmd/Tr.rc
+++ b/programs/cmd/Tr.rc
@@ -232,4 +232,5 @@
   WCMD_CONFIRM, "Are you sure"
   WCMD_YES, "Y"
   WCMD_NO, "N"
+  WCMD_NOASSOC, "File association missing for extension %s\n"
 }
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 8418ab4..79c522c 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -1457,3 +1457,159 @@
     /* Return the answer */
     return (answer[0] == Ybuffer[0]);
 }
+
+/*****************************************************************************
+ * WCMD_assoc
+ *
+ *	Lists or sets file associations
+ */
+void WCMD_assoc (char *command) {
+
+    HKEY    key;
+    DWORD   accessOptions = KEY_READ;
+    char   *newValue;
+    LONG    rc = ERROR_SUCCESS;
+    char    keyValue[MAXSTRING];
+    DWORD   valueLen = MAXSTRING;
+    HKEY    readKey;
+
+
+    /* See if parameter includes '=' */
+    errorlevel = 0;
+    newValue = strchr(command, '=');
+    if (newValue) accessOptions |= KEY_WRITE;
+
+    /* Open a key to HKEY_CLASSES_ROOT for enumerating */
+    if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "", 0,
+                     accessOptions, &key) != ERROR_SUCCESS) {
+      WINE_FIXME("Unexpected failure opening HKCR key: %d\n", GetLastError());
+      return;
+    }
+
+    /* If no paramaters then list all associations */
+    if (*command == 0x00) {
+      int index = 0;
+
+      /* Enumerate all the keys */
+      while (rc != ERROR_NO_MORE_ITEMS) {
+        char  keyName[MAXSTRING];
+        DWORD nameLen;
+
+        /* Find the next value */
+        nameLen = MAXSTRING;
+        rc = RegEnumKeyEx(key, index++,
+                          keyName, &nameLen,
+                          NULL, NULL, NULL, NULL);
+
+        if (rc == ERROR_SUCCESS) {
+
+          /* Only interested in extension ones */
+          if (keyName[0] == '.') {
+
+            if (RegOpenKeyEx(key, keyName, 0,
+                             accessOptions, &readKey) == ERROR_SUCCESS) {
+
+              rc = RegQueryValueEx(readKey, NULL, NULL, NULL,
+                                   (LPBYTE)keyValue, &valueLen);
+              WCMD_output_asis(keyName);
+              WCMD_output_asis("=");
+              /* If no default value found, leave line empty after '=' */
+              if (rc == ERROR_SUCCESS) {
+                WCMD_output_asis(keyValue);
+              }
+              WCMD_output_asis("\n");
+            }
+          }
+        }
+      }
+      RegCloseKey(readKey);
+
+    } else {
+
+      /* Parameter supplied - if no '=' on command line, its a query */
+      if (newValue == NULL) {
+        char *space;
+
+        /* Query terminates the parameter at the first space */
+        strcpy(keyValue, command);
+        space = strchr(keyValue, ' ');
+        if (space) *space=0x00;
+
+        if (RegOpenKeyEx(key, keyValue, 0,
+                         accessOptions, &readKey) == ERROR_SUCCESS) {
+
+          rc = RegQueryValueEx(readKey, NULL, NULL, NULL,
+                               (LPBYTE)keyValue, &valueLen);
+          WCMD_output_asis(command);
+          WCMD_output_asis("=");
+          /* If no default value found, leave line empty after '=' */
+          if (rc == ERROR_SUCCESS) WCMD_output_asis(keyValue);
+          WCMD_output_asis("\n");
+          RegCloseKey(readKey);
+
+        } else {
+          char  msgbuffer[MAXSTRING];
+          char  outbuffer[MAXSTRING];
+
+          /* Load the translated 'File association not found' */
+          LoadString (hinst, WCMD_NOASSOC, msgbuffer, sizeof(msgbuffer));
+          sprintf(outbuffer, msgbuffer, keyValue);
+          WCMD_output_asis(outbuffer);
+          errorlevel = 2;
+        }
+
+      /* Not a query - its a set or clear of a value */
+      } else {
+
+        /* Get pointer to new value */
+        *newValue = 0x00;
+        newValue++;
+
+        /* If nothing after '=' then clear value */
+        if (*newValue == 0x00) {
+
+          rc = RegDeleteKey(key, command);
+          if (rc == ERROR_SUCCESS) {
+            WINE_TRACE("HKCR Key '%s' deleted\n", command);
+
+          } else if (rc != ERROR_FILE_NOT_FOUND) {
+            WCMD_print_error();
+            errorlevel = 2;
+
+          } else {
+            char  msgbuffer[MAXSTRING];
+            char  outbuffer[MAXSTRING];
+
+            /* Load the translated 'File association not found' */
+            LoadString (hinst, WCMD_NOASSOC, msgbuffer, sizeof(msgbuffer));
+            sprintf(outbuffer, msgbuffer, keyValue);
+            WCMD_output_asis(outbuffer);
+            errorlevel = 2;
+          }
+
+        /* It really is a set value = contents */
+        } else {
+          rc = RegCreateKeyEx(key, command, 0, NULL, REG_OPTION_NON_VOLATILE,
+                              accessOptions, NULL, &readKey, NULL);
+          if (rc == ERROR_SUCCESS) {
+            rc = RegSetValueEx(readKey, NULL, 0, REG_SZ,
+                                 (LPBYTE)newValue, strlen(newValue));
+            RegCloseKey(readKey);
+          }
+
+          if (rc != ERROR_SUCCESS) {
+            WCMD_print_error();
+            errorlevel = 2;
+          } else {
+            WCMD_output_asis(command);
+            WCMD_output_asis("=");
+            WCMD_output_asis(newValue);
+            WCMD_output_asis("\n");
+          }
+        }
+      }
+    }
+
+    /* Clean up */
+    RegCloseKey(key);
+}
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 49307c7..fc3ce12 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <ctype.h>
 
+void WCMD_assoc (char *);
 void WCMD_batch (char *, char *, int, char *, HANDLE);
 void WCMD_call (char *command);
 void WCMD_change_tty (void);
@@ -155,9 +156,10 @@
 #define WCMD_SETLOCAL 37
 #define WCMD_PUSHD  38
 #define WCMD_POPD   39
+#define WCMD_ASSOC  40
 
 /* Must be last in list */
-#define WCMD_EXIT   40
+#define WCMD_EXIT   41
 
 /* Some standard messages */
 extern const char nyi[];
@@ -169,6 +171,7 @@
 #define WCMD_CONFIRM  1001
 #define WCMD_YES      1002
 #define WCMD_NO       1003
+#define WCMD_NOASSOC  1004
 
 /* msdn specified max for Win XP */
 #define MAXSTRING 8192
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index a1f426c..757cd3a 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -26,13 +26,16 @@
 
 #include "config.h"
 #include "wcmd.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(cmd);
 
 const char * const inbuilt[] = {"ATTRIB", "CALL", "CD", "CHDIR", "CLS", "COPY", "CTTY",
 		"DATE", "DEL", "DIR", "ECHO", "ERASE", "FOR", "GOTO",
 		"HELP", "IF", "LABEL", "MD", "MKDIR", "MOVE", "PATH", "PAUSE",
 		"PROMPT", "REM", "REN", "RENAME", "RD", "RMDIR", "SET", "SHIFT",
                 "TIME", "TITLE", "TYPE", "VERIFY", "VER", "VOL", 
-                "ENDLOCAL", "SETLOCAL", "PUSHD", "POPD", "EXIT" };
+                "ENDLOCAL", "SETLOCAL", "PUSHD", "POPD", "ASSOC", "EXIT" };
 
 HINSTANCE hinst;
 DWORD errorlevel;
@@ -441,6 +444,7 @@
  * Strip leading whitespaces, and a '@' if supplied
  */
     whichcmd = WCMD_strtrim_leading_spaces(cmd);
+    WINE_TRACE("Command: '%s'\n", cmd);
     if (whichcmd[0] == '@') whichcmd++;
 
 /*
@@ -570,6 +574,9 @@
       case WCMD_POPD:
         WCMD_popd();
         break;
+      case WCMD_ASSOC:
+        WCMD_assoc(p);
+        break;
       case WCMD_EXIT:
         WCMD_exit ();
         break;