#include <sys/socket.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <setjmp.h>
#include <unistd.h>
#include "talk.h"
#include "talk_ctl.h"
#define STRING_LENGTH 158
int local_id, remote_id;
jmp_buf invitebuf;
void
invite_remote(void)
{
int new_sockt;
struct itimerval itimer;
CTL_RESPONSE response;
struct sockaddr rp;
socklen_t rplen = sizeof(struct sockaddr);
struct hostent *rphost;
char rname[STRING_LENGTH];
itimer.it_value.tv_sec = RING_WAIT;
itimer.it_value.tv_usec = 0;
itimer.it_interval = itimer.it_value;
if (listen(sockt, 5) != 0)
quit("Error on attempt to listen for caller", 1);
#ifdef MSG_EOR
msg.addr = *(struct osockaddr *)&my_addr;
msg.addr.sa_family = htons(my_addr.sin_family);
#else
msg.addr = *(struct sockaddr *)&my_addr;
#endif
msg.id_num = htonl(-1);
invitation_waiting = 1;
announce_invite();
end_msgs();
setitimer(ITIMER_REAL, &itimer, NULL);
message("Waiting for your party to respond");
signal(SIGALRM, re_invite);
(void) setjmp(invitebuf);
while ((new_sockt = accept(sockt, &rp, &rplen)) == -1) {
if (errno == EINTR || errno == EWOULDBLOCK ||
errno == ECONNABORTED)
continue;
quit("Unable to connect with your party", 1);
}
close(sockt);
sockt = new_sockt;
msg.id_num = htonl(local_id);
ctl_transact(my_machine_addr, msg, DELETE, &response);
msg.id_num = htonl(remote_id);
ctl_transact(his_machine_addr, msg, DELETE, &response);
invitation_waiting = 0;
if (his_machine_addr.s_addr !=
((struct sockaddr_in *)&rp)->sin_addr.s_addr) {
rphost = gethostbyaddr((char *) &((struct sockaddr_in
*)&rp)->sin_addr, sizeof(struct in_addr), AF_INET);
if (rphost)
snprintf(rname, STRING_LENGTH,
"Answering talk request from %s@%s", msg.r_name,
rphost->h_name);
else
snprintf(rname, STRING_LENGTH,
"Answering talk request from %s@%s", msg.r_name,
inet_ntoa(((struct sockaddr_in *)&rp)->sin_addr));
message(rname);
}
}
void
re_invite(int dummy)
{
message("Ringing your party again");
msg.id_num = htonl(remote_id + 1);
announce_invite();
longjmp(invitebuf, 1);
}
static char *answers[] = {
"answer #0",
"Your party is not logged on",
"Target machine is too confused to talk to us",
"Target machine does not recognize us",
"Your party is refusing messages",
"Target machine can not handle remote talk",
"Target machine indicates protocol mismatch",
"Target machine indicates protocol botch (addr)",
"Target machine indicates protocol botch (ctl_addr)",
};
#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
void
announce_invite(void)
{
CTL_RESPONSE response;
current_state = "Trying to connect to your party's talk daemon";
ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
remote_id = response.id_num;
if (response.answer != SUCCESS)
quit(response.answer < NANSWERS ? answers[response.answer] : NULL, 0);
ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response);
local_id = response.id_num;
}
void
send_delete(void)
{
msg.type = DELETE;
msg.id_num = htonl(remote_id);
daemon_addr.sin_addr = his_machine_addr;
if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
(struct sockaddr *)&daemon_addr,
sizeof (daemon_addr)) != sizeof(msg))
warn("send_delete (remote)");
msg.id_num = htonl(local_id);
daemon_addr.sin_addr = my_machine_addr;
if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
(struct sockaddr *)&daemon_addr,
sizeof (daemon_addr)) != sizeof (msg))
warn("send_delete (local)");
}