source: trunk/athena/bin/olc/server/olcd/notify.c @ 2348

Revision 2348, 11.6 KB checked in by tjcoppet, 35 years ago (diff)
3.0a.
Line 
1/*
2 * This file is part of the OLC On-Line Consulting System.
3 * It contains functions for handling the daemon's I/O.
4 *
5 *      Win Treese
6 *      Dan Morgan
7 *      Bill Saphir
8 *      MIT Project Athena
9 *
10 *      Ken Raeburn
11 *      MIT Information Systems
12 *
13 *      Tom Coppeto
14 *      MIT Project Athena
15 *
16 *      Copyright (c) 1988 by the Massachusetts Institute of Technology
17 *
18 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/olc/server/olcd/notify.c,v $
19 *      $Author: tjcoppet $
20 */
21
22#ifndef lint
23static char rcsid[]="$Header: /afs/dev.mit.edu/source/repository/athena/bin/olc/server/olcd/notify.c,v 1.5 1989-11-17 13:58:29 tjcoppet Exp $";
24#endif
25
26
27#include <olc/olc.h>
28#include <olcd.h>
29
30#ifdef ZEPHYR
31#include <zephyr/zephyr.h>      /* Zephyr defs. */
32#endif ZEPHYR
33
34#include <sys/types.h>
35#include <sys/socket.h>         /* IPC socket defs. */
36#include <sys/file.h>           /* File handling defs. */
37#include <sys/stat.h>           /* File status defs. */
38#include <sys/wait.h>           /* */
39#include <netdb.h>              /* Net database defs. */
40#include <pwd.h>                /* Directory defs. */
41#include <signal.h>             /* System signal definitions. */
42#include <sgtty.h>              /* Terminal param. definitions. */
43#include <setjmp.h>
44
45
46/* External Variables. */
47
48extern char DaemonHost[];       /* Name of daemon's machine. */
49
50int notice_timeout();
51static jmp_buf env;
52
53/*
54 * Function:    write_message() uses the program "write" to send a message
55 *                      from one person to another within the OLC system.
56 * Arguments:   touser:         Username of person receiving the message.
57 *              tomachine:      Name of machine he is using.
58 *              fromuser:       Username of person sending the message.
59 *              frommachine:    Name of machine she is using.
60 *              message:        Ptr. to buffer containing message.
61 * Returns:     SUCCESS or ERROR.
62 * Notes:
63 *      First try using zwrite_message() for Zephyr users; if that fails,
64 *      use the standard Unix write code.
65 *      This code is essentially the same as that in write.c for the
66 *      program 'write'.
67 *
68 */
69
70static int write_port = 0;
71
72ERRCODE
73write_message(touser, tomachine, fromuser, frommachine, message)
74        char *touser, *tomachine, *fromuser, *frommachine, *message;
75{
76        FILE *tf = NULL;        /* Temporary file. */
77        int fds;                /* Socket descriptor. */
78        char buf[BUFSIZE];      /* Message buffer. */
79        char error[ERRSIZE];    /* Error message. */
80        struct hostent *host;   /* Host entry for receiver. */
81        struct sockaddr_in sin; /* Socket address. */
82        int flag = 0;
83
84        if (touser == (char *)NULL) /* User sanity check. */
85                return(ERROR);
86
87#ifdef ZEPHYR
88        /* First try using Zephyr write.  If return status is anything
89         * but SUCCESS, try again using Unix write.
90         */
91        if (zwrite_message(touser, message) == SUCCESS)
92          return(SUCCESS);
93#endif ZEPHYR
94
95        if (write_port == 0) {
96                struct servent *service;
97                service = getservbyname("write", "tcp");
98                if (!service) {
99                        log_error("write_message: Can't find 'write' service");
100                        return(ERROR);
101                }
102                write_port = service->s_port;
103        }
104
105        host = gethostbyname(tomachine);
106        if (host == (struct hostent *)NULL) {
107                (void) sprintf(error,
108                               "Can't resolve name of host '%s'", tomachine);
109                log_error(error);
110                return(ERROR);
111        }
112        sin.sin_family = host->h_addrtype;
113        bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length);
114        sin.sin_port = write_port;
115        fds = socket(host->h_addrtype, SOCK_STREAM, 0);
116        if (fds < 0) {
117                perror("socket");
118                exit(1);
119        }
120
121
122        signal(SIGALRM, notice_timeout);
123        alarm(OLCD_TIMEOUT);
124        if(setjmp(env) != 0) {
125                sprintf(error, "Unable to contact writed on %s", tomachine);
126                log_error(error);
127                if(tf!=NULL)
128                  fclose(tf);
129                close(fds);
130                alarm(0);
131                return(ERROR);
132        }
133
134
135        if (connect(fds, &sin, sizeof (sin)) < 0) {
136          alarm(0);
137          (void) close(fds);
138          return(MACHINE_DOWN);
139        }
140        (void) write(fds, fromuser, strlen(fromuser));
141        (void) write(fds, "@", 1);
142        (void) write(fds, frommachine, strlen(frommachine));
143        (void) write(fds, " ", 1);
144        (void) write(fds, touser, strlen(touser));
145        (void) write(fds, "\r\n", 2);
146        tf = fdopen(fds, "r");
147        flag++;
148        while (1) {
149                if (fgets(buf, sizeof(buf), tf) == (char *)NULL) {
150                        (void) fclose(tf);
151                        (void) close(fds);
152                        alarm(0);
153                        return(LOGGED_OUT);
154                }
155                if (buf[0] == '\n')
156                        break;
157                (void) write(1, buf, strlen(buf));
158        }
159        (void) write(fds, message, strlen(message));
160        (void) write(fds, "\r\n", 2);
161        (void) fclose(tf);
162        (void) close(fds);
163        alarm(0);
164        return(SUCCESS);
165}
166
167 
168int
169notice_timeout(a)
170     int     a;
171{
172    longjmp(env, 1);
173}
174
175   
176/*
177 * Function:    write_message_to_user() sends a message from the
178 *                      daemon to a user using "write".
179 * Arguments:   user:           Ptr. to user structure.
180 *              message:        Ptr. to buffer containing the message.
181 *              flags:          Specifies special actions.
182 * Returns:     SUCCESS or ERROR.
183 * Notes:
184 *      First, try to write a message to the user.  If it does not
185 *      succeed, notify the consultant.
186 */
187
188
189ERRCODE
190write_message_to_user(k, message, flags)
191  KNUCKLE *k;
192  char *message;
193  int flags;
194{
195  int result;           /* Result of writing the message. */
196  char msgbuf[BUFSIZE]; /* Message buffer. */
197  int status;
198
199  if (k == (KNUCKLE *) NULL)
200    return(ERROR);
201
202  if(k->user->no_knuckles > 1)
203    {
204      sprintf(msgbuf,"To: %s %s@%s (%d)\n",k->title,k->user->username,
205              k->user->realm,k->instance);
206      strcat(msgbuf,message);
207      result = write_message(k->user->username, k->user->machine,
208                             "OLC-Service", DaemonHost, msgbuf);
209    }
210  else
211    result = write_message(k->user->username, k->user->machine,
212                             "OLC-Daemon", DaemonHost, message);
213 
214  switch(result)
215    {
216    case ERROR:
217      set_status(k->user, UNKNOWN_STATUS);
218      (void) sprintf(msgbuf,"Unable to contact %s %s.  Cause unknown.",
219              k->title, k->user->username);
220      if(!(flags & NO_RESPOND))
221        (void) write_message_to_user(k->connected, msgbuf, NO_RESPOND);
222      log_daemon(k, msgbuf);
223      status = ERROR;
224      break;
225
226    case MACHINE_DOWN:
227      set_status(k->user, UNKNOWN_STATUS);
228      (void) sprintf(msgbuf,"Unable to contact %s %s. Host machine down.",
229              k->title, k->user->username);
230      if(!(flags & NO_RESPOND))
231        (void) write_message_to_user(k->connected, msgbuf, NO_RESPOND);
232      log_daemon(k, msgbuf);
233      status = ERROR;
234      break;
235
236    case LOGGED_OUT:
237      set_status(k->user, LOGGED_OUT);
238      (void) sprintf(msgbuf,"Unable to contact %s %s. User logged out.",
239              k->title, k->user->username);
240      if(!(flags & NO_RESPOND))
241        (void) write_message_to_user(k->connected, msgbuf, NO_RESPOND);
242      log_daemon(k, msgbuf);
243      status = ERROR;
244      break;
245
246    default:
247      set_status(k->user,ACTIVE);
248      status = SUCCESS;
249      break;
250    }
251  return(status);
252}
253
254#define FUDGEFACTOR 20
255#define MESSAGE_CLASS "MESSAGE"
256#define PERSONAL_INSTANCE "PERSONAL"
257#define OLC_INSTANCE "OLC"
258#ifdef TEST
259#define OLC_CLASS    "OLCTEST"
260#else TEST
261#define OLC_CLASS    "OLC"
262#endif TEST
263
264ERRCODE olc_broadcast_message(instance,message, code)
265     char *instance, *message, *code;
266{
267#ifdef ZEPHYR 
268  if(zsend_message(OLC_CLASS,instance,code,"",message,0) == ERROR)
269    return(ERROR);
270#endif ZEPHYR
271
272  return(SUCCESS);
273}
274
275#ifdef ZEPHYR
276
277/*
278 * Function:    zwrite_message(username, message) writes a message to the
279 *              specified user.
280 * Arguments:   username:       Username of intended recipient.
281 *              message:        Message to send.
282 * Returns:     SUCCESS if message sent successfully, else ERROR.
283 *
284 * Inspired greatly by Robert French's zwrite.c (i.e. somewhat swiped).
285 *
286 */
287
288
289ERRCODE
290zwrite_message(username, message)
291     char *username;
292     char *message;
293{
294   char error[ERRSIZE];
295
296    /* Sanity check the username. */
297  if (username == NULL)
298    {
299      (void) sprintf(error, "zwrite_message: null username");
300      log_error(error);
301      return(ERROR);
302    }
303  if (strlen(username) == 0)
304    {
305      (void) sprintf(error, "zwrite_message: zero length username");
306      log_error(error);
307      return(ERROR);
308    }
309
310  if(zsend_message(MESSAGE_CLASS,PERSONAL_INSTANCE,"olc hello",username,message,0)
311     == ERROR)
312    return(ERROR);
313   
314   return(SUCCESS);
315}
316
317
318ERRCODE
319zsend_message(class,instance,opcode,username,message, flags)
320     char *class,*instance,*opcode,*username,*message;
321     int flags;
322{
323  ZNotice_t notice;             /* Zephyr notice */
324  int ret;                      /* return value, length */
325  char error[ERRSIZE];
326  char buf[BUFSIZ];
327  char *signature = "From: OLC Service \n";
328
329#ifdef lint
330  flags = flags;
331  opcode = opcode;
332#endif lint;
333
334  if ((ret = ZInitialize()) != ZERR_NONE)
335    {
336      (void) fprintf(stderr, "zwrite_message: couldn't ZInitialize\n");
337      return(ERROR);            /* Oops, couldn't initialize. */
338    }
339 
340  bzero(&notice, sizeof(ZNotice_t));
341
342  if(username!= (char *) NULL)
343    {
344      if(!string_eq(username,""))
345        notice.z_kind = ACKED;
346      else
347        notice.z_kind = UNSAFE;
348    }
349  else
350    notice.z_kind = UNSAFE;
351
352  notice.z_port = 0;
353  notice.z_class = class;
354  notice.z_class_inst = instance;
355  notice.z_sender = 0;
356  notice.z_message_len = 0;
357  notice.z_recipient = username;
358  notice.z_default_format = "Message $message";
359  notice.z_opcode = opcode;
360
361  (void) strcpy(buf,signature);
362  (void) strcat(buf,message);
363
364
365  /* Watch the moving pointer.... */
366  notice.z_message = buf;     
367  notice.z_message_len = strlen(buf) + 1;
368  ret = zsend(&notice); /* send real message */
369
370  return(ret); 
371}
372 
373/*
374 * Function:    zsend(&notice, isreal): Send a Zephyr notice.
375 * Arguments:   notice: Zephyr notice to send.
376 * Returns:     SUCCESS on success, else ERROR
377 */
378
379ERRCODE
380zsend(notice)
381     ZNotice_t *notice;
382{
383  int ret;
384  ZNotice_t retnotice;
385
386  if ((ret = ZSendNotice(notice, ZAUTH)) != ZERR_NONE)
387    {
388      /* Some sort of unknown communications error. */
389      fprintf(stderr, "zsend: error %d from ZSendNotice\n", ret);
390      return(ERROR);
391    }
392
393  if(notice->z_kind != ACKED)
394    return(SUCCESS);
395
396  if ((ret = ZIfNotice(&retnotice, (struct sockaddr_in *) 0,
397                       ZCompareUIDPred, (char *) &notice->z_uid)) !=
398      ZERR_NONE)
399    {
400      /* Server acknowledgement error here. */
401      fprintf(stderr, "zsend: error %d from ZIfNotice\n", ret);
402      ZFreeNotice(&retnotice);
403      return(ERROR);
404    }
405
406  if (retnotice.z_kind == SERVNAK)
407    {
408      fprintf(stderr, "zsend: authentication failure\n");
409      ZFreeNotice(&retnotice);
410      return(ERROR);
411    }
412
413  if (retnotice.z_kind != SERVACK || !retnotice.z_message_len)
414    {
415      fprintf(stderr, "zsend: server failure during SERVACK\n");
416      ZFreeNotice(&retnotice);
417      return(ERROR);
418    }
419
420  if (! strcmp(retnotice.z_message, ZSRVACK_SENT))
421    {
422      ZFreeNotice(&retnotice);
423      return(SUCCESS);          /* Message made it */
424    }
425  else
426    {
427#ifdef TEST
428      printf("zsend: unknown error sending Zephyr message\n");
429#endif
430      ZFreeNotice(&retnotice);
431      return(ERROR);    /* Some error, probably not using Zephyr */
432    }
433}
434
435
436
437#endif ZEPHYR
438
439/*
440 * Function:    perror() similar to that of the C library, except that
441 *      a datestamp precedes the message printed.
442 * Arguments:   msg:    Message to print.
443 * Returns:     nothing
444 *
445 */
446
447#include <sys/uio.h>
448extern int sys_nerr;
449extern char *sys_errlist[];
450extern int errno;
451static char time_buf[20];
452
453perror(msg)
454        char *msg;
455{
456        register int error_number;
457        struct iovec iov[6];
458        register struct iovec *v = iov;
459
460        error_number = errno;
461
462        time_now(time_buf);
463        v->iov_base = time_buf;
464        v->iov_len = strlen(time_buf);
465        v++;
466
467        v->iov_base = " ";
468        v->iov_len = 1;
469        v++;
470
471        if (msg) {
472                if (*msg) {
473                        v->iov_base = msg;
474                        v->iov_len = strlen(msg);
475                        v++;
476                        v->iov_base = ": ";
477                        v->iov_len = 2;
478                        v++;
479                }
480        }
481
482        if (error_number < sys_nerr)
483                v->iov_base = sys_errlist[error_number];
484        else
485                v->iov_base = "Unknown error";
486        v->iov_len = strlen(v->iov_base);
487        v++;
488
489        v->iov_base = "\n";
490        v->iov_len = 1;
491        (void) writev(2, iov, (v - iov) + 1);
492}
Note: See TracBrowser for help on using the repository browser.