Index: trunk.inputto/doc/master/privilege_violation
===================================================================
--- trunk.inputto/doc/master/privilege_violation	(Revision 2537)
+++ trunk.inputto/doc/master/privilege_violation	(Arbeitskopie)
@@ -1,5 +1,5 @@
 SYNOPSIS
-        int privilege_violation(string op, mixed who, mixed arg, mixed arg2)
+        int privilege_violation(string op, mixed who, mixed arg, mixed arg2, mixed arg3)
 
 DESCRIPTION
         Validate the execution of a privileged operation.
@@ -18,6 +18,8 @@
         bind_lambda       Bind a lambda-closure to object <arg>.
         call_out_info     Return an array with all call_out
                           informations.
+        configure_interactive Set option <arg2> with value <arg3> as
+                          default (<arg>==0) or for object <arg>.
         enable_telnet     Enable/disable telnet (<arg2>) for object <arg>.
         execute_command   Execute command string <arg2> for the object
                           <arg>.
Index: trunk.inputto/doc/efun/set_driver_hook
===================================================================
--- trunk.inputto/doc/efun/set_driver_hook	(Revision 2537)
+++ trunk.inputto/doc/efun/set_driver_hook	(Arbeitskopie)
@@ -88,6 +88,11 @@
           Optional hook to notify the mudlib about the termination of
           the erq demon.
 
+        H_MSG_DISCARDED
+          arg: lambda closure, lfun closure, string
+          Optional hook to specify a message or take other measures
+          when a message had to be discarded.
+
         See hooks(C) for a detailed discussion.
 
 HISTORY
Index: trunk.inputto/doc/concepts/hooks
===================================================================
--- trunk.inputto/doc/concepts/hooks	(Revision 2537)
+++ trunk.inputto/doc/concepts/hooks	(Arbeitskopie)
@@ -125,6 +125,11 @@
           the erq demon.
 
 
+        H_MSG_DISCARDED
+          Optional hook to specify a message or take other measures
+          when a message had to be discarded.
+
+
 HISTORY
         The hooks concept was introduced in 3.2.1
         H_MOVE_OBJECT0/1 were introduced in 3.2.1@1
Index: trunk.inputto/src/pkg-mccp.c
===================================================================
--- trunk.inputto/src/pkg-mccp.c	(Revision 2537)
+++ trunk.inputto/src/pkg-mccp.c	(Arbeitskopie)
@@ -204,7 +204,7 @@
     ip->out_compress_buf = NULL;
 
     /* try to send any residual data */
-    comm_socket_write((char*) buf, len, ip);
+    comm_socket_write((char*) buf, len, ip, WB_NONDISCARDABLE);
    
     printf("%s MCCP-DEBUG: '%s' mccp ended\n"
           , time_stamp(), get_txt(ip->ob->name));
Index: trunk.inputto/src/make_func.y
===================================================================
--- trunk.inputto/src/make_func.y	(Revision 2537)
+++ trunk.inputto/src/make_func.y	(Arbeitskopie)
@@ -1652,6 +1652,8 @@
         return H_PRINT_PROMPT;
     if ( !strcmp(name, "REGEXP_PACKAGE") )
         return H_REGEXP_PACKAGE;
+    if ( !strcmp(name, "MSG_DISCARDED") )
+        return H_MSG_DISCARDED;
     return -1;
 }
 
Index: trunk.inputto/src/prolang.y
===================================================================
--- trunk.inputto/src/prolang.y	(Revision 2537)
+++ trunk.inputto/src/prolang.y	(Arbeitskopie)
@@ -207,6 +207,7 @@
     H_DEFAULT_PROMPT: SH(T_CLOSURE) SH(T_STRING), \
     H_PRINT_PROMPT:   SH(T_CLOSURE) SH(T_STRING), \
     H_REGEXP_PACKAGE: SH(T_NUMBER), \
+    H_MSG_DISCARDED:  SH(T_CLOSURE) SH(T_STRING), \
 
 #undef SH
 
Index: trunk.inputto/src/comm.c
===================================================================
--- trunk.inputto/src/comm.c	(Revision 2537)
+++ trunk.inputto/src/comm.c	(Arbeitskopie)
@@ -134,6 +134,7 @@
 #include "i-eval_cost.h"
 
 #include "../mudlib/sys/comm.h"
