home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume3 / rsend < prev    next >
Internet Message Format  |  1986-11-30  |  34KB

  1. From: talcott!seismo!enea!ttds!zap (Svante Lindahl)
  2. Subject: rsend - BSD communications program
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 3, Issue 73
  7. Submitted by: seismo!enea!ttds!zap (Svante Lindahl)
  8.  
  9.  
  10.     Here is a program that we use all the time, instead of
  11.     write and talk. It can be used for one-way communication
  12.     (like write) and over a local network (like talk).
  13.     It is very BSD:ish, sockets and all.
  14.  
  15.     We have it running on three VAXen and several SUNs on our
  16.     ethernet, and communication between VAX and SUN works fine
  17.     (unlike talk :-(  (ours does work now!)).
  18.  
  19.     Please, no flames, this was my first UNIX-hack, my first
  20.     C-hack and my first communications program. Accurate criticism
  21.     is of course welcome.
  22.  
  23. : This is a shar archive.  Extract with sh, not csh.
  24. : This archive ends with exit, so do not worry about trailing junk.
  25. echo 'Extracting README'
  26. sed 's/^X//' > README << '+ END-OF-FILE README'
  27. XThis is the README file for rsend.
  28. XThe other files you need are:
  29. X    rsend.h        - the headerfile for rsend.c and rsendd.c
  30. X    rsend.c        - the user interface
  31. X    rsendd.c    - the rsend daemon
  32. X    rsend.1        - the manual entry for rsend
  33. X    Makefile    - makes rsend and rsendd
  34. X
  35. Xrsend is a program for sending messages to other users on a local machine
  36. Xor other machines in a local area network. (cf. SEND on TOPS-10). It is
  37. Ximplemented using sockets and will thus only run on 4.xBSD (for x>=2).
  38. X
  39. XBefore typing make, take a look at the makefile and see which compile-
  40. Xtime flags you want to use.
  41. X
  42. XWhen installing it you need to do the following:
  43. X
  44. X    make an entry for rsend in /etc/services looking something
  45. X    like this:
  46. X        rsend        777/udp
  47. X    (Where 777 is an arbitrary address less than 1024)
  48. X
  49. X    put the following in /etc/rc.local to start the daemon when
  50. X    the machine boots:
  51. X        if [ -f /usr/net/rsendd ]; then
  52. X            /usr/net/rsendd & echo -n ' rsendd' > /dev/console
  53. X        fi
  54. X    (or at least something looking remotely like this, depending
  55. X     on whether you echo the names of local daemons to the console,
  56. X     and where you prefer to install rsendd)
  57. X
  58. XNote that the daemon has to be started by root.
  59. + END-OF-FILE README
  60. chmod 'u=rw,g=rw,o=r' 'README'
  61. echo '    -rw-rw-r--  1 zap          1154 Dec 30 23:04 README        (as sent)'
  62. echo -n '    '
  63. /bin/ls -l README
  64. echo 'Extracting Makefile'
  65. sed 's/^X//' > Makefile << '+ END-OF-FILE Makefile'
  66. XDAEMONDIR    = /usr/net
  67. XDESTDIR        = /usr/local
  68. X
  69. XOBJECTS    = rsendd.o rsend.o
  70. XSOURCE    = rsendd.c rsend.c
  71. XHEADRS    = rsend.h
  72. X
  73. X#
  74. X# Possible defines in CFLAGS are:
  75. X#
  76. X# -DDEBUG    when debugging the daemon, it will run attached to a terminal
  77. X#        compile and load with -g instead of -O, and debug it
  78. X# -DTEST     when testing the daemon, doesn't need to be root, but can't
  79. X#        recieve from other machines (Entry in /etc/services not needed)
  80. X# -DINET_D    if you let the daemon be invoked by inetd (the internet daemon)
  81. X#        when its service is required
  82. X# -DUNIQUE    if you want the user program to check rwho database for
  83. X#        reciever on other hosts when not logged in on the local machine
  84. X#        (i e one username is always the same person on all machines in
  85. X#        the local area network)
  86. X
  87. XCFLAGS    = -O -DUNIQUE
  88. X# LDFLAGS = -O    # when debugging
  89. X
  90. Xall:    rsend rsendd
  91. X    
  92. Xrsend:    rsend.o
  93. X    cc ${LDFLAGS} -o rsend rsend.o
  94. X
  95. Xrsendd:    rsendd.o
  96. X    cc ${LDFLAGS} -o rsendd rsendd.o
  97. X
  98. Xrsend.o:     ${HEADRS}
  99. X
  100. Xrsendd.o:     ${HEADRS}
  101. X
  102. Xinstall:    all
  103. X    strip rsend rsendd
  104. X    cp rsend ${DESTDIR}/rsend
  105. X    cp rsendd ${DAEMONDIR}/rsendd
  106. X    chmod 755 ${DESTDIR}/rsend
  107. X    chmod 700 ${DAEMONDIR/rsendd
  108. X
  109. Xclean:
  110. X    rm -f *.o
  111. + END-OF-FILE Makefile
  112. chmod 'u=rw,g=r,o=r' 'Makefile'
  113. echo '    -rw-r--r--  1 zap          1138 Dec 30 23:11 Makefile        (as sent)'
  114. echo -n '    '
  115. /bin/ls -l Makefile
  116. echo 'Extracting rsend.1'
  117. sed 's/^X//' > rsend.1 << '+ END-OF-FILE rsend.1'
  118. X.TH RSEND Local "30 December 1985"
  119. X.SH NAME
  120. X.B rsend
  121. X\- send a message to another (possibly remote) user
  122. X.SH SYNOPSIS
  123. X.B rsend
  124. Xperson [ \-ttyname ] [ message ]
  125. X.SH DESCRIPTION
  126. X.I Rsend
  127. Xsends a message to another user on your machine,
  128. Xor to a user on another machine in a
  129. Xlocal area network.
  130. X.PP 
  131. XIf you wish to send to someone on you own machine, then
  132. X.I person
  133. Xis just the person's login name. If you wish to send to
  134. Xa user on another host, then
  135. X.I person
  136. Xis of the form:
  137. X.sp
  138. X.in +1.5i
  139. X.I user@host
  140. X\ or\ 
  141. X.I host!user
  142. X\ or
  143. X.br
  144. X.I host:user
  145. X\ or\ 
  146. X.I host.user
  147. X.br
  148. X.in -1.5i
  149. X.sp
  150. XIf you don't specify a host or the username isn't logged in on your
  151. Xmachine (or doesn't even exist on your machine), the rwho\-database
  152. Xis searched for that user on the other hosts in the local area network.
  153. XIf a user is logged in several times 
  154. Xthe tty with the least idletime is choosen to recieve
  155. Xthe message.
  156. X.PP 
  157. X.I Rsend
  158. Xcan be used either with a message on the commandline
  159. Xor interactively. Be aware that the shell will interpret
  160. Xmetacharacters on the commandline, so it may be wise to
  161. Xquote the message, or use
  162. X.I rsend
  163. Xinteractively.
  164. X.PP
  165. XIf a message, for example ``Hello'', is supplied on the commandline
  166. X.I rsend
  167. Xwill send a message, that looks like this:
  168. X.PP
  169. X    <11:47 From yourname@yourhost (yourttyname): Hello>
  170. X.PP
  171. Xand then exit.
  172. XThe message is preceded by, and followed by a newline so that the
  173. Xreciever's screen doesn't get too messed up.
  174. XThere is also a bell (Control\-G) included in the message
  175. Xto alert the recipient.
  176. X.PP
  177. XTo run
  178. X.I rsend
  179. Xinteractively omit the message from the commandline.
  180. X.I Rsend
  181. Xwill prompt ``rsend>'' and at this time the message can
  182. Xbe typed. Nothing will be sent until the first line of
  183. Xthe message is completed (unlike write(1)).
  184. XThe first line sent looks exactly as if
  185. X.I rsend
  186. Xhad been used with the message on the commandline.
  187. XThe rsend\-prompt will return and subsequent non\-empty
  188. Xlines will be sent, looking like this:
  189. X.PP
  190. X    <yourname: text being sent>
  191. X.PP
  192. Xpreceded and followed by a newline.
  193. XTo exit
  194. X.I rsend
  195. Xtype either the EOF\-character, or `.' as the first
  196. Xand only character on a line.
  197. XIf the character `!' is typed first on a line a subshell
  198. Xwill be invoked (as specified by the environment\-variable
  199. XSHELL, or /bin/sh if SHELL is undefined).
  200. XIf the `!' is the only character on the line, the shell
  201. Xwill be interactive, otherwise the rest of the line
  202. Xwill be interpreted as a command to the shell,
  203. Xand the shell will exit after executing the command.
  204. X.PP
  205. XIf the reciever is logged in more than once, the
  206. X.I \-ttyname
  207. Xargument can be used to specify the appropriate
  208. Xterminal, e.g.
  209. X.I ``rsend foo@bar \-ttyd3''
  210. Xor
  211. X.I ``rsend bar!foo \-d3''.
  212. XIt is also possible to replace
  213. X.I ``user''
  214. Xwith a specification of a terminal when specifying
  215. X.I ``person'',
  216. Xe.g.
  217. X.I ``rsend \-d3''
  218. Xor
  219. X.I ``rsend \-ttyd3@bar''.
  220. X.SH DIAGNOSTICS
  221. XIf a message couldn't be sent an appropriate
  222. Xwarning is written to the senders terminal.
  223. X.SH FILES
  224. X/etc/utmp        searched for reciever
  225. X/usr/spool/rwho/whod.*    searched for reciever
  226. X/bin/sh        subshell if SHELL is not found
  227. X.SH "SEE ALSO"
  228. Xmesg(1), who(1), rwho(1C), talk(1), mail(1), write(1)
  229. X.SH AUTHOR
  230. XSvante Lindahl, Royal Institute of Technology, Stockholm
  231. X.SH BUGS
  232. XPossibly!
  233. + END-OF-FILE rsend.1
  234. chmod 'u=rw,g=r,o=r' 'rsend.1'
  235. echo '    -rw-r--r--  1 zap          3230 Dec 30 22:35 rsend.1        (as sent)'
  236. echo -n '    '
  237. /bin/ls -l rsend.1
  238. echo 'Extracting rsend.h'
  239. sed 's/^X//' > rsend.h << '+ END-OF-FILE rsend.h'
  240. X/*
  241. X * $Header: rsend.h,v 1.7 85/09/12 15:07:15 zap Exp $
  242. X */
  243. X
  244. X/*
  245. X * Revision 1.2  85/08/17  01:44:22  zap
  246. X * New format for msg - request type field added, request types can be
  247. X * CHECK (check if reciver is logged in and tty writeable) and SEND
  248. X * (go ahead and send message).
  249. X * 
  250. X * Revision 1.1  85/08/16  21:42:05  zap
  251. X * Initial revision
  252. X * 
  253. X *    rsend.h    1.0    zap@bogart    1985-07-02 03:39:48
  254. X */
  255. X
  256. X/*
  257. X** Copyright (C) 1985 by Svante Lindahl.
  258. X**
  259. X** rsend - send a message to a local or remote user
  260. X**
  261. X*/
  262. X
  263. X#include <sys/types.h>
  264. X#include <sys/socket.h>
  265. X#include <pwd.h>
  266. X#include <utmp.h>
  267. X#include <netdb.h>
  268. X#include <netinet/in.h>
  269. X#include <stdio.h>
  270. X#include <errno.h>
  271. X#include <signal.h>
  272. X#include <sys/wait.h>
  273. X#include <sys/stat.h>
  274. X#include <sys/dir.h>
  275. X#include <sys/time.h>
  276. X#include "/usr/src/net/rwhod/rwhod.h"
  277. X
  278. X#define TRUE    1
  279. X#define    FALSE    0
  280. X#define ever    ;;
  281. X
  282. X#ifdef    TEST
  283. X#define RENDEZ_VOUS    11147
  284. X#endif
  285. X
  286. X#define NAME_SIZE    9
  287. X#define TTY_SIZE    8
  288. X#define    LINE_LENGTH    80
  289. X#define BUF_SIZE    400
  290. X#define HOST_NAME_SIZE    32
  291. X
  292. X#define WHDRSIZE   (sizeof(wd) - sizeof (wd.wd_we))
  293. X
  294. X/* request values */
  295. X#define    CHECK        0
  296. X#define    SEND        1
  297. X
  298. X/* response values */
  299. X#define SUCCESS        0
  300. X#define NO_USER        1
  301. X#define NOT_IN        2
  302. X#define NOT_TTY        3
  303. X#define    WRNG_TTY    4
  304. X#define NOT_USED    5
  305. X#define    DENIED        6
  306. X#define OP_UTMP        7
  307. X#define OP_TTY        8
  308. X#define WR_FAIL        9
  309. X#define CONFUSED    10
  310. X#define NO_ANSW        11
  311. X#define CHDIR        12
  312. X
  313. X/* Seems like nr of bytes must be divisible by 4 to work between Sun and VAX */
  314. Xstruct rsend_msg {    
  315. X    char rcv_name[NAME_SIZE];   /*   9 */
  316. X    char rcv_tty[TTY_SIZE];     /*   8 */
  317. X    char rqst_type;            /*   1 */
  318. X    char fill[2];            /*   2 */
  319. X    char text[BUF_SIZE];        /* 400 */
  320. X} msg;
  321. X
  322. X/* Seems like nr of bytes must be divisible by 4 to work between Sun and VAX */
  323. Xstruct rsend_rsp {
  324. X        char code;                  /*   1 */
  325. X    char fill[2];               /*   2 */
  326. X        char rcv_name[NAME_SIZE];   /*   9 */
  327. X        char rcv_tty[TTY_SIZE];     /*   8 */
  328. X} rsp;
  329. X
  330. Xextern int errno;
  331. + END-OF-FILE rsend.h
  332. chmod 'u=r,g=r,o=r' 'rsend.h'
  333. echo '    -r--r--r--  1 zap          1990 Sep 12 15:07 rsend.h        (as sent)'
  334. echo -n '    '
  335. /bin/ls -l rsend.h
  336. echo 'Extracting rsendd.c'
  337. sed 's/^X//' > rsendd.c << '+ END-OF-FILE rsendd.c'
  338. X#ifndef lint
  339. Xstatic char *RCSid = "$Header: rsendd.c,v 1.8 85/12/30 22:56:16 zap Exp $";
  340. Xstatic char *Copyright = "rsendd.c  Copyright (C) 1985 Svante Lindahl.";
  341. X#endif
  342. X
  343. X/*
  344. X * $Log:    rsendd.c,v $
  345. X * Revision 1.8  85/12/30  22:56:16  zap
  346. X * Made lint happier.
  347. X * 
  348. X * Revision 1.7  85/10/06  19:50:46  zap
  349. X * Problem: daemon would occasionally get hung, fix(?): timeout after 3
  350. X * seconds in wait and send a SIGKILL to the child.
  351. X * 
  352. X * Revision 1.6  85/10/06  19:04:30  zap
  353. X * Bugfix; didn't recognize that a tty was unused, badly placed '!' removed.
  354. X * 
  355. X * Revision 1.5  85/08/21  18:27:59  zap
  356. X * Better way of finding tty with least idletime.
  357. X * 
  358. X * Revision 1.4  85/08/19  23:09:44  zap
  359. X * The daemon now tries to find reciver's job with least idletime if no
  360. X * particular tty is requested.
  361. X * 
  362. X * Revision 1.3  85/08/19  21:10:34  zap
  363. X * Some small fixes.
  364. X * 
  365. X * Revision 1.2  85/08/17  01:31:28  zap
  366. X * Checks if person is logged in and tty is writeable when called with
  367. X * request type CHECK, only writes on tty with request is set to SEND.
  368. X * 
  369. X * Revision 1.1  85/08/16  21:40:20  zap
  370. X * Initial revision
  371. X * 
  372. X * rsendd.c    1.0    zap@bogart    1985-07-05 18:00:30
  373. X *
  374. X */
  375. X
  376. X/*
  377. X** rsendd - daemon for rsend a message sending program 
  378. X**
  379. X** This program, and any documentation for it, is copyrighted by Svante
  380. X** Lindahl. It may be copied for non-commercial use only, provided that
  381. X** any and all copyright notices are preserved.
  382. X**
  383. X** Please report any bugs and/or fixes to:
  384. X**
  385. X** UUCP: {seismo,mcvax,cernvax,diku,ircam,prlb2,tut,ukc,unido}!enea!ttds!zap
  386. X** ARPA: enea!ttds!zap@seismo.ARPA
  387. X**   or  Svante_Lindahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA
  388. X**
  389. X*/
  390. X
  391. X#include "rsend.h"
  392. X
  393. X#include <fcntl.h>
  394. X#include <sys/ioctl.h>
  395. X#include <sys/resource.h>
  396. X
  397. X#ifdef    INET_D
  398. X#define TIMEOUT    30        /* let the daemon time out and exit if.. */
  399. X#define MAXIDLE    120       /* ..it is invoked by the inet-daemon    */
  400. X#endif
  401. X
  402. Xstruct    sockaddr_in sin, from ;
  403. Xint    fromlen = sizeof(from) ;
  404. Xextern    int doit() ;
  405. X
  406. X#ifndef DEBUG
  407. Xint    pid ;
  408. Xlong    lastmsgtime ;
  409. X#endif
  410. X
  411. Xmain ()
  412. X{
  413. X    int s, f, cc, w;
  414. X    union wait status;
  415. X    int (*saveintr)(), (*savequit)();
  416. X    struct passwd *getpwnam() ;
  417. X    struct servent *sp ;
  418. X#ifndef    DEBUG
  419. X    extern    void reaper(), chaser() ;
  420. X#endif
  421. X#ifdef    INET_D
  422. X    extern    void timeout() ;
  423. X#endif
  424. X    
  425. X    sin.sin_addr.s_addr = INADDR_ANY ;
  426. X    sin.sin_family = AF_INET ;
  427. X#ifndef TEST
  428. X    if (getuid()) {
  429. X        fprintf (stderr, "rsendd: not super user\n") ;
  430. X        exit(1) ;
  431. X    }
  432. X    sp = getservbyname("rsend", "udp") ;
  433. X    if (sp == NULL) {
  434. X        fprintf (stderr, "rsendd: udp/rsend: unknown service\n") ;
  435. X        exit(1) ;
  436. X    }
  437. X    sin.sin_port = sp->s_port ;
  438. X#else
  439. X    sin.sin_port = htons(RENDEZ_VOUS) ;
  440. X#endif
  441. X#ifndef    DEBUG
  442. X     /* fork, parent quits, child dissociates itself from the tty */
  443. X    if (fork())
  444. X        _exit(0) ;
  445. X    for (f = 0 ; f < 5 ; f++)
  446. X        (void) close(f) ;
  447. X    (void) open("/dev/null", O_RDONLY) ;
  448. X    (void) open("/dev/null", O_WRONLY) ;
  449. X    (void) dup(1) ;
  450. X    if ((f = open("/dev/tty", O_RDWR)) > 0) {
  451. X        (void) ioctl(f, (int) TIOCNOTTY, (char *) 0) ;
  452. X        (void) close(f) ;
  453. X    }
  454. X    s = socket(AF_INET, SOCK_DGRAM, 0) ;
  455. X    if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  456. X        perror("rsendd: bind") ;
  457. X        exit(1) ;
  458. X    }
  459. X    (void) signal(SIGCHLD, reaper) ;    /* try not to leave zombies around */
  460. X    for(ever) {
  461. X        cc = recvfrom(s, (char *)&msg, sizeof(msg),
  462. X                      0, (struct sockaddr *) &from, &fromlen);
  463. X        if ((pid = vfork()) == 0)
  464. X            exit(doit(s, cc)) ;
  465. X        (void) time(&lastmsgtime) ;
  466. X        saveintr = signal(SIGINT, SIG_IGN) ;
  467. X        savequit = signal(SIGQUIT, SIG_IGN) ;
  468. X    (void) signal(SIGALRM, chaser) ;
  469. X        (void) alarm(3);
  470. X        while ((w = wait(&status)) != pid && w != -1)
  471. X            ;
  472. X        (void) signal(SIGQUIT, saveintr) ;
  473. X        (void) signal(SIGQUIT, savequit) ;
  474. X#ifdef    INET_D
  475. X        (void) signal(SIGALRM, timeout) ;
  476. X        (void) alarm(TIMEOUT) ;
  477. X#else
  478. X    (void) alarm(0) ;
  479. X#endif
  480. X    }
  481. X#else
  482. X    s = socket(AF_INET, SOCK_DGRAM, 0) ;
  483. X    if (bind(s, &sin, sizeof(sin)) < 0) {
  484. X        perror("rsendd: bind") ;
  485. X        exit(1) ;
  486. X    }
  487. X    for(ever) {
  488. X        cc = recvfrom(s, (char *)&msg, sizeof(msg), 0, &from, &fromlen) ;
  489. X        doit(s, cc) ;
  490. X    }
  491. X#endif
  492. X}
  493. X
  494. Xint
  495. Xdoit(s, cc)
  496. X    int s, cc ;
  497. X{
  498. X    int  f, i, idle = -1 ;
  499. X    struct stat st ;
  500. X    struct utmp ut ;
  501. X    struct passwd *pwp ;
  502. X    long   now ;
  503. X
  504. X    if (cc != sizeof(msg)) {
  505. X        if (cc < 0 && errno != EINTR)
  506. X            perror("recvfrom") ;
  507. X        return(1) ;
  508. X    }
  509. X    if (chdir("/dev") < 0)
  510. X        rsp.code = CHDIR ;
  511. X    else if (*msg.rcv_tty != '\0') {
  512. X        (void) strcpy(rsp.rcv_tty, msg.rcv_tty) ;
  513. X        if (stat(msg.rcv_tty, &st) < 0)
  514. X            rsp.code = NOT_TTY ;
  515. X        else if (((st.st_uid == 0) && (strcmp(msg.rcv_name, "root")))
  516. X          || (pwp = getpwuid(st.st_uid)) == NULL)
  517. X            rsp.code = NOT_USED ;
  518. X        else if (*msg.rcv_name != '\0') {
  519. X            (void) strcpy(rsp.rcv_name, msg.rcv_name) ;
  520. X            if (getpwnam(msg.rcv_name) == NULL)
  521. X                rsp.code = NO_USER ;
  522. X            else if (strcmp(msg.rcv_name, pwp->pw_name) != 0)
  523. X                rsp.code = WRNG_TTY ;
  524. X            else if (!(st.st_mode & 2))
  525. X                rsp.code = DENIED ;
  526. X            else
  527. X                rsp.code = SUCCESS ;
  528. X        } else {
  529. X            if (!(st.st_mode & 2))
  530. X                rsp.code = DENIED ;
  531. X            else {
  532. X                rsp.code = SUCCESS ;
  533. X                (void) strcpy(rsp.rcv_name, pwp->pw_name) ;
  534. X            }
  535. X        }
  536. X    } else if (*msg.rcv_name != '\0') {
  537. X        (void) strcpy(rsp.rcv_name, msg.rcv_name) ;
  538. X        if (getpwnam(msg.rcv_name) == NULL)
  539. X            rsp.code = NO_USER ;
  540. X    else if ((f = open ("/etc/utmp", 0)) < 0)
  541. X        rsp.code = OP_UTMP ;
  542. X    else {        /* search for reciver in /etc/utmp */
  543. X        rsp.code = NOT_IN ;
  544. X        (void) time(&now) ;
  545. X        while (read (f, (char *)&ut, sizeof(ut)) > 0) {
  546. X        if (strcmp(msg.rcv_name, ut.ut_name) == 0) {
  547. X            if ((stat(ut.ut_line, &st) >= 0) && (st.st_mode & 2) 
  548. X                      && (((i = now - st.st_mtime) < idle) || (idle = -1))) {
  549. X                        (void) strcpy(rsp.rcv_tty, ut.ut_line) ;
  550. X            rsp.code = SUCCESS ;
  551. X                        idle = i ;
  552. X            } else if (rsp.code != SUCCESS) {
  553. X                        (void) strcpy(rsp.rcv_tty, ut.ut_line) ;
  554. X            rsp.code = DENIED ;
  555. X            }
  556. X        }
  557. X        }
  558. X        (void) close(f) ;
  559. X        }
  560. X    } else
  561. X        rsp.code = CONFUSED ;        /* hopefully not reached... */
  562. X
  563. X    if (rsp.code == SUCCESS) {       /* found somewhere to send it */
  564. X        if ((f = open(rsp.rcv_tty, O_WRONLY)) < 0)
  565. X            rsp.code = OP_TTY ;
  566. X        else if (msg.rqst_type == SEND) {
  567. X            if (write(f, msg.text, strlen(msg.text)) != strlen(msg.text))
  568. X                rsp.code = WR_FAIL ;
  569. X            (void) close(f) ;
  570. X        }
  571. X    }
  572. X    /* send status report to the sender */
  573. X    cc = sendto(s, (char *)&rsp, sizeof(rsp),
  574. X                0, (struct sockaddr *) &from, sizeof(from)) ;
  575. X    return(cc == sizeof(rsp) ? 0 : -1) ;
  576. X}
  577. X
  578. X#ifdef    INET_D
  579. Xvoid
  580. Xtimeout()
  581. X{
  582. X    long now ;
  583. X
  584. X    (void) time(&now) ;
  585. X    if (now - lastmsgtime >= MAXIDLE)
  586. X        exit(0) ;
  587. X    (void) alarm(TIMEOUT) ;
  588. X}
  589. X#endif
  590. X
  591. X#ifndef DEBUG
  592. Xvoid
  593. Xreaper()            /* takes care of getting rid of zombie-children */
  594. X{
  595. X    union wait status ;
  596. X
  597. X    while (wait3(&status, WNOHANG, (struct rusage *) 0) > 0) ;
  598. X}
  599. X
  600. Xvoid
  601. Xchaser()        /* chase down children that refuse to die */
  602. X{
  603. X    (void) kill(pid, SIGKILL) ;
  604. X}
  605. X#endif
  606. + END-OF-FILE rsendd.c
  607. chmod 'u=r,g=r,o=r' 'rsendd.c'
  608. echo '    -r--r--r--  1 zap          7552 Dec 30 22:56 rsendd.c        (as sent)'
  609. echo -n '    '
  610. /bin/ls -l rsendd.c
  611. echo 'Extracting rsend.c'
  612. sed 's/^X//' > rsend.c << '+ END-OF-FILE rsend.c'
  613. X#ifndef lint
  614. Xstatic char *RCSid = "$Header: rsend.c,v 1.7 85/12/30 22:54:02 zap Exp $";
  615. Xstatic char *Copyright = "rsend.c  Copyright (C) 1985 Svante Lindahl.";
  616. X#endif
  617. X
  618. X/*
  619. X * $Log:    rsend.c,v $
  620. X * Revision 1.7  85/12/30  22:54:02  zap
  621. X * Made lint happier. Fixed bug, replacing strcmp with strncmp.
  622. X * 
  623. X * Revision 1.6  85/10/06  19:01:35  zap
  624. X * Bugfix; working directory was "wrong" when shellescape invoked, now
  625. X * does a chdir back after checking things in /dev & /usr/spool/rwho.
  626. X * 
  627. X * Revision 1.5  85/08/21  17:37:12  zap
  628. X * Now chooses to send to writeable tty with least idletime if reciever
  629. X * is logged in more than once on the local host.
  630. X * 
  631. X * Revision 1.4  85/08/19  23:08:56  zap
  632. X * Small change.
  633. X * 
  634. X * Revision 1.3  85/08/19  21:27:51  zap
  635. X * When no host is specified and the reciever isn't logged in on the local
  636. X * host the rwho database is searched to find reciever on an other machine
  637. X * in the local area network. If logged in several times on other hosts the
  638. X * tty (pty) with the least idletime is selected.
  639. X * 
  640. X * Revision 1.2  85/08/17  01:40:41  zap
  641. X * Now checks if reciever is logged in and tty is writeable before entering
  642. X * interactive mode.
  643. X * 
  644. X * Revision 1.1  85/08/16  21:41:09  zap
  645. X * Initial revision
  646. X * 
  647. X * rsend.c    1.0    zap@bogart    1985-07-23 21:29:27
  648. X *
  649. X */
  650. X
  651. X/*
  652. X** rsend - send a message to a local or remote user
  653. X**
  654. X** This program, and any documentation for it, is copyrighted by Svante
  655. X** Lindahl. It may be copied for non-commercial use only, provided that
  656. X** any and all copyright notices are preserved.
  657. X**
  658. X** Please report any bugs and/or fixes to:
  659. X**
  660. X** UUCP: {seismo,mcvax,cernvax,diku,ircam,prlb2,tut,ukc,unido}!enea!ttds!zap
  661. X** ARPA: enea!ttds!zap@seismo.ARPA
  662. X**   or  Svante_Lindahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA
  663. X**
  664. X*/
  665. X
  666. X#include "rsend.h"
  667. X
  668. X#define    TIMEOUT    2                    /* seconds */
  669. X
  670. Xint    Argc, remotesend, interactive = FALSE ;
  671. Xchar    **Argv, *my_name, *my_tty ;
  672. Xchar    my_cpu[HOST_NAME_SIZE] ;
  673. Xchar    rcv_cpu[HOST_NAME_SIZE] ;
  674. Xstruct    sockaddr_in sin;
  675. X
  676. Xchar    *getlogin(), *ttyname(), *rindex() ;
  677. Xstruct    hostent *gethostbyname() ;
  678. Xstruct    servent *getservbyname() ;
  679. X
  680. Xextern    void err_check () ;
  681. Xextern    void who_am_i () ;
  682. Xextern    void who_is_rcvr () ;
  683. Xextern    void set_up_msg() ;
  684. Xextern    void set_up_tty() ;
  685. Xextern    int  where_is_rcvr () ;
  686. Xextern    void where_to () ;
  687. Xextern    void check_it () ;
  688. Xextern    void be_interactive () ;
  689. Xextern    void do_shell ();
  690. Xextern    void build_msg () ;
  691. Xextern    int  build_header () ;
  692. Xextern    void send_it () ;
  693. Xextern    void timeout() ;
  694. Xextern    void error_handle() ;
  695. X
  696. Xmain (argc, argv)
  697. X    int argc ;
  698. X    char **argv ;
  699. X{
  700. X    Argc = argc ;
  701. X    Argv = argv ;
  702. X    err_check () ;
  703. X    who_am_i () ;
  704. X    who_is_rcvr () ;
  705. X    where_to () ;
  706. X    if (interactive) {
  707. X        check_it () ;
  708. X        be_interactive() ;
  709. X    } else {
  710. X        build_msg () ;
  711. X        send_it () ;
  712. X    }
  713. X}
  714. X
  715. Xvoid
  716. Xerr_check ()
  717. X{
  718. X    if (Argc < 2 ) {
  719. X        fprintf(stderr,
  720. X            "Usage: rsend user[@host] [-tty] [message...]\n") ;
  721. X        exit(1) ;
  722. X    }
  723. X    if (!isatty(0)) {
  724. X        fprintf(stderr,
  725. X               "rsend: Sorry, standard input must be a tty!\n") ;
  726. X        exit(1) ;
  727. X    }
  728. X}
  729. X
  730. Xvoid
  731. Xwho_am_i ()
  732. X{
  733. X    struct passwd *pwp ;
  734. X
  735. X    my_name = getlogin() ;
  736. X    if (*my_name == NULL)
  737. X        if ((pwp = getpwuid(getuid())) == NULL) {
  738. X            fprintf(stderr, "You are not for real!.\n") ;
  739. X            exit(1) ;
  740. X        }
  741. X        else
  742. X            my_name = (char *)pwp->pw_name ;
  743. X    my_tty = rindex(ttyname(0), '/') + 1 ;
  744. X    (void) gethostname(my_cpu, sizeof(my_cpu)) ;
  745. X}
  746. X
  747. Xvoid
  748. Xwho_is_rcvr ()
  749. X{
  750. X    char *ptr ;
  751. X    int  code ;
  752. X
  753. X    Argc-- ;  Argv++ ;
  754. X    *msg.rcv_tty = '\0' ;
  755. X    *msg.rcv_name = '\0' ;
  756. X    for (ptr = *Argv ; *ptr != '\0' && *ptr != '@' && *ptr != ':' 
  757. X        && *ptr != '!' && *ptr != '.' ; ptr++)
  758. X            ;
  759. X    if (*ptr == '\0') {               /* no host specified */
  760. X        set_up_msg(*Argv, my_cpu) ;
  761. X        if (*msg.rcv_tty == '\0') {
  762. X            if ((code = where_is_rcvr()) != SUCCESS)
  763. X                error_handle(code) ;
  764. X    }
  765. X    } else {
  766. X        if (*ptr == '@') {            /* user@host || -tty@host */
  767. X            *ptr++ = '\0' ;
  768. X            set_up_msg(*Argv, ptr) ;
  769. X        } else {                      /* host[.!:]user || host[.!:]-tty */
  770. X            *ptr++ = '\0' ;     
  771. X            set_up_msg(ptr, *Argv) ;
  772. X        }
  773. X    }
  774. X    remotesend = strcmp(rcv_cpu, my_cpu) ;
  775. X    Argc-- ;  Argv++ ;
  776. X    if (Argc == 0)                    /* anything left on the commandline? */
  777. X        interactive = TRUE ;
  778. X    else if (**Argv == '-') {         /* tty-specification? */
  779. X        set_up_tty(&Argv[0][1]) ;
  780. X        Argc-- ;  Argv++ ;
  781. X        if (Argc == 0)                /* still more? */
  782. X            interactive = TRUE ;
  783. X    }
  784. X}
  785. X
  786. Xvoid
  787. Xset_up_msg(ptr, cpu)
  788. X    char *ptr, *cpu;
  789. X{
  790. X    if (*ptr != '-')                  /* reciever's username or tty? */
  791. X        (void) strcpy(msg.rcv_name, ptr) ;
  792. X    else
  793. X        set_up_tty(++ptr) ;
  794. X    (void) strcpy(rcv_cpu, cpu) ;
  795. X}
  796. X
  797. Xvoid
  798. Xset_up_tty(ptr)
  799. X    char *ptr ;
  800. X{
  801. X    if (!strcmp("console", ptr))
  802. X        (void) strcpy(msg.rcv_tty, ptr) ;
  803. X    else {
  804. X        if (strncmp("tty", ptr, 3)) 
  805. X            (void) strcpy(msg.rcv_tty, "tty") ;
  806. X        (void) strcat(msg.rcv_tty, ptr) ;
  807. X    }
  808. X    msg.rcv_tty[TTY_SIZE-1] = '\0' ;
  809. X}
  810. X
  811. Xint
  812. Xwhere_is_rcvr()
  813. X{
  814. X    int    code, f, i, idle = -1, nowd = 0 ;
  815. X    char   path[1024], *getwd() ;
  816. X    struct stat st ;
  817. X    struct utmp ut ;
  818. X    long   now ;
  819. X
  820. X    if (getwd(path) == '\0')
  821. X        nowd++ ;
  822. X    if (getpwnam(msg.rcv_name) == NULL)
  823. X        code = NO_USER ;
  824. X    else if ((f = open ("/etc/utmp", 0)) < 0)
  825. X        code = OP_UTMP ;
  826. X    else if (chdir("/dev") < 0)
  827. X        code = CHDIR ;
  828. X    else {
  829. X        code = NOT_IN ;       /* search for reciver in /etc/utmp */
  830. X        (void) time(&now) ;
  831. X    while (read(f, (char *)&ut, sizeof(ut)) > 0) {
  832. X        if (strncmp (msg.rcv_name, ut.ut_name, 8) == 0) {
  833. X        if ((stat(ut.ut_line, &st) >= 0) && (st.st_mode & 2)
  834. X          && (((i = now - st.st_mtime) < idle) || (idle = -1))) {
  835. X            (void) strcpy(msg.rcv_tty, ut.ut_line) ;
  836. X            code = SUCCESS ;
  837. X                    idle = i ;
  838. X        } else if (code != SUCCESS) { 
  839. X                    (void) strcpy(msg.rcv_tty, ut.ut_line) ;
  840. X            code = DENIED ;
  841. X        }
  842. X        }
  843. X    }
  844. X        (void) close(f) ;
  845. X    }
  846. X#ifdef UNIQUE
  847. X    {
  848. X        int    cc, n ;
  849. X        DIR   *dirp ;
  850. X        struct direct *dp ;
  851. X        struct whoent *we ;
  852. X        struct whod wd ;
  853. X        register struct whod *wp = &wd ;
  854. X
  855. X        if (   ((code == NO_USER) || (code == NOT_IN) || (code == CHDIR))
  856. X            && (chdir("/usr/spool/rwho") >= 0)
  857. X            && ((dirp = opendir(".")) != NULL)) {
  858. X            /* check other machines in local network (use rwho database) */
  859. X        (void) time(&now) ;
  860. X        while (dp = readdir (dirp)) {
  861. X        if ((dp->d_ino == 0) || (strncmp(dp->d_name, "whod.", 5)))
  862. X            continue ;
  863. X        if ((f = open(dp->d_name, 0)) < 0)
  864. X            continue ;
  865. X        cc = read(f, (char *)&wd, sizeof(struct whod)) ;
  866. X        if ((cc < WHDRSIZE) ||  (now - wp->wd_recvtime > 5 * 60) 
  867. X          || (!strcmp (my_cpu, wp->wd_hostname))) {
  868. X            (void) close (f) ;
  869. X            continue ;
  870. X        }
  871. X        for(we = wp->wd_we,
  872. X                  n = (cc - WHDRSIZE) / sizeof(struct whoent);
  873. X          n > 0; n--, we++) {
  874. X            if (strncmp(msg.rcv_name, we->we_utmp.out_name, 8))
  875. X            continue ;
  876. X            if ((i = we->we_idle) < idle || idle == -1) {
  877. X            code = SUCCESS ;
  878. X            idle = i ;
  879. X            (void) strcpy(rcv_cpu, wp->wd_hostname) ;
  880. X            (void) strcpy(msg.rcv_tty, we->we_utmp.out_line) ;
  881. X            }
  882. X        }
  883. X        (void) close (f) ;
  884. X        }
  885. X        if (code == SUCCESS)
  886. X        fprintf(stderr, "%s not logged in on %s, sending to %s@%s\n",
  887. X          msg.rcv_name, my_cpu, msg.rcv_name, rcv_cpu) ;
  888. X    }
  889. X    }
  890. X#endif 
  891. X    if (!nowd)
  892. X        (void) chdir(path) ;
  893. X    return(code) ;
  894. X}
  895. X
  896. Xvoid
  897. Xwhere_to()
  898. X{
  899. X    struct    hostent *hp ;
  900. X    struct    servent *sp ;
  901. X
  902. X    hp = gethostbyname(rcv_cpu) ;      /* get address of reciever's machine */
  903. X    if (hp == (struct hostent *) 0 ) {
  904. X        fprintf(stderr, "rsend: I don't know a machine named %s\n", rcv_cpu) ;
  905. X        exit(1) ;
  906. X    }
  907. X    bzero(&sin, sizeof (sin)) ;
  908. X    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length) ;
  909. X    sin.sin_family = hp->h_addrtype ;
  910. X#ifndef    TEST
  911. X    sp = getservbyname("rsend", "udp") ;     /* find daemon's port */
  912. X    if (sp == NULL) {
  913. X        fprintf(stderr, "rsend isn't supported by this machine\n") ;
  914. X        exit(1) ;
  915. X    }
  916. X    sin.sin_port = sp->s_port ;
  917. X#else
  918. X    if (remotesend) {    /* remote sends not supported when testing */
  919. X        fprintf(stderr,
  920. X            "Sorry, only local sends are supported at this time\n") ;
  921. X        exit(1) ;
  922. X    }
  923. X    sin.sin_port = htons(RENDEZ_VOUS) ;      /* find daemon's port */
  924. X#endif
  925. X}
  926. X
  927. Xvoid
  928. Xcheck_it()
  929. X{
  930. X    msg.rqst_type = CHECK ;
  931. X    send_it() ;
  932. X    msg.rqst_type = SEND ;
  933. X}
  934. X
  935. Xvoid
  936. Xbe_interactive()
  937. X{
  938. X    int hdr_siz, i ;
  939. X    char buf[BUF_SIZE] ;
  940. X
  941. X    hdr_siz = build_header () ;   /* standard header for first message */
  942. X    msg.text[hdr_siz++] = ' ' ;
  943. X    msg.text[hdr_siz] = '\0' ;
  944. X    for(ever) {
  945. X        printf("rsend>") ;        /* prompt for input */
  946. X        (void) fflush(stdout) ;
  947. X        if (fgets(buf, sizeof(buf), stdin) != NULL) {
  948. X            if ((i = strlen(buf)) > 1) {
  949. X                buf[--i] = '\0' ;             /* nullify the \n from fgets */
  950. X                if (i == 1 && *buf == '.')    /* '.' to exit pgm */
  951. X                    break ;
  952. X                else if (*buf == '!') 
  953. X                    do_shell(i, buf) ;
  954. X                else {
  955. X                    if (hdr_siz + i > LINE_LENGTH)  /* separate header if .. */
  956. X                        (void) strcat(msg.text, "\r\n") ; /* .. long message */
  957. X                    if (hdr_siz + i + 8 > BUF_SIZE) {     /* too much... */
  958. X                        (void) strncat(msg.text, buf, BUF_SIZE-hdr_siz-i-8) ;
  959. X                        (void) strcat(msg.text, "...\r\n") ;
  960. X                        fprintf(stderr, 
  961. X                            "rsend: long message, %d word(s) truncated\n",
  962. X                                Argc + 1) ;
  963. X                    } else {
  964. X                        (void) strcat(msg.text, buf) ;
  965. X                        (void) strcat(msg.text, ">\r\n") ;
  966. X                    }
  967. X                    msg.text[BUF_SIZE-1] = '\0' ;
  968. X                    send_it() ;
  969. X                    (void) sprintf(msg.text, "\r\n<%s: ", my_name) ; 
  970. X                    hdr_siz = strlen(msg.text) ;
  971. X                }
  972. X            }
  973. X        } else {
  974. X            printf("\r\n") ;
  975. X            break ;
  976. X        }
  977. X    } 
  978. X}
  979. X
  980. Xvoid
  981. Xdo_shell (i, cmd)
  982. X    int i ;
  983. X    char *cmd ;
  984. X{
  985. X    int pid, w ;
  986. X    union wait status ;
  987. X    char *sh, *getenv() ;
  988. X    int (*saveintr)(), (*savequit)() ;
  989. X
  990. X    if ((sh = getenv("SHELL")) == NULL)
  991. X        sh = "/bin/sh" ;
  992. X    if (i == 1) {                             /* interactive shell */
  993. X        if ((pid = vfork()) == 0)
  994. X            execl(sh, sh, (char *) 0) ;
  995. X    }
  996. X    else if ((pid = vfork ()) == 0)            /* do one commandline */
  997. X        execl(sh, sh, "-c", ++cmd, (char *) 0) ;
  998. X    saveintr = signal(SIGINT, SIG_IGN) ;
  999. X    savequit = signal(SIGQUIT, SIG_IGN) ;
  1000. X    while ((w = wait(&status)) != pid && w != -1)
  1001. X        ;
  1002. X    if (i == 1)
  1003. X        printf("\n") ;
  1004. X    (void) signal(SIGINT, saveintr) ;
  1005. X    (void) signal(SIGQUIT, savequit) ;
  1006. X}
  1007. X
  1008. Xvoid
  1009. Xbuild_msg ()
  1010. X{
  1011. X    int     hdr_siz, too_much = FALSE ;
  1012. X    char    buf[BUF_SIZE] ;
  1013. X
  1014. X    msg.rqst_type = SEND ;
  1015. X    hdr_siz = build_header() ;
  1016. X    while (Argc--) {            /* copy everything from the commandline */
  1017. X        (void) strcat(buf, " ") ;
  1018. X        if (hdr_siz + strlen(buf) + 8 + strlen(*Argv) > BUF_SIZE ) {
  1019. X            too_much = TRUE ;
  1020. X            break ;
  1021. X        }
  1022. X        (void) strcat(buf, *Argv++) ;
  1023. X    }
  1024. X    if (hdr_siz + strlen(buf) > LINE_LENGTH)  /* separate heading from .. */
  1025. X        (void) strcat(msg.text, "\r\n") ;     /*  ..message if it's long  */
  1026. X    (void) strcat(msg.text, buf) ;
  1027. X    if (too_much) {
  1028. X        (void) strcat(msg.text, "...\r\n") ;
  1029. X        fprintf(stderr, 
  1030. X            "rsend: long message, %d word(s) truncated\n", Argc + 1) ;
  1031. X    }
  1032. X    else
  1033. X        (void) strcat(msg.text, ">\r\n") ;
  1034. X    msg.text[BUF_SIZE-1] = '\0' ;        /* just to make sure...*/
  1035. X}
  1036. X
  1037. Xint
  1038. Xbuild_header ()
  1039. X{
  1040. X    long    clock ;
  1041. X    struct  tm *tp, *localtime() ;
  1042. X
  1043. X    (void) time(&clock) ;  /* message header: "<11:47 From foo@bar (ttyxx):" */
  1044. X    tp = localtime(&clock) ;
  1045. X    (void) sprintf(msg.text,"\r\n\007<%d:%02d From %s@%s (%s):", 
  1046. X        tp->tm_hour, tp->tm_min, my_name, my_cpu, my_tty) ;
  1047. X    return(strlen(msg.text)) ;
  1048. X}
  1049. X
  1050. Xvoid
  1051. Xsend_it ()
  1052. X{
  1053. X    struct sockaddr from ;
  1054. X    int s, cc, fromlen = sizeof(from) ;
  1055. X
  1056. X    s = socket(AF_INET, SOCK_DGRAM, 0) ;    /* get a socket */
  1057. X    if (s < 0) {
  1058. X        perror("rsend: socket") ;
  1059. X        exit(1) ;
  1060. X    }
  1061. X    /* send to address in 'sin' through socket to (possibly remote) daemon */
  1062. X    cc = sendto(s, (char *)&msg, sizeof(msg),
  1063. X                0, (struct sockaddr *)&sin, sizeof (sin)) ;
  1064. X    if (cc != sizeof(msg)) {
  1065. X        perror("sendto") ;
  1066. X        exit(1) ;
  1067. X    }
  1068. X    rsp.code = NO_ANSW ;
  1069. X    (void) signal(SIGALRM, timeout) ;/* will not wait forever for a response */
  1070. X    (void) alarm(TIMEOUT) ;
  1071. X    (void) recvfrom(s, (char *)&rsp, sizeof(rsp), 0, &from, &fromlen) ;
  1072. X    (void) close(s) ;
  1073. X    (void) alarm(0) ;               /* don't time out on an interactive user */
  1074. X    if (*msg.rcv_name == '\0')
  1075. X        (void) strcpy(msg.rcv_name, rsp.rcv_name) ;
  1076. X    if (*msg.rcv_tty == '\0')
  1077. X        (void) strcpy(msg.rcv_tty, rsp.rcv_tty) ;
  1078. X    if (rsp.code != SUCCESS)
  1079. X        error_handle(rsp.code) ;
  1080. X}
  1081. X
  1082. Xvoid
  1083. Xtimeout ()
  1084. X{
  1085. X    fprintf(stderr, "rsend: timeout before acknowledged by rsend-daemon@%s\n",
  1086. X        rcv_cpu) ;
  1087. X    exit(0) ;
  1088. X}
  1089. X
  1090. Xvoid
  1091. Xerror_handle (errcod)
  1092. X    int errcod ;
  1093. X{
  1094. X    char errmsg[BUF_SIZE] ;
  1095. X    char recvr[NAME_SIZE + HOST_NAME_SIZE + 1] ;
  1096. X    char daemon_at[HOST_NAME_SIZE + 15] ;
  1097. X
  1098. X    if (remotesend) {
  1099. X        (void) sprintf(recvr, "%s@%s", msg.rcv_name, rcv_cpu) ;
  1100. X        (void) sprintf(daemon_at, "rsend-daemon@%s", rcv_cpu) ;
  1101. X        (void) strcat(rcv_cpu, ":") ;
  1102. X    } else {
  1103. X        (void) strcpy(recvr, msg.rcv_name) ;
  1104. X        (void) strcpy(daemon_at, "rsend-daemon") ;
  1105. X        *rcv_cpu = '\0' ;
  1106. X    }
  1107. X
  1108. X    switch (errcod) {
  1109. X    case NO_USER :
  1110. X        (void) sprintf(errmsg, "%s: no such user", recvr) ;
  1111. X        break ;
  1112. X    case NOT_IN :
  1113. X        (void) sprintf(errmsg, "%s not logged in", recvr) ;
  1114. X        break ;
  1115. X    case NOT_TTY :
  1116. X        (void) sprintf(errmsg, "%s/dev/%s no such device",
  1117. X            rcv_cpu, msg.rcv_tty) ;
  1118. X        break ;
  1119. X    case WRNG_TTY :
  1120. X        (void) sprintf(errmsg, "%s is not on %s", recvr, msg.rcv_tty) ;
  1121. X        break ;
  1122. X    case NOT_USED :
  1123. X        (void) sprintf(errmsg, "%s/dev/%s is not in use",
  1124. X            rcv_cpu, msg.rcv_tty) ;
  1125. X        break ;
  1126. X    case DENIED :
  1127. X        (void) sprintf(errmsg,
  1128. X            "%s/dev/%s: permission denied, try mail instead", 
  1129. X             rcv_cpu, msg.rcv_tty) ;
  1130. X        break ;
  1131. X    case OP_UTMP :
  1132. X        (void) sprintf(errmsg, "cannot open %s/etc/utmp", rcv_cpu) ;
  1133. X        break ;
  1134. X    case OP_TTY :
  1135. X        (void) sprintf(errmsg, "cannot open %s/dev/%s", rcv_cpu, msg.rcv_tty) ;
  1136. X        break ;
  1137. X    case WR_FAIL :
  1138. X        (void) sprintf(errmsg, "couldn't write on %s/dev/%s", 
  1139. X            rcv_cpu, msg.rcv_tty) ;
  1140. X        break ;
  1141. X    case CONFUSED :
  1142. X        (void) sprintf(errmsg, "%s is confused", daemon_at) ;
  1143. X        break ;
  1144. X    case NO_ANSW :
  1145. X        (void) sprintf(errmsg, "no answer from %s", daemon_at) ;
  1146. X        break ;
  1147. X    case CHDIR :
  1148. X        (void) sprintf(errmsg, "couldn't chdir to /dev") ;
  1149. X        break ;
  1150. X    default :
  1151. X        (void) sprintf(errmsg,
  1152. X            "this cannot happen! (unknown error, no:%d)", errcod) ;
  1153. X    }
  1154. X    fprintf(stderr, "rsend: %s\n", errmsg) ;
  1155. X    exit(1) ;
  1156. X}
  1157. + END-OF-FILE rsend.c
  1158. chmod 'u=r,g=r,o=r' 'rsend.c'
  1159. echo '    -r--r--r--  1 zap         15648 Dec 30 22:55 rsend.c        (as sent)'
  1160. echo -n '    '
  1161. /bin/ls -l rsend.c
  1162. exit 0
  1163.  
  1164. --
  1165. Svante Lindahl, NADA, KTH            Numerical Analysis & Computer Science 
  1166. Phone: +46-8-787-7146                Royal Institute of Technology         
  1167. UUCP: {seismo,mcvax}!enea!ttds!zap   ARPA: enea!ttds!zap@seismo.CSS.GOV    
  1168.  
  1169.