/* This file is part of the Project Athena Zephyr Notification System.
 * It contains code for the "zping" command.
 *
 *	Created by:	Robert French
 *      Modified by:    Derek Atkins
 *
 *	$Source: /afs/media-lab.mit.edu/user/warlord/C/zping/RCS/zping.c,v $
 *	$Author: warlord $
 *
 *	Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
 *	For copying and distribution information, see the file
 *	"mit-copyright.h". 
 */

#include <zephyr/mit-copyright.h>

#include <zephyr/zephyr.h>
#include <string.h>
#include <netdb.h>
#include <pwd.h>
#include <ctype.h>

#define DEFAULT_CLASS "MESSAGE"
#define DEFAULT_INSTANCE "PERSONAL"
#define URGENT_INSTANCE "URGENT"

#define MAXRECIPS 100

int nrecips = 0, msgarg, onesent = 0, machincl, exactmach;
char *whoami, *inst, *class, *recips[MAXRECIPS];
int (*auth)();
int f_flag = 1;				/* finger flag default */
int v_flag = 0;				/* verbose default */

extern char *malloc(), *realloc();

main(argc, argv)
    int argc;
    char *argv[];
{
    ZNotice_t notice;
    int retval, arg;
    char *signature = NULL;
    char sigbfr[BUFSIZ];
    char *sendervar = NULL;
	
    whoami = argv[0];

    if ((retval = ZInitialize()) != ZERR_NONE) {
	com_err(whoami, retval, "while initializing");
	exit(1);
    } 

    if (argc < 2 && !onesent)
	usage(whoami);

    bzero((char *) &notice, sizeof(notice));

    auth = ZAUTH;
    msgarg = 0;

    class = DEFAULT_CLASS;
    inst = DEFAULT_INSTANCE;
    signature = ZGetVariable("zwrite-signature");
    if (signature) {
	(void) strcpy(sigbfr, signature);
	signature = sigbfr;
    } 
	
    arg = 1;
	
    for (;arg<argc&&!msgarg;arg++) {
	nrecips = 0;
	if (*argv[arg] == '-') {

	    if (strlen(argv[arg]) > 2) 
		usage(whoami);
	    
	    switch (argv[arg][1]) {
		
	    case 'f':
		f_flag = 0;
		break;
	    case 'v':
		v_flag = 1;
		break;
	    case 's':
		v_flag = 0;
		break;
	    case 'l':
		if (arg == argc)
		    usage(whoami);
		arg++;
		readfile(argv[arg]);
		break;
	    default:
		usage(whoami);
	    }
	    
	    /*	case 'h':
	     *	    if (arg == argc-1)
	     *	        usage(whoami);
	     *	    arg++;
	     *	    sendervar = argv[arg];
	     *	    break;
	     *       case 'w':
	     *	    if (arg == argc-1)
	     *	        usage(whoami);
	     *	    arg++;
	     *	    if ((status = ZSetVariable("fakehost", argv[arg])) != ZERR_NONE)
	     *	        usage(whoami);
	     *	    break; 
	     */
	} else {
	    if (*argv[arg] != '@') {
		recips[nrecips++] = argv[arg];
		onesent = 1;
		
		if (!signature) {
		    /* try to find name in the password file */
		    register struct passwd *pwd;
		    register char *cp = sigbfr;
		    register char *cp2, *pp;
		    
		    pwd = getpwuid(getuid());
		    if (pwd) {
			cp2 = pwd->pw_gecos;
			for (; *cp2 && *cp2 != ',' ; cp2++) {
			    if (*cp2 == '&') {
				pp = pwd->pw_name;
				*cp++ = islower(*pp) ? toupper(*pp) : *pp;
				pp++;
				while (*pp)
				    *cp++ = *pp++;
			    } else
				*cp++ = *cp2;
			}
			signature = sigbfr;
		    }
		}	
		
		notice.z_kind = ACKED;
		notice.z_port = 0;
		notice.z_class = class;		/* can set these to filsrv */
		notice.z_class_inst = inst;	/* and their file server */
		notice.z_opcode = "PING";
		if (!sendervar) {
		    notice.z_sender = 0;
		}
		else {
		    notice.z_sender = sendervar; 
		}
		notice.z_message_len = 5;
		notice.z_message = "PONG\n";
		notice.z_recipient = "";
		if (signature)
		    notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient)\n@bold($1) <$sender>\n\n$2";
		else
		    notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient)\n$message";
		
		send_off(&notice, 0);
	    
	    } else {
		allstation(argv[arg]);
	    }
	}
    }
    if (!nrecips && !(strcmp(class, DEFAULT_CLASS) ||
		      (strcmp(inst, DEFAULT_INSTANCE) &&
		       strcmp(inst, URGENT_INSTANCE)))) {
	/* must specify recipient if using default class and
	   (default instance or urgent instance) */
	if (!onesent) {
	    fprintf(stderr, "No people specified to ping.\n");
	    usage(whoami);
	} else
	    exit(1);
    }
}

