xref: /original-bsd/libexec/talkd/announce.c (revision f3cd0a77)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)announce.c	5.7 (Berkeley) 05/11/89";
20 #endif /* not lint */
21 
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sgtty.h>
25 #include <sys/ioctl.h>
26 #include <sys/time.h>
27 #include <stdio.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <syslog.h>
31 
32 #include <protocols/talkd.h>
33 #include <paths.h>
34 
35 extern	int errno;
36 extern	char hostname[];
37 
38 /*
39  * Announce an invitation to talk.
40  *
41  * Because the tty driver insists on attaching a terminal-less
42  * process to any terminal that it writes on, we must fork a child
43  * to protect ourselves
44  */
45 announce(request, remote_machine)
46 	CTL_MSG *request;
47 	char *remote_machine;
48 {
49 	int pid, val, status;
50 
51 	if (pid = fork()) {
52 		/* we are the parent, so wait for the child */
53 		if (pid == -1)		/* the fork failed */
54 			return (FAILED);
55 		do {
56 			val = wait(&status);
57 			if (val == -1) {
58 				if (errno == EINTR)
59 					continue;
60 				/* shouldn't happen */
61 				syslog(LOG_WARNING, "announce: wait: %m");
62 				return (FAILED);
63 			}
64 		} while (val != pid);
65 		if (status&0377 > 0)	/* we were killed by some signal */
66 			return (FAILED);
67 		/* Get the second byte, this is the exit/return code */
68 		return ((status >> 8) & 0377);
69 	}
70 	/* we are the child, go and do it */
71 	_exit(announce_proc(request, remote_machine));
72 }
73 
74 /*
75  * See if the user is accepting messages. If so, announce that
76  * a talk is requested.
77  */
78 announce_proc(request, remote_machine)
79 	CTL_MSG *request;
80 	char *remote_machine;
81 {
82 	int pid, status;
83 	char full_tty[32];
84 	FILE *tf;
85 	struct stat stbuf;
86 
87 	(void)sprintf(full_tty, "%s/%s", _PATH_DEV, request->r_tty);
88 	if (access(full_tty, 0) != 0)
89 		return (FAILED);
90 	if ((tf = fopen(full_tty, "w")) == NULL)
91 		return (PERMISSION_DENIED);
92 	/*
93 	 * On first tty open, the server will have
94 	 * it's pgrp set, so disconnect us from the
95 	 * tty before we catch a signal.
96 	 */
97 	ioctl(fileno(tf), TIOCNOTTY, (struct sgttyb *) 0);
98 	if (fstat(fileno(tf), &stbuf) < 0)
99 		return (PERMISSION_DENIED);
100 	if ((stbuf.st_mode&020) == 0)
101 		return (PERMISSION_DENIED);
102 	print_mesg(tf, request, remote_machine);
103 	fclose(tf);
104 	return (SUCCESS);
105 }
106 
107 #define max(a,b) ( (a) > (b) ? (a) : (b) )
108 #define N_LINES 5
109 #define N_CHARS 120
110 
111 /*
112  * Build a block of characters containing the message.
113  * It is sent blank filled and in a single block to
114  * try to keep the message in one piece if the recipient
115  * in in vi at the time
116  */
117 print_mesg(tf, request, remote_machine)
118 	FILE *tf;
119 	CTL_MSG *request;
120 	char *remote_machine;
121 {
122 	struct timeval clock;
123 	struct timezone zone;
124 	struct tm *localtime();
125 	struct tm *localclock;
126 	char line_buf[N_LINES][N_CHARS];
127 	int sizes[N_LINES];
128 	char big_buf[N_LINES*N_CHARS];
129 	char *bptr, *lptr;
130 	int i, j, max_size;
131 
132 	i = 0;
133 	max_size = 0;
134 	gettimeofday(&clock, &zone);
135 	localclock = localtime( &clock.tv_sec );
136 	(void)sprintf(line_buf[i], " ");
137 	sizes[i] = strlen(line_buf[i]);
138 	max_size = max(max_size, sizes[i]);
139 	i++;
140 	(void)sprintf(line_buf[i], "Message from Talk_Daemon@%s at %d:%02d ...",
141 	hostname, localclock->tm_hour , localclock->tm_min );
142 	sizes[i] = strlen(line_buf[i]);
143 	max_size = max(max_size, sizes[i]);
144 	i++;
145 	(void)sprintf(line_buf[i], "talk: connection requested by %s@%s.",
146 		request->l_name, remote_machine);
147 	sizes[i] = strlen(line_buf[i]);
148 	max_size = max(max_size, sizes[i]);
149 	i++;
150 	(void)sprintf(line_buf[i], "talk: respond with:  talk %s@%s",
151 		request->l_name, remote_machine);
152 	sizes[i] = strlen(line_buf[i]);
153 	max_size = max(max_size, sizes[i]);
154 	i++;
155 	(void)sprintf(line_buf[i], " ");
156 	sizes[i] = strlen(line_buf[i]);
157 	max_size = max(max_size, sizes[i]);
158 	i++;
159 	bptr = big_buf;
160 	*bptr++ = ''; /* send something to wake them up */
161 	*bptr++ = '\r';	/* add a \r in case of raw mode */
162 	*bptr++ = '\n';
163 	for (i = 0; i < N_LINES; i++) {
164 		/* copy the line into the big buffer */
165 		lptr = line_buf[i];
166 		while (*lptr != '\0')
167 			*(bptr++) = *(lptr++);
168 		/* pad out the rest of the lines with blanks */
169 		for (j = sizes[i]; j < max_size + 2; j++)
170 			*(bptr++) = ' ';
171 		*(bptr++) = '\r';	/* add a \r in case of raw mode */
172 		*(bptr++) = '\n';
173 	}
174 	*bptr = '\0';
175 	fprintf(tf, big_buf);
176 	fflush(tf);
177 	ioctl(fileno(tf), TIOCNOTTY, (struct sgttyb *) 0);
178 }
179