xref: /openbsd/usr.bin/talk/invite.c (revision c9899b11)
1 /*	$OpenBSD: invite.c,v 1.17 2016/03/16 15:41:11 krw Exp $	*/
2 /*	$NetBSD: invite.c,v 1.3 1994/12/09 02:14:18 jtc Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 
36 #include <err.h>
37 #include <errno.h>
38 #include <netdb.h>
39 #include <setjmp.h>
40 #include <unistd.h>
41 
42 #include "talk.h"
43 #include "talk_ctl.h"
44 
45 #define STRING_LENGTH 158
46 
47 /*
48  * There wasn't an invitation waiting, so send a request containing
49  * our sockt address to the remote talk daemon so it can invite
50  * him
51  */
52 
53 /*
54  * The msg.id's for the invitations
55  * on the local and remote machines.
56  * These are used to delete the
57  * invitations.
58  */
59 int	local_id, remote_id;
60 jmp_buf invitebuf;
61 
62 void
invite_remote(void)63 invite_remote(void)
64 {
65 	int new_sockt;
66 	struct itimerval itimer;
67 	CTL_RESPONSE response;
68 	struct sockaddr rp;
69 	socklen_t rplen = sizeof(struct sockaddr);
70 	struct hostent *rphost;
71 	char rname[STRING_LENGTH];
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 		quit("Error on attempt to listen for caller", 1);
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 	 * We no longer turn automatic messages back on to avoid a bonus
92 	 * message after we've connected; this is okay even though end_msgs()
93 	 * gets called again in main().
94 	 */
95 	end_msgs();
96 	setitimer(ITIMER_REAL, &itimer, NULL);
97 	message("Waiting for your party to respond");
98 	signal(SIGALRM, re_invite);
99 	(void) setjmp(invitebuf);
100 	while ((new_sockt = accept(sockt, &rp, &rplen)) == -1) {
101 		if (errno == EINTR || errno == EWOULDBLOCK ||
102 		    errno == ECONNABORTED)
103 			continue;
104 		quit("Unable to connect with your party", 1);
105 	}
106 	close(sockt);
107 	sockt = new_sockt;
108 
109 	/*
110 	 * Have the daemons delete the invitations now that we
111 	 * have connected.
112 	 */
113 	msg.id_num = htonl(local_id);
114 	ctl_transact(my_machine_addr, msg, DELETE, &response);
115 	msg.id_num = htonl(remote_id);
116 	ctl_transact(his_machine_addr, msg, DELETE, &response);
117 	invitation_waiting = 0;
118 
119 	/*
120 	 * Check to see if the other guy is coming from the machine
121 	 * we expect.
122 	 */
123 	if (his_machine_addr.s_addr !=
124 	    ((struct sockaddr_in *)&rp)->sin_addr.s_addr) {
125 		rphost = gethostbyaddr((char *) &((struct sockaddr_in
126 		    *)&rp)->sin_addr, sizeof(struct in_addr), AF_INET);
127 		if (rphost)
128 			snprintf(rname, STRING_LENGTH,
129 			    "Answering talk request from %s@%s", msg.r_name,
130 			    rphost->h_name);
131 		else
132 			snprintf(rname, STRING_LENGTH,
133 			    "Answering talk request from %s@%s", msg.r_name,
134 			    inet_ntoa(((struct sockaddr_in *)&rp)->sin_addr));
135 		message(rname);
136 	}
137 }
138 
139 /*
140  * Routine called on interrupt to re-invite the callee
141  */
142 void
re_invite(int dummy)143 re_invite(int dummy)
144 {
145 	message("Ringing your party again");
146 	/* force a re-announce */
147 	msg.id_num = htonl(remote_id + 1);
148 	announce_invite();
149 	longjmp(invitebuf, 1);
150 }
151 
152 static	char *answers[] = {
153 	"answer #0",					/* SUCCESS */
154 	"Your party is not logged on",			/* NOT_HERE */
155 	"Target machine is too confused to talk to us",	/* FAILED */
156 	"Target machine does not recognize us",		/* MACHINE_UNKNOWN */
157 	"Your party is refusing messages",		/* PERMISSION_REFUSED */
158 	"Target machine can not handle remote talk",	/* UNKNOWN_REQUEST */
159 	"Target machine indicates protocol mismatch",	/* BADVERSION */
160 	"Target machine indicates protocol botch (addr)",/* BADADDR */
161 	"Target machine indicates protocol botch (ctl_addr)",/* BADCTLADDR */
162 };
163 #define NANSWERS (sizeof (answers) / sizeof (answers[0]))
164 
165 /*
166  * Transmit the invitation and process the response
167  */
168 void
announce_invite(void)169 announce_invite(void)
170 {
171 	CTL_RESPONSE response;
172 
173 	current_state = "Trying to connect to your party's talk daemon";
174 	ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
175 	remote_id = response.id_num;
176 	if (response.answer != SUCCESS)
177 		quit(response.answer < NANSWERS ? answers[response.answer] : NULL, 0);
178 	/* leave the actual invitation on my talk daemon */
179 	ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response);
180 	local_id = response.id_num;
181 }
182 
183 /*
184  * Tell the daemon to remove your invitation
185  */
186 void
send_delete(void)187 send_delete(void)
188 {
189 
190 	msg.type = DELETE;
191 	/*
192 	 * This is just a extra clean up, so just send it
193 	 * and don't wait for an answer
194 	 */
195 	msg.id_num = htonl(remote_id);
196 	daemon_addr.sin_addr = his_machine_addr;
197 	if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
198 	    (struct sockaddr *)&daemon_addr,
199 	    sizeof (daemon_addr)) != sizeof(msg))
200 		warn("send_delete (remote)");
201 	msg.id_num = htonl(local_id);
202 	daemon_addr.sin_addr = my_machine_addr;
203 	if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
204 	    (struct sockaddr *)&daemon_addr,
205 	    sizeof (daemon_addr)) != sizeof (msg))
206 		warn("send_delete (local)");
207 }
208