unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Back to emacsclient/server
@ 2006-10-23 14:14 Juanma Barranquero
  2006-10-23 14:54 ` Jason Rumney
                   ` (4 more replies)
  0 siblings, 5 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-23 14:14 UTC (permalink / raw)


I'm finally getting the time to try implementing TCP sockets (and so
Win32 support) for emacsclient.c/server.el. I must confess that the
talk about reimplementing gnuserv in Java has made me shiver quite a
lot (no offense intended, I just happen to not like Java *at all*).

I've reviewed all comments exchanged about this issue in past threads
(or at least all the ones I could find). There were some decisions
that got more-or-less universal agreement, some that were
controversial, and a few that were left undecided (mostly because we
were throwing ideas back and forth).

So let's recapitulate:

  - The server (i.e., server.el) should:
   - Have an option to choose among Unix (if available) or TCP sockets.
   - Have an option to specify the host address, defaulting to 127.0.0.1.
   - Choose the port at random (to allow multiple server in the same computer).
   - Write the hostname address, port and random authentication string
in a file.
   - Close any connection which doesn't start with "-auth
AUTHENTICATION-STRING".

  - The client (emasclient.c) should:
  - Interpret --server-name as an Unix socket (if available), and, if
that does fail, as a path to the server file.
  - Default --server-name to an environment variable
(EMACS_SERVER_NAME, for example), if -server-name is missing.
  - Send "-auth AUTHENTICATION-STRING" as the first command in any connection.

There was some discussion about allowing/not allowing remote
connections (defaulting to "not allow"). If they're allowed, either a
option in server.el would activate remote connection support, or
perhaps just the fact that server-host != 127.0.0.1 should suffice. I
favor this, because connections on Unix sockets will never be remote,
so a new option seems redundant. But I don't care much.

Stefan wanted that --server-name=foo, if not valid as a Unix socket,
would try to open server file ~/.emacs.server/foo to get the address,
port and authentication string. I'm not so sure. I don't see why root
in one session cannot try to connect with Emacs in another user's
session, so --server-name is gonna need to be a (relative or absolute)
path, and not a name depending of the current user. Am I missing
something?

The last time around, about 80% of the above was implemented; I'll
have to rework it because I got rid of the Unix socket support (which
must stay), but it shouldn't be too difficult.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 14:14 Back to emacsclient/server Juanma Barranquero
@ 2006-10-23 14:54 ` Jason Rumney
  2006-10-23 19:48   ` Stefan Monnier
  2006-10-23 16:00 ` Ted Zlatanov
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 54+ messages in thread
From: Jason Rumney @ 2006-10-23 14:54 UTC (permalink / raw)
  Cc: Emacs Devel

Juanma Barranquero wrote:
>   - Choose the port at random (to allow multiple server in the same 
> computer).
>   - Write the hostname address, port and random authentication string
> in a file.

These files will need cleaning up, including in the case where Emacs 
crashes. So it is probably easier to use a fixed port, or a fixed 
filename and only allow one instance of the server for an initial 
implementation, since I don't think there is going to be time to 
implement all of this before the release.

OTOH, perhaps it is already too late to consider this for release, and 
Windows users will have to continue to use gnuclient until Emacs 23 is 
released. In that case, you might as well deal with the tricky issues now.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 14:14 Back to emacsclient/server Juanma Barranquero
  2006-10-23 14:54 ` Jason Rumney
@ 2006-10-23 16:00 ` Ted Zlatanov
  2006-10-23 20:09   ` Eli Zaretskii
                     ` (2 more replies)
  2006-10-23 16:26 ` Jan D.
                   ` (2 subsequent siblings)
  4 siblings, 3 replies; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-23 16:00 UTC (permalink / raw)


This may seem like an offbeat suggestion, but I think Emacs could
behave like a SSH daemon for emacsclient/server interactions..

Consider the advantages:
(assuming OpenSSH would be the starting point)

- it's not difficult to do, and the protocol is fairly standard
- authentication and automation can be handled with SSH keys
- the client can be a plain SSH client
- encryption is free (and can be disabled, but on by default)
- Emacs doesn't have to be updated if the SSL libraries change
- there will be less "standalone" code in Emacs and perhaps less code overall
- debugging, using, and understanding the mechanism would be easier

I realize this is not a trivial project, but I also think it would
benefit Emacs greatly.

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 14:14 Back to emacsclient/server Juanma Barranquero
  2006-10-23 14:54 ` Jason Rumney
  2006-10-23 16:00 ` Ted Zlatanov
@ 2006-10-23 16:26 ` Jan D.
  2006-10-23 19:52   ` Stefan Monnier
  2006-10-23 19:46 ` Stefan Monnier
       [not found] ` <f7ccd24b0610271000p16dda672mb146860725d47e00@mail.gmail.com>
  4 siblings, 1 reply; 54+ messages in thread
From: Jan D. @ 2006-10-23 16:26 UTC (permalink / raw)
  Cc: Emacs Devel

Juanma Barranquero skrev:
> I'm finally getting the time to try implementing TCP sockets (and so
> Win32 support) for emacsclient.c/server.el. I must confess that the
> talk about reimplementing gnuserv in Java has made me shiver quite a
> lot (no offense intended, I just happen to not like Java *at all*).
> 
> I've reviewed all comments exchanged about this issue in past threads
> (or at least all the ones I could find). There were some decisions
> that got more-or-less universal agreement, some that were
> controversial, and a few that were left undecided (mostly because we
> were throwing ideas back and forth).
> 
> So let's recapitulate:
> 
>  - The server (i.e., server.el) should:
>   - Have an option to choose among Unix (if available) or TCP sockets.
>   - Have an option to specify the host address, defaulting to 127.0.0.1.
>   - Choose the port at random (to allow multiple server in the same
> computer).

Isn't it better to start with a well known number and if that is busy, just
add 1 until you get a free one?  That way emacslcient can have a default which
just works if there is just one emacs server running.

Then you can write the files as ~/emacs.d/server-(port - start port).
I.e. ~/emacs.d/server-0, ~/emacs.d/server-1, ...

Emacsclient by default then reads ~/emacs.d/server-0.  emacsclient --server 1
would be ~/emacs.d/server-1.

	Jan D.


	Jan D.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 14:14 Back to emacsclient/server Juanma Barranquero
                   ` (2 preceding siblings ...)
  2006-10-23 16:26 ` Jan D.
@ 2006-10-23 19:46 ` Stefan Monnier
  2006-10-23 21:54   ` Juanma Barranquero
       [not found] ` <f7ccd24b0610271000p16dda672mb146860725d47e00@mail.gmail.com>
  4 siblings, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-23 19:46 UTC (permalink / raw)
  Cc: Emacs Devel

>  - The server (i.e., server.el) should:
>   - Have an option to choose among Unix (if available) or TCP sockets.
>   - Have an option to specify the host address, defaulting to 127.0.0.1.
>   - Choose the port at random (to allow multiple server in the same computer).
>   - Write the hostname address, port and random authentication string
> in a file.
>   - Close any connection which doesn't start with "-auth
> AUTHENTICATION-STRING".

The -auth thingy is not need for unix-sockets.

>  - The client (emasclient.c) should:
>  - Interpret --server-name as an Unix socket (if available), and, if
> that does fail, as a path to the server file.
>  - Default --server-name to an environment variable
> (EMACS_SERVER_NAME, for example), if -server-name is missing.
>  - Send "-auth AUTHENTICATION-STRING" as the first command in any connection.

Sounds OK.  I'm not quite sure how "-server-name" and
"--socket-name" relate.  Maybe we should merge them?

> There was some discussion about allowing/not allowing remote connections
> (defaulting to "not allow"). If they're allowed, either a option in
> server.el would activate remote connection support, or perhaps just the
> fact that server-host != 127.0.0.1 should suffice.  I favor this, because
> connections on Unix sockets will never be remote, so a new option seems
> redundant. But I don't care much.

Agreed.

> Stefan wanted that --server-name=foo, if not valid as a Unix socket,
> would try to open server file ~/.emacs.server/foo to get the address,
> port and authentication string. I'm not so sure. I don't see why root
> in one session cannot try to connect with Emacs in another user's
> session, so --server-name is gonna need to be a (relative or absolute)
> path, and not a name depending of the current user. Am I missing
> something?

I don't understand.  Currently, "--socket-name=FOO" tries /tmp/esrv-UID/FOO
(and if not specified it assumes FOO to be "server"), and that doesn't
prevent root from saying "--socket-name=/tmp/esrv-OTHERUID/bar".
Why shouldn't this work just as well for --server-name?
BTW, it shouldn't be ~/.emacs.server but ~/.emacs.d/servers or something
like that.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 14:54 ` Jason Rumney
@ 2006-10-23 19:48   ` Stefan Monnier
  2006-10-23 21:17     ` Jason Rumney
  0 siblings, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-23 19:48 UTC (permalink / raw)
  Cc: Juanma Barranquero, Emacs Devel

>> - Choose the port at random (to allow multiple server in the same computer).
>> - Write the hostname address, port and random authentication string
>>   in a file.

> These files will need cleaning up, including in the case where Emacs crashes.

Why?
The .Xauthority file isn't cleaned up at all ever and it's not a big problem.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 16:26 ` Jan D.
@ 2006-10-23 19:52   ` Stefan Monnier
  2006-10-23 20:35     ` Jan Djärv
  0 siblings, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-23 19:52 UTC (permalink / raw)
  Cc: Juanma Barranquero, Emacs Devel

> Isn't it better to start with a well known number and if that is busy, just
> add 1 until you get a free one?  That way emacslcient can have a default which
> just works if there is just one emacs server running.