+#include "../mudlib/sys/configuration.h"
 #include "../mudlib/sys/driver_hook.h"
 #include "../mudlib/sys/input_to.h"
 
@@ -225,8 +226,10 @@
    * a 'null format string'.
    */
 
-long write_buffer_max_size = WRITE_BUFFER_MAX_SIZE;
+p_int write_buffer_max_size = WRITE_BUFFER_MAX_SIZE;
   /* Amount of data held pending in the write fifo queue.
+   *   0: No queue.
+   *  -1: Infinite queue.
    */
 
 
@@ -469,7 +472,9 @@
 static void send_wont(int);
 static void send_do(int);
 static void send_dont(int);
+static void add_flush_entry(interactive_t *ip);
 static void remove_flush_entry(interactive_t *ip);
+static void clear_message_buf(interactive_t *ip);
 static void new_player(object_t *receiver, SOCKET_T new_socket, struct sockaddr_in *addr, size_t len, int login_port);
 
 #ifdef ERQ_DEMON
@@ -753,7 +758,6 @@
       default: putc('\n', stderr);
       }
     fprintf(stderr, "  .supress_go_ahead:  %02hhx\n", (unsigned char)ip->supress_go_ahead);
-    fprintf(stderr, "  .msg_discarded:     %hd\n", ip->msg_discarded);
     fprintf(stderr, "  .text_end:          %hd (%p)\n", ip->text_end, ip->text+ip->text_end);
     fprintf(stderr, "  .command_start:     %hd (%p)\n", ip->command_start, ip->text+ip->command_start);
     fprintf(stderr, "  .command_end:       %hd (%p)\n", ip->command_end, ip->text+ip->command_end);
@@ -1350,7 +1354,7 @@
         case EPIPE:
             fprintf(stderr, "%s comm: write EPIPE detected\n", time_stamp());
             break;
-            
+
         case ECONNRESET:
             fprintf(stderr, "%s comm: write ECONNRESET detected\n", time_stamp());
             break;
@@ -1362,10 +1366,10 @@
                                   , time_stamp(), e, strerror(e));
             }
         }
-        
+
         if (n == 0)
             break;
-            
+
         ip->do_close = FLAG_DO_CLOSE;
         return -1;
 
@@ -1385,11 +1389,13 @@
 
 /*-------------------------------------------------------------------------*/
 Bool
-comm_socket_write (char *msg, size_t size, interactive_t *ip)
+comm_socket_write (char *msg, size_t size, interactive_t *ip, write_buffer_flag_t flags)
 
 /* Stand in for socket_write(): take the data to be written, compress and
  * encrypt them if needed and send them to <ip>. If no data can be send
- * right now append them to the buffer.
+ * right now append them to the buffer. Returns false if no more data
+ * is accepted at this time (messages are discarded or the connection
+ * was dropped).
  */
 
 {
@@ -1401,30 +1407,64 @@
         return MY_TRUE;
 
 #ifdef USE_MCCP
+    /* We cannot discard already compressed packets,
+     * because the zlib will generate a checksum
+     * over all bytes. So we have to check before
+     * compressing the message whether we can send 
+     * or put them in the write buffer.
+     *
+     * To provide a consistent behavior we do this
+     * also for uncompressed connections.
+     */
+#endif
+
+    if (!(flags & WB_NONDISCARDABLE) && ip->write_first)
+    {
+        p_int max_size;
+
+        max_size = ip->write_max_size;
+        if (max_size == -2)
+            max_size = write_buffer_max_size;
+
+        if (max_size >= 0 && ip->write_size >= (p_uint) max_size)
+        {
+            /* Buffer overflow. */
+            if (ip->msg_discarded != DM_NONE)
+                return MY_FALSE; /* Message will be or was sent. */
+
+            /* Notify the master about it. */
+            ip->msg_discarded = DM_SEND_INFO;
+            add_flush_entry(ip);
+
+            return MY_FALSE;
+        }
+    }
+
+#ifdef USE_MCCP
     if (ip->out_compress)
     {
         int status;
-        
+
         ip->out_compress->next_in = (unsigned char *) msg;
         ip->out_compress->avail_in = size;
-            
+
         ip->out_compress->next_out = ip->out_compress_buf;
         ip->out_compress->avail_out = COMPRESS_BUF_SIZE;
 
         status = deflate(ip->out_compress, Z_SYNC_FLUSH);
-          
+
         if (status != Z_OK)
         {
             fprintf(stderr, "%s comm: MCCP compression error: %d\n"
                           , time_stamp(), status);
             return MY_FALSE;
         }
-            
+
         /* ok.. perhaps i should take care that all data in message_buf
          * is compressed, but i guess there is no chance that 1024 byte
          * compressed won't fit into the 8192 byte buffer
          */
-        
+
         length = ip->out_compress->next_out - ip->out_compress_buf;
         buf = (char *) ip->out_compress_buf;
     }
@@ -1440,7 +1480,7 @@
     {
         /* Try writing to the socket first. */
         ssize_t n = comm_send_buf(buf, length, ip);
-        
+
         if (n == -1)
             return MY_FALSE;
         else if (n == length)
@@ -1448,45 +1488,34 @@
             /* We're done. */
             return MY_TRUE;
         }
-        else
+        else if (n > 0)
         {
             buf += n;
             length -= n;
         }
     }
