home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-05-06 | 53.5 KB | 1,783 lines |
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # If this archive is complete, you will see the following message at the end:
- # "End of archive 16 (of 19)."
- # Contents: mush/dates.c mush/file.c mush/sample.mushrc mush/tool.c
- # Wrapped by argv@turnpike on Wed May 2 13:59:48 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'mush/dates.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/dates.c'\"
- else
- echo shar: Extracting \"'mush/dates.c'\" \(14562 characters\)
- sed "s/^X//" >'mush/dates.c' <<'END_OF_FILE'
- X/* @(#)dates.c 3.0 (c) copyright 3/01/90 (Dan Heller, Bart Schaefer) */
- X
- X#include "mush.h"
- X
- X/*
- X * %ld%3c%s gmt_in_secs weekday orig_timezone
- X * The standard "date format" stored in the msg data structure.
- X */
- Xchar *day_names[] = {
- X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- X};
- Xchar *month_names[] = { /* imported in pick.c */
- X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- X};
- X
- Xstatic int mtbl[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
- X
- X/* Time Zone Stuff */
- Xstruct zoneoff {
- X char *zname;
- X int hr_off;
- X int mn_off;
- X} time_zones[] = {
- X /* Universal Time */
- X { "UT", 0, 0 }, { "GMT", 0, 0 },
- X /* European Time */
- X { "BST", 1, 0 }, /* Brit. Summer */
- X { "EET", 0, 0 }, { "EEST", 1, 0 }, /* Eastern */
- X { "MET", -1, 0 }, { "MEST", 0, 0 }, /* Middle */
- X { "WET", -2, 0 }, { "WEST", -1, 0 }, /* Western */
- X /* North American Time */
- X { "NST", -3,-30 }, /* Newfoundland */
- X { "AST", -4, 0 }, { "ADT", -3, 0 }, /* Atlantic */
- X { "EST", -5, 0 }, { "EDT", -4, 0 }, /* Eastern */
- X { "CST", -6, 0 }, { "CDT", -5, 0 }, /* Central */
- X { "MST", -7, 0 }, { "MDT", -6, 0 }, /* Mountain */
- X { "PST", -8, 0 }, { "PDT", -7, 0 }, /* Pacific */
- X { "YST", -9, 0 }, { "YDT", -8, 0 }, /* Yukon */
- X { "HST", -10, 0 }, { "HDT", -9, 0 }, /* Hawaii */
- X /* Japan and Australia Time */
- X {"JST", 9, 0 }, /* Japan */
- X {"AEST", 10, 0 }, {"AESST", 11, 0 }, /* Eastern */
- X {"ACST", 9, 30 }, {"ACSST", 10, 30 }, /* Central */
- X {"AWST", 8, 0 }, /* Western */
- X /* Military Time */
- X { "A", 1, 0 }, { "N", -1, 0 },
- X { "B", 2, 0 }, { "O", -2, 0 },
- X { "C", 3, 0 }, { "P", -3, 0 },
- X { "D", 4, 0 }, { "Q", -4, 0 },
- X { "E", 5, 0 }, { "R", -5, 0 },
- X { "F", 6, 0 }, { "S", -6, 0 },
- X { "G", 7, 0 }, { "T", -7, 0 },
- X { "H", 8, 0 }, { "U", -8, 0 },
- X { "I", 9, 0 }, { "V", -9, 0 },
- X { "K", 10, 0 }, { "W", -10, 0 },
- X { "L", 11, 0 }, { "X", -11, 0 },
- X { "M", 12, 0 }, { "Y", -12, 0 },
- X { "Z", 0, 0 },
- X /* Also legal is +/- followed by hhmm offset from UT */
- X { 0, 0, 0 }
- X};
- X
- Xlong
- Xgetzoff(zone)
- Xchar *zone;
- X{
- X struct zoneoff *z;
- X int hours, mins;
- X char sign[2];
- X
- X if (!zone || !*zone)
- X return 0;
- X if (sscanf(zone, "%1[-+]%2d%2d", sign, &hours, &mins) == 3)
- X return (hours * 3600 + mins * 60) * (*sign == '-' ? -1 : 1);
- X for (z = time_zones; z->zname; z++)
- X if (lcase_strncmp(zone, z->zname, -1) == 0)
- X return z->hr_off * 3600 + z->mn_off * 60;
- X return 0;
- X}
- X
- X/*
- X * Kind of the reverse of localtime() and gmtime() -- converts a struct tm
- X * to time in seconds since 1970. Valid until 2038.
- X * If the "zone" argument is present, it modifies the return value.
- X * The zone should be a string, either +/-hhmm or symbolic (above).
- X * The "how" argument should be -1 to convert FROM gmt, 1 to convert TO gmt,
- X * and (as a "side-effect") 0 if the Zone parameter is to be ignored.
- X *
- X * Thanks to ktl@wag240.caltech.edu (Kian-Tat Lim) for similar algorithm
- X * written in perl from which this was derived.
- X */
- Xlong
- Xtime2gmt(tym, zone, how)
- Xstruct tm *tym;
- Xchar *zone;
- Xint how;
- X{
- X long year, julian;
- X
- X if (tym->tm_year < 100)
- X year = tym->tm_year + 1900;
- X if (year < 69)
- X year += 100;
- X
- X julian = 365 * (year - 1970) + (int)((year - 1970 + 1) / 4) +
- X mtbl[tym->tm_mon] + tym->tm_mday - 1;
- X /* tym->tm_yday might not be valid */
- X if (tym->tm_mon > 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0))
- X julian++;
- X julian *= 86400; /* convert to seconds */
- X julian += (tym->tm_hour * 60 + tym->tm_min) * 60 + tym->tm_sec;
- X return julian - getzoff(zone) * how;
- X}
- X
- Xstruct tm *
- Xtime_n_zone(zone)
- Xchar *zone;
- X{
- X struct tm *T;
- X char *tz;
- X#if defined(SYSV) || defined(TIMEZONE)
- X long x;
- X
- X (void) time(&x);
- X T = localtime(&x);
- X#ifndef TIMEZONE
- X {
- X extern char *tzname[];
- X tz = tzname[T->tm_isdst];
- X }
- X#endif /* TIMEZONE */
- X#else /* SYSV || TIMEZONE */
- X extern char *timezone();
- X struct timeval mytime;
- X struct timezone myzone;
- X
- X (void) gettimeofday(&mytime, &myzone);
- X T = localtime(&mytime.tv_sec);
- X tz = timezone(myzone.tz_minuteswest, (T->tm_isdst && myzone.tz_dsttime));
- X#endif /* !SYSV */
- X
- X#ifdef TIMEZONE
- X#ifdef DAYLITETZ
- X if (T->tm_isdst)
- X tz = DAYLITETZ;
- X else
- X#endif /* DAYLITETZ */
- X tz = TIMEZONE;
- X#endif /* TIMEZONE */
- X
- X (void) strncpy(zone, tz, 7), zone[7] = 0;
- X return T;
- X}
- X
- X/* Time() returns a string according to criteria:
- X * if "now" is 0, then the current time is gotten and used.
- X * else, use the time described by now
- X * opts points to a string of args which is parsed until an unknown
- X * arg is found and opts will point to that upon return.
- X * valid args are T (time of day), D (day of week), M (month), Y (year),
- X * N (number of day in month -- couldn't think of a better letter).
- X */
- Xchar *
- XTime(opts, now)
- Xregister char *opts;
- Xlong now;
- X{
- X static char time_buf[30];
- X struct tm *T;
- X register char *p = time_buf;
- X long x;
- X
- X if (!opts)
- X return NULL;
- X if (now)
- X x = now;
- X else
- X (void) time(&x);
- X T = localtime(&x);
- X for (;; opts++) {
- X switch(*opts) {
- X case 'T':
- X if (ison(glob_flags, MIL_TIME))
- X (void) sprintf(p, "%2d:%02d", T->tm_hour, T->tm_min);
- X else
- X (void) sprintf(p, "%d:%02d", (T->tm_hour) ?
- X ((T->tm_hour <= 12) ? T->tm_hour : T->tm_hour - 12) :
- X 12, T->tm_min);
- X when 'D': case 'W': (void) strcpy(p, day_names[T->tm_wday]);
- X when 'M': (void) strcpy(p, month_names[T->tm_mon]);
- X when 'y': (void) sprintf(p, "%d", T->tm_year);
- X when 'Y': (void) sprintf(p, "%d", T->tm_year + 1900);
- X when 'N': (void) sprintf(p, "%d", T->tm_mday);
- X otherwise: *--p = 0; return time_buf;
- X }
- X p += strlen(p);
- X *p++ = ' ';
- X }
- X}
- X
- X/* parse date and return a string that looks like
- X * %ld%3c%s gmt_in_secs weekday orig_timezone
- X * This function is a bunch of scanfs on known date formats. Don't
- X * trust the "weekday" name fields because they may not be spelled
- X * right, or have the correct punctuation. Figure it out once the
- X * year and month and date have been determined.
- X */
- Xchar *
- Xparse_date(p)
- Xregister char *p;
- X{
- X /* When scanf-ing if month isn't a month, it could be a _long_ string.
- X * this is also the static buffer whose address we return.
- X */
- X static char month[64];
- X char Wkday[4], Zone[8];
- X char a_or_p;
- X int Month = 0, Day = 0, Year = 0;
- X int Uhour = 0, Umin = 0, Hours = -1, Mins = -1;
- X struct tm T;
- X
- X Zone[0] = 0;
- X skipspaces(0);
- X
- X /* programmer's note -- there are too many scanfs here for some compilers
- X * to put them all into one if statement. Use goto's :-( Also reset
- X * Zone[0] after any sscanf() that could corrupt it on a partial match.
- X */
- X
- X /* RFC822 formats and minor variations -- order important */
- X
- X /* day_number month_name year_number time timezone */
- X if (sscanf(p, "%d %s %d %d:%d:%*d %7s",
- X &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- X goto gotit;
- X Zone[0] = 0;
- X if (sscanf(p, "%d %s %d %d:%d %7s",
- X &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- X goto gotit;
- X Zone[0] = 0;
- X /* day_name day_number month_name year_number time timezone */
- X if (sscanf(p, "%*s %d %s %d %d:%d:%*d %7s",
- X &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- X goto gotit;
- X Zone[0] = 0;
- X if (sscanf(p, "%*s %d %s %d %d:%d %7s",
- X &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- X goto gotit;
- X Zone[0] = 0;
- X
- X /* Ctime format (From_ lines) -- timezone almost never found */
- X
- X /* day_name month_name day_number time year_number */
- X if (sscanf(p, "%*s %s %d %d:%d:%*d %d %7s",
- X month, &Day, &Hours, &Mins, &Year, Zone) >= 5)
- X goto gotit;
- X Zone[0] = 0;
- X
- X /* Other common variants */
- X
- X /* day_number month_name year_number time-timezone (day) */
- X /* ^no colon separator */
- X if (sscanf(p, "%d %s %d %2d%2d-%6[0123456789]",
- X &Day, month, &Year, &Hours, &Mins, &Zone[1]) == 6) {
- X Zone[0] = '-';
- X goto gotit;
- X }
- X if (sscanf(p, "%d %s %d %2d%2d-%7s",
- X &Day, month, &Year, &Hours, &Mins, Zone) == 6)
- X goto gotit;
- X Zone[0] = 0;
- X
- X /* day_number month_name year_number time timezone */
- X /* ^no colon separator */
- X /* (This is the odd one in the RFC822 examples section; */
- X /* also catches the slop from partial hits above.) */
- X if (sscanf(p, "%d %s %d %2d%2d %7s",
- X &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- X goto gotit;
- X Zone[0] = 0;
- X
- X Zone[1] = 0; /* Yes, Zone[1] -- tested below */
- X
- X /* day_number month_name year_number, time "-" ?? */
- X if (sscanf(p,"%d %s %d, %d:%d:%*d -%6[0123456789]",
- X &Day, month, &Year, &Hours, &Mins, &Zone[1]) >= 5 && Day) {
- X if (Zone[1])
- X Zone[0] = '-';
- X goto gotit;
- X }
- X
- X /* day_number month_name year_number 12_hour_time a_or_p */
- X if (sscanf(p, "%d %s %d %d:%d:%*d %cm %7s",
- X &Day, month, &Year, &Hours, &Mins, &a_or_p, Zone) >= 6) {
- X if (a_or_p == 'p')
- X Hours += 12;
- X goto gotit;
- X }
- X
- X /* day_name month_name day_number year_number time */
- X if (sscanf(p, "%*s %s %d %d %d:%d:%*d %7s",
- X month, &Day, &Year, &Hours, &Mins, Zone) >= 5)
- X goto gotit;
- X Zone[0] = 0;
- X if (sscanf(p, "%*s %s %d %d %d:%d %7s",
- X month, &Day, &Year, &Hours, &Mins, Zone) >= 5)
- X goto gotit;
- X Zone[0] = 0;
- X
- X /* day_name month_name day_number time timezone year_number */
- X if (sscanf(p, "%*s %s %d %d:%d:%*d %7s %d",
- X month, &Day, &Hours, &Mins, Zone, &Year) == 6)
- X goto gotit;
- X Zone[0] = 0;
- X if (sscanf(p, "%*s %s %d %d:%d %7s %d",
- X month, &Day, &Hours, &Mins, Zone, &Year) == 6)
- X goto gotit;
- X Zone[0] = 0;
- X
- X /* day_number-month_name-year time */
- X if (sscanf(p,"%d-%[^-]-%d %d:%d", &Day, month, &Year, &Hours, &Mins) == 5)
- X goto gotit;
- X
- X /* day_name, day_number-month_name-year time */
- X if (sscanf(p,"%*s %d-%[^-]-%d %d:%d",
- X &Day, month, &Year, &Hours, &Mins) == 5)
- X goto gotit;
- X
- X /* year_number-month_number-day_number time */
- X if (sscanf(p, "%d-%d-%d %d:%d", &Year, &Month, &Day, &Hours, &Mins) == 5)
- X goto gotit;
- X
- X /* month_name day_number time year Zone */
- X /* (ctime, but without the day name) */
- X if (sscanf(p, "%s %d %d:%d:%*d %d %7s",
- X month, &Day, &Hours, &Mins, &Year, Zone) >= 5)
- X goto gotit;
- X Zone[0] = 0;
- X
- X goto didnt_getit;
- X
- Xgotit:
- X if (Year > 1900)
- X Year -= 1900;
- X if (!Month && (Month = month_to_n(month)) == -1) {
- X print("bad month: %s\n", p);
- X return NULL;
- X }
- X if (Zone[0] == 0) {
- X /* Use local time zone if none found -- important for date_recv */
- X (void) time_n_zone(Zone);
- X }
- X {
- X /* Lots of foolishness with casts for Xenix-286 16-bit ints */
- X
- X long days_ctr; /* 16-bit ints overflowed Sept 12, 1989 */
- X
- X days_ctr = ((long)Year * 365L) + ((Year + 3) / 4);
- X days_ctr += mtbl[Month-1] + Day + 6;
- X if (Month > 2 && (Year % 4 == 0))
- X days_ctr++;
- X (void) (sprintf(Wkday, "%.3s", day_names[(int)(days_ctr % 7L)]));
- X }
- X T.tm_sec = 0; /* not recorded, so ignore it */
- X T.tm_min = Mins;
- X T.tm_hour = Hours;
- X T.tm_mday = Day;
- X T.tm_mon = Month - 1;
- X T.tm_year = Year;
- X T.tm_wday = T.tm_yday = 0; /* not used in time2gmt() */
- X T.tm_isdst = 0; /* determined from Zone */
- X return sprintf(month, "%ld%s%s", time2gmt(&T, Zone, 1), Wkday, Zone);
- Xdidnt_getit:
- X if (ison(glob_flags, WARNING))
- X print("Unknown date format: %s\n", p);
- X return NULL;
- X}
- X
- X/* pass a string in the standard date format, put into string.
- X * return values in buffers provided they are not null.
- X */
- Xchar *
- Xdate_to_string(Date, Yr, Mon, Day, Wkday, Tm, Zone, ret_buf)
- Xchar *Date, *Yr, *Mon, *Day, *Wkday, *Tm, *Zone, *ret_buf;
- X{
- X long gmt;
- X struct tm *T;
- X char a_or_p, *p = ret_buf;
- X
- X Zone[0] = 0;
- X (void) sscanf(Date, "%ld%3c%s", &gmt, Wkday, Zone);
- X Wkday[3] = 0;
- X gmt += getzoff(Zone);
- X T = gmtime(&gmt);
- X a_or_p = (T->tm_hour < 12)? 'a': 'p';
- X
- X (void) sprintf(Yr, "%d", T->tm_year + 1900);
- X (void) sprintf(Day, "%d", T->tm_mday);
- X (void) strcpy(Mon, month_names[T->tm_mon]);
- X p += strlen(sprintf(p, "%s %2.d, ", Mon, T->tm_mday));
- X
- X if (ison(glob_flags, MIL_TIME))
- X (void) sprintf(p, "%2d:%02d",T->tm_hour,T->tm_min);
- X else
- X (void) sprintf(p, "%2.d:%02d%cm",
- X (T->tm_hour)? (T->tm_hour <= 12)? T->tm_hour: T->tm_hour-12: 12,
- X T->tm_min, a_or_p);
- X (void) strcpy(Tm, p);
- X
- X return ret_buf;
- X}
- X
- X/* pass a string in the internal mush date format.
- X * return pointer to static buffer holding ctime-format date.
- X */
- Xchar *
- Xdate_to_ctime(Date)
- Xchar *Date;
- X{
- X static char ret_buf[32];
- X long gmt;
- X
- X ret_buf[0] = 0;
- X (void) sscanf(Date, "%ld", &gmt);
- X (void) strcpy(ret_buf, ctime(&gmt));
- X
- X return ret_buf;
- X}
- X
- X/*
- X * Build a date string according to the specification in the RFC for Date:
- X */
- Xchar *
- Xrfc_date(buf)
- Xchar buf[];
- X{
- X struct tm *T;
- X char zone[8];
- X
- X T = time_n_zone(zone);
- X return sprintf(buf, "%s, %d %s %d %02d:%02d:%02d %s",
- X day_names[T->tm_wday], /* day name */
- X T->tm_mday, /* day of the month */
- X month_names[T->tm_mon], /* month name */
- X T->tm_year + 1900, /* year number */
- X T->tm_hour, /* hours (24hr) */
- X T->tm_min, T->tm_sec, /* mins/secs */
- X zone); /* timezone */
- X}
- X
- X#define JAN 1
- X#define FEB 2
- X#define MAR 3
- X#define APR 4
- X#define MAY 5
- X#define JUN 6
- X#define JUL 7
- X#define AUG 8
- X#define SEP 9
- X#define OCT 10
- X#define NOV 11
- X#define DEC 12
- X
- X/* stolen direct from ELM */
- Xmonth_to_n(name)
- Xregister char *name;
- X{
- X /** return the month number given the month name... **/
- X
- X register char ch;
- X
- X switch (lower(*name)) {
- X case 'a' : if ((ch = lower(name[1])) == 'p')
- X return(APR);
- X else if (ch == 'u')
- X return(AUG);
- X else return(-1); /* error! */
- X case 'd' : return(DEC);
- X case 'f' : return(FEB);
- X case 'j' : if ((ch = lower(name[1])) == 'a')
- X return(JAN);
- X else if (ch == 'u') {
- X if ((ch = lower(name[2])) == 'n')
- X return(JUN);
- X else if (ch == 'l')
- X return(JUL);
- X else return(-1); /* error! */
- X }
- X else return(-1); /* error */
- X case 'm' : if ((ch = lower(name[2])) == 'r')
- X return(MAR);
- X else if (ch == 'y')
- X return(MAY);
- X else return(-1); /* error! */
- X case 'n' : return(NOV);
- X case 'o' : return(OCT);
- X case 's' : return(SEP);
- X default : return(-1);
- X }
- X}
- END_OF_FILE
- if test 14562 -ne `wc -c <'mush/dates.c'`; then
- echo shar: \"'mush/dates.c'\" unpacked with wrong size!
- fi
- # end of 'mush/dates.c'
- fi
- if test -f 'mush/file.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/file.c'\"
- else
- echo shar: Extracting \"'mush/file.c'\" \(14337 characters\)
- sed "s/^X//" >'mush/file.c' <<'END_OF_FILE'
- X/* file.c -- Copyright (1988) Dan Heller */
- X
- X#include "mush.h"
- X#include <pwd.h>
- X
- X/* takes string 'p' and address of int (isdir). If p uses the ~ to reference
- X * a home directory of some sort, then expand it. find out what sort of
- X * file final path is. set isdir to 1 if a directory, 0 if not, -1 on error
- X * return final path. If an error occurs, return string indicating error.
- X * if isdir has a value of 1 when passed, it ignores "No such file or directory"
- X */
- Xchar *
- Xgetpath(p, isdir)
- Xregister char *p;
- Xint *isdir;
- X{
- X static char buf[MAXPATHLEN];
- X struct stat stat_buf;
- X
- X if (!p || !*p || !strcmp(p, "~")) {
- X char *home = do_set(set_options, "home");
- X if (!home || !*home)
- X home = ALTERNATE_HOME;
- X (void) strcpy(buf, home); /* no arg means home */
- X } else if (*p == '~') {
- X if (p[1] != '/') {
- X /* not our home, but someone else's
- X * look for ~user or ~user/subpath
- X * if '/' exists, separate into tmp="user" p="subpath"
- X */
- X struct passwd *ent, *getpwnam();
- X char *p2 = p+1;
- X if (p = index(p2, '/'))
- X *p++ = 0;
- X if (!(ent = getpwnam(p2))) {
- X *isdir = -1;
- X return sprintf(buf, "no such user: %s", p2);
- X }
- X /* append subpath to pathname */
- X if (p && *p)
- X (void) sprintf(buf, "%s/%s", ent->pw_dir, p);
- X /* if *p == NULL, pathname is done (buf), set isdir = 1 */
- X else {
- X *isdir = 1;
- X return strcpy(buf, ent->pw_dir);
- X }
- X } else {
- X char *home = do_set(set_options, "home");
- X if (!home || !*home)
- X home = ALTERNATE_HOME;
- X (void) sprintf(buf, "%s/%s", home, p+2);
- X }
- X } else if (*p == '%') {
- X /* if %user, append user name... else, it's just us */
- X if (!*++p || *p == ' ' || *p == '\t')
- X (void) strcpy(buf, spoolfile);
- X else
- X#ifndef HOMEMAIL
- X (void) sprintf(buf, "%s/%s", MAILDIR, p);
- X#else /* HOMEMAIL */
- X {
- X /* If it's NOT us, recur to get the path for ~user/MAILFILE */
- X int t_isdir = *isdir;
- X char *t, tmp[MAXPATHLEN];
- X (void) sprintf(tmp, "~%s/%s", p, MAILFILE);
- X t = getpath(tmp, &t_isdir);
- X if (t_isdir == -1) {
- X *isdir = -1;
- X return t;
- X }
- X /* strcpy(buf, t); --buf already has info because it's static */
- X }
- X#endif /* HOMEMAIL */
- X } else if (*p == '+') {
- X register char *p2 = do_set(set_options, "folder");
- X if (!p2 || !*p2)
- X p2 = DEF_FOLDER;
- X if (*++p)
- X (void) sprintf(buf, "%s/%s", p2, p);
- X else
- X (void) strcpy(buf, p2);
- X if (*buf != '/') {
- X int t_isdir = *isdir;
- X char *t, tmp[MAXPATHLEN];
- X if (*buf != '~')
- X (void) sprintf(tmp, "~/%s", buf);
- X else
- X (void) strcpy(tmp, buf);
- X t = getpath(tmp, &t_isdir);
- X if (t_isdir == -1) {
- X *isdir = -1;
- X return t;
- X }
- X /* strcpy(buf, t); --buf already has info because it's static */
- X }
- X } else { /* allow \ to escape the special chars, +, %, ~ */
- X if (*p == '\\')
- X p++;
- X (void) strcpy(buf, p);
- X }
- X if (stat(buf, &stat_buf)) {
- X (void) access(buf, F_OK); /* set errno to the "real" reason */
- X if (errno == ENOENT && *isdir == 1) {
- X *isdir = 0; /* say it's a regular file even tho it doesn't exist */
- X return buf; /* it may be wanted for creating */
- X }
- X *isdir = -1;
- X return sys_errlist[errno];
- X }
- X *isdir = ((stat_buf.st_mode & S_IFMT) == S_IFDIR);
- X return buf;
- X}
- X
- X/*
- X * Given a (possibly NULL or empty) string, return the name of a a valid
- X * directory. The string may contain the usual filename metachars (see
- X * above). Returns the current user's home directory if the input string
- X * does not refer to a directory, the ALTERNATE_HOME if the user's home
- X * directory cannot be found, or NULL if none of the above are accessible.
- X *
- X * NOTE: Returns the getpath() static buffer, so the same caveats apply.
- X */
- Xchar *
- Xgetdir(path)
- Xchar *path;
- X{
- X int isdir = 0;
- X
- X /* getpath() already handles the NULL and empty cases */
- X if (!(path = getpath(path, &isdir)) || isdir != 1) {
- X isdir = 0;
- X path = getpath(ALTERNATE_HOME, &isdir);
- X if (isdir != 1)
- X path = NULL;
- X }
- X return path;
- X}
- X
- X/*
- X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
- X * opens the file with the mode.
- X * If the mode is "r" then we read the file into the file pointer at the
- X * end (fseek(fp, 2, 0)). If the file is opened for writing, then read
- X * from the beginning of fp and write it into the file.
- X * This is usually called to read .signatures into messages (thus,
- X * opening .signature with "r" and writing to the end of fp which is probably
- X * the sendmail process or the message file pointer) or to write fortunes into
- X * the message buffer: reading fp (the popened fortune) and writing into file.
- X */
- Xfile_to_fp(p, fp, mode)
- Xregister char *p;
- Xregister FILE *fp;
- Xchar *mode;
- X{
- X int x = 1;
- X char *file, buf[BUFSIZ];
- X FILE *tmp_fp;
- X
- X if (!p || !*p) {
- X print("specify filename");
- X return -1;
- X }
- X /* Special case for IS_SENDING && !IS_GETTING should eventually go away */
- X if (ison(glob_flags, IS_SENDING) && isoff(glob_flags, IS_GETTING) &&
- X strcmp(p, "-") == 0) {
- X file = p;
- X if (*mode == 'r')
- X tmp_fp = stdin;
- X else
- X tmp_fp = stdout;
- X } else {
- X file = getpath(p, &x);
- X if (x == -1) { /* on error, file contains error message */
- X wprint(file);
- X return -1;
- X }
- X wprint("%s: ", file);
- X if (x) {
- X /* if x == 1, then path is a directory */
- X wprint("is a directory.\n");
- X return -1;
- X } else if (!(tmp_fp = fopen(file, mode))) {
- X wprint("%s\n", sys_errlist[errno]);
- X return -1;
- X }
- X }
- X if (*mode != 'r') {
- X rewind(fp);
- X for(x = 0; fgets(buf, BUFSIZ, fp); x++)
- X (void) fputs(buf, tmp_fp);
- X } else {
- X for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
- X (void) fputs(buf, fp);
- X (void) fflush(fp);
- X }
- X wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
- X x, (x == 1)? "": "s");
- X if (file != p || strcmp(file, "-") != 0)
- X (void) fclose(tmp_fp);
- X return 0;
- X}
- X
- X/* clear all contents of the file. Careful that the file is opened for
- X * _writing_ --tempfile is opened for reading, so don't try to empty it
- X * if you're using ftruncate. Return -1 on error, 0 on success.
- X */
- Xemptyfile(fp, fname)
- Xregister FILE **fp;
- Xregister char *fname;
- X{
- X Debug("Emptying \"%s\"\n", fname);
- X#ifndef SYSV
- X return ftruncate(fileno(*fp), 0L);
- X#else
- X {
- X int omask = umask(077), ret;
- X (void) fclose(*fp);
- X if (!(*fp = fopen(fname, "w")))
- X ret = -1;
- X ret = 0;
- X (void) umask(omask);
- X return ret;
- X }
- X#endif /* SYSV */
- X}
- X
- X/*
- X * Finds out how many file descriptors are opened. Useful for making sure
- X * no files got opened in subprocedures which were not subsequently closed.
- X * If argc is 0, returns the number of available fds.
- X */
- Xnopenfiles(argc)
- X{
- X#ifdef MAXFILES
- X register int size = MAXFILES;
- X#else
- X register int size = getdtablesize();
- X#endif /* MAXFILES */
- X register int nfiles = 0, totalfiles = size;
- X
- X if (argc > 1)
- X return -1;
- X
- X if (argc == 1)
- X wprint("open file descriptors:");
- X while (--size >= 0)
- X if (fcntl(size, F_GETFL, 0) != -1) {
- X if (argc == 1)
- X wprint(" %d", size);
- X ++nfiles;
- X }
- X if (argc == 1) {
- X wprint("\n");
- X return 0;
- X }
- X return totalfiles - nfiles;
- X}
- X
- X/*
- X * Close all "extraneous" file descriptors; return the number closed
- X */
- Xclosefileds (n)
- X{
- X register int nfiles = 0;
- X#ifdef MAXFILES
- X register int size = MAXFILES;
- X#else
- X register int size = getdtablesize();
- X#endif /* MAXFILES */
- X
- X while (--size >= n)
- X if (fcntl(size, F_GETFL, 0) != -1) {
- X (void) close(size);
- X ++nfiles;
- X }
- X return nfiles;
- X}
- X
- X/*
- X * Open a path for writing or appending -- return a FILE pointer.
- X * If program is TRUE, then use popen, not fopen and don't check
- X * to see if the file is writable. If program is FALSE and lockit
- X * is TRUE, then lock on open.
- X */
- XFILE *
- Xopen_file(p, program, lockit)
- Xregister char *p;
- X{
- X register FILE *newfile = NULL_FILE;
- X register char *tmp;
- X int x = 1;
- X
- X if (program || *p == '/')
- X tmp = p, x = 0;
- X else
- X tmp = getpath(p, &x);
- X if (x == 1)
- X print("%s is a directory.\n", tmp);
- X else if (x == -1)
- X print("%s: %s\n", p, tmp);
- X else {
- X register char *mode = NULL;
- X /* if it doesn't exist open for "w" */
- X if (program || Access(tmp, F_OK))
- X mode = "w";
- X /* if we can't write to it, forget it */
- X else if (Access(tmp, W_OK))
- X error(tmp);
- X else
- X mode = "a";
- X if (mode)
- X if (program) {
- X if (!(newfile = popen(tmp, mode)))
- X error("Can't execute %s\n", tmp);
- X } else if (lockit) {
- X /* Lock on open */
- X if (!(newfile = lock_fopen(tmp, mode)))
- X error("Can't write to %s", tmp);
- X } else {
- X /* Ordinary open */
- X if (!(newfile = mask_fopen(tmp, mode)))
- X error("Can't write to %s", tmp);
- X }
- X if (newfile != NULL_FILE)
- X Debug("Successfully opened %s\n", tmp);
- X }
- X return newfile;
- X}
- X
- X/*
- X * Open each file in the vector names[] and place the corresponding
- X * file descriptor in files[]. If the file is really a program (pipe),
- X * delete the name after opening; otherwise lock the file.
- X * Tokens beginning with a "/, ~, or + are files; tokens beginning
- X * with a | are programs.
- X */
- Xopen_list(names, files, size)
- Xchar *names[];
- XFILE *files[];
- X{
- X register int total = 0, prog;
- X register char *fpath;
- X
- X Debug("opening "), print_argv(names);
- X for (total = 0; size && total < size; ) {
- X fpath = names[total] + (prog = (names[total][0] == '|'));
- X /* open_file() locks the file here only if prog is false */
- X if ((files[total] = open_file(fpath, prog, TRUE))) {
- X if (prog) {
- X xfree(names[total]);
- X names[total++] = NULL;
- X } else {
- X /* Seek to end of file AFTER locking */
- X (void) fseek(files[total++], 0L, 2);
- X }
- X } else {
- X Debug("Failed to open %s\n", names[total]);
- X /* Swap the failed file with the last in the list */
- X if (size--) {
- X xfree(names[total]);
- X names[total] = names[size];
- X names[size] = NULL;
- X }
- X }
- X }
- X return size;
- X}
- X
- X/*
- X * find_files gets a set of addresses and an array of
- X * char pointers and the maximum size that array can be.
- X * The object is to find the files or programs listed in "s". If the
- X * size is 0, then just extract the file names and give error messages
- X * for each one since they will not be opened. Return the number of
- X * files found and delete all files from the list in * "s".
- X * The string "s" is modified to be a list of address -- all names AND
- X * files are stripped out of the list.
- X * The force parameter causes names to be interpreted as files even if
- X * they would normally appear to be addresses.
- X */
- Xfind_files(s, names, size, force)
- Xregister char *s;
- Xchar *names[];
- X{
- X register int total = 0;
- X char file[MAXPATHLEN], buf[HDRSIZ], *start = s, c;
- X register char *p, *b = buf, *fpath;
- X
- X do {
- X if (!(p = get_name_n_addr(s, NULL, file)))
- X break;
- X c = *p, *p = 0;
- X /* See if it's a file. This doesn't get written back
- X * onto "buf" since it is supposed to be extracted anyway.
- X */
- X if (force || *file == '+' || *file == '~' ||
- X *file == '|' || *file == '/') {
- X int isdir;
- X /* open either "file" or &file[1] */
- X if (*file == '|') {
- X isdir = 0;
- X fpath = file;
- X } else {
- X isdir = 1;
- X /* if successful, getpath will reset isdir to 0 */
- X fpath = getpath(file, &isdir);
- X }
- X if (!isdir) {
- X if (size && total < size)
- X names[total++] = savestr(fpath);
- X else
- X print("No open space for %s\n", file);
- X } else if (isdir == 1)
- X print("%s: is a directory\n", file);
- X else
- X print("%s: %s\n", file, fpath);
- X } else {
- X b += Strcpy(b, s);
- X *b++ = ',', *b++ = ' ';
- X }
- X for (*p = c, s = p; *s == ',' || isspace(*s); s++)
- X ;
- X } while (*s);
- X for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X names[total] = NULL; /* for free_vec() */
- X return total;
- X}
- X
- X/*
- X * access(2) has an undocumented feature which ignores suid. If you are
- X * su'ed and try to read your mail, you will be unable to because access()
- X * will give the illusion that you cannot read/write to your mbox. Solve
- X * the problem by using stat() instead.
- X */
- XAccess(file, mode)
- Xregister char *file;
- X{
- X struct stat buf;
- X
- X if (stat(file, &buf) == -1)
- X return -1;
- X if (mode == R_OK)
- X return (buf.st_mode & 0400)? 0 : -1;
- X if (mode == W_OK)
- X return (buf.st_mode & 0200)? 0 : -1;
- X return 0;
- X}
- X
- X/*
- X * Open a file for read/write/whatever but make sure umask is rw by user only.
- X */
- XFILE *
- Xmask_fopen(file, mode)
- Xchar *file, *mode;
- X{
- X int omask = umask(077);
- X FILE *fp = fopen(file, mode);
- X (void) umask(omask);
- X return fp;
- X}
- X
- X/*
- X * Shorten a file name, replacing its full path name with one using an
- X * accepted mush abbreviation:
- X * ~ home directory
- X * + folder directory
- X * For files in the current directory, the path is simply skipped.
- X * Returns a pointer into a static buffer holding the trimmed path.
- X */
- Xchar *
- Xtrim_filename(name)
- Xchar *name;
- X{
- X static char buf[MAXPATHLEN];
- X char *fldr = do_set(set_options, "folder"),
- X *home = do_set(set_options, "home");
- X int len;
- X
- X /* Handling $folder is tough, because if it is not set then we should
- X * trim DEF_FOLDER; but DEF_FOLDER may not be a full path, and we can't
- X * call getpath() because the "name" parameter may point to gepath()'s
- X * static buffer. So we handle the special case of DEF_FOLDER starting
- X * with a tilde ($home), and forget about it otherwise. Yuck.
- X */
- X if ((!fldr || !*fldr) && (fldr = DEF_FOLDER) && *fldr == '~' && home) {
- X (void) sprintf(buf, "%s%s", home, fldr + 1);
- X fldr = buf; /* buf will get overwritten again below */
- X }
- X /* One more special case: if $folder and $home are the same, then we
- X * trim as $home, otherwise we trim as $folder. This prevents strange
- X * contractions like "+.cshrc" for "~/.cshrc".
- X */
- X if ((!home || strcmp(home, fldr)) && (len = strlen(fldr)) &&
- X !strncmp(fldr, name, len) && (name[len] == '/' || !name[len])) {
- X buf[0] = '+';
- X if (name[len] && name[len + 1])
- X (void) strcpy(buf + 1, name + len + 1);
- X else
- X buf[1] = 0;
- X return buf;
- X } else if (home && (len = strlen(home)) && !strncmp(home, name, len) &&
- X (name[len] == '/' || !name[len])) {
- X buf[0] = '~';
- X (void) strcpy(buf + 1, name + len);
- X return buf;
- X } else if ((fldr = do_set(set_options, "cwd")) &&
- X (len = strlen(fldr)) && !strncmp(fldr, name, len) &&
- X name[len] == '/')
- X return strcpy(buf, name + len + 1);
- X return strcpy(buf, name);
- X}
- END_OF_FILE
- if test 14337 -ne `wc -c <'mush/file.c'`; then
- echo shar: \"'mush/file.c'\" unpacked with wrong size!
- fi
- # end of 'mush/file.c'
- fi
- if test -f 'mush/sample.mushrc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/sample.mushrc'\"
- else
- echo shar: Extracting \"'mush/sample.mushrc'\" \(6541 characters\)
- sed "s/^X//" >'mush/sample.mushrc' <<'END_OF_FILE'
- X# sample.mushrc
- X# By Bart Schaefer and Dan Heller
- X#
- X# Change mush's temp file directory, to avoid quota collisions.
- X# /usr/tmp so tmpfiles won't be rm'd before they can be recovered.
- Xset tmpdir=/usr/tmp
- X
- X# Set the folder and mbox locations; the + expands to value of "folder".
- Xset folder=$HOME/Mail mbox=+mbox
- X
- X# Set up the display early to allow quick exit in headers-only mode.
- X# The hdrs_only flag is true if the command line was: "mush -H".
- X# The variable hdr_format is set to change the format of the header
- X# summaries that are displayed.
- Xif hdrs_only
- X set hdr_format='%28a %M %-2N %.33s'
- X exit # Quits reading this file
- Xelse
- X set hdr_format='%28a %M %-2N (%3.5l li) %.25s'
- Xendif
- X
- X# Set the prompt to show current time, name of the current folder,
- X# current message number, and count of total messages.
- Xset prompt="(%T) %f: #%m of %t> "
- X
- X# Hitting <CR> should do nothing (helps make mush more shell-like). If
- X# newline is not set, hitting <CR> prints the next message (like Mail).
- X# This variable could be set to any mush command.
- Xset newline
- X
- X# These variables are helpful for new users:
- X# ask -- always prompt for Subject: of mail
- X# ignoreeof -- ignore end-of-file from keyboard
- X# verify -- query that all is well before sending mail
- X# warning -- report miscellaneous possible problems
- Xset ask verify warning
- Xset ignoreeof="echo 'Use "'"'quit'"'" to quit.'"
- X
- X# When reading messages, don't bother looking at lengthy, boring headers.
- Xignore message-id received via status
- X
- X# Since mush has csh-like history, you might find it annoying to type
- X# things like "mail host\!host1\!host2\!user" from within the mush shell.
- X# Setting nonobang will prevent the "unknown event" and allow the !'s to
- X# be typed without having to be preceded by backslashes.
- Xset nonobang
- X
- X# By default, mush's history is set to the last command only. Set it to
- X# remember the last 100 commands.
- Xset history = 100
- X
- X# If the variable "unix" is set, then any command that isn't a mush command
- X# will execute the command as if you typed it from the shell. Note, such
- X# commands will not go through another shell -- this is it.
- Xset unix
- X
- X# Mush tries to read ~/.mushrc first, then it tries ~/.mailrc. Assuming
- X# you use *this* file as your .mushrc, source the contents of .mailrc as
- X# well in case there are Mail aliases that are set there.
- Xsource $HOME/.mailrc
- X
- X# Use a real pager.
- Xset pager=less
- X
- X# When typing in a letter, it is sometimes convenient to have lines wrap
- X# automatically similar to editors like vi and emacs. In this example, if
- X# the user types past column 74, a newline will automatically be inserted.
- Xset wrapcolumn=74
- X
- X# If "autosign" is set, then a file can be read in automatically whenever
- X# mail is sent. This file is normally your "signature," that is, your
- X# name and other information you want included in every message.
- Xset autosign = ~/.signature
- X
- X# When you use the -i option to reply, or use the ~i tilde escape in a letter
- X# when in compose mode, the current message will be included in your text.
- X# Put a nice wrapper around those included messages. Here, show the author's
- X# name and the subject of his letter, label the end, and add a trailing blank
- X# to separate each inclusion and make finding the end easier.
- Xset pre_indent_str='On %M %N, %T, %.50n wrote:\n} Subject: %.65s'
- Xset indent_str='} ' # actual message text is preceded by a "}"
- Xset post_indent_str='}-- End of excerpt from %.50n\n'
- X
- X# Label replies with a header showing the who, what, and when of the
- X# message being replied-to.
- Xset in_reply_to='%f\n\t"%s" (%d)'
- X
- X# Mail routing and address-fixing conveniences. If auto_route is set, then
- X# replies to messages take a closer look at the addresses of the recipients.
- X# If any redundant paths are present, they are pruned. Also, the path that
- X# precedes any hosts listed in the "known_hosts" list is truncated. This is
- X# useful for uucp sites only, and is therefore commented out in this sample.
- X# set auto_route known_hosts="sun ucbcad well unicom"
- X
- X# The "alts" command specifies alternate addresses that I have. Here,
- X# "*" expands to any "path" whose recipient ends with the user's current
- X# login name. If another login name is desired, the login and/or path
- X# to that login must be preceded by a !. Otherwise, standard paths are used.
- Xalts "*"
- X
- X# The "map" command can rebind certain key sequences in tty-mode only.
- X# Here, if the user types two R's in a row at the prompt, then the string
- X# "reply -ei " will be echoed as if the user typed it.
- Xmap RR "reply -ei "
- X# "rr" will do a reply and do the newline for you so you don't have to.
- Xmap rr "reply\n"
- X
- X# The "map!" command is similar to "map" in that you can do keyboard
- X# acceleration, but map! occurs during letter composition mode only.
- Xmap! '\CT' ' ' # ^T generates 4 spaces in composition mode.
- X# Here, hitting * twice will append a pre-signature.
- Xmap! ** "\n Later,\n"
- X
- X# Be careful with map and map! -- you can cause an infinite loop.
- X# Your interrupt key (usually ^C) will stop such loops.
- X
- X# The curses mode allows the screen to be set up like a full screen editor.
- X# There are basic "curses commands" which are bound to keyboard key-sequences
- X# (usually one character). The user can rebind these keys to suit his tastes.
- X# Note that the binding for R below removes the binding of reply-all.
- X#
- Xset curses_help # Unset this to remove help message in curses.
- Xbind \n display # Hit return to display the next message.
- Xbind t top # Make it easier to see the top few lines.
- Xbind e macro "[line-mode]edit\n" # Quick edit from curses.
- Xbind P macro "[line-mode]Print\n" # Show me all the headers.
- Xbind R macro "[line-mode]reply -ei " # Reply with inclusion and edit.
- Xbind A macro "R[getline]~t\n\CUargv\n" # R to Dan w/auto address fix.
- X
- X# "cmd" is used to set command line aliases similar to the way "csh"
- X# does it. The only difference is that "alias" is a reserved word in
- X# Mush and Mail, so cmd is used.
- X#
- Xcmd dq 'd \!*; q' # Delete a message list, then quit.
- Xcmd unread 'flags \!* U O' # Mark messages unread.
- Xcmd : curses # Colon now "toggles" curses mode.
- X
- X# Find messages from mailer-daemon (ignore upper/lower case).
- Xcmd md 'pick -i -f mailer-daemon'
- X# Because mush can pipe commands to one another, including "cmd"'s, this
- X# example will delete all messages from mailer-daemon
- Xcmd dmd 'md | delete'
- X
- X# aliases -- just like Mail's, but you can specify "names"
- Xalias argv Dan Heller <argv@sun.com>
- Xalias bart Bart Schaefer <schaefer@ogicse.ogi.edu>
- Xalias mush-users Mush Users <mush-users-request@garp.mit.edu>
- END_OF_FILE
- if test 6541 -ne `wc -c <'mush/sample.mushrc'`; then
- echo shar: \"'mush/sample.mushrc'\" unpacked with wrong size!
- fi
- # end of 'mush/sample.mushrc'
- fi
- if test -f 'mush/tool.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/tool.c'\"
- else
- echo shar: Extracting \"'mush/tool.c'\" \(15050 characters\)
- sed "s/^X//" >'mush/tool.c' <<'END_OF_FILE'
- X/* @(#)tool.c (c) copyright 10/15/86 (Dan Heller) */
- X
- X/* tool.c --make the mailtool windows, panels, etc... */
- X#include "mush.h"
- X
- X#ifndef FONTDIR
- X#define FONTDIR "/usr/lib/fonts/fixedwidthfonts/"
- X#endif /* FONTDIR */
- X
- Xextern void print_sigwinch(), make_hdr_sw();
- Xextern Notify_value fkey_interposer();
- X
- Xstatic void init_cursors(), geticon();
- X
- Xextern Panel /* panels.c */
- X make_hdr_panel(), make_main_panel();
- X
- XPanel
- X main_panel, /* the main panel dealing with generic items */
- X hdr_panel; /* panel which contains message header specific items */
- X
- XTextsw cprint_sw, mfprint_sw, wprint_sw;
- XFrame compose_frame;
- X
- Xstatic char **choice_args, **button_args;
- X
- Xshort dat_mail_icon_1[] = {
- X#include "mail.icon.1"
- X};
- X
- Xshort dat_mail_icon_2[] = {
- X#include "mail.icon.2"
- X};
- X
- Xshort dat_coffee_cup[] = {
- X 0x0200,0x0100,0x0600,0x0800,0x0600,0x0100,0xFFF8,0x800C,
- X 0x800A,0x4012,0x401C,0x2020,0x9048,0x7FF0,0x3FE0,0x0000
- X};
- X
- Xmpr_static(mail_icon_image1, 64, 64, 1, dat_mail_icon_1);
- Xmpr_static(mail_icon_image2, 64, 64, 1, dat_mail_icon_2);
- X
- Xmpr_static(coffee_cup, 16, 16, 1, dat_coffee_cup);
- X
- X/* public for hdr_sw.c */
- XCursor l_cursor, m_cursor, r_cursor;
- Xstatic Cursor coffee;
- X
- X/* text and font will be set in mail_status() */
- XIcon mail_icon;
- X
- Xstatic Notify_value scroll_hdr();
- X
- Xmake_tool()
- X{
- X Rect mrect; /* Position and size of icon label. */
- X struct stat rootbuf, tmpbuf;
- X char *p;
- X struct pixfont *pf_open();
- X
- X if (p = do_set(set_options, "font")) {
- X char buf[MAXPATHLEN];
- X (void) sprintf(buf, "%s%s", FONTDIR, p);
- X if (!(mush_font = pf_open(buf)))
- X print("couldn't open font \"%s\"\nUsing default font.\n", buf);
- X }
- X if (!mush_font)
- X mush_font = pf_default();
- X
- X geticon();
- X check_icons();
- X
- X if (p = do_set(set_options, "screen_win"))
- X screen = atoi(p);
- X else
- X screen = 6;
- X
- X /* where to place text on mail icon -- how many messages there are */
- X mrect.r_left = l_width();
- X mrect.r_top = 58-l_height();
- X mrect.r_width = 3*l_width();
- X mrect.r_height = l_height();
- X (void) icon_set(mail_icon, ICON_LABEL_RECT, &mrect, NULL);
- X
- X (void) window_set(tool,
- X FRAME_ICON, mail_icon,
- X WIN_CONSUME_KBD_EVENTS,
- X WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
- X NULL);
- X (void) notify_interpose_destroy_func(tool, destroy_proc);
- X
- X choice_args = panel_make_list(
- X PANEL_MENU_TITLE_FONT, mush_font,
- X PANEL_DISPLAY_LEVEL, PANEL_NONE,
- X PANEL_SHOW_MENU, TRUE,
- X PANEL_SHOW_MENU_MARK, FALSE,
- X NULL);
- X
- X button_args = panel_make_list(
- X PANEL_FEEDBACK, PANEL_INVERTED,
- X PANEL_SHOW_MENU, FALSE,
- X NULL);
- X
- X hdr_panel = make_hdr_panel(tool, choice_args, button_args);
- X
- X make_hdr_sw(tool);
- X
- X main_panel = make_main_panel(tool, choice_args, button_args);
- X
- X /* main mush frame text subwindow for wprint() */
- X mfprint_sw = window_create(tool, TEXTSW,
- X WIN_BELOW, main_panel,
- X WIN_HEIGHT, l_height() * 4,
- X TEXTSW_READ_ONLY, TRUE,
- X TEXTSW_BLINK_CARET, FALSE,
- X TEXTSW_LINE_BREAK_ACTION, TEXTSW_WRAP_AT_CHAR,
- X NULL);
- X /* order is important -- scroll_textwin should be called first! */
- X (void) notify_interpose_event_func(mfprint_sw,
- X fkey_interposer, NOTIFY_SAFE);
- X (void) notify_interpose_event_func(mfprint_sw,
- X scroll_textwin, NOTIFY_SAFE);
- X
- X /* text subwindow for paging messages */
- X p = do_set(set_options, "crt_win");
- X pager_textsw = window_create(tool, TEXTSW,
- X WIN_HEIGHT, l_height() * (p? atoi(p) : 12),
- X TEXTSW_READ_ONLY, TRUE,
- X TEXTSW_BLINK_CARET, FALSE,
- X#ifdef SUN_4_0 /* SunOS 4.0+ */
- X TEXTSW_LINE_BREAK_ACTION, TEXTSW_WRAP_AT_WORD,
- X#else /* SUN_4_0 */
- X TEXTSW_LINE_BREAK_ACTION, TEXTSW_WRAP_AT_CHAR,
- X#endif /* SUN_4_0 */
- X NULL);
- X /* order is important -- scroll_textwin should be called first! */
- X (void) notify_interpose_event_func(pager_textsw,
- X fkey_interposer, NOTIFY_SAFE);
- X (void) notify_interpose_event_func(pager_textsw,
- X scroll_textwin, NOTIFY_SAFE);
- X
- X (void) sprintf(blank, "%128c", ' ');
- X mrect = *(Rect *)window_get(hdr_sw, WIN_RECT);
- X pw_writebackground(hdr_win, 0,0, mrect.r_width, mrect.r_height, PIX_CLR);
- X istool = 2;
- X (void) fclose(stdin);
- X (void) fclose(stdout);
- X#ifndef SUN_3_5
- X /* SunOS 3.5 takes tty modes for ttysws from stderr. */
- X (void) fclose(stderr);
- X#endif /* SUN_3_5 */
- X (void) do_version();
- X init_cursors();
- X timeout_cursors(TRUE);
- X window_fit_height(tool);
- X}
- X
- Xvoid
- Xclose_frame()
- X{
- X window_set(compose_frame, WIN_SHOW, FALSE, NULL);
- X}
- X
- Xvoid
- Xmake_compose_frame()
- X{
- X char *p;
- X Textsw msg_sw;
- X Panel panel, make_compose_panel();
- X
- X#ifdef SUN_3_5
- X if (nopenfiles(0) < 8) {
- X ok_box("Too many frames; close one, please.\n");
- X return;
- X }
- X#endif /* SUN_3_5 */
- X
- X compose_frame = window_create(tool, FRAME,
- X FRAME_LABEL, "Compose Letter",
- X FRAME_SHOW_LABEL, TRUE,
- X FRAME_NO_CONFIRM, TRUE,
- X FRAME_DONE_PROC, close_frame,
- X WIN_SHOW, TRUE,
- X NULL);
- X
- X panel = make_compose_panel(compose_frame, choice_args, button_args);
- X
- X#ifdef CPRINT_SW
- X /* text subwindow for wprint() */
- X cprint_sw = window_create(compose_frame, TEXTSW,
- X WIN_HEIGHT, l_height() * 4,
- X WIN_BELOW, panel,
- X TEXTSW_READ_ONLY, TRUE,
- X TEXTSW_BLINK_CARET, FALSE,
- X TEXTSW_LINE_BREAK_ACTION, TEXTSW_WRAP_AT_CHAR,
- X NULL);
- X notify_interpose_event_func(cprint_sw, scroll_textwin, NOTIFY_SAFE);
- X (void) notify_interpose_event_func(cprint_sw,
- X fkey_interposer, NOTIFY_SAFE);
- X#else /* CPRINT_SW */
- X /* not enough fd's in SunOS 3.X for the extra textsw */
- X cprint_sw = (Textsw) 0;
- X#endif /* CPRINT_SW */
- X
- X /* text subwindow for composing messages */
- X p = do_set(set_options, "msg_win");
- X msg_sw = window_create(compose_frame, TEXTSW,
- X#ifdef CPRINT_SW
- X WIN_BELOW, cprint_sw,
- X#else /* CPRINT_SW */
- X WIN_BELOW, panel,
- X#endif /* CPRINT_SW */
- X WIN_HEIGHT, l_height() * (p? atoi(p) : 24),
- X TEXTSW_READ_ONLY, TRUE, /* set to false later */
- X TEXTSW_BLINK_CARET, FALSE,
- X TEXTSW_LINE_BREAK_ACTION, TEXTSW_WRAP_AT_CHAR,
- X TEXTSW_IGNORE_LIMIT, TEXTSW_INFINITY,
- X NULL);
- X notify_interpose_event_func(msg_sw, fkey_interposer, NOTIFY_SAFE);
- X notify_interpose_event_func(msg_sw, edit_msg_textwin, NOTIFY_SAFE);
- X
- X /* Assign textsw (msg_sw) to panel for panel items' callbacks */
- X panel_set(panel, PANEL_CLIENT_DATA, msg_sw, NULL);
- X
- X /* tty subwindow */
- X if (!(tty_sw = window_create(compose_frame, TTY,
- X TTY_QUIT_ON_CHILD_DEATH, FALSE,
- X TTY_ARGV, TTY_ARGV_DO_NOT_FORK,
- X WIN_CLIENT_DATA, msg_sw,
- X WIN_SHOW, FALSE,
- X WIN_WIDTH, WIN_EXTEND_TO_EDGE,
- X WIN_BELOW, msg_sw,
- X NULL)))
- X perror("tty_sw"), cleanup(0);
- X
- X window_fit_height(compose_frame);
- X}
- X
- X/*ARGSUSED*/
- Xvoid
- Xopen_compose()
- X{
- X if (compose_frame)
- X window_set(compose_frame, WIN_SHOW, TRUE, NULL);
- X else
- X make_compose_frame();
- X}
- X
- Xparse_tool_opts(argcp, argv)
- Xint *argcp;
- Xchar **argv;
- X{
- X if (!(tool = window_create((Window) 0, FRAME,
- X FRAME_ARGC_PTR_ARGV, argcp, argv,
- X NULL)))
- X cleanup(0);
- X}
- X
- X/*
- X * used by both the hdr_sw (to scroll canvas) and by textsw's.
- X * Return values:
- X * MUSH_SCROLL_TO (to scroll _to_ a particular location)
- X * MUSH_SCROLL_RELATIVE (scroll relative our current location)
- X * MUSH_SCROLL_IGNORE (not a scroll event and ignore it entirely (up events))
- X * MUSH_SCROLL_PASS_EVENT (not a scroll event; pass it to next event handler)
- X * If absolute scrolling (scroll_to) then "amount" is set to 1 for beginning
- X * of textsw or 2 for end of textsw.
- X * User can precede a keyboard scrolling request by a "count" -- the
- X * count is typed by the user in digits: 5j = move 5 lines down.
- X * It is assumed that if the user moves the mouse after a digit is pressed,
- X * then he doesn't really want to adjust the scrolling amount and the
- X * count is reset to the default (1).
- X */
- XScroll_action
- Xdecode_scroll(client, event, len, amount)
- XNotify_client client;
- XEvent *event;
- Xint len, *amount;
- X{
- X static int count;
- X
- X if (event_id(event) == LOC_MOVE) {
- X count = 0;
- X return MUSH_SCROLL_PASS_EVENT;
- X }
- X
- X *amount = 0; /* Assume relative scroll */
- X if (ID == SCROLL_REQUEST)
- X return MUSH_SCROLL_PASS_EVENT;
- X
- X if (event_is_up(event))
- X return MUSH_SCROLL_PASS_EVENT;
- X if (event_is_ascii(event) && isdigit(event_id(event))) {
- X count = (count * 10) + event_id(event) - '0';
- X return MUSH_SCROLL_IGNORE;
- X }
- X#ifdef SUN_4_0 /* SunOS 4.0+ */
- X /* returns sunview events for some ctl chars */
- X switch (event_action(event)) {
- X case ACTION_GO_LINE_FORWARD:
- X case ACTION_GO_COLUMN_FORWARD:
- X *amount = count ? count : 1;
- X count = 0;
- X return MUSH_SCROLL_RELATIVE;
- X case ACTION_GO_LINE_BACKWARD:
- X case ACTION_GO_COLUMN_BACKWARD:
- X *amount = count ? -count : -1;
- X count = 0;
- X return MUSH_SCROLL_RELATIVE;
- X case ACTION_GO_DOCUMENT_START:
- X *amount = 1;
- X count = 0;
- X return MUSH_SCROLL_TO;
- X case ACTION_GO_DOCUMENT_END:
- X *amount = 2;
- X count = 0;
- X return MUSH_SCROLL_TO;
- X }
- X#endif /* SUN_4_0 */
- X /* for SunOS 3.5, assume default SunView key mapping */
- X /* a little redundancy for 4.0, but it's ok */
- X if (!event_is_ascii(event) && ID != KEY_RIGHT(14) && ID != KEY_RIGHT(8)
- X && ID != KEY_RIGHT(7) && ID != KEY_RIGHT(13))
- X /* may have to reset "count" here */
- X return MUSH_SCROLL_PASS_EVENT; /* Not a scroll event */
- X switch (event_id(event)) {
- X case KEY_RIGHT(7): /* Home on new keyboards */
- X *amount = 1, count = 0;
- X return MUSH_SCROLL_TO;
- X case KEY_RIGHT(13): /* End on new keyboards */
- X *amount = 2, count = 0;
- X return MUSH_SCROLL_TO;
- X case 'j': case KEY_RIGHT(14): /* downarrow */
- X *amount = count ? count : 1;
- X when 'k': case KEY_RIGHT(8): /* uparrow */
- X *amount = count ? -count : -1;
- X when 'F'-'@': /* ^f */
- X *amount = count ? count * (len-1) : len - 1;
- X when 'D'-'@': /* ^d */
- X *amount = len/2;
- X when 'B'-'@': /* ^b */
- X *amount = -(count ? count * (1-len) : len - 1);
- X when 'U'-'@': /* ^u */
- X *amount = -len/2;
- X when '\033': /* Escape */
- X /* For SunOS 3.5 check to see if this is a cursor
- X * move key, i.e. ESC[A or ESC[B.
- X */
- X if (!(int)window_read_event(client, event) &&
- X event_id(event) == '[' &&
- X !(int)window_read_event(client, event))
- X if (event_id(event) == 'A') {
- X *amount = -1;
- X break;
- X } else if (event_id(event) == 'B') {
- X *amount = 1;
- X break;
- X }
- X default:
- X count = 0;
- X return event_is_ascii(event) ?
- X MUSH_SCROLL_IGNORE : MUSH_SCROLL_PASS_EVENT;
- X }
- X count = 0;
- X /* Scroll indicated amount if event is down, ignore up events */
- X return MUSH_SCROLL_RELATIVE;
- X}
- X
- XNotify_value
- Xscroll_textwin(textsw, event, arg, type)
- XTextsw textsw;
- XEvent *event;
- XNotify_arg arg;
- XNotify_event_type type;
- X{
- X int scroll_amount;
- X
- X switch (decode_scroll(textsw, event, textsw_screen_line_count(textsw),
- X &scroll_amount)) {
- X case MUSH_SCROLL_PASS_EVENT :
- X return notify_next_event_func(textsw, event, arg, type);
- X case MUSH_SCROLL_IGNORE:
- X return NOTIFY_IGNORED;
- X case MUSH_SCROLL_TO:
- X if (scroll_amount == 1)
- X window_set(textsw, TEXTSW_FIRST, 0, NULL);
- X else if (scroll_amount == 2)
- X window_set(textsw, TEXTSW_FIRST, TEXTSW_INFINITY, NULL);
- X textsw_scroll_lines(textsw, -textsw_screen_line_count(textsw));
- X break;
- X case MUSH_SCROLL_RELATIVE :
- X textsw_scroll_lines(textsw, scroll_amount);
- X }
- X window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
- X return NOTIFY_DONE;
- X}
- X
- X/*ARGSUSED*/
- XNotify_value
- Xdestroy_proc(frame, status)
- XFrame frame;
- XDestroy_status status;
- X{
- X if (ison(glob_flags, IS_GETTING))
- X rm_edfile(-1);
- X /* status is ignored -- maybe post notice asking to confirm quit? */
- X if (status == DESTROY_CHECKING && ison(glob_flags, DO_UPDATE) &&
- X !ask("Your folder has been modified. Quit anyway?"))
- X (void) notify_veto_destroy(frame);
- X else
- X cleanup(0); /* doesn't return */
- X return NOTIFY_DONE;
- X}
- X
- X/* Initialise the Mush mail icon. */
- Xstatic void
- Xgeticon()
- X{
- X static Rect lrect = { 5, 5, 26, 12 };
- X
- X mail_icon = icon_create(
- X ICON_WIDTH, 64,
- X ICON_HEIGHT, 64,
- X ICON_FONT, mush_font,
- X ICON_IMAGE, &mail_icon_image1,
- X ICON_LABEL, "",
- X ICON_LABEL_RECT, &lrect,
- X 0);
- X}
- X
- X/* Initialise all the cursors used. */
- Xstatic void
- Xinit_cursors()
- X{
- X extern Pixrect mouse_left, mouse_middle, mouse_right, bent_arrow;
- X extern Cursor bentarrow;
- X
- X l_cursor = cursor_create(
- X CURSOR_XHOT, 3,
- X CURSOR_YHOT, 3,
- X CURSOR_OP, PIX_SRC,
- X CURSOR_IMAGE, &mouse_left,
- X NULL);
- X m_cursor = cursor_create(
- X CURSOR_XHOT, 3,
- X CURSOR_YHOT, 3,
- X CURSOR_OP, PIX_SRC,
- X CURSOR_IMAGE, &mouse_middle,
- X NULL);
- X r_cursor = cursor_create(
- X CURSOR_XHOT, 3,
- X CURSOR_YHOT, 3,
- X CURSOR_OP, PIX_SRC,
- X CURSOR_IMAGE, &mouse_right,
- X NULL);
- X bentarrow = cursor_create(
- X CURSOR_XHOT, 8,
- X CURSOR_YHOT, 8,
- X CURSOR_OP, PIX_SRC|PIX_DST,
- X CURSOR_IMAGE, &bent_arrow,
- X NULL);
- X coffee = cursor_create(
- X CURSOR_XHOT, 8,
- X CURSOR_YHOT, 8,
- X CURSOR_OP, PIX_SRC,
- X CURSOR_IMAGE, &coffee_cup,
- X NULL);
- X}
- X
- X/* show the timeout cursor (coffee cup) when "on" is TRUE. This routine
- X * may be called many times in layers of locking mechanisms, so be careful
- X * not to unlock cursors until "on" has been FALSE as many times as it has
- X * been TRUE.
- X */
- Xvoid
- Xtimeout_cursors(on)
- Xint on;
- X{
- X Window win;
- X Frame subframe;
- X static int locked, numwins;
- X int i = 0, j;
- X static struct {
- X Cursor cursor;
- X Window win;
- X } win_curs[64];
- X
- X on? locked++ : locked--;
- X if (istool < 2 || locked > 1 || locked == 1 && on == 0)
- X return;
- X if (on) {
- X for (numwins = 0; win = window_get(tool, FRAME_NTH_SUBWINDOW, numwins);
- X numwins++) {
- X win_curs[numwins].cursor =
- X cursor_copy((Cursor) window_get(win, WIN_CURSOR));
- X win_curs[numwins].win = win;
- X window_set(win, WIN_CURSOR, coffee, NULL);
- X }
- X while (subframe = window_get(tool, FRAME_NTH_SUBFRAME, i++))
- X for (j = 0; win = window_get(subframe, FRAME_NTH_SUBWINDOW, j);
- X j++,numwins++) {
- X win_curs[numwins].cursor =
- X cursor_copy((Cursor) window_get(win, WIN_CURSOR));
- X win_curs[numwins].win = win;
- X window_set(win, WIN_CURSOR, coffee, NULL);
- X }
- X } else {
- X for (j = 0; j < numwins; j++) {
- X window_set(win_curs[j].win, WIN_CURSOR, win_curs[j].cursor, NULL);
- X cursor_destroy(win_curs[j].cursor);
- X }
- X }
- X}
- X
- X/*
- X * If the user has specified an alternate icon or set of icons in
- X * his .mushrc file, copy the image(s) over the defaults.
- X */
- Xvoid
- Xcheck_icons()
- X{
- X Pixrect *icon_mpr;
- X char errbuf[256], *icon_file, *icon_path;
- X int isdir;
- X
- X if ((icon_file = do_set(set_options, "mail_icon")) && *icon_file) {
- X isdir = 0;
- X icon_path = getpath(icon_file, &isdir);
- X if (isdir == 0) {
- X if (!(icon_mpr = icon_load_mpr(icon_path, errbuf)))
- X error("Error loading mail icon file:\n%s",errbuf);
- X else
- X pr_rop(&mail_icon_image1, 0,0,64,64, PIX_SRC, icon_mpr, 0, 0);
- X }
- X }
- X if ((icon_file = do_set(set_options, "newmail_icon")) && *icon_file) {
- X isdir = 0;
- X icon_path = getpath(icon_file, &isdir);
- X if (isdir == 0) {
- X if (!(icon_mpr = icon_load_mpr(icon_path, errbuf)))
- X error("Error loading newmail icon file:\n%s",errbuf);
- X else
- X pr_rop(&mail_icon_image2, 0,0,64,64, PIX_SRC, icon_mpr, 0, 0);
- X }
- X }
- X}
- END_OF_FILE
- if test 15050 -ne `wc -c <'mush/tool.c'`; then
- echo shar: \"'mush/tool.c'\" unpacked with wrong size!
- fi
- # end of 'mush/tool.c'
- fi
- echo shar: End of archive 16 \(of 19\).
- cp /dev/null ark16isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 19 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-
-