Huh?  Why would you need that.
It seems just as simple to
- bind to any port.
- get the port that was used.
- write it into ~/.emacs.d/server/server ("server" is the default
  `server-name') along with the host name and the auth key.

emacsclient looks in ~/.emacs.d/server/server (where "server" is the
default but can be changed with --server-name) to find all the relevant info.

> Emacsclient by default then reads ~/emacs.d/server-0.  emacsclient --server 1
> would be ~/emacs.d/server-1.

That sounds messy.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 16:00 ` Ted Zlatanov
@ 2006-10-23 20:09   ` Eli Zaretskii
  2006-10-24  0:02     ` Ted Zlatanov
  2006-10-23 21:47   ` Juanma Barranquero
  2006-10-24  2:01   ` Stefan Monnier
  2 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2006-10-23 20:09 UTC (permalink / raw)
  Cc: emacs-devel

> From: Ted Zlatanov <tzz@lifelogs.com>
> Date: Mon, 23 Oct 2006 17:00:24 +0100
> 
> This may seem like an offbeat suggestion, but I think Emacs could
> behave like a SSH daemon for emacsclient/server interactions..

That sounds like a huge overkill to me.  Let's not forget that
emacsclient is first and foremost for _local_ connections, and these
hardly justify SSH.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 19:52   ` Stefan Monnier
@ 2006-10-23 20:35     ` Jan Djärv
  2006-10-23 21:20       ` Jason Rumney
  2006-10-23 21:57       ` Juanma Barranquero
  0 siblings, 2 replies; 54+ messages in thread
From: Jan Djärv @ 2006-10-23 20:35 UTC (permalink / raw)
  Cc: Juanma Barranquero, Emacs Devel



Stefan Monnier skrev:
>> Isn't it better to start with a well known number and if that is busy, just
>> add 1 until you get a free one?  That way emacslcient can have a default which
>> just works if there is just one emacs server running.
> 
> Huh?  Why would you need that.
> It seems just as simple to
> - bind to any port.

And if that fails, what do you do?  You still have to handle bind failures.


> - get the port that was used.
> - write it into ~/.emacs.d/server/server ("server" is the default
>   `server-name') along with the host name and the auth key.
> 
> emacsclient looks in ~/.emacs.d/server/server (where "server" is the
> default but can be changed with --server-name) to find all the relevant info.
> 
>> Emacsclient by default then reads ~/emacs.d/server-0.  emacsclient --server 1
>> would be ~/emacs.d/server-1.
> 
> That sounds messy.

If you think so, I don't see much difference.

	Jan D.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 19:48   ` Stefan Monnier
@ 2006-10-23 21:17     ` Jason Rumney
  2006-10-23 22:02       ` Andreas Schwab
  0 siblings, 1 reply; 54+ messages in thread
From: Jason Rumney @ 2006-10-23 21:17 UTC (permalink / raw)
  Cc: Juanma Barranquero, Emacs Devel

Stefan Monnier wrote:
> Why?
> The .Xauthority file isn't cleaned up at all ever and it's not a big problem.
>   
How does X decide that it is OK to overwrite .Xauthority rather than 
creating .Xauthority-2 or whatever numbering it uses for multiple servers?

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 20:35     ` Jan Djärv
@ 2006-10-23 21:20       ` Jason Rumney
  2006-10-23 21:59         ` Jason Rumney
  2006-10-24  5:06         ` Jan Djärv
  2006-10-23 21:57       ` Juanma Barranquero
  1 sibling, 2 replies; 54+ messages in thread
From: Jason Rumney @ 2006-10-23 21:20 UTC (permalink / raw)
  Cc: Juanma Barranquero, Stefan Monnier, Emacs Devel

Jan Djärv wrote:
>
> Stefan Monnier skrev:
>>
>> Huh?  Why would you need that.
>> It seems just as simple to
>> - bind to any port.
>
> And if that fails, what do you do?  You still have to handle bind 
> failures.
If that fails, you give up, since it will only ever fail if there are no 
ports free, or no network interfaces to bind to.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 16:00 ` Ted Zlatanov
  2006-10-23 20:09   ` Eli Zaretskii
@ 2006-10-23 21:47   ` Juanma Barranquero
  2006-10-23 23:50     ` Ted Zlatanov
  2006-10-24  2:01   ` Stefan Monnier
  2 siblings, 1 reply; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-23 21:47 UTC (permalink / raw)


On 10/23/06, Ted Zlatanov <tzz@lifelogs.com> wrote:

> This may seem like an offbeat suggestion, but I think Emacs could
> behave like a SSH daemon for emacsclient/server interactions..

Well, I'm not so sure, and in any case that is out of my league (so I
won't be the one implementing it), and probably too complex to do
before the pretest.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 19:46 ` Stefan Monnier
@ 2006-10-23 21:54   ` Juanma Barranquero
  2006-10-24  2:04     ` Stefan Monnier
  0 siblings, 1 reply; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-23 21:54 UTC (permalink / raw)


On 10/23/06, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> The -auth thingy is not need for unix-sockets.

Yes, of course. From "Choose the port at random" on I was talking of
the TCP socket case.

> Sounds OK.  I'm not quite sure how "-server-name" and
> "--socket-name" relate.  Maybe we should merge them?

This is what you said a year ago:

"Maybe you're right, and .emacs.servers should be a directory.
So if you run emacsclient --server-name foo it would look for
/tmp/emacs<uid>/foo for a unix socket and if that fails it'd look for
~/.emacs.servers/foo for a file holding the host/port/auth info."

so I think yes, you were thinking of merging both.

> I don't understand.  Currently, "--socket-name=FOO" tries /tmp/esrv-UID/FOO
> (and if not specified it assumes FOO to be "server"), and that doesn't
> prevent root from saying "--socket-name=/tmp/esrv-OTHERUID/bar".
> Why shouldn't this work just as well for --server-name?

OK, but then, --server-name=foo is taken to be (in TCP sockets) either
~/.emacs.d/server/foo, or an absolute path. That wasn't explicit in
the earlier thread and I understood "foo" to be always taken as a
server name.

> BTW, it shouldn't be ~/.emacs.server but ~/.emacs.d/servers or something
> like that.

Agreed.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 20:35     ` Jan Djärv
  2006-10-23 21:20       ` Jason Rumney
@ 2006-10-23 21:57       ` Juanma Barranquero
  2006-10-24  5:08         ` Jan Djärv
  1 sibling, 1 reply; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-23 21:57 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 400 bytes --]

On 10/23/06, Jan Djärv <jan.h.d@swipnet.se> wrote:

> And if that fails, what do you do?  You still have to handle bind failures.

Throw an error, show a message to the user and refuse to start the
server. Why should it be different than trying to write a file and not
being able to?

> If you think so, I don't see much difference.

I'm with Stefan on this one.

-- 
                    /L/e/k/t/u

[-- Attachment #2: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 21:20       ` Jason Rumney
@ 2006-10-23 21:59         ` Jason Rumney
  2006-10-24  5:06         ` Jan Djärv
  1 sibling, 0 replies; 54+ messages in thread
From: Jason Rumney @ 2006-10-23 21:59 UTC (permalink / raw)
  Cc: Juanma Barranquero, Jan Djärv, Stefan Monnier, Emacs Devel

Jason Rumney wrote:
> Jan Djärv wrote:
>>
>> Stefan Monnier skrev:
>>>
>>> Huh?  Why would you need that.
>>> It seems just as simple to
>>> - bind to any port.
>>
>> And if that fails, what do you do?  You still have to handle bind 
>> failures.
> If that fails, you give up, since it will only ever fail if there are 
> no ports free, or no network interfaces to bind to.

The following seems to work nicely following Stefan's suggestion.

(cadr (process-contact (make-network-process :name "test" :buffer "test"
                                             :host 'local :service t 
:server t)))

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 21:17     ` Jason Rumney
@ 2006-10-23 22:02       ` Andreas Schwab
  0 siblings, 0 replies; 54+ messages in thread
From: Andreas Schwab @ 2006-10-23 22:02 UTC (permalink / raw)
  Cc: Juanma Barranquero, Stefan Monnier, Emacs Devel

Jason Rumney <jasonr@gnu.org> writes:

> How does X decide that it is OK to overwrite .Xauthority rather than
> creating .Xauthority-2 or whatever numbering it uses for multiple servers?

An X authority file can contain multiple entries, see xauth(1).

Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 21:47   ` Juanma Barranquero
@ 2006-10-23 23:50     ` Ted Zlatanov
  0 siblings, 0 replies; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-23 23:50 UTC (permalink / raw)


On 23 Oct 2006, lekktu@gmail.com wrote:

On 10/23/06, Ted Zlatanov <tzz@lifelogs.com> wrote:
>
>> This may seem like an offbeat suggestion, but I think Emacs could
>> behave like a SSH daemon for emacsclient/server interactions..
>
> Well, I'm not so sure, and in any case that is out of my league (so I
> won't be the one implementing it), and probably too complex to do
> before the pretest.

Sure, I'm just making a suggestion, not requesting a feature or a
bugfix.  It can wait.

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 20:09   ` Eli Zaretskii
@ 2006-10-24  0:02     ` Ted Zlatanov
  2006-10-24  4:35       ` Eli Zaretskii
  0 siblings, 1 reply; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-24  0:02 UTC (permalink / raw)


On 23 Oct 2006, eliz@gnu.org wrote:

>> From: Ted Zlatanov <tzz@lifelogs.com>
>> Date: Mon, 23 Oct 2006 17:00:24 +0100
>>
>> This may seem like an offbeat suggestion, but I think Emacs could
>> behave like a SSH daemon for emacsclient/server interactions..
>
> That sounds like a huge overkill to me.  Let's not forget that
> emacsclient is first and foremost for _local_ connections, and these
> hardly justify SSH.

Oh, I understand that.  Local IP connections are generally much faster
than external IP connections.  As for the data overhead, it's not
significant IMO, considering the payload is tiny.

If you mean memory overhead, it won't be that much.  People run SSH
daemons all the time, so the libraries are already loaded.

There are performance and memory hits, yes, but they are minor
compared to the gains I listed earlier.

Did I understand your objection correctly?

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 16:00 ` Ted Zlatanov
  2006-10-23 20:09   ` Eli Zaretskii
  2006-10-23 21:47   ` Juanma Barranquero
@ 2006-10-24  2:01   ` Stefan Monnier
  2006-10-24 15:40     ` Ted Zlatanov
  2 siblings, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-24  2:01 UTC (permalink / raw)
  Cc: emacs-devel

> This may seem like an offbeat suggestion, but I think Emacs could
> behave like a SSH daemon for emacsclient/server interactions..

You mean: no change to server.el, and simply change emacsclient such that
it runs emacsclient on the server host via ssh?

I used to do that with a script and it's trivial to do, indeed.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 21:54   ` Juanma Barranquero
@ 2006-10-24  2:04     ` Stefan Monnier
  2006-10-24  8:39       ` Juanma Barranquero
  0 siblings, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-24  2:04 UTC (permalink / raw)
  Cc: Emacs Devel

>> Sounds OK.  I'm not quite sure how "-server-name" and
>> "--socket-name" relate.  Maybe we should merge them?

> This is what you said a year ago:

> "Maybe you're right, and .emacs.servers should be a directory.
> So if you run emacsclient --server-name foo it would look for
> /tmp/emacs<uid>/foo for a unix socket and if that fails it'd look for
> ~/.emacs.servers/foo for a file holding the host/port/auth info."

> so I think yes, you were thinking of merging both.

I guess I didn't notice the "socket" vs "server" part of the option's name.
It's probably not important either way.

>> I don't understand.  Currently, "--socket-name=FOO" tries /tmp/esrv-UID/FOO
>> (and if not specified it assumes FOO to be "server"), and that doesn't
>> prevent root from saying "--socket-name=/tmp/esrv-OTHERUID/bar".
>> Why shouldn't this work just as well for --server-name?

> OK, but then, --server-name=foo is taken to be (in TCP sockets) either
> ~/.emacs.d/server/foo, or an absolute path.  That wasn't explicit in
> the earlier thread and I understood "foo" to be always taken as a
> server name.

You mean that if FOO is an absolute path, there is ambiguity as to whether
FOO should be taken to be the file name of a socket file or the file name of
a "emacs server" file?
I didn't think of it, but I guess we can check the file's type to
distinguish the two cases.  Or if we don't merge --server-name
and --socket-name then there's no such ambiguity.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  0:02     ` Ted Zlatanov
@ 2006-10-24  4:35       ` Eli Zaretskii
  2006-10-24 15:36         ` Ted Zlatanov
  0 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2006-10-24  4:35 UTC (permalink / raw)
  Cc: emacs-devel

> From: Ted Zlatanov <tzz@lifelogs.com>
> Date: Tue, 24 Oct 2006 01:02:18 +0100
> 
> > That sounds like a huge overkill to me.  Let's not forget that
> > emacsclient is first and foremost for _local_ connections, and these
> > hardly justify SSH.
> 
> Oh, I understand that.  Local IP connections are generally much faster
> than external IP connections.

I meant ``local'' as in ``on the same machine''.  No IP connection is
needed.

> There are performance and memory hits, yes, but they are minor
> compared to the gains I listed earlier.

What about the overkill of writing a much more complicated code in
Emacs?  That was what I was talking about.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 21:20       ` Jason Rumney
  2006-10-23 21:59         ` Jason Rumney
@ 2006-10-24  5:06         ` Jan Djärv
  2006-10-24  8:37           ` Juanma Barranquero
  2006-10-24 13:27           ` Jason Rumney
  1 sibling, 2 replies; 54+ messages in thread
From: Jan Djärv @ 2006-10-24  5:06 UTC (permalink / raw)
  Cc: Juanma Barranquero, Stefan Monnier, Emacs Devel



Jason Rumney skrev:
> Jan Djärv wrote:
>>
>> Stefan Monnier skrev:
>>>
>>> Huh?  Why would you need that.
>>> It seems just as simple to
>>> - bind to any port.
>>
>> And if that fails, what do you do?  You still have to handle bind 
>> failures.
> If that fails, you give up, since it will only ever fail if there are no 
> ports free, or no network interfaces to bind to.

If you choose a random port, it is likely you hit a used port, i.e. bind 
fails.  It is not only when there are no ports free or no interfaces to bind to.

You would of course exclude the well known ports, but even then you can never 
guarantee that you will not by accident choose a port that is in use.

	Jan D.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-23 21:57       ` Juanma Barranquero
@ 2006-10-24  5:08         ` Jan Djärv
  2006-10-24  7:32           ` Kim F. Storm
  0 siblings, 1 reply; 54+ messages in thread
From: Jan Djärv @ 2006-10-24  5:08 UTC (permalink / raw)
  Cc: Emacs Devel



Juanma Barranquero skrev:
> On 10/23/06, Jan Djärv <jan.h.d@swipnet.se> wrote:
> 
>> And if that fails, what do you do?  You still have to handle bind 
>> failures.
> 
> Throw an error, show a message to the user and refuse to start the
> server. Why should it be different than trying to write a file and not
> being able to?
> 

Because if you choose a random port and just give up if you happen to get a 
busy one, you have a situation where emacs server works sometimes and doesn't 
sometimes randomly.  That will lead to bug reports.

	Jan D.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  5:08         ` Jan Djärv
@ 2006-10-24  7:32           ` Kim F. Storm
  0 siblings, 0 replies; 54+ messages in thread
From: Kim F. Storm @ 2006-10-24  7:32 UTC (permalink / raw)
  Cc: Juanma Barranquero, Emacs Devel

Jan Djärv <jan.h.d@swipnet.se> writes:

>
> Because if you choose a random port and just give up if you happen to
             ^^^

make-network-process will choose an unused, random port for you if you
use :server t :service t .

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  5:06         ` Jan Djärv
@ 2006-10-24  8:37           ` Juanma Barranquero
  2006-10-24 13:27           ` Jason Rumney
  1 sibling, 0 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-24  8:37 UTC (permalink / raw)
  Cc: Emacs Devel, Stefan Monnier, Jason Rumney

[-- Attachment #1: Type: text/plain, Size: 297 bytes --]

On 10/24/06, Jan Djärv <jan.h.d@swipnet.se> wrote:

> If you choose a random port, it is likely you hit a used port, i.e. bind
> fails.

I wasn't planning on *choosing* a random port, but letting
make-network-process do it, as Kim suggests in another message.

-- 
                    /L/e/k/t/u

[-- Attachment #2: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  2:04     ` Stefan Monnier
@ 2006-10-24  8:39       ` Juanma Barranquero
  2006-10-27  0:27         ` Juanma Barranquero
  0 siblings, 1 reply; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-24  8:39 UTC (permalink / raw)


On 10/24/06, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> I didn't think of it, but I guess we can check the file's type to
> distinguish the two cases.  Or if we don't merge --server-name
> and --socket-name then there's no such ambiguity.

I prefer the second option: just don't mix --server-name and --socket-name.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  5:06         ` Jan Djärv
  2006-10-24  8:37           ` Juanma Barranquero
@ 2006-10-24 13:27           ` Jason Rumney
  1 sibling, 0 replies; 54+ messages in thread
From: Jason Rumney @ 2006-10-24 13:27 UTC (permalink / raw)
  Cc: Juanma Barranquero, Stefan Monnier, Emacs Devel

Jan Djärv wrote:
> If you choose a random port, it is likely you hit a used port,
No, YOU don't choose a random port, you leave it to the OS to choose it.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  4:35       ` Eli Zaretskii
@ 2006-10-24 15:36         ` Ted Zlatanov
  2006-10-24 17:31           ` Eli Zaretskii
  0 siblings, 1 reply; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-24 15:36 UTC (permalink / raw)


On 24 Oct 2006, eliz@gnu.org wrote:

>> From: Ted Zlatanov <tzz@lifelogs.com>
>> Date: Tue, 24 Oct 2006 01:02:18 +0100
>>
>>> That sounds like a huge overkill to me.  Let's not forget that
>>> emacsclient is first and foremost for _local_ connections, and these
>>> hardly justify SSH.
>>
>> Oh, I understand that.  Local IP connections are generally much faster
>> than external IP connections.
>
> I meant ``local'' as in ``on the same machine''.  No IP connection is
> needed.

Yes, I understand that.  Really.  Since SSH is a TCP protocol,
obviously a TCP/IP connection would be needed if SSH was the transport
mechanism for emacsclient-style interactions.  Since I'm suggesting
SSH specifically, I'm implicitly suggesting that emacsclient should go
over TCP/IP instead of a local connection (socket, for example).

>> There are performance and memory hits, yes, but they are minor
>> compared to the gains I listed earlier.
>
> What about the overkill of writing a much more complicated code in
> Emacs?  That was what I was talking about.

1) Are you sure it's much more complicated than the existing
   emacsclient+emacsserver combinations?  I think it's a worse, but
   not unjustifiably so.  The OpenSSL libraries do a lot of the hard
   work.  Emacs would not have to implement the full OpenSSH
   functionality, and it does not have to deal with much of the code
   that makes OpenSSH complicated: user/group logins, file security,
   etc.

2) Please consider the gains from a SSH approach: no special
   emacsclient, secure authenticated connections, etc. as I listed
   already.  Don't discard a suggestion just because the code it would
   engender is more complicated.  Take security, user convenience, and
   future gains (e.g. automating Emacs remotely over TCP/IP) into
   account.

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  2:01   ` Stefan Monnier
@ 2006-10-24 15:40     ` Ted Zlatanov
  2006-10-24 18:17       ` Stefan Monnier
  0 siblings, 1 reply; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-24 15:40 UTC (permalink / raw)


On 24 Oct 2006, monnier@iro.umontreal.ca wrote:

>> This may seem like an offbeat suggestion, but I think Emacs could
>> behave like a SSH daemon for emacsclient/server interactions..
>
> You mean: no change to server.el, and simply change emacsclient such that
> it runs emacsclient on the server host via ssh?
>
> I used to do that with a script and it's trivial to do, indeed.

No, I mean:

1) on the client side

ssh tzz@hostname:4567 '(function)'

2) on the Emacs side, running on `hostname' with IP `ip'

; bind to ip:4567
(sshd ip 4567)
; add a user for remote execution, with the following keys
(sshd-add-keys "tzz" "~/.ssh/identity" "~/.ssh/id_dsa")

So emacsclient would be gone, and server.el would be sshd.el or
something similar.

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 15:36         ` Ted Zlatanov
@ 2006-10-24 17:31           ` Eli Zaretskii
  2006-10-24 19:24             ` Ted Zlatanov
  0 siblings, 1 reply; 54+ messages in thread
From: Eli Zaretskii @ 2006-10-24 17:31 UTC (permalink / raw)
  Cc: emacs-devel

> From: Ted Zlatanov <tzz@lifelogs.com>
> Date: Tue, 24 Oct 2006 16:36:15 +0100
> 
> > What about the overkill of writing a much more complicated code in
> > Emacs?  That was what I was talking about.
> 
> 1) Are you sure it's much more complicated than the existing
>    emacsclient+emacsserver combinations?

I think it's pretty obvious: the need to autodetect the libraries in
the configure script, the need for C code to interface with the
libraries, the need to require the libraries for emacsclient
functionality, etc.

> 2) Please consider the gains from a SSH approach: no special
>    emacsclient, secure authenticated connections, etc. as I listed
>    already.

I don't see any need for authentication and secure connections as long
as the connection is on the same machine.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 15:40     ` Ted Zlatanov
@ 2006-10-24 18:17       ` Stefan Monnier
  2006-10-24 19:31         ` Ted Zlatanov
  0 siblings, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-24 18:17 UTC (permalink / raw)
  Cc: emacs-devel

>>> This may seem like an offbeat suggestion, but I think Emacs could
>>> behave like a SSH daemon for emacsclient/server interactions..
>> 
>> You mean: no change to server.el, and simply change emacsclient such that
>> it runs emacsclient on the server host via ssh?
>> 
>> I used to do that with a script and it's trivial to do, indeed.

> No, I mean:

> 1) on the client side

> ssh tzz@hostname:4567 '(function)'

> 2) on the Emacs side, running on `hostname' with IP `ip'

> ; bind to ip:4567
> (sshd ip 4567)
> ; add a user for remote execution, with the following keys
> (sshd-add-keys "tzz" "~/.ssh/identity" "~/.ssh/id_dsa")

> So emacsclient would be gone, and server.el would be sshd.el or
> something similar.

What would be the benefit compared to what I suggested (i.e. on the server
side just a unix-socket, and on the client side "ssh machine emacsclient
...")?


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 17:31           ` Eli Zaretskii
@ 2006-10-24 19:24             ` Ted Zlatanov
  2006-10-24 22:22               ` Stefan Monnier
  2006-10-25 11:46               ` Michael Olson
  0 siblings, 2 replies; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-24 19:24 UTC (permalink / raw)


On 24 Oct 2006, eliz@gnu.org wrote:

>> From: Ted Zlatanov <tzz@lifelogs.com>
>> Date: Tue, 24 Oct 2006 16:36:15 +0100
>>
>>> What about the overkill of writing a much more complicated code in
>>> Emacs?  That was what I was talking about.
>>
>> 1) Are you sure it's much more complicated than the existing
>> emacsclient+emacsserver combinations?
>
> I think it's pretty obvious: the need to autodetect the libraries in
> the configure script, the need for C code to interface with the
> libraries, the need to require the libraries for emacsclient
> functionality, etc.

I understand that it requires work.  I doubt it's "much more"
considering there will be no client, and that the server will offer
limited functionality.  If I'm the only one interested, however, I
will stop bothering people now.

>> 2) Please consider the gains from a SSH approach: no special
>> emacsclient, secure authenticated connections, etc. as I listed
>> already.
>
> I don't see any need for authentication and secure connections as long
> as the connection is on the same machine.

I disagree.  See Juanma's first post in this thread, for instance,
where he specifically talks about authentication as a requirement.

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 18:17       ` Stefan Monnier
@ 2006-10-24 19:31         ` Ted Zlatanov
  0 siblings, 0 replies; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-24 19:31 UTC (permalink / raw)


On 24 Oct 2006, monnier@iro.umontreal.ca wrote:

>>>> This may seem like an offbeat suggestion, but I think Emacs could
>>>> behave like a SSH daemon for emacsclient/server interactions..
>>>
>>> You mean: no change to server.el, and simply change emacsclient such that
>>> it runs emacsclient on the server host via ssh?
>>>
>>> I used to do that with a script and it's trivial to do, indeed.
>
>> No, I mean:
>
>> 1) on the client side
>
>> ssh tzz@hostname:4567 '(function)'
>
>> 2) on the Emacs side, running on `hostname' with IP `ip'
>
>> ; bind to ip:4567
>> (sshd ip 4567)
>> ; add a user for remote execution, with the following keys
>> (sshd-add-keys "tzz" "~/.ssh/identity" "~/.ssh/id_dsa")
>
>> So emacsclient would be gone, and server.el would be sshd.el or
>> something similar.
>
> What would be the benefit compared to what I suggested (i.e. on the server
> side just a unix-socket, and on the client side "ssh machine emacsclient
> ...")?

1) no quoting required, you're talking directly to Emacs--this is very
   convenient, shells can make quotes hell

2) no SSHD needed on server machine (e.g. Windows users would like
   that)

3) you can open just Emacs, not general SSHD, to outside access

4) Emacs "user" (named in sshd-add-keys) doesn't have to be a valid
   local system user

5) no need to download, compile, and set up emacsclient/gnuclient

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 19:24             ` Ted Zlatanov
@ 2006-10-24 22:22               ` Stefan Monnier
  2006-10-25 16:33                 ` Ted Zlatanov
  2006-10-25 11:46               ` Michael Olson
  1 sibling, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-24 22:22 UTC (permalink / raw)
  Cc: emacs-devel

> I understand that it requires work.  I doubt it's "much more"
> considering there will be no client, and that the server will offer
> limited functionality.  If I'm the only one interested, however, I
> will stop bothering people now.

I think people might be interested in a patch, but otherwise it looks like
a lot of work.  After all, the OpenSSH daemon is not a twoliner, even though
it also uses OpenSSL (AFAIK).
Maybe you know that code better and can see how simple it can be.  If so,
great: show us the goods ;-)


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 19:24             ` Ted Zlatanov
  2006-10-24 22:22               ` Stefan Monnier
@ 2006-10-25 11:46               ` Michael Olson
  2006-10-25 12:38                 ` David Kastrup
  1 sibling, 1 reply; 54+ messages in thread
From: Michael Olson @ 2006-10-25 11:46 UTC (permalink / raw)



[-- Attachment #1.1: Type: text/plain, Size: 824 bytes --]

Ted Zlatanov <tzz@lifelogs.com> writes:

> I understand that it requires work.  I doubt it's "much more"
> considering there will be no client, and that the server will offer
> limited functionality.  If I'm the only one interested, however, I
> will stop bothering people now.

I'm also interested in seeing this happen, since it seems like a
reasonable and secure way to "log into" a remote Emacs session from a
different machine and open a local frame.

-- 
Michael Olson -- FSF Associate Member #652 -- http://www.mwolson.org/
Interests: Emacs Lisp, text markup, protocols -- Jabber: mwolson_at_hcoop.net
  /` |\ | | | Projects: Emacs, Muse, ERC, EMMS, Planner, ErBot, DVC
 |_] | \| |_| Reclaim your digital rights by eliminating DRM.
      See http://www.defectivebydesign.org/what_is_drm for details.

[-- Attachment #1.2: Type: application/pgp-signature, Size: 188 bytes --]

[-- Attachment #2: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-25 11:46               ` Michael Olson
@ 2006-10-25 12:38                 ` David Kastrup
  0 siblings, 0 replies; 54+ messages in thread
From: David Kastrup @ 2006-10-25 12:38 UTC (permalink / raw)
  Cc: emacs-devel

Michael Olson <mwolson@gnu.org> writes:

> Ted Zlatanov <tzz@lifelogs.com> writes:
>
>> I understand that it requires work.  I doubt it's "much more"
>> considering there will be no client, and that the server will offer
>> limited functionality.  If I'm the only one interested, however, I
>> will stop bothering people now.
>
> I'm also interested in seeing this happen, since it seems like a
> reasonable and secure way to "log into" a remote Emacs session from
> a different machine and open a local frame.

That approach might be nice to have when we merge the multi-tty
support.

-- 
David Kastrup, Kriemhildstr. 15, 44793 Bochum

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24 22:22               ` Stefan Monnier
@ 2006-10-25 16:33                 ` Ted Zlatanov
  0 siblings, 0 replies; 54+ messages in thread
From: Ted Zlatanov @ 2006-10-25 16:33 UTC (permalink / raw)


On 24 Oct 2006, monnier@iro.umontreal.ca wrote:

>> I understand that it requires work.  I doubt it's "much more"
>> considering there will be no client, and that the server will offer
>> limited functionality.  If I'm the only one interested, however, I
>> will stop bothering people now.
>
> I think people might be interested in a patch, but otherwise it
> looks like a lot of work.  After all, the OpenSSH daemon is not a
> twoliner, even though it also uses OpenSSL (AFAIK).

I'm not great at C coding (severely out of practice), but I'll take a
look as time allows.  Nothing will happen before the next release in
any case, so I have a while :)

Ted

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-24  8:39       ` Juanma Barranquero
@ 2006-10-27  0:27         ` Juanma Barranquero
  2006-10-27 11:08           ` Juanma Barranquero
  0 siblings, 1 reply; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-27  0:27 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 1982 bytes --]