-    
+
     /* We have to enqueue the message. */
-    b = xalloc(sizeof(struct write_buffer_s) + size - 1);
+
+    b = xalloc(sizeof(struct write_buffer_s) + length - 1);
     if (!b)
-        outofmem(sizeof(struct write_buffer_s) + size - 1, "comm_socket_write()");
+        outofmem(sizeof(struct write_buffer_s) + length - 1, "comm_socket_write()");
 
     b->length = length;
     b->pos = 0;
+    b->flags = flags;
     b->next = NULL;
     memcpy(b->buffer, buf, length);
 
-    /* Chain in the new buffer */
-    if(ip->write_first)
+     /* Chain in the new buffer */
+    if (ip->write_first)
         ip->write_last = ip->write_last->next = b;
     else
-        ip->write_first = ip->write_last = b;
-    ip->write_size += size;
-    
-    /* Make sure that the amount of data pending never exceeds
-     * the maximum.
-     */
-    while (write_buffer_max_size != 0
-        && ip->write_size >= (unsigned long)write_buffer_max_size)
-    {
-        struct write_buffer_s *tmp = ip->write_first;
-        ip->write_first = tmp->next;
-        ip->write_size -= tmp->length;
-        xfree(tmp);
+        ip->write_last = ip->write_first = b;
 
-        if (!ip->msg_discarded)
-            ip->msg_discarded = 1;
-    }
-    
+    ip->write_size += length;
+    ip->msg_discarded = DM_NONE;
+
     return MY_TRUE;
 } /* comm_socket_write() */
 
