Implementation for console control events (includes process groups
support).

diff --git a/server/console.c b/server/console.c
index 6ddd077..718d124 100644
--- a/server/console.c
+++ b/server/console.c
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <signal.h>
 
 #include "handle.h"
 #include "process.h"
@@ -385,6 +386,54 @@
     return console->recnum ? 1 : 0;
 }
 
+struct console_signal_info {
+    struct console_input        *console;
+    struct process              *group;
+    int                          signal;
+};
+
+static int propagate_console_signal_cb(struct process *process, void *user)
+{
+    struct console_signal_info* csi = (struct console_signal_info*)user;
+
+    if (process->console == csi->console && process->running_threads &&
+        (csi->group == NULL || process->group_id == csi->group))
+    {
+        struct thread *thread = process->thread_list;
+
+        while (thread)
+        {
+            struct thread *next = thread->proc_next;
+            kill( thread->unix_pid, csi->signal );
+            thread = next;
+        }
+    }
+    return FALSE;
+}
+
+static void propagate_console_signal( struct console_input *console, 
+                                      int sig, void* group_id )
+{
+    struct console_signal_info csi;
+
+    if (!console)
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+    /* FIXME: should support the other events (like CTRL_BREAK) */
+    if (sig != CTRL_C_EVENT)
+    {
+        set_error( STATUS_NOT_IMPLEMENTED );
+        return;
+    }
+    csi.console = console;
+    csi.signal  = SIGINT;
+    csi.group   = group_id;
+
+    enum_processes(propagate_console_signal_cb, &csi);
+}
+
 static int get_console_mode( obj_handle_t handle )
 {
     struct object *obj;
@@ -443,8 +492,31 @@
     }
     console->records = new_rec;
     memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
-    console->recnum += count;
 
+    if (console->mode & ENABLE_PROCESSED_INPUT)
+    {
+        int i = 0;
+        while (i < count)
+        {
+            if (records[i].EventType == KEY_EVENT && 
+		records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
+		!(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
+            {
+                if (i != count - 1)
+                    memcpy( &console->records[console->recnum + i], 
+                            &console->records[console->recnum + i + 1], 
+                            (count - i - 1) * sizeof(INPUT_RECORD) );
+                count--;
+                if (records[i].Event.KeyEvent.bKeyDown)
+                {
+                    /* send SIGINT to all processes attached to this console */
+                    propagate_console_signal( console, CTRL_C_EVENT, NULL );
+                }
+            }
+            else i++;
+        }
+    }
+    console->recnum += count;
     /* wake up all waiters */
     wake_up( &console->obj, 0 );
     return count;
@@ -1385,3 +1457,18 @@
     scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
 			   req->w, req->h );
 }
+
+/* sends a signal to a console (process, group...) */
+DECL_HANDLER(send_console_signal)
+{
+    void*       group;
+
+    group = req->group_id ? req->group_id : current->process->group_id;
+
+    if (!group)
+        set_error( STATUS_INVALID_PARAMETER);
+    else
+        propagate_console_signal( current->process->console, req->signal, group );
+}
+
+
diff --git a/server/process.c b/server/process.c
index 0f89aa3..6a60569 100644
--- a/server/process.c
+++ b/server/process.c
@@ -218,6 +218,7 @@
     process->exe.dbg_size    = 0;
     process->exe.namelen     = 0;
     process->exe.filename    = NULL;
+    process->group_id        = NULL;
 
     gettimeofday( &process->start_time, NULL );
     if ((process->next = first_process) != NULL) process->next->prev = process;
@@ -285,6 +286,7 @@
     /* set the process console */
     if (!set_process_console( process, parent_thread, info, reply )) return NULL;
 
+    process->group_id = process;
     if (parent)
     {
         /* attach to the debugger if requested */
@@ -292,6 +294,8 @@
             set_process_debugger( process, parent_thread );
         else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
             set_process_debugger( process, parent->debugger );
+        if (!(process->create_flags & CREATE_NEW_PROCESS_GROUP))
+            process->group_id = parent->group_id;
     }
 
     /* thread will be actually suspended in init_done */
@@ -614,6 +618,16 @@
 }
 
 
