These patches are written by Dark@Igor for Dutch Mountains, in December 1995.
They are freely redistributable.


diff -u src.orig/comm.c src.ident/comm.c
--- src.orig/comm.c	Fri Dec 15 16:23:26 1995
+++ src.ident/comm.c	Wed Jan  3 22:41:48 1996
@@ -272,6 +272,8 @@
 DESCRIPTOR_DATA *   descriptor_free;    /* Free list for descriptors    */
 DESCRIPTOR_DATA *   descriptor_list;    /* All open descriptors         */
 DESCRIPTOR_DATA *   d_next;             /* Next descriptor in loop      */
+IDENT_DATA *        ident_free;         /* Free list for ident structs  */
+IDENT_DATA *        ident_list;         /* Ident query structs in use   */
 FILE *              fpReserve;          /* Reserved filehandle          */
 FILE *              fpReserveBug;       /* Reserved filehandle for bugs */
 bool                god;                /* All new chars are gods!      */
@@ -302,6 +304,9 @@
 void    new_descriptor          args( ( int control ) );
 bool    read_from_descriptor    args( ( DESCRIPTOR_DATA *d ) );
 bool    write_to_descriptor     args( ( int desc, char *txt, int length ) );
+void    free_ident              args( ( IDENT_DATA *id ) );
+IDENT_DATA * new_ident          args( ( DESCRIPTOR_DATA *desc ) );
+void    parse_ident             args( ( IDENT_DATA *id ) );
 #endif
 
 
@@ -440,7 +445,7 @@
     int x = 1;
     int fd;
 