OK, there's a rough first cut at the emacsclient patch (attached in
context and unified diffs, for easier reading). No doc patches nor
ChangeLogs, yet.

Notes:

  - Should `server-ensure-safe-dir' be used also to create/check
safety of the `server-auth-dir' directory (by default at
~/.emacs.d/server)? If so, `server-ensure-safe-dir' must be changed to
create directories in the path (because `server-auth-dir', unlike
`server-socket-dir', can be customized by the user, and so it can be
at any depth). I've implemented this (by passing the PARENTS arg to
`make-directory'), but I'm not sure that's the right way,
security-wise.

  - Also, I've patched `server-ensure-safe-dir' to ignore Unix-style
file permissions in Windows (checking ACLs would be useful, but I
don't know whether that's possible from Emacs).

  - emasclient.c compiles and works fine with MinGW 3.4.5; I'll try to
test it with MSVC once the code/features settle.

  - With an eye to porting it to MSVC, I've changed the code to use
send/recv instead of streams (it'll be easier to maintain
compatibility, I believe). The Unix sockets code should work OK, but I
don't really know, so please test it.

 - I haven't tried compiling on GNU/Linux or Unix, so there could be
typos or oversights, which should be trivial to fix.

  - There's a new argument --server-file. If --server-file (or
environment variable EMACS_SERVER_FILE) exist, emacsclient uses TCP
sockets, else it uses Unix sockets (either --socket-name, or "emacs"
by default).

  - The only major thing missing is interpreting
--server-file=SERVERNAME as ~/.emacs.d/server/SERVERNAME (currently,
you've got to pass the full path). What would be the easier portable
way to find the user directory? The $HOME (or %HOME in Windows) env
var?

I'd be glad if people could try the patch, with stress on testing on
non-Windows environments and non-TCP sockets (I want to be sure I'm
not breaking anything).

Comments welcome.

                    /L/e/k/t/u

[-- Attachment #2: newserver-c.patch --]
[-- Type: application/octet-stream, Size: 30313 bytes --]

Index: lisp/server.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/server.el,v
retrieving revision 1.113
diff -b -c -2 -r1.113 server.el
*** lisp/server.el	6 Jul 2006 22:48:16 -0000	1.113
--- lisp/server.el	26 Oct 2006 23:06:08 -0000
***************
*** 83,86 ****
--- 83,115 ----
    :group 'external)
  
+ (defcustom server-use-tcp nil
+   "If non-nil, use TCP sockets instead of local sockets."
+   :set #'(lambda (sym val)
+            (if (featurep 'make-network-process '(:family local))
+                (set-default sym val)
+              (unless load-in-progress
+                (message "Local sockets unsupported, using TCP sockets"))
+              (set-default sym t)))
+   :group 'server
+   :type 'boolean
+   :version "22.1")
+ 
+ (defcustom server-host nil
+   "The name or IP address to use as host address of the server process.
+ If set, the server accepts remote connections; otherwise it is local."
+   :group 'server
+   :type '(choice
+           (string :tag "Name or IP address")
+           (const :tag "Local" nil))
+   :version "22.1")
+ (put 'server-host 'risky-local-variable t)
+ 
+ (defcustom server-auth-dir "~/.emacs.d/server/"
+   "Directory for server authentication files."
+   :group 'server
+   :type 'directory
+   :version "22.1")
+ (put 'server-auth-dir 'risky-local-variable t)
+ 
  (defcustom server-visit-hook nil
    "*Hook run when visiting a file for the Emacs server."
***************
*** 101,104 ****
--- 130,136 ----
    "The current server process.")
  
+ (defvar server-auth-string nil
+   "The current server authentication string.")
+ 
  (defvar server-clients nil
    "List of current server clients.
***************
*** 232,242 ****
    (let ((attrs (file-attributes dir)))
      (unless attrs
!       (letf (((default-file-modes) ?\700)) (make-directory dir))
        (setq attrs (file-attributes dir)))
      ;; Check that it's safe for use.
      (unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
! 		 (zerop (logand ?\077 (file-modes dir))))
        (error "The directory %s is unsafe" dir))))
  
  ;;;###autoload
  (defun server-start (&optional leave-dead)
--- 264,285 ----
    (let ((attrs (file-attributes dir)))
      (unless attrs
!       (letf (((default-file-modes) ?\700)) (make-directory dir t))
        (setq attrs (file-attributes dir)))
      ;; Check that it's safe for use.
      (unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
!                  (or (eq system-type 'windows-nt)
!                      (zerop (logand ?\077 (file-modes dir)))))
        (error "The directory %s is unsafe" dir))))
  
+ (defun server-auth-string ()
+   (or server-auth-string
+       ;; If the authentication string does not exist, create it on the fly:
+       ;; it's a 64-byte string of random chars in the range `!'..`~'.
+       (setq server-auth-string
+ 	    (loop
+ 	       for i below 64
+ 	       collect (+ 33 (random 94)) into auth
+ 	       finally return (concat auth)))))
+ 
  ;;;###autoload
  (defun server-start (&optional leave-dead)
***************
*** 249,259 ****
  Prefix arg means just kill any existing server communications subprocess."
    (interactive "P")
    ;; kill it dead!
!   (if server-process
!       (condition-case () (delete-process server-process) (error nil)))
!   ;; Delete the socket files made by previous server invocations.
!   (condition-case ()
        (delete-file (expand-file-name server-name server-socket-dir))
!     (error nil))
    ;; If this Emacs already had a server, clear out associated status.
    (while server-clients
--- 292,304 ----
  Prefix arg means just kill any existing server communications subprocess."
    (interactive "P")
+   (when server-process
      ;; kill it dead!
!     (ignore-errors (delete-process server-process))
!     (ignore-errors
!       ;; Delete the socket or authentication files made by previous server invocations.
!       (if (eq (process-contact server-process :family) 'local)
            (delete-file (expand-file-name server-name server-socket-dir))
!         (setq server-auth-string nil)
!         (delete-file (expand-file-name server-name server-auth-dir)))))
    ;; If this Emacs already had a server, clear out associated status.
    (while server-clients
***************
*** 263,279 ****
    (unless leave-dead
      ;; Make sure there is a safe directory in which to place the socket.
!     (server-ensure-safe-dir server-socket-dir)
!     (if server-process
  	(server-log (message "Restarting server")))
      (letf (((default-file-modes) ?\700))
        (setq server-process
! 	    (make-network-process
! 	     :name "server" :family 'local :server t :noquery t
! 	     :service (expand-file-name server-name server-socket-dir)
! 	     :sentinel 'server-sentinel :filter 'server-process-filter
  	     ;; We must receive file names without being decoded.
  	     ;; Those are decoded by server-process-filter according
  	     ;; to file-name-coding-system.
! 	     :coding 'raw-text)))))
  
  ;;;###autoload
--- 308,342 ----
    (unless leave-dead
      ;; Make sure there is a safe directory in which to place the socket.
!     (server-ensure-safe-dir (if server-use-tcp server-auth-dir server-socket-dir))
!     (when server-process
        (server-log (message "Restarting server")))
      (letf (((default-file-modes) ?\700))
        (setq server-process
!             (apply #'make-network-process
!                    :name server-name
!                    :server t
!                    :noquery t
!                    :sentinel 'server-sentinel
!                    :filter 'server-process-filter
                     ;; We must receive file names without being decoded.
                     ;; Those are decoded by server-process-filter according
                     ;; to file-name-coding-system.
!                    :coding 'raw-text
!                    ;; The rest of the arguments depend on the kind of socket used
!                    (if server-use-tcp
!                        (list :family nil
!                              :service t
!                              :host (or server-host 'local)
!                              :plist '(:authenticated nil))
!                      (list :family 'local
!                            :service (expand-file-name server-name server-socket-dir)
!                            :plist '(:authenticated t))))))
!     (unless server-process (error "Could not start server process"))
!     (when server-use-tcp
!       (with-temp-file (expand-file-name server-name server-auth-dir)
!         (set-buffer-multibyte nil)
!         (setq buffer-file-coding-system 'no-conversion)
!         (insert (format-network-address (process-contact server-process :local))
!                 "\n" (server-auth-string))))))
  
  ;;;###autoload
***************
*** 290,301 ****
    (server-start (not server-mode)))
  \f
! (defun server-process-filter (proc string)
    "Process a request from the server to edit some files.
  PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
    (server-log string proc)
!   (let ((prev (process-get proc 'previous-string)))
      (when prev
        (setq string (concat prev string))
!       (process-put proc 'previous-string nil)))
    ;; If the input is multiple lines,
    ;; process each line individually.
--- 353,375 ----
    (server-start (not server-mode)))
  \f
! (defun* server-process-filter (proc string)
    "Process a request from the server to edit some files.
  PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
+   ;; First things first: let's check the authentication
+   (unless (process-get proc :authenticated)
+     (if (and (string-match "-auth \\(.*?\\)\n" string)
+              (string= (match-string 1 string) server-auth-string))
+         (progn
+           (setq string (substring string (match-end 0)))
+           (process-put proc :authenticated t)
+           (server-log "Authentication successful" proc))
+       (server-log "Authentication failed" proc)
+       (delete-process proc)
+       (return-from server-process-filter)))
    (server-log string proc)
!   (let ((prev (process-get proc :previous-string)))
      (when prev
        (setq string (concat prev string))
!       (process-put proc :previous-string nil)))
    ;; If the input is multiple lines,
    ;; process each line individually.
***************
*** 390,394 ****
    ;; Save for later any partial line that remains.
    (when (> (length string) 0)
!     (process-put proc 'previous-string string)))
  
  (defun server-goto-line-column (file-line-col)
--- 464,468 ----
    ;; Save for later any partial line that remains.
    (when (> (length string) 0)
!     (process-put proc :previous-string string)))
  
  (defun server-goto-line-column (file-line-col)
Index: lib-src/emacsclient.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/emacsclient.c,v
retrieving revision 1.77
diff -b -c -2 -r1.77 emacsclient.c
*** lib-src/emacsclient.c	18 Jul 2006 16:33:45 -0000	1.77
--- lib-src/emacsclient.c	27 Oct 2006 00:06:01 -0000
***************
*** 27,35 ****
  #endif
  
  #undef signal
  
  #include <ctype.h>
  #include <stdio.h>
! #include <getopt.h>
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
--- 27,40 ----
  #endif
  
+ #ifdef WINDOWSNT
+ #define HAVE_SOCKETS
+ #define NO_SOCKETS_IN_FILE_SYSTEM
+ #endif
+ 
  #undef signal
  
  #include <ctype.h>
  #include <stdio.h>
! #include "getopt.h"
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
***************
*** 38,43 ****
  #ifdef VMS
  # include "vms-pwd.h"
! #else
  # include <pwd.h>
  #endif /* not VMS */
  
--- 43,52 ----
  #ifdef VMS
  # include "vms-pwd.h"
! #else /* not VMS */
! #ifdef WINDOWSNT
! # include <io.h>
! #else /* not WINDOWSNT */
  # include <pwd.h>
+ #endif /* not WINDOWSNT */
  #endif /* not VMS */
  
***************
*** 49,52 ****
--- 58,76 ----
  #endif
  
+ #define SEND_STRING(data) (send_to_emacs (s, (data)))
+ #define SEND_QUOTED(data) (quote_file_name (s, (data)))
+ 
+ #ifndef EXIT_SUCCESS
+ #define EXIT_SUCCESS 0
+ #endif
+ 
+ #ifndef EXIT_FAILURE
+ #define EXIT_FAILURE 1
+ #endif
+ 
+ #ifndef NO_RETURN
+ #define NO_RETURN
+ #endif
+ \f
  /* Name used to invoke this program.  */
  char *progname;
***************
*** 68,71 ****
--- 92,98 ----
  char *socket_name = NULL;
  
+ /* If non-NULL, the filename of the authentication file.  */
+ char *server_file = NULL;
+ 
  void print_help_and_exit () NO_RETURN;
  
***************
*** 78,81 ****
--- 105,109 ----
    { "alternate-editor", required_argument, NULL, 'a' },
    { "socket-name",	required_argument, NULL, 's' },
+   { "server-file",	required_argument, NULL, 'f' },
    { "display",	required_argument, NULL, 'd' },
    { 0, 0, 0, 0 }
***************
*** 91,99 ****
  {
    alternate_editor = getenv ("ALTERNATE_EDITOR");
  
    while (1)
      {
        int opt = getopt_long (argc, argv,
! 			     "VHnea:s:d:", longopts, 0);
  
        if (opt == EOF)
--- 119,128 ----
  {
    alternate_editor = getenv ("ALTERNATE_EDITOR");
+   server_file = getenv ("EMACS_SERVER_FILE");
  
    while (1)
      {
        int opt = getopt_long (argc, argv,
! 			     "VHnea:s:f:d:", longopts, 0);
  
        if (opt == EOF)
***************
*** 115,118 ****
--- 144,151 ----
  	  break;
  
+ 	case 'f':
+ 	  server_file = optarg;
+ 	  break;
+ 
  	case 'd':
  	  display = optarg;
***************
*** 158,163 ****
  -e, --eval              Evaluate the FILE arguments as ELisp expressions\n\
  -d, --display=DISPLAY   Visit the file in the given display\n\
! -s, --socket-name=FILENAME\n\
                          Set the filename of the UNIX socket for communication\n\
  -a, --alternate-editor=EDITOR\n\
                          Editor to fallback to if the server is not running\n\
--- 191,202 ----
  -e, --eval		Evaluate the FILE arguments as ELisp expressions\n\
  -d, --display=DISPLAY	Visit the file in the given display\n\
! "
! #ifndef NO_SOCKETS_IN_FILE_SYSTEM
! "-s, --socket-name=FILENAME\n\
  			Set the filename of the UNIX socket for communication\n\
+ "
+ #endif
+ "-f, --server-file=FILENAME\n\
+ 			Set the filename of the TCP configuration file\n\
  -a, --alternate-editor=EDITOR\n\
  			Editor to fallback to if the server is not running\n\
***************
*** 167,178 ****
  }
  
  /* In NAME, insert a & before each &, each space, each newline, and
     any initial -.  Change spaces to underscores, too, so that the
     return value never contains a space.  */
- 
  void
! quote_file_name (name, stream)
       char *name;
-      FILE *stream;
  {
    char *copy = (char *) malloc (strlen (name) * 2 + 1);
--- 206,313 ----
  }
  
+ \f
+ /*
+   Try to run a different command, or --if no alternate editor is
+   defined-- exit with an errorcode.
+ */
+ void
+ fail (argc, argv)
+      int argc;
+      char **argv;
+ {
+   if (alternate_editor)
+     {
+       int i = optind - 1;
+       execvp (alternate_editor, argv + i);
+       return;
+     }
+   else
+     {
+       exit (EXIT_FAILURE);
+     }
+ }
+ 
+ \f
+ #if !defined (HAVE_SOCKETS)
+ 
+ int
+ main (argc, argv)
+      int argc;
+      char **argv;
+ {
+   fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
+ 	   argv[0]);
+   fprintf (stderr, "on systems with Berkeley sockets.\n");
+ 
+   fail (argc, argv);
+ }
+ 
+ #else /* HAVE_SOCKETS */
+ 
+ #define AUTH_STRING_LENGTH   64
+ #define SEND_BUFFER_SIZE   4096
+ 
+ #ifdef WINDOWSNT
+ # include <winsock2.h>
+ #else
+ # include <sys/types.h>
+ # include <sys/socket.h>
+ # include <sys/un.h>
+ # include <sys/stat.h>
+ # include <errno.h>
+ #endif
+ 
+ extern char *strerror ();
+ extern int errno;
+ 
+ /* Buffer to accumulate data to send in TCP connections.  */
+ char send_buffer[SEND_BUFFER_SIZE + 1];
+ int sblen = 0;	/* Fill pointer for the send buffer.  */
+ 
+ /* Let's send the data to Emacs when either
+    - the data ends in "\n", or
+    - the buffer is full (but this shouldn't happen)
+    Otherwise, we just accumulate it.  */
+ void send_to_emacs (s, data)
+      SOCKET s;
+      char *data;
+ {
+   while (data)
+     {
+       int dlen = strlen (data);
+       if (dlen + sblen >= SEND_BUFFER_SIZE)
+ 	{
+ 	  int part = SEND_BUFFER_SIZE - sblen;
+ 	  strncpy (&send_buffer[sblen], data, part);
+ 	  data += part;
+ 	  sblen = SEND_BUFFER_SIZE;
+ 	}
+       else if (dlen)
+ 	{
+ 	  strcpy (&send_buffer[sblen], data);
+ 	  data = NULL;
+ 	  sblen += dlen;
+ 	}
+       else
+ 	break;
+ 
+       if (sblen == SEND_BUFFER_SIZE
+ 	  || (sblen > 0 && send_buffer[sblen-1] == '\n'))
+ 	{
+ 	  int sent = send (s, send_buffer, sblen, 0);
+ 	  if (sent != sblen)
+ 	    strcpy (send_buffer, &send_buffer[sent]);
+ 	  sblen -= sent;
+ 	}
+     }
+ }
+ 
  /* In NAME, insert a & before each &, each space, each newline, and
     any initial -.  Change spaces to underscores, too, so that the
     return value never contains a space.	 */
  void
! quote_file_name (s, name)
!      SOCKET s;
       char *name;
  {
    char *copy = (char *) malloc (strlen (name) * 2 + 1);
***************
*** 204,274 ****
    *q++ = 0;
  
!   fprintf (stream, "%s", copy);
  
    free (copy);
  }
  
! /* Like malloc but get fatal error if memory is exhausted.  */
  
! long *
! xmalloc (size)
!      unsigned int size;
  {
!   long *result = (long *) malloc (size);
!   if (result == NULL)
    {
!     perror ("malloc");
      exit (EXIT_FAILURE);
    }
!   return result;
  }
  \f
  /*
!   Try to run a different command, or --if no alternate editor is
!   defined-- exit with an errorcode.
  */
! void
! fail (argc, argv)
!      int argc;
!      char **argv;
  {
!   if (alternate_editor)
      {
!       int i = optind - 1;
!       execvp (alternate_editor, argv + i);
!       return;
      }
    else
      {
        exit (EXIT_FAILURE);
      }
- }
  
  
  \f
! #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
  
! int
! main (argc, argv)
!      int argc;
!      char **argv;
  {
!   fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
! 	   argv[0]);
!   fprintf (stderr, "on systems with Berkeley sockets.\n");
  
!   fail (argc, argv);
! }
  
! #else /* HAVE_SOCKETS */
  
! #include <sys/types.h>
! #include <sys/socket.h>
! #include <sys/un.h>
! #include <sys/stat.h>
! #include <errno.h>
  
! extern char *strerror ();
! extern int errno;
  
  /* Three possibilities:
--- 339,463 ----
    *q++ = 0;
  
!   SEND_STRING (copy);
  
    free (copy);
  }
  
! #ifdef WINDOWSNT
! /* Wrapper to make WSACleanup a cdecl, as required by atexit().	 */
! void close_winsock ()
! {
!   WSACleanup ();
! }
! #endif /* WINDOWSNT */
  
! void initialize_sockets ()
  {
! #ifdef WINDOWSNT
!   WSADATA wsaData;
! 
!   /* Initialize the WinSock2 library.  */
!   if (WSAStartup (MAKEWORD (2, 0), &wsaData))
      {
!       fprintf (stderr, "%s: error initializing WinSock2", progname);
        exit (EXIT_FAILURE);
      }
! 
!   atexit (close_winsock);
! #endif /* WINDOWSNT */
  }
  
  /*
!  * Read the information needed to set up a TCP comm channel with
!  * the Emacs server: host, port and authentication string.
  */
! void get_server_config (server, authentication)
!      struct sockaddr_in *server;
!      char *authentication;
  {
!   FILE *config;
!   char dotted[32];
!   char *port;
! 
!   if (! (config = fopen (server_file, "rb")))
      {
!       fprintf (stderr, "%s: cannot read configuration file %s",
! 	       progname, server_file);
!       exit (EXIT_FAILURE);
!     }
! 
!   if (fgets (dotted, sizeof dotted, config)
!       && (port = strchr (dotted, ':')))
!     {
!       *port++ = '\0';
      }
    else
      {
+       fprintf (stderr, "%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_STRING_LENGTH, 1, config))
+     {
+       fprintf (stderr, "%s: cannot read authentication info", progname);
+       exit (EXIT_FAILURE);
+     }
  
!   fclose (config);
! }
  
! SOCKET
! set_tcp_socket ()
  {
!   SOCKET s;
!   struct sockaddr_in server;
!   unsigned long c_arg = 0;
!   struct linger l_arg = {1, 1};
!   char auth_string[AUTH_STRING_LENGTH + 1];
  
!   initialize_sockets ();
  
!   get_server_config (&server, auth_string);
  
!   /*
!    * Open up an AF_INET socket
!    */
!   if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
!     {
!       fprintf (stderr, "%s: ", progname);
!       perror ("socket");
!       return INVALID_SOCKET;
!     }
  
!   /*
!    * Set up the socket
!    */
!   if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
!     {
!       fprintf (stderr, "%s: ", progname);
!       perror ("connect");
!       return INVALID_SOCKET;
!     }
! 
!   ioctlsocket (s, FIONBIO, &c_arg);
!   setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
! 
!   /*
!    * Send the authentication
!    */
!   auth_string[AUTH_STRING_LENGTH] = '\0';
! 
!   SEND_STRING ("-auth ");
!   SEND_STRING (auth_string);
!   SEND_STRING ("\n");
! 
!   return s;
! }
! 
! #if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
  
  /* Three possibilities:
***************
*** 292,317 ****
  }
  
! int
! main (argc, argv)
!      int argc;
!      char **argv;
  {
!   int s, i, needlf = 0;
!   FILE *out, *in;
    struct sockaddr_un server;
-   char *cwd, *str;
-   char string[BUFSIZ];
- 
-   progname = argv[0];
- 
-   /* Process options.  */
-   decode_options (argc, argv);
- 
-   if ((argc - optind < 1) && !eval)
-     {
-       fprintf (stderr, "%s: file name or argument required\n", progname);
-       fprintf (stderr, "Try `%s --help' for more information\n", progname);
-       exit (EXIT_FAILURE);
-     }
  
    /*
--- 481,489 ----
  }
  
! SOCKET
! set_local_socket ()
  {
!   SOCKET s;
    struct sockaddr_un server;
  
    /*
***************
*** 321,327 ****
    if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
      {
!       fprintf (stderr, "%s: ", argv[0]);
        perror ("socket");
!       fail (argc, argv);
      }
  
--- 493,499 ----
    if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
      {
!       fprintf (stderr, "%s: ", progname);
        perror ("socket");
!       return INVALID_SOCKET;
      }
  
***************
*** 353,357 ****
        {
  	fprintf (stderr, "%s: socket-name %s too long",
! 		 argv[0], socket_name);
  	exit (EXIT_FAILURE);
        }
--- 525,529 ----
        {
  	fprintf (stderr, "%s: socket-name %s too long",
! 		 progname, socket_name);
  	exit (EXIT_FAILURE);
        }
***************
*** 388,392 ****
  		  {
  		    fprintf (stderr, "%s: socket-name %s too long",
! 			     argv[0], socket_name);
  		    exit (EXIT_FAILURE);
  		  }
--- 560,564 ----
  		  {
  		    fprintf (stderr, "%s: socket-name %s too long",
! 			     progname, socket_name);
  		    exit (EXIT_FAILURE);
  		  }
***************
*** 408,412 ****
  	   {
  	     fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
! 	     fail (argc, argv);
  	   }
  	 break;
--- 580,584 ----
  	  {
  	    fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
! 	    return INVALID_SOCKET;
  	  }
  	break;
***************
*** 418,427 ****
  		    "%s: can't find socket; have you started the server?\n\
  To start the server in Emacs, type \"M-x server-start\".\n",
! 		    argv[0]);
  	 else
  	   fprintf (stderr, "%s: can't stat %s: %s\n",
! 		    argv[0], server.sun_path, strerror (saved_errno));
! 	 fail (argc, argv);
! 	 break;
         }
    }
--- 590,598 ----
  		   "%s: can't find socket; have you started the server?\n\
  To start the server in Emacs, type \"M-x server-start\".\n",
! 		   progname);
  	else
  	  fprintf (stderr, "%s: can't stat %s: %s\n",
! 		   progname, server.sun_path, strerror (saved_errno));
! 	return INVALID_SOCKET;
        }
    }
***************
*** 430,458 ****
        < 0)
      {
!       fprintf (stderr, "%s: ", argv[0]);
        perror ("connect");
!       fail (argc, argv);
      }
  
!   /* We use the stream OUT to send our command to the server.  */
!   if ((out = fdopen (s, "r+")) == NULL)
      {
!       fprintf (stderr, "%s: ", argv[0]);
!       perror ("fdopen");
!       fail (argc, argv);
      }
  
!   /* We use the stream IN to read the response.
!      We used to use just one stream for both output and input
!      on the socket, but reversing direction works nonportably:
!      on some systems, the output appears as the first input;
!      on other systems it does not.  */
!   if ((in = fdopen (s, "r+")) == NULL)
      {
!       fprintf (stderr, "%s: ", argv[0]);
!       perror ("fdopen");
!       fail (argc, argv);
      }
  
  #ifdef HAVE_GETCWD
    cwd = getcwd (string, sizeof string);
--- 601,654 ----
        < 0)
      {
!       fprintf (stderr, "%s: ", progname);
        perror ("connect");
!       return INVALID_SOCKET;
      }
  
