? Makefile
? cvs
? options.h
? options.h-SAVED
? cvsbug
? todo
? .pure
Index: commit.c
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/commit.c,v
retrieving revision 1.1.1.2
diff -b -u -r1.1.1.2 commit.c
--- commit.c	2000/01/05 16:35:46	1.1.1.2
+++ commit.c	2000/03/20 14:31:46
@@ -292,6 +292,11 @@
 
     data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
     data->type = status;
+    data->repository = xstrdup (finfo->repository);
+    data->hostname = xstrdup (hostname);
+    data->wd = (char *) xmalloc (strlen (CurDir) + sizeof ('/') + strlen (finfo->update_dir) + 1);
+    sprintf (data->wd, "%s%c%s", CurDir, finfo->update_dir != NULL  &&  *finfo->update_dir != '\0'   ?   '/'   :   '\0', finfo->update_dir);
+    data->editor = NULL;
     data->tag = xstrdup (vers->tag);
     data->rev_old = data->rev_new = NULL;
 
@@ -557,6 +562,30 @@
 	    }
 	}
 
+        /* send local file info to server */
+        if (supported_request ("FileInfo"))
+        {
+            char **v = NULL;
+
+            for(v = find_args.argv; v < find_args.argv + find_args.argc; ++v)
+            {
+                Node *p = NULL;
+
+                p = findnode (find_args.ulist, *v);
+                if(p != NULL)
+                {
+                    send_to_server ("FileInfo ", 0);
+                    send_to_server (*v, 0);
+                    send_to_server ("\012", 1);
+                    send_to_server (((struct logfile_info *) p->data)->hostname, 0);
+                    send_to_server ("\t", 1);
+                    send_to_server (((struct logfile_info *) p->data)->wd, 0);
+                    send_to_server ("\t", 1);
+                    send_to_server ("\012", 1);
+                }
+            }
+        }
+
 	if (local)
 	    send_arg("-l");
 	if (force_ci)
@@ -586,6 +615,36 @@
 
 	send_to_server ("ci\012", 0);
 	err = get_responses_and_close ();
