home *** CD-ROM | disk | FTP | other *** search
- /* main.c -- argument parser and control loops
- Copyright (C) 1989 David MacKenzie
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* hint - send a one-line message to other users
-
- Usage: hint [-fp] [-d sec] user|tty[,user|tty...] [message]
- hint -y [-bs] [-T terminal]
- hint -n
- hint -V
- hint
-
- Options:
- -f make hint last forever, until overwritten
- -p put sender's name at beginning of hint instead of end
- -d duration in seconds (5 <= sec <= 60) before hint is erased (default 10)
-
- -y enable receipt of hints
- -b don't use a visual bell (can still use audible bell)
- -s don't use an audible bell (can still use visual bell)
- -T specify terminal type, overriding $TERM
-
- -n disable receipt of hints
-
- -V display program version number
-
- With no arguments, displays the current hint status.
-
- David MacKenzie <edf@rocky2.rockefeller.edu>
- Latest revision: 08/24/89 */
-
- #define ALLOCATE /* Allocate global variables in hint.h. */
-
- #include "hint.h"
-
- /* Hint status to set if 'y' or 'n'. */
- static int new_stats;
-
- /* The hint message can be no longer than this. */
- static int length_limit;
-
- /* Head of linked list of ttys to hint. */
- static struct ttylist *tty_list;
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- extern int optind;
- struct ttylist *tp; /* A ttylist entry. */
- char temp_message[MAX_MESSAGE]; /* Hint read from tty. */
- int i; /* To reset `optind' between uses. */
-
- program_name = argv[0] = basename (argv[0]);
- new_stats = 0;
- length_limit = MAX_MESSAGE - 1;
-
- if (argc == 1)
- {
- show_status ();
- exit (0);
- }
-
- if (chdir ("/dev") == -1)
- pfatal ("Cannot change directory to /dev");
-
- term = getenv ("TERM");
- /* Some implementations of getopt seem to start out with `optind' == 0,
- while others start out with `optind' == 1. Whatever it starts out as,
- we save it and then restore it. */
- i = optind;
- parse_environment ();
- optind = i;
- parse_options (argc, argv, 1);
-
- if (new_stats)
- {
- if (argc < optind)
- usage ();
- set_status (new_stats);
- exit (0);
- }
-
- /* Check for user|tty[,user|tty...]. */
- if (optind < argc)
- add_recipients (argv[optind++]);
- if (tty_list == NULL)
- {
- fprintf (stderr, "%s: No ttys to hint\n", program_name);
- exit (1);
- }
- endhtent ();
-
- length_limit -= 11; /* 8 for username + 3 for punctuation. */
- if (length_limit < 11)
- length_limit = 11; /* Let's be reasonable. */
-
- /* Check for message. */
- if (optind < argc)
- for (; optind < argc; ++optind)
- {
- append_word (argv[optind]);
- if (optind < argc - 1)
- append_word (" ");
- }
- else
- {
- prompt ();
- fgets (temp_message, MAX_MESSAGE, stdin);
- append_word (temp_message);
- }
-
- set_signals ();
- /* Send the hint to all relevant ttys. */
- while (tp = next_tty ())
- sendhint (tp);
-
- if (forever)
- exit (0);
- switch (fork ())
- {
- case -1:
- pfatal ("Cannot fork");
- case 0: /* Child. */
- sleep (duration);
- while (tp = next_tty ())
- erasehint (tp);
- }
- exit (0);
- /* NOTREACHED */
- }
-
- void
- parse_environment ()
- {
- char *enval;
- struct args *argsp;
- char *s; /* program_name + enval. */
-
- enval = getenv (ENVAR);
- if (enval && *enval)
- {
- s = xmalloc ((unsigned) (strlen (enval) + strlen (program_name) + 2));
- strcpy (s, program_name);
- strcat (s, " ");
- strcat (s, enval);
- argsp = stov (s);
- parse_options (argsp->argc, argsp->argv, 0);
- free (s);
- }
- }
-
- /* If `cmdline' is nonzero, this function was called with command line
- arguments; otherwise they were taken from the environment. */
-
- void
- parse_options (argc, argv, cmdline)
- int argc;
- char **argv;
- int cmdline;
- {
- extern int optind;
- extern char *optarg;
- int c;
-
- while ((c = getopt (argc, argv, "ynbfpsd:T:V")) != EOF)
- {
- switch (c)
- {
- case 'y':
- case 'n':
- if (cmdline)
- new_stats = c;
- else
- ignored (c);
- break;
- case 'b':
- use_vbell = 0;
- break;
- case 'f':
- forever = 1;
- break;
- case 'p':
- name_at_end = 0;
- break;
- case 's':
- use_bell = 0;
- break;
- case 'd':
- duration = atoi (optarg);
- if (duration < MIN_SEC || duration > MAX_SEC)
- {
- fprintf (stderr,
- "%s: %d: Duration out of range (%d-%d seconds)\n",
- program_name, duration, MIN_SEC, MAX_SEC);
- exit (1);
- }
- break;
- case 'T':
- term = optarg;
- break;
- case 'V':
- if (cmdline)
- {
- fprintf (stderr, "hint, version 3.5\n");
- exit (0);
- }
- else
- ignored (c);
- break;
- default:
- if (cmdline)
- usage ();
- else
- fprintf (stderr, "%s: Invalid option in environment ignored\n",
- program_name);
- break;
- }
- }
- }
-
- /* Display a prompt that attempts to be as long as `length_limit'. */
-
- void
- prompt ()
- {
- static char *prompt_string = "[ Enter message (max. %d characters):";
- int prompt_length;
-
- printf (prompt_string, length_limit);
- /* Set prompt_length to length of the prompt except for trailing spaces. */
- prompt_length = strlen (prompt_string) + 1; /* The 1 is the ']'. */
- if (length_limit > 99)
- ++prompt_length; /* Adjust for the extra digit. */
- if (prompt_length > length_limit)
- prompt_length = length_limit;
- printf ("%*s]\n", length_limit - prompt_length, " ");
- fflush (stdout);
- }
-
- /* Print the program name, `s', and a system error message, and die. */
-
- void
- pfatal (s)
- char *s;
- {
- fprintf (stderr, "%s: ", program_name);
- perror (s);
- exit (1);
- }
-
- /* Same but stay alive. */
-
- void
- pnonfatal (s)
- char *s;
- {
- fprintf (stderr, "%s: ", program_name);
- perror (s);
- }
-
- void
- show_status ()
- {
- char *tty;
-
- tty = ttyname (2); /* Stderr is least likely to be redirected. */
- if (tty == NULL)
- pfatal ("Cannot get ttyname");
- printf ("is %c\n", hintable (tty) ? 'y' : 'n');
- }
-
- /* Set hint status.
- `newstat' can be 'y' or 'n'. */
-
- void
- set_status (newstat)
- char newstat;
- {
- struct stat tty_stats;
- char *tty;
-
- tty = ttyname (2);
- if (tty == NULL)
- pfatal ("Cannot get ttyname");
- if (stat (tty, &tty_stats) < 0)
- pfatal (tty);
-
- if (newstat == 'y')
- {
- tty_stats.st_mode |= HINTBIT;
- updatetab (tty);
- }
- else
- tty_stats.st_mode &= ~HINTBIT;
- if (chmod (tty, tty_stats.st_mode) < 0)
- pfatal (tty);
- }
-
- /* Return true if `tty' is hint y, false otherwise. */
-
- int
- hintable (tty)
- char *tty;
- {
- struct stat tty_stats;
-
- if (stat (tty, &tty_stats) < 0)
- {
- pnonfatal (tty);
- return 0; /* Cannot stat; assume they're hint n. */
- }
- return tty_stats.st_mode & HINTBIT;
- }
-
- /* Return true if `name' is a tty device in /dev. */
-
- int
- istty (name)
- char *name;
- {
- struct stat stats;
- char *path;
- int i;
-
- path = xmalloc (strlen (name) + 3);
- strcpy (path, "./");
- strcat (path, name);
- i = stat (path, &stats);
- free (path);
- if (i == -1 || (stats.st_mode & S_IFMT) != S_IFCHR)
- return 0;
- else
- return 1;
- }
-
- void
- add_recipients (names)
- char *names;
- {
- char *name;
-
- for (name = strtok (names, ","); name; name = strtok ((char *) NULL, ","))
- if (istty (name))
- {
- addtty ("user", name);
- }
- else
- {
- /* Add any ttys where user `name' is logged on to `tty_list'. */
- if (adduser (name) == 0)
- fprintf (stderr, "%s: %s is not logged on\n", program_name, name);
- }
- }
-
- /* Add `user' at `tty' (which should have no leading path) to the list of
- ttys to send the hint to. */
-
- void
- addtty (user, tty)
- char *user;
- char *tty;
- {
- struct ttylist *tp;
- struct hinttab *ht;
- char *ttypath;
-
- /* Make sure they haven't already been added. */
- for (tp = tty_list; tp; tp = tp->tt_next)
- if (!strcmp (tp->tt_tty, tty))
- return;
-
- if (!hintable (tty))
- {
- /* They're hint n. */
- fprintf (stderr, "%s: %s on %s is refusing hints\n",
- program_name, user, tty);
- return;
- }
-
- sethtent (); /* Rewind hinttab file. */
-
- ttypath = xmalloc ((unsigned) (strlen (tty) + 6));
- strcpy (ttypath, "/dev/");
- strcat (ttypath, tty);
- ht = gethttty (ttypath);
- free (ttypath);
-
- if (ht == NULL)
- {
- fprintf (stderr, "%s: No hinttab entry for %s\n", program_name, tty);
- return;
- }
-
- tp = (struct ttylist *) xmalloc (sizeof (struct ttylist));
- tp->tt_user = strdup (user);
- tp->tt_tty = strdup (tty);
- tp->tt_ht = *ht;
-
- tp->tt_next = tty_list;
- tty_list = tp;
-
- /* Keep track of the shortest status line we'll be hinting. */
- if (length_limit > tp->tt_ht.h_ws)
- length_limit = tp->tt_ht.h_ws;
- }
-
- /* Return the next tty in the list.
- Return NULL if the list is empty. */
-
- struct ttylist *
- next_tty ()
- {
- static struct ttylist *tp = NULL;
-
- tp = tp ? tp->tt_next : tty_list;
-
- return tp;
- }
-
- void
- set_signals ()
- {
- #ifdef SIGTTOU
- signal (SIGTTOU, SIG_IGN);
- #endif
- /* If the sender logs out right after hinting, stick around to erase the
- hint. */
- signal (SIGHUP, SIG_IGN);
- signal (SIGINT, SIG_IGN);
- }
-
- /* Concatenate `word' onto the end of the hint message, silently truncating
- if it would overflow `length_limit', and removing any control
- characters. */
-
- void
- append_word (word)
- char *word;
- {
- static int message_length = 0;/* Length of message. */
-
- for (; *word && message_length < length_limit; ++word)
- if (isascii (*word) && isprint (*word))
- message[message_length++] = *word;
- message[message_length] = 0;
- }
-
- /* Return a malloc'd duplicate of string `s'. */
-
- char *
- strdup (s)
- char *s;
- {
- return strcpy (xmalloc ((unsigned) (strlen (s) + 1)), s);
- }
-
- /* Return `name' with any leading path stripped off. */
-
- char *
- basename (name)
- char *name;
- {
- char *base;
-
- base = strrchr (name, '/');
- return base ? base + 1 : name;
- }
-
- void
- ignored (c)
- char c;
- {
- fprintf (stderr, "%s: Option ignored in environment: -%c\n", program_name, c);
- }
-
- void
- usage ()
- {
- fprintf (stderr,
- "Usage: %s [-fp] [-d sec] user|tty[,user|tty...] [message]\n",
- program_name);
- fprintf (stderr, " %s -y [-bs] [-T termtype]\n", program_name);
- fprintf (stderr, " %s -n\n", program_name);
- fprintf (stderr, " %s -V\n", program_name);
- fprintf (stderr, " %s\n", program_name);
- exit (1);
- }
-