1/*	$NetBSD: faketalk.c,v 1.17 2009/07/04 07:51:35 dholland Exp $	*/
2/*
3 * Copyright (c) 1983-2003, Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * + Redistributions of source code must retain the above copyright
11 *   notice, this list of conditions and the following disclaimer.
12 * + Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 * + Neither the name of the University of California, San Francisco nor
16 *   the names of its contributors may be used to endorse or promote
17 *   products derived from this software without specific prior written
18 *   permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34#ifndef lint
35__RCSID("$NetBSD: faketalk.c,v 1.17 2009/07/04 07:51:35 dholland Exp $");
36#endif /* not lint */
37
38#include "bsd.h"
39#include "hunt.h"
40
41#if defined(TALK_43) || defined(TALK_42)
42
43#include <sys/time.h>
44#include <sys/wait.h>
45#include <ctype.h>
46#include <netdb.h>
47#include <signal.h>
48#include <stdio.h>
49#include <string.h>
50#include <unistd.h>
51#include "talk_ctl.h"
52
53#define TRUE		1
54#define FALSE		0
55
56/* defines for fake talk message to announce start of game */
57#ifdef TALK_43
58#define MASQUERADE	"\"Hunt Game\""
59#else
60#define MASQUERADE	"HuntGame"
61#endif
62#define RENDEZVOUS	"hunt-players"
63#define ARGV0		"HUNT-ANNOUNCE"
64
65extern char *my_machine_name;
66extern char *First_arg, *Last_arg;
67extern char **environ;
68
69static void do_announce(char *);
70void exorcise(int);
71
72/*
73 * exorcise - disspell zombies
74 */
75
76void
77exorcise(int dummy __unused)
78{
79	(void) wait(0);
80}
81
82/*
83 * query the local SMTP daemon to expand the RENDEZVOUS mailing list
84 * and fake a talk request to each address thus found.
85 */
86
87void
88faketalk(void)
89{
90	struct servent *sp;
91	char buf[BUFSIZ];
92	FILE *f;
93	int service;		/* socket of service */
94	struct sockaddr_in des;	/* address of destination */
95	char *a, *b;
96
97	(void) signal(SIGCHLD, exorcise);
98
99	if (fork() != 0)
100		return;
101
102	(void) signal(SIGINT, SIG_IGN);
103	(void) signal(SIGPIPE, SIG_IGN);
104
105	/*
106	 * change argv so that a ps shows ARGV0
107	 */
108	*environ = NULL;
109	for (a = First_arg, b = ARGV0; a < Last_arg; a++) {
110		if (*b)
111			*a = *b++;
112		else
113			*a = ' ';
114	}
115
116	/*
117	 *	initialize "talk"
118	 */
119	get_local_name(MASQUERADE);
120	open_ctl();
121
122	/*
123	 *	start fetching addresses
124	 */
125
126	if ((sp = getservbyname("smtp", NULL)) == NULL) {
127#ifdef LOG
128		syslog(LOG_ERR, "faketalk: smtp protocol not supported\n");
129#else
130		warn("faketalk: stmp protocol not supported");
131#endif
132		_exit(1);
133	}
134
135	memset(&des, 0, sizeof (des));
136	des.sin_family = AF_INET;
137	des.sin_addr = my_machine_addr;
138	des.sin_port = sp->s_port;
139
140	if ((service = socket(des.sin_family, SOCK_STREAM, 0)) < 0) {
141#ifdef LOG
142		syslog(LOG_ERR, "falktalk:  socket");
143#else
144		warn("falktalk:  socket");
145#endif
146		_exit(1);
147	}
148
149	if (connect(service, (struct sockaddr *) &des, sizeof(des)) != 0) {
150#ifdef LOG
151		syslog(LOG_ERR, "faketalk:  connect");
152#else
153		warn("faketalk:  connect");
154#endif
155		_exit(1);
156	}
157	if ((f = fdopen(service, "r")) == NULL) {
158#ifdef LOG
159		syslog(LOG_ERR, "fdopen failed\n");
160#else
161		warn("faketalk:  fdopen");
162#endif
163		_exit(2);
164	}
165
166	(void) fgets(buf, BUFSIZ, f);
167	(void) snprintf(buf, sizeof(buf),
168			"HELO HuntGame@%s\r\n", my_machine_name);
169	(void) write(service, buf, strlen(buf));
170	(void) fgets(buf, BUFSIZ, f);
171	(void) snprintf(buf, sizeof(buf),
172			"EXPN %s@%s\r\n", RENDEZVOUS, my_machine_name);
173	(void) write(service, buf, strlen(buf));
174	while (fgets(buf, BUFSIZ, f) != NULL) {
175		char *s, *t;
176
177		if (buf[0] != '2' || buf[1] != '5' || buf[2] != '0')
178			break;
179		if ((s = strchr(buf + 4, '<')) == NULL)
180			s = buf + 4, t = buf + strlen(buf) - 1;
181		else {
182			s += 1;
183			if ((t = strrchr(s, '>')) == NULL)
184				t = s + strlen(s) - 1;
185			else
186				t -= 1;
187		}
188		while (isspace(*s))
189			s += 1;
190		if (*s == '\\')
191			s += 1;
192		while (isspace(*t))
193			t -= 1;
194		*(t + 1) = '\0';
195		do_announce(s);		/* construct and send talk request */
196		if (buf[3] == ' ')
197			break;
198	}
199	(void) shutdown(service, 2);
200	(void) close(service);
201	_exit(0);
202}
203
204/*
205 * The msg.id's for the invitations on the local and remote machines.
206 * These are used to delete the invitations.
207 */
208
209static void
210do_announce(char *s)
211{
212	CTL_RESPONSE response;
213
214	get_remote_name(s);	/* setup his_machine_addr, msg.r_name */
215
216#ifdef TALK_43
217	msg.ctl_addr = *(struct osockaddr *) &ctl_addr;
218	msg.ctl_addr.sa_family = htons(msg.ctl_addr.sa_family);
219#else
220	msg.ctl_addr = ctl_addr;
221	msg.ctl_addr.sin_family = htons(msg.ctl_addr.sin_family);
222#endif
223	msg.id_num = (int) htonl((uint32_t) -1);	/* an impossible id_num */
224	ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
225	if (response.answer != SUCCESS)
226		return;
227
228	/*
229	 * Have the daemons delete the invitations now that we
230	 * have announced.
231	 */
232
233	/* we don't care if cleanup doesn't make it. */
234	msg.type = DELETE;
235	msg.id_num = (int) htonl(response.id_num);
236	daemon_addr.sin_addr = his_machine_addr;
237	if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
238			(struct sockaddr *) &daemon_addr, sizeof(daemon_addr))
239			!= sizeof(msg))
240		p_error("send delete remote");
241}
242
243#else
244
245void
246faketalk(void)
247{
248	return;
249}
250
251#endif
252