@@ -1498,35 +1527,21 @@
  */
 
 {
-    /* First, if a previous call had to discard the message, inform the user.
-     */
-    if (ip->msg_discarded)
-    {
-        ssize_t n;
-        char msg[] = "\n*** Text lost in transmission ***\n";
-        
-        n = comm_send_buf(msg, sizeof(msg) - ip->msg_discarded, ip);
-        
-        ip->msg_discarded += n;
-        if (ip->msg_discarded >= sizeof(msg))
-            ip->msg_discarded = 0;
-    }
-    
     while (ip->write_first != NULL)
     {
         struct write_buffer_s *buf;
         ssize_t n;
-        
+
         buf = ip->write_first;
         n = comm_send_buf(buf->buffer + buf->pos, buf->length - buf->pos, ip);
 
         if (n == -1)
             return;
-        
+
         buf->pos += n;
         if (buf->pos < buf->length)
             return;
-        
+
         ip->write_first = buf->next;
         ip->write_size -= buf->length;
         xfree(buf);
@@ -1534,6 +1549,63 @@
 } /* comm_write_pending() */
 
 /*-------------------------------------------------------------------------*/
+static void
+add_discarded_message (interactive_t *ip)
+
+/* Calls the H_MSG_DISCARDED driver hook and adds the
+ * message to the write buffer of <ip>. <ip> is removed
+ * from the list of dirty interactives if it's clean afterwards.
+ */
+{
+    string_t *discarded_msg;
+
+    if (driver_hook[H_MSG_DISCARDED].type == T_CLOSURE)
+    {
+        if (driver_hook[H_MSG_DISCARDED].x.closure_type == CLOSURE_LAMBDA)
+        {
+            free_object(driver_hook[H_MSG_DISCARDED].u.lambda->ob, "add_discarded_message");
+            driver_hook[H_MSG_DISCARDED].u.lambda->ob = ref_object(ip->ob, "add_discarded_message");
+        }
+
+        push_ref_valid_object(inter_sp, ip->ob, "add_discarded_message");
+
+        call_lambda(&driver_hook[H_MSG_DISCARDED], 1);
+
+        if (inter_sp->type == T_STRING)
+        {
+            /* The new discarded_msg. Adopt the reference. */
+            discarded_msg = inter_sp->u.str;
+
+            inter_sp->type = T_INVALID;
+            inter_sp--;
+        }
+        else
+            discarded_msg = NULL;
+    }
+    else if (driver_hook[H_MSG_DISCARDED].type == T_STRING)
+    {
+        discarded_msg = ref_mstring(driver_hook[H_MSG_DISCARDED].u.str);
+    }
+    else
+    {
+        discarded_msg = ref_mstring(STR_DISCARDED_MSG);
+    }
+
+    if (discarded_msg)
+    {
+        /* Append it to the write buffer. */
+        comm_socket_write(get_txt(discarded_msg), mstrsize(discarded_msg)
+                        , ip, WB_NONDISCARDABLE);
+        free_mstring(discarded_msg);
+    }
+
+    ip->msg_discarded = DM_INFO_WAS_SENT;
+
+    if (!ip->message_length)
+        remove_flush_entry(ip);
+}
+
+/*-------------------------------------------------------------------------*/
 void
 add_message (const char *fmt, ...)
 
@@ -1838,6 +1910,11 @@
     dest = &ip->message_buf[old_message_length];
     end  = &ip->message_buf[sizeof ip->message_buf];
 
+    /* If there's any recursive call, let it begin
+     * at the start.
+     */
+    ip->message_length = 0;
+    
     /* This loop advances source until it reaches the end.
      * Every character encountered is copied, translated or fed
      * into the telnet machine.
@@ -1925,10 +2002,10 @@
 
         /* Write .message_buf[] to the network. */
 
-        if (!comm_socket_write(ip->message_buf, (size_t)chunk, ip))
+        if (!comm_socket_write(ip->message_buf, (size_t)chunk, ip, 0))
         {
             if (old_message_length)
-                remove_flush_entry(ip);
+                clear_message_buf(ip);
             return;
         }
 
@@ -1946,18 +2023,11 @@
     {
         /* Buffer became 'dirty': add this interactive to the list.
          */
-        if ( NULL != (ip->next_player_for_flush = first_player_for_flush) )
-        {
-            O_GET_INTERACTIVE(first_player_for_flush)->
-              previous_player_for_flush =
-                command_giver;
-        }
-        ip->previous_player_for_flush = NULL;
-        first_player_for_flush = command_giver;
+        add_flush_entry(ip);
     }
     if ( !length && old_message_length ) /* buffer has become empty */
     {
-        remove_flush_entry(ip);
+        clear_message_buf(ip);
     }
 } /* add_message() */
 
@@ -1999,19 +2069,35 @@
 
 /*-------------------------------------------------------------------------*/
 static void
+add_flush_entry (interactive_t *ip)
+
+/* Add the given interactive <ip> to the list of 'dirty' interactives.
+ * The function is safe to call for interactives already in the list.
+ */
+
+{
+    if ( ip->previous_player_for_flush || first_player_for_flush == ip->ob)
+        return;
+
+    if ( NULL != (ip->next_player_for_flush = first_player_for_flush) )
+    {
+        O_GET_INTERACTIVE(first_player_for_flush)->
+          previous_player_for_flush = ip->ob;
+    }
+    ip->previous_player_for_flush = NULL;
+    first_player_for_flush = ip->ob;
+} /* add_flush_entry() */
+
+/*-------------------------------------------------------------------------*/
+static void
 remove_flush_entry (interactive_t *ip)
 
 /* Remove the given interactive <ip> from the list of 'dirty' interactives
  * and make sure it is really clean. The function is safe to call for
  * interactives not in the list.
- *
- * This function is called after an interactive sent all pending data (or
- * failing while doing so).
  */
 
 {
-    ip->message_length = 0;
-
     /* To make it safe for calling the function even for interactives
      * not in the flush list, we check that <ip> is either in the middle
      * or at the end of the flush list (one or both of the .previous
@@ -2050,19 +2136,43 @@
 
 {
     object_t *p, *np;
+    interactive_t *ip;
     object_t *save = command_giver;
 
     for ( p = first_player_for_flush; p != NULL; p = np)
     {
-        np = O_GET_INTERACTIVE(p)->next_player_for_flush;
+        ip = O_GET_INTERACTIVE(p);
+        np = ip->next_player_for_flush;
           /* add_message() will clobber (p)->next_player_for_flush! */
         command_giver = p;
         add_message(message_flush);
+
+        if(ip->msg_discarded == DM_SEND_INFO)
+            add_discarded_message(ip);
     }
     command_giver = save;
 } /* flush_all_player_mess() */
 
 /*-------------------------------------------------------------------------*/
