+int
+file_name_absolute_p (filename)
+ const unsigned char *filename;
+{
+ /* Sanity check, it shouldn't happen. */
+ if (! filename) return FALSE;
+
+ /* /xxx is always an absolute path. */
+ if (filename[0] == '/') return TRUE;
+
+ /* Empty filenames (which shouldn't happen) are relative. */
+ if (filename[0] == '\0') return FALSE;
+
+#ifdef WINDOWSNT
+ /* X:\xxx is always absolute. */
+ if (isalpha (filename[0])
+ && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/'))
+ return TRUE;
+
+ /* Both \xxx and \\xxx\yyy are absolute. */
+ if (filename[0] == '\\') return TRUE;
+
+ /*
+ FIXME: There's a corner case not dealt with, "x:y", where:
+
+ 1) x is a valid drive designation (usually a letter in the A-Z range)
+ and y is a path, relative to the current directory on drive x. This
+ is absolute, *after* fixing the y part to include the current
+ directory in x.
+
+ 2) x is a relative file name, and y is an NTFS stream name. This is a
+ correct relative path, but it is very unusual.
+
+ The trouble is that first case items are also valid examples of the
+ second case, i.e., "c:test" can be understood as drive:path or as
+ file:stream.
+
+ The "right" fix would involve checking whether
+ - the current drive/partition is NTFS,
+ - x is a valid (and accesible) drive designator,
+ - x:y already exists as a file:stream in the current directory,
+ - y already exists on the current directory of drive x,
+ - the auspices are favorable,
+ and then taking an "informed decision" based on the above.
+
+ Whatever the result, Emacs currently does a very bad job of dealing
+ with NTFS file:streams: it cannot visit them, and the only way to
+ create one is by setting `buffer-file-name' to point to it (either
+ manually or with emacsclient). So perhaps resorting to 1) and ignoring
+ 2) for now is the right thing to do.
+
+ Anyway, something to decide After the Release.
+ */
+#endif
+
+ return FALSE;
+}
+
+#ifdef WINDOWSNT
+/* Wrapper to make WSACleanup a cdecl, as required by atexit. */
+void
+__cdecl close_winsock ()
+{
+ WSACleanup ();
+}
+
+/* Initialize the WinSock2 library. */
+void
+initialize_sockets ()
+{
+ WSADATA wsaData;
+
+ if (WSAStartup (MAKEWORD (2, 0), &wsaData))
+ {
+ message (TRUE, "%s: error initializing WinSock2", progname);
+ exit (EXIT_FAILURE);
+ }
+
+ atexit (close_winsock);
+}
+#endif /* WINDOWSNT */
+\f
+/*
+ * Read the information needed to set up a TCP comm channel with
+ * the Emacs server: host, port, pid and authentication string.
+ */
+int
+get_server_config (server, authentication)
+ struct sockaddr_in *server;
+ char *authentication;
+{
+ char dotted[32];
+ char *port;
+ char *pid;
+ FILE *config = NULL;
+
+ if (file_name_absolute_p (server_file))
+ config = fopen (server_file, "rb");
+ else
+ {
+ char *home = getenv ("HOME");
+
+ if (home)
+ {
+ char *path = alloca (32 + strlen (home) + strlen (server_file));
+ sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
+ config = fopen (path, "rb");
+ }
+#ifdef WINDOWSNT
+ if (!config && (home = getenv ("APPDATA")))
+ {
+ char *path = alloca (32 + strlen (home) + strlen (server_file));
+ sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
+ config = fopen (path, "rb");
+ }
+#endif
+ }
+
+ if (! config)
+ return FALSE;
+
+ if (fgets (dotted, sizeof dotted, config)
+ && (port = strchr (dotted, ':'))
+ && (pid = strchr (port, ' ')))
+ {
+ *port++ = '\0';
+ *pid++ = '\0';
+ }
+ else
+ {
+ message (TRUE, "%s: invalid configuration info", progname);
+ exit (EXIT_FAILURE);
+ }
+
+ server->sin_family = AF_INET;
+ server->sin_addr.s_addr = inet_addr (dotted);
+ server->sin_port = htons (atoi (port));
+
+ if (! fread (authentication, AUTH_KEY_LENGTH, 1, config))
+ {
+ message (TRUE, "%s: cannot read authentication info", progname);
+ exit (EXIT_FAILURE);
+ }
+
+ fclose (config);
+
+ emacs_pid = atoi (pid);
+
+ return TRUE;
+}
+
+HSOCKET
+set_tcp_socket ()
+{
+ HSOCKET s;
+ struct sockaddr_in server;
+ struct linger l_arg = {1, 1};
+ char auth_string[AUTH_KEY_LENGTH + 1];
+
+ if (! get_server_config (&server, auth_string))
+ return INVALID_SOCKET;
+
+ if (server.sin_addr.s_addr != inet_addr ("127.0.0.1"))
+ message (FALSE, "%s: connected to remote socket at %s\n",
+ progname, inet_ntoa (server.sin_addr));
+
+ /*
+ * Open up an AF_INET socket
+ */
+ if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ {
+ message (TRUE, "%s: socket: %s\n", progname, strerror (errno));
+ return INVALID_SOCKET;
+ }
+
+ /*
+ * Set up the socket
+ */
+ if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
+ {
+ message (TRUE, "%s: connect: %s\n", progname, strerror (errno));
+ return INVALID_SOCKET;
+ }
+
+ setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
+
+ /*
+ * Send the authentication
+ */
+ auth_string[AUTH_KEY_LENGTH] = '\0';
+
+ SEND_STRING ("-auth ");
+ SEND_STRING (auth_string);
+ SEND_STRING ("\n");
+
+ return s;
+}
+
+#if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
+
+/* Three possibilities:
+ 2 - can't be `stat'ed (sets errno)
+ 1 - isn't owned by us
+ 0 - success: none of the above */
+
+static int
+socket_status (socket_name)
+ char *socket_name;
+{
+ struct stat statbfr;
+
+ if (stat (socket_name, &statbfr) == -1)
+ return 2;
+
+ if (statbfr.st_uid != geteuid ())
+ return 1;
+
+ return 0;
+}
+
+HSOCKET
+set_local_socket ()
+{
+ HSOCKET s;
+ struct sockaddr_un server;
+
+ /*