1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31
32__FBSDID("$FreeBSD$");
33
34#ifndef lint
35static const char sccsid[] = "@(#)invite.c	8.1 (Berkeley) 6/6/93";
36#endif
37
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <protocols/talkd.h>
41
42#include <err.h>
43#include <errno.h>
44#include <setjmp.h>
45#include <signal.h>
46#include <unistd.h>
47
48#include "talk_ctl.h"
49#include "talk.h"
50
51/*
52 * There wasn't an invitation waiting, so send a request containing
53 * our sockt address to the remote talk daemon so it can invite
54 * him
55 */
56
57/*
58 * The msg.id's for the invitations
59 * on the local and remote machines.
60 * These are used to delete the
61 * invitations.
62 */
63static int	local_id, remote_id;
64static jmp_buf invitebuf;
65
66void
67invite_remote(void)
68{
69	int new_sockt;
70	struct itimerval itimer;
71	CTL_RESPONSE response;
72
73	itimer.it_value.tv_sec = RING_WAIT;
74	itimer.it_value.tv_usec = 0;
75	itimer.it_interval = itimer.it_value;
76	if (listen(sockt, 5) != 0)
77		p_error("Error on attempt to listen for caller");
78#ifdef MSG_EOR
79	/* copy new style sockaddr to old, swap family (short in old) */
80	msg.addr = *(struct osockaddr *)&my_addr;  /* XXX new to old  style*/
81	msg.addr.sa_family = htons(my_addr.sin_family);
82#else
83	msg.addr = *(struct sockaddr *)&my_addr;
84#endif
85	msg.id_num = htonl(-1);		/* an impossible id_num */
86	invitation_waiting = 1;
87	announce_invite();
88	/*
89	 * Shut off the automatic messages for a while,
90	 * so we can use the interrupt timer to resend the invitation
91	 */
92	end_msgs();
93	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
94	message("Waiting for your party to respond");
95	signal(SIGALRM, re_invite);
96	(void) setjmp(invitebuf);
97	while ((new_sockt = accept(sockt, 0, 0)) < 0) {
98		if (errno == EINTR)
99			continue;
100		p_error("Unable to connect with your party");
101	}
102	close(sockt);
103	sockt = new_sockt;
104
105	/*
106	 * Have the daemons delete the invitations now that we
107	 * have connected.
108	 */
109	current_state = "Waiting for your party to respond";
110	start_msgs();
111
112	msg.id_num = htonl(local_id);
113	ctl_transact(my_machine_addr, msg, DELETE, &response);
114	msg.id_num = htonl(remote_id);
115	ctl_transact(his_machine_addr, msg, DELETE, &response);
116	invitation_waiting = 0;
117}
118
119/*
120 * Routine called on interrupt to re-invite the callee
121 */
122/* ARGSUSED */
123void
124re_invite(int signo __unused)
125{
126
127	message("Ringing your party again");
128	waddch(my_win.x_win, '\n');
129	if (current_line < my_win.x_nlines - 1)
130		current_line++;
131	/* force a re-announce */
132	msg.id_num = htonl(remote_id + 1);
133	announce_invite();
134	longjmp(invitebuf, 1);
135}
136
137static	const char *answers[] = {
138	"answer #0",					/* SUCCESS */
139	"Your party is not logged on",			/* NOT_HERE */
140	"Target machine is too confused to talk to us",	/* FAILED */
141	"Target machine does not recognize us",		/* MACHINE_UNKNOWN */
142	"Your party is refusing messages",		/* PERMISSION_REFUSED */
143	"Target machine can not handle remote talk",	/* UNKNOWN_REQUEST */
144	"Target machine indicates protocol mismatch",	/* BADVERSION */
145	"Target machine indicates protocol botch (addr)",/* BADADDR */
146	"Target machine indicates protocol botch (ctl_addr)",/* BADCTLADDR */
147};
148#define	NANSWERS	(sizeof (answers) / sizeof (answers[0]))
149
150/*
151 * Transmit the invitation and process the response
152 */
153void
154announce_invite(void)
155{
156	CTL_RESPONSE response;
157
158	current_state = "Trying to connect to your party's talk daemon";
159	ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
160	remote_id = response.id_num;
161	if (response.answer != SUCCESS) {
162		if (response.answer < NANSWERS)
163			message(answers[response.answer]);
164		quit();
165	}
166	/* leave the actual invitation on my talk daemon */
167	current_state = "Trying to connect to local talk daemon";
168	ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response);
169	local_id = response.id_num;
170}
171
172/*
173 * Tell the daemon to remove your invitation
174 */
175void
176send_delete(void)
177{
178
179	msg.type = DELETE;
180	/*
181	 * This is just an extra clean up, so just send it
182	 * and don't wait for an answer
183	 */
184	msg.id_num = htonl(remote_id);
185	daemon_addr.sin_addr = his_machine_addr;
186	if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
187	    (struct sockaddr *)&daemon_addr,
188	    sizeof (daemon_addr)) != sizeof(msg))
189		warn("send_delete (remote)");
190	msg.id_num = htonl(local_id);
191	daemon_addr.sin_addr = my_machine_addr;
192	if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
193	    (struct sockaddr *)&daemon_addr,
194	    sizeof (daemon_addr)) != sizeof (msg))
195		warn("send_delete (local)");
196}
197