+static void
+clear_message_buf (interactive_t *ip)
+
+/* Clear the buffer of the given interactive <ip> and remove it from
+ * the list of 'dirty' interactives if there is nothing else to do.
+ * The function is safe to call for interactives not in the list.
+ *
+ * This function is called after an interactive sent all pending data (or
+ * failing while doing so).
+ */
+
+{
+    ip->message_length = 0;
+
+    if (ip->msg_discarded != DM_SEND_INFO)
+        remove_flush_entry(ip);
+} /* clear_message_buf() */
+
+/*-------------------------------------------------------------------------*/
 Bool
 get_message (char *buff)
 
@@ -2191,7 +2301,7 @@
                         nfds = socket_number(ip->socket)+1;
                 }
 
-                if (ip->write_first != NULL || ip->msg_discarded)
+                if (ip->write_first != NULL)
                 {
                     /* There is something to write. */
                     FD_SET(ip->socket, &writefds);
@@ -3025,7 +3135,7 @@
                     {
                         comm_socket_write(ip->text + ip->chars_ready
                                         , (size_t)(length - ip->chars_ready)
-                                        , ip);
+                                        , ip, 0);
                         ip->chars_ready = length;
                     }
                 }
@@ -3532,7 +3642,6 @@
     new_interactive->input_to = NULL;
     put_number(&new_interactive->prompt, 0);
     new_interactive->modify_command = NULL;
-    new_interactive->msg_discarded = 0;
     new_interactive->closing = MY_FALSE;
     new_interactive->tn_enabled = MY_TRUE;
     new_interactive->do_close = 0;
@@ -3564,9 +3673,11 @@
     new_interactive->socket = new_socket;
     new_interactive->next_player_for_flush = NULL;
     new_interactive->previous_player_for_flush = NULL;
+    new_interactive->msg_discarded = DM_NONE;
 
     new_interactive->write_first = new_interactive->write_last = NULL;
     new_interactive->write_size = 0;
+    new_interactive->write_max_size = -2;
 
     /* Add the new interactive structure to the list of users */
 
@@ -5143,12 +5254,12 @@
                         {
                             comm_socket_write(&ip->text[ip->chars_ready]
                                             , (size_t)(to - &ip->text[ip->chars_ready])
-                                            , ip);
+                                            , ip, 0);
                             ip->chars_ready = to - ip->text;
                         }
                         if (to > first)
                         {
-                            comm_socket_write("\b \b", 3, ip);
+                            comm_socket_write("\b \b", 3, ip, 0);
                             to--;
                             ip->chars_ready--;
                         }
@@ -6909,7 +7020,7 @@
              * to the socket now.
              */
 
-            if (comm_socket_write(get_txt(msg), mstrsize(msg), ip))
+            if (comm_socket_write(get_txt(msg), mstrsize(msg), ip, 0))
                 wrote = mstrsize(msg);
 
         } /* if (type of write) */
@@ -8781,4 +8892,80 @@
     return sp;
 } /* f_net_connect() */
 