+void enum_processes( int (*cb)(struct process*, void*), void *user )
+{
+    struct process *process;
+    for (process = first_process; process; process = process->next)
+    {
+        if ((cb)(process, user)) break;
+    }
+}
+
+
 /* get all information about a process */
 static void get_process_info( struct process *process, struct get_process_info_reply *reply )
 {
diff --git a/server/process.h b/server/process.h
index e320491..27ea25f 100644
--- a/server/process.h
+++ b/server/process.h
@@ -72,6 +72,7 @@
     struct process_dll   exe;             /* main exe file */
     void                *ldt_copy;        /* pointer to LDT copy in client addr space */
     void                *ldt_flags;       /* pointer to LDT flags in client addr space */
+    void                *group_id;        /* group ID of the process */
 };
 
 struct process_snapshot
@@ -110,6 +111,7 @@
 extern void detach_debugged_processes( struct thread *debugger );
 extern struct process_snapshot *process_snap( int *count );
 extern struct module_snapshot *module_snap( struct process *process, int *count );
+extern void enum_processes( int (*cb)(struct process*, void*), void *user);
 
 inline static void *get_process_id( struct process *process ) { return process; }
 inline static int is_process_init_done( struct process *process )
diff --git a/server/protocol.def b/server/protocol.def
index 8b68a43..9d4f8f3 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1009,6 +1009,7 @@
     VARARG(data,bytes);
 @END
 
+
 /* move a rect (of data) in screen buffer content */
 @REQ(move_console_output)
     obj_handle_t handle;        /* handle to the console output */
@@ -1021,6 +1022,13 @@
 @END
 
 
+/* Sends a signal to a process group */
+@REQ(send_console_signal)
+    int          signal;        /* the signal to send */
+    void*        group_id;      /* the group to send the signal to */
+@END
+
+
 /* Create a change notification */
 @REQ(create_change_notification)
     int          subtree;       /* watch all the subtree */
diff --git a/server/request.h b/server/request.h
index 94a659d..5f893ab 100644
--- a/server/request.h
+++ b/server/request.h
@@ -172,6 +172,7 @@
 DECL_HANDLER(fill_console_output);
 DECL_HANDLER(read_console_output);
 DECL_HANDLER(move_console_output);
+DECL_HANDLER(send_console_signal);
 DECL_HANDLER(create_change_notification);
 DECL_HANDLER(create_mapping);
 DECL_HANDLER(open_mapping);
@@ -333,6 +334,7 @@
     (req_handler)req_fill_console_output,
     (req_handler)req_read_console_output,
     (req_handler)req_move_console_output,
+    (req_handler)req_send_console_signal,
     (req_handler)req_create_change_notification,
     (req_handler)req_create_mapping,
     (req_handler)req_open_mapping,
diff --git a/server/trace.c b/server/trace.c
index b36cfa7..c96863d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1191,6 +1191,12 @@
     fprintf( stderr, " h=%d", req->h );
 }
 
+static void dump_send_console_signal_request( const struct send_console_signal_request *req )
+{
+    fprintf( stderr, " signal=%d,", req->signal );
+    fprintf( stderr, " group_id=%p", req->group_id );
+}
+
 static void dump_create_change_notification_request( const struct create_change_notification_request *req )
 {
     fprintf( stderr, " subtree=%d,", req->subtree );
@@ -2239,6 +2245,7 @@
     (dump_func)dump_fill_console_output_request,
     (dump_func)dump_read_console_output_request,
     (dump_func)dump_move_console_output_request,
+    (dump_func)dump_send_console_signal_request,
     (dump_func)dump_create_change_notification_request,
     (dump_func)dump_create_mapping_request,
     (dump_func)dump_open_mapping_request,
@@ -2397,6 +2404,7 @@
     (dump_func)dump_fill_console_output_reply,
     (dump_func)dump_read_console_output_reply,
     (dump_func)0,
+    (dump_func)0,
     (dump_func)dump_create_change_notification_reply,
     (dump_func)dump_create_mapping_reply,
     (dump_func)dump_open_mapping_reply,
@@ -2555,6 +2563,7 @@
     "fill_console_output",
     "read_console_output",
     "move_console_output",
+    "send_console_signal",
     "create_change_notification",
     "create_mapping",
     "open_mapping",