!   return s;
! }
! #endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
! 
! SOCKET
! set_socket ()
! {
!   if (server_file)
!     return set_tcp_socket ();
!   else
! #ifndef NO_SOCKETS_IN_FILE_SYSTEM
!     return set_local_socket ();
! #else
      {
!       fprintf (stderr, "%s: missing --server-file option", progname);
!       exit (EXIT_FAILURE);
      }
+ #endif
+ }
+ 
+ int
+ main (argc, argv)
+      int argc;
+      char **argv;
+ {
+   SOCKET s;
+   int i, rl, needlf = 0;
+   char *cwd;
+   char string[BUFSIZ+1];
+ 
+   progname = argv[0];
  
!   /* Process options.  */
!   decode_options (argc, argv);
! 
!   if ((argc - optind < 1) && !eval)
      {
!       fprintf (stderr, "%s: file name or argument required\n", progname);
!       fprintf (stderr, "Try `%s --help' for more information\n", progname);
!       exit (EXIT_FAILURE);
      }
  
+   if ((s = set_socket ()) == INVALID_SOCKET)
+     fail (argc, argv);
+ 
  #ifdef HAVE_GETCWD
    cwd = getcwd (string, sizeof string);
***************
*** 465,472 ****
  
  #ifdef HAVE_GETCWD
!       fprintf (stderr, "%s: %s (%s)\n", argv[0],
  	       "Cannot get current working directory", strerror (errno));
  #else
!       fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
  #endif
        fail (argc, argv);
--- 661,668 ----
  
  #ifdef HAVE_GETCWD
!       fprintf (stderr, "%s: %s (%s)\n", progname,
  	       "Cannot get current working directory", strerror (errno));
  #else
!       fprintf (stderr, "%s: %s (%s)\n", progname, string, strerror (errno));
  #endif
        fail (argc, argv);
***************
*** 474,487 ****
  
    if (nowait)
!     fprintf (out, "-nowait ");
  
    if (eval)
!     fprintf (out, "-eval ");
  
    if (display)
      {
!       fprintf (out, "-display ");
!       quote_file_name (display, out);
!       fprintf (out, " ");
      }
  
--- 670,683 ----
  
    if (nowait)
!     SEND_STRING ("-nowait ");
  
    if (eval)
!     SEND_STRING ("-eval ");
  
    if (display)
      {
!       SEND_STRING ("-display ");
!       SEND_QUOTED (display);
!       SEND_STRING (" ");
      }
  
***************
*** 498,531 ****
  	      if (*p != 0)
  		{
! 		  quote_file_name (cwd, out);
! 		  fprintf (out, "/");
  		}
  	    }
  	  else if (*argv[i] != '/')
  	    {
! 	      quote_file_name (cwd, out);
! 	      fprintf (out, "/");
  	    }
  
! 	  quote_file_name (argv[i], out);
! 	  fprintf (out, " ");
  	}
      }
    else
      {
!       while ((str = fgets (string, BUFSIZ, stdin)))
  	{
! 	  quote_file_name (str, out);
  	}
!       fprintf (out, " ");
      }
  
!   fprintf (out, "\n");
!   fflush (out);
  
    /* Maybe wait for an answer.   */
!   if (nowait)
!     return EXIT_SUCCESS;
! 
    if (!eval)
      {
--- 694,734 ----
  	      if (*p != 0)
  		{
! 		  SEND_QUOTED (cwd);
! 		  SEND_STRING ("/");
  		}
  	    }
+ #ifndef WINDOWSNT
  	  else if (*argv[i] != '/')
+ #else
+ 	  else if ((*argv[i] != '/')
+ 		   /* Absolute paths can also start with backslash
+ 		      or drive letters.	 */
+ 		   && (*argv[i] != '\\')
+ 		   && (!islower (tolower (*argv[i]))
+ 		       || (argv[i][1] != ':')))
+ #endif
  	    {
! 	      SEND_QUOTED (cwd);
! 	      SEND_STRING ("/");
  	    }
  
! 	  SEND_QUOTED (argv[i]);
! 	  SEND_STRING (" ");
  	}
      }
    else
      {
!       while (fgets (string, BUFSIZ, stdin))
  	{
! 	  SEND_QUOTED (string);
  	}
!       SEND_STRING (" ");
      }
  
!   SEND_STRING ("\n");
  
    /* Maybe wait for an answer.	 */
!   if (!nowait)
!     {
        if (!eval)
  	{
***************
*** 536,545 ****
  
    /* Now, wait for an answer and print any messages.  */
!   while ((str = fgets (string, BUFSIZ, in)))
      {
        if (needlf == 2)
  	printf ("\n");
!       printf ("%s", str);
!       needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
      }
  
--- 739,749 ----
  
        /* Now, wait for an answer and print any messages.  */
!       while ((rl = recv (s, string, BUFSIZ, 0)) > 0)
  	{
+ 	  string[rl] = '\0';
  	  if (needlf == 2)
  	    printf ("\n");
! 	  printf ("%s", string);
! 	  needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n';
  	}
  
***************
*** 547,551 ****
--- 751,757 ----
  	printf ("\n");
        fflush (stdout);
+     }
  
+   closesocket (s);
    return EXIT_SUCCESS;
  }
Index: lib-src/makefile.w32-in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/makefile.w32-in,v
retrieving revision 2.46
diff -b -c -2 -r2.46 makefile.w32-in
*** lib-src/makefile.w32-in	9 Oct 2006 19:57:43 -0000	2.46
--- lib-src/makefile.w32-in	26 Oct 2006 22:23:12 -0000
***************
*** 21,25 ****
  #
  
! ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc
  
  .PHONY: $(ALL)
--- 21,25 ----
  #
  
! ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc emacsclient
  
  .PHONY: $(ALL)
***************
*** 33,37 ****
  #		$(BLD)/server.exe	\
  #		$(BLD)/emacstool.exe	\
- #		$(BLD)/emacsclient.exe	\
  #		$(BLD)/cvtmail.exe	\
  
--- 33,36 ----
***************
*** 60,63 ****
--- 59,63 ----
  sorted-doc:	$(BLD) $(BLD)/sorted-doc.exe
  digest-doc:	$(BLD) $(BLD)/digest-doc.exe
+ emacsclient:	$(BLD) $(BLD)/emacsclient.exe
  
  test-distrib:	$(BLD) $(BLD)/test-distrib.exe
***************
*** 75,78 ****
--- 75,91 ----
  		$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(MOVEMAILOBJS) $(WSOCK32) $(LIBS)
  
+ ECLIENT_CFLAGS = -DWINDOWSNT -DHAVE_GETCWD -DHAVE_STRERROR -c
+ ECLIENTOBJS =	$(BLD)/emacsclient.$(O) \
+ 		$(BLD)/getopt.$(O) \
+ 		$(BLD)/getopt1.$(O) \
+ 		$(BLD)/ntlib.$(O)
+ 
+ $(BLD)/emacsclient.exe:		$(ECLIENTOBJS)
+ # put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib
+ 		$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(LIBS)
+ 
+ $(BLD)/emacsclient.$(O):	emacsclient.c
+ 		$(CC) $(ECLIENT_CFLAGS) $(CC_OUT)$@ emacsclient.c
+ 
  ETAGSOBJ      = $(BLD)/etags.$(O) \
  		$(BLD)/getopt.$(O) \
***************
*** 297,300 ****
--- 310,314 ----
  		$(CP) $(BLD)/sorted-doc.exe $(INSTALL_DIR)/bin
  		$(CP) $(BLD)/digest-doc.exe $(INSTALL_DIR)/bin
+ 		$(CP) $(BLD)/emacsclient.exe $(INSTALL_DIR)/bin
  		- mkdir "$(INSTALL_DIR)/etc"
  		$(CP) $(DOC) $(INSTALL_DIR)/etc

[-- Attachment #3: newserver-u.patch --]
[-- Type: application/octet-stream, Size: 24201 bytes --]

Index: lisp/server.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/server.el,v
retrieving revision 1.113
diff -b -u -2 -r1.113 server.el
--- lisp/server.el	6 Jul 2006 22:48:16 -0000	1.113
+++ lisp/server.el	26 Oct 2006 23:06:08 -0000
@@ -83,4 +83,33 @@
   :group 'external)
 
+(defcustom server-use-tcp nil
+  "If non-nil, use TCP sockets instead of local sockets."
+  :set #'(lambda (sym val)
+           (if (featurep 'make-network-process '(:family local))
+               (set-default sym val)
+             (unless load-in-progress
+               (message "Local sockets unsupported, using TCP sockets"))
+             (set-default sym t)))
+  :group 'server
+  :type 'boolean
+  :version "22.1")
+
+(defcustom server-host nil
+  "The name or IP address to use as host address of the server process.
+If set, the server accepts remote connections; otherwise it is local."
+  :group 'server
+  :type '(choice
+          (string :tag "Name or IP address")
+          (const :tag "Local" nil))
+  :version "22.1")
+(put 'server-host 'risky-local-variable t)
+
+(defcustom server-auth-dir "~/.emacs.d/server/"
+  "Directory for server authentication files."
+  :group 'server
+  :type 'directory
+  :version "22.1")
+(put 'server-auth-dir 'risky-local-variable t)
+
 (defcustom server-visit-hook nil
   "*Hook run when visiting a file for the Emacs server."
@@ -101,4 +130,7 @@
   "The current server process.")
 
+(defvar server-auth-string nil
+  "The current server authentication string.")
+
 (defvar server-clients nil
   "List of current server clients.
@@ -232,11 +264,22 @@
   (let ((attrs (file-attributes dir)))
     (unless attrs
-      (letf (((default-file-modes) ?\700)) (make-directory dir))
+      (letf (((default-file-modes) ?\700)) (make-directory dir t))
       (setq attrs (file-attributes dir)))
     ;; Check that it's safe for use.
     (unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
-		 (zerop (logand ?\077 (file-modes dir))))
+                 (or (eq system-type 'windows-nt)
+                     (zerop (logand ?\077 (file-modes dir)))))
       (error "The directory %s is unsafe" dir))))
 