+/*-------------------------------------------------------------------------*/
+svalue_t *
+f_configure_interactive (svalue_t *sp)
+
+/* EFUN configure_interactive()
+ *
+ *   void configure_interactive(object ob, int what, mixed data)
+ *
+ * Sets the option <what> to the value <data> on the interactive <ob>
+ * or the default for all interactives if <ob> is 0.
+ *
+ * <what> == IC_MAX_WRITE_BUFFER_SIZE
+ *
+ * If the first argument <ob> is not this_object(), the privilege violation
+ * ("configure_interactive", this_object(), ob, what, data) occurs.
+ */
+
+{
+    object_t *ob;
+    interactive_t *ip;
+
+    if (sp[-2].type == T_OBJECT)
+    {
+        ob = sp[-2].u.ob;
+
+        if (!O_SET_INTERACTIVE(ip, ob))
+        {
+            errorf("Bad arg 1 to configure_interactive(): "
+                   "Object '%s' is not interactive.\n"
+                 , get_txt(ob->name)
+                 );
+            return sp; /* NOTREACHED */
+        }
+    }
+    else
+    {
+        ob = NULL;
+        ip = NULL;
+    }
+
+    if (ob != current_object
+     && !privilege_violation_n(STR_CONFIGURE_INTERACTIVE, ob, sp, 2))
+    {
+        sp = pop_n_elems(3, sp);
+        return sp;
+    }
+
+    switch(sp[-1].u.number)
+    {
+    default:
+        errorf("Illegal value %"PRIdPINT" for configure_interactive().\n", sp[-1].u.number);
+        return sp; /* NOTREACHED */
+
+    case IC_MAX_WRITE_BUFFER_SIZE:
+        {
+            int max;
+
+            if (sp->type != T_NUMBER)
+                efun_exp_arg_error(3, TF_NUMBER, sp->type, sp);
+
+            max = sp->u.number;
+            if (max < 0)
+                max = -1;
+
+            if (!ip)
+                write_buffer_max_size = max;
+            else
+                ip->write_max_size = max;
+            break;
+        }
+    }
+
+    sp = pop_n_elems(3, sp);
+    return sp;
+} /* f_configure_interactive() */
+
 /***************************************************************************/
Index: trunk.inputto/src/comm.h
===================================================================
--- trunk.inputto/src/comm.h	(Revision 2537)
+++ trunk.inputto/src/comm.h	(Arbeitskopie)
@@ -126,14 +126,32 @@
  * The instances are kept in a linked list from the interactive_t
  * structure.
  */
+enum write_buffer_flags
+{
+    WB_NONDISCARDABLE = 0x0001, /* This message must be sent. */
+};
+
+typedef uint32 write_buffer_flag_t;
+
 struct write_buffer_s
 {
     struct write_buffer_s *next;
     size_t length;
     size_t pos;
+    write_buffer_flag_t flags;
     char buffer[1 /* .length */ ];
 };
 
+/* Indicates discarded messages. */
+enum discarded_msg_states
+{
+    DM_NONE = 0,
+    DM_SEND_INFO,
+    DM_INFO_WAS_SENT,
+};
+
+typedef char discarded_msg_state_t;
+
 /* --- struct input_to_s: input_to() datastructure
  *
  * input-to structures describe a pending input_to() for a given
@@ -186,9 +204,9 @@
     CBool outgoing_conn;        /* TRUE if the connection was created by 
                                  * net_connect().
                                  */
-
-    short msg_discarded;        /* != 0 if an earlier msg had been discarded,
-                                   index into the message to be sent. */
+    discarded_msg_state_t msg_discarded;
+                                /* Indicates if an earlier message had
+                                 * been discarded. */
     short text_end;             /* first free char in buffer */
     short command_start;        /* used for charmode */
     short command_end;          /* where we are up to in player cmd buffer */
@@ -247,14 +265,20 @@
       /* The send buffer. */
 
 #ifdef USE_MCCP
-     unsigned char   compressing;     
-     z_stream      * out_compress;    
-     unsigned char * out_compress_buf;
-#endif   
+    unsigned char   compressing;
+    z_stream      * out_compress;
+    unsigned char * out_compress_buf;
+#endif
 
     struct write_buffer_s *write_first;  /* List of buffers to write */
     struct write_buffer_s *write_last;
-    unsigned long          write_size;
+    p_uint                 write_size;
+    p_int                  write_max_size; 
+      /* Maximum write_size.
+       *   0: No write buffer.
+       *  -1: Infinite write buffer.
+       *  -2: Use global variable write_buffer_max_size.
+       */
 
 #ifdef USE_TLS
     tls_session_t          tls_session;
@@ -356,7 +380,7 @@
 extern char *message_flush;
 extern char *domain_name;
 
-extern long write_buffer_max_size;
+extern p_int write_buffer_max_size;
 
 #ifdef COMM_STAT
 extern unsigned long add_message_calls;
