4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
28 * All Rights Reserved.
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California.
34 * All Rights Reserved.
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
41 #pragma ident "%Z%%M% %I% %E% SMI"
44 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <sys/fcntl.h>
58 #include "talkd_impl.h"
60 static int nofork
= 0; /* to be set from the debugger */
62 static int announce_proc(CTL_MSG
*request
, char *remote_machine
);
63 static void print_mesg(FILE *tf
, CTL_MSG
*request
, char *remote_machine
);
66 * Because the tty driver insists on attaching a terminal-less
67 * process to any terminal that it writes on, we must fork a child
68 * to protect ourselves.
72 announce(CTL_MSG
*request
, char *remote_machine
)
78 return (announce_proc(request
, remote_machine
));
83 /* we are the parent, so wait for the child */
84 if (pid
== (pid_t
)-1) {
91 if (val
== (pid_t
)-1) {
95 /* shouldn't happen */
100 } while (val
!= pid
);
102 if ((status
& 0377) > 0) {
103 /* we were killed by some signal */
107 /* Get the second byte, this is the exit/return code */
108 return ((status
>>8)&0377);
110 /* we are the child, go and do it */
111 _exit(announce_proc(request
, remote_machine
));
118 * See if the user is accepting messages. If so, announce that
119 * a talk is requested.
122 announce_proc(CTL_MSG
*request
, char *remote_machine
)
125 char full_tty
[TTY_BUFSZ
];
131 (void) snprintf(full_tty
, TTY_BUFSZ
, "/dev/%s", request
->r_tty
);
132 p
= getpwnam(request
->r_name
);
134 if (p
== 0 || access(full_tty
, 0) != 0) {
138 /* fopen uses O_CREAT|O_TRUNC, we don't want that */
139 if ((fd
= open(full_tty
, O_WRONLY
|O_NONBLOCK
)) == -1) {
140 return (PERMISSION_DENIED
);
145 return (PERMISSION_DENIED
);
149 * open gratuitously attaches the talkd to any tty it opens, so
150 * disconnect us from the tty before we catch a signal
154 if (fstat(fd
, &stbuf
) < 0 || stbuf
.st_uid
!= p
->pw_uid
) {
156 return (PERMISSION_DENIED
);
159 if ((stbuf
.st_mode
&020) == 0) {
161 return (PERMISSION_DENIED
);
164 if ((tf
= fdopen(fd
, "w")) == NULL
) {
166 return (PERMISSION_DENIED
);
169 print_mesg(tf
, request
, remote_machine
);
174 #define max(a, b) ((a) > (b) ? (a) : (b))
179 * Build a block of characters containing the message.
180 * It is sent blank filled and in a single block to
181 * try to keep the message in one piece if the recipient
182 * is in vi at the time.
185 print_mesg(FILE *tf
, CTL_MSG
*request
, char *remote_machine
)
187 struct timeval clock
;
188 struct tm
*localclock
;
189 char line_buf
[N_LINES
][N_CHARS
];
195 * [3 wakeup chars + (lines * max chars/line) +
196 * (lines * strlen("\r\n")) + 1(NUL)].
198 char big_buf
[3 + (N_LINES
* (N_CHARS
- 1)) + (N_LINES
* 2) + 1];
200 * ( (length of (request->l_name) - 1(NUL)) *
201 * (strlen("M-") + 1('^') + 1(printable char)) ) + 1(NUL).
203 char l_username
[((NAME_SIZE
- 1) * 4) + 1];
209 (void) gettimeofday(&clock
, NULL
);
210 localclock
= localtime(&clock
.tv_sec
);
212 (void) sprintf(line_buf
[i
], " ");
214 sizes
[i
] = strlen(line_buf
[i
]);
215 max_size
= max(max_size
, sizes
[i
]);
218 (void) snprintf(line_buf
[i
], N_CHARS
,
219 "Message from Talk_Daemon@%s at %d:%02d ...", hostname
,
220 localclock
->tm_hour
, localclock
->tm_min
);
222 sizes
[i
] = strlen(line_buf
[i
]);
223 max_size
= max(max_size
, sizes
[i
]);
226 len
= (strlen(request
->l_name
) > NAME_SIZE
- 1) ? (NAME_SIZE
- 1) :
227 strlen(request
->l_name
);
228 for (j
= 0, k
= 0; j
< len
; j
++) {
229 if (!isprint((unsigned char)request
->l_name
[j
])) {
231 if (!isascii((unsigned char)request
->l_name
[j
])) {
232 l_username
[k
++] = 'M';
233 l_username
[k
++] = '-';
234 c
= toascii(request
->l_name
[j
]);
236 if (iscntrl((unsigned char)request
->l_name
[j
])) {
237 l_username
[k
++] = '^';
238 /* add decimal 64 to the control character */
239 c
= request
->l_name
[j
] + 0100;
243 l_username
[k
++] = request
->l_name
[j
];
246 l_username
[k
] = '\0';
248 (void) snprintf(line_buf
[i
], N_CHARS
,
249 "talk: connection requested by %s@%s.", l_username
, remote_machine
);
251 sizes
[i
] = strlen(line_buf
[i
]);
252 max_size
= max(max_size
, sizes
[i
]);
255 (void) snprintf(line_buf
[i
], N_CHARS
, "talk: respond with: talk %s@%s",
256 l_username
, remote_machine
);
258 sizes
[i
] = strlen(line_buf
[i
]);
259 max_size
= max(max_size
, sizes
[i
]);
262 (void) sprintf(line_buf
[i
], " ");
264 sizes
[i
] = strlen(line_buf
[i
]);
265 max_size
= max(max_size
, sizes
[i
]);
269 *(bptr
++) = '\a'; /* send something to wake them up */
270 *(bptr
++) = '\r'; /* add a \r in case of raw mode */
272 for (i
= 0; i
< N_LINES
; i
++) {
273 /* copy the line into the big buffer */
275 while (*lptr
!= '\0') {
276 *(bptr
++) = *(lptr
++);
279 /* pad out the rest of the lines with blanks */
280 for (j
= sizes
[i
]; j
< max_size
; j
++) {
284 *(bptr
++) = '\r'; /* add a \r in case of raw mode */
289 (void) fputs(big_buf
, tf
);