send_off(notice, real)
    ZNotice_t *notice;
    int real;
{
    int i, success, retval, numlocs, var;
    char bfr[BUFSIZ], user[BUFSIZ], user_buf[BUFSIZ];
    ZNotice_t retnotice;

    success = 0;
	
    for (i=0;i<nrecips || !nrecips;i++) {
	machincl = -1;
	if (!index(recips[i],'@')) {
	    notice->z_recipient = nrecips?recips[i]:"";
	} else {
	    (void) strcpy(user, recips[i]);
	    for (var = 0; user[var] != '@'; var++) {
		user_buf[var] = user[var];
	    }
	    user_buf[var] = '\0';
	    notice->z_recipient = user_buf;
	    machincl = i;
	}
	if ((retval = ZSendNotice(notice, auth)) != ZERR_NONE) {
	    (void) sprintf(bfr, "while sending notice to %s", 
		    nrecips?notice->z_recipient:inst);
	    com_err(whoami, retval, bfr);
	    break;
	}
	if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *) 0,
				ZCompareUIDPred, 
				(char *)&notice->z_uid)) !=
	    ZERR_NONE) {
	    ZFreeNotice(&retnotice);
	    (void) sprintf(bfr, "while waiting for acknowledgement for %s", 
		    nrecips?notice->z_recipient:inst);
	    com_err(whoami, retval, bfr);

	}
	if (retnotice.z_kind == SERVNAK) {
	    printf("Received authorization failure while pinging %s\n", 
		   nrecips?notice->z_recipient:inst);
	    ZFreeNotice(&retnotice);
	    break;			/* if auth fails, punt */
	} 
	if (retnotice.z_kind != SERVACK || !retnotice.z_message_len) {
	    printf("Detected server failure while receiving acknowledgement for %s\n", 
		   nrecips?notice->z_recipient:inst);
	    ZFreeNotice(&retnotice);
	    continue;
	  }
	(void) strcpy(user,notice->z_recipient);
	if (!index(user,'@')) {
	  (void) strcat(user,"@");
	  (void) strcat(user,ZGetRealm());
	}
	if ((retval = ZLocateUser(user,&numlocs)) != ZERR_NONE) {
	  com_err(whoami,retval,"while locating user %s",user);
	  return(1);
	}
	if (!strcmp(retnotice.z_message, ZSRVACK_SENT)) {
	  if (numlocs == 0) {
	    printf("%s: Subscribed to messages ", notice->z_recipient);
	    if (machincl == -1) {
		printf("but not locatable.\n");
	    } else {
		printf("and not locatable, but trying:\n");
		print_locs(notice->z_recipient, numlocs);
	    }
	} else {
	    printf("%s: Subscribed to messages and locatable on the following machine%s:\n",
		   notice->z_recipient, (numlocs > 1) ?  "s" : "");
	    print_locs(notice->z_recipient, numlocs);
	}
      } else if (!strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) {
	  if (numlocs != 0) {
	    printf("%s: Not subscribed to messages, but online on:\n",
		   notice->z_recipient);
	    print_locs(notice->z_recipient, numlocs);
	  } else {
	      if (machincl == -1) {
		  printf("%s: Not locatable and not subscribing to messages\n",
			 notice->z_recipient);
	      } else {
		  printf("%s: Not locatable and not subscribing, but trying:\n",
			 notice->z_recipient);
		  print_locs(notice->z_recipient, numlocs);
	      }
	  }
      } else {
	  printf("%s: Not logged in or not subscribing to messages (error).\n",
		 notice->z_recipient);
      }
    }
      
    ZFreeNotice(&retnotice);
    if (!real && !success)
      return(1);
    return(0);
}

print_locs(user,nlocs)
     char *user;
     int nlocs;
{
  int one=1, retval;
  char fulluser[BUFSIZ];
  ZLocations_t locations;
  int finger();

  exactmach = 0;

  if (nlocs != 0) {
      for (;nlocs;nlocs--) {
	  if ((retval = ZGetLocations(&locations,&one)) != ZERR_NONE) {
	      com_err(whoami,retval,"while getting location");
	      return(1);
	  }
	  
	  if (v_flag) 
	      printf("  %-*s %-*s %s",30,locations.host,7,locations.tty,
		     locations.time);
	  else
	      printf("  %-*s ",25,locations.host);
	  
	  (void) strcpy(fulluser,user);
	  if (!index(fulluser,'@')) {
	      (void) strcat(fulluser,"@");
	      (void) strcat(fulluser,locations.host);
	  }
	  if (f_flag) {
	      if (!finger(fulluser))
		  printf("Error fingering\n");
	  }
	  if (!v_flag)
	      printf(" %-*s %s\n",7,locations.tty, locations.time);
      }
  }

  if (machincl != -1) {
      exactmach = 1;
      if (!finger(recips[machincl]))
	  printf("Error fingering\n");
  }
      
  return(1);
}

usage(s)
    char *s;
{
    printf("Usage: %s [-f] [-v] [-l filename] [-s] username ... \n\n", s);
    printf("\tAt least one recipient must be specified\n");
    printf("\tor you must specify a file with at least one username in it.\n");
    exit(1);
} 