@@ -372,7 +396,7 @@
 extern void initialize_host_ip_number(const char *, const char *);
 extern void  prepare_ipc(void);
 extern void  ipc_remove(void);
-extern Bool comm_socket_write (char *msg, size_t size, interactive_t *ip);
+extern Bool comm_socket_write (char *msg, size_t size, interactive_t *ip, uint32 flags);
 extern void  add_message VARPROT((const char *, ...), printf, 1, 2);
 extern void  flush_all_player_mess(void);
 extern Bool get_message(char *buff);
@@ -437,6 +461,7 @@
 extern svalue_t *f_set_max_commands (svalue_t *sp);
 extern svalue_t *f_enable_telnet (svalue_t *sp);
 extern svalue_t *f_net_connect (svalue_t *sp);
+extern svalue_t *f_configure_interactive(svalue_t *sp);
 
 extern void refresh_access_data(void (*add_entry)(struct sockaddr_in *, int, long*) );
 
Index: trunk.inputto/src/func_spec
===================================================================
--- trunk.inputto/src/func_spec	(Revision 2537)
+++ trunk.inputto/src/func_spec	(Arbeitskopie)
@@ -502,6 +502,7 @@
 object  blueprint(string|object default: F_THIS_OBJECT); /* PRELIMINARY */
 object  clone_object(string|object);
 object *clones(void|int|string|object, void|int);
+void    configure_interactive(object, int, mixed);
 void    destruct(null|object);
 int     exec(object, object);
 object  find_object(string);
Index: trunk.inputto/src/string_spec
===================================================================
--- trunk.inputto/src/string_spec	(Revision 2537)
+++ trunk.inputto/src/string_spec	(Arbeitskopie)
@@ -20,6 +20,7 @@
 DANGLING_V_CL     "dangling var closure"
 DEFAULT_PROMPT    "> "
 DESTRUCTED        "destructed"
+DISCARDED_MSG     "\n*** Text lost in transmission ***\n"
 EFUN              "efun"
 EFUN_CLOSURE      "<efun closure>"
 FATAL_ERROR       "Fatal Error"
@@ -70,6 +71,7 @@
 ATTACH_ERQ_DEMON   "attach_erq_demon"
 BIND_LAMBDA        "bind_lambda"
 CALL_OUT_INFO      "call_out_info"
+CONFIGURE_INTERACTIVE  "configure_interactive"
 SEND_ERQ           "erq"
 INPUT_TO           "input_to"
 SEND_UDP           "send_udp"
Index: trunk.inputto/src/interpret.c
===================================================================
--- trunk.inputto/src/interpret.c	(Revision 2537)
+++ trunk.inputto/src/interpret.c	(Arbeitskopie)
@@ -6652,6 +6652,79 @@
 } /* privilege_violation4() */
 
 /*-------------------------------------------------------------------------*/
+Bool
+privilege_violation_n ( string_t *what, object_t *whom, svalue_t *sp, int num_arg)
+
+/* Call the mudlib to check for a privilege violation:
+ *
+ *   master->privilege_violation(what, current_object, whom,
+ *                               sp[-num_arg+1], ...., sp)
+ *
+ * where <what> describes the type of the violation, and <whom> and the last
+ * <num_arg> values of the stack are data used in the violation. <sp> is 
+ * also the current stack setting. All strings are not counted.
+ *
+ * If the apply returns a positive number, the privilege is granted and
+ * the function returns TRUE.
+ * If the apply returns 0, the privilege is gently denied and the function
+ * returns FALSE.
+ * If the apply returns something else, or if the lfun doesn't exist,
+ * an error is raised.
+ *
+ * If the current_object is the master or simul_efun object, this function
+ * immediately returns TRUE.
+ *
+ * If the lfun doesn't exist, or returns anything else but a positive
+ * number, an error is raised.
+ *
+ * <inter_sp> is updated to <sp>, <inter_pc> is assumed to be correct.
+ */
+
+{
+    svalue_t *svp, *arg;
+    int num;
+
+    /* Trust these objects */
+    if (current_object == master_ob) return MY_TRUE;
+    if (current_object == simul_efun_object) return MY_TRUE;
+
+    /* Set up the lfun call */
+
+    arg = sp + 1 - num_arg;
+
+    push_ref_string(sp, what);
+    push_ref_valid_object(sp, current_object, "privilege_violation");
+    if (!whom)
+    {
+        push_number(sp, 0);
+    }
+    else
+    {
+        push_ref_object(sp, whom, "privilege_violation");
+    }
+
+    for (num = num_arg; num--; arg++)
+    {
+        sp++;
+        assign_svalue_no_free(sp,  arg);
+    }
+
+    inter_sp = sp;
+    svp = apply_master(STR_PRIVILEGE, 3 + num_arg);
+
+    /* Was it the proper lfun to call? */
+    if (!svp || svp->type != T_NUMBER || svp->u.number < 0)
+    {
+        inter_sp = sp - 3 - num_arg;
+        errorf("privilege violation : %s\n", get_txt(what));
+        /* TODO: Print full args and types */
+    }
+
+    /* Return the result */
+    return svp->u.number > 0;
+} /* privilege_violation_n() */
+
+/*-------------------------------------------------------------------------*/
 static Bool
 trace_test (int b)
 