-    if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
+    if ( ( fd = socket( PF_INET, SOCK_STREAM, 0 ) ) < 0 )
     {
         perror( "Init_socket: socket" );
         exit( 1 );
@@ -761,6 +766,7 @@
         fd_set out_set;
         fd_set exc_set;
         DESCRIPTOR_DATA *d;
+	IDENT_DATA *id, *id_next;
         int maxdesc, tmp;
 
 #if defined(MALLOC_DEBUG)
@@ -780,9 +786,17 @@
         {
             maxdesc = UMAX( maxdesc, d->descriptor );
             FD_SET( d->descriptor, &in_set  );
-            FD_SET( d->descriptor, &out_set );
             FD_SET( d->descriptor, &exc_set );
         }
+	for ( id = ident_list; id != NULL; id = id->next )
+        {
+            maxdesc = UMAX( maxdesc, id->descriptor );
+            if (id->connected)
+                 FD_SET( id->descriptor, &in_set );
+	    else
+                 FD_SET( id->descriptor, &out_set );
+	}
+   
 
         if ( select( maxdesc+1, &in_set, &out_set, &exc_set, &null_time ) < 0 )
         {
@@ -807,7 +821,6 @@
             if ( FD_ISSET( d->descriptor, &exc_set ) )
             {
                 FD_CLR( d->descriptor, &in_set  );
-                FD_CLR( d->descriptor, &out_set );
                 if ( d->character )
                     save_char_obj( d->character, TRUE );
                 d->outtop       = 0;
@@ -825,6 +838,73 @@
 
         }
 
+	/*
+         * Process ident queries.
+         */
+        for ( id = ident_list; id != NULL; id = id_next )
+	{
+            long size;
+	    char * p;
+	    struct sockaddr sa;
+	    int salen = sizeof(sa);
+
+	    id_next = id->next;
+	    if ( !id->connected && FD_ISSET( id->descriptor, &out_set ) )
+	    {
+	        if ( getpeername( id->descriptor, &sa, &salen ) < 0 )
+		    free_ident ( id );
+		else
+		{
+		    char querybuf[20];
+		    sprintf( querybuf, "%d,%d\r\n",
+			    id->remoteport, id->localport );
+		    write( id->descriptor, querybuf, strlen(querybuf) );
+		    id->connected = TRUE;
+		    id->timeout = current_time + IDENT_TIMEOUT;
+		}
+	    }
+            else if ( FD_ISSET( id->descriptor, &in_set ) )
+	    {
+                size = read( id->descriptor, id->reply_text + id->reply_pos,
+			     IDENT_BUFFER - id->reply_pos );
+		if (size < 0)
+		    free_ident( id );
+		else
+		{
+		    bool complete = FALSE;
+
+		    id->reply_pos += size;
+		    if ( id->reply_pos == IDENT_BUFFER )
+		    {
+		        complete = TRUE;
+			id->reply_text[IDENT_BUFFER-2] = '\r';
+			id->reply_text[IDENT_BUFFER-1] = '\n';
+		    }
+		    else
+		    {
+		        for ( p = id->reply_text + id->reply_pos - 2;
+			      p >= id->reply_text; p-- )
+			{
+			    if ( *p == '\r' && *(p+1) == '\n' )
+			    {
+			        complete = TRUE;
+				break;
+			    }
+			}
+		    }
+		    if ( complete )
+		    {
+		        parse_ident( id );
+			free_ident( id );
+		    }
+		}
+	    }
+	    else if ( current_time > id->timeout )
+	    {
+	        free_ident( id );
+	    }
+	}
+
         /*
          * Process input.
          */
@@ -841,7 +921,6 @@
                     d->original->timer = 0;
                 if ( !read_from_descriptor( d ) )
                 {
-                    FD_CLR( d->descriptor, &out_set );
                     if ( d->character != NULL )
                         save_char_obj( d->character, TRUE );
                     d->outtop     = 0;
@@ -1007,6 +1086,8 @@
 
     free_string( d->host );
     free_mem( d->outbuf, d->outsize );
+    if ( d->ident )
+        free_ident ( d->ident );
     for ( iHistory = 0; iHistory < MAX_HISTORY; iHistory++ )
         free_string( GET_HISTORY(d, iHistory) );
     d->next = descriptor_free;
@@ -1038,6 +1119,185 @@
 /* END */
 
 #if defined(unix)
+void free_ident( IDENT_DATA *id )
+{
+    if ( id->descriptor > 0 )
+        close( id->descriptor );
+    id->desc->ident = NULL;
+
+    if ( ident_list == id )
+        ident_list = ident_list->next;
+    else
+    {
+        IDENT_DATA *idp;
+
+        for ( idp = ident_list; idp; idp = idp->next )
+	{
+	    if ( idp->next == id )
+	    {
+	        idp->next = id->next;
+		break;
+	    }
+	}
+    }
+
+    id->next = ident_free;
+    ident_free = id;
+}
+
+IDENT_DATA *new_ident( DESCRIPTOR_DATA *desc )
+{
+    IDENT_DATA *id;
+    static IDENT_DATA id_zero;
+    sh_int d;
+    int localport, remoteport;
+    struct sockaddr_in sin;
+    size_t len = sizeof(sin);
+
+    if ( getsockname( desc->descriptor, (struct sockaddr *) &sin, &len ) < 0 
+	|| len < sizeof(sin) )
+        return NULL;
+    localport = ntohs( sin.sin_port );
+
+    /* This will also leave sin.sin_addr useful for connect() below. */
+    if ( getpeername( desc->descriptor, (struct sockaddr *) &sin, &len ) < 0 
+	|| len < sizeof(sin) )
+        return NULL;
+    remoteport = ntohs( sin.sin_port );
+
+    if ( (d = socket( PF_INET, SOCK_STREAM, 0 )) < 0 )
+    {
+        perror("Ident socket: socket");
+	return NULL;
+    }
+
+#if !defined(FNDELAY)
+#define FNDELAY O_NDELAY
+#endif
+
+    if ( fcntl ( d, F_SETFL, FNDELAY ) == -1 )
+    {
+        perror( "Ident socket: fcntl: FNDELAY" );
+	close( d );
+        return NULL;
+    }
+
+    /* sin.sin_addr was set by getpeername() above. */
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(113);
+    if ( connect( d, (struct sockaddr *) &sin, len ) < 0 
+	&& errno != EINPROGRESS && errno != EAGAIN )
+    {
+	close ( d );
+	return NULL;
+    }
+
+    if ( ident_free == NULL )
+    {
+        id = alloc_perm( sizeof(*id) );
+    }
+    else
+    {
+        id = ident_free;
+	ident_free = ident_free->next;
+    }
+
+    *id = id_zero;
+    id->desc = desc;
+    id->descriptor = d;
+    id->connected = FALSE;
+    id->timeout = current_time + IDENT_TIMEOUT;
+    id->remoteport = remoteport;
+    id->localport = localport;
+    id->next = ident_list;
+    ident_list = id;
+
+    return id;
+}
+
+void parse_ident( IDENT_DATA *id )
+{
+    char *p;
+    int remoteport, localport;
+    char replytype[40];
+    char foo;
+    int tmp;
+    char *ident;
+    char *hostid;
+    static char tokenchars[] =
+      "abcdefghijklmnopqrstuvwxyz"
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "-, .!@#$%^&*()_=+.,<>/?\"'~`{}[];";
+
+    if ( !(p = strstr( id->reply_text, "\r\n")) )
+        return;
+    *p = 0;
+
+    /*
+     * The extra argument "foo" is used because sscanf doesn't count
+     * a bare %n. 
+     */
+    if ( sscanf( id->reply_text, "%d , %d : %39s : %n%c",
+		&remoteport, &localport, replytype, &tmp, &foo ) < 4 
+	|| remoteport != id->remoteport
+	|| localport != id->localport )
+        return;
+
+    p = id->reply_text + tmp;
+
+    if ( strcmp( replytype, "ERROR" ) == 0 )
+    {
+	tmp = strspn( p, tokenchars );
+	if ( p[tmp] )
+	    return;
+
+	if ( p[0] == 'X' )
+	    ident = p + 1;
+	else if ( strcmp( p, "NO-USER" ) == 0 )
+	    ident = "<nobody>";
+	else if ( strcmp( p, "HIDDEN-USER" ) == 0 )
+	    ident = "<hidden>";
+	else
+	    ident = "<error>";
+    }
+    else if ( strcmp( replytype, "USERID" ) == 0 )
+    {
+	/* Skip straight to the userid field */
+	p = strchr( p, ':' );
+	if ( p == NULL )
+	    return;
+	p++;
+	/*
+         * The RFC says not to ignore leading whitespace here.
+         * Unfortunately, some servers get it wrong because of
+         * the example on line 109 of RFC1413.
+         */
+	ident = p + strspn( p, " \t" );
+	for ( p = ident; *p; p++ )
+	{
+	    if ( !isprint( *p ) )
+	        *p = '?';
+	}
+    }
+    else return;
+
+    if ( id->desc->host )
+    {
+        hostid = alloc_mem( strlen( ident ) + strlen( id->desc->host ) + 2 );
+	sprintf( hostid, "%s@%s", ident, id->desc->host );
+	free_string( id->desc->host );
+    }
+    else
+    {
+        hostid = alloc_mem( strlen( ident ) + 6 );
+	sprintf( hostid, "%s@NULL", ident );
+    }
+    id->desc->host = hostid;
+}
+#endif
+    
+
+#if defined(unix)
 void new_descriptor( int control )
 {
     static DESCRIPTOR_DATA d_zero;
@@ -1065,12 +1325,6 @@
 #define FNDELAY O_NDELAY
 #endif
 
-    if ( fcntl( control, F_SETFL, FNDELAY ) == -1 )
-    {
-        perror( "New_descriptor: fcntl: FNDELAY" );
-        return;
-    }
-
     if ( fcntl( desc, F_SETFL, FNDELAY ) == -1 )
     {
         perror( "New_descriptor: fcntl: FNDELAY" );
@@ -1134,6 +1388,8 @@
 
         dnew->host = str_dup( from ? from->h_name : buf );
     }
+
+    dnew->ident         = new_ident( dnew );
 
     /*
      * Swiftest: I added the following to ban sites.  I don't
diff -u src.orig/merc.h src.ident/merc.h
--- src.orig/merc.h	Tue Dec 12 17:12:05 1995
+++ src.ident/merc.h	Thu Dec 28 02:30:36 1995
@@ -82,6 +82,7 @@
 typedef struct  extra_descr_data        EXTRA_DESCR_DATA;
 typedef struct  trap_data               TRAP_DATA;
 typedef struct  help_data               HELP_DATA;
+typedef struct  ident_data              IDENT_DATA;
 typedef struct  mob_index_data          MOB_INDEX_DATA;
 typedef struct  name_ban_data           NAME_BAN_DATA;
 typedef struct  note_data               NOTE_DATA;
@@ -259,6 +260,7 @@
     DESCRIPTOR_DATA *   snoop_by;
     CHAR_DATA *         character;
     CHAR_DATA *         original;
+    IDENT_DATA *        ident;
     char *              host;
     sh_int              descriptor;
     sh_int              connected;
@@ -277,7 +279,24 @@
     int                 showstr_len;
 };
 
+#define IDENT_TIMEOUT   120       /* 2 minutes */
+#define IDENT_BUFFER    1024
 
+/* 
+ * Data for Ident (RFC1413) queries.
+ */
+struct  ident_data
+{
+    IDENT_DATA *        next;
+    DESCRIPTOR_DATA *   desc;
+    sh_int              descriptor;
+    bool                connected;
+    time_t              timeout;
+    sh_int              localport;
+    sh_int              remoteport;
+    sh_int              reply_pos;
+    char                reply_text      [IDENT_BUFFER];
+};
 
 /*
  * Attribute bonus structures.