+(defun server-auth-string ()
+  (or server-auth-string
+      ;; If the authentication string does not exist, create it on the fly:
+      ;; it's a 64-byte string of random chars in the range `!'..`~'.
+      (setq server-auth-string
+	    (loop
+	       for i below 64
+	       collect (+ 33 (random 94)) into auth
+	       finally return (concat auth)))))
+
 ;;;###autoload
 (defun server-start (&optional leave-dead)
@@ -249,11 +292,13 @@
 Prefix arg means just kill any existing server communications subprocess."
   (interactive "P")
+  (when server-process
   ;; kill it dead!
-  (if server-process
-      (condition-case () (delete-process server-process) (error nil)))
-  ;; Delete the socket files made by previous server invocations.
-  (condition-case ()
+    (ignore-errors (delete-process server-process))
+    (ignore-errors
+      ;; Delete the socket or authentication files made by previous server invocations.
+      (if (eq (process-contact server-process :family) 'local)
       (delete-file (expand-file-name server-name server-socket-dir))
-    (error nil))
+        (setq server-auth-string nil)
+        (delete-file (expand-file-name server-name server-auth-dir)))))
   ;; If this Emacs already had a server, clear out associated status.
   (while server-clients
@@ -263,17 +308,35 @@
   (unless leave-dead
     ;; Make sure there is a safe directory in which to place the socket.
-    (server-ensure-safe-dir server-socket-dir)
-    (if server-process
+    (server-ensure-safe-dir (if server-use-tcp server-auth-dir server-socket-dir))
+    (when server-process
 	(server-log (message "Restarting server")))
     (letf (((default-file-modes) ?\700))
       (setq server-process
-	    (make-network-process
-	     :name "server" :family 'local :server t :noquery t
-	     :service (expand-file-name server-name server-socket-dir)
-	     :sentinel 'server-sentinel :filter 'server-process-filter
+            (apply #'make-network-process
+                   :name server-name
+                   :server t
+                   :noquery t
+                   :sentinel 'server-sentinel
+                   :filter 'server-process-filter
 	     ;; We must receive file names without being decoded.
 	     ;; Those are decoded by server-process-filter according
 	     ;; to file-name-coding-system.
-	     :coding 'raw-text)))))
+                   :coding 'raw-text
+                   ;; The rest of the arguments depend on the kind of socket used
+                   (if server-use-tcp
+                       (list :family nil
+                             :service t
+                             :host (or server-host 'local)
+                             :plist '(:authenticated nil))
+                     (list :family 'local
+                           :service (expand-file-name server-name server-socket-dir)
+                           :plist '(:authenticated t))))))
+    (unless server-process (error "Could not start server process"))
+    (when server-use-tcp
+      (with-temp-file (expand-file-name server-name server-auth-dir)
+        (set-buffer-multibyte nil)
+        (setq buffer-file-coding-system 'no-conversion)
+        (insert (format-network-address (process-contact server-process :local))
+                "\n" (server-auth-string))))))
 
 ;;;###autoload
@@ -290,12 +353,23 @@
   (server-start (not server-mode)))
 \f
-(defun server-process-filter (proc string)
+(defun* server-process-filter (proc string)
   "Process a request from the server to edit some files.
 PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
+  ;; First things first: let's check the authentication
+  (unless (process-get proc :authenticated)
+    (if (and (string-match "-auth \\(.*?\\)\n" string)
+             (string= (match-string 1 string) server-auth-string))
+        (progn
+          (setq string (substring string (match-end 0)))
+          (process-put proc :authenticated t)
+          (server-log "Authentication successful" proc))
+      (server-log "Authentication failed" proc)
+      (delete-process proc)
+      (return-from server-process-filter)))
   (server-log string proc)
-  (let ((prev (process-get proc 'previous-string)))
+  (let ((prev (process-get proc :previous-string)))
     (when prev
       (setq string (concat prev string))
-      (process-put proc 'previous-string nil)))
+      (process-put proc :previous-string nil)))
   ;; If the input is multiple lines,
   ;; process each line individually.
@@ -390,5 +464,5 @@
   ;; Save for later any partial line that remains.
   (when (> (length string) 0)
-    (process-put proc 'previous-string string)))
+    (process-put proc :previous-string string)))
 
 (defun server-goto-line-column (file-line-col)
Index: lib-src/emacsclient.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/emacsclient.c,v
retrieving revision 1.77
diff -b -u -2 -r1.77 emacsclient.c
--- lib-src/emacsclient.c	18 Jul 2006 16:33:45 -0000	1.77
+++ lib-src/emacsclient.c	27 Oct 2006 00:06:01 -0000
@@ -27,9 +27,14 @@
 #endif
 
+#ifdef WINDOWSNT
+#define HAVE_SOCKETS
+#define NO_SOCKETS_IN_FILE_SYSTEM
+#endif
+
 #undef signal
 
 #include <ctype.h>
 #include <stdio.h>
-#include <getopt.h>
+#include "getopt.h"
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -38,6 +43,10 @@
 #ifdef VMS
 # include "vms-pwd.h"
-#else
+#else /* not VMS */
+#ifdef WINDOWSNT
+# include <io.h>
+#else /* not WINDOWSNT */
 # include <pwd.h>
+#endif /* not WINDOWSNT */
 #endif /* not VMS */
 
@@ -49,4 +58,19 @@
 #endif
 \f
+#define SEND_STRING(data) (send_to_emacs (s, (data)))
+#define SEND_QUOTED(data) (quote_file_name (s, (data)))
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+#ifndef NO_RETURN
+#define NO_RETURN
+#endif
+\f
 /* Name used to invoke this program.  */
 char *progname;
@@ -68,4 +92,7 @@
 char *socket_name = NULL;
 
+/* If non-NULL, the filename of the authentication file.  */
+char *server_file = NULL;
+
 void print_help_and_exit () NO_RETURN;
 
@@ -78,4 +105,5 @@
   { "alternate-editor", required_argument, NULL, 'a' },
   { "socket-name",	required_argument, NULL, 's' },
+  { "server-file",	required_argument, NULL, 'f' },
   { "display",	required_argument, NULL, 'd' },
   { 0, 0, 0, 0 }
@@ -91,9 +119,10 @@
 {
   alternate_editor = getenv ("ALTERNATE_EDITOR");
+  server_file = getenv ("EMACS_SERVER_FILE");
 
   while (1)
     {
       int opt = getopt_long (argc, argv,
-			     "VHnea:s:d:", longopts, 0);
+			     "VHnea:s:f:d:", longopts, 0);
 
       if (opt == EOF)
@@ -115,4 +144,8 @@
 	  break;
 
+	case 'f':
+	  server_file = optarg;
+	  break;
+
 	case 'd':
 	  display = optarg;
@@ -158,6 +191,12 @@
 -e, --eval              Evaluate the FILE arguments as ELisp expressions\n\
 -d, --display=DISPLAY   Visit the file in the given display\n\
--s, --socket-name=FILENAME\n\
+"
+#ifndef NO_SOCKETS_IN_FILE_SYSTEM
+"-s, --socket-name=FILENAME\n\
                         Set the filename of the UNIX socket for communication\n\
+"
+#endif
+"-f, --server-file=FILENAME\n\
+			Set the filename of the TCP configuration file\n\
 -a, --alternate-editor=EDITOR\n\
                         Editor to fallback to if the server is not running\n\
@@ -167,12 +206,108 @@
 }
 
+\f
+/*
+  Try to run a different command, or --if no alternate editor is
+  defined-- exit with an errorcode.
+*/
+void
+fail (argc, argv)
+     int argc;
+     char **argv;
+{
+  if (alternate_editor)
+    {
+      int i = optind - 1;
+      execvp (alternate_editor, argv + i);
+      return;
+    }
+  else
+    {
+      exit (EXIT_FAILURE);
+    }
+}
+
+\f
+#if !defined (HAVE_SOCKETS)
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
+	   argv[0]);
+  fprintf (stderr, "on systems with Berkeley sockets.\n");
+
+  fail (argc, argv);
+}
+
+#else /* HAVE_SOCKETS */
+
+#define AUTH_STRING_LENGTH   64
+#define SEND_BUFFER_SIZE   4096
+
+#ifdef WINDOWSNT
+# include <winsock2.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <sys/stat.h>
+# include <errno.h>
+#endif
+
+extern char *strerror ();
+extern int errno;
+
+/* Buffer to accumulate data to send in TCP connections.  */
+char send_buffer[SEND_BUFFER_SIZE + 1];
+int sblen = 0;	/* Fill pointer for the send buffer.  */
+
+/* Let's send the data to Emacs when either
+   - the data ends in "\n", or
+   - the buffer is full (but this shouldn't happen)
+   Otherwise, we just accumulate it.  */
+void send_to_emacs (s, data)
+     SOCKET s;
+     char *data;
+{
+  while (data)
+    {
+      int dlen = strlen (data);
+      if (dlen + sblen >= SEND_BUFFER_SIZE)
+	{
+	  int part = SEND_BUFFER_SIZE - sblen;
+	  strncpy (&send_buffer[sblen], data, part);
+	  data += part;
+	  sblen = SEND_BUFFER_SIZE;
+	}
+      else if (dlen)
+	{
+	  strcpy (&send_buffer[sblen], data);
+	  data = NULL;
+	  sblen += dlen;
+	}
+      else
+	break;
+
+      if (sblen == SEND_BUFFER_SIZE
+	  || (sblen > 0 && send_buffer[sblen-1] == '\n'))
+	{
+	  int sent = send (s, send_buffer, sblen, 0);
+	  if (sent != sblen)
+	    strcpy (send_buffer, &send_buffer[sent]);
+	  sblen -= sent;
+	}
+    }
+}
+
 /* In NAME, insert a & before each &, each space, each newline, and
    any initial -.  Change spaces to underscores, too, so that the
    return value never contains a space.  */
-
 void
-quote_file_name (name, stream)
+quote_file_name (s, name)
+     SOCKET s;
      char *name;
-     FILE *stream;
 {
   char *copy = (char *) malloc (strlen (name) * 2 + 1);
@@ -204,71 +339,125 @@
   *q++ = 0;
 
-  fprintf (stream, "%s", copy);
+  SEND_STRING (copy);
 
   free (copy);
 }
 
-/* Like malloc but get fatal error if memory is exhausted.  */
+#ifdef WINDOWSNT
+/* Wrapper to make WSACleanup a cdecl, as required by atexit().	 */
+void close_winsock ()
+{
+  WSACleanup ();
+}
+#endif /* WINDOWSNT */
 
-long *
-xmalloc (size)
-     unsigned int size;
+void initialize_sockets ()
 {
-  long *result = (long *) malloc (size);
-  if (result == NULL)
+#ifdef WINDOWSNT
+  WSADATA wsaData;
+
+  /* Initialize the WinSock2 library.  */
+  if (WSAStartup (MAKEWORD (2, 0), &wsaData))
   {
-    perror ("malloc");
+      fprintf (stderr, "%s: error initializing WinSock2", progname);
     exit (EXIT_FAILURE);
   }
-  return result;
+
+  atexit (close_winsock);
+#endif /* WINDOWSNT */
 }
 \f
 /*
-  Try to run a different command, or --if no alternate editor is
-  defined-- exit with an errorcode.
+ * Read the information needed to set up a TCP comm channel with
+ * the Emacs server: host, port and authentication string.
 */
-void
-fail (argc, argv)
-     int argc;
-     char **argv;
+void get_server_config (server, authentication)
+     struct sockaddr_in *server;
+     char *authentication;
 {
-  if (alternate_editor)
+  FILE *config;
+  char dotted[32];
+  char *port;
+
+  if (! (config = fopen (server_file, "rb")))
     {
-      int i = optind - 1;
-      execvp (alternate_editor, argv + i);
-      return;
+      fprintf (stderr, "%s: cannot read configuration file %s",
+	       progname, server_file);
+      exit (EXIT_FAILURE);
+    }
+
+  if (fgets (dotted, sizeof dotted, config)
+      && (port = strchr (dotted, ':')))
+    {
+      *port++ = '\0';
     }
   else
     {
+      fprintf (stderr, "%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_STRING_LENGTH, 1, config))
+    {
+      fprintf (stderr, "%s: cannot read authentication info", progname);
+      exit (EXIT_FAILURE);
+    }
 \f
-#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
+  fclose (config);
+}
 
-int
-main (argc, argv)
-     int argc;
-     char **argv;
+SOCKET
+set_tcp_socket ()
 {
-  fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
-	   argv[0]);
-  fprintf (stderr, "on systems with Berkeley sockets.\n");
+  SOCKET s;
+  struct sockaddr_in server;
+  unsigned long c_arg = 0;
+  struct linger l_arg = {1, 1};
+  char auth_string[AUTH_STRING_LENGTH + 1];
 
-  fail (argc, argv);
-}
+  initialize_sockets ();
 
-#else /* HAVE_SOCKETS */
+  get_server_config (&server, auth_string);
 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <errno.h>
+  /*
+   * Open up an AF_INET socket
+   */
+  if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+    {
+      fprintf (stderr, "%s: ", progname);
+      perror ("socket");
+      return INVALID_SOCKET;
+    }
 
-extern char *strerror ();
-extern int errno;
+  /*
+   * Set up the socket
+   */
+  if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
+    {
+      fprintf (stderr, "%s: ", progname);
+      perror ("connect");
+      return INVALID_SOCKET;
+    }
+
+  ioctlsocket (s, FIONBIO, &c_arg);
+  setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
+
+  /*
+   * Send the authentication
+   */
+  auth_string[AUTH_STRING_LENGTH] = '\0';
+
+  SEND_STRING ("-auth ");
+  SEND_STRING (auth_string);
+  SEND_STRING ("\n");
+
+  return s;
+}
+
+#if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
 
 /* Three possibilities:
@@ -292,26 +481,9 @@
 }
 
-int
-main (argc, argv)
-     int argc;
-     char **argv;
+SOCKET
+set_local_socket ()
 {
-  int s, i, needlf = 0;
-  FILE *out, *in;
+  SOCKET s;
   struct sockaddr_un server;
-  char *cwd, *str;
-  char string[BUFSIZ];
-
-  progname = argv[0];
-
-  /* Process options.  */
-  decode_options (argc, argv);
-
-  if ((argc - optind < 1) && !eval)
-    {
-      fprintf (stderr, "%s: file name or argument required\n", progname);
-      fprintf (stderr, "Try `%s --help' for more information\n", progname);
-      exit (EXIT_FAILURE);
-    }
 
   /*
@@ -321,7 +493,7 @@
   if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
     {
-      fprintf (stderr, "%s: ", argv[0]);
+      fprintf (stderr, "%s: ", progname);
       perror ("socket");
-      fail (argc, argv);
+      return INVALID_SOCKET;
     }
 
@@ -353,5 +525,5 @@
       {
 	fprintf (stderr, "%s: socket-name %s too long",
-		 argv[0], socket_name);
+		 progname, socket_name);
 	exit (EXIT_FAILURE);
       }
@@ -388,5 +560,5 @@
 		  {
 		    fprintf (stderr, "%s: socket-name %s too long",
-			     argv[0], socket_name);
+			     progname, socket_name);
 		    exit (EXIT_FAILURE);
 		  }
@@ -408,5 +580,5 @@
 	   {
 	     fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
-	     fail (argc, argv);
+	    return INVALID_SOCKET;
 	   }
 	 break;
@@ -418,10 +590,9 @@
 		    "%s: can't find socket; have you started the server?\n\
 To start the server in Emacs, type \"M-x server-start\".\n",
-		    argv[0]);
+		   progname);
 	 else
 	   fprintf (stderr, "%s: can't stat %s: %s\n",
-		    argv[0], server.sun_path, strerror (saved_errno));
-	 fail (argc, argv);
-	 break;
+		   progname, server.sun_path, strerror (saved_errno));
+	return INVALID_SOCKET;
        }
   }
@@ -430,29 +601,54 @@
       < 0)
     {
-      fprintf (stderr, "%s: ", argv[0]);
+      fprintf (stderr, "%s: ", progname);
       perror ("connect");
-      fail (argc, argv);
+      return INVALID_SOCKET;
     }
 
-  /* We use the stream OUT to send our command to the server.  */
-  if ((out = fdopen (s, "r+")) == NULL)
+  return s;
+}
+#endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
+
+SOCKET
+set_socket ()
+{
+  if (server_file)
+    return set_tcp_socket ();
+  else
+#ifndef NO_SOCKETS_IN_FILE_SYSTEM
+    return set_local_socket ();
+#else
     {
-      fprintf (stderr, "%s: ", argv[0]);
-      perror ("fdopen");
-      fail (argc, argv);
+      fprintf (stderr, "%s: missing --server-file option", progname);
+      exit (EXIT_FAILURE);
     }
+#endif
+}
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  SOCKET s;
+  int i, rl, needlf = 0;
+  char *cwd;
+  char string[BUFSIZ+1];
+
+  progname = argv[0];
 
-  /* We use the stream IN to read the response.
-     We used to use just one stream for both output and input
-     on the socket, but reversing direction works nonportably:
-     on some systems, the output appears as the first input;
-     on other systems it does not.  */
-  if ((in = fdopen (s, "r+")) == NULL)
+  /* Process options.  */
+  decode_options (argc, argv);
+
+  if ((argc - optind < 1) && !eval)
     {
-      fprintf (stderr, "%s: ", argv[0]);
-      perror ("fdopen");
-      fail (argc, argv);
+      fprintf (stderr, "%s: file name or argument required\n", progname);
+      fprintf (stderr, "Try `%s --help' for more information\n", progname);
+      exit (EXIT_FAILURE);
     }
 
+  if ((s = set_socket ()) == INVALID_SOCKET)
+    fail (argc, argv);
+
 #ifdef HAVE_GETCWD
   cwd = getcwd (string, sizeof string);
@@ -465,8 +661,8 @@
 
 #ifdef HAVE_GETCWD
-      fprintf (stderr, "%s: %s (%s)\n", argv[0],
+      fprintf (stderr, "%s: %s (%s)\n", progname,
 	       "Cannot get current working directory", strerror (errno));
 #else
-      fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
+      fprintf (stderr, "%s: %s (%s)\n", progname, string, strerror (errno));
 #endif
       fail (argc, argv);
@@ -474,14 +670,14 @@
 
   if (nowait)
-    fprintf (out, "-nowait ");
+    SEND_STRING ("-nowait ");
 
   if (eval)
-    fprintf (out, "-eval ");
+    SEND_STRING ("-eval ");
 
   if (display)
     {
-      fprintf (out, "-display ");
-      quote_file_name (display, out);
-      fprintf (out, " ");
+      SEND_STRING ("-display ");
+      SEND_QUOTED (display);
+      SEND_STRING (" ");
     }
 
@@ -498,34 +694,41 @@
 	      if (*p != 0)
 		{
-		  quote_file_name (cwd, out);
-		  fprintf (out, "/");
+		  SEND_QUOTED (cwd);
+		  SEND_STRING ("/");
 		}
 	    }
+#ifndef WINDOWSNT
 	  else if (*argv[i] != '/')
+#else
+	  else if ((*argv[i] != '/')
+		   /* Absolute paths can also start with backslash
+		      or drive letters.	 */
+		   && (*argv[i] != '\\')
+		   && (!islower (tolower (*argv[i]))
+		       || (argv[i][1] != ':')))
+#endif
 	    {
-	      quote_file_name (cwd, out);
-	      fprintf (out, "/");
+	      SEND_QUOTED (cwd);
+	      SEND_STRING ("/");
 	    }
 
-	  quote_file_name (argv[i], out);
-	  fprintf (out, " ");
+	  SEND_QUOTED (argv[i]);
+	  SEND_STRING (" ");
 	}
     }
   else
     {
-      while ((str = fgets (string, BUFSIZ, stdin)))
+      while (fgets (string, BUFSIZ, stdin))
 	{
-	  quote_file_name (str, out);
+	  SEND_QUOTED (string);
 	}
-      fprintf (out, " ");
+      SEND_STRING (" ");
     }
 
