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

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