Index: trunk.inputto/src/interpret.h
===================================================================
--- trunk.inputto/src/interpret.h	(Revision 2537)
+++ trunk.inputto/src/interpret.h	(Arbeitskopie)
@@ -181,6 +181,7 @@
 extern Bool privilege_violation(string_t *what, svalue_t *arg, svalue_t *sp);
 extern Bool privilege_violation2(string_t *what, svalue_t *arg, svalue_t *arg2, svalue_t *sp);
 extern Bool privilege_violation4(string_t *what, object_t *whom, string_t *how_str, int how_num, svalue_t *sp);
+extern Bool privilege_violation_n(string_t *what, object_t *whom, svalue_t *sp, int num_arg);
 
 extern svalue_t *sapply_int(string_t *fun, object_t *ob, int num_arg, Bool b_ign_prot, Bool b_use_default);
 #define sapply(f,o,n) sapply_int(f,o,n, MY_FALSE, MY_TRUE)
Index: trunk.inputto/CHANGELOG
===================================================================
--- trunk.inputto/CHANGELOG	(Revision 2538)
+++ trunk.inputto/CHANGELOG	(Arbeitskopie)
@@ -1,6 +1,13 @@
 This file lists all changes made to the game driver in all glory detail.
 See the file HISTORY for a user-oriented summary of all the changes.
 
+??-Apr-2009 (Gnomi)
+  - (comm.c, interpret.c, doc/) Made the maximum write buffer size
+    configurable per interactive via a new efun configure_interactive.
+    New optional driver hook H_MSG_DISCARDED to inform the master about
+    discarded messages and send a custom error message to the interactive.
+    Already compressed packages wont be discarded (Bug #297).
+
 07-Apr-2009 (Gnomi)
   - (pkg-tls.h) Corrected the definition of tls_check_certificate.
   - (pkg-gnutls.h, pkg-openssl.h) Forgot an include.
Index: trunk.inputto/mudlib/sys/configuration.h
===================================================================
--- trunk.inputto/mudlib/sys/configuration.h	(Revision 0)
+++ trunk.inputto/mudlib/sys/configuration.h	(Revision 0)
@@ -0,0 +1,11 @@
+#ifndef LPC_CONFIGURATION_H_
+#define LPC_ CONFIGURATION_H_
+
+/* Definition of argument values for configure_interactive().
+ */
+
+/* Possible options for configure_interactive().
+ */
+#define IC_MAX_WRITE_BUFFER_SIZE 0
+
+#endif /* LPC_CONFIGURATION_H_ */
Index: trunk.inputto/mudlib/sys/driver_hook.h
===================================================================
--- trunk.inputto/mudlib/sys/driver_hook.h	(Revision 2537)
+++ trunk.inputto/mudlib/sys/driver_hook.h	(Arbeitskopie)
@@ -28,8 +28,9 @@
 #define H_DEFAULT_PROMPT        21
 #define H_PRINT_PROMPT          22
 #define H_REGEXP_PACKAGE        23
+#define H_MSG_DISCARDED         24
 
-#define NUM_DRIVER_HOOKS        24  /* Number of hooks */
+#define NUM_DRIVER_HOOKS        25  /* Number of hooks */
 
 #endif /* LPC_DRIVER_HOOK_ */
 