-  fprintf (out, "\n");
-  fflush (out);
+  SEND_STRING ("\n");
 
   /* Maybe wait for an answer.   */
-  if (nowait)
-    return EXIT_SUCCESS;
-
+  if (!nowait)
+    {
   if (!eval)
     {
@@ -536,10 +739,11 @@
 
   /* Now, wait for an answer and print any messages.  */
-  while ((str = fgets (string, BUFSIZ, in)))
+      while ((rl = recv (s, string, BUFSIZ, 0)) > 0)
     {
+	  string[rl] = '\0';
       if (needlf == 2)
 	printf ("\n");
-      printf ("%s", str);
-      needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
+	  printf ("%s", string);
+	  needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n';
     }
 
@@ -547,5 +751,7 @@
     printf ("\n");
   fflush (stdout);
+    }
 
+  closesocket (s);
   return EXIT_SUCCESS;
 }
Index: lib-src/makefile.w32-in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/makefile.w32-in,v
retrieving revision 2.46
diff -b -u -2 -r2.46 makefile.w32-in
--- lib-src/makefile.w32-in	9 Oct 2006 19:57:43 -0000	2.46
+++ lib-src/makefile.w32-in	26 Oct 2006 22:23:12 -0000
@@ -21,5 +21,5 @@
 #
 
-ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc
+ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc emacsclient
 
 .PHONY: $(ALL)
@@ -33,5 +33,4 @@
 #		$(BLD)/server.exe	\
 #		$(BLD)/emacstool.exe	\
-#		$(BLD)/emacsclient.exe	\
 #		$(BLD)/cvtmail.exe	\
 
@@ -60,4 +59,5 @@
 sorted-doc:	$(BLD) $(BLD)/sorted-doc.exe
 digest-doc:	$(BLD) $(BLD)/digest-doc.exe
+emacsclient:	$(BLD) $(BLD)/emacsclient.exe
 
 test-distrib:	$(BLD) $(BLD)/test-distrib.exe
@@ -75,4 +75,17 @@
 		$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(MOVEMAILOBJS) $(WSOCK32) $(LIBS)
 
+ECLIENT_CFLAGS = -DWINDOWSNT -DHAVE_GETCWD -DHAVE_STRERROR -c
+ECLIENTOBJS =	$(BLD)/emacsclient.$(O) \
+		$(BLD)/getopt.$(O) \
+		$(BLD)/getopt1.$(O) \
+		$(BLD)/ntlib.$(O)
+
+$(BLD)/emacsclient.exe:		$(ECLIENTOBJS)
+# put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib
+		$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(LIBS)
+
+$(BLD)/emacsclient.$(O):	emacsclient.c
+		$(CC) $(ECLIENT_CFLAGS) $(CC_OUT)$@ emacsclient.c
+
 ETAGSOBJ      = $(BLD)/etags.$(O) \
 		$(BLD)/getopt.$(O) \
@@ -297,4 +310,5 @@
 		$(CP) $(BLD)/sorted-doc.exe $(INSTALL_DIR)/bin
 		$(CP) $(BLD)/digest-doc.exe $(INSTALL_DIR)/bin
+		$(CP) $(BLD)/emacsclient.exe $(INSTALL_DIR)/bin
 		- mkdir "$(INSTALL_DIR)/etc"
 		$(CP) $(DOC) $(INSTALL_DIR)/etc

[-- Attachment #4: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27  0:27         ` Juanma Barranquero
@ 2006-10-27 11:08           ` Juanma Barranquero
  2006-10-27 12:21             ` Jason Rumney
  2006-10-28  7:27             ` Richard Stallman
  0 siblings, 2 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-27 11:08 UTC (permalink / raw)


Two additional notes:

  - Currently, when emacsclient fails the authentication check, it
just ends (because Emacs closes the connection). Should it give an
error message?

  - server.el generates the authentication string with `random', but
Emacs uses the same seed every time. I'm reluctant to call (random t)
in server.el; Emacs doesn't do it for a good reason (repeatability).
The problem is not critical (Emacs won't accept remote connections
unless the user customizes `server-host'), but two users on the same
machine will be able to connect to each other's Emacs servers... I
suppose the "fix" is adding a note in the docs instructing people who
uses TCP sockets with server.el to add (random t) to their .emacs.el.

(Perhaps adding a function (random-seed SEED) which would change the
seed and return the previous one would be useful; it'd allow defining
a macro `with-temp-seed'... but I digress.)

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 11:08           ` Juanma Barranquero
@ 2006-10-27 12:21             ` Jason Rumney
  2006-10-27 13:25               ` Stefan Monnier
  2006-10-27 13:29               ` Juanma Barranquero
  2006-10-28  7:27             ` Richard Stallman
  1 sibling, 2 replies; 54+ messages in thread
From: Jason Rumney @ 2006-10-27 12:21 UTC (permalink / raw)
  Cc: Emacs Devel

Juanma Barranquero wrote:
>  - server.el generates the authentication string with `random', but
> Emacs uses the same seed every time. I'm reluctant to call (random t)
> in server.el; Emacs doesn't do it for a good reason (repeatability).

I don't think repeatability is realistic within Emacs, because a Lisp 
function cannot have any control over other functions that might have 
called random before it. If repeatability is desired, then we need a 
function to set the random seed to a known value, so Lisp code that 
requires repeatability can call it at the start of its psuedorandom 
number generation. As far as I can tell, no such function exists.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 12:21             ` Jason Rumney
@ 2006-10-27 13:25               ` Stefan Monnier
  2006-10-27 13:35                 ` Juanma Barranquero
  2006-10-27 13:29               ` Juanma Barranquero
  1 sibling, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-27 13:25 UTC (permalink / raw)
  Cc: Juanma Barranquero, Emacs Devel

> I don't think repeatability is realistic within Emacs, because a Lisp
> function cannot have any control over other functions that might have called
> random before it.  If repeatability is desired, then we need a function to
> set the random seed to a known value, so Lisp code that requires
> repeatability can call it at the start of its psuedorandom number
> generation. As far as I can tell, no such function exists.

Agreed.  A quick "grep '(random t)' **/*.el" shows that many packages freely
use (random t).  I think Emacs should do a (random t) at startup.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 12:21             ` Jason Rumney
  2006-10-27 13:25               ` Stefan Monnier
@ 2006-10-27 13:29               ` Juanma Barranquero
  2006-10-27 13:50                 ` Slawomir Nowaczyk
  2006-10-27 14:20                 ` Stefan Monnier
  1 sibling, 2 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-27 13:29 UTC (permalink / raw)


On 10/27/06, Jason Rumney <jasonr@gnu.org> wrote:

> I don't think repeatability is realistic within Emacs,
> because a Lisp function cannot have any control over
> other functions that might have
> called random before it.

Still, if the initial seed is always the same and you control the code
that runs, you can have repeatability. Viz the current situation,
where I'm getting the same authentication string in different
invocations of Emacs :)

> If repeatability is desired, then we need a
> function to set the random seed to a known value,
> so Lisp code that requires repeatability can call
> it at the start of its psuedorandom number generation.

...which is exactly what I was proposing with (random-seed SEED) and
`with-tmp-seed' (or perhaps `with-current-seed') :)

But all this has no bearing on the emacsclient/server issue. All I
need to know is whether people thinks is better to call (random t) in
server.el, or note the need to do so in the documentation.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 13:25               ` Stefan Monnier
@ 2006-10-27 13:35                 ` Juanma Barranquero
  0 siblings, 0 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-27 13:35 UTC (permalink / raw)


On 10/27/06, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> Agreed.  A quick "grep '(random t)' **/*.el" shows that many packages freely
> use (random t).

I wouldn't say "many": allout.el, type-break.el, calc/calc-comb.el,
gnus/message.el and (unsurprisingly) a bunch of play/*.el files. All
in all, I'd say I hardly ever use any of them.

> I think Emacs should do a (random t) at startup.

Agreed.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 13:29               ` Juanma Barranquero
@ 2006-10-27 13:50                 ` Slawomir Nowaczyk
  2006-10-27 14:20                 ` Stefan Monnier
  1 sibling, 0 replies; 54+ messages in thread
From: Slawomir Nowaczyk @ 2006-10-27 13:50 UTC (permalink / raw)


On Fri, 27 Oct 2006 15:29:19 +0200
Juanma Barranquero <lekktu@gmail.com> wrote:

#> But all this has no bearing on the emacsclient/server issue. All I
#> need to know is whether people thinks is better to call (random t) in
#> server.el, or note the need to do so in the documentation.

Better to call it in server.el, IMHO.

If you *really* feel paranoid about that, provide a user option to
disable, but since this is pretty important for security, server.el
should -- by default -- call (random t).

-- 
 Best wishes,
   Slawomir Nowaczyk
     ( slawomir.nowaczyk.847@student.lu.se )

The greatest enemy of a good plan is the dream of a perfect plan.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 13:29               ` Juanma Barranquero
  2006-10-27 13:50                 ` Slawomir Nowaczyk
@ 2006-10-27 14:20                 ` Stefan Monnier
  2006-10-27 15:18                   ` Juanma Barranquero
  1 sibling, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-27 14:20 UTC (permalink / raw)
  Cc: Emacs Devel

> ...which is exactly what I was proposing with (random-seed SEED) and
> `with-tmp-seed' (or perhaps `with-current-seed') :)

> But all this has no bearing on the emacsclient/server issue. All I
> need to know is whether people thinks is better to call (random t) in
> server.el, or note the need to do so in the documentation.

Just call (random t) and forget about it.
Don't lose your sleep over it, it's really not worth it.


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 14:20                 ` Stefan Monnier
@ 2006-10-27 15:18                   ` Juanma Barranquero
  2006-10-28 18:13                     ` Richard Stallman
  2006-10-30  1:02                     ` Stefan Monnier
  0 siblings, 2 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-27 15:18 UTC (permalink / raw)


On 10/27/06, Slawomir Nowaczyk wrote:

> If you *really* feel paranoid about that, provide a
> user option to disable, but since this is pretty
> important for security, server.el should -- by default
> -- call (random t).

Not paranoid at all, just trying to be a good citizen.

I've now set it up so (random t) is called when `server-use-tcp' is
set to t (which includes customize-variable, and also the
initialization if ":family 'local" is not supported).


On 10/27/06, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> Just call (random t) and forget about it.

Done.

BTW, I'd *really* like for someone to test the changes and comment on
my other questions.

Otherwise, I'm just gonna commit the code and wait for the fireworks :)

                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
       [not found]                 ` <f7ccd24b0610271700v472f9c53v43017fce05e761e9@mail.gmail.com>
@ 2006-10-28  0:24                   ` Juanma Barranquero
  0 siblings, 0 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-28  0:24 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 905 bytes --]

Updated patch; mainly changes in emacsclient.c:

 - Now --server-file=xxx (or EMACS_SERVER_FILE=xxx) tries to open:
   - "xxx" (as an absolute or relative path)
   - "%HOME%/.emacs.d/server/xxx"
   - "%APPDATA%/.emacs.d/server/xxx" (on Windows)
 - With no --server-file, it tries to open a local socket.
  - If no --server-file and no local sockets, acts like
"--server-file=server" (which is the same default that server.el
uses).

Some more unresolved questions:

  - Ideas about making server.el bring the frame to the front? Also,
making it compatible with pop-up-frames = t (requested by Drew).

  - In GNU/Linux, is the above search sequence the right one, or
should it use getpwnam (...)->pw_dir to locate the user home
directory?

(Note: I'm beating this into shape with the idea of installing it in
the next few days; I sure hope the pretest is not a problem...)

                     /L/e/k/t/u

[-- Attachment #2: newserver-u.patch --]
[-- Type: application/octet-stream, Size: 32111 bytes --]

Index: lisp/server.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/server.el,v
retrieving revision 1.113
diff -u -2 -r1.113 server.el
--- lisp/server.el	6 Jul 2006 22:48:16 -0000	1.113
+++ lisp/server.el	27 Oct 2006 22:02:28 -0000
@@ -83,4 +83,38 @@
   :group 'external)
 
+(defcustom server-use-tcp nil
+  "If non-nil, use TCP sockets instead of local sockets."
+  :set #'(lambda (sym val)
+           (unless (featurep 'make-network-process '(:family local))
+             (setq val t)
+             (unless load-in-progress
+               (message "Local sockets unsupported, using TCP sockets")))
+           (when val (random t))
+           (set-default sym val))
+  :group 'server
+  :type 'boolean
+  :version "22.1")
+
+(defcustom server-host nil
+  "The name or IP address to use as host address of the server process.
+If set, the server accepts remote connections; otherwise it is local."
+  :group 'server
+  :type '(choice
+          (string :tag "Name or IP address")
+          (const :tag "Local" nil))
+  :version "22.1")
+(put 'server-host 'risky-local-variable t)
+
+(defcustom server-auth-dir "~/.emacs.d/server/"
+  "Directory for server authentication files."
+  :group 'server
+  :type 'directory
+  :version "22.1")
+(put 'server-auth-dir 'risky-local-variable t)
+
+(defvar server-auth-key nil
+  "The current server authentication key.")
+(put 'server-auth-key 'risky-local-variable t)
+
 (defcustom server-visit-hook nil
   "*Hook run when visiting a file for the Emacs server."
@@ -167,11 +201,11 @@
 (defun server-log (string &optional client)
   "If a *server* buffer exists, write STRING to it for logging purposes."
-  (if (get-buffer "*server*")
-      (with-current-buffer "*server*"
-	(goto-char (point-max))
-	(insert (current-time-string)
-		(if client (format " %s:" client) " ")
-		string)
-	(or (bolp) (newline)))))
+  (when (get-buffer "*server*")
+    (with-current-buffer "*server*"
+      (goto-char (point-max))
+      (insert (current-time-string)
+	      (if client (format " %s:" client) " ")
+	      string)
+      (or (bolp) (newline)))))
 
 (defun server-sentinel (proc msg)
@@ -232,9 +266,10 @@
   (let ((attrs (file-attributes dir)))
     (unless attrs
-      (letf (((default-file-modes) ?\700)) (make-directory dir))
+      (letf (((default-file-modes) ?\700)) (make-directory dir t))
       (setq attrs (file-attributes dir)))
     ;; Check that it's safe for use.
     (unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
-		 (zerop (logand ?\077 (file-modes dir))))
+                 (or (eq system-type 'windows-nt)
+                     (zerop (logand ?\077 (file-modes dir)))))
       (error "The directory %s is unsafe" dir))))
 
@@ -249,11 +284,13 @@
 Prefix arg means just kill any existing server communications subprocess."
   (interactive "P")
+  (when server-process
   ;; kill it dead!
-  (if server-process
-      (condition-case () (delete-process server-process) (error nil)))
-  ;; Delete the socket files made by previous server invocations.
-  (condition-case ()
+    (ignore-errors (delete-process server-process))
+    (ignore-errors
+      ;; Delete the socket or authentication files made by previous server invocations.
+      (if (eq (process-contact server-process :family) 'local)
       (delete-file (expand-file-name server-name server-socket-dir))
-    (error nil))
+        (setq server-auth-key nil)
+        (delete-file (expand-file-name server-name server-auth-dir)))))
   ;; If this Emacs already had a server, clear out associated status.
   (while server-clients
@@ -263,17 +300,41 @@
   (unless leave-dead
     ;; Make sure there is a safe directory in which to place the socket.
-    (server-ensure-safe-dir server-socket-dir)
-    (if server-process
+    (server-ensure-safe-dir (if server-use-tcp server-auth-dir server-socket-dir))
+    (when server-process
 	(server-log (message "Restarting server")))
     (letf (((default-file-modes) ?\700))
       (setq server-process
-	    (make-network-process
-	     :name "server" :family 'local :server t :noquery t
-	     :service (expand-file-name server-name server-socket-dir)
-	     :sentinel 'server-sentinel :filter 'server-process-filter
+            (apply #'make-network-process
+                   :name server-name
+                   :server t
+                   :noquery t
+                   :sentinel 'server-sentinel
+                   :filter 'server-process-filter
 	     ;; We must receive file names without being decoded.
 	     ;; Those are decoded by server-process-filter according
 	     ;; to file-name-coding-system.
-	     :coding 'raw-text)))))
+                   :coding 'raw-text
+                   ;; The rest of the arguments depend on the kind of socket used
+                   (if server-use-tcp
+                       (list :family nil
+                             :service t
+                             :host (or server-host 'local)
+                             :plist '(:authenticated nil))
+                     (list :family 'local
+                           :service (expand-file-name server-name server-socket-dir)
+                           :plist '(:authenticated t))))))
+    (unless server-process (error "Could not start server process"))
+    (when server-use-tcp
+      (setq server-auth-key
+	    (loop
+               ;; The auth key is a 64-byte string of random chars in the range `!'..`~'.
+	       for i below 64
+	       collect (+ 33 (random 94)) into auth
+	       finally return (concat auth)))
+      (with-temp-file (expand-file-name server-name server-auth-dir)
+        (set-buffer-multibyte nil)
+        (setq buffer-file-coding-system 'no-conversion)
+        (insert (format-network-address (process-contact server-process :local))
+                "\n" server-auth-key)))))
 
 ;;;###autoload
@@ -290,12 +351,24 @@
   (server-start (not server-mode)))
 \f
-(defun server-process-filter (proc string)
+(defun* server-process-filter (proc string)
   "Process a request from the server to edit some files.
 PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
+  ;; First things first: let's check the authentication
+  (unless (process-get proc :authenticated)
+    (if (and (string-match "-auth \\(.*?\\)\n" string)
+             (string= (match-string 1 string) server-auth-key))
+        (progn
+          (setq string (substring string (match-end 0)))
+          (process-put proc :authenticated t)
+          (server-log "Authentication successful" proc))
+      (server-log "Authentication failed" proc)
+      (delete-process proc)
+      ;; We return immediately
+      (return-from server-process-filter)))
   (server-log string proc)
-  (let ((prev (process-get proc 'previous-string)))
+  (let ((prev (process-get proc :previous-string)))
     (when prev
       (setq string (concat prev string))
-      (process-put proc 'previous-string nil)))
+      (process-put proc :previous-string nil)))
   ;; If the input is multiple lines,
   ;; process each line individually.
@@ -308,5 +381,5 @@
 	  (files nil)
 	  (lineno 1)
-	  (tmp-frame nil) ; Sometimes used to embody the selected display.
+	  (tmp-frame nil) ;; Sometimes used to embody the selected display.
 	  (columnno 0))
       ;; Remove this line from STRING.
@@ -338,6 +411,6 @@
 	    (setq arg (server-unquote-arg arg))
 	    ;; Now decode the file name if necessary.
-	    (if coding-system
-		(setq arg (decode-coding-string arg coding-system)))
+	    (when coding-system
+	      (setq arg (decode-coding-string arg coding-system)))
 	    (if eval
 		(let* (errorp
@@ -384,17 +457,17 @@
       ;; call pop-to-buffer etc.), delete it to avoid preserving the
       ;; connection after the last real frame is deleted.
-      (if tmp-frame
-	  (if (eq (selected-frame) tmp-frame)
-	      (set-frame-parameter tmp-frame 'visibility t)
-	    (delete-frame tmp-frame)))))
+      (when tmp-frame
+	(if (eq (selected-frame) tmp-frame)
+	    (set-frame-parameter tmp-frame 'visibility t)
+	  (delete-frame tmp-frame)))))
   ;; Save for later any partial line that remains.
   (when (> (length string) 0)
-    (process-put proc 'previous-string string)))
+    (process-put proc :previous-string string)))
 
 (defun server-goto-line-column (file-line-col)
   (goto-line (nth 1 file-line-col))
   (let ((column-number (nth 2 file-line-col)))
-    (if (> column-number 0)
-	(move-to-column (1- column-number)))))
+    (when (> column-number 0)
+      (move-to-column (1- column-number)))))
 
 (defun server-visit-files (files client &optional nowait)
@@ -468,31 +541,31 @@
 	  (setq server-clients (delq client server-clients))))
       (setq old-clients (cdr old-clients)))
-    (if (and (bufferp buffer) (buffer-name buffer))
-	;; We may or may not kill this buffer;
-	;; if we do, do not call server-buffer-done recursively
-	;; from kill-buffer-hook.
-	(let ((server-kill-buffer-running t))
-	  (with-current-buffer buffer
-	    (setq server-buffer-clients nil)
-	    (run-hooks 'server-done-hook))
-	  ;; Notice whether server-done-hook killed the buffer.
-	  (if (null (buffer-name buffer))
+    (when (and (bufferp buffer) (buffer-name buffer))
+      ;; We may or may not kill this buffer;
+      ;; if we do, do not call server-buffer-done recursively
+      ;; from kill-buffer-hook.
+      (let ((server-kill-buffer-running t))
+	(with-current-buffer buffer
+	  (setq server-buffer-clients nil)
+	  (run-hooks 'server-done-hook))
+	;; Notice whether server-done-hook killed the buffer.
+	(if (null (buffer-name buffer))
+	    (setq killed t)
+	  ;; Don't bother killing or burying the buffer
+	  ;; when we are called from kill-buffer.
+	  (unless for-killing
+	    (when (and (not killed)
+		       server-kill-new-buffers
+		       (with-current-buffer buffer
+			 (not server-existing-buffer)))
 	      (setq killed t)
-	    ;; Don't bother killing or burying the buffer
-	    ;; when we are called from kill-buffer.
-	    (unless for-killing
-	      (when (and (not killed)
-			 server-kill-new-buffers
-			 (with-current-buffer buffer
-			   (not server-existing-buffer)))
-		(setq killed t)
-		(bury-buffer buffer)
-		(kill-buffer buffer))
-	      (unless killed
-		(if (server-temp-file-p buffer)
-		    (progn
-		      (kill-buffer buffer)
-		      (setq killed t))
-		  (bury-buffer buffer)))))))
+	      (bury-buffer buffer)
+	      (kill-buffer buffer))
+	    (unless killed
+	      (if (server-temp-file-p buffer)
+		  (progn
+		    (kill-buffer buffer)
+		    (setq killed t))
+		(bury-buffer buffer)))))))
     (list next-buffer killed)))
 
@@ -521,8 +594,8 @@
 	      (buffer-backed-up nil))
 	  (save-buffer))
-      (if (and (buffer-modified-p)
-	       buffer-file-name
-	       (y-or-n-p (concat "Save file " buffer-file-name "? ")))
-	  (save-buffer)))
+      (when (and (buffer-modified-p)
+		 buffer-file-name
+		 (y-or-n-p (concat "Save file " buffer-file-name "? ")))
+	(save-buffer)))
     (server-buffer-done (current-buffer))))
 
@@ -544,6 +617,6 @@
     ;; See if any clients have any buffers that are still alive.
     (while tail
-      (if (memq t (mapcar 'stringp (mapcar 'buffer-name (cdr (car tail)))))
-	  (setq live-client t))
+      (when (memq t (mapcar 'stringp (mapcar 'buffer-name (cdr (car tail)))))
+	(setq live-client t))
       (setq tail (cdr tail)))
     (or (not live-client)
@@ -611,6 +684,6 @@
 	      ;; The buffer is already displayed: just reuse the window.
 	      (let ((frame (window-frame win)))
-		(if (eq (frame-visible-p frame) 'icon)
-		    (raise-frame frame))
+		(when (eq (frame-visible-p frame) 'icon)
+		  (raise-frame frame))
 		(select-window win)
 		(set-buffer next-buffer))
@@ -620,9 +693,9 @@
 		   (select-window server-window))
 		  ((framep server-window)
-		   (if (not (frame-live-p server-window))
-		       (setq server-window (make-frame)))
+		   (unless (frame-live-p server-window)
+		     (setq server-window (make-frame)))
 		   (select-window (frame-selected-window server-window))))
-	    (if (window-minibuffer-p (selected-window))
-		(select-window (next-window nil 'nomini 0)))
+	    (when (window-minibuffer-p (selected-window))
+	      (select-window (next-window nil 'nomini 0)))
 	    ;; Move to a non-dedicated window, if we have one.
 	    (when (window-dedicated-p (selected-window))
Index: lib-src/emacsclient.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/emacsclient.c,v
retrieving revision 1.77
diff -u -2 -r1.77 emacsclient.c
--- lib-src/emacsclient.c	18 Jul 2006 16:33:45 -0000	1.77
+++ lib-src/emacsclient.c	28 Oct 2006 00:09:27 -0000
@@ -27,9 +27,14 @@
 #endif
 
+#ifdef WINDOWSNT
+#define HAVE_SOCKETS
+#define NO_SOCKETS_IN_FILE_SYSTEM
+#endif
+
 #undef signal
 
 #include <ctype.h>
 #include <stdio.h>
-#include <getopt.h>
+#include "getopt.h"
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -38,6 +43,10 @@
 #ifdef VMS
 # include "vms-pwd.h"
-#else
+#else /* not VMS */
+#ifdef WINDOWSNT
+# include <io.h>
+#else /* not WINDOWSNT */
 # include <pwd.h>
