xref: /original-bsd/libexec/talkd/announce.c (revision 7385a648)
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.6 (Berkeley) 06/18/88";
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 
34 extern	int errno;
35 extern	char hostname[];
36 
37 /*
38  * Announce an invitation to talk.
39  *
40  * Because the tty driver insists on attaching a terminal-less
41  * process to any terminal that it writes on, we must fork a child
42  * to protect ourselves
43  */
44 announce(request, remote_machine)
45 	CTL_MSG *request;
46 	char *remote_machine;
47 {
48 	int pid, val, status;
49 
50 	if (pid = fork()) {
51 		/* we are the parent, so wait for the child */
52 		if (pid == -1)		/* the fork failed */
53 			return (FAILED);
54 		do {
55 			val = wait(&status);
56 			if (val == -1) {
57 				if (errno == EINTR)
58 					continue;
59 				/* shouldn't happen */
60 				syslog(LOG_WARNING, "announce: wait: %m");
61 				return (FAILED);
62 			}
63 		} while (val != pid);
64 		if (status&0377 > 0)	/* we were killed by some signal */
65 			return (FAILED);
66 		/* Get the second byte, this is the exit/return code */
67 		return ((status >> 8) & 0377);
68 	}
69 	/* we are the child, go and do it */
70 	_exit(announce_proc(request, remote_machine));
71 }
72 
73 /*
74  * See if the user is accepting messages. If so, announce that
75  * a talk is requested.
76  */
77 announce_proc(request, remote_machine)
78 	CTL_MSG *request;
79 	char *remote_machine;
80 {
81 	int pid, status;
82 	char full_tty[32];
83 	FILE *tf;
84 	struct stat stbuf;
85 
86 	(void)sprintf(full_tty, "/dev/%s", request->r_tty);
87 	if (access(full_tty, 0) != 0)
88 		return (FAILED);
89 	if ((tf = fopen(full_tty, "w")) == NULL)
90 		return (PERMISSION_DENIED);
91 	/*
92 	 * On first tty open, the server will have
93 	 * it's pgrp set, so disconnect us from the
94 	 * tty before we catch a signal.
95 	 */
96 	ioctl(fileno(tf), TIOCNOTTY, (struct sgttyb *) 0);
97 	if (fstat(fileno(tf), &stbuf) < 0)
98 		return (PERMISSION_DENIED);
99 	if ((stbuf.st_mode&020) == 0)
100 		return (PERMISSION_DENIED);
101 	print_mesg(tf, request, remote_machine);
102 	fclose(tf);
103 	return (SUCCESS);
104 }
105 
106 #define max(a,b) ( (a) > (b) ? (a) : (b) )
107 #define N_LINES 5
108 #define N_CHARS 120
109 
110 /*
111  * Build a block of characters containing the message.
112  * It is sent blank filled and in a single block to
113  * try to keep the message in one piece if the recipient
114  * in in vi at the time
115  */
116 print_mesg(tf, request, remote_machine)
117 	FILE *tf;
118 	CTL_MSG *request;
119 	char *remote_machine;
120 {
121 	struct timeval clock;
122 	struct timezone zone;
123 	struct tm *localtime();
124 	struct tm *localclock;
125 	char line_buf[N_LINES][N_CHARS];
126 	int sizes[N_LINES];
127 	char big_buf[N_LINES*N_CHARS];
128 	char *bptr, *lptr;
129 	int i, j, max_size;
130 
131 	i = 0;
132 	max_size = 0;
133 	gettimeofday(&clock, &zone);
134 	localclock = localtime( &clock.tv_sec );
135 	(void)sprintf(line_buf[i], " ");
136 	sizes[i] = strlen(line_buf[i]);
137 	max_size = max(max_size, sizes[i]);
138 	i++;
139 	(void)sprintf(line_buf[i], "Message from Talk_Daemon@%s at %d:%02d ...",
140 	hostname, localclock->tm_hour , localclock->tm_min );
141 	sizes[i] = strlen(line_buf[i]);
142 	max_size = max(max_size, sizes[i]);
143 	i++;
144 	(void)sprintf(line_buf[i], "talk: connection requested by %s@%s.",
145 		request->l_name, remote_machine);
146 	sizes[i] = strlen(line_buf[i]);
147 	max_size = max(max_size, sizes[i]);
148 	i++;
149 	(void)sprintf(line_buf[i], "talk: respond with:  talk %s@%s",
150 		request->l_name, remote_machine);
151 	sizes[i] = strlen(line_buf[i]);
152 	max_size = max(max_size, sizes[i]);
153 	i++;
154 	(void)sprintf(line_buf[i], " ");
155 	sizes[i] = strlen(line_buf[i]);
156 	max_size = max(max_size, sizes[i]);
157 	i++;
158 	bptr = big_buf;
159 	*bptr++ = ''; /* send something to wake them up */
160 	*bptr++ = '\r';	/* add a \r in case of raw mode */
161 	*bptr++ = '\n';
162 	for (i = 0; i < N_LINES; i++) {
163 		/* copy the line into the big buffer */
164 		lptr = line_buf[i];
165 		while (*lptr != '\0')
166 			*(bptr++) = *(lptr++);
167 		/* pad out the rest of the lines with blanks */
168 		for (j = sizes[i]; j < max_size + 2; j++)
169 			*(bptr++) = ' ';
170 		*(bptr++) = '\r';	/* add a \r in case of raw mode */
171 		*(bptr++) = '\n';
172 	}
173 	*bptr = '\0';
174 	fprintf(tf, big_buf);
175 	fflush(tf);
176 	ioctl(fileno(tf), TIOCNOTTY, (struct sgttyb *) 0);
177 }
178