+        if (err == 0  &&  !supported_request ("FileInfo"))
+        {
+            /* FIXME: Noel Yap (yap_noel@yahoo.com) 2000 Feb 28
+               This block is to support old servers.  It should be
+               removed once it's deemed that all servers support the
+               "FileInfo" request.  IMHO, it should be safe to remove
+               by 2002 Feb 28 (ie in two years).
+            */
+            char **v = NULL;
+
+            for(v = find_args.argv; v < find_args.argv + find_args.argc; ++v)
+            {
+                Node *p = NULL;
+
+                p = findnode (find_args.ulist, *v);
+                if(p != NULL)
+                {
+                    char *repository = NULL;
+                    char *user = NULL;
+
+                    user = getcaller ();
+                    repository = ((struct logfile_info *) p->data)->repository;
+
+                    fileattr_startdir (repository);
+                    notify_do ('C', *v, user, user, NULL, "", repository);
+                    fileattr_free ();
+                }
+            }
+        }
+
 	if (err != 0 && use_editor && saved_message != NULL)
 	{
 	    /* If there was an error, don't nuke the user's carefully
@@ -828,9 +887,13 @@
 	    error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname);
 	    freevers_ts (&vers);
 	    return (1);
+
 	case T_MODIFIED:
 	case T_ADDED:
 	case T_REMOVED:
+        {
+            struct logfile_info *client_fileinfo = NULL;
+
 	    /*
 	     * some quick sanity checks; if no numeric -r option specified:
 	     *	- can't have a sticky date
@@ -1004,9 +1067,81 @@
 	    li = ((struct logfile_info *)
 		  xmalloc (sizeof (struct logfile_info)));
 	    li->type = status;
+
+            client_fileinfo = server_getfileinfo (finfo->fullname);
+            if (client_fileinfo == NULL)
+            {
+                li->repository = NULL;
+                li->hostname = NULL;
+                li->wd = NULL;
+                li->editor = NULL;
+            }
+            else
+            {
+                char *editors = NULL;
+
+                li->repository = xstrdup (client_fileinfo->repository);
+                li->hostname = xstrdup (client_fileinfo->hostname);
+                li->wd = xstrdup (client_fileinfo->wd);
+
+                editors = fileattr_get0 (finfo->file, "_editors");
+                if (editors == NULL)
+                {
+                    li->editor = NULL;
+                }
+                else
+                {
+                    char *editor = NULL;
+                    char *user = NULL;
+                    char *p = NULL;
+                    char *p0 = NULL;
+
+                    user = getcaller ();
+
+                    editor = (char *) xmalloc (strlen (user) + sizeof ('@') + strlen (li->hostname) + sizeof (':') + strlen (li->wd) + 1);
+                    sprintf (editor, "%s@%s:%s", user, li->hostname, li->wd);
+
+                    p = editors;
+                    p0 = p;
+                    while (*p != '\0')
+                    {
+                        p = strchr (p, '>');
+                        if (p == NULL)
+                        {
+                            break;
+                        }
+                        *p = '\0';
+                        if (strcmp (editor, p0) == 0)
+                        {
+                            break;
+                        }
+                        p = strchr (p, ',');
+                        if (p == NULL)
+                        {
+                            break;
+                        }
+                        ++p;
+                        p0 = p;
+                    }
+
+                    if (strcmp (editor, p0) == 0)
+                    {
+                        li->editor = editor;
+                    }
+                    else
+                    {
+                        li->editor = NULL;
+                        free (editor);
+                    }
+
+                    free (editors);
+                }
+            }
+
 	    li->tag = xstrdup (vers->tag);
 	    li->rev_old = xstrdup (vers->vn_rcs);
 	    li->rev_new = NULL;
+
 	    p->data = (char *) li;
 	    (void) addnode (ulist, p);
 
@@ -1017,12 +1152,20 @@
 	    ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
 	    ci->status = status;
 	    if (vers->tag)
+        {
 		if (isdigit ((unsigned char) *vers->tag))
+        {
 		    ci->rev = xstrdup (vers->tag);
+        }
 		else
+        {
 		    ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
+        }
+        }
 	    else
+        {
 		ci->rev = (char *) NULL;
+        }
 	    ci->tag = xstrdup (vers->tag);
 	    ci->options = xstrdup(vers->options);
 	    p->data = (char *) ci;
@@ -1064,6 +1207,8 @@
 #endif
 
 	    break;
+        }
+
 	case T_UNKNOWN:
 	    error (0, 0, "nothing known about `%s'", finfo->fullname);
 	    freevers_ts (&vers);
@@ -1364,8 +1509,25 @@
 
     /* Clearly this is right for T_MODIFIED.  I haven't thought so much
        about T_ADDED or T_REMOVED.  */
-    notify_do ('C', finfo->file, getcaller (), NULL, NULL, finfo->repository);
+    {
+        char *editor = NULL;
+        Node *p = NULL;
+
+        p = findnode (ulist, finfo->file);
+        if (p != NULL)
+        {
+            struct logfile_info *li = NULL;
 
+            li = (struct logfile_info *) p->data;
+            if (li != NULL)
+            {
+                editor = li->editor;
+            }
+        }
+
+        notify_do ('C', finfo->file, getcaller (), editor ? editor : getcaller (), NULL, "", finfo->repository);
+    }
+
 out:
     if (err != 0)
     {
@@ -1388,14 +1550,16 @@
 
 	if (ci->status != T_REMOVED)
 	{
+
 	    p = findnode (ulist, finfo->file);
 	    if (p)
 	    {
+                struct logfile_info *li = NULL;
 		Vers_TS *vers;
-		struct logfile_info *li;
 
-		(void) classify_file_internal (finfo, &vers);
 		li = (struct logfile_info *) p->data;
+
+		(void) classify_file_internal (finfo, &vers);
 		li->rev_new = xstrdup (vers->vn_rcs);
 		freevers_ts (&vers);
 	    }
@@ -2295,6 +2459,14 @@
     struct logfile_info *li;
 
     li = (struct logfile_info *) p->data;
+    if (li->repository)
+        free (li->repository);
+    if (li->hostname)
+        free (li->hostname);
+    if (li->wd)
+        free (li->wd);
+    if (li->editor)
+        free (li->editor);
     if (li->tag)
 	free (li->tag);
     if (li->rev_old)
Index: cvs.h
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/cvs.h,v
retrieving revision 1.1.1.2
diff -b -u -r1.1.1.2 cvs.h
--- cvs.h	2000/01/03 20:49:12	1.1.1.2
+++ cvs.h	2000/03/20 14:31:46
@@ -791,6 +791,10 @@
 struct logfile_info
 {
   enum classify_type type;
+  char *repository;
+  char *hostname;
+  char *wd;     /* working directory */
+  char *editor;
   char *tag;
   char *rev_old;		/* rev number before a commit/modify,
 				   NULL for add or import */
Index: edit.c
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/edit.c,v
retrieving revision 1.10
diff -b -u -r1.10 edit.c
--- edit.c	2000/03/13 21:44:37	1.10
+++ edit.c	2000/03/20 14:31:46
@@ -157,6 +157,7 @@
     struct file_info *finfo;
 {
     int notif_type;
+    char *editor = NULL;
     char *filename;
     char *val;
     char *cp;
@@ -201,12 +202,16 @@
 	    continue;
 	*cp++ = '\0';
 	watches = cp;
+	cp = strchr (cp, '\t');
+	if (cp == NULL)
+	    continue;
+        editor = cp;
 	cp = strchr (cp, '\n');
 	if (cp == NULL)
 	    continue;
 	*cp = '\0';
 
-	notify_do (notif_type, filename, getcaller (), val, watches,
+	notify_do (notif_type, filename, getcaller (), editor, val, watches,
 		   finfo->repository);
     }
     free (line);
@@ -215,7 +220,6 @@
 	error (0, errno, "cannot read %s", CVSADM_NOTIFY);
     if (fclose (fp) < 0)
 	error (0, errno, "cannot close %s", CVSADM_NOTIFY);
-
     if ( CVS_UNLINK (CVSADM_NOTIFY) < 0)
 	error (0, errno, "cannot remove %s", CVSADM_NOTIFY);
 
@@ -514,41 +518,29 @@
     return err;
 }
 
-static int edit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
+static void notify_put PROTO ((struct file_info *finfo, char *editor, char action, int tedit, int tunedit, int tcommit));
 
-static int
-edit_fileproc (callerdat, finfo)
-    void *callerdat;
+static void
+notify_put (finfo, editor, action, tedit, tunedit, tcommit)
     struct file_info *finfo;
+    char *editor;
+    char action;
+    int tedit;
+    int tunedit;
+    int tcommit;
 {
     FILE *fp;
     time_t now;
     char *ascnow;
-    char *basefilename;
-
-    if (noexec)
-	return 0;
+    char *wd = NULL;
 
-    /* This is a somewhat screwy way to check for this, because it
-       doesn't help errors other than the nonexistence of the file
-       (e.g. permissions problems).  It might be better to rearrange
-       the code so that CVSADM_NOTIFY gets written only after the
-       various actions succeed (but what if only some of them
-       succeed).  */
-    if (!isfile (finfo->file))
-    {
-	error (0, 0, "no such file %s; ignored", finfo->fullname);
-	return 0;
-    }
     fp = open_file (CVSADM_NOTIFY, "a");
 
     (void) time (&now);
     ascnow = asctime (gmtime (&now));
     ascnow[24] = '\0';
-
-    {
-        char *wd = (char *) malloc (strlen (CurDir) + strlen ("/") + strlen (finfo->update_dir) + 1);
 
+    wd = (char *) malloc (strlen (CurDir) + strlen ("/") + strlen (finfo->update_dir) + 1);
         strcpy(wd, CurDir);
 
         if(finfo->update_dir != NULL  &&  *finfo->update_dir != '\0')
@@ -557,17 +549,24 @@
             strcat(wd, finfo->update_dir);
         }
 
-        fprintf (fp, "E%s\t%s GMT\t%s\t%s\t", finfo->file, ascnow, hostname, wd);
+    fprintf (fp, "%c%s\t%s GMT\t%s\t%s\t", action, finfo->file, ascnow, hostname, wd);
 
-        free(wd);
-    }
-
-    if (setting_tedit)
+    if (tedit)
 	fprintf (fp, "E");
-    if (setting_tunedit)
+    if (tunedit)
 	fprintf (fp, "U");
-    if (setting_tcommit)
+    if (tcommit)
 	fprintf (fp, "C");
+
+    if (editor == NULL  ||  strcmp (editor, "") == 0)
+    {
+        fprintf (fp, "\t%s@%s:%s\t", getcaller (), hostname, wd);
+    }
+    else
+    {
+        fprintf (fp, "\t%s\t", editor);
+    }
+
     fprintf (fp, "\n");
 
     if (fclose (fp) < 0)
@@ -579,6 +578,36 @@
 		   CVSADM_NOTIFY);
     }
 
+    if (wd != NULL)
+        free (wd);
+}
+
+static int edit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
+
+static int
+edit_fileproc (callerdat, finfo)
+    void *callerdat;
+    struct file_info *finfo;
+{
+    char *basefilename;
+
+    if (noexec)
+	return 0;
+
+    /* This is a somewhat screwy way to check for this, because it
+       doesn't help errors other than the nonexistence of the file
+       (e.g. permissions problems).  It might be better to rearrange
+       the code so that CVSADM_NOTIFY gets written only after the
+       various actions succeed (but what if only some of them
+       succeed).  */
+    if (!isfile (finfo->file))
+    {
+	error (0, 0, "no such file %s; ignored", finfo->fullname);
+	return 0;
+    }
+
+    notify_put (finfo, NULL, 'E', setting_tedit, setting_tunedit, setting_tcommit);
+
     xchmod (finfo->file, 1);
 
     /* Now stash the file away in CVSADM so that unedit can revert even if
@@ -756,23 +785,8 @@
         rename_file (basefilename, finfo->file);
         free (basefilename);
     }
-
-    fp = open_file (CVSADM_NOTIFY, "a");
-
-    (void) time (&now);
-    ascnow = asctime (gmtime (&now));
-    ascnow[24] = '\0';
-    fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", finfo->file,
-	     ascnow, hostname, CurDir);
 
-    if (fclose (fp) < 0)
-    {
-	if (finfo->update_dir[0] == '\0')
-	    error (0, errno, "cannot close %s", CVSADM_NOTIFY);
-	else
-	    error (0, errno, "cannot close %s/%s", finfo->update_dir,
-		   CVSADM_NOTIFY);
-    }
+    notify_put (finfo, unedit_editor, 'U', 0, 0, 0);
 
     /* Now update the revision number in CVS/Entries from CVS/Baserev.
        The basic idea here is that we are reverting to the revision
@@ -826,9 +840,10 @@
 	}
 	free (baserev);
 	base_deregister (finfo);
-    }
 
     xchmod (finfo->file, 0);
+    }
+
     return 0;
 }
 
@@ -922,7 +937,9 @@
     }
 
     edlist = fileattr_get0 (filename, "_editors");
+
     newlist = fileattr_modify (edlist, editor, val, '>', ',');
+
     /* If the attributes is unchanged, don't rewrite the attribute file.  */
     if (!((edlist == NULL && newlist == NULL)
 	  || (edlist != NULL
@@ -941,7 +958,7 @@
     /* User who is running the command which causes notification.  */
     char *notifier;
     /* User to be notified.  */
-    char *notifyee;
+    char *watcher;
     /* Editor affected */
     char *editor;
     /* File.  */
@@ -968,9 +985,9 @@
     struct notify_proc_args *args = notify_args;
 
     srepos = Short_Repository (repository);
-    prog = xmalloc (strlen (filter) + strlen (args->notifyee) + 1);
+    prog = xmalloc (strlen (filter) + strlen (args->watcher) + 1);
     /* Copy FILTER to PROG, replacing the first occurrence of %s with
-       the notifyee.  We only allocated enough memory for one %s, and I doubt
+       the watcher.  We only allocated enough memory for one %s, and I doubt
        there is a need for more.  */
     for (p = filter, q = prog; *p != '\0'; ++p)
     {
@@ -978,7 +995,7 @@
 	{
 	    if (p[1] == 's')
 	    {
-		strcpy (q, args->notifyee);
+		strcpy (q, args->watcher);
 		q += strlen (q);
 		strcpy (q, p + 2);
 		q += strlen (q);
@@ -1013,7 +1030,7 @@
     fprintf (pipefp, "Triggered %s watch on %s\n", args->type, repository);
     fprintf (pipefp, "By %s\n", args->notifier);
 
-    if(args->editor != NULL  &&  strcmp(args->editor, "") != 0)
+    if (args->editor != NULL  &&  strcmp (args->editor, "") != 0)
     {
         fprintf (pipefp, "For %s\n", args->editor);
     }
@@ -1030,16 +1047,18 @@
    an error so that server.c can know whether to report Notified back
    to the client.  */
 void
-notify_do (type, filename, who, val, watches, repository)
+notify_do (type, filename, who, editor, val, watches, repository)
     int type;
     char *filename;
     char *who;
+    char *editor;
     char *val;
     char *watches;
     char *repository;
 {
     static struct addremove_args blank;
     struct addremove_args args;
+    int edit_count = 0;
     char *watchers;
     char *p;
     char *endp;
@@ -1055,11 +1074,11 @@
 		error (0, 0, "invalid character in editor value");
 		return;
 	    }
-	    editor_set (filename, who, val);
+	    editor_set (filename, editor, val);
 	    break;
 	case 'U':
 	case 'C':
-	    editor_set (filename, who, NULL);
+	    editor_set (filename, editor, NULL);
 	    break;
 	default:
 	    return;
@@ -1079,15 +1098,52 @@
 	    break;
 	nextp = strchr (p, ',');
 
+error(0, 0, __FILE__ "::%d: who = %s, %s", __LINE__, who, p);
 	if ((size_t)(endp - p) == strlen (who) && strncmp (who, p, endp - p) == 0)
+	{
+            char *e = NULL;
+            char *editors = NULL;
+
+            editors = fileattr_get0 (filename, "_editors");
+            e = editors;
+            while (e != NULL)
+            {
+                char *e_at = NULL;
+                char *e_end = NULL;
+                char *e_gt = NULL;
+
+                e_at = strchr (e, '@');
+                e_gt = strchr (e, '>');
+
+                e_end = (e_at != NULL)   ?   e_at   :   e_gt;
+
+error(0, 0, __FILE__ "::%d: editor = %s, who = %s", __LINE__, e, who);
+                if ((size_t) (e_end - e) == strlen (who)  &&
+                    strncmp (who, e, e_end - e) == 0)
+                {
+                    ++edit_count;
+error(0, 0, __FILE__ "::%d: edit_count = %d", __LINE__, edit_count);
+                }
+
+                e = strchr (e, ',');
+                if (e != NULL)
 	{
-	    /* Don't notify user of their own changes.  Would perhaps
-	       be better to check whether it is the same working
-	       directory, not the same user, but that is hairy.  */
+                    ++e;
+                }
+            }
+
+            if (edit_count <= 1)
+            {
 	    p = nextp == NULL ? nextp : nextp + 1;
 	    continue;
 	}
 
+            if (editors != NULL)
+            {
+                free (editors);
+            }
+	}
+
 	/* Now we point q at a string which looks like
 	   "edit+unedit+commit,"... and walk down it.  */
 	q = endp + 1;
@@ -1154,7 +1210,7 @@
 	    char *line = NULL;
 	    size_t line_len = 0;
 
-	    args.notifyee = NULL;
+	    args.watcher = NULL;
 	    usersname = xmalloc (strlen (CVSroot_directory)
 				 + sizeof CVSROOTADM
 				 + sizeof CVSROOTADM_USERS
@@ -1175,14 +1231,14 @@
 			&& line[len] == ':')
 		    {
 			char *cp;
-			args.notifyee = xstrdup (line + len + 1);
+			args.watcher = xstrdup (line + len + 1);
 
                         /* There may or may not be more
                            colon-separated fields added to this in the
                            future; in any case, we ignore them right
                            now, and if there are none we make sure to
                            chop off the final newline, if any. */
-			cp = strpbrk (args.notifyee, ":\n");
+			cp = strpbrk (args.watcher, ":\n");
 
 			if (cp != NULL)
 			    *cp = '\0';
@@ -1198,21 +1254,21 @@
 	    if (line != NULL)
 		free (line);
 
-	    if (args.notifyee == NULL)
+	    if (args.watcher == NULL)
 	    {
-		args.notifyee = xmalloc (endp - p + 1);
-		strncpy (args.notifyee, p, endp - p);
-		args.notifyee[endp - p] = '\0';
+		args.watcher = xmalloc (endp - p + 1);
+		strncpy (args.watcher, p, endp - p);
+		args.watcher[endp - p] = '\0';
 	    }
 
 	    notify_args = &args;
 	    args.type = notif;
 	    args.notifier = who;
-        args.editor = unedit_editor;
+        args.editor = editor;
 	    args.file = filename;
 
 	    (void) Parse_Info (CVSROOTADM_NOTIFY, repository, notify_proc, 1);
-	    free (args.notifyee);
+	    free (args.watcher);
 	}
 
 	p = nextp;
@@ -1220,6 +1276,9 @@
     if (watchers != NULL)
 	free (watchers);
 
+    if (edit_count <= 1)
+    {
+error(0, 0, __FILE__ "::%d: modifying watch on %s", __LINE__, filename);
     switch (type)
     {
 	case 'E':
@@ -1244,6 +1303,7 @@
 	    args.remove_temp = 1;
 	    watch_modify_watchers (filename, &args);
 	    break;
+        }
     }
 }
 
Index: edit.h
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/edit.h,v
retrieving revision 1.2
diff -b -u -r1.2 edit.h
--- edit.h	2000/01/24 19:29:23	1.2
+++ edit.h	2000/03/20 14:31:46
@@ -26,6 +26,7 @@
    _editors, and WATCHES is zero or more of E,U,C, in that order, to specify
    what kinds of temporary watches to set.  */
 extern void notify_do PROTO ((int type, char *filename, char *who,
+                              char *editor,
 			      char *val, char *watches, char *repository));
 
 /* Take note of the fact that FILE is up to date (this munges CVS/Base;
Index: rcs.c
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/rcs.c,v
retrieving revision 1.1.1.2
diff -b -u -r1.1.1.2 rcs.c
--- rcs.c	2000/01/05 16:35:46	1.1.1.2
+++ rcs.c	2000/03/20 14:31:46
@@ -6122,8 +6122,8 @@
    ourselves.
 
    If REV is not null and is locked by someone else, break their
-   lock and notify them.  It is an open issue whether RCS_unlock
-   queries the user about whether or not to break the lock. */
+   lock.  It is an open issue whether RCS_unlock queries the user
+   about whether or not to break the lock. */
 
 int
 RCS_unlock (rcs, rev, unlock_quiet)
@@ -6200,21 +6200,8 @@
 	free (xrev);
 	return 0;
     }
+error(0, 0, __FILE__ "::%d: would've notified here", __LINE__);
 
-    if (! STREQ (lock->data, user))
-    {
-        /* If the revision is locked by someone else, notify
-	   them.  Note that this shouldn't ever happen if RCS_unlock
-	   is called with a NULL revision, since that means "whatever
-	   revision is currently locked by the caller." */
-	char *repos, *workfile;
-	repos = xstrdup (rcs->path);
-	workfile = strrchr (repos, '/');
-	*workfile++ = '\0';
-	notify_do ('C', workfile, user, NULL, NULL, repos);
-	free (repos);
-    }
-
     delnode (lock);
     if (!unlock_quiet)
     {
Index: server.c
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/server.c,v
retrieving revision 1.1.1.2
diff -b -u -r1.1.1.2 server.c
--- server.c	1999/11/22 22:17:00	1.1.1.2
+++ server.c	2000/03/20 14:31:47
@@ -1407,7 +1407,7 @@
 	    goto out;
 	}
 
-	if (gunzip_and_write (fd, file, filebuf, size))
+	if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size))
 	{
 	    if (alloc_pending (80))
 		sprintf (pending_error_text,
@@ -1883,6 +1883,122 @@
     }
 }
 
+List *fileinfo_list = NULL;
+
+static void serve_fileinfo PROTO ((char *));
+
+static void
+serve_fileinfo (arg)
+     char *arg;
+{
+    char *data = NULL;
+    int status;
+
+    status = buf_read_line (buf_from_net, &data, (int *) NULL);
+    if (status != 0)
+    {
+	if (status == -2)
+        {
+	    pending_error = ENOMEM;
+        }
+	else
+	{
+	    pending_error_text = malloc (80 + strlen (arg));
+	    if (pending_error_text == NULL)
+            {
+		pending_error = ENOMEM;
+            }
+	    else
+	    {
+		if (status == -1)
+                {
+		    sprintf (
+                        pending_error_text,
+                        "E end of file reading notification for %s",
+                        arg);
+                }
+		else
+		{
+		    sprintf (
+                        pending_error_text,
+                        "E error reading notification for %s",
+                        arg);
+		    pending_error = status;
+		}
+	    }
+	}
+    }
+    else
+    {
+        char *cp = NULL;
+        char *cp0 = NULL;
+        struct logfile_info *li;
+        Node *p = NULL;
+
+        if (fileinfo_list == NULL)
+        {
+            fileinfo_list = getlist ();
+        }
+
+        p = getnode ();
+        p->key = xstrdup (arg);
+        p->type = UPDATE;
+        p->delproc = update_delproc;
+
+        li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
+        li->type = T_UNKNOWN;
+
+        cp = data;
+
+        cp0 = cp;
+        cp = strchr (cp0, '\t');
+        if (cp == NULL)
+        {
+            goto error;
+        }
+        *cp++ = '\0';
+
+        li->hostname = xstrdup (cp0);
+
+        cp0 = cp;
+        cp = strchr (cp0, '\t');
+        if (cp != NULL)
+        {
+            *cp = '\0';
+        }
+
+        li->wd = xstrdup (cp0);
+        li->editor = NULL;
+
+        li->tag = NULL;
+        li->rev_old = NULL;
+        li->rev_new = NULL;
+
+        p->data = (char *) li;
+        (void) addnode (fileinfo_list, p);
+    }
+
+error:
+    return;
+}
+
+struct logfile_info *
+server_getfileinfo (filename)
+    char *filename;
+{
+    Node *p = NULL;
+
+    p = findnode (fileinfo_list, filename);
+    if (p != NULL)
+    {
+        return (struct logfile_info *) p->data;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
 struct notify_note {
     /* Directory in which this notification happens.  malloc'd*/
     char *dir;
@@ -1897,6 +2013,7 @@
     /* time+host+dir */
     char *val;
     char *watches;
+    char *editor;
 
     struct notify_note *next;
 };
@@ -1996,11 +2113,41 @@
 	/* If there is another tab, ignore everything after it,
 	   for future expansion.  */
 	cp = strchr (cp, '\t');
+	if (cp == NULL)
+        {
+            /* FIXME: Noel Yap (yap_noel@yahoo.com) 2000 Feb 28
+               This block is to support old clients.  It should be
+               removed once it's deemed that all clients send the
+               editor field.  IMHO, it should be safe to remove
+               by 2002 Feb 28 (ie in two years).
+            */
+            new->editor = getcaller();  /* to support old clients */
+        }
+        else
+	{
+	    *cp++ = '\0';
+            new->editor = cp;
+
+            /* If there is another tab, ignore everything after it,
+               for future expansion.  */
+            cp = strchr (cp, '\t');
 	if (cp != NULL)
 	{
 	    *cp = '\0';
 	}
 
+            /* lob off extra val fields */
+            {
+                char *cp = NULL;
+
+                cp = strchr (new->val, '+');
+                if (cp != NULL)
+                {
+                    *cp = '\0';
+                }
+            }
+	}
+
 	new->next = NULL;
 
 	if (last_node == NULL)
@@ -2044,6 +2191,7 @@
 	fileattr_startdir (repos);
 
 	notify_do (*notify_list->type, notify_list->filename, getcaller(),
+                   notify_list->editor,
 		   notify_list->val, notify_list->watches, repos);
 
 	buf_output0 (buf_to_net, "Notified ");
@@ -4017,7 +4165,7 @@
 
 	if (file != NULL)
 	{
-	    buf_output (protocol, file, file_used);
+	    buf_output (protocol, (const char *) file, file_used);
 	    free (file);
 	    file = NULL;
 	}
@@ -4567,6 +4715,7 @@
   REQ_LINE("UseUnchanged", serve_enable_unchanged, RQ_ENABLEME | RQ_ROOTLESS),
 
   REQ_LINE("Unchanged", serve_unchanged, RQ_ESSENTIAL),
+  REQ_LINE("FileInfo", serve_fileinfo, 0),
   REQ_LINE("Notify", serve_notify, 0),
   REQ_LINE("Questionable", serve_questionable, 0),
   REQ_LINE("Case", serve_case, 0),
Index: server.h
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/server.h,v
retrieving revision 1.1.1.1
diff -b -u -r1.1.1.1 server.h
--- server.h	1999/12/27 13:46:33	1.1.1.1
+++ server.h	2000/03/20 14:31:47
@@ -119,6 +119,8 @@
    to the client.  */
 extern char *server_dir;
 
+extern struct logfile_info *server_getfileinfo PROTO((char *));
+
 enum progs {PROG_CHECKIN, PROG_UPDATE};
 extern void server_prog PROTO((char *, char *, enum progs));
 extern void server_cleanup PROTO((int sig));
Index: version.c
===================================================================
RCS file: /home/cvs-adm/.cvsroot/cvs/src/version.c,v
retrieving revision 1.8
diff -b -u -r1.8 version.c
--- version.c	2000/03/13 21:44:38	1.8
+++ version.c	2000/03/20 14:31:47
@@ -12,7 +12,7 @@
 
 #include "cvs.h"
 
-char *version_string = "\nConcurrent Versions System (CVS) 1.10.8.5";
+char *version_string = "\nConcurrent Versions System (CVS) 1.10.8.6";
 
 #ifdef CLIENT_SUPPORT
 #ifdef SERVER_SUPPORT