+#endif /* not WINDOWSNT */
 #endif /* not VMS */
 
@@ -49,4 +58,19 @@
 #endif
 \f
+#define SEND_STRING(data) (send_to_emacs (s, (data)))
+#define SEND_QUOTED(data) (quote_file_name (s, (data)))
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+#ifndef NO_RETURN
+#define NO_RETURN
+#endif
+\f
 /* Name used to invoke this program.  */
 char *progname;
@@ -68,4 +92,7 @@
 char *socket_name = NULL;
 
+/* If non-NULL, the filename of the authentication file.  */
+char *server_file = NULL;
+
 void print_help_and_exit () NO_RETURN;
 
@@ -78,4 +105,5 @@
   { "alternate-editor", required_argument, NULL, 'a' },
   { "socket-name",	required_argument, NULL, 's' },
+  { "server-file",	required_argument, NULL, 'f' },
   { "display",	required_argument, NULL, 'd' },
   { 0, 0, 0, 0 }
@@ -91,9 +119,10 @@
 {
   alternate_editor = getenv ("ALTERNATE_EDITOR");
+  server_file = getenv ("EMACS_SERVER_FILE");
 
   while (1)
     {
       int opt = getopt_long (argc, argv,
-			     "VHnea:s:d:", longopts, 0);
+			     "VHnea:s:f:d:", longopts, 0);
 
       if (opt == EOF)
@@ -115,4 +144,8 @@
 	  break;
 
+	case 'f':
+	  server_file = optarg;
+	  break;
+
 	case 'd':
 	  display = optarg;
@@ -157,7 +190,11 @@
 -n, --no-wait           Don't wait for the server to return\n\
 -e, --eval              Evaluate the FILE arguments as ELisp expressions\n\
--d, --display=DISPLAY   Visit the file in the given display\n\
--s, --socket-name=FILENAME\n\
-                        Set the filename of the UNIX socket for communication\n\
+-d, --display=DISPLAY   Visit the file in the given display\n"
+#ifndef NO_SOCKETS_IN_FILE_SYSTEM
+"-s, --socket-name=FILENAME\n\
+                        Set the filename of the UNIX socket for communication\n"
+#endif
+"-f, --server-file=FILENAME\n\
+			Set the filename of the TCP configuration file\n\
 -a, --alternate-editor=EDITOR\n\
                         Editor to fallback to if the server is not running\n\
@@ -167,12 +204,116 @@
 }
 
+\f
+/*
+  Try to run a different command, or --if no alternate editor is
+  defined-- exit with an errorcode.
+*/
+void
+fail (argc, argv)
+     int argc;
+     char **argv;
+{
+  if (alternate_editor)
+    {
+      int i = optind - 1;
+      execvp (alternate_editor, argv + i);
+      fprintf (stderr, "%s: error executing alternate editor \"%s\"\n",
+               progname, alternate_editor);
+    }
+  else
+    {
+      fprintf (stderr, "%s: No socket or alternate editor.  Please use:\n\n"
+#if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
+"\t--socket-name\n"
+#endif
+"\t--server-file      (or environment variable EMACS_SERVER_FILE)\n\
+\t--alternate-editor (or environment variable ALTERNATE_EDITOR)\n",
+               progname);
+    }
+  exit (EXIT_FAILURE);
+}
+
+\f
+#if !defined (HAVE_SOCKETS)
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
+	   argv[0]);
+  fprintf (stderr, "on systems with Berkeley sockets.\n");
+
+  fail (argc, argv);
+}
+
+#else /* HAVE_SOCKETS */
+
+#ifdef WINDOWSNT
+# include <winsock2.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <sys/stat.h>
+# include <errno.h>
+#endif
+
+#define AUTH_KEY_LENGTH      64
+#define SEND_BUFFER_SIZE   4096
+
+extern char *strerror ();
+extern int errno;
+
+/* Buffer to accumulate data to send in TCP connections.  */
+char send_buffer[SEND_BUFFER_SIZE + 1];
+int sblen = 0;	/* Fill pointer for the send buffer.  */
+
+/* Let's send the data to Emacs when either
+   - the data ends in "\n", or
+   - the buffer is full (but this shouldn't happen)
+   Otherwise, we just accumulate it.  */
+void send_to_emacs (s, data)
+     SOCKET s;
+     char *data;
+{
+  while (data)
+    {
+      int dlen = strlen (data);
+      if (dlen + sblen >= SEND_BUFFER_SIZE)
+	{
+	  int part = SEND_BUFFER_SIZE - sblen;
+	  strncpy (&send_buffer[sblen], data, part);
+	  data += part;
+	  sblen = SEND_BUFFER_SIZE;
+	}
+      else if (dlen)
+	{
+	  strcpy (&send_buffer[sblen], data);
+	  data = NULL;
+	  sblen += dlen;
+	}
+      else
+	break;
+
+      if (sblen == SEND_BUFFER_SIZE
+	  || (sblen > 0 && send_buffer[sblen-1] == '\n'))
+	{
+	  int sent = send (s, send_buffer, sblen, 0);
+	  if (sent != sblen)
+	    strcpy (send_buffer, &send_buffer[sent]);
+	  sblen -= sent;
+	}
+    }
+}
+
 /* In NAME, insert a & before each &, each space, each newline, and
    any initial -.  Change spaces to underscores, too, so that the
    return value never contains a space.  */
-
 void
-quote_file_name (name, stream)
+quote_file_name (s, name)
+     SOCKET s;
      char *name;
-     FILE *stream;
 {
   char *copy = (char *) malloc (strlen (name) * 2 + 1);
@@ -204,71 +345,140 @@
   *q++ = 0;
 
-  fprintf (stream, "%s", copy);
+  SEND_STRING (copy);
 
   free (copy);
 }
 
-/* Like malloc but get fatal error if memory is exhausted.  */
+#ifdef WINDOWSNT
+/* Wrapper to make WSACleanup a cdecl, as required by atexit().	 */
+void close_winsock ()
+{
+  WSACleanup ();
+}
+#endif /* WINDOWSNT */
 
-long *
-xmalloc (size)
-     unsigned int size;
+void initialize_sockets ()
 {
-  long *result = (long *) malloc (size);
-  if (result == NULL)
-  {
-    perror ("malloc");
-    exit (EXIT_FAILURE);
-  }
-  return result;
+#ifdef WINDOWSNT
+  WSADATA wsaData;
+
+  /* Initialize the WinSock2 library.  */
+  if (WSAStartup (MAKEWORD (2, 0), &wsaData))
+    {
+      fprintf (stderr, "%s: error initializing WinSock2", progname);
+      exit (EXIT_FAILURE);
+    }
+
+  atexit (close_winsock);
+#endif /* WINDOWSNT */
 }
 \f
 /*
-  Try to run a different command, or --if no alternate editor is
-  defined-- exit with an errorcode.
+ * Read the information needed to set up a TCP comm channel with
+ * the Emacs server: host, port and authentication string.
 */
-void
-fail (argc, argv)
-     int argc;
-     char **argv;
+void get_server_config (server, authentication)
+     struct sockaddr_in *server;
+     char *authentication;
 {
-  if (alternate_editor)
+  FILE *config;
+  char dotted[32];
+  char *port;
+
+  if (! (config = fopen (server_file, "rb")))
+    {
+      char *home = getenv ("HOME");
+#ifdef WINDOWSNT
+      if (! home)
+          home = getenv ("APPDATA");
+#endif
+      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");
+        }
+    }
+
+  if (! config)
     {
-      int i = optind - 1;
-      execvp (alternate_editor, argv + i);
-      return;
+      fprintf (stderr, "%s: cannot read configuration file %s",
+               progname, server_file);
+      exit (EXIT_FAILURE);
+    }
+
+  if (fgets (dotted, sizeof dotted, config)
+      && (port = strchr (dotted, ':')))
+    {
+      *port++ = '\0';
     }
   else
     {
+      fprintf (stderr, "%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));
 
-\f
-#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
+  if (! fread (authentication, AUTH_KEY_LENGTH, 1, config))
+    {
+      fprintf (stderr, "%s: cannot read authentication info", progname);
+      exit (EXIT_FAILURE);
+    }
 
-int
-main (argc, argv)
-     int argc;
-     char **argv;
+  fclose (config);
+}
+
+SOCKET
+set_tcp_socket ()
 {
-  fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
-	   argv[0]);
-  fprintf (stderr, "on systems with Berkeley sockets.\n");
+  SOCKET s;
+  struct sockaddr_in server;
+  unsigned long c_arg = 0;
+  struct linger l_arg = {1, 1};
+  char auth_string[AUTH_KEY_LENGTH + 1];
 
-  fail (argc, argv);
-}
+  initialize_sockets ();
 
-#else /* HAVE_SOCKETS */
+  get_server_config (&server, auth_string);
+
+  /*
+   * Open up an AF_INET socket
+   */
+  if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+    {
+      fprintf (stderr, "%s: ", progname);
+      perror ("socket");
+      return INVALID_SOCKET;
+    }
+
+  /*
+   * Set up the socket
+   */
+  if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
+    {
+      fprintf (stderr, "%s: ", progname);
+      perror ("connect");
+      return INVALID_SOCKET;
+    }
 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <errno.h>
+  ioctlsocket (s, FIONBIO, &c_arg);
+  setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
 
-extern char *strerror ();
-extern int errno;
+  /*
+   * 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:
@@ -292,26 +502,9 @@
 }
 
-int
-main (argc, argv)
-     int argc;
-     char **argv;
+SOCKET
+set_local_socket ()
 {
-  int s, i, needlf = 0;
-  FILE *out, *in;
+  SOCKET s;
   struct sockaddr_un server;
-  char *cwd, *str;
-  char string[BUFSIZ];
-
-  progname = argv[0];
-
-  /* Process options.  */
-  decode_options (argc, argv);
-
-  if ((argc - optind < 1) && !eval)
-    {
-      fprintf (stderr, "%s: file name or argument required\n", progname);
-      fprintf (stderr, "Try `%s --help' for more information\n", progname);
-      exit (EXIT_FAILURE);
-    }
 
   /*
@@ -321,7 +514,7 @@
   if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
     {
-      fprintf (stderr, "%s: ", argv[0]);
+      fprintf (stderr, "%s: ", progname);
       perror ("socket");
-      fail (argc, argv);
+      return INVALID_SOCKET;
     }
 
@@ -353,5 +546,5 @@
       {
 	fprintf (stderr, "%s: socket-name %s too long",
-		 argv[0], socket_name);
+		 progname, socket_name);
 	exit (EXIT_FAILURE);
       }
@@ -388,5 +581,5 @@
 		  {
 		    fprintf (stderr, "%s: socket-name %s too long",
-			     argv[0], socket_name);
+			     progname, socket_name);
 		    exit (EXIT_FAILURE);
 		  }
@@ -400,29 +593,28 @@
       }
 
-     switch (sock_status)
-       {
-       case 1:
-	 /* There's a socket, but it isn't owned by us.  This is OK if
-	    we are root. */
-	 if (0 != geteuid ())
-	   {
-	     fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
-	     fail (argc, argv);
-	   }
-	 break;
-
-       case 2:
-	 /* `stat' failed */
-	 if (saved_errno == ENOENT)
-	   fprintf (stderr,
-		    "%s: can't find socket; have you started the server?\n\
+    switch (sock_status)
+      {
+      case 1:
+        /* There's a socket, but it isn't owned by us.  This is OK if
+           we are root. */
+        if (0 != geteuid ())
+          {
+            fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
+	    return INVALID_SOCKET;
+          }
+        break;
+
+      case 2:
+        /* `stat' failed */
+        if (saved_errno == ENOENT)
+          fprintf (stderr,
+                   "%s: can't find socket; have you started the server?\n\
 To start the server in Emacs, type \"M-x server-start\".\n",
-		    argv[0]);
-	 else
-	   fprintf (stderr, "%s: can't stat %s: %s\n",
-		    argv[0], server.sun_path, strerror (saved_errno));
-	 fail (argc, argv);
-	 break;
-       }
+		   progname);
+        else
+          fprintf (stderr, "%s: can't stat %s: %s\n",
+		   progname, server.sun_path, strerror (saved_errno));
+	return INVALID_SOCKET;
+      }
   }
 
@@ -430,29 +622,54 @@
       < 0)
     {
-      fprintf (stderr, "%s: ", argv[0]);
+      fprintf (stderr, "%s: ", progname);
       perror ("connect");
-      fail (argc, argv);
+      return INVALID_SOCKET;
     }
 
-  /* We use the stream OUT to send our command to the server.  */
-  if ((out = fdopen (s, "r+")) == NULL)
+  return s;
+}
+#endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
+
+SOCKET
+set_socket ()
+{
+  if (server_file)
+    return set_tcp_socket ();
+  else
+#ifndef NO_SOCKETS_IN_FILE_SYSTEM
+    return set_local_socket ();
+#else
     {
-      fprintf (stderr, "%s: ", argv[0]);
-      perror ("fdopen");
-      fail (argc, argv);
+      server_file = "server";
+      return set_tcp_socket ();
     }
+#endif
+}
 
-  /* We use the stream IN to read the response.
-     We used to use just one stream for both output and input
-     on the socket, but reversing direction works nonportably:
-     on some systems, the output appears as the first input;
-     on other systems it does not.  */
-  if ((in = fdopen (s, "r+")) == NULL)
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  SOCKET s;
+  int i, rl, needlf = 0;
+  char *cwd;
+  char string[BUFSIZ+1];
+
+  progname = argv[0];
+
+  /* Process options.  */
+  decode_options (argc, argv);
+
+  if ((argc - optind < 1) && !eval)
     {
-      fprintf (stderr, "%s: ", argv[0]);
-      perror ("fdopen");
-      fail (argc, argv);
+      fprintf (stderr, "%s: file name or argument required\n", progname);
+      fprintf (stderr, "Try `%s --help' for more information\n", progname);
+      exit (EXIT_FAILURE);
     }
 
+  if ((s = set_socket ()) == INVALID_SOCKET)
+    fail (argc, argv);
+
 #ifdef HAVE_GETCWD
   cwd = getcwd (string, sizeof string);
@@ -465,8 +682,8 @@
 
 #ifdef HAVE_GETCWD
-      fprintf (stderr, "%s: %s (%s)\n", argv[0],
+      fprintf (stderr, "%s: %s (%s)\n", progname,
 	       "Cannot get current working directory", strerror (errno));
 #else
-      fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
+      fprintf (stderr, "%s: %s (%s)\n", progname, string, strerror (errno));
 #endif
       fail (argc, argv);
@@ -474,14 +691,14 @@
 
   if (nowait)
-    fprintf (out, "-nowait ");
+    SEND_STRING ("-nowait ");
 
   if (eval)
-    fprintf (out, "-eval ");
+    SEND_STRING ("-eval ");
 
   if (display)
     {
-      fprintf (out, "-display ");
-      quote_file_name (display, out);
-      fprintf (out, " ");
+      SEND_STRING ("-display ");
+      SEND_QUOTED (display);
+      SEND_STRING (" ");
     }
 
@@ -498,59 +715,69 @@
 	      if (*p != 0)
 		{
-		  quote_file_name (cwd, out);
-		  fprintf (out, "/");
+		  SEND_QUOTED (cwd);
+		  SEND_STRING ("/");
 		}
 	    }
+#ifndef WINDOWSNT
 	  else if (*argv[i] != '/')
+#else
+	  else if ((*argv[i] != '/')
+		   /* Absolute paths can also start with backslash
+		      or drive letters.	 */
+		   && (*argv[i] != '\\')
+		   && (!islower (tolower (*argv[i]))
+		       || (argv[i][1] != ':')))
+#endif
 	    {
-	      quote_file_name (cwd, out);
-	      fprintf (out, "/");
+	      SEND_QUOTED (cwd);
+	      SEND_STRING ("/");
 	    }
 
-	  quote_file_name (argv[i], out);
-	  fprintf (out, " ");
+	  SEND_QUOTED (argv[i]);
+	  SEND_STRING (" ");
 	}
     }
   else
     {
-      while ((str = fgets (string, BUFSIZ, stdin)))
+      while (fgets (string, BUFSIZ, stdin))
 	{
-	  quote_file_name (str, out);
+	  SEND_QUOTED (string);
 	}
-      fprintf (out, " ");
+      SEND_STRING (" ");
     }
 
-  fprintf (out, "\n");
-  fflush (out);
+  SEND_STRING ("\n");
 
   /* Maybe wait for an answer.   */
-  if (nowait)
-    return EXIT_SUCCESS;
-
-  if (!eval)
+  if (!nowait)
     {
-      printf ("Waiting for Emacs...");
-      needlf = 2;
+      if (!eval)
+        {
+          printf ("Waiting for Emacs...");
+          needlf = 2;
+        }
+      fflush (stdout);
+
+      /* Now, wait for an answer and print any messages.  */
+      while ((rl = recv (s, string, BUFSIZ, 0)) > 0)
+        {
+	  string[rl] = '\0';
+          if (needlf == 2)
+            printf ("\n");
+	  printf ("%s", string);
+	  needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n';
+        }
+
+      if (needlf)
+        printf ("\n");
+      fflush (stdout);
     }
-  fflush (stdout);
-
-  /* Now, wait for an answer and print any messages.  */
-  while ((str = fgets (string, BUFSIZ, in)))
-    {
-      if (needlf == 2)
-	printf ("\n");
-      printf ("%s", str);
-      needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
-    }
-
-  if (needlf)
-    printf ("\n");
-  fflush (stdout);
 
+  closesocket (s);
   return EXIT_SUCCESS;
 }
 
 #endif /* HAVE_SOCKETS */
-\f
+
 #ifndef HAVE_STRERROR
 char *
Index: lib-src/makefile.w32-in
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/makefile.w32-in,v
retrieving revision 2.46
diff -u -2 -r2.46 makefile.w32-in
--- lib-src/makefile.w32-in	9 Oct 2006 19:57:43 -0000	2.46
+++ lib-src/makefile.w32-in	27 Oct 2006 22:02:28 -0000
@@ -21,5 +21,5 @@
 #
 
-ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc
+ALL = make-docfile hexl ctags etags movemail ebrowse sorted-doc digest-doc emacsclient
 
 .PHONY: $(ALL)
@@ -33,5 +33,4 @@
 #		$(BLD)/server.exe	\
 #		$(BLD)/emacstool.exe	\
-#		$(BLD)/emacsclient.exe	\
 #		$(BLD)/cvtmail.exe	\
 
@@ -60,4 +59,5 @@
 sorted-doc:	$(BLD) $(BLD)/sorted-doc.exe
 digest-doc:	$(BLD) $(BLD)/digest-doc.exe
+emacsclient:	$(BLD) $(BLD)/emacsclient.exe
 
 test-distrib:	$(BLD) $(BLD)/test-distrib.exe
@@ -75,4 +75,17 @@
 		$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(MOVEMAILOBJS) $(WSOCK32) $(LIBS)
 
+ECLIENT_CFLAGS = -DWINDOWSNT -DHAVE_GETCWD -DHAVE_STRERROR -c
+ECLIENTOBJS =	$(BLD)/emacsclient.$(O) \
+		$(BLD)/getopt.$(O) \
+		$(BLD)/getopt1.$(O) \
+		$(BLD)/ntlib.$(O)
+
+$(BLD)/emacsclient.exe:		$(ECLIENTOBJS)
+# put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib
+		$(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(LIBS)
+
+$(BLD)/emacsclient.$(O):	emacsclient.c
+		$(CC) $(ECLIENT_CFLAGS) $(CC_OUT)$@ emacsclient.c
+
 ETAGSOBJ      = $(BLD)/etags.$(O) \
 		$(BLD)/getopt.$(O) \
@@ -297,4 +310,5 @@
 		$(CP) $(BLD)/sorted-doc.exe $(INSTALL_DIR)/bin
 		$(CP) $(BLD)/digest-doc.exe $(INSTALL_DIR)/bin
+		$(CP) $(BLD)/emacsclient.exe $(INSTALL_DIR)/bin
 		- mkdir "$(INSTALL_DIR)/etc"
 		$(CP) $(DOC) $(INSTALL_DIR)/etc

[-- Attachment #3: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 11:08           ` Juanma Barranquero
  2006-10-27 12:21             ` Jason Rumney
@ 2006-10-28  7:27             ` Richard Stallman
  2006-10-28 21:16               ` Juanma Barranquero
  1 sibling, 1 reply; 54+ messages in thread
From: Richard Stallman @ 2006-10-28  7:27 UTC (permalink / raw)
  Cc: emacs-devel

      - Currently, when emacsclient fails the authentication check, it
    just ends (because Emacs closes the connection). Should it give an
    error message?

That would be an improvement.

      - server.el generates the authentication string with `random', but
    Emacs uses the same seed every time. I'm reluctant to call (random t)
    in server.el; Emacs doesn't do it for a good reason (repeatability).

Let's make (random 'random) generate a new seed, use it, then restore
the old one, so that it has no effect on the sequence.  This is a much
smaller change than adding a means to read and set the random seed.
I'd rather not do the latter now, but we could do it later.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 15:18                   ` Juanma Barranquero
@ 2006-10-28 18:13                     ` Richard Stallman
  2006-10-30  1:02                     ` Stefan Monnier
  1 sibling, 0 replies; 54+ messages in thread
From: Richard Stallman @ 2006-10-28 18:13 UTC (permalink / raw)
  Cc: emacs-devel

    I've now set it up so (random t) is called when `server-use-tcp' is
    set to t (which includes customize-variable, and also the
    initialization if ":family 'local" is not supported).

Please implement (random 'random) as I suggested, and use that instead.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-28  7:27             ` Richard Stallman
@ 2006-10-28 21:16               ` Juanma Barranquero
  2006-10-28 23:38                 ` Kim F. Storm
  2006-10-30 13:33                 ` Richard Stallman
  0 siblings, 2 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-28 21:16 UTC (permalink / raw)


On 10/28/06, Richard Stallman <rms@gnu.org> wrote:

> Let's make (random 'random) generate a new seed, use it, then restore
> the old one, so that it has no effect on the sequence. This is a much
> smaller change than adding a means to read and set the random seed.

On one hand, both are really equivalent. To restore the old seed you
first need a way to get it. The current random code in sysdep.c tries
to massage wildly different random implementations (lrand48, rand,
etc.) into a consistent interface, and there's no support in place *at
all* for getting back the seed (which also varies quite a lot across
implementations of random functions). I don't think is very sensible
to hastily add now a mechanism for getting the seed which, to make any
sense, should have to be heavily tested in as much environments as
possible.

On the other hand, I don't quite get what you're proposing. Currently,
the output of (random t) is almost never used, because when you're
passing t you cannot pass N. In the Emacs sources, (random) is used
about 7 times, while (random N) is used approx. 70. But your proposed
(random 'random), if I'm understanding you, would save the seed,
return a value, then restore the seed. For that to be useful, it'd
have to be (random N 'random). Moreover,
the current `random', when passed t, does:

    seed_random (getpid () + time (NULL));

So in many situations, when several values are needed at once (as is
the case in server.el), the code using your 'random would be:

  loop N times
     save seed
     set seed to (getpid () + time (NULL))
     collect a random value
     restore seed
  end loop

I very much doubt the result is hardly random enough; in fact,
getpid() + time(NULL) is bound to return the same value for a lot of
consecutive calls... To make that useful we'd need a way to get N
values at once from random.

But I think that's all unnecessary right now. As others have pointed
out, several packages already do initialize the random seed for
trivial reasons; I see no harm in doing the same in server.el. If your
proposal (or any variant) is ever implemented, fixing server.el is a
one-line change.

                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-28 21:16               ` Juanma Barranquero
@ 2006-10-28 23:38                 ` Kim F. Storm
  2006-10-30 13:33                 ` Richard Stallman
  1 sibling, 0 replies; 54+ messages in thread
From: Kim F. Storm @ 2006-10-28 23:38 UTC (permalink / raw)
  Cc: emacs-devel

"Juanma Barranquero" <lekktu@gmail.com> writes:

> On 10/28/06, Richard Stallman <rms@gnu.org> wrote:
>
>> Let's make (random 'random) generate a new seed, use it, then restore
>> the old one, so that it has no effect on the sequence. This is a much
>> smaller change than adding a means to read and set the random seed.

> But I think that's all unnecessary right now. As others have pointed
> out, several packages already do initialize the random seed for
> trivial reasons; I see no harm in doing the same in server.el. If your
> proposal (or any variant) is ever implemented, fixing server.el is a
> one-line change.

I agree.  I see no harm in doing (random t) in server.el.

If someone really want repeatable output from random, we _do_ need
at way to set the seed, e.g. (random &optional n seed)

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-27 15:18                   ` Juanma Barranquero
  2006-10-28 18:13                     ` Richard Stallman
@ 2006-10-30  1:02                     ` Stefan Monnier
  2006-10-31  0:35                       ` Juanma Barranquero
  1 sibling, 1 reply; 54+ messages in thread
From: Stefan Monnier @ 2006-10-30  1:02 UTC (permalink / raw)
  Cc: Emacs Devel

> Otherwise, I'm just gonna commit the code and wait for the fireworks :)

Please do so,


        Stefan

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-28 21:16               ` Juanma Barranquero
  2006-10-28 23:38                 ` Kim F. Storm
@ 2006-10-30 13:33                 ` Richard Stallman
  1 sibling, 0 replies; 54+ messages in thread
From: Richard Stallman @ 2006-10-30 13:33 UTC (permalink / raw)
  Cc: emacs-devel

    But your proposed
    (random 'random), if I'm understanding you, would save the seed,
    return a value, then restore the seed. For that to be useful, it'd
    have to be (random N 'random).

You are right.  It would have to be able to take two arguments.

    I very much doubt the result is hardly random enough; in fact,
    getpid() + time(NULL) is bound to return the same value for a lot of
    consecutive calls... To make that useful we'd need a way to get N
    values at once from random.

That is a good point also.

    But I think that's all unnecessary right now. As others have pointed
    out, several packages already do initialize the random seed for
    trivial reasons; I see no harm in doing the same in server.el.

Ok.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Back to emacsclient/server
  2006-10-30  1:02                     ` Stefan Monnier
@ 2006-10-31  0:35                       ` Juanma Barranquero
  0 siblings, 0 replies; 54+ messages in thread
From: Juanma Barranquero @ 2006-10-31  0:35 UTC (permalink / raw)


On 10/30/06, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> Please do so,

OK, the TCP socket code for emacsclient is installed.

server.el should be OK. As for emasclient.c, I've tried to use macros
to isolate Winsock-specific code. Still, it is quite possible it
doesn't compile under GNU/Linux or other systems. If that happens,
it's better to fix it than complain to me (because I don't have any
way to test it on those systems) :)

There are a few things lacking; for example, a way to make server.el
bring the Emacs frame to the front (on Windows, at least). Also,
documentation. And, of course, lots of testing.

One weird thing (but I must be overlooking something): When Emacs (and
server.el) is not running,

  C:\> emacsclient -a test.bat my-file.txt

runs test.bat (with CMD.EXE). However, both

  C:\> emacsclient --alternate-editor=test.bat my-file.txt

and

  C:\> SET ALTERNATE_EDITOR=test.bat
  C:\> emacsclient my-file.txt

fail. The first one with a message stating that "--alternate-editor"
is not recognized, and the second one with a weird loop cmd.exe ->
emacsclient.exe -> cmd.exe, etc.

It only happens with .BAT scripts, not executables, so something
related to the way execvp() tries to run cmd.exe, I suppose.

-- 
                    /L/e/k/t/u

^ permalink raw reply	[flat|nested] 54+ messages in thread

end of thread, other threads:[~2006-10-31  0:35 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-23 14:14 Back to emacsclient/server Juanma Barranquero
2006-10-23 14:54 ` Jason Rumney
2006-10-23 19:48   ` Stefan Monnier
2006-10-23 21:17     ` Jason Rumney
2006-10-23 22:02       ` Andreas Schwab
2006-10-23 16:00 ` Ted Zlatanov
2006-10-23 20:09   ` Eli Zaretskii
2006-10-24  0:02     ` Ted Zlatanov
2006-10-24  4:35       ` Eli Zaretskii
2006-10-24 15:36         ` Ted Zlatanov
2006-10-24 17:31           ` Eli Zaretskii
2006-10-24 19:24             ` Ted Zlatanov
2006-10-24 22:22               ` Stefan Monnier
2006-10-25 16:33                 ` Ted Zlatanov
2006-10-25 11:46               ` Michael Olson
2006-10-25 12:38                 ` David Kastrup
2006-10-23 21:47   ` Juanma Barranquero
2006-10-23 23:50     ` Ted Zlatanov
2006-10-24  2:01   ` Stefan Monnier
2006-10-24 15:40     ` Ted Zlatanov
2006-10-24 18:17       ` Stefan Monnier
2006-10-24 19:31         ` Ted Zlatanov
2006-10-23 16:26 ` Jan D.
2006-10-23 19:52   ` Stefan Monnier
2006-10-23 20:35     ` Jan Djärv
2006-10-23 21:20       ` Jason Rumney
2006-10-23 21:59         ` Jason Rumney
2006-10-24  5:06         ` Jan Djärv
2006-10-24  8:37           ` Juanma Barranquero
2006-10-24 13:27           ` Jason Rumney
2006-10-23 21:57       ` Juanma Barranquero
2006-10-24  5:08         ` Jan Djärv
2006-10-24  7:32           ` Kim F. Storm
2006-10-23 19:46 ` Stefan Monnier
2006-10-23 21:54   ` Juanma Barranquero
2006-10-24  2:04     ` Stefan Monnier
2006-10-24  8:39       ` Juanma Barranquero
2006-10-27  0:27         ` Juanma Barranquero
2006-10-27 11:08           ` Juanma Barranquero
2006-10-27 12:21             ` Jason Rumney
2006-10-27 13:25               ` Stefan Monnier
2006-10-27 13:35                 ` Juanma Barranquero
2006-10-27 13:29               ` Juanma Barranquero
2006-10-27 13:50                 ` Slawomir Nowaczyk
2006-10-27 14:20                 ` Stefan Monnier
2006-10-27 15:18                   ` Juanma Barranquero
2006-10-28 18:13                     ` Richard Stallman
2006-10-30  1:02                     ` Stefan Monnier
2006-10-31  0:35                       ` Juanma Barranquero
2006-10-28  7:27             ` Richard Stallman
2006-10-28 21:16               ` Juanma Barranquero
2006-10-28 23:38                 ` Kim F. Storm
2006-10-30 13:33                 ` Richard Stallman
     [not found] ` <f7ccd24b0610271000p16dda672mb146860725d47e00@mail.gmail.com>
     [not found]   ` <45426C6B.10401@student.lu.se>
     [not found]     ` <f7ccd24b0610271400x343c7197jbd6b775f49834924@mail.gmail.com>
     [not found]       ` <454276CB.9000002@student.lu.se>
     [not found]         ` <f7ccd24b0610271419p51bf429fjf5fb548e613cd950@mail.gmail.com>
     [not found]           ` <45427A24.8020107@student.lu.se>
     [not found]             ` <f7ccd24b0610271438r64539e94j6b17c251b213a047@mail.gmail.com>
     [not found]               ` <45427F8E.5040507@student.lu.se>
     [not found]                 ` <f7ccd24b0610271700v472f9c53v43017fce05e761e9@mail.gmail.com>
2006-10-28  0:24                   ` Juanma